이것은 Morph의 Soundbend에 대한 기술적 설명으로, 완전한 디지털 오디오 작업대(5개의 네이티브 악기, FX 체인과 AUX 송신이 있는 믹서, 30개 이상의 효과(5개의 Airwindows Tier-1 포트와 진짜 피크 리미터 포함), MIDI 효과 랙, WAM v2 플러그인 호스팅, Yjs CRDT 협업 계층 포함)가 브라우저 탭에서 전체적으로 실행된다는 내용입니다.
The practical question is: is this actually competitive with Ableton? The honest answer: for most producer workflows, yes. For deep Max for Live integrations, not yet. Read the Ableton alternative comparison for the product-level breakdown. This post is the engineering.
스택
- React + Vite 프론트엔드
- Web Audio API를 사용하여 오디오 그래프를 구축합니다.
- 사용자 정의 DSP(메인 스레드에서 분리)를 위한 AudioWorkletProcessor
- 성능이 중요한 DSP(사용자 정의 WASM 빌드)를 위한 WebAssembly
- MessagePort + ring buffers를 통한 UI ↔ worklet 통신
- Yjs를 통한 CRDT 협업
- 프로젝트 지속성 및 샘플 저장을 위한 IndexedDB
- 하드웨어 컨트롤러 입력을 위한 WebMIDI
- OfflineAudioContext를 통한 바운스/내보내기
1. 오디오 그래프
Soundbend의 모든 트랙은 다음 체인을 통해 라우팅됩니다: 악기 → 트랙 FX 체인 → 보조 송신 → 믹서 스트립 → 마스터 버스 → 리미터 → 대상. 각 화살표는 Web Audio AudioNode 연결을 나타냅니다.
Web Audio는 AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode 및 기타를 제공합니다. 이들은 브라우저 엔진(V8/SpiderMonkey/JSC 모두 깊이 투자)에 의해 최적화됩니다. 표준 효과 — EQ, 게인 자동화, 기본 필터링 —에는 네이티브 노드를 사용합니다. 이들은 빠르고 잘 테스트되었습니다.
사용자 정의 효과를 위해 — Airwindows 포트, 우리의 포화, 진정한 피크 리미터 — 우리는 AudioWorkletProcessor로 내려가며, 이는 오디오 스레드에서 실행되며, 보장된 실시간 우선순위를 가지며, 비표준 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는 public/audio-worklets/*.js에 배치되어 audioContext.audioWorklet.addModule(path)를 통해 로드됩니다. 로드된 후, 그래프의 어느 부분에서든 AudioWorkletNode를 해당 프로세서로 인스턴스화할 수 있습니다. 처리는 메인 스레드에서 분리되어 실행되며, UI 애니메이션은 오디오 처리를 방해하지 않습니다.
2. 5개의 Airwindows Tier-1 포트
Chris Johnson의 Airwindows는 MIT 라이선스를 받은 2,500개 이상의 오디오 플러그인으로, 전설적으로 맛있는 DSP로 유명합니다. 우리는 Soundbend의 Wave 12 출시를 위해 5개를 브라우저 AudioWorklets로 포트했습니다:
- Pressure6 — 투명한 압축이 숨 쉬는 것처럼
- ToTape9 — 아날로그 테이프 포화 모델링
- PurestDrive — 날카로운 고주파 없이 최소 위상 포화
- CreamCoat — 따뜻함 + 조화 발진기
- NotJustAnotherDither — 비트 깊이 감소(마스터링)를 위한 TPDF 디서.
각 포트는 AudioWorkletProcessor에서 수학 약 30-80 LOC입니다. 포트는 Airwindows와 비트 단위로 일치하지 않습니다(다른 C++와 JS 수치 엔진에서 FMA/비정규 처리가 다름), 그러나 소닉적으로 일치합니다. Null-tests는 출력을 금속 기준에 비해 ≤ -80 dBFS 잔여물로 유지하므로 DSP 변경 사항이 감지됩니다.
3. 진정한 피크 리미터
현대의 스트리밍 플랫폼(Spotify, Apple Music, YouTube)은 ITU-R BS.1770-5 기준으로 진정한 피크 음량 정규화를 강제합니다. 샘플 피크와 샘플 간 피크는 서로 다른 개념이며, 신호가 샘플 단위로 -1 dBFS 피크를 보일 수 있지만 D/A 재구성 후 0 dBFS를 초과할 수 있습니다. 비-진정한 피크 리미터는 DAW에서 깨끗하게 보이지만 DAC에서 클리핑될 수 있습니다.
우리의 리미터는 전체 ITU 사양을 구현합니다: 4배 오버샘플링, 인터샘플 피크 감지, 룩아헤드, 소프트니 릴리즈. AudioWorklet 형식으로 public/audio-worklets/true-peak-limiter-processor.js에 배포됩니다. 참조 구현체(Oxford Limiter, iZotope Ozone Maximizer)와의 측정 결과는 LUFS 통합에서 0.1 dB 이내로 일치합니다.
4. 메인 스레드 외 통신
오디오 그래프는 오디오 스레드에서 실행되고, UI는 메인 스레드에서 실행됩니다. 매개변수 변경(노브 조정, 트랙 페이드)은 UI → 오디오로 전파되어야 하며, 오디오가 끊기지 않아야 합니다.
웹 오디오의 AudioParam는 표준 매개변수(GainNode gain, BiquadFilterNode frequency)에 대해 내장으로 처리합니다. 사용자 정의 워크릿 매개변수의 경우, UI 메시지에 MessagePort와 구조화 복제를 사용하고, 고속 자동화 데이터에는 SharedArrayBuffer 기반의 링 버퍼를 사용합니다.
SharedArrayBuffer는 Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp 헤더가 필요합니다. 이는 public/_headers에서 /soundbend + /pulse 경로에 설정됩니다. Tape Delay는 메시지 포트 지연을 방지하기 위해 96kHz에서 반지름 버퍼를 사용합니다.
5. 5개의 내장 인스트루먼트
Soundbend는 5개의 맞춤형 악기와 함께 제공됩니다:
FM 합성 — DX7 / Operator를 기반으로 한 6연산자 FM 합성. 알고리즘 시각화 도구 + 전체 변조 매트릭스. UI는 약 800 LOC JS, 음성 할당기에는 약 300 LOC 워크릿이 사용되었습니다.
웨이블테이블 싱스 — 웨이블테이블 간 변환 합성. 스펙트럴 왜곡 + 유니슨 + 스테레오 디튠. 30개 이상의 공장 웨이블테이블. ConvolverNode를 사용하여 오디오 속도에서 웨이블테이블 크로스페이드를 구현합니다.
아날로그 서브트랙티브 — 2오실레이터 폴리신스와 Cytomic SVF 필터. Cytomic은 상태-변수 필터 구조로, 올바른 소리를 내며, 단순한 SVF는 fc > SR/6 이상에서 앨리어싱 문제를 일으킵니다. Cytomic 포트는 제로 딜레이 피드백 수학을 통해 이를 처리합니다.
DrumRack + Sampler — 패드 기반 샘플 재생으로 각 패드의 피치/필터/앰프 익스프레션을 조절합니다. 샘플은 IndexedDB에 저장되어 빠른 재호출이 가능합니다. 5가지 장르별 팩토리 킷 (부엄밥, 트랩, 하우스, DNB, 아프로비트).
SeedSynth + Geist (구 AudioStudioEngine에서 사용되던 기능 — Wave 14부터 Soundbend으로 통합됨) — 유전적 패치 생성기(Synplant 2-클래스)와 Geist 스타일 드럼 머신입니다. 이는 통합 이념을 큰 이슈로 만든 특허 기술로, 3만 줄의 병합 과정에서 비트 정확한 동작을 유지해야 했습니다. 병합 후 100개 시드 null 테스트 통과.
6. 믹서 + 보조 출력
적절한 믹서 — 트랙별 볼륨 조절이 아닌 트랙별 FX 삽입, 사전/사후 볼륨 조절 보조 송신, 마스터 버스를 갖춘 믹서는 DAW와 시퀀서를 구분합니다. Soundbend의 믹서 클래스는 약 655 LOC (src/audio/mixer.js)입니다. 각 트랙은 삽입 슬롯, 송신 탭 포인트, 미터링을 갖춘 AudioNode 그래프입니다.
어려운 부분은 프리페이더와 포스트페이더 어시스턴트 송신입니다. 프리페이더는 트랙 볼륨과 무관하게 리버브 버스로 보냅니다(전통적인 사용: 트랙 페이드 시에도 유지되는 병렬 리버브). 포스트페이더는 트랙 볼륨에 따라 조정됩니다. 둘 다 제공됩니다.
7. MIDI + WAM 플러그인 호스트
WebMIDI가 성숙했습니다 — USB-MIDI 키보드에서 어떤 컨트롤러 입력도 즉시 작동합니다. MIDI 랙(아르페지에이터, 스케일, 코드)은 컨트롤러와 악기 사이에 위치하여 노트 스트림을 변환합니다.
플러그인을 위해 우리는 Web Audio Modules v2 (WAM)을 호스팅합니다 — 브라우저 내장 플러그인입니다. VST(25년의 선두 주자)보다 생태계가 작지만 성장 중입니다. WAM을 로드하는 방법은 getWamHost().load(wamUri)로, 이는 AudioNode를 반환하며 이를 어떤 체인에도 삽입할 수 있습니다.
WAM은 각 경로별 CSP를 요구합니다. 사용자 제공 JS를 불러오기 때문입니다. 우리의 _headers는 /soundbend에 대해 script-src 허용 목록을 사용하여 CSP를 엄격하게 제한합니다. 이 목록에는 잘 알려진 WAM 레지스트리가 포함됩니다.
8. OfflineAudioContext를 사용한 바운스
내보내기는 OfflineAudioContext를 통해 실행됩니다 — 체인 복잡도에 따라 실시간보다 빠르게(또는 느리게) 정적 AudioBuffer로 렌더링한 후, 브라우저 내 인코더를 사용하여 WAV로 인코딩합니다.
주의: 모든 노드가 OfflineAudioContext에서 작동하지 않습니다. MediaStreamAudioSourceNode는 작동하지 않습니다(오프라인으로 실시간 마이크 녹음은 당연히 불가능합니다). 일부 워크릿은 온라인 → 오프라인 전환 시 주의 깊은 상태 재설정이 필요합니다. 우리는 이 문제를 반복적으로 마주쳤고 이제 Mixer.toJSON() + Mixer.fromJSON(offlineCtx)가 표준 패턴입니다: 믹서 상태를 직렬화하고 오프라인 컨텍스트에서 병렬 믹서를 다시 구축한 후 렌더링합니다.
9. Yjs를 통한 협업
Yjs는 다중 사용자 협업 편집을 자동 충돌 해결과 함께 처리하는 CRDT 라이브러리입니다. 우리의 SoundbendSession 클래스는 트랙별 문서 구조(트랙 메타데이터는 Y.Map, 패턴 단계는 Y.Array, 가사/노트는 Y.Text)를 Yjs로 감싸고 있습니다.
두 명에서 네 명의 프로듀서가 샘플 정확도로 트랙 동기화를 통해 동시에 같은 프로젝트를 편집할 수 있습니다. 이는 오디오 데이터가 텍스트 문서 협업보다 수백만 배 더 크기 때문에 텍스트 문서 협업보다 더 어렵습니다 — 우리는 원본 오디오 대신 메타데이터와 패턴을 Yjs를 통해 공유합니다. 원본 샘플은 로컬에 유지됩니다(사용자별 IndexedDB).
10. 성능 예산
브라우저에서 전체 DAW를 60fps UI + 실시간 오디오 + SharedArrayBuffer + WASM + 여러 워크릿을 사용하여 실행하는 것은 엄청난 예산이 필요합니다. 일부 숫자:
- 오디오 스레드: 48kHz에서 ~2ms / 128샘플 버퍼 (서프레임)
- 메인 스레드: 16.6ms / 60fps 프레임; 오디오 처리는 프레임당 <1ms를 유지해야 합니다.
- Worklet 설정: 워크렛 로드당 한 번만 비용 발생 (~10-50ms) (15개 이상의 워크렛을 배치 — 배치 처리됨)
- SharedArrayBuffer 할당: 동적 워크렛 매개변수당 4KB 라인 버퍼
- Soundbend 청크 크기(통합 후): 약 496 KB 원시, 약 120 KB gzip
- 전체 프로젝트 로드(차가운 로드): 중급 노트북에서 약 800ms
- 내보내기 렌더링: 효과 체인 복잡도에 따라 실시간의 약 0.3배에서 2배 소요됩니다.
11. Null-테스트 헌드레스
DSP 회귀는 침묵합니다 — 코드 리뷰로는 잡을 수 없는 미세한 방식으로 오디오가 달라 보입니다. Soundbend는 tests/audio-null/에서 Puppeteer 기반 null 테스트 헌치를 제공합니다.
각 효과 × 프리셋 × 테스트 신호에 대해, 헌치는 headless Chromium 내부에서 OfflineAudioContext를 통해 렌더링하고, 결과 WAV를 커밋된 골든 기준과 null 테스트한 후 잔여 피크가 -60 dBFS를 초과하면 빌드를 실패시킵니다.
Wave 14F에서 100개의 SeedSynth 시드 기준과 32개의 Geist 드럼 패턴 골든이 추가되었습니다. Soundbend를 AudioStudio(Wave 14B-G)에 통합할 때, null-test로 인해 기존 프로퍼리어트 도구가 무시되거나 손상되는 것을 방지했습니다. 100개 중 96개의 SeedSynth 시드가 비트 정확하게 통과했습니다. 4개의 실패는 기존 크롬 웹 오디오 퀴크(고-Q 필터 공명 드리프트, OfflineAudioContext 인스턴스 간)로 인한 것이며, 통합 회귀가 아니며 JS에서 수정할 수 없습니다.
DSP 회귀는 조용합니다. 코드 검토는 그 소리를 들을 수 없습니다. null-테스트 헌치는 들을 수 있습니다 — 이것이 왜 CI 차단으로 작동하는지입니다.
12. 브라우저 + 클라이언트 사이드가 옳은 선택이었습니다
네이티브 DAW(ableton, Logic, FL Studio)는 30년 이상의 경쟁력이 있습니다. 기능별로 이기기는 긴 여정이지만, 가격은 다른 아키텍처 선택으로 즉시 승리할 수 있었습니다.
2022-2024년 사이 WebAssembly은 성능 한계를 넘어섰습니다. 같은 시기 Web Audio AudioWorklets이 널리 배포되었습니다. SharedArrayBuffer + COOP/COEP이 안정화되었습니다. 크롬, 파이어폭스, 사파리 모두 필요한 API를 충분한 성능으로 지원합니다.
가격 인과: 오디오 처리가 사용자 기기에서 실행되면, 우리는 그것을 위해 지불하지 않습니다. 우리의 프로 구독자당 변동 비용은 근처 0입니다. 따라서 $4.99/mo는 지속 가능합니다 영원히. 라고스의 2020년 안드로이드 사용자도 샌프란시스코의 사람이 지불하는 것과 동일한 $4.99로 완전한 DAW를 사용할 수 있습니다.
경제학에 대한 가격 체계 에세이를 읽어보세요. DSP의 경우, 이는 대부분의 이야기입니다.
체험해 보세요
Soundbend은 morph.cool/soundbend에서 이용할 수 있습니다. 무료 계정은 가입 없이 작동합니다. $4.99/월 Pro는 마스터링 체인 + 진정한 피크 리미터 + 추가 프리셋을 제공합니다. WebMIDI 키보드는 환영하지만 필수는 아닙니다.
— 하이든 및 Morph 에이전트 팀
2026년 4월 22일