Make a score from a song or a MIDI file
ferraus score writes readable sheet music: a lead sheet with chord symbols, a grand staff
for piano, a drum score, or tonic sol-fa. MusicXML is the main output; MuseScore, Finale,
Sibelius, Dorico, and most notation apps open it. This walkthrough starts from MIDI (the
reliable path), then goes from a recording. Outputs are trimmed copies of what ferraus 0.1.0
printed.
You need: a MIDI file, or a recording plus the separation model (see Split a song into stems). PDF, SVG, and PNG pages also need an engraver (step 4).
1. A melody to a lead sheet
Making a test file. A MIDI file can be written from a few lines of JSON:
cat > melody.json <<'EOF' {"tempo_map": [{"beat": 0, "bpm": 100}], "tracks": [{"notes": [ {"beat": 0, "duration_beats": 1, "name": "E5", "velocity": 100}, {"beat": 1, "duration_beats": 1, "name": "D5", "velocity": 100}, {"beat": 2, "duration_beats": 1, "name": "C5", "velocity": 100}, {"beat": 3, "duration_beats": 1, "name": "D5", "velocity": 100}]}]} EOF ferraus midi from-json melody.json -o melody.midThe examples below used a 16-note version of this melody.
ferraus score melody.mid -o melody.musicxml --title "Little Tune" --svg melody.svg --abc melody.abc --solfa-txt melody.solfa.txt --json
{"ok": true, "command": "score",
"outputs": [{"path": "melody.musicxml", "role": "musicxml"}, {"path": "melody.abc", "role": "abc"},
{"path": "melody.solfa.txt", "role": "solfa"}, {"path": "melody.svg", "role": "svg"}],
"params": {"engraver": "native", "key": "A minor", "time": "4/4", "quantize": "1/16", ...},
"result": {"measures": 4, "check": {"ok": true, "errors": 0, "warnings": 0}, "low_confidence": [],
"notation": {"key": "A minor", "key_source": "estimated", "key_confidence": 1.0, "tempo_bpm": 100.0,
"parts": [{"id": "P1", "name": "Piano", "layout": "lead-sheet", "notes": 16}]}}}
The ABC and sol-fa outputs are plain text:
X:1
T:Little Tune
M:4/4
L:1/8
Q:1/4=100
K:Am
e2 d2 c2 d2 | e2 e2 e2 c2 | c2 B2 A2 B2 | c2 c2 A2 A2 |]
Little Tune
Key: Doh is C (A minor, lah is A)
Time: 4/4
Tempo: 100 bpm
|m :r :d :r |m :m :m :d |d :t, :l, :t, |d :d :l, :l, ||
Check: open melody.musicxml in a notation app (or melody.svg in a browser) and play
it back. The key was estimated from the notes (key_source); this melody sits equally well
in C major and its relative minor, A minor, and ferraus chose A minor. If you know the key,
give it: --key C. Notes are snapped to --quantize 1/16 (use 1/8 for simpler rhythms,
1/32 for fast passages).
Sol-fa only, with no staff (--solfa only), or fixed do (--solfa fixed):
ferraus score melody.mid --solfa only -o melody-solfa.txt
Transpose for another instrument or singer, with guitar chord diagrams:
ferraus score melody.mid --chords diagrams --transpose 3 -o lead.musicxml
2. A full arrangement
A multi-track MIDI file becomes one part per track: the drum channel (10) gets a drum score, wide-range parts get a grand staff, and the rest get lead sheets (in the bass clef when low).
ferraus score song.mid -o song.musicxml --midi song.score.mid --json
{"result": {"parts": [{"id": "P1", "name": "lead", "staves": 1}, {"id": "P2", "name": "piano", "staves": 2},
{"id": "P3", "name": "bass", "staves": 1}, {"id": "P4", "name": "drums", "staves": 1, "percussion": true}],
"measures": 8, "check": {"ok": true, "errors": 0, "warnings": 0},
"notation": {"key": "C major", "key_confidence": 0.9, "time": "4/4", "tempo_bpm": 100.0,
"chords": ["C", "Am", "F", "G", "Gadd9", "C", "Am", "F", "G"]}}}
--midi song.score.mid also writes the MIDI performance of the notation, so you can hear
exactly what was notated. Validate any score file with:
ferraus score check song.musicxml
{"ok": true, "errors": 0, "warnings": 0, "parts": 4, "measures": 8, "notes": 184, "issues": [], "failing_measures": []}
Force a layout when the automatic choice is wrong: --layout grand --split C4 for piano
with a fixed hand split, --layout drums, --layout bass, --layout lead-sheet.
3. From a recording
The one-command route
ferraus score take.wav --parts vocals,bass,drums -o take.musicxml --midi take.mid -y
This runs analyze tempo, analyze key, analyze chords, separate, transcribe per
stem, and a native drum transcription, then notates. --dry-run shows that plan. It separates
with the default tier (balanced in this release: four fine-tuned Demucs models, about 660 MB
on the first run; see Stems and separation tiers). Measured with the
quality tier (the Mel-Band RoFormer for the vocals) on a 7-second excerpt of a MUSDB18 test
song, it took 52 s on a laptop CPU and peaked at 3.2 GB of memory:
{"parts": [{"id": "P1", "name": "Vocals"}, {"id": "P2", "name": "Bass"}, {"id": "P3", "name": "Drums", "percussion": true}],
"measures": 6, "check": {"ok": true, "errors": 0, "warnings": 0},
"audio": {"stems": [{"role": "vocals", "notes": 20, "mode": "mono"}, {"role": "bass", "notes": 16, "mode": "mono"},
{"role": "drums", "notes": 67, "method": "native onset drum transcription"}]}}
A stem with nothing pitched in it (a part the song does not have) is reported with a
no_notes warning and left out of the score.
The step-by-step route (faster, pitched parts)
Do the same steps yourself with the fast tier, which needs one 166 MB model.
Measure the tempo first and pass it to every transcription, so all the parts share one tempo
map:
ferraus analyze tempo song.wav # "bpm": 100.0, "confidence": 1.0
ferraus separate song.wav --tier fast -y
ferraus transcribe song.bass.wav --mode mono --program 33 --bpm 100 -o bass.mid
ferraus transcribe song.other.wav --mode poly --bpm 100 -y -o other.mid # chords: Basic Pitch model, 230 kB
ferraus midi merge other.mid bass.mid -o parts.mid
ferraus score parts.mid --title "From audio" -o parts.musicxml
{"notation": {"key": "C major", "time": "4/4", "tempo_bpm": 100.0, "measures": 9,
"parts": [{"id": "P1", "layout": "grand", "notes": 159}, {"id": "P2", "layout": "lead-sheet", "notes": 33}],
"chords": ["C", "Am", "F", "G", "C", "Am", "F", "Bm7b5/F", "G"]}}
Check: the bass line (one note at a time) transcribes very accurately (33 notes for 32
played). Polyphonic parts (--mode poly, chords) are best-effort: the mean note confidence
was 0.52, and the chord list has one wrong chord (Bm7b5/F where the song plays F). Open the
score, play it back against the recording, and fix what you hear. Drum audio is not
transcribed on this route; analyze chords song.wav gives chord symbols with times if you
only need a chord chart.
4. PDF, SVG, and PNG pages
MusicXML, ABC, LilyPond (--ly), MEI (--mei), and sol-fa are written natively. --svg falls
back to a minimal built-in renderer. Proper engraving (--pdf, --png, and good SVG) needs
the ferraus-engrave helper (shipped in the release packages; from source:
cargo build -p ferraus-engrave --release) or LilyPond. Without either, ferraus says so:
{"ok": false, "error": {"code": "engraver_missing",
"message": "no engraver found: neither the ferraus-engrave helper (Verovio) nor LilyPond is available; SVG, PDF, and PNG output need one", ...}}
ferraus doctor reports which engraver it found ("engraver": {"helper": ..., "lilypond": ...}).
Reference
score · score check · score convert · transcribe · midi merge · analyze chords · Notation and solfa