Skip to content

Instantly share code, notes, and snippets.

@syncopika
Created March 2, 2018 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syncopika/329d06aff900de6eef491e0c3b9ee8ca to your computer and use it in GitHub Desktop.
Save syncopika/329d06aff900de6eef491e0c3b9ee8ca to your computer and use it in GitHub Desktop.
web audio demo - scheduling a sequence of notes and getting smooth notes
<!doctype html>
<html>
<head>
</head>
<body>
<p> testing Web Audio... </p>
<button onclick='test()'> play </button>
</body>
<script>
var ctx = new AudioContext();
gainNode = ctx.createGain();
gainNode.connect(ctx.destination);
gainNode.gain.setTargetAtTime(0, 0, 0); // set gain to 0 initially
var nextTime; // hold the next time an oscillator needs to play
// the beginning notes to 'Sand Canyon'. taken from the demo json file found in my piano_roll_browser application.
var notes = [
{"freq":349.23,"duration":200,"block":{"id":"F4col_0","length":"eighth","volume":"0.2","style":"default"}},
{"freq":0,"duration":100,"block":{"id":null,"length":"sixteenth","volume":"0.3","style":"default"}},
{"freq":523.25,"duration":100,"block":{"id":"C5col_1-2","length":"sixteenth","volume":"0.2","style":"default"}},
{"freq":493.88,"duration":200,"block":{"id":"B4col_2","length":"eighth","volume":"0.8","style":"default"}},
{"freq":523.25,"duration":200,"block":{"id":"C5col_3","length":"eighth","volume":"0.2","style":"default"}},
{"freq":698.46,"duration":200,"block":{"id":"F5col_4","length":"eighth","volume":"0.2","style":"glide"}},
{"freq":622.25,"duration":200,"block":{"id":"Eb5col_5","length":"eighth","volume":"0.6","style":"default"}},
{"freq":587.33,"duration":200,"block":{"id":"D5col_6","length":"eighth","volume":"0.6","style":"default"}},
{"freq":523.25,"duration":200,"block":{"id":"C5col_7","length":"eighth","volume":"0.2","style":"default"}},
{"freq":493.88,"duration":200,"block":{"id":"B4col_8","length":"eighth","volume":"0.2","style":"legato"}},
{"freq":523.25,"duration":100,"block":{"id":"C5col_9-1","length":"sixteenth","volume":"0.2","style":"default"}},
{"freq":0,"duration":100,"block":{"id":null,"length":"sixteenth","volume":"0.3","style":"default"}},
{"freq":0,"duration":200,"block":{"id":null,"length":"eighth","volume":"0.3","style":"default"}}
];
function test(){
var counter = 0;
while(counter < notes.length){
var note = notes[counter];
var currTime = ctx.currentTime;
if(counter == 0){
nextTime = ctx.currentTime;
}
// create a new oscillator for each note
var osc = ctx.createOscillator();
osc.type = 'sine';
osc.connect(gainNode);
//osc.connect(ctx.destination);
// set frequency and volume
//osc.frequency.value = note.freq;
osc.frequency.setTargetAtTime(note.freq, 0.01, 0);
//gainNode.gain.value = note.block.volume; // deprecated way
// when you use setTargetAtTime to ramp up to a volume, you need to also ramp back down
// so there needs to be a corresponding setTargetAtTime
gainNode.gain.setTargetAtTime(parseFloat(note.block.volume), nextTime + .002, 0.002);
// using an exponential ramp sounds a bit like an electronic stab wave
// using a linear ramp sounds a bit like a mallet instrument
//gainNode.gain.exponentialRampToValueAtTime(note.block.volume, nextTime + 0.002);
osc.start(nextTime);
//gainNode.gain.exponentialRampToValueAtTime(0.01, nextTime + (note.duration/1000) - 0.002);
gainNode.gain.setTargetAtTime(0, nextTime + (note.duration/1000) - .008, 0.0020);
osc.stop(nextTime + (note.duration/1000));
nextTime = nextTime + (note.duration/1000);
counter++;
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment