Desktop-App (PyQt6), die gedruckte Notenblätter (PDF/Bild) per Optical Music Recognition in sauberes MusicXML digitalisiert — als Vorlage zur Weiterbearbeitung und zum Transponieren in MuseScore. Zielgruppe: Musiklehrer, die analoge Noten digital verfügbar machen wollen. MIDI-Export ist optional zuschaltbar.
PDF/Bild
→ (1) Ingest pdf2image (poppler) — nur für Vorschau/oemer
→ (2) Preprocess OpenCV (nur oemer): Graustufen → Perspektive → Deskew
→ (3) OMR austauschbares Backend (Audiveris | oemer) → MusicXML
→ (4) Cleanup konservative Korrektur typ. Audiveris-Fehler (pp+ff → cresc.)
→ (4) MusicXML ► PRIMÄRES ERGEBNIS (.musicxml) — in den Ausgabeordner gespeichert
→ (5) MIDI optional (Standard: aus) — MuseScore → verovio → music21
Fokus: Das Produkt ist die MusicXML. In MuseScore öffnen → von Hand korrigieren → transponieren. MIDI ist optional (Stage 5) und derzeit im Backlog.
core/cleanup.py korrigiert rein strukturell und konservativ eindeutige, positions-unabhängige Audiveris-Fehlklassifikationen, ohne korrekte Daten anzutasten (deaktivierbar in den Einstellungen):
cresc./dim.alspp fffehlgelesen: Audiveris liest den Text „cresc." über dem Takt häufig als zwei einsame Dynamikzeichenpp(oberes System) +ff(unteres System). Ein Takt mit genau diesem Paar → ersetzt durch einecresc.-Text-Direction.- Dynamiken in Singstimmen (
strip_vocal_dynamics, Standard an): Bei Chorscores liest Audiveris oft Liedtext-/Symbolfragmente als Dynamiken in die Gesangsstimmen. Parts mit Liedtext (oder vokalem Namen) werden von Dynamiken befreit; Klavier-/Instrumental-Parts behalten ihre Dynamiken. Bei reinen Instrumentalstücken wirkungslos.
Liedtext-Hinweis: Audiveris nutzt Tesseracts Legacy-OCR-Engine (im Build fest verdrahtet), die kleine, silbenweise getrennte Liedtexte nur schwach erkennt. Liedtext bleibt daher ein manueller Korrekturpunkt in MuseScore — die Noten/Struktur sind das verlässliche Ergebnis.
Nicht automatisch reparierbar (Audiveris-Leseebene, daher in MuseScore manuell): falsch platzierte Schlüssel, unvollständige Glissandi, Crescendo-Wedges, zu lange Noten.
python3.11 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # Kern-App + Build-Tools
# optional, MIT-Engine (schwergewichtig, lädt Modelle beim 1. Lauf):
pip install -e ".[oemer]"
python scripts/patch_oemer.py # Kompatibilitäts-Patches für oemer 0.1.5 (s. u.)oemer 0.1.5 Kompatibilität: Diese oemer-Version ist nicht mit NumPy 2.x kompatibel (
np.int) und stürzt auf einigen Bildern in ihren Nachverarbeitungs-Heuristiken ab.scripts/patch_oemer.pywendet kleine, sichere Fixes auf das installierte Paket an und ist idempotent — nach jeder oemer-(Neu-)Installation erneut ausführen.
| Tool | Wofür | Beschaffung |
|---|---|---|
| poppler | PDF→Bild (pdf2image) | macOS: brew install poppler · Linux: apt install poppler-utils · Windows: poppler-Binaries in PATH |
| Audiveris 5.x | OMR-Default-Engine (Java) | s. u. — in PATH, /Applications, oder unter resources/audiveris/ ablegen |
| Java (JRE 17+) | für Audiveris | im offiziellen Installer/DMG bereits enthalten (jpackage) |
Audiveris auf macOS (Apple Silicon) bündeln:
curl -fL -o /tmp/audiveris.dmg \
https://github.com/Audiveris/audiveris/releases/download/5.10.2/Audiveris-5.10.2-macosx-arm64.dmg
yes | hdiutil attach /tmp/audiveris.dmg -nobrowse -mountpoint /tmp/aud_mnt # AGPL-SLA bestätigen
cp -R /tmp/aud_mnt/Audiveris.app resources/audiveris/
xattr -dr com.apple.quarantine resources/audiveris/Audiveris.app
hdiutil detach /tmp/aud_mntDer Pfad-Resolver (core/omr/audiveris.py) findet das .app-Bundle
automatisch (resources/audiveris/Audiveris.app/Contents/MacOS/Audiveris), ebenso eine Installation
in /Applications. Das DMG (jpackage) enthält bereits eine eigene JRE 17.
| oemer | OMR-Alternative (MIT) | pip install oemer |
| Tesseract-Sprachdaten | OCR für Liedtext (Chor) + Textmarken in Audiveris | s. u. — nach resources/tessdata/ |
OCR-Sprachdaten (für Chorscores mit Text & Vortragsbezeichnungen): Audiveris bringt die
Tesseract-Engine mit, aber keine Sprachdaten — ohne sie wird kein Text/Liedtext erkannt.
Die Standard-tessdata laden (enthält die von Audiveris benötigte Legacy-Engine; die
kleineren tessdata_best/tessdata_fast funktionieren nicht):
mkdir -p resources/tessdata
for L in deu eng ita; do
curl -fsSL -o resources/tessdata/$L.traineddata \
https://github.com/tesseract-ocr/tessdata/raw/main/$L.traineddata
doneDas Audiveris-Backend setzt TESSDATA_PREFIX automatisch auf resources/tessdata und
aktiviert deu+eng+ita (core/omr/audiveris.py).
Fehlt eine Engine, zeigt der Einstellungs-Dialog einen Hinweis; die App startet trotzdem.
sheet2midi # via Entry-Point
# oder
python -m sheet2midi.apppytest # schnelle Unit-Tests (Preprocess, Repair, Cleanup, Backends)
pytest -m scores # Score-Korpus durchlaufen (langsam, echte Audiveris-Läufe)Um die OMR-Robustheit gegen reale Bedingungen zu testen, lassen sich aus einer sauberen PDF/Bild-Vorlage realistisch verschlechterte Eingaben erzeugen (core/degrade.py):
python scripts/degrade_score.py "scores/clean.pdf" --preset photo # Handy-Foto
python scripts/degrade_score.py "scores/clean.pdf" --preset scan # Flachbett-Scan
python scripts/degrade_score.py "scores/clean.pdf" --preset bad_scan --pdfPresets: scan (leichte Schräglage/Rauschen/Graustufen), bad_scan (niedrige Auflösung,
starke JPEG-Artefakte), photo (Perspektive, Beleuchtung, Unschärfe), photo_bg
(realistisches Handy-Foto: Blatt schräg auf einem Tisch mit Hintergrund).
Seedbar → reproduzierbar. So bekommt man Testfälle mit bekanntem Soll-Ergebnis und
abgestufter Schwierigkeit (gemessen: saubere Seite 329 Noten → scan 332 → bad_scan 294 →
photo 221).
So fügst du eigene Test-Scores hinzu (z. B. unterschiedliche Scan-Qualität, Chorscores mit Text/mehreren Stimmen):
- Datei (PDF/Bild) nach
scores/legen. - In scores/expectations.json einen Eintrag mit deinen
Erwartungen ergänzen (Schema steht dort unter
__schema__). Nur gesetzte Felder werden geprüft — z. B.parts,min_notes,has_lyrics,expect_words,no_bogus_pp_ff. pytest -m scoresausführen. Erstkonvertierung pro Score ist langsam; Ergebnisse werden inscores/.cache/zwischengespeichert (Folgeläufe schnell, bis die Quelle sich ändert).
pyinstaller Sheet2MIDI.specLege Audiveris (+ JRE) und poppler vorher unter resources/ ab, damit sie mitgebündelt werden.
| Engine | Lizenz | Stärke | Hinweis |
|---|---|---|---|
| Audiveris (Default) | AGPL-3.0 | Beste Qualität bei sauber gedruckten Noten | Java; AGPL — siehe Lizenz |
| oemer | MIT | Robust bei Handy-Fotos, kommerziell unbedenklich | reines Python, lädt Modelle |
Der Wechsel ist eine reine Einstellung — die Pipeline ist über core/omr/registry.py
(Strategy-Pattern) entkoppelt.
Engine-bewusste Eingabe:
- Audiveris verarbeitet die Originaldatei (PDF/Bild) direkt — eigene hochwertige
Binarisierung/Deskew und native Mehrseiten-Verarbeitung (ein PDF → eine kohärente
MusicXML). Unser OpenCV-Preprocessing und die
DPI-Einstellung werden dabei übersprungen (sie gelten nur für oemer). Das vermeidet Qualitätsverlust und einen fehleranfälligen music21-Mehrseiten-Merge. - oemer erhält ein deskewtes Graustufenbild (Deep-Learning-Engines binarisieren/
segmentieren selbst) und wird mit
-daufgerufen (App deskewt bereits).
Bild-Aufbereitung für Audiveris (Fotos/Scans): Bild-Eingaben (keine PDFs) werden vor
Audiveris aufbereitet (enhance_images, Standard an): Perspektivkorrektur (erkennt ein
Blatt auf kontrastierendem Hintergrund und entzerrt es — randfüllende Scans bleiben
unverändert), Beleuchtung glätten (Schatten/Vignette), leichtes Schärfen (gegen verwischte/
„dicke" Notenlinien), Deskew, Hochskalieren. Ohne Binarisierung — die macht Audiveris selbst.
PDFs gehen unverändert direkt an Audiveris. Messbare Wirkung an simulierten Fotos:
- Foto ohne Hintergrund: 221 → 269 Noten (sauber: 329).
- Realistisches Foto auf Tisch (
photo_bg): 50 → ~300 Noten dank Perspektivkorrektur.
MIDI-Erzeugung (Stage 4) — Qualitäts-Eskalation: Notation→MIDI ist kein simples Umkopieren (MusicXML beschreibt Notation: Voices, Ties, Tuplets; MIDI beschreibt Performance: Note-on/off). Daher in dieser Reihenfolge:
- MuseScore-CLI (falls installiert, z. B.
/Applications/MuseScore 4.app) — die getreueste Abbildung; trifft die Notenwerte/das Timing exakt. Auto-erkannt; Pfad in den Einstellungen überschreibbar (musescore_path). - verovio — Fallback (kann bei manchen Stücken Noten verdoppeln/verschieben).
- music21 — letzter Fallback bzw. mehrseitige oemer-Ausgaben (mit abgesicherter,
bei Fehler übersprungener Reparatur;
Quantisierungwirkt nur hier).
Empfehlung: MuseScore 4 installieren (
brew install --cask musescore) für beste MIDI-Qualität.
Robuste Mehrseiten-PDFs: Enthält ein PDF leere/ungültige Seiten (ohne Notensystem),
bricht Audiveris normalerweise das ganze Buch ab (Exit 1, keine Ausgabe). Das Backend
(core/omr/audiveris.py) fängt das ab: es erkennt die
ungültigen Seiten, exportiert die gültigen Seiten aus der bereits transkribierten .omr
und liefert so trotzdem eine MusicXML (mit Hinweis, welche Seiten übersprungen wurden).
Die App selbst ist proprietär. Audiveris ist AGPL-3.0: Es wird bewusst als separater Subprozess aufgerufen (Aggregation statt Einbettung), nicht in den App-Code gelinkt. Wird Audiveris mitgeliefert, müssen AGPL-Lizenztext und ein Quellcode-Angebot (Link auf das öffentliche Audiveris-Repo) beigelegt werden.
Für eine vollständig permissive/proprietäre Auslieferung: in core/omr/registry.py
DEFAULT_BACKEND = "oemer" setzen (oemer ist MIT) und Audiveris nicht bündeln.