Morph Blog
Engineering

Hoe we een DAW in je browser hebben gebouwd.

Soundbend draait op WebAssembly, Web Audio API en 25 jaar DSP-onderzoek — alles client-side. Het volledige technische verhaal: audio-grafiek, worklets, Airwindows-ports, true-peak limiter, plugin-host.

DOOR HAYDEN SIMERLY12 MIN LEZENBijgewerkt april 2026

This is a technical post about how Morph's Soundbend — a full digital audio workstation including 5 native instruments, a Mixer with FX chains and aux sends, 30+ effects (including 5 Airwindows Tier-1 ports and a true-peak limiter), a MIDI effects rack, a WAM v2 plugin host, and a Yjs CRDT collaboration layer — runs entirely in a browser tab.

Het praktische vraagstuk is: is dit echt concurrerend met Ableton? Het eerlijke antwoord: voor de meeste producentenwerkstromen, ja. Voor diepe Max for Live integraties, nog niet. Lees de Ableton alternatief vergelijking voor een productniveau vergelijking. Dit bericht is de engineering.

De stack

1. Het audioverloop

Elke track in Soundbend gaat door een keten: instrument → track FX keten → aux send → Mixer strip → master bus → limiter → bestemming. Elke pijl is een Web Audio AudioNode-verbinding.

Web Audio geeft ons AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode en vrienden. Deze zijn geoptimaliseerd door browsermotoren (V8/SpiderMonkey/JSC zijn diep betrokken). Voor standaard effecten — EQ, gain automatisering, basisfiltering — gebruiken we native nodes. Ze zijn snel en goed getest.

Voor custom effecten — Airwindows ports, onze saturatie, onze true-peak limiter — gaan we naar AudioWorkletProcessor, dat op de audio-thread draait, gegarandeerd real-time prioriteit heeft, en de juiste architecturale plaats is voor niet-standaard DSP.

class PurestDriveProcessor extends AudioWorkletProcessor {
  process(inputs, outputs) {
    const input = inputs[0];
    const output = outputs[0];
    // Airwindows PurestDrive port — ~30 LOC of saturation math
    for (let ch = 0; ch < input.length; ch++) {
      for (let i = 0; i < input[ch].length; i++) {
        const s = input[ch][i];
        // [...tape-saturation math...]
        output[ch][i] = processed;
      }
    }
    return true;
  }
}
registerProcessor('purest-drive', PurestDriveProcessor);

Worklets worden geleverd in public/audio-worklets/*.js en laden via audioContext.audioWorklet.addModule(path). Zodra geladen, kan elk deel van het grafiek een AudioWorkletNode instantiëren voor die processor. Verwerking vindt plaats op een aparte thread — UI-animaties verstoren geen audio.

2. De 5 Airwindows Tier-1 ports

Chris Johnson's Airwindows is 2.500+ audio plugins, MIT-licensed, legendarisch smaakvolle DSP. We hebben 5 geport naar browser AudioWorklets voor Soundbend's Wave 12 ship:

Elke poort is ~30-80 LOC wiskunde in een AudioWorkletProcessor. De poorten komen niet bit-per-bit overeen met Airwindows (verschillende FMA/denormal behandeling tussen C++ en JS numerieke engines), maar ze klinken hetzelfde. Null-tests houden de uitvoer ≤ -80 dBFS residu tegen goldens, dus DSP-wijzigingen worden opgemerkt.

3. De echte pieklimiter

Moderne streamingplatforms (Spotify, Apple Music, YouTube) eisen echte piek luidheid normalisatie volgens ITU-R BS.1770-5. Steekproefpieken en inter-voorbeeldpieken zijn verschillende dingen; een signaal kan pieken op -1 dBFS steekproefmatig maar hoger uitkomen dan 0 dBFS echte piek na D/A reconstructie. Een niet-echte piek limiter zal knippen in de DAC, ook al toont je DAW het schoon.

Onze limiter implementeert de volledige ITU-spec: 4x oversampling, inter-sample-peak detectie, lookahead, soft-knee release. Het wordt geleverd in AudioWorklet-vorm op public/audio-worklets/true-peak-limiter-processor.js. Metingen tegen referentie-implementaties (Oxford Limiter, iZotope Ozone Maximizer) komen binnen 0,1 dB op LUFS geïntegreerd overeen.

4. Communicatie buiten de hoofdthread

De audio-grafiek wordt uitgevoerd op de audio-thread. De UI wordt uitgevoerd op de hoofd-thread. Parameterwijzigingen (draai een knop, fade een track) moeten van UI → audio propageren zonder het audio te verstoringen.

Web Audio's AudioParam verwerkt dit nagenoeg standaard voor standaardparameters (GainNode gain, BiquadFilterNode frequency). Voor aangepaste worklet-parameters gebruiken we MessagePort met gestructureerd klonen voor UI-berichten, en SharedArrayBuffer-gebaseerde ringbuffertjes voor hoge snelheid automatiseringsgegevens.

SharedArrayBuffer vereist Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp headers. Deze zijn ingesteld in public/_headers voor de /soundbend + /pulse routes. De Tape Delay gebruikt een ringbuffer bij 96kHz om berichtpoortlatentie te voorkomen.

5. De 5 native instrumenten

Soundbend bevat 5 instrumenten, allemaal op maat:

FM Synth — 6-operator FM-synthese gemodelleerd op DX7 / Operator. Algoritmevisualisator + volledige modulatiematrix. ~800 LOC JS voor de UI, ~300 LOC worklet voor de stemallocator.

Wavetable Synth — morph-between-tables synthese. Spectrale vervorming + unisono + stereo detune. 30+ fabriekswavetables. Gebruikt ConvolverNode voor wavetable crossfade op audiorate.

Analog Subtractive — 2-oscillator polysynth met Cytomic SVF-filters. Cytomic is de state-variable filter topologie die goed klinkt; naive SVF heeft aliasing problemen boven fc > SR/6. De Cytomic port lost dit op via zero-delay feedback wiskunde.

DrumRack + Sampler — pad-gebaseerde sample afspelen met per-pad pitch/filter/amp envelopes. Samples worden opgeslagen in IndexedDB voor snelle herinnering. 5 genre-specifieke fabriekskits (boombap, trap, house, dnb, afrobeat).

SeedSynth + Geist (in de verouderde AudioStudioEngine — nu samengevoegd in Soundbend sinds Wave 14) — een genetische patch-generator (Synplant 2-class) en een Geist-stijl drummachine. Dit zijn de eigen merken die de consolidatie doctrine een groot succes maakten — we moesten bit-identieke gedrag behouden door een 30k-lijn samenvoeging. 100-zaad null-test geslaagd na samenvoeging.

6. De Mixer + aux-zenders

Een echte Mixer — niet alleen per-track faders maar ook FX inserts per track, pre/post-fader aux sends, master bus — is wat een DAW van een sequencer onderscheidt. De Mixer-klasse van Soundbend is ~655 LOC (src/audio/mixer.js). Elke track is een AudioNode-grafiek met insert slots, send tap punten en metering.

Het lastige deel is pre-fader versus post-fader aux-send. Pre-fader stuurt naar een reverbbus ongeacht de volume van de track (klassieke gebruik: parallelle reverb die overleeft een trackfade). Post-fader schaalt met trackvolume. Beide zijn standaard.

7. MIDI + WAM plugin host

WebMIDI is rijp — controllerinput vanaf elke USB-MIDI-toetsenbord werkt direct. Onze MIDI-rij (Arpeggiator, Schaal, Akkoord) zit tussen de controller en het instrument, en transformeert notenstromen.

Voor plugins hosten we Web Audio Modules v2 (WAM) — browser-native plugins. Kleinere ecosystem dan VST (25-jarige voorsprong) maar groeiend. Het laden van een WAM is getWamHost().load(wamUri) wat een AudioNode retourneert dat je kunt invoegen in elke keten.

WAMs vereisen per-route CSP omdat ze willekeurige, door de gebruiker geleverde JS laden. Onze _headers beperkt CSP nauwkeurig voor /soundbend met een script-src toegelijst voor bekende WAM-registeradressen.

8. OfflineAudioContext voor bounce

Export werkt via OfflineAudioContext — render sneller dan realtime (of langzamer, afhankelijk van de ketencomplexiteit) naar een statisch AudioBuffer, en encodeer vervolgens naar WAV met onze in-browser encoder.

Vang: niet alle knooppunten werken in OfflineAudioContext. MediaStreamAudioSourceNode werkt niet (kan geen live microfoon offline opnemen, uiteraard). Bepaalde worklets hebben een zorgvuldige state-reset nodig tussen online → offline overgangen. We hebben dit herhaaldelijk tegen gekomen en nu is Mixer.toJSON() + Mixer.fromJSON(offlineCtx) het canonieke patroon: serialiseer de mixerstatus, bouw een parallelle mixer op de offline context op, render.

9. Samenwerken via Yjs

Yjs is een CRDT-bibliotheek die meertalige samenwerkende bewerkingen met automatische conflictoplossing beheert. Onze SoundbendSession-klasse omvat Yjs met per-track documentstructuur (Y.Map voor track-metadata, Y.Array voor patroonstappen, Y.Text voor teksten/klanken).

Twee tot vier producenten kunnen tegelijkertijd hetzelfde project bewerken met sample-accurate track synchronisatie. Dit is moeilijker dan tekstdocumenten samenwerken omdat audiodata orders van grootte groter is — we delen metadata en patronen via Yjs, niet de ruwe audio. Ruwe samples blijven lokaal (IndexedDB per gebruiker).

10. Het prestatiebudget

Een volledige DAW in een browser uitvoeren met 60fps UI + realtime audio + SharedArrayBuffer + WASM + meerdere worklets vereist strakke budgetten. Enkele cijfers:

11. Null-test harness

DSP regressies zijn stil — audio klinkt op subtiele manieren anders die code review niet kan vaststellen. Soundbend wordt geleverd met een Puppeteer-geleide null-test harness in tests/audio-null/.

Voor elke effect × preset × testsignaal renderen de harness via OfflineAudioContext binnen een headless Chromium, null-test het resulterende WAV tegen een gecommit golden, en mislukt de build als de residuele piek -60 dBFS overschrijdt.

Wave 14F heeft 100 SeedSynth seed baselines en 32 Geist drum-pattern goldens toegevoegd. Toen we Soundbend in AudioStudio (Wave 14B-G) integreerden, ving de null-test alles op wat mogelijk onzichtbaar zou zijn gebroken. 96 van de 100 SeedSynth seeds zijn bit-identiek geslaagd. De 4 mislukkingen waren reeds bestaande Chromium Web Audio-quirks (hoge-Q filter resonantie drift tussen OfflineAudioContext instanties) — geen merge regressies, en niet te herstellen vanuit JS.

DSP regressies zijn stil. Code review kan ze niet horen. De null-test harness kan dat — daarom is het CI-blokkerend.

12. Waarom browser + client-side de juiste keuze was

Native DAW's (Ableton, Logic, FL Studio) hebben een voorsprong van 30 jaar. Het verslaan ervan functie voor functie is een lange weg. Maar prijsstelling — dat was direct te winnen door andere architecturale keuzes te maken.

WebAssembly heeft in 2022-2024 de prestatiebarrière overschreden. Web Audio AudioWorklets zijn rond dezelfde tijd wijdverspreid uitgebracht. SharedArrayBuffer + COOP/COEP is gestabiliseerd. Chromium, Firefox en Safari ondersteunen allemaal de nodige API's met voldoende prestaties.

De prijsimplicatie: als audioverwerking op het apparaat van de gebruiker plaatsvindt, betalen wij er niet voor. Onze marginale kosten per Pro-abonnee zijn bijna nul. Dus $4.99/mo is duurzaam voor altijd. Een kind in Lagos met een Android van 2020 krijgt een volledige DAW die iemand in San Francisco eveneens $4.99 betaalt om te gebruiken.

Lees de prijsarchitectuur essay voor de economie. Voor de DSP is dat het grootste deel van het verhaal.

Probeer het

Soundbend is te vinden op morph.cool/soundbend. De gratis tier werkt zonder registratie. $4,99/maand Pro activeert de mastering chain + true-peak limiter + extra voorinstellingen. WebMIDI toetsenbord welkom, niet vereist.

Open Soundbend

— Hayden + het Morph agent team
22 april 2026