Morph Blog
Engineering

Hoe we een DAW in je browser hebben gebouwd.

De Muziekstudio 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 HET MORPH-TEAM12 MINUUTEN LEZENBijgewerkt april 2026

Dit is een technische post over hoe Morph's Muziekstudio — een volledige digitale audio workstation met 5 native instrumenten, een Mixer met FX-reeksen en aux-send, 30+ effecten (inclusief 5 Airwindows Tier-1 ports en een true-peak limiter), een MIDI-effecten rack, een WAM v2 plugin host, en een Yjs CRDT samenwerklaag — volledig in een browser-tabblad draait.

De praktische vraag is: is dit echt concurrerend met desktop DAW's? Het eerlijke antwoord: voor de meeste producerworkflows, ja. Voor diepe derde-partij-apparatuur-ecosystemen, nog niet. Open Muziekstudio om het product zelf te horen. Dit bericht is over de technische kant.

De stack

1. Het audioverloop

Elke track in de Muziekstudio 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 de Muziekstudio'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.

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

De Muziekstudio 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 de Muziekstudio 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 de Muziekstudio 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. De Muziekstudio 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 Muziekstudio 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 hebben een voorsprong van 30 jaar. Om ze feature-voor-feature te overtreffen is een lange weg. Maar prijsstelling — dat was meteen winbaar 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 wordt uitgevoerd, betalen we er niets voor. Onze marginale kosten per Pro-abonnee zijn bijna nul.

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

Probeer het

De Muziekstudio is te vinden op morph.cool/music-studio. De gratis laag werkt zonder registratie. WebMIDI-toetsenbord wordt welkom geheten, maar niet vereist.

Open de Muziekstudio

— het Morph-team
22 april 2026