يتضمن الإصدار Chrome 64 ميزة جديدة مرتقبة بشدة في واجهة برمجة التطبيقات Web Audio - AudioWorklet: سوف تتعلم هنا المفاهيم والاستخدام لإنشاء مخصص لمعالجة الصوت مع رمز JavaScript. يمكنك إلقاء نظرة على العروض التوضيحية المباشرة. ستطرأ المقالة التالية في السلسلة Audio Worklet Design Pattern قراءة مفيدة لإنشاء تطبيق صوتي متقدم.
الخلفية: ScriptProcessorNode
يتم تشغيل معالجة الصوت في Web Audio API في سلسلة محادثات منفصلة عن مؤشر ترابط واجهة المستخدم، ولذلك يعمل بسلاسة. لتفعيل معالجة الصوت المخصّصة في جافا سكريبت، اقترحت واجهة برمجة تطبيقات Web Audio استخدام ScriptProcessorNode معالِجات الأحداث لاستدعاء النص البرمجي للمستخدم في سلسلة واجهة المستخدم الرئيسية.
تظهر مشكلتان في هذا التصميم: معالجة الحدث غير متزامنة.
ويحدث تنفيذ الرمز البرمجي في سلسلة التعليمات الرئيسية. السابق
ويزيد من وقت الاستجابة، ويضغط الطرف الثاني على السلسلة الرئيسية
عادةً ما يكون مزدحمًا بمهام مختلفة متعلقة بواجهة المستخدم وDOM، مما يؤدي إلى
إلى "جانك" أو الصوت إلى "خلل". وبسبب هذا العيب الأساسي في التصميم،
تم إيقاف ScriptProcessorNode
نهائيًا من المواصفات
بـ AudioWorklet.
المفاهيم
تحتفظ Audio Worklet بشفرة JavaScript التي يقدمها المستخدم، وكل ذلك داخل
سلسلة معالجة الصوت. وهذا يعني أنه ليس من الضروري الانتقال إلى الصفحة الرئيسية
سلسلة المحادثات لمعالجة الصوت. يعني هذا أنه سيتم تشغيل رمز النص البرمجي الذي يقدمه المستخدم
في سلسلة عرض الصوت (AudioWorkletGlobalScope
) بالإضافة إلى
AudioNodes
مدمجة، ما يضمن عدم وقت استجابة إضافي ومتزامن
العرض.
التسجيل وإنشاء مثيل
يتكون استخدام ميزة Audio Worklet من جزأين: AudioWorkletProcessor
AudioWorkletNode
ويتم استخدام هذا الأسلوب أكثر من استخدام ScriptProcessorNode،
ولكن هناك حاجة إلى منح المطوّرين إمكانية منخفضة المستوى لإنشاء صوت مخصّص
قيد المعالجة. يمثّل AudioWorkletProcessor
معالج الصوت الفعلي.
في رمز JavaScript، وتظهر في AudioWorkletGlobalScope
.
AudioWorkletNode
هو نظير AudioWorkletProcessor
ويأخذ
بالاتصال من وإلى AudioNodes
الأخرى في سلسلة التعليمات الرئيسية. أُنشأها جون هنتر، الذي كان متخصصًا
النطاق العام الرئيسي والدوال مثل AudioNode
العادية.
في ما يلي زوج من مقتطفات الرمز لتوضيح التسجيل مثيل.
// The code in the main global scope.
class MyWorkletNode extends AudioWorkletNode {
constructor(context) {
super(context, 'my-worklet-processor');
}
}
let context = new AudioContext();
context.audioWorklet.addModule('processors.js').then(() => {
let node = new MyWorkletNode(context);
});
لإنشاء AudioWorkletNode
، يجب إضافة AudioContext.
واسم المعالج كسلسلة. يمكن تعريف المعالج
تم تحميلها وتسجيلها من خلال استدعاء addModule()
لعنصر Audio Worklet الجديد.
لا تتوفر واجهات برمجة تطبيقات Worklet، بما في ذلك Audio Worklet، إلا في
سياق آمن، وبالتالي
يجب عرض الصفحة التي تستخدمها عبر HTTPS، على الرغم من أن http://localhost
يعتبر آمنًا للاختبار المحلي.
يمكنك ضبط الفئة الفرعية AudioWorkletNode
لتحديد
عقدة مخصصة مدعومة بالمعالج الذي يعمل على الوظيفة المصغّرة.
// This is the "processors.js" file, evaluated in AudioWorkletGlobalScope
// upon audioWorklet.addModule() call in the main global scope.
class MyWorkletProcessor extends AudioWorkletProcessor {
constructor() {
super();
}
process(inputs, outputs, parameters) {
// audio processing code here.
}
}
registerProcessor('my-worklet-processor', MyWorkletProcessor);
تعتمد الطريقة registerProcessor()
في AudioWorkletGlobalScope
على
نصية لاسم المعالج المراد تسجيله وتعريف الفئة.
بعد الانتهاء من تقييم رمز البرنامج النصي في النطاق العمومي،
سيتم التعامل بشكل نهائي مع وعد AudioWorklet.addModule()
لإعلام المستخدمين
أن تعريف الفئة جاهز للاستخدام في النطاق العمومي الرئيسي.
المَعلمات الصوتية المخصّصة
أحد الأشياء المفيدة بشأن AudioNodes هي المعلمة القابلة للجدولة
التشغيل الآلي باستخدام AudioParam
يمكن لـ AudioWorkletNodes استخدام هذه العناصر للحصول على
المعاملات المكشوفة التي يمكن التحكم فيها وفقًا لمعدل الصوت تلقائيًا.
يمكن الإعلان عن المعلَمات الصوتية التي يحددها المستخدم في AudioWorkletProcessor
تعريف الفئة من خلال إعداد مجموعة من AudioParamDescriptor
. تشير رسالة الأشكال البيانية
ويلتقط محرك WebAudio الأساسي هذه المعلومات أثناء
إنشاء AudioWorkletNode، ثم إنشاء روابط
AudioParam
إلى العقدة وفقًا لذلك.
/* A separate script file, like "my-worklet-processor.js" */
class MyWorkletProcessor extends AudioWorkletProcessor {
// Static getter to define AudioParam objects in this custom processor.
static get parameterDescriptors() {
return [{
name: 'myParam',
defaultValue: 0.707
}];
}
constructor() { super(); }
process(inputs, outputs, parameters) {
// |myParamValues| is a Float32Array of either 1 or 128 audio samples
// calculated by WebAudio engine from regular AudioParam operations.
// (automation methods, setter) Without any AudioParam change, this array
// would be a single value of 0.707.
const myParamValues = parameters.myParam;
if (myParamValues.length === 1) {
// |myParam| has been a constant value for the current render quantum,
// which can be accessed by |myParamValues[0]|.
} else {
// |myParam| has been changed and |myParamValues| has 128 values.
}
}
}
طريقة واحدة (AudioWorkletProcessor.process()
)
تتم معالجة الصوت الفعلي في طريقة معاودة الاتصال بـ process()
ضمن
AudioWorkletProcessor
يجب أن ينفّذه مستخدم في الفئة.
التعريف. يستدعي محرك WebAudio هذه الدالة بتنسيق
نمط لخلاصة الإدخالات والمَعلمات واسترجاع المخرجات.
/* AudioWorkletProcessor.process() method */
process(inputs, outputs, parameters) {
// The processor may have multiple inputs and outputs. Get the first input and
// output.
const input = inputs[0];
const output = outputs[0];
// Each input or output may have multiple channels. Get the first channel.
const inputChannel0 = input[0];
const outputChannel0 = output[0];
// Get the parameter value array.
const myParamValues = parameters.myParam;
// if |myParam| has been a constant value during this render quantum, the
// length of the array would be 1.
if (myParamValues.length === 1) {
// Simple gain (multiplication) processing over a render quantum
// (128 samples). This processor only supports the mono channel.
for (let i = 0; i < inputChannel0.length; ++i) {
outputChannel0[i] = inputChannel0[i] * myParamValues[0];
}
} else {
for (let i = 0; i < inputChannel0.length; ++i) {
outputChannel0[i] = inputChannel0[i] * myParamValues[i];
}
}
// To keep this processor alive.
return true;
}
بالإضافة إلى ذلك، يمكن استخدام القيمة المعروضة لطريقة process()
للأغراض التالية:
التحكُّم في مدة عمل AudioWorkletNode
حتى يتمكّن المطوّرون من إدارتها
أثر الذاكرة. عرض false
من process()
علامات طريقة
المعالِج غير نشط، ولم يعُد محرّك "WebAudio
" يستدعي
. للحفاظ على نشاط المعالج، يجب أن تعرض الطريقة true
.
بخلاف ذلك، يعد زوج العقدة والمعالج من البيانات غير الضرورية التي يجمعها النظام.
في النهاية.
الاتصال ثنائي الاتجاه باستخدام MessagePort
في بعض الأحيان، تريد AudioWorkletNode
المخصص عرض عناصر التحكم
يتم ربطها بـ AudioParam
، مثل سمة type
مستندة إلى سلسلة.
يُستخدم للتحكّم في فلتر مخصص. لهذا الغرض وأكثر من ذلك،
الجهازان AudioWorkletNode
وAudioWorkletProcessor
مزودان
MessagePort
للاتصال ثنائي الاتجاه. أي نوع من البيانات المخصّصة
ويمكن استبداله من خلال هذه القناة.
يمكن الوصول إلى MessagePort باستخدام السمة .port
في كل من العقدة
المعالج. ترسل طريقة port.postMessage()
للعقدة رسالة إلى
معالِج port.onmessage
الخاص بالمعالج المرتبط وبعكس ذلك.
/* The code in the main global scope. */
context.audioWorklet.addModule('processors.js').then(() => {
let node = new AudioWorkletNode(context, 'port-processor');
node.port.onmessage = (event) => {
// Handling data from the processor.
console.log(event.data);
};
node.port.postMessage('Hello!');
});
/* "processors.js" file. */
class PortProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.port.onmessage = (event) => {
// Handling data from the node.
console.log(event.data);
};
this.port.postMessage('Hi!');
}
process(inputs, outputs, parameters) {
// Do nothing, producing silent output.
return true;
}
}
registerProcessor('port-processor', PortProcessor);
يتيح MessagePort
استخدام ملف قابل للتحويل، ما يتيح لك
نقل تخزين البيانات أو وحدة WASM عبر حدود سلسلة التعليمات. سيتم فتح الرابط
احتمالات لا حصر لها بشأن كيفية استخدام نظام Audio Worklet.
الاطّلاع على: إنشاء WinNode
وفي ما يلي مثال كامل لـ WinNode يعتمد على
"AudioWorkletNode
" وAudioWorkletProcessor
"
ملف index.html
:
<!doctype html>
<html>
<script>
const context = new AudioContext();
// Loads module script with AudioWorklet.
context.audioWorklet.addModule('gain-processor.js').then(() => {
let oscillator = new OscillatorNode(context);
// After the resolution of module loading, an AudioWorkletNode can be
// constructed.
let gainWorkletNode = new AudioWorkletNode(context, 'gain-processor');
// AudioWorkletNode can be interoperable with other native AudioNodes.
oscillator.connect(gainWorkletNode).connect(context.destination);
oscillator.start();
});
</script>
</html>
ملف gain-processor.js
:
class GainProcessor extends AudioWorkletProcessor {
// Custom AudioParams can be defined with this static getter.
static get parameterDescriptors() {
return [{ name: 'gain', defaultValue: 1 }];
}
constructor() {
// The super constructor call is required.
super();
}
process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const gain = parameters.gain;
for (let channel = 0; channel < input.length; ++channel) {
const inputChannel = input[channel];
const outputChannel = output[channel];
if (gain.length === 1) {
for (let i = 0; i < inputChannel.length; ++i)
outputChannel[i] = inputChannel[i] * gain[0];
} else {
for (let i = 0; i < inputChannel.length; ++i)
outputChannel[i] = inputChannel[i] * gain[i];
}
}
return true;
}
}
registerProcessor('gain-processor', GainProcessor);
تتناول هذه المقالة أساسيات نظام Audio Worklet. تتوفر عروض توضيحية مباشرة في مستودع GitHub لفريق Chrome WebAudio.
نقل الميزة: من تجريبي إلى ثابت
تكون ميزة Audio Worklet مفعّلة تلقائيًا في الإصدار 66 من Chrome أو الإصدارات الأحدث. في Chrome 64 وChrome 65، كانت الميزة خلف العلامة التجريبية.