Skip to content

DefinitivJakob/Sheet2Midi

Repository files navigation

Sheet2MIDI

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.

MusicXML-Cleanup (Stage 4.5)

core/cleanup.py korrigiert rein strukturell und konservativ eindeutige, positions-unabhängige Audiveris-Fehlklassifikationen, ohne korrekte Daten anzutasten (deaktivierbar in den Einstellungen):

  • cresc./dim. als pp ff fehlgelesen: Audiveris liest den Text „cresc." über dem Takt häufig als zwei einsame Dynamikzeichen pp (oberes System) + ff (unteres System). Ein Takt mit genau diesem Paar → ersetzt durch eine cresc.-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.

Installation (Entwicklung)

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.py wendet kleine, sichere Fixes auf das installierte Paket an und ist idempotent — nach jeder oemer-(Neu-)Installation erneut ausführen.

Externe Abhängigkeiten

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_mnt

Der 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
done

Das 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.

Starten

sheet2midi              # via Entry-Point
# oder
python -m sheet2midi.app

Tests

pytest                  # schnelle Unit-Tests (Preprocess, Repair, Cleanup, Backends)
pytest -m scores        # Score-Korpus durchlaufen (langsam, echte Audiveris-Läufe)

Test-Eingaben aus sauberen Vorlagen erzeugen (Scan/Foto simulieren)

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 --pdf

Presets: 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).

Score-Korpus erweitern (Qualitäts-Regression)

So fügst du eigene Test-Scores hinzu (z. B. unterschiedliche Scan-Qualität, Chorscores mit Text/mehreren Stimmen):

  1. Datei (PDF/Bild) nach scores/ legen.
  2. 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.
  3. pytest -m scores ausführen. Erstkonvertierung pro Score ist langsam; Ergebnisse werden in scores/.cache/ zwischengespeichert (Folgeläufe schnell, bis die Quelle sich ändert).

Build (Desktop-Installer)

pyinstaller Sheet2MIDI.spec

Lege Audiveris (+ JRE) und poppler vorher unter resources/ ab, damit sie mitgebündelt werden.

OMR-Engine wählen (Einstellungen → OMR-Engine)

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 -d aufgerufen (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:

  1. 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).
  2. verovio — Fallback (kann bei manchen Stücken Noten verdoppeln/verschieben).
  3. music21 — letzter Fallback bzw. mehrseitige oemer-Ausgaben (mit abgesicherter, bei Fehler übersprungener Reparatur; Quantisierung wirkt 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).

Lizenz / Kommerzialisierung (kein Rechtsrat)

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.

PDF-PNG-2-Sheet

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages