Sesli İş Akışı artık varsayılan olarak kullanılabilir

Hongchan Choi

Chrome 64, Web Audio API'da merakla beklenen yeni bir özellikle birlikte sunuluyor: AudioWorklet olarak ayarlayın. Burada, bir dönüşüm etkinliği oluşturmak için özel ses işlemcisi ve JavaScript kodu içerir. Şu bölüme göz atın: canlı demolara gidin. Serideki bir sonraki makale olan Ses İş Akışı Tasarım Deseni, gelişmiş ses uygulaması geliştirmek için okumaya devam edebilirsiniz.

Arka plan: ScriptProcessorNode

Web Audio API'sında ses işleme, ana tablodan ayrı bir iş parçacığında çalışır sorunsuz bir şekilde çalışır. Özel ses işlemeyi etkinleştirmek için Web Audio API'sı, bir komut dosyası işlemcisi kullanarak ana kullanıcı arayüzü iş parçacığında kullanıcı komut dosyasını çağırmak için etkinlik işleyiciler.

Bu tasarımda iki sorun vardır: olay işleme eşzamansız ana iş parçacığı üzerinde kod yürütme işlemi gerçekleştirir. Önceki gecikmeyi tetikler ve ikincisi, gecikmeyi başlatır. genellikle kullanıcı arayüzlerine neden olan çeşitli kullanıcı arayüzü ve DOM ile ilgili görevlerle "tutkulu" olarak veya sesi "aksaklığa" çevirir. Bu temel tasarım hatası nedeniyle ScriptProcessorNode, spesifikasyonda kullanımdan kaldırıldı ve AudioWorklet'tir.

Kavramlar

Ses İş Akışı, kullanıcı tarafından sağlanan JavaScript kodunu ses işleme ileti dizisi. Yani, doğrudan ana panelinize ileti dizisine dokunun. Bu, kullanıcı tarafından sağlanan komut dosyası kodunun çalıştırılacağı anlamına gelir ses oluşturma ileti dizisinde (AudioWorkletGlobalScope) ve diğer sıfır ek gecikme ve eşzamanlı senkronizasyon sağlayan yerleşik AudioNodes oluşturma.

Ana küresel kapsam ve Ses İş Akışı kapsamı şeması
Fig.1

Kayıt ve örneklendirme

Ses İşlet'i kullanımı iki bölümden oluşur: AudioWorkletProcessor ve AudioWorkletNode. Bu, ScriptProcessorNode kullanımından daha karmaşıktır. Ancak geliştiricilere, özel ses içeriği için alt düzey bir ses olanağı sunmak için gereklidir. bahsedeceğim. AudioWorkletProcessor, gerçek ses işlemcisini temsil eder JavaScript kodunda yazılır ve AudioWorkletGlobalScope içinde bulunur. AudioWorkletNode, AudioWorkletProcessor değerinin eşdeğeridir ve şu değeri alır: ana iş parçacığındaki diğer AudioNodes ile olan bağlantıyla ilgilenir. Google ana global kapsamda gösterilir ve normal bir AudioNode gibi çalışır.

Aşağıda, kaydı ve kayıt işlemini gösteren örneklendirmektir.

// 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 oluşturmak için bir AudioContext eklemeniz gerekir bir dize olarak kullanır. İşleyen tanımı, yeni Ses İş Akışı nesnesinin addModule() çağrısı tarafından yüklenip kaydedildi. Audio Worklet'ı içeren Worklet API'leri yalnızca güvenli bağlam sağlar. bunları kullanan sayfanın HTTPS üzerinden sunulması gerekir, ancak http://localhost güvenli kabul edilir.

AudioWorkletNode alt sınıfını tanımlamak için iş akışında çalışan işlemci tarafından desteklenen bir özel düğüm.

// 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);

AudioWorkletGlobalScope içindeki registerProcessor() yöntemi bir kaydedilecek işlemci adı ve sınıf tanımına ilişkin dize. Global kapsamda komut dosyası kodunun değerlendirilmesi tamamlandıktan sonra AudioWorklet.addModule() tarafından verilen söz, kullanıcıları bilgilendirerek gerçekleştirilecek ana global kapsamda kullanılmaya hazır olduğunu belirtmelidir.

Özel ses parametreleri

AudioNodes ile ilgili yararlı şeylerden biri, planlanabilir parametredir. AudioParam ile otomasyon. AudioWorkletNodes, şunları almak için bunları kullanabilir: otomatik olarak kontrol edilebilen açıkta kalan parametreler.

Ses iş akışı düğümü ve işlemcisi şeması
Fig.2

Kullanıcı tanımlı ses parametreleri, AudioWorkletProcessor ile tanımlanabilir. bir AudioParamDescriptor kümesi ayarlayarak sınıf tanımını değiştirebilirsiniz. İlgili içeriği oluşturmak için kullanılan WebAudio motorunun bu bilgileri algılaması bir AudioWorkletNode'un oluşturulmasını ve daha sonra, AudioParam nesneleri buna uygun şekilde düğüme bağlayabilirsiniz.

/* 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() yöntemi

Gerçek ses işleme, process() geri çağırma yönteminde gerçekleşir. AudioWorkletProcessor. Sınıftaki bir kullanıcı tarafından uygulanmalıdır belirler. WebAudio motoru bu işlevi eş kronik bir şekilde çağırır girişler ve parametreler feed'ini ve çıkışları getirmeyi sağlar.

/* 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;
}

Buna ek olarak, process() yönteminin döndürülen değeri şu işlemler için kullanılabilir: geliştiricilerin yönetebilmesi için AudioWorkletNode ömrünü kontrol edebilir boyutu da büyük olur. process() yöntem işaretinden false döndürülüyor işlemci devre dışıdır ve WebAudio motoru artık yöntemidir. İşleyenin etkin durumda kalması için yöntemin true döndürmesi gerekir. Aksi takdirde, düğüm ve işlemci çifti sistem tarafından toplanan atıklardır. kazanacaksınız.

MessagePort ile çift yönlü iletişim

Bazen özel bir AudioWorkletNode, kontrol panelinde görünmeyen kontrolleri göstermek ister. AudioParam ile eşlenirken (ör. dizeye dayalı type özelliği) kontrol etmek için kullanılır. Bu amaç doğrultusunda ve daha sonrasında da AudioWorkletNode ve AudioWorkletProcessor şunları içerir: Çift yönlü iletişim için MessagePort. Her tür özel veri bu kanal üzerinden değiştirilebilir.

Fig.2
Fig.2

MessagePort, hem düğümdeki hem de düğümdeki .port özelliğiyle erişilebilir. göstermenizi sağlar. Düğümün port.postMessage() yöntemi, işleyicinin port.onmessage işleyicisi ile tersi de geçerlidir.

/* 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, aktarılabilir özelliği destekler. Bu özellik şunları yapmanıza olanak tanır: iş parçacığı sınırının üzerinde veri depolama alanı veya WASM modülü aktarın. Bu işlemin açıldığı tarih: nasıl kullanılabileceğine dair sayısız ihtimal var.

Adım adım açıklamalı: GainNode oluşturma

Aşağıdaki adımlarda, AudioWorkletNode ve AudioWorkletProcessor.

index.html dosyası:

<!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 dosyası:

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);

Bu bilgiler, Ses İş Akışı sisteminin temel özelliklerini kapsar. Canlı demolar var. Chrome WebAudio ekibinin GitHub deposunda.

Özellik geçişi: Deneysel'den kararlı sürüme

Audio Worklet, Chrome 66 veya sonraki sürümlerde varsayılan olarak etkindir. Chrome 64 ve 65 sürümlerinde bu özellik, deneysel aşamada öne çıkıyordu.