Whistle a tune β get sheet-ready notes and a playable MIDI file.
A tiny native macOS app: whistle into the microphone, watch your melody appear as
notes on a piano roll, play it back, fix the parts you missed by re-whistling them,
and export a standard .mid file that opens in GarageBand or Logic.
Pure SwiftUI + AVFoundation. No dependencies, no cloud β everything runs on your Mac.
- π Whistle-to-notes β real-time pitch detection tuned for whistling (YIN algorithm, 350β5000 Hz)
- πΉ Piano roll β detected notes with names (A5, C6β¦), live note indicator while you whistle
- π Re-whistle a fragment β select the notes you got wrong, whistle them again, and the new take is spliced in seamlessly
βΆοΈ Instant playback β whole melody or just the selection, through the built-in GM synth- πΎ MIDI export β standard MIDI file (GM "Whistle" instrument) for any DAW or notation app
Selected notes (orange) are ready to be replaced by a new take β hit Re-whistle Selection and whistle just that fragment again:
Grab WhistleMelody-x.y.z.zip from the
latest release,
unzip and move WhistleMelody.app to Applications.
First launch: the app is not notarized yet (no Apple Developer subscription), so macOS will refuse to open it at first. Two ways around it:
- Try to open the app once, then go to System Settings β Privacy & Security, scroll down and click Open Anyway. On macOS 13β14 you can simply right-click the app β Open β Open.
- Or clear the quarantine flag in Terminal:
xattr -d com.apple.quarantine /Applications/WhistleMelody.appThis is a one-time step. Building from source (below) needs no workarounds at all.
Requires macOS 14+ and Xcode command line tools (Swift 5.9+).
./scripts/build_app.sh
open build/WhistleMelody.appFor quick development iterations: swift run (the mic permission is then attributed
to your terminal app).
- Record (Space) β start recording, whistle, press again to stop. Detected notes appear on the piano roll.
- Click notes to select them (click empty area to deselect).
- Re-whistle Selection β record a replacement take; new notes are spliced into the selected range, the rest of the melody shifts to stay continuous.
- Play / Play Selection β playback through the system GM synth.
- Save MIDIβ¦ β export a
.midfile.
- Pitch detection β YIN algorithm over an AVAudioEngine mic tap (window 2048, hop 1024, whistle band 350β5000 Hz, RMS noise gate).
- Segmentation β median-smoothed pitch track split into notes on semitone jumps (> 0.7 st) or silence (> 60 ms); fragments < 90 ms are dropped as noise.
- MIDI β hand-written SMF format 0 (480 tpq, 120 BPM, GM program 79 "Whistle"), played via AVMIDIPlayer.
Design decisions live in features/whistle-melody.md.
Sources/WhistleMelody/
App.swift β entry point
ContentView.swift β toolbar, status bar, layout
PianoRollView.swift β note visualization and selection
MelodyStore.swift β app state: record/play/splice/export
AudioRecorder.swift β mic capture, framing, RMS gate
PitchDetector.swift β YIN pitch detection
NoteSegmenter.swift β pitch track β discrete notes
MidiFile.swift β Standard MIDI File writer
MidiPlayer.swift β playback via AVMIDIPlayer
scripts/ β .app bundling (Info.plist + build_app.sh)

