นี่คือโพสต์ทางเทคนิคเกี่ยวกับวิธีที่ Morph's Soundbend — ระบบสร้างเสียงดิจิทัลแบบครบวงจร พร้อมเครื่องมือสร้างเสียง 5 แบบ ตัวผสมเสียงพร้อมเอฟเฟกต์และช่องส่งสัญญาณเสริม 30+ เอฟเฟกต์ (รวมถึงการแปลงพอร์ต Airwindows Tier-1 5 แบบ และตัวจำกัดระดับสูงสุดแบบแท้จริง) ชั้นเอฟเฟกต์ MIDI ตัวโฮสต์ปลั๊กอิน WAM v2 และชั้นการทำงานร่วมกันด้วย Yjs CRDT — ทำงาน ทั้งหมด ในแท็บเบราว์เซอร์.
คำถามที่เป็นประโยชน์คือ: นี่คือ จริง ๆ แล้ว แข่งขันกับ Ableton ได้หรือไม่ คำตอบที่ตรงไปตรงมา: สำหรับการใช้งานส่วนใหญ่ของนักผลิต ใช่ สำหรับการรวมกับ Max for Live ลึก ๆ ยังไม่ได้ อ่าน เปรียบเทียบ Ableton แบบเปรียบเทียบ เพื่อการวิเคราะห์ระดับผลิตภัณฑ์ โพสต์นี้คือการวิศวกรรม
สแต็ก
- Frontend React + Vite
- Web Audio API สำหรับกราฟเสียง
- AudioWorkletProcessor สำหรับ DSP แบบกำหนดเอง (ทำงานนอก main-thread)
- WebAssembly สำหรับ DSP ที่ต้องการประสิทธิภาพสูง (การสร้าง WASM แบบกำหนดเอง)
- MessagePort + ring buffers สำหรับการสื่อสารระหว่าง UI ↔ worklet
- Yjs สำหรับการร่วมมือ CRDT
- IndexedDB สำหรับการเก็บข้อมูลโปรเจกต์ + การเก็บตัวอย่าง
- WebMIDI สำหรับการป้อนข้อมูลจากอุปกรณ์ควบคุมฮาร์ดแวร์
- OfflineAudioContext สำหรับการ bounce/export
1. กราฟเสียง
ทุกแทร็กใน Soundbend ผ่านการเชื่อมต่อในสาย: เครื่องดนตรี → ชั้น FX แทร็ก → ส่ง Aux → แถบมิกซ์ → บัสหลัก → ลิมิเตอร์ → ปลายทาง แต่ละลูกศรคือการเชื่อมต่อ Web Audio AudioNode
Web Audio ให้เราใช้ AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode และเพื่อนๆ นี้ถูกปรับให้ทำงานได้ดีโดยเครื่องยนต์เบราว์เซอร์ (V8/SpiderMonkey/JSC ทั้งหมดลงทุนอย่างลึกซึ้ง) สำหรับ มาตรฐาน ของเอฟเฟกต์ — EQ, การควบคุมระดับเสียงอัตโนมัติ, การกรองพื้นฐาน — เราใช้โหนดแบบเดิม พวกมันเป็น เร็ว และผ่านการทดสอบมาแล้ว
สำหรับ เอฟเฟกต์แบบกำหนดเอง — การนำเข้า Airwindows, การบิดเบือนของเรา, ตัวจำกัดระดับสูงสุดของเรา — เราใช้ AudioWorkletProcessor ซึ่งทำงานบน Thread เสียง รับประกันการจัดลำดับความสำคัญแบบเรียลไทม์ และเป็นตำแหน่งทางสถาปัตยกรรมที่ถูกต้องสำหรับ 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 สำหรับโปรเซสเซอร์นั้นได้ การประมวลผลทำงานนอก Thread หลัก — การเคลื่อนไหวของ UI ไม่ทำให้เสียงหยุดทำงาน
2. พอร์ต Tier-1 ของ Airwindows 5 ตัว
Chris Johnson's Airwindows เป็นปลั๊กอินเสียง 2,500+ ชิ้น ที่ได้รับใบอนุญาต MIT และมีชื่อเสียงในด้าน DSP ที่เลิศเลอ เราได้นำ 5 ตัวมาใช้ใน AudioWorklets ของเบราว์เซอร์สำหรับ Wave 12 ของ Soundbend:
- Pressure6 — การบีบอัดแบบโปร่งใสที่หายใจได้
- ToTape9 — การจำลองการบิดเบือนของเทปอะนาล็อก
- PurestDrive — การเพิ่มความอิ่มตัวแบบเฟสต่ำโดยไม่ทำให้เสียงแหลมดังเกินไป
- CreamCoat — ความอบอุ่น + เครื่องเร่งความถี่เสียง
- NotJustAnotherDither — TPDF dither สำหรับลดความลึกของบิต (การปรับแต่งสุดท้าย)
แต่ละพอร์ตมีขนาดประมาณ 30-80 บรรทัดของคณิตศาสตร์ใน AudioWorkletProcessor พอร์ตไม่ตรงกับ Airwindows ทีละบิต (การจัดการ FMA/denormal แตกต่างกันระหว่างเครื่องมือคณิตศาสตร์ C++ และ JS) แต่ตรงกันในเชิงเสียง ทดสอบ Null ทำให้ค่าเอาต์พุต ≤ -80 dBFS ที่เหลือจากการเปรียบเทียบกับต้นแบบ ดังนั้นการเปลี่ยนแปลง DSP จะถูกจับได้
3. ตัวจำกัดระดับจริง (True-Peak Limiter)
แพลตฟอร์มสตรีมมิ่งสมัยใหม่ (Spotify, Apple Music, YouTube) บังคับใช้การปรับระดับความดังแบบ true-peak ตามมาตรฐาน ITU-R BS.1770-5 จุดสูงสุดตัวอย่างและจุดสูงสุดระหว่างตัวอย่างเป็นสิ่งที่ต่างกัน ข้อมูลเสียงอาจมีจุดสูงสุดที่ -1 dBFS ตัวอย่าง แต่เกิน 0 dBFS true-peak หลังการแปลง D/A ตัวจำกัดระดับความดังที่ไม่ใช่ true-peak จะตัดสัญญาณใน DAC แม้ว่า DAW ของคุณจะแสดงว่าสะอาด
ตัวจำกัดของเราใช้มาตรฐาน ITU ทั้งหมด: การสุ่มตัวอย่าง 4 เท่า การตรวจจับจุดสูงสุดระหว่างตัวอย่าง การตรวจสอบล่วงหน้า การปล่อยแบบนุ่ม ตัวจำกัดนี้ส่งมอบในรูปแบบ AudioWorklet ที่ public/audio-worklets/true-peak-limiter-processor.js การวัดค่าเมื่อเปรียบเทียบกับการใช้งานอ้างอิง (Oxford Limiter, iZotope Ozone Maximizer) ตรงกันภายใน 0.1 dB บน LUFS integrated
4. การสื่อสารแบบไม่ใช้หลัก-thread
The audio graph runs on the audio thread. The UI runs on the main thread. Parameter changes (turn a knob, fade a track) need to propagate from UI → audio without glitching the audio.
Web Audio's AudioParam จัดการนี้โดยธรรมชาติสำหรับพารามิเตอร์มาตรฐาน (GainNode gain, BiquadFilterNode frequency) สำหรับงานที่กำหนดเอง ใช้ MessagePort กับการคัดลอกแบบโครงสร้างสำหรับข้อความ UI และ SharedArrayBuffer-backed ring buffers สำหรับข้อมูลการควบคุมอัตโนมัติความเร็วสูง
SharedArrayBuffer ต้องการ Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp หัวข้อ ซึ่งตั้งค่าใน public/_headers สำหรับเส้นทาง /soundbend + /pulse เทปดีเลย์ใช้บัฟเฟอร์แบบวงกลมที่ความถี่ 96kHz เพื่อหลีกเลี่ยงความล่าช้าของ Message-Port
5. เครื่องดนตรี 5 แบบที่ใช้ตามมาตรฐาน
Soundbend ส่งมอบ 5 เครื่องดนตรี ทั้งหมดเป็นแบบกำหนดเอง:
FM Synth — การสร้างเสียงแบบ FM 6 ตัวอัลกอริทึมที่จำลองจาก DX7 / Operator ตัวแสดงผลอัลกอริทึม + เมทริกซ์การปรับแต่งเต็มรูปแบบ ~800 LOC JS สำหรับ UI ~300 LOC สำหรับ worklet
Wavetable Synth — การสร้างเสียงแบบ morph-between-tables รวมถึง Spectral warping + unison + stereo detune 30+ wavetable แบบโรงงาน ใช้ ConvolverNode สำหรับ crossfade wavetable ที่อัตราเสียง
Analog Subtractive — ซินธ์ 2 โอซิลเลเตอร์ที่มีตัวกรอง Cytomic SVF ตัวกรอง Cytomic เป็นโครงสร้างตัวกรองแบบตัวแปรที่ให้เสียงที่ถูกต้อง; SVF แบบธรรมดาอาจมีปัญหาการแทรกสอดเมื่อ fc > SR/6 การแปลง Cytomic จัดการปัญหานี้ผ่านการคำนวณแบบ zero-delay feedback
DrumRack + Sampler — การเล่นตัวอย่างแบบพื้นที่ปุ่ม พร้อมการปรับความถี่/ฟิลเตอร์/ระดับเสียงต่อปุ่ม ตัวอย่างถูกเก็บใน IndexedDB เพื่อให้เรียกใช้ได้เร็ว 5 ชุดตัวอย่างสำหรับแต่ละแนวเพลง (boombap, trap, house, dnb, afrobeat).
SeedSynth + Geist (ใน AudioStudioEngine แบบเก่า — ตอนนี้รวมเข้ากับ Soundbend แล้วตั้งแต่ Wave 14) — เครื่องสร้างพัชเชิงพันธุกรรม (Synplant 2-class) และเครื่องจักรกลจังหวะแบบ Geist นี่คือทรัพย์สินทางปัญญาเฉพาะที่ทำให้หลักการรวมตัวเป็นที่น่าสนใจ — เราต้องรักษาการทำงานเหมือนเดิมทุกประการหลังการรวมกัน 30k บรรทัด ทดสอบ null 100 ค่าผ่านหลังการรวม
6. เครื่องผสม + ส่งเสริมช่องสัญญาณเสริม
มิกเซอร์ที่เหมาะสม — ไม่ใช่แค่ฟีเดอร์ต่อแทร็ก แต่ยังมีช่องใส่เอฟเอ็กซ์ต่อแทร็ก ช่องส่งซ้ำก่อน/หลังฟีเดอร์ บัสหลัก — คือสิ่งที่แยก DAW จากเครื่องจักรจัดทำเพลง ระบบมิกเซอร์ของ Soundbend มีขนาดประมาณ 655 บรรทัด (src/audio/mixer.js) แต่ละแทร็กเป็นกราฟ AudioNode พร้อมช่องใส่เอฟเอ็กซ์ จุดต่อส่ง และการวัดค่า
ส่วนที่ซับซ้อนคือการส่ง Aux แบบ Pre-fader หรือ Post-fader Pre-fader ส่งไปยังบัสเรเวิร์บ ไม่ว่าระดับเสียงของแทร็กจะเป็นอย่างไร (การใช้งานแบบคลาสสิก: เรเวิร์บแบบ Parallel ที่ยังคงอยู่แม้แทร็กจะลดระดับ) Post-fader ปรับตามระดับเสียงแทร็ก ทั้งสองแบบพร้อมใช้งาน
7. MIDI + WAM plugin host
WebMIDI ใช้งานได้เต็มประสิทธิภาพ — การรับสัญญาณจากคีย์บอร์ด USB-MIDI ทุกตัวทำงานได้ทันที แร็ก MIDI ของเรา (Arpeggiator, Scale, Chord) ตั้งอยู่ระหว่างคีย์บอร์ดและเครื่องดนตรี แปลงสตรีมโน้ตให้เป็นรูปแบบที่ต้องการ
สำหรับปลั๊กอิน เราโฮสต์ Web Audio Modules v2 (WAM) — ปลั๊กอินแบบฝังในเบราว์เซอร์ ระบบนิเวศเล็กกว่า VST (มีความคืบหน้า 25 ปี) แต่กำลังเติบโต การโหลด WAM คือ getWamHost().load(wamUri) ซึ่งจะคืนค่า AudioNode ที่คุณสามารถแทรกเข้าไปในสายสัญญาณใดก็ได้
WAMs ต้องการ CSP แบบกำหนดเส้นทางเพราะโหลด JS ที่ผู้ใช้ให้มาได้ทุกแบบ เราใช้ _headers จำกัด CSP สำหรับ /soundbend โดยมี script-src อนุญาตเฉพาะเว็บไซต์ WAM ที่รู้จัก
8. OfflineAudioContext สำหรับการกระแทก
การส่งออกทำงานผ่าน OfflineAudioContext — แปลงเร็วกว่าเวลาจริง (หรือช้ากว่า ขึ้นอยู่กับความซับซ้อนของชั้น) เป็น AudioBuffer แบบคงที่ แล้วเข้ารหัสเป็น WAV โดยใช้ตัวเข้ารหัสในเบราว์เซอร์
จุดที่ต้องระวัง: ไม่ใช่โหนดทั้งหมดทำงานใน OfflineAudioContext MediaStreamAudioSourceNode ไม่ทำงาน (ไม่สามารถบันทึกไมค์สดแบบออฟไลน์ได้ แน่นอน) โหนดบางตัวต้องรีเซ็ตสถานะอย่างระมัดระวังระหว่างการเปลี่ยนจากออนไลน์เป็นออฟไลน์ เราเผชิญกับปัญหานี้บ่อยครั้ง และตอนนี้ Mixer.toJSON() + Mixer.fromJSON(offlineCtx) เป็นรูปแบบมาตรฐาน: serialize สถานะของ mixer สร้าง mixer แบบขนานใน context ออฟไลน์ และเรนเดอร์
9. การร่วมมือผ่าน Yjs
Yjs เป็นไลบรารี CRDT ที่จัดการการแก้ไขร่วมกันแบบหลายผู้ใช้ด้วยการแก้ไขข้อขัดแย้งอัตโนมัติ คลาส SoundbendSession ของเราห่อ Yjs ด้วยโครงสร้างเอกสารตามแทร็ก (Y.Map สำหรับข้อมูลเมตาแทร็ก, Y.Array สำหรับขั้นตอนรูปแบบ, Y.Text สำหรับเนื้อเพลง/หมายเหตุ)
ผู้ผลิตสองถึงสี่คนสามารถแก้ไขโครงการเดียวกันพร้อมกันได้ด้วยการซิงค์แทร็กที่แม่นยำในระดับตัวอย่าง ซึ่งเป็นเรื่องที่ยากกว่าการร่วมมือกันในเอกสารข้อความ เนื่องจากข้อมูลเสียงมีขนาดใหญ่กว่าข้อมูลข้อความหลายเท่า เราแบ่งปันข้อมูลเมตา + รูปแบบผ่าน Yjs ไม่ใช่ข้อมูลเสียงดิบ ตัวอย่างเสียงดิบจะถูกเก็บไว้ที่อุปกรณ์ของคุณ (IndexedDB ต่อผู้ใช้)
10. งบประมาณประสิทธิภาพ
การรัน DAW แบบเต็มรูปแบบในเบราว์เซอร์พร้อม UI 60fps + เสียงแบบเรียลไทม์ + SharedArrayBuffer + WASM + worklets หลายตัว ต้องใช้การจัดการงบประมาณอย่างเข้มงวด ตัวอย่างตัวเลข:
- Thread เสียง: ~2 มิลลิวินาที / บัฟเฟอร์ 128 ตัวอย่างที่ความถี่ 48kHz (ส่วนย่อย)
- Thread หลัก: 16.6ms / 60fps frame; การจัดการเสียงต้องใช้เวลา <1ms ต่อเฟรม
- การตั้งค่า Worklet: ค่าใช้จ่ายครั้งเดียวประมาณ 10-50ms ต่อการโหลด Worklet แต่ละตัว (ส่งมอบ 15+ Worklet — เราจัดกลุ่ม)
- การจัดสรร SharedArrayBuffer: 4KB ring buffers ต่อแต่ละพารามิเตอร์ worklet แบบไดนามิก
- ขนาดชิ้นส่วน Soundbend (หลังการรวม): ~496 KB แบบดิบ, ~120 KB gzip
- เวลาโหลดโครงการเต็ม (เริ่มจากศูนย์): ~800ms บนแล็ปท็อประดับกลาง
- การส่งออกการเรนเดอร์: ~0.3x ถึง 2x ของเวลาจริง ขึ้นอยู่กับความซับซ้อนของเอฟเฟกต์
11. Null-test harness
การถดถอย DSP ไม่มีเสียง — เสียงฟังดูแตกต่างในลักษณะเล็กน้อยที่การตรวจสอบโค้ดไม่สามารถจับได้ Soundbend มาพร้อมกับระบบทดสอบ null ที่ขับเคลื่อนด้วย Puppeteer ใน tests/audio-null/
สำหรับแต่ละเอฟเฟกต์ × เพรเซ็ต × สัญญาณทดสอบ ระบบจะแสดงผลผ่าน OfflineAudioContext ภายใน Chromium แบบไม่มีหน้าจอ ทดสอบค่า WAV ที่ได้กับค่าที่ถูกบันทึกไว้ และล้มเหลวในการสร้างหากค่าสูงสุดที่เหลือเกิน -60 dBFS
Wave 14F เพิ่ม SeedSynth 100 แบบและ Geist 32 แบบ รูปแบบการเต้น หลังจากที่เราผสาน Soundbend เข้ากับ AudioStudio (Wave 14B-G) การทดสอบ null จับสิ่งที่อาจทำให้เครื่องมือเฉพาะเจาะจงเสียหายโดยไม่รู้ตัว 96 จาก 100 แบบ SeedSynth ผ่านการทดสอบแบบ bit-identical 4 แบบที่ล้มเหลวเป็นข้อผิดพลาดที่มีอยู่ก่อนใน Chromium Web Audio (การรั่วไหลของความถี่สูง-Q ระหว่าง OfflineAudioContext ต่างกัน) — ไม่ใช่ข้อผิดพลาดจากการผสาน และไม่สามารถแก้ไขได้จาก JS
การถดถอย DSP นั้นเงียบ. การตรวจสอบโค้ดไม่สามารถได้ยินมันได้ แต่ null-test harness สามารถทำได้ — นั่นคือเหตุผลที่มันเป็นตัวบล็อก CI.
12. ทำไมการใช้เบราว์เซอร์ + ด้านลูกค้าถึงเป็นทางเลือกที่ถูกต้อง
DAW แบบ Native (Ableton, Logic, FL Studio) มีข้อได้เปรียบ 30 ปี ในการแข่งขัน การเอาชนะพวกเขาทีละฟีเจอร์อาจใช้เวลานาน แต่ ราคา — นี่คือจุดที่สามารถชนะได้ทันที โดยการเลือกโครงสร้างที่แตกต่างกัน
WebAssembly เกินขีดจำกัดประสิทธิภาพในช่วง 2022-2024 Web Audio AudioWorklets ถูกใช้งานอย่างแพร่หลายในช่วงเวลาเดียวกัน SharedArrayBuffer + COOP/COEP ได้รับการยืนยันแล้ว Chromium + Firefox + Safari สนับสนุน API ที่จำเป็นด้วยประสิทธิภาพที่เพียงพอ
ผลการคำนวณเกี่ยวกับราคา: หากการประมวลผลเสียงทำงานบนอุปกรณ์ผู้ใช้ เราไม่ต้องจ่ายค่าใช้จ่าย ต้นทุนต่อผู้ใช้ Pro ของเราใกล้ศูนย์ ดังนั้น $4.99/เดือน ยั่งยืน ตลอดไป เด็กในลากอสที่ใช้ Android 2020 ได้รับ DAW ครบวงจรที่คนในซานฟรานซิสโกจ่าย $4.99 เท่ากันเพื่อเข้าถึง
อ่าน บทความเกี่ยวกับโครงสร้างราคา เพื่อเข้าใจเศรษฐศาสตร์ สำหรับ DSP นี่คือเรื่องราวหลัก
ลองใช้ดู
Soundbend อยู่ที่ morph.cool/soundbend เวอร์ชันฟรีทำงานได้โดยไม่ต้องสมัครสมาชิก $4.99/เดือน Pro เปิดใช้งานการเชื่อมต่อการปรับแต่ง + ตัวจำกัดระดับสูงสุดจริง + ตัวเลือกเพิ่มเติม เครื่องมือ WebMIDI ยินดีต้อนรับ แต่ไม่จำเป็น
— Hayden + ทีม Morph agent
22 เมษายน 2026