如何让基于振荡器的底鼓每次发出完全相同的声音

How to make oscillator-based kick drum sound exactly the same every time

我正在尝试创建一种以不同速度循环播放时听起来必须完全相同的底鼓声音。下面的实现在每秒重复一次时听起来完全相同,但在我看来,每半秒播放一次时,其他踢腿的音调会更高。好像有削波声什么的

var context = new AudioContext();

function playKick(when) {
    var oscillator = context.createOscillator();
    var gain = context.createGain();
    oscillator.connect(gain);
    gain.connect(context.destination);

    oscillator.frequency.setValueAtTime(150, when);
    gain.gain.setValueAtTime(1, when);
    oscillator.frequency.exponentialRampToValueAtTime(0.001, when + 0.5);
    gain.gain.exponentialRampToValueAtTime(0.001, when + 0.5);

    oscillator.start(when);
    oscillator.stop(when + 0.5);
}

for (var i = 0; i < 16; i++) {
    playKick(i * 0.5); // Sounds fine with multiplier set to 1
}

这是 JSFiddle 上的相同代码:https://jsfiddle.net/1kLn26p4/3/

不正确; oscillator.start 将从 0 开始该阶段。问题是您将 "when" 参数从零开始;你应该从 context.currentTime.

开始
for (var i = 0; i < 16; i++) {
    playKick(context.current time + i * 0.5); // Sounds fine with multiplier set to 1
}

振荡器设置为在从默认频率 440 Hz 更改为 150 Hz 的同时启动。有时这会导致出现故障,因为可以暂时听到过渡。

可以通过在创建时将振荡器节点的频率设置为 150 Hz 来防止毛刺。所以添加:

oscillator.frequency.value = 150;

如果你出于好奇想让故障更明显,试试:

oscillator.frequency.value = 5000;

你应该能听到发生了什么。

Updated fiddle.

编辑

此外,同样的问题与斜坡的时间相互作用。您可以通过确保 setValueAtTime 事件始终在播放开始后的短时间内发生来进一步改善声音:

   oscillator.frequency.setValueAtTime(3500, when + 0.001);

同样,在 3500 Hz 下并不完美,但这是一个改进,我不确定您能否通过 Web Audio 获得完美的声音。您能做的最好的事情就是尝试掩盖这些故障,直到实现得到改进。在实际的底鼓频率下(例如原始 Q. 中的 150 Hz),我无法分辨出连续声音之间的任何区别。希望这足够好。

Revised fiddle.