ميزة Audio Worklet هي متاحة الآن بشكل تلقائي.

يتضمن الإصدار 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 مدمجة، ما يضمن عدم وقت استجابة إضافي ومتزامن العرض.

مخطط النطاق العمومي الرئيسي ومخطط الصوت Worklet
Fig.1

التسجيل وإنشاء مثيل

يتكون استخدام ميزة 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 استخدام هذه العناصر للحصول على المعاملات المكشوفة التي يمكن التحكم فيها وفقًا لمعدل الصوت تلقائيًا.

عقدة مُهمّة صوتية ومخطط لمعالج البيانات
Fig.2

يمكن الإعلان عن المعلَمات الصوتية التي يحددها المستخدم في 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 للاتصال ثنائي الاتجاه. أي نوع من البيانات المخصّصة ويمكن استبداله من خلال هذه القناة.

Fig.2
Fig.2

يمكن الوصول إلى 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، كانت الميزة خلف العلامة التجريبية.