هذا منشور تقني حول كيفية عمل Soundbend في Morph — وهو محطة عمل صوتية رقمية كاملة تشمل 5 آلات موسيقية أصلية، ومُحَوِّل مع سلاسل تأثيرات ومراسلات إضافية، و30+ تأثير (بما في ذلك 5 من تطبيقات Airwindows من الدرجة الأولى ومرسوم مُحدِّد ذروة حقيقي)، وشاشة تأثيرات MIDI، ومستضيف لملفات واجهة برمجة تطبيقات WAM v2، وطبقة تعاونية تعتمد على Yjs CRDT — يعمل كليًا في علامة تبويب متصفح.
السؤال العملي هو: هل هذا حقًّا منافس لـ Ableton؟ الإجابة الصادقة: نعم، لمعظم سير العمل لمنتجي الصوت. أما بالنسبة للتكاملات العميقة مع Max for Live، فلا يزال غير متوفر. اقرأ مقارنة منافس Ableton للتفاصيل على مستوى المنتج. هذه المقالة هي عن الجانب الهندسي.
البطاقة
- واجهة أمامية React + Vite
- Web Audio API لرسم الرسم البياني الصوتي
- AudioWorkletProcessor لمعالجة DSP مخصصة (خارج الخيط الرئيسي)
- WebAssembly للاستفادة من الأداء في معالجة الإشارات الرقمية الحرجة (بناء WASM مخصص)
- MessagePort + ring buffers for UI ↔ worklet communication
- Yjs لتعاون CRDT
- IndexedDB للاحتفاظ بالمشاريع + تخزين العينات
- WebMIDI لاستخدام مدخلات تحكم الأجهزة المادية.
- OfflineAudioContext للاستماع/التصدير
1. رسم بياني للصوت
كل مسار في Soundbend يمر عبر سلسلة: أداة موسيقية → سلسلة تأثيرات المسار → إرسال مساعد → شريط المُعَدِّل → خط المُعَدِّل الرئيسي → مُحدِّد الحد الأقصى → الوجهة. كل سهم يمثل اتصالًا باستخدام Web Audio AudioNode.
يمنحنا Web Audio AudioContext, GainNode, BiquadFilterNode, ConvolverNode, AnalyserNode, و同类. هذه مُحسَّنة بواسطة محركات المتصفح (V8/SpiderMonkey/JSC جميعها مُستثمرة بعمق). بالنسبة لـالتأثيرات القياسية — مثل التوازن الصوتي، التحكم في القوة، والتصفية الأساسية — نستخدم العقد القياسية. وهي سريعة ومُختبرة جيدًا.
لـ تأثيرات مخصصة — مُساقط Airwindows، تأثير التشبع الخاص بنا، ومُحدد الذروة الحقيقي الخاص بنا — نستخدم AudioWorkletProcessor، الذي يعمل على خيط الصوت، مع ضمان أولوية زمنية حقيقية، وهو المكان المعماري الصحيح لمعالجة الإشارات غير القياسية.
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 لهذا المعالج. يتم معالجة البيانات خارج الخيط الرئيسي — فلا تؤثر الحركات على واجهة المستخدم على الصوت.
2. مُسارات Airwindows من الفئة الأولى
Chris Johnson's Airwindows هو 2500+ من إضافات الصوت، مرخص بموجب MIT، ومشهور بذوقه الرفيع في معالجة الإشارة الرقمية. قمنا بتحويل 5 منها إلى AudioWorklets في المتصفح لـ Soundbend's Wave 12:
- Pressure6 — ضغط شفاف يتنفس
- ToTape9 — نمذجة تشبع الشريط المُعَدِّي
- PurestDrive — تشبع خطي بحد أدنى دون ارتفاعات حادة
- CreamCoat — دفء + مُحفز تردد
- NotJustAnotherDither — تخفيف TPDF لتقليل عمق البت (التصنيف النهائي)
كل منفذ يحتوي على ~30-80 سطرًا من التعليمات البرمجية في AudioWorkletProcessor. لا تتطابق المنافذ مع Airwindows بتقنية البت (لأن معالجة FMA/القيم المُعَدَّلة تختلف بين محركات الأرقام في C++ و JavaScript)، لكنها تتطابق صوتيًا. تُحافظ اختبارات Null على المخرجات ≤ -80 dBFS مقابل المعايير، لذا يتم اكتشاف تغييرات DSP.
3. مُحدّد الذروة الحقيقية
منصات البث الحديثة (Spotify، Apple Music، YouTube) تفرض الصوت الحقيقي القياسي لضبط شدة الصوت وفق معيار ITU-R BS.1770-5. قمم العينة وقمة ما بين العينات هي أمور مختلفة؛ يمكن أن تصل الإشارة إلى -1 dBFS على مستوى العينة ولكن تتجاوز 0 dBFS عند إعادة التحويل إلى إشارة رقمية- analogue. سيقوم مُحدِّد الصوت غير الحقيقي القياسي بقطع الإشارة في DAC حتى لو أظهرت برامجك DAW أنها نظيفة.
يُطبّق مُحدّدنا المواصفات الكاملة لـ ITU: تكبير 4x، كشف ذروة بين العينات، توقع مسبق، وإطلاق ناعم. يتم توصيله في شكل AudioWorklet في public/audio-worklets/true-peak-limiter-processor.js. تتوافق القياسات مع الإصدارات المرجعية (Oxford Limiter، iZotope Ozone Maximizer) داخل 0.1 ديسيبل على LUFS المتكامل.
4. الاتصال خارج الخط الرئيسي
يعمل الرسم البياني الصوتي على خيط الصوت. تعمل واجهة المستخدم على الخيط الرئيسي. تحتاج تغييرات المعلمات (مثل تحريك عجلة، تلاشي مسار) إلى الانتشار من واجهة المستخدم → الصوت دون إحداث تقطيع في الصوت.
يتعامل Web Audio's AudioParam مع هذا بشكل مدمج للمعايير القياسية (GainNode gain، BiquadFilterNode frequency). أما بالنسبة للعمل المخصص لـ worklet، فنستخدم MessagePort مع تكرار التصنيف المُنظَّم لرسائل واجهة المستخدم، و SharedArrayBuffer-backed ring buffers لبيانات التحكم عالية المعدل.
يتطلب 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 Synth — توليد الصوت باستخدام التوليد الترددي (FM) بـ 6 مشغلات مُعَدَّة بناءً على DX7 / Operator. مُنظِّم خرائط الخوارزمية + مصفوفة التحوير الكاملة. ~800 سطر من كود JS للواجهة، ~300 سطر لـ worklet لمحول الصوت.
مُولِّد الموجات الجدولية — توليد مُتَحَوِّل بين الجداول. تشويه طيفي + وحدة مزدوجة + تفكيك ستيريو. أكثر من 30 جدول موجي مُصنع مسبقًا. يستخدم ConvolverNode لعمل تحوير موجي عالي السرعة في الوقت الفعلي.
الاستخلاص التماثلي — مُولّد موجات مُتعدّد الترددات بـ 2 مُولّد موجات مع مرشحات Cytomic SVF. تُعتبر Cytomic هي طريقة تصفية متغيرات الحالة التي ت sounded جيدة؛ فالمرشحات SVF البسيطة تُعاني من مشاكل تداخل فوق fc > SR/6. يتعامل الـ Cytomic مع هذا عبر رياضيات التغذية الراجعة بدون تأخير.
DrumRack + Sampler — تشغيل عينات مبنية على لوحة مع إعدادات منفصلة لكل لوحة (النغمة، المرشح، وشدة الصوت). تُخزّن العينات في IndexedDB لاسترجاع سريع. 5 مجموعات مصغّرة مُعدّة مسبقًا حسب النوع (boombap، trap، house، dnb، afrobeat).
SeedSynth + Geist (في محرك AudioStudioEngine القديم — تم دمجه الآن في Soundbend مع Wave 14) — مولد براءة اختراع جينية (Synplant 2-class) وآلة طبول من نوع Geist. هذه هي الملكية الفكرية المُحَفَّظة التي جعلت مفهوم التجميع مُهمًا — كنا مضطرين إلى الحفاظ على السلوك المتطابق بتقنية البت خلال دمج 30k سطر. نجح اختبار 100 بذرة فارغة بعد الدمج.
6. المُعَدِّل + إرسالات مساعدة
مُزيل صوت محترف — ليس مجرد مُتحكمات صوتية لكل مسار، بل مسارات مُضافة للفعاليات لكل مسار، وإرسالات مساعدة قبل/بعد المُتحكم، ومسار رئيسي — هذا ما يفصل بين برنامج DAW وبرنامج ترتيب الموسيقى. مُزيل الصوت في Soundbend يحتوي على فئة ~655 سطر كود (src/audio/mixer.js). كل مسار هو رسم بياني لـ AudioNode مع نقاط إدخال، نقاط إرسال، وقياسات.
الجزء الصعب هو إرسال المُساعد المُسبق للـ fader مقابل إرسال المُساعد اللاحق للـ fader. يرسل المُساعد المُسبق إلى حافلة الرنين بغض النظر عن حجم الصوت (الاستخدام الكلاسيكي: الرنين المتوازي الذي يبقى حتى عند تقليل حجم الصوت). يتناسب المُساعد اللاحق مع حجم الصوت. كلا الخيارين متوفران.
7. مُضيّع MIDI + WAM
WebMIDI ناضج — إدخال التحكم من أي لوحة مفاتيح USB-MIDI تعمل تمامًا. يقع مصفوفة MIDI الخاصة بنا (Arpeggiator، Scale، Chord) بين المُتحكم والأداة الموسيقية، تحويل تدفق الملاحظات.
للمكونات الإضافية، نحن نقدم موديولات الصوت الويب v2 (WAM) — مكونات إضافية متوافقة مع المتصفح. يحتوي على نظام أقل اكتمالاً مقارنة بـ VST (مما يمنحه ميزة 25 عامًا) لكنه ينمو بسرعة. يتم تحميل WAM باستخدام getWamHost().load(wamUri) الذي يعيد AudioNode يمكنك إدراجه في أي سلسلة.
تتطلب WAMs سياسة محتوى محددة (CSP) لكل مسار لأنها تحميل JS مقدم من المستخدم بشكل عشوائي. نحن نستخدم _headers لتطبيق سياسة محتوى محددة (CSP) بشكل دقيق لـ /soundbend مع قائمة مسموح بها لـ script-src لregistries معروفة لـ WAM.
8. OfflineAudioContext لـ bounce
يتم تصدير الملف عبر OfflineAudioContext — يتم معالجة أسرع من الوقت الفعلي (أو أبطأ، حسب تعقيد السلسلة) إلى AudioBuffer ثابت، ثم يتم تشفيره إلى WAV باستخدام مُشفّرنا في المتصفح.
ملاحظة: لا تعمل جميع العقد في OfflineAudioContext. لا تعمل MediaStreamAudioSourceNode (لا يمكن تسجيل الميكروفون الحي دون اتصال، منطقيًا). تحتاج بعض العملات إلى إعادة تعيين الحالة بعناية بين الانتقالات من الإنترنت إلى عدم الاتصال. واجهنا هذا الأمر مرارًا وتكرارًا، والآن Mixer.toJSON() + Mixer.fromJSON(offlineCtx) هو النمط القياسي: تسلسل حالة المُعَدِّل، وإنشاء مُعَدِّل موازٍ في السياق غير المتصل، ثم عرض النتيجة.
9. التعاون عبر Yjs
Yjs هو مكتبة CRDT تتعامل مع التحرير التعاوني متعدد المستخدمين مع حل تلقائي للصراعات. يغلف صفنا SoundbendSession Yjs مع هيكل مستند لكل مسار (Y.Map لبيانات المسار، Y.Array لخطوات النمط، Y.Text للكلمات/الملاحظات).
يمكن لاثنين إلى أربعة من المُنتجين تحرير المشروع نفسه في نفس الوقت مع مزامنة دقيقة للآخدة. هذا أصعب من التعاون في المستندات النصية لأن بيانات الصوت أكبر بمرات عديدة — نشارك البيانات الوصفية والأنماط عبر Yjs، وليس الصوت الخام. تبقى العينات الخام محلية (IndexedDB لكل مستخدم).
10. ميزانية الأداء
تشغيل داف كامل في المتصفح مع واجهة مستخدم بـ 60 إطارًا في الثانية + صوت في الوقت الفعلي + SharedArrayBuffer + WASM + عدة عملات يتطلب ميزانيات ضيقة. بعض الأرقام:
- خيط الصوت: ~2 مللي ثانية / مساحة تخزين 128 عينة عند تردد 48 كيلو هرتز (أجزاء فرعية)
- الخيط الرئيسي: 16.6 مللي ثانية / إطار بسرعة 60 إطارًا في الثانية؛ يجب أن تبقى معالجة الصوت أقل من 1 مللي ثانية لكل إطار
- إعداد Worklet: تكلفة واحدة-time ~10-50ms لكل تحميل Worklet (شحنة 15+ Worklet — نقوم بتجميعها)
- تخصيص ذاكرة SharedArrayBuffer: مساحات دائرية بحجم 4 كيلوبايت لكل معلمة عمل ديناميكي
- حجم قطعة Soundbend (بعد التجميع): ~496 كيلوبايت خام، ~120 كيلوبايت gzip
- التحميل الكامل للمشروع (بدون ذاكرة مؤقتة): ~800 مللي ثانية على جهاز كمبيوتر متوسط المدى
- تصدير العرض: ~0.3x إلى 2x من الوقت الفعلي حسب تعقيد سلسلة التأثيرات
11. مُختبر اختبار الفراغ
الانحدارات الرقمية الصوتية تحدث بصمت — يصبح الصوت مختلفًا بطرق خفية لا يمكن اكتشافها بمراجعة الشيفرة. يحتوي Soundbend على مُختبر اختبار خالي من الأخطاء مُدار بواسطة Puppeteer في tests/audio-null/.
لكل تأثير × معايير × إشارة اختبار، يتم عرض المحرك عبر OfflineAudioContext داخل Chromium بدون واجهة، ويختبر الناتج WAV مقابل ذهبي مُسجَّل، ويفشل البناء إذا تجاوزت الذروة المتبقية -60 ديسيبل فعّال.
تم إضافة Wave 14F 100 بذرة SeedSynth و32 نمط طبول Geist ذهبي. عندما دمجنا Soundbend في AudioStudio (Wave 14B-G)، اكتشفت اختبارات null-test أي شيء قد يعطل الأدوات البرمجية بشكل سري. نجحت 96 من أصل 100 بذرة SeedSynth بشكل متطابق. فشلت 4 بذور بسبب أخطاء مسبقة في Chromium Web Audio (انزياح تردد مرشح عالي الجودة بين مثيلات OfflineAudioContext) — وليس عودة مُعَدَّة، ولا يمكن إصلاحها من خلال JS.
تتلاشى انزياحات معالجة الإشارة الرقمية (DSP) دون أن يسمعها مراجعة الكود. يمكن لـ "الحقيبة الاختبارية للحالة الصفرية" اكتشافها — وهذا هو السبب في أنها تمنع CI.
12. لماذا كان الخيار المفضل هو المتصفح + العميلية
لديها مُعَدَّات DAW الأصلية (Ableton، Logic، FL Studio) مُتَقَدِّمة بـ 30 عامًا. كسرها ميزات مُقَارنة مُعَدَّة لطريق طويل. لكن السعر — كان من الممكن الفوز به فورًا من خلال اتخاذ اختيارات معمارية مختلفة.
عبرت WebAssembly الحد الأدنى للأداء في عام 2022-2024. تم إصدار Web Audio AudioWorklets على نطاق واسع تقريبًا في نفس الوقت. استقرت SharedArrayBuffer + COOP/COEP. تدعم كل من Chromium و Firefox و Safari جميع واجهات البرمجة المطلوبة بأداء كافٍ.
التأثير المالي: إذا تم معالجة الصوت على جهاز المستخدم، فلا ندفع مقابل ذلك. تكلفة هامشية لكل مشترك Pro تقترب من الصفر. لذا فإن $4.99/شهر مستدام لأبد. طفل في لاغوس بجهاز أندرويد من عام 2020 يحصل على برنامج DAW كامل، يدفع شخص في سان فرانسيسكو نفس $4.99 للوصول إليه.
اقرأ مقالة هيكلة الأسعار لفهم الاقتصاد. بالنسبة لـ DSP، هذا هو جزء كبير من القصة.
جربه
Soundbend موجود في morph.cool/soundbend. يعمل الوضع المجاني دون تسجيل. يفتح خطة Pro بسعر $4.99/شهر سلسلة التصنيف + مُحدد الذروة الحقيقية + إعدادات مسبقة إضافية. مُدخل مُوسيقى WebMIDI مرحَّب به، غير مطلوب.
— هايدن وفريق وكيل Morph
22 أبريل 2026