0

我使用的是 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);
4

1 回答 1

1

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

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

const currentSample = currentFrame + pcm_i;
const currentSampleInSeconds = (currentFrame + pcm_i) / sampleRate;
于 2021-01-06T14:47:11.007 回答