ferraus transcribe
Turn singing, humming, or an instrument into MIDI
Synopsis
ferraus transcribe <input> [options] [-o <output>]
What it does
Transcribes a recording to a MIDI file plus a JSON sidecar (<out>.notes.json) listing every note with its confidence. Mono mode (singing, humming, whistling, a monophonic instrument) tracks pitch every 10 ms, splits notes on pitch jumps over 80 cents or energy dips, takes each note's median pitch, maps peak loudness to velocity, merges notes shorter than --min-note, snaps to the detected key, and writes a tempo map from the detected (or given) tempo. Poly mode decodes Basic Pitch note activations (piano, guitar chords) and needs the model 'transcribe/basic-pitch'. Auto picks mono when the pitch tracker finds a single voiced line.
Examples
Hummed melody to MIDI, with part.notes.json listing each note's confidence
ferraus transcribe hum.wav -o part.mid
Fixed tempo and sixteenth-note quantize in the same run
ferraus transcribe whistle.wav --bpm 96 --quantize 1/16 -o tune.mid
A bass part: octave chosen for a bass, even velocities
ferraus transcribe bassline.wav --program 33 --velocity fixed:100 -o bass.mid
Chords with the Basic Pitch model (ferraus models pull transcribe/basic-pitch)
ferraus transcribe piano.wav --mode poly -o piano.mid
Options
| Flag | Type | Default | Meaning |
|---|---|---|---|
--mode | mono | poly | auto | auto | mono: one note at a time (voice, whistle, bass); poly: chords via the Basic Pitch model; auto: mono when the pitch tracker reports a single voiced line |
--tracker | pyin | crepe | pyin | Pitch tracker for mono mode; crepe needs the model pitch/crepe |
--min-note | time | 60ms | Shortest note kept (60ms); shorter fragments merge into a neighbour or are dropped |
--onset-sensitivity | percent | 50% | How readily repeated or sliding notes are split: 50% splits on 80-cent pitch jumps and 9 dB energy dips, 100% on 40 cents and 3 dB, 0% on 120 cents and 15 dB (poly: onset threshold 1 − sensitivity) Range: 0..100%. |
--velocity | text | from-rms | from-rms: each note's peak loudness through a loudness curve (loudest note 112, −6 dB 79, −20 dB 35); fixed:<1-127> gives every note the same velocity |
--bpm | text | auto | Tempo of the written file in BPM: auto detects it from the note onsets and the recording (also set by the global --bpm) |
--quantize | grid | off | Quantize note starts in the same run: a grid such as 1/16 or 1/8T, auto to detect the subdivision, or off |
--key-snap | on|off | on | When the detected key's confidence is above 0.6, move out-of-key notes onto the nearest key note (notes sung within 25 cents of a chromatic pitch are kept) |
--pitch-bend | on|off | off | Encode slides (portamento up to 2 semitones) and pitch drift as pitch bend (±2 semitone range) instead of discrete notes (mono mode) |
--octave | text | auto | auto shifts by whole octaves so the median note lands in the comfortable range of --program (piano E2-C6, bass G1-D3, flute D4-G6); or a fixed shift in octaves (-1, +1, 0) |
--program | integer | 0 | General MIDI program (0-based) written into the track; also picks the --octave auto range (0 piano, 33 bass, 40 violin) Range: 0..127. |
Global options
Every command also accepts the global options (-o, --json, --dry-run, --overwrite, --progress, ...). See Global options.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Processing failed |
| 2 | Usage or parameter error |
| 3 | Input missing or unreadable |
| 4 | Unsupported format or codec |
| 5 | Model not cached and downloads disabled |
| 6 | Model download or verification failed |
| 8 | Cancelled |
| 10 | Network error |
| 70 | Internal error (bug) |
Common mistakes
- Forgetting that outputs are never overwritten: pass
--overwriteor a new-opath when re-running. - Beat-based times (
4b,1/4) need a tempo: pass--bpmor write4b@120. - Percentages accept
80%or the fraction0.8; a bare80means 80x, not 80%.
For models
- MCP tool:
ferraus_transcribe - Schema:
ferraus schema transcribe - Pipeline:
{ op: transcribe, args: { ... } }(flag names with_instead of-) - fx stage: no
{"command": "transcribe", "defaults": {"mode": "auto", "tracker": "pyin", "min_note": "60ms", "onset_sensitivity": "50%", "velocity": "from-rms", "bpm": "auto", "quantize": "off", "key_snap": "on", "pitch_bend": "off", "octave": "auto", "program": "0"}}