Keep the melody before it disappears
An idea for a melody rarely arrives with a music project open and an instrument ready. I built Humfolio to make the first step smaller: hum a phrase into the browser, hear it back as notes, correct it, and export a MIDI file.
The name combines hum and folio. I wanted a small notebook for musical ideas, with a clear path from capturing a phrase to continuing it elsewhere.
Hum, listen, edit, export. That sequence shaped the application. Transcription gives the user a starting point; playback and direct editing help them turn it into what they intended.
Connect capture, transcription, and editing
I built the application with React, strict TypeScript, Vite, and Tailwind CSS. Browser audio APIs handle microphone capture, synthesis, and rendering. Pitchy supplies a McLeod Pitch Method detector; my processing code turns its frequency and clarity observations into a score.
An AudioWorklet captures mono PCM samples on the browser’s audio processing thread and transfers batches to the main thread. Pitch analysis and note segmentation run on the main thread. Keeping that boundary explicit helps explain both the implementation and where further performance work could happen.
I handled the complete recording lifecycle: cancellation while microphone permission is pending, streams that arrive after cancellation, the final partial audio batch, and denied access or unavailable devices. Takes are capped at two minutes.
The score stores notes in quarter-note beats. BPM maps those beats to seconds, and a selectable grid snaps note boundaries. That same score drives the piano roll, synthesized playback, and export, so an edit changes what the user hears and downloads.
Find the boundary between repeated notes
A pitch detector can identify the frequency of a sustained hum without knowing how many notes the performer intended. Vibrato, harmonics, weak frames, and short breaths complicate that distinction.
I smooth pitch observations in semitone space, reject unclear frames, and combine pitch changes with energy boundaries. The most useful refinement came from repeated notes at the same pitch: a short breath could disappear inside a 50 ms average and turn two notes into one.
I kept pitch observations on 50 ms hops while preserving amplitude changes in 10 ms energy bins. The segmenter can then use a brief, deep energy valley to separate repetitions without treating ordinary vibrato as a new note.
For a continuous tone at one pitch, the performer can use the editor’s Split action to place the boundary between intended repetitions.
Make correction part of the workflow
The piano roll supports moving notes in pitch and time, resizing either edge, adding and deleting notes, and splitting a selected note. Keyboard controls provide another way to edit. A complete drag becomes one undo step, rather than dozens of intermediate states.
A/B audition lets the user compare the original recording with the synthesized score. Playback uses the audio clock for scheduling; the visible playhead follows that clock. Original PCM stays available for the current take, while the editable score can be saved independently.
I revised the interface around neutral surfaces, readable contrast, and one blue accent. The score gets the main workspace. Recording, playback, tempo, and MIDI export remain visible; saved melodies and detailed guidance open when needed.
Rams’s principles, editorial work by Pentagram, and research on visual complexity and first impressions informed the interface’s restraint, hierarchy, and use of familiar controls.
Save a melody without bringing it back after deletion
Audio analysis, editing, storage, and export all run in the browser. There is no account or application backend. The notebook saves up to 50 scores in localStorage, while raw microphone samples remain in session memory and disappear when the take is replaced or the page reloads.
Deleting a melody revealed a different kind of engineering problem. An old autosave timer or unload callback could restore a score after the user had deliberately removed it. I added a persistence generation guard and made score/title transitions synchronous, addressing both stale callbacks and an immediate-refresh race.
Deletion now names the target in a confirmation, focuses Cancel by default, and commits the storage change before removing the entry from the interface. A failed write leaves the melody visible. Deleting the last saved melody leaves an unsaved blank workspace.
These controls protect the flow within a page. Browser storage can still be cleared, so exporting a file is the durable way to keep an important idea.
Export the same score the user can hear
Humfolio exports MIDI, WAV, and a text note sequence. The MIDI encoder writes a type 0 Standard MIDI File with 480 ticks per quarter note, tempo, meter, and note events. Note-offs precede note-ons at the same tick so adjacent repetitions remain separate events.
WAV export renders the edited score through OfflineAudioContext and encodes mono, 16-bit PCM at 44.1 kHz, including a short release tail. Playback uses browser synthesis, and its three demo melodies are original compositions created for the project.
Verify the complete workflow
For the October 4, 2026 revision, the project passed 52 Vitest tests and 31 Chromium browser tests, along with formatting, strict TypeScript compilation, and the production build. The browser suite also passed against the deployed HTTPS site.
The checks cover musical conversions, smoothing and segmentation, capture cancellation, score editing, storage, and file generation. MIDI output is read back by the independent @tonejs/midi parser. Generated harmonic signals travel through a real MediaStream and AudioWorklet, including a regression for six quiet repeated tones separated by short breaths. Other browser tests check deletion races, download flows, and stale accessibility announcements.
Humfolio taught me to treat transcription as a workflow rather than an isolated detector. The useful result depends on note boundaries, musical timing, immediate audition, recoverable editing, and predictable storage working together.