Ceci est un article technique sur la façon dont Morph's Soundbend — une station de travail numérique audio complète incluant 5 instruments natifs, un Mixer avec des chaînes d'effets et des envois auxiliaires, 30+ effets (dont 5 ports Airwindows Tier-1 et un limiteur true-peak), une rack d'effets MIDI, un hôte de plugins WAM v2, et une couche de collaboration Yjs CRDT — fonctionne entièrement dans un onglet navigateur.
La question pratique est : est-ce que ceci est réellement compétitif avec Ableton ? La réponse honnête : pour la plupart des workflows de producteur, oui. Pour les intégrations profondes avec Max for Live, pas encore. Lisez la comparaison avec Ableton pour une analyse au niveau du produit. Ce post est l'ingénierie.
La pile
- Frontend React + Vite
- Web Audio API pour le graphique audio
- AudioWorkletProcessor pour DSP personnalisé (hors-thread principal)
- WebAssembly pour les traitements DSP critiques en performance (builds WASM personnalisés)
- MessagePort + ring buffers pour la communication UI ↔ worklet
- Yjs pour la collaboration CRDT
- IndexedDB pour la persistance des projets + stockage d'échantillons
- WebMIDI pour l'entrée des contrôleurs matériels
- OfflineAudioContext pour rebond/export
1. Le graphique audio
Chaque piste dans Soundbend suit une chaîne : instrument → chaîne d'effets de piste → envoi auxiliaire → bande de mixage → bus principal → limiteur → destination. Chaque flèche représente une connexion Web Audio AudioNode.
Web Audio nous donne AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode et autres. Ces éléments sont optimisés par les moteurs de navigateur (V8/SpiderMonkey/JSC investis en profondeur). Pour les effets standards — EQ, automation de gain, filtrage de base — nous utilisons des nœuds natifs. Ils sont rapides et bien testés.
Pour des effets personnalisés — ports Airwindows, notre saturation, notre limiteur true-peak — nous passons à AudioWorkletProcessor, qui s'exécute sur le thread audio, avec une priorité temps réel garantie, et est l'emplacement architectural correct pour un 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);
Les Worklets sont livrés dans public/audio-worklets/*.js et sont chargés via audioContext.audioWorklet.addModule(path). Une fois chargés, n'importe quelle partie du graphique peut instancier un AudioWorkletNode pour ce processeur. Le traitement s'exécute hors du thread principal — les animations de l'interface utilisateur ne perturbent pas l'audio.
2. Les 5 ports Tier-1 Airwindows
Chris Johnson's Airwindows est 2 500+ plugins audio, sous licence MIT, légendairement savoureux en DSP. Nous avons porté 5 plugins vers AudioWorklets du navigateur pour Wave 12 de Soundbend :
- Pressure6 — compression transparente qui respire
- ToTape9 — modélisation de saturation de bande analogique
- PurestDrive — saturation à phase minimale sans aigus durs
- CreamCoat — chaleur + excitateur harmonique
- NotJustAnotherDither — Dither TPDF pour réduction de profondeur de bits (maîtrise)
Chaque port est ~30-80 LOC de mathématiques dans un AudioWorkletProcessor. Les ports ne correspondent pas bit à bit à Airwindows (différents traitements FMA/dénormaux entre les moteurs numériques C++ et JS) mais correspondent soniquement. Les tests nuls maintiennent les sorties ≤ -80 dBFS résiduels par rapport aux références, donc les changements DSP sont détectés.
3. Le limiteur de crête réel
Les plateformes de streaming modernes (Spotify, Apple Music, YouTube) appliquent la normalisation du niveau sonore vrai-pic selon ITU-R BS.1770-5. Les pics d'échantillonnage et les pics inter-échantillonnage sont des choses différentes ; un signal peut atteindre -1 dBFS au niveau de l'échantillon mais dépasser 0 dBFS vrai-pic après la reconstruction D/A. Un limiteur non-vrai-pic clippera dans le DAC même si votre DAW l'affiche propre.
Notre limiteur implémente spécifiquement la norme ITU : 4x échantillonnage, détection des pics inter-échantillons, lookahead, relâchement à knee doux. Il est livré sous forme d'AudioWorklet à public/audio-worklets/true-peak-limiter-processor.js. Les mesures par rapport aux implémentations de référence (Oxford Limiter, iZotope Ozone Maximizer) correspondent à moins de 0,1 dB sur LUFS intégré.
4. Communication hors-thread principale
Le graphique audio s'exécute sur le thread audio. L'interface utilisateur s'exécute sur le thread principal. Les modifications des paramètres (tourner un bouton, atténuer une piste) doivent se propager de l'interface utilisateur vers l'audio sans perturber le son.
Web Audio utilise nativement AudioParam pour les paramètres standards (GainNode gain, BiquadFilterNode frequency). Pour les travaux personnalisés avec worklet, nous utilisons MessagePort avec clonage structuré pour les messages UI, et des tampons circulaires basés sur SharedArrayBuffer pour les données d'automatisation à haut débit.
SharedArrayBuffer nécessite Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp dans les en-têtes. Ces en-têtes sont définis dans public/_headers pour les routes /soundbend + /pulse. Le Tape Delay utilise un tampon circulaire à 96 kHz pour éviter la latence des ports de message.
5. Les 5 instruments natifs
Soundbend embarque 5 instruments, tous personnalisés :
Synthèse FM — Synthèse FM à 6 opérateurs modélisée sur DX7 / Operator. Visualiseur d'algorithme + matrice de modulation complète. ~800 LOC JS pour l'interface, ~300 LOC pour le worklet de gestion des voix.
Synthé wavetable — synthèse morph-between-tables. Déformation spectrale + unison + détune stéréo. 30+ tables de formes d'onde par défaut. Utilise ConvolverNode pour le fondu croisé de wavetable à vitesse audio.
Analog Subtractive — polysynthé avec 2 oscillateurs et filtres Cytomic SVF. Cytomic est la topologie de filtre à variable d'état qui sonne juste ; une SVF naive présente des problèmes d'aliasing au-delà de fc > SR/6. La portée Cytomic gère cela via des mathématiques de rétroaction à retard zéro.
DrumRack + Sampler — lecture d'échantillons par pads avec enveloppes de hauteur, filtre et ampli par pad. Les échantillons sont stockés dans IndexedDB pour un rappel rapide. 5 kits d'usine spécifiques aux genres (boombap, trap, house, dnb, afrobeat).
SeedSynth + Geist (dans le moteur AudioStudioEngine hérité — désormais intégré à Soundbend depuis la Wave 14) — un générateur de patch génétique (Synplant 2-class) et une machine à batterie de style Geist. Ce sont les brevets propriétaires qui ont rendu la doctrine de consolidation importante — nous avons dû préserver un comportement identique à l'octet après une fusion de 30 000 lignes. Test null de 100 graines réussi après la fusion.
6. Le Mixer + envois auxiliaires
Un véritable Mixer — non pas seulement des faders par piste mais des inserts d'effets par piste, des envois auxiliaires pré/post-fader, bus master — est ce qui distingue un DAW d'un séquenceur. Le Mixer de Soundbend est classé ~655 LOC (src/audio/mixer.js). Chaque piste est un graphe AudioNode avec des emplacements d'insertion, des points de prise pour les envois et un compteur.
La partie délicate est la différence entre les envois auxiliaires pré-fader et post-fader. Les envois pré-fader vont vers un bus de réverbération indépendamment du volume de la piste (utilisation classique : réverbération parallèle qui survit à une atténuation de piste). Les envois post-fader évoluent avec le volume de la piste. Les deux sont disponibles.
7. Hôte de plugins MIDI + WAM
WebMIDI est mature — les entrées de contrôle à partir de n'importe quel clavier MIDI USB fonctionnent parfaitement. Notre rack MIDI (Arpeggiator, Scale, Chord) se situe entre le contrôleur et l'instrument, transformant les flux de notes.
Pour les plugins, nous hébergeons Web Audio Modules v2 (WAM) — des plugins natifs au navigateur. Écosystème plus petit que VST (avance de 25 ans) mais en croissance. Charger un WAM se fait avec getWamHost().load(wamUri), ce qui renvoie un AudioNode que vous pouvez insérer dans n'importe quelle chaîne.
Les WAM nécessitent un CSP par route car ils chargent du JS fourni par l'utilisateur arbitraire. Nos _headers limitent étroitement le CSP pour /soundbend avec une liste autorisée script-src pour les registres WAM bien connus.
8. OfflineAudioContext pour rebondir
L'exportation s'effectue via OfflineAudioContext — rendu plus rapide que temps réel (ou plus lent, selon la complexité de la chaîne) vers un AudioBuffer statique, puis encodage en WAV via notre encodeur intégré.
Attention : tous les nœuds ne fonctionnent pas dans OfflineAudioContext. MediaStreamAudioSourceNode ne fonctionne pas (impossible d'enregistrer un micro en direct hors ligne, évidemment). Certains worklets nécessitent une réinitialisation soigneuse de l'état entre les transitions en ligne → hors ligne. Nous avons rencontré ce problème à plusieurs reprises et maintenant Mixer.toJSON() + Mixer.fromJSON(offlineCtx) est le modèle canonique : sérialisez l'état du mixer, reconstruisez un mixer parallèle dans le contexte hors ligne, puis effectuez le rendu.
9. Collaboration via Yjs
Yjs est une bibliothèque CRDT qui gère l'édition collaborative multi-utilisateurs avec résolution automatique des conflits. Notre classe SoundbendSession enveloppe Yjs avec une structure de document par piste (Y.Map pour les métadonnées de piste, Y.Array pour les étapes de motif, Y.Text pour les paroles/remarques).
Deux à quatre producteurs peuvent éditer le même projet simultanément avec une synchronisation précise au niveau des échantillons. Cela est plus difficile que la collaboration sur des documents texte car les données audio sont d'un ordre de grandeur supérieur — nous partageons les métadonnées et les schémas via Yjs, pas les données brutes. Les échantillons bruts restent locaux (IndexedDB par utilisateur).
10. Budget de performance
Exécuter une DAW complète dans un navigateur avec une interface utilisateur à 60 fps + audio en temps réel + SharedArrayBuffer + WASM + plusieurs worklets nécessite des budgets serrés. Quelques chiffres :
- Fil audio : ~2 ms / tampon de 128 échantillons à 48 kHz (sous-trame)
- Thread principal : 16,6ms / 60fps par image ; la gestion audio doit rester <1ms par image
- Configuration du Worklet : coût unique de ~10-50ms par chargement de worklet (livrer 15+ worklets — nous regroupons)
- Allocation de SharedArrayBuffer : tampons circulaires de 4 Ko par paramètre de worklet dynamique
- Taille du chunk Soundbend (après consolidation) : ~496 Ko bruts, ~120 Ko gzip
- Chargement complet du projet (froid) : ~800 ms sur un ordinateur portable moyen
- Export render : ~0,3x à 2x temps réel selon la complexité de la chaîne d'effets
11. Ensemble de tests null
Les régressions DSP sont silencieuses — l'audio sonne différemment de manières subtiles que la revue de code ne peut détecter. Soundbend est livré avec un ensemble de tests piloté par Puppeteer dans tests/audio-null/.
Pour chaque effet × préréglage × signal de test, le système de test génère via OfflineAudioContext dans un Chromium headless, teste null le résultat WAV contre un golden commité, et échoue la construction si le pic résiduel dépasse -60 dBFS.
Wave 14F a ajouté 100 bases de graines SeedSynth et 32 motifs de batterie Geist dorés. Lorsque nous avons fusionné Soundbend dans AudioStudio (Wave 14B-G), le test null a détecté tout ce qui aurait pu briser silencieusement les instruments propriétaires. 96 des 100 graines SeedSynth ont passé le test bit-identique. Les 4 échecs étaient dus à des défauts préexistants dans Chromium Web Audio (drift de résonance du filtre à haute qualité entre les instances OfflineAudioContext) — pas des régressions de fusion, et non corrigibles depuis JavaScript.
Les régressions DSP sont silencieuses. La revue de code ne peut pas les entendre. Le dispositif de test null le peut — c'est pourquoi il bloque la CI.
12. Pourquoi le navigateur + client-side était le bon choix
Les DAW natives (Ableton, Logic, FL Studio) ont un avantage de 30 ans. Battre ces outils fonctionnalité par fonctionnalité est une longue route. Mais prix — cela pouvait être gagné immédiatement en faisant des choix architecturaux différents.
WebAssembly a franchi la barrière des performances entre 2022 et 2024. Les Web Audio AudioWorklets ont été largement disponibles autour de la même période. SharedArrayBuffer + COOP/COEP a stabilisé. Chromium, Firefox et Safari prennent tous en charge les API nécessaires avec des performances adéquates.
The pricing implication: if audio processing runs on the user's device, we don't pay for it. Our marginal cost per Pro subscriber is near-zero. So $4.99/mo is sustainable forever. A kid in Lagos with a 2020 Android gets a full DAW that someone in San Francisco pays the same $4.99 to access.
Lisez l'essai sur l'architecture des prix pour les détails économiques. Pour le DSP, c'est la majeure partie de l'histoire.
Essayez-le
Soundbend est à morph.cool/soundbend. La version gratuite fonctionne sans inscription. Le Pro à 4,99 $/mois débloque la chaîne de mastering + limiteur de crête réelle + pré-réglages supplémentaires. Clavier WebMIDI bienvenu, mais non requis.
— Hayden + l'équipe d'agents Morph
22 avril 2026