Search code examples
javascriptapiweb-audio-api

Playing a chord with OscillatorNodes using the Web Audio API


I would like to play a chord using OscillatorNodes:

var ac = new (window.AudioContext || window.webkitAudioContext);
// C4, E4, G4
var freqs = [261.63, 329.63, 392.00];
for(var i=0;i<freqs.length;i++) {
  var o = ac.createOscillator();
  o.frequency.value = freqs[i];
  o.connect(ac.destination);
  o.noteOn(0);
  setTimeout(function() {o.noteOff(0)}, 1000);
}

But this approach sounds like a mess (here's what it sounds like). If I try creating new AudioContexts for each note in the chord, then it sounds fine (like this):

// C4, E4, G4
var freqs = [261.63, 329.63, 392.00];
for(var i=0;i<freqs.length;i++) {
  var ac = new (window.AudioContext || window.webkitAudioContext);
  var o = ac.createOscillator();
  o.frequency.value = freqs[i];
  o.connect(ac.destination);
  o.noteOn(0);
  setTimeout(function() {o.noteOff(0)}, 1000);
}

But I read that you're only supposed to have one AudioContext. What am I doing wrong?


Solution

  • Not sure this can be a solution, but I found out inserting a GainNode and setting it's value so that the gain will sum to 1 eliminates the issue:

    var ac = new (window.AudioContext || window.webkitAudioContext);
    // C4, E4, G4
    var freqs = [261.63, 329.63, 392.00];
    for(var i=0;i<freqs.length;i++) {
      var o = ac.createOscillator();
      var g = ac.createGainNode();
      o.frequency.value = freqs[i];
      o.connect(g);
      g.gain.value = 1/freqs.length;
      g.connect(ac.destination);
      o.start(0);
      setTimeout(function(s) {s.stop(0)}, 1000, o);
    }
    

    I tried this on Chrome 23.0.1271.101

    Updated to use the new start and stop methods: createOscillator noteOn not working