Morph Blog
Engineering

Come abbiamo costruito un DAW nel tuo browser.

Lo Studio musicale funziona su WebAssembly, Web Audio API e 25 anni di ricerca su DSP — tutto lato client. La storia tecnica completa: grafo audio, worklets, porting di Airwindows, limitatore true-peak, host per plugin.

DAL TEAM MORPH12 MINUTI DI LETTURAAGGIORNATO APRILE 2026

Questa è una pubblicazione tecnica su come Morph's Studio musicale — un intero workstation digitale audio completo con 5 strumenti nativi, un Mixer con catene di effetti e invii ausiliari, 30+ effetti (inclusi 5 porting Tier-1 di Airwindows e un true-peak limiter), una rack di effetti MIDI, un host plugin WAM v2 e un layer di collaborazione Yjs CRDT — funziona interamente in una scheda del browser.

La domanda pratica è: questo è davvero competitivo con i DAW desktop? La risposta onesta: per la maggior parte dei flussi di lavoro dei produttori, sì. Per gli ecosistemi di dispositivi terzi profondi, non ancora. Apri Studio musicale per ascoltare il prodotto in prima persona. Questo post è l'aspetto tecnico.

Lo stack

1. Il grafico audio

Ogni traccia nello Studio musicale passa attraverso una catena: strumento → catena FX traccia → invio aux → striscia del mixer → bus master → limitatore → destinazione. Ogni freccia rappresenta una connessione Web Audio AudioNode.

Web Audio ci offre AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode e amici. Questi sono ottimizzati dai motori del browser (V8/SpiderMonkey/JSC investiti in profondità). Per effetti standard — EQ, automazione del guadagno, filtraggio di base — utilizziamo nodi nativi. Sono veloci e ben testati.

Per effetti personalizzati — porting di Airwindows, la nostra saturazione, il nostro true-peak limiter — passiamo a AudioWorkletProcessor, che funziona sul thread audio, garantendo priorità in tempo reale, e rappresenta il posto architetturale corretto per DSP non standard.

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);

I Worklets vengono distribuiti in public/audio-worklets/*.js e caricati tramite audioContext.audioWorklet.addModule(path). Una volta caricati, qualsiasi parte del grafico può istanziare un AudioWorkletNode per quel processore. L'elaborazione avviene fuori dal thread principale — le animazioni dell'interfaccia utente non interferiscono con l'audio.

2. Le 5 porte Tier-1 Airwindows

Chris Johnson's Airwindows è 2.500+ plugin audio, con licenza MIT, leggendariamente raffinati nel DSP. Abbiamo portato 5 plugin nel browser per AudioWorklets dello Studio musicale nella versione Wave 12:

Ogni porta è ~30-80 LOC di matematica in un AudioWorkletProcessor. Le porte non corrispondono bit per bit ad Airwindows (diversa gestione FMA/denormal tra motori numerici C++ e JS) ma corrispondono sonoricamente. I test null mantengono le uscite ≤ -80 dBFS rispetto ai riferimenti, quindi i cambiamenti DSP vengono rilevati.

3. Il limitatore di picco vero

Le piattaforme moderne di streaming (Spotify, Apple Music, YouTube) applicano la normalizzazione del livello di volume true-peak secondo ITU-R BS.1770-5. I picchi di campionamento e i picchi inter-campionamento sono cose diverse; un segnale può raggiungere -1 dBFS a livello di campione ma superare 0 dBFS true-peak dopo la ricostruzione D/A. Un limitatore non true-peak clipperà nel DAC anche se il tuo DAW lo mostra pulito.

Il nostro limitatore implementa specifiche complete ITU: 4x oversampling, rilevamento inter-sample-peak, lookahead, rilascio soft-knee. Viene fornito in formato AudioWorklet all'indirizzo public/audio-worklets/true-peak-limiter-processor.js.

4. Comunicazione fuori dal thread principale

Il grafico audio viene eseguito nel thread audio. L'interfaccia utente viene eseguita nel thread principale. Le modifiche ai parametri (ruotare un quadrante, attenuare una traccia) devono propagarsi dall'interfaccia utente → audio senza interruzioni audio.

Web Audio's AudioParam gestisce questo nativamente per i parametri standard (GainNode gain, BiquadFilterNode frequency). Per lavoro personalizzato, utilizziamo MessagePort con clonazione strutturata per i messaggi UI, e buffer anulari supportati da SharedArrayBuffer per dati di automazione ad alta frequenza.

SharedArrayBuffer richiede Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp headers. Questi sono impostati in public/_headers per le rotte /soundbend + /pulse. Il Tape Delay utilizza un buffer circolare a 96kHz per evitare la latenza delle porte di messaggio.

5. Le 5 strumenti native

Lo Studio musicale include 5 strumenti, tutti personalizzati:

Sintesi FM — sintesi FM a 6 operatori modellata su DX7 / Operator. Visualizzatore di algoritmi + matrice completa di modulazione. ~800 LOC JS per l'interfaccia utente, ~300 LOC per il worklet di allocazione vocale.

Sintetizzatore Wavetable — sintesi morph-between-tables. Warping spettrale + unisono + stereo detune. Oltre 30 wavetable factory. Utilizza ConvolverNode per il crossfade wavetable in tempo reale.

Analog Subtractive — polisintetizzatore a 2 oscillatori con filtri Cytomic SVF. Cytomic è la topologia dei filtri a variabile di stato che suona bene; il SVF naive presenta problemi di aliasing per fc > SR/6. La versione Cytomic gestisce questo tramite matematica a feedback a ritardo zero.

DrumRack + Sampler — riproduzione di campioni basata su pad con envelope di pitch/filtro/ampiezza per ogni pad. I campioni sono memorizzati in IndexedDB per un richiamo rapido. 5 kit factory specifici per genere (boombap, trap, house, dnb, afrobeat).

SeedSynth + Geist (nell'engine AudioStudioLegacy — ora integrato nello Studio musicale a partire dalla Wave 14) — un generatore di patch genetiche (Synplant 2-class) e una macchina ritmica di stile Geist. Questi sono i brevetti proprietari che hanno reso la dottrina di consolidamento un grande successo — abbiamo dovuto preservare il comportamento identico a bit attraverso un merge di 30k linee. Test nullo a 100 semi superato post-merge.

6. Il Mixer + invii ausiliari

Un Mixer adeguato — non solo equalizzatori per traccia ma inserimenti FX per traccia, invii ausiliari pre/post-fader, bus master — è ciò che distingue un DAW da un sequencer. Il Mixer dello Studio musicale è class ~655 LOC (src/audio/mixer.js). Ogni traccia è un grafico AudioNode con slot di inserimento, punti di tap per invii e misurazione.

La parte difficile è distinguere tra invii aux pre-fader e post-fader. Gli invii pre-fader vengono inviati a un bus di riverbero indipendentemente dal volume della traccia (uso classico: riverbero parallelo che sopravvive a una riduzione del volume della traccia). Gli invii post-fader variano in proporzione al volume della traccia. Entrambi sono disponibili.

7. MIDI + WAM plugin host

WebMIDI è maturo — l'input del controller da qualsiasi tastiera USB-MIDI funziona semplicemente. La nostra rack MIDI (Arpeggiatore, Scala, Accordi) si trova tra il controller e l'strumento, trasformando i flussi di note.

Per i plugin, ospitiamo Web Audio Modules v2 (WAM) — plugin nativi del browser. L'ecosistema è più piccolo rispetto a VST (25 anni di vantaggio) ma in crescita. Il caricamento di un WAM avviene con getWamHost().load(wamUri), che restituisce un AudioNode che puoi inserire in qualsiasi catena.

I WAM richiedono un CSP per route perché caricano JS forniti dall'utente arbitrario. I nostri _headers limitano strettamente il CSP per /soundbend con un allow-list script-src per registri WAM noti.

8. OfflineAudioContext per rimbalzo

L'esportazione avviene tramite OfflineAudioContext — elabora più velocemente del tempo reale (o più lentamente, a seconda della complessità della catena) in un AudioBuffer statico, quindi codifica in WAV tramite il nostro encoder in-browser.

Avvertenza: non tutti i nodi funzionano in OfflineAudioContext. MediaStreamAudioSourceNode non funziona (non è possibile registrare un microfono live offline, ovviamente). Alcuni worklet richiedono una reimpostazione accurata dello stato tra transizioni online → offline. Ci siamo imbattuti ripetutamente in questo problema e ora Mixer.toJSON() + Mixer.fromJSON(offlineCtx) è il modello canonico: serializza lo stato del mixer, ricostruisci un mixer parallelo nel contesto offline, renderizza.

9. Collaborazione tramite Yjs

Yjs è una libreria CRDT che gestisce l'editing collaborativo multi-utente con risoluzione automatica dei conflitti. La nostra classe SoundbendSession avvolge Yjs con una struttura documentale per traccia (Y.Map per i metadati della traccia, Y.Array per i passi del pattern, Y.Text per testi/notes).

Due a quattro produttori possono modificare lo stesso progetto contemporaneamente con sincronizzazione dei tracce accurata a livello di campione. Questo è più difficile che collaborare su documenti testuali perché i dati audio sono di ordini di grandezza più grandi: condividiamo metadati e schemi tramite Yjs, non i dati audio grezzi. I campioni grezzi rimangono locali (IndexedDB per utente).

10. Budget di prestazioni

Eseguire un DAW completo in un browser con interfaccia utente a 60fps + audio in tempo reale + SharedArrayBuffer + WASM + più worklet richiede un bilancio preciso. Alcuni numeri:

11. Test harness di null

Le regressioni DSP sono silenziose — l'audio suona diverso in modi sottili che una revisione del codice non può rilevare. Lo Studio musicale include un test harness guidato da Puppeteer in tests/audio-null/.

Per ogni effetto × preset × segnale di test, il sistema genera tramite OfflineAudioContext all'interno di Chromium headless, esegue test null sul risultato WAV confrontandolo con un golden commit, e fallisce la build se il picco residuo supera -60 dBFS.

Wave 14F ha aggiunto 100 baselines SeedSynth e 32 pattern drum Geist goldens. Quando abbiamo integrato Studio musicale in AudioStudio (Wave 14B-G), il test null ha rilevato qualsiasi cosa che avrebbe potuto rompere silenziosamente gli strumenti proprietari. 96 su 100 seed SeedSynth hanno superato il test bit-identico. I 4 fallimenti erano già presenti in Chromium Web Audio (drift di risonanza del filtro ad alto Q tra istanze di OfflineAudioContext) — non regressioni di fusione e non risolvibili da JS.

Le regressioni DSP sono silenziose. La revisione del codice non le può sentire. L'ambiente di test null lo può fare — ed è per questo che blocca la CI.

12. Perché browser + client-side è stata la scelta giusta

I DAW nativi hanno un vantaggio di 30 anni. Superarli funzionalità per funzionalità è una strada lunga. Ma il prezzo — questo era un obiettivo raggiungibile immediatamente scegliendo architetture diverse.

WebAssembly ha superato la soglia di prestazioni nel 2022-2024. Web Audio AudioWorklets sono stati distribuiti ampiamente nello stesso periodo. SharedArrayBuffer + COOP/COEP è stato stabilizzato. Chromium, Firefox e Safari supportano tutti le API necessarie con prestazioni adeguate.

L'implicazione dei prezzi: se l'elaborazione audio viene eseguita sul dispositivo dell'utente, non dobbiamo pagare per essa. Il nostro costo marginale per ogni abbonato Pro è quasi nullo.

Leggi il manifesto per l'economia. Per il DSP, questa è gran parte della storia.

Provalo

Lo Studio musicale è su morph.cool/music-studio. La versione gratuita funziona senza registrazione. La tastiera WebMIDI è benvenuta, ma non obbligatoria.

Apri lo Studio musicale

— il team Morph
22 aprile 2026