!function() { var contexts = [...Array(9).keys()].map(_=>new AudioContext), trackLen, timeout, nodes=[] p0 = (params) => { var tempo = 1/8 nodes.map(o => o.stop()) nodes = [] clearTimeout(timeout) var now = contexts[0].currentTime params[trackLen = 0].replace(/[\!\|]/g,'').split('\n').map((track, trackI) => { if(track) { if(track*1) { tempo = track/1000 } else { var context = contexts[trackI] var now = context.currentTime var node = new OscillatorNode(context) var gain = new GainNode(context) const real = new Float32Array(3) const imag = new Float32Array(3) real[0] = 0 imag[0] = 0 real[1] = 1 imag[1] = 0 real[2] = 1 imag[2] = 0 const wave = context.createPeriodicWave(real, imag) node.setPeriodicWave(wave) node.connect(gain).connect(context.destination) //if(!nodes[0])node.type = "triangle" track.split('').map((letter, i) => { var duration = 1, note = letter.charCodeAt(0) note -= note>90 ? 71 : 65 while(track[i+duration]=='-') { duration++ } if(trackLen=0) { node.frequency.setValueAtTime(65.406 * 1.06 ** note, now+i*tempo) if(i) { gain.gain.setTargetAtTime(0, now+(i-.5)*tempo, .05) } else { gain.gain.setTargetAtTime(1, now+.01, .05) } gain.gain.setTargetAtTime(1, now+i*tempo, .01) } }) gain.gain.value = 0 gain.gain.setTargetAtTime(0, now+(trackLen-.5)*tempo, .01) nodes.push(node) } } }) nodes.map(node => node.start()) timeout = setTimeout(() => p0(params), trackLen*1000*tempo) } }()