To jest techniczny post o tym, jak Morph Soundbend — pełny cyfrowy system dźwiękowy z 5 wbudowanymi instrumentami, mikserem z łańcuchami efektów i pomocniczymi wysyłkami, 30+ efektami (w tym 5 portów Airwindows Tier-1 i prawdziwym limiterem true-peak), szafą MIDI z efektami, hostem wtyczek WAM v2 oraz warstwą współpracy Yjs CRDT — działa całkowicie w karcie przeglądarki.
Prawdziwe pytanie brzmi: czy to rzeczywiście jest konkurencyjne z Abletonem? Szczera odpowiedź: dla większości prac producentów, tak. Dla głębokiej integracji Max for Live, jeszcze nie. Przeczytaj porównanie alternatywy dla Abletona dla szczegółów na poziomie produktu. Ten post to inżynieria.
Stos
- Frontend na React + Vite
- Web Audio API dla grafu dźwiękowego
- AudioWorkletProcessor dla niestandardowych DSP (poza głównym wątkiem)
- WebAssembly dla wydajnościowych obliczeń DSP (niestandardowe budowy WASM)
- MessagePort + ring buffers for UI ↔ worklet communication
- Yjs dla współpracy CRDT
- IndexedDB dla przechowywania projektów i próbek
- WebMIDI dla wejścia z kontrolera sprzętowego
- OfflineAudioContext dla bounce/export
1. Grafika dźwiękowa
Każda ścieżka w Soundbend przechodzi przez łańcuch: instrument → łańcuch efektów ścieżki → wysyłka do pomocniczego → pasek miksera → główna magistrala → limiter → cel. Każdy strzałka to połączenie Web Audio AudioNode.
Web Audio daje nam AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode i inne. Są one zoptymalizowane przez silniki przeglądarek (V8/SpiderMonkey/JSC głęboko zaangażowane). Dla standardowych efektów — EQ, automatyzacja głośności, podstawowe filtry — używamy natywnych węzłów. Są one szybkie i dobrze przetestowane.
Dla niestandardowych efektów — porty Airwindows, nasza saturacja, nasz prawdziwy limiter szczytowy — wchodzimy do AudioWorkletProcessor, który działa na wątku audio, gwarantując real-time priorytet, i jest poprawnym miejscem architekturalnym dla niestandardowych 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);
Worklety są dostarczane w public/audio-worklets/*.js i ładują się za pomocą audioContext.audioWorklet.addModule(path). Po załadowaniu dowolna część grafu może zainicjować AudioWorkletNode dla tego procesora. Przetwarzanie odbywa się poza głównym wątkiem — animacje interfejsu nie zatrzymują dźwięku.
2. 5 portów Airwindows Tier-1
Chris Johnson's Airwindows to 2 500+ dźwiękowych wtyczek, licencjonowanych na zasadach MIT, legendarnie smakowitych DSP. Przenosimy 5 z nich do przeglądarki w postaci AudioWorklets dla Wave 12 w Soundbend:
- Pressure6 — przezroczysta kompresja, która oddycha
- ToTape9 — modelowanie saturacji taśm analogowych
- PurestDrive — minimalna saturacja bez szorstkich wysokich tonów
- CreamCoat — ciepło + harmoniczny ekscyter
- NotJustAnotherDither — TPDF dither dla redukcji głębi bitowej (mastering)
Każdy port to ~30-80 linii kodu matematycznego w AudioWorkletProcessor. Porty nie są zgodne bit po bit z Airwindows (różne obsługę FMA/denormal między silnikami numerycznymi C++ i JS), ale są dźwiękowo zgodne. Testy null utrzymują wyjścia ≤ -80 dBFS względem oryginałów, więc zmiany DSP są wykrywane.
3. Prawdziwy limiter szczytowy
Nowoczesne platformy streamingowe (Spotify, Apple Music, YouTube) wymagają prawdziwej głośności szczytowej zgodnie z ITU-R BS.1770-5. Szczytowe próbki i szczytowe próbki międzypróbki to różne rzeczy; sygnał może osiągać -1 dBFS na poziomie próbek, ale przekroczyć 0 dBFS prawdziwej głośności szczytowej po konwersji D/A. Nieprawdziwy limiter głośności przycina w DAC, nawet jeśli Twój DAW pokazuje, że jest czysty.
Nasza limiter implementuje pełny specyfikację ITU: 4x próbkowanie nadprzeciętnego, wykrywanie inter-peak, lookahead, miękki mechanizm zwalniania. Dostarczany jest w formie AudioWorklet pod public/audio-worklets/true-peak-limiter-processor.js. Pomiar względem implementacji referencyjnych (Oxford Limiter, iZotope Ozone Maximizer) zgadza się w granicach 0,1 dB na LUFS zintegrowany.
4. Komunikacja poza głównym wątkiem
Wykres dźwiękowy działa na wątku dźwiękowym. Interfejs użytkownika działa na głównym wątku. Zmiany parametrów (obracanie pokrętła, fade tracku) muszą być przekazywane z UI → audio bez zakłóceń dźwięku.
Web Audio's AudioParam obsługuje to natywnie dla standardowych parametrów (GainNode gain, BiquadFilterNode frequency). Dla własnych prac z workletem, używamy MessagePort z strukturalnym klonowaniem dla komunikatów interfejsu, a SharedArrayBuffer-backed ring buffers dla danych automatyzacji o wysokiej częstotliwości.
SharedArrayBuffer wymaga Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp nagłówków. Są one ustawione w public/_headers dla tras /soundbend + /pulse. Tape Delay używa bufora kołowego na 96kHz, aby uniknąć opóźnień wiadomości.
5. 5 natywnych instrumentów
Soundbend dostarcza 5 instrumentów, wszystkie niestandardowe:
FM Synth — syntezator FM z 6 operatorami modelowany na DX7 / Operator. Wizualizator algorytmu + pełny macierz modulacji. ~800 LOC JS dla interfejsu, ~300 LOC worklet dla alokatora głosu.
Wavetable Synth — syntezator między tabelami. Wymiana spektralna + unison + stereodetune. 30+ fabrycznych tabel. Używa ConvolverNode do przeplotu tabel na poziomie dźwięku.
Analog Subtractive — syntezator wielofrekencyjny z 2 oscylatorami i filtrami Cytomic SVF. Cytomic to topologia filtru zmiennego, która brzmi dobrze; prosta topologia SVF ma problemy z aliasingiem powyżej fc > SR/6. Port Cytomic rozwiązuje to za pomocą matematyki zero-delay feedback.
DrumRack + Sampler — odtwarzanie próbek oparte na padach z osobistymi ustawieniami wysokości dźwięku, filtru i głośności na każdy pad. Próbki przechowywane w IndexedDB dla szybkiego odzyskania. 5 fabrycznych zestawów dla różnych gatunków (boombap, trap, house, dnb, afrobeat).
SeedSynth + Geist (w dziedziczonej AudioStudioEngine — teraz scalone z Soundbend od Wave 14) — generator genetyczny (Synplant 2-class) i perkusyjny generator stylu Geist. To są własne IP, które sprawiły, że konsolidacja stworzyła dużą sensację — musieliśmy zachować identyczność bitową przez scalenie 30k linii kodu. Przetestowano 100-seed null-test po scaleniu.
6. Mixer + wysyłki pomocnicze
Prawdziwy Mixer — nie tylko regulatory poziomu na poszczególnych śledach, ale także wtyczki efektów na poszczególnych śledach, pre/post-fader aux sends, bus główny — to co oddziela DAW od sequencer'a. Mixer w Soundbend ma ~655 linii kodu (src/audio/mixer.js). Każdy śled jest grafem AudioNode z miejscami na wtyczki, punktami do podłączenia wysyłek i metrami.
Trudnym elementem jest pre-fader vs post-fader aux sends. Pre-fader wysyła do busu rewerberacji niezależnie od głośności ścieżki (klasyczne zastosowanie: równoległa rewerberacja, która przetrwa spadek głośności ścieżki). Post-fader skaluje się z głośnością ścieżki. Oba są domyślnie włączone.
7. MIDI + WAM plugin host
WebMIDI jest dojrzałym standardem — wejście kontrolera z dowolnej klawiatury USB-MIDI działa natychmiast. Nasz rack MIDI (Arpeggiator, Skala, Akord) znajduje się między kontrolerem a instrumentem, przekształcając strumienie nut.
Dla wtyczek hostujemy Web Audio Modules v2 (WAM) — wtyczki natively dla przeglądarki. Mniejsza ekosystem niż VST (25-letni przewaga) ale rośnie. Załadowanie WAM odbywa się przez getWamHost().load(wamUri), które zwraca AudioNode, który możesz wstawić do dowolnej łańcuchu.
WAMs wymagają per-route CSP, ponieważ ładują dowolny, dostarczony przez użytkownika JS. Nasze _headers ograniczają CSP dla /soundbend za pomocą listy dozwolonych script-src dla znanych rejestrów WAM.
8. OfflineAudioContext dla bounce
Eksport działa poprzez OfflineAudioContext — renderuje szybciej niż w czasie rzeczywistym (lub wolniej, w zależności od złożoności łańcucha) do statycznego AudioBuffer, a następnie koduje do WAV za pomocą naszego w przeglądarce kodera.
Uwaga: nie wszystkie węzły działają w OfflineAudioContext. MediaStreamAudioSourceNode nie działa (nie można rejestrować mikrofonu na żywo w trybie offline, oczywiście). Niektóre worklety wymagają starannego resetu stanu między przejściami online → offline. Napotkaliśmy to wielokrotnie i teraz Mixer.toJSON() + Mixer.fromJSON(offlineCtx) jest kanonicznym wzorcem: serializuj stan mixer, zbuduj równoległy mixer w kontekście offline, renderuj.
9. Współpraca przez Yjs
Yjs to biblioteka CRDT obsługująca współbieżną edycję wielu użytkowników z automatycznym rozwiązywaniem konfliktów. Nasza klasa SoundbendSession otacza Yjs w strukturze dokumentu na poziomie ścieżki (Y.Map dla metadanych ścieżki, Y.Array dla kroków wzoru, Y.Text dla tekstu/notek).
Dwa do czterech producentów może jednocześnie edytować ten sam projekt z synchronizacją śledzenia próbek. Jest to trudniejsze niż współpraca w dokumentach tekstowych, ponieważ dane audio są o kilka rzędów wielkości większe — dzielimy się metadane i wzory przez Yjs, a nie surowym dźwiękiem. Surowe próbki pozostają lokalnie (IndexedDB na użytkownika).
10. Budżet wydajności
Uruchomienie pełnego DAW w przeglądarce z interfejsem 60fps + dźwiękiem w czasie rzeczywistym + SharedArrayBuffer + WASM + wiele workletów wymaga precyzyjnego zarządzania zasobami. Niektóre liczby:
- Wątek audio: ~2ms / bufor 128 próbek przy 48kHz (podramka)
- Główny wątek: 16,6ms / 60fps; obsługa dźwięku musi pozostać <1ms na klatkę
- Ustawienie Worklet: jednorazowy koszt ~10-50ms na ładowanie workletu (wysyłka 15+ workletów — grupujemy)
- Przydział SharedArrayBuffer: 4KB buforów pierścieniowych na każdy dynamiczny parametr workletu
- Rozmiar fragmentu Soundbend (po konsolidacji): ~496 KB surowe, ~120 KB gzip
- Pełne załadowanie projektu (zimny start): ~800 ms na laptopie średniej klasy
- Eksport renderowania: ~0,3x do 2x szybciej niż w czasie rzeczywistym w zależności od złożoności łańcucha efektów
11. Testowy harmonogram null
Regressje DSP są niezauważalne — dźwięk brzmi inaczej w subtelny sposób, który nie można złapać w przeglądzie kodu. Soundbend dostarcza zintegrowany test null w tests/audio-null/ oparty na Puppeteer.
Dla każdego efektu × preset × sygnału testowego, narzędzie renderuje za pomocą OfflineAudioContext w bezgłowym Chromium, przeprowadza null-test wynikowego WAV w porównaniu z zatwierdzonym złotym, i zatrzymuje budowę, jeśli residualny szczyt przekracza -60 dBFS.
Wave 14F dodał 100 podstaw seed baselines dla SeedSynth i 32 złote wzory perkusyjne Geist. Gdy połączyliśmy Soundbend z AudioStudio (Wave 14B-G), test null wykrył wszystko, co mogłoby niezauważalnie uszkodzić instrumenty propetryczne. 96 z 100 nasion SeedSynth przeszło bit-identycznie. 4 błędy były już istniejącymi wadami Chromium Web Audio (drift rezonansu filtra wysokim-Q między instancjami OfflineAudioContext) — nie były to regresje połączenia i nie dało się ich naprawić z JavaScriptu.
DSP-regresje są cisze. Przegląd kodu nie może ich słyszeć. Testowy zestaw null-testów może — dlatego jest blokujący w CI.
12. Dlaczego przeglądarka + klient-side to była dobra decyzja
Natywne DAW (Ableton, Logic, FL Studio) mają 30-letnie przewagę. Przecięcie ich funkcjonalności krok po kroku to długa droga. Ale cena — to było możliwe do wygrania natychmiast, wybierając inne architekturę.
WebAssembly przekroczył próg wydajności w latach 2022-2024. Web Audio AudioWorklets zostały szeroko wdrożone w tym samym czasie. SharedArrayBuffer + COOP/COEP został stabilizowany. Chromium, Firefox i Safari wszystkie obsługują potrzebne interfejsy API z odpowiednią wydajnością.
Skutki cenowe: jeśli przetwarzanie dźwięku odbywa się na urządzeniu użytkownika, nie płacimy za to. Nasz koszt marginalny na subskrybenta Pro jest bliski zera. Dlatego $4.99/mo jest trwały na zawsze. Dziecko w Lagos z Androidem z 2020 roku dostaje pełny DAW, który ktoś w San Francisco płaci za ten sam $4.99, aby uzyskać dostęp.
Przeczytaj esej o architekturze cenowej, aby zrozumieć ekonomię. Dla DSP, to jest większość historii.
Wypróbuj
Soundbend znajduje się pod morph.cool/soundbend. Wersja bezpłatna działa bez rejestracji. $4,99/mc Pro umożliwia dostęp do łańcucha masteringowego + prawdziwego limitera szczytowego + dodatkowych presetów. Klawiatura WebMIDI jest mile widziana, ale nie jest wymagana.
— Hayden + zespół agenta Morph
22 kwietnia 2026