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

时间:2015-03-31 21:25:52

标签: 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);

3 个答案:

答案 0 :(得分:7)

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

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

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

答案 1 :(得分:4)

看起来Web Audio API为开发人员提供了一种简单的方法,可以在不突然停止波形的情况下停止播放声源,并避免任何噪音和声音伪影。

  1. 创建声源(在我的示例中为振荡器)
  2. 创建增益节点并将其与声源连接。
  3. 启动声源并将增益值设置为0.这样,即使技术上正在播放,您也不会听到声音
  4. 如果希望播放源,请将增益值设置为1,不播放时将增益值设置为0。增益节点将处理其余部分,并且不会听到任何点击
  5. var audioContext = new(AudioContext || webkitAudioContext)();
    
    var frequencyOffset = 0
      // 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. It will also allow us to mute and replay
    // our sound on demand
    var gainNode = audioContext.createGain();
    oscillator.connect(gainNode);
    gainNode.connect(audioContext.destination);
    
    gainNode.gain.value = 0;
    oscillator.frequency.value = 200;
    oscillator.start(0);
    
    function boop() {
      gainNode.gain.value = 0.1;
      // The sound should last for 250ms
      setTimeout(function() {
        gainNode.gain.value = 0;
      }, 250);
      oscillator.frequency.value++;
    }
    
    setInterval(boop, 500);

答案 2 :(得分:2)

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

本文的主要内容是删除点击工作的指数方法更好; exponentialRampToValueAtTime setTargetAtTime

使用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);
});

使用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);
});

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