How can I avoid this 'clicking' sound when I stop playing a sound?

前端 未结 3 2013
别跟我提以往
别跟我提以往 2020-12-30 12:55

I really hope this question stays a programming question and do not end up an Sound Mechanics question... Here goes...

I am doing some experiments in order to figure

相关标签:
3条回答
  • 2020-12-30 13:39

    Looks like the Web Audio API gives the developer an easy way of stopping a sound source from playing without abruptly stopping the waveform and avoid any noise and sound artifacts.

    1. Create your sound source (in my example an oscillator)
    2. Create a gain node and connect it with the sound source.
    3. Start the sound source and set the gain value to 0. That way, you won't listen to the sound even if it's technically playing
    4. Set the gain value to 1 when you want the source to play and to 0 when it should not play. The gain node will handle the rest, and no clicking will be heard

    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);

    0 讨论(0)
  • 2020-12-30 13:46

    There's a brief explanation of why we hear the clicking sound (it's a human ear thing) and good examples of how to get around that using the Web audio API here: http://alemangui.github.io/blog//2015/12/26/ramp-to-value.html

    The main takeaway from the article is that the exponential methods to remove the click work better; exponentialRampToValueAtTime and setTargetAtTime.

    Using setTargetAtTime to remove the click

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

    Using exponentialRampToValueAtTime to remove the click

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

    Both of these worked for me in my use case, with exponentialRampToValueAtTime working slightly better. I could still hear a faint click using setTargetAtTime.

    0 讨论(0)
  • 2020-12-30 13:58

    This is an audio issue, not a programming problem. The click you hear occurs when a waveform is stopped/cut in the middle of a wave, rather than at a zero-crossing.

    The best simple solution from a audio paradigm is to very quickly fade-out, instead of just stopping playback.

    A slightly more complex solution is to find the next zero-crossing and stop playback at precisely that point.

    0 讨论(0)
提交回复
热议问题