You are not recognized as the original poster of this topic.
var audioCtx=new(window.AudioContext||window.webkitAudioContext)();
let semitones={C:-9,D:-7,E:-5,F:-4,G:-2,A:0,B:2};
function noteToFreq(note){
//Notes can either be integers or strings.
let semitone;
if(typeof note==="number"){semitone=note;}
else{
let match=note.match(/^([A-G])([b#]?)(-?\d+)$/i);
if(!match)throw new Error("Invalid note: "+note);
semitone=semitones[match[1].toUpperCase()];
let accidental=match[2],octave=parseInt(match[3],10);
if(accidental==="#")semitone++;
if(accidental==="b")semitone--;
semitone+=(octave-4)*12; //4 is the octave of A4
}
return 440*Math.pow(2,semitone/12);
}
function playNote(note,duration,velocity,start){
let osc=audioCtx.createOscillator(),
gain=audioCtx.createGain(),
freq=noteToFreq(note);
osc.frequency.setValueAtTime(freq,audioCtx.currentTime+start);
gain.gain.setValueAtTime(velocity,audioCtx.currentTime+start);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start(audioCtx.currentTime+start);
osc.stop(audioCtx.currentTime+start+duration);
}
function scheduleNotes(notes){
notes=notes.slice().sort((a,b)=>a.start-b.start);
let startTime=audioCtx.currentTime,
index=0,
interval=setInterval(()=>{
let currentTime=audioCtx.currentTime-startTime;
while(index<notes.length&¬es[index].start<=currentTime*1000){
let{note,duration,velocity,start}=notes[index];
playNote(note,duration,velocity,start);
index++;
}
if(index>=notes.length)
clearInterval(interval); //Stop
},50);
}
//scheduleNotes([{note:"C4",start:0,duration:10,velocity:.5},{note:"A4",start:5,duration:5,velocity:1}]);
scheduleNotes((()=>{let a=[],n=[..."CDEFGA"];for(let i=0;i<100;i++){let note=n[Math.floor(Math.random()*n.length)]+(4+Math.floor(Math.random()*3)),duration=.1+Math.random()*.2,velocity=Math.random()*.25,start=i/10;a.push({note,duration,velocity,start});}return a;})());