Search code examples
web-audio-api

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


I’m trying to create a kick drum sound that must sound exactly the same when looped at different tempi. The implementation below sounds exactly the same when repeated once every second, but it sounds to me like every other kick has a higher pitch when played every half second. It’s like there is a clipping sound or something.

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
}

Here’s the same code on JSFiddle: https://jsfiddle.net/1kLn26p4/3/


Solution

  • The oscillator is set to start at the same time as the change from the default frequency of 440 Hz to 150 Hz. Sometimes this results in a glitch as the transition is momentarily audible.

    The glitch can be prevented by setting the frequency of the oscillator node to 150 Hz at the time of creation. So add:

    oscillator.frequency.value = 150;
    

    If you want to make the glitch more obvious out of curiosity, try:

    oscillator.frequency.value = 5000;
    

    and you should be able to hear what is happening.

    Updated fiddle.

    EDIT

    In addition the same problem is interacting with the timing of the ramp. You can further improve the sound by ensuring that the setValueAtTime event always occurs a short time after playback starts:

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

    Again, not perfect at 3500 Hz, but it's an improvement, and I'm not sure you'll achieve sonic perfection with Web Audio. The best you can do is try to mask these glitches until implementations improve. At actual kick drum frequencies (e.g. the 150 Hz in your original Q.), I can't tell any difference between successive sounds. Hopefully that's good enough.

    Revised fiddle.