In-Browser Mic Recording
Record straight from the browser mic, in sync with the existing mix
Overview
Lets a user record a take straight from the browser's microphone instead of recording in a separate app and uploading the file — mainly built to give iPhone users a way around Voice Memos not being reachable from Safari's file picker (see Add Your Track). While recording, the song's existing mix plays back in sync so the new take can be laid down as an overdub, matching what the other tracks are already doing.
How it works
RecordTrackButton.tsxusesnavigator.mediaDevices.getUserMedia({ audio: true })+MediaRecorder. It picks the first supported MIME type from['audio/mp4', 'audio/webm;codecs=opus', 'audio/webm', 'audio/ogg']— iOS Safari recordsaudio/mp4(AAC), named.m4aon upload to match the other accepted formats; Chrome/Firefox recordaudio/webm.onStart/onStopcallbacks let the parent (MultiTrackPlayer.tsx) drive playback in step with the recording: starting a recording callsstop()thenplay()on the transport (so the existing mix always plays from the top), and stopping the recording callsstop()again.- On stop, the recorded chunks become a
Blob, wrapped in aFile(recording.<ext>), and handed to the sameuploadFile()→uploadTrackFile()path used by manual file upload and GarageBand import. - Mic permission errors (e.g. denied) surface as an inline message rather than failing silently.
Key files
| File | Role |
|---|---|
src/components/RecordTrackButton.tsx | Mic capture via MediaRecorder, MIME/extension selection, recording UI |
src/components/MultiTrackPlayer.tsx | Wires onStart/onStop to the playback transport (handleRecordStart, stop) |
src/lib/trackUpload.ts | Shared upload path the recorded file goes through |
Limitations / notes
- Mic-only capture, not a mixdown — the existing mix plays through speakers/headphones, but the recording only captures what the microphone picks up. Without headphones, the mix will bleed into the new take; the UI shows a headphones hint whenever there are existing tracks to play along with.
- Not sample-accurate sync — there's a small (tens of ms) gap between the mic starting and playback starting, since they're two separate async calls (
getUserMedia/recorder.start()vs. the playback transport's own 50ms scheduling lead). Fine for casual overdubbing; tighter alignment would need something like a count-in click before recording starts. - No in-app preview/re-record before upload — stopping the recording uploads immediately.