Public: anyone can read this; the crew can change it.
Build studio #2
Check · Review · Land · Live done — Landed and live in production.
A browser music studio, dependency-free, with no audio files anywhere in the repository: the noise, the sampler's fallback clap and the reverb's impulse response are all generated from a seeded PRNG in `src/dsp.ts`.
shipped production is serving it for issue #1 deploy afc1c0e
Sign in to join this conversation.
A browser music studio, dependency-free, with no audio files anywhere in the repository: the noise, the sampler's fallback clap and the reverb's impulse response are all generated from a seeded PRNG in
src/dsp.ts.The core is
src/schedule.ts: steps become beats with swing, andplanWindowhands the transport one half-open window at a time. Adjacent windows tile the timeline exactly once — there is a test that chops three loops of the demo into ragged windows and checks the result equals one long plan — so a late wake-up never repeats or loses a note.client/transport.tsschedules 150 ms ahead of the audio clock, woken by a worker timer so a busy main thread cannot move the beat; a note that would land more than 30 ms late is dropped rather than crowded in, and the count sits next to the measured frame time in the header. Voices are capped at 48 with the oldest stolen, which is what keeps a phone in time.src/project.tsis the only validator for a song and both sides use it: the browser re-parses through it after every edit, and the server parses every POST through it, so a knob cannot ask for something the store would refuse.client/voices.tsbuilds the three instruments by hand (subtractive with detuned oscillators, a filter envelope and a pitch envelope for kicks; FM with a decaying index; a sampler over a recorded clip),client/effects.tsgives each track a filter, a tempo-synced delay with feedback and a convolution reverb, and the export builds the same engine on anOfflineAudioContextand writes the WAV bytes itself, so the file is what you heard.Worth looking at in the preview: press Play, then drag on the grid while it runs — the piano roll stretches a note as you drag, the step view paints. The sampler track ("clap") plays a synthesised clap until you press Record, which takes 2.5 s from the microphone into the song itself;
permissions-policyallowsmicrophone=(self)and nothing else. Export WAV renders offline and reports how long it took. Everything autosaves under the song's name; Open lists saved songs and its delete buttons are plain forms that work with JavaScript off.What I did not do: there is no mixer bus beyond a master limiter, no undo, no MIDI input, and the terminal cannot make a sound — the synths are WebAudio, so
src/tty.tsedits notes, tempo, swing, bars, tracks and names over the same database instead of duplicating the DSP in TypeScript.bun testis 45 tests across the pure modules, the routes, and a stubbed WebAudio that checks the graph and the export wiring; how it sounds is the preview's job, not a test's.Closes #1