当我停止播放声音时,如何避免这种"咔哒"声?

Lou*_*pax 7 audio html5-audio

我真的希望这个问题能够成为一个编程问题并且最终不会出现声音力学的问题...这里......

我正在做一些实验,以弄清楚Web Audio API的工作原理.我想要做的是一个简单的"挂断电话"声音循环播放.问题是当声音结束时,你可以听到一声非常烦人的"咔哒"声.我无法更好地解释它,但如果您测试代码,您可以听到它.

有什么方法可以避免这种情况吗?我可以应用一些过滤器或任何东西?

var audioContext = new (AudioContext || webkitAudioContext)();
    
    var frequencyOffset = 0
    function boop(){
      // Our sound source is a simple triangle oscillator
      var oscillator = audioContext.createOscillator(); // Create sound source  
      oscillator.type = 'triangle';
      
      // Adding a gain node just to lower the volume a bit and to make the
      // sound less ear-piercing
      var gain = audioContext.createGain();
      oscillator.connect(gain);
      gain.connect(audioContext.destination);
      
      gain.gain.value = 0.1;
      // Just for fun let the frequency increase on each itteration
      oscillator.frequency.value = 200 + frequencyOffset;
      oscillator.start(0);
      
      // The sound should last for 250ms
      setTimeout(function(){
        oscillator.disconnect(); 
        oscillator.stop();
        gain.disconnect();
      }, 250);
      frequencyOffset += 1;
    }

    setInterval(boop, 500);
Run Code Online (Sandbox Code Playgroud)

Sil*_*gel 7

这是一个音频问题,而不是编程问题.当波形在波浪中间停止/切割而不是在零交叉处时,会发出您听到的咔嗒声.

音频范例的最佳简单解决方案是快速淡出,而不仅仅是停止播放.

稍微复杂的解决方案是找到下一个过零点并在此点停止播放.


tim*_*liu 6

这里有一个关于我们为什么会听到咔嗒声(这是人耳的声音)的简要说明,以及如何使用 Web 音频 API 解决这个问题的好例子:http : //alemangui.github.io/blog//2015/12 /26/ramp-to-value.html

这篇文章的主要内容是消除点击的指数方法效果更好;indexRampToValueAtTimesetTargetAtTime

使用 setTargetAtTime 删除点击

var context = new AudioContext();
var oscillator = context.createOscillator();
var gainNode = context.createGain();

oscillator.connect(gainNode);
gainNode.connect(context.destination)
oscillator.start();

stopButton.addEventListener('click', function() {
    gainNode.gain.setTargetAtTime(0, context.currentTime, 0.015);
});
Run Code Online (Sandbox Code Playgroud)

使用exponentialRampToValueAtTime 删除点击

var context = new AudioContext();
var oscillator = context.createOscillator();
var gainNode = context.createGain();

oscillator.connect(gainNode);
gainNode.connect(context.destination)

oscillator.start();

stopButton.addEventListener('click', function() {
    // Important! Setting a scheduled parameter value
    gainNode.gain.setValueAtTime(gainNode.gain.value, context.currentTime); 

    gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.03);
});
Run Code Online (Sandbox Code Playgroud)

在我的用例中,这两个都对我有用,exponentialRampToValueAtTime工作得稍微好一些。使用setTargetAtTime 时,我仍然可以听到微弱的点击声。