2

I have the following snippet that creates an oscillator and plays it at a certain volume. I keep the oscillator variable outside of the scope of the function so that I can stop it with other functions if I need to.

var oscillator = null;
var isPlaying = false;

function play(freq, gain) {

    //stop the oscillator if it's already playing
    if (isPlaying) {
        o.stop();
        isPlaying = false;
    }

    //re-initialize the oscillator
    var context = new AudioContext();

    //create the volume node;
    var volume = context.createGain();
    volume.connect(context.destination);
    volume.gain.value = gain;

    //connect the oscillator to the nodes
    oscillator = context.createOscillator();
    oscillator.type = 'sine';
    oscillator.frequency.value = freq;

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

    //start playing
    oscillator.start();
    isPlaying = true;

    //log
    console.log('Playing at frequency ' + freq + ' with volume ' + gain);
}

Trouble is, the gain node volume seems to not work as you'd expect. From what I understand, a gain of 0 is muted, and a gain of 1 is 100% volume. But, in this case, passing 0 as the gain value only plays the sound muffled, as opposed to muting it completely (I hope I'm explaining that properly).

What am I doing wrong? Can anybody help?

2
  • why do you connect the oscillator to both the volume node and the context.destination. Try removing the second connection.
    – jaket
    Commented Feb 27, 2016 at 0:31
  • @jaket you're right. Thanks! If you post that as the answer I'll accept it.
    – Cliff
    Commented Feb 27, 2016 at 1:19

2 Answers 2

8

The problem is that the oscillator node is connect to both the gain node and the destination node.

                +---------------+
                |               |
 oscillator ----+----> gain ----+---> destination

So even if the gain node is attenuated to 0 there is still another path to the destination. The problem can be by deleting the second oscillator.connect line.

oscillator.connect(volume);
//oscillator.connect(context.destination);
2
  • 1
    I can't thank you enough! This is a part that I really missed in other explanations elsewhere. Commented Apr 30, 2022 at 1:32
  • Very helpful answer, Well explained and straight to the point
    – elkhayder
    Commented Nov 19, 2022 at 21:07
6

For anyone falling here from google. I do it normally like this:

    // I create the class with best available
    var ctxClass = window.audioContext || window.AudioContext || window.AudioContext || window.webkitAudioContext
    // We instance the class, create the context
    var ctx = new ctxClass();
    // Create the oscillator
    var osc = ctx.createOscillator();
    // Define type of wave
    osc.type = 'sine';
    // We create a gain intermediary
    var volume = ctx.createGain();
    // We connect the oscillator with the gain knob
    osc.connect(volume);
    // Then connect the volume to the context destination
    volume.connect(ctx.destination);
    // We can set & modify the gain knob
    volume.gain.value = 0.1;

    //We can test it with some frequency at current time
    osc.frequency.setValueAtTime(440.0, ctx.currentTime);
    if (osc.noteOn) osc.noteOn(0);
    if (osc.start) osc.start();

    // We'll have to stop it at some point
    setTimeout(function () {
        if (osc.noteOff) osc.noteOff(0);
        if (osc.stop) osc.stop();
        // We can insert a callback here, let them know you've finished, may be play next note?
        //finishedCallback();
    }, 5000);

Not the answer you're looking for? Browse other questions tagged or ask your own question.