【问题标题】:Simple WebAudioWorklet Generating Choppy Audio简单的 WebAudioWorklet 生成断断续续的音频
【发布时间】:2021-04-11 22:45:14
【问题描述】:

我使用的是 Firefox 84.0.1、Windows 10、x86_64。我有一个非常基本的WebAudioWorklet 合成器,可以将键映射到音符的频率。当一个键被按住时,它会产生非常断断续续的音频。这让我认为没有足够的音频样本排队等待扬声器播放,因此音频会进出。但是,在音频处理方面,我正在执行一项非常低强度的任务。结果,我觉得默认的Worklet 设置应该能够处理这个问题。这是我的代码:

syn.js

(async() => {
  let a2_hertz = 110.0;
  let twelfth_root_of_two = Math.pow(2.0, 1.0 / 12.0);
  
  let audio_cxt = new AudioContext();
  await audio_cxt.audioWorklet.addModule("syn-worklet.js", {credentials: "omit"});
 
  let audio_worklet_options = {
    numberOfInputs: 0,
    numberOfOutputs: 1,
    outputChannelCount: [audio_cxt.destination.channelCount]
  };
  let audio_worklet = new AudioWorkletNode(audio_cxt, "synthesiser", audio_worklet_options);
  audio_worklet.connect(audio_cxt.destination);
  
  document.addEventListener("keydown", (evt) => {
    for (let key = 0; key < 12; ++key) {
      if (evt.code == "Key" + "QWERTYUIOPAS"[key]) {
        audio_worklet.port.postMessage(a2_hertz * Math.pow(twelfth_root_of_two, key));
      }
    }
  });
  
  document.addEventListener("keyup", (evt) => {
    audio_worklet.port.postMessage(0.0);
  });
})();

syn-worklet.js

function angular_frequency(hertz) {
  return hertz * 2 * Math.PI;
}

let OSC_TYPES = {"sine": 0, "square": 1, "triangle": 2};
function oscillator(hertz, osc_type) {
  switch (osc_type) {
    case OSC_TYPES.sine: {
      return Math.sin(angular_frequency(hertz) * currentTime);
    } break;
    case OSC_TYPES.square: {
      return Math.sin(angular_frequency(hertz) * currentTime) > 0.0 ? 1.0 : -1.0;
    } break;
    case OSC_TYPES.triangle: {
      return Math.asin(Math.sin(angular_frequency(hertz) * currentTime)) * (2.0 / Math.PI);
    } break;
    default: {
      return 0.0;
    }
  }
}

class Synthesiser extends AudioWorkletProcessor {
  constructor() {
    super();

    this.hertz = 0.0;

    this.port.onmessage = (evt) => {
      this.hertz = evt.data;
    };
  }

  process(inputs, outputs) {
    let channels = outputs[0];
    let num_samples_per_channel = channels[0].length;

    for (let pcm_i = 0; pcm_i < num_samples_per_channel; ++pcm_i) {
      let volume = 0.1;
      let pcm_value = volume * oscillator(this.hertz, OSC_TYPES.sine);
      for (let channel_i = 0; channel_i < channels.length; ++channel_i) {
        channels[channel_i][pcm_i] = pcm_value;
      }
    }

    return true;
  }
}

registerProcessor("synthesiser", Synthesiser);

【问题讨论】:

    标签: javascript firefox audio web-audio-api audio-worklet


    【解决方案1】:

    我认为问题在于currentTime 似乎是唯一影响oscillator() 函数输出的因素。但是currentTime 在调用process() 函数期间不会改变。

    我建议改用currentFrame。它会给你一个整数值,代表currentTime(以帧为单位)。如果将其与 pcm_i 结合使用,您将获得正在处理的样本的实际索引。

    const currentSample = currentFrame + pcm_i;
    const currentSampleInSeconds = (currentFrame + pcm_i) / sampleRate;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2017-06-18
      相关资源
      最近更新 更多