JSFiddle - React, Tailwind, and code Playground
by octatone
JavaScript
var isPlaying = false; // Are we currently playing?
var startTime; // The start time of the entire sequence.
var current16thNote; // What note is currently last scheduled?
var tempo = 132.0; // tempo (in beats per minute)
var lookahead = 25.0; // How frequently to call scheduling function
//(in milliseconds)
var scheduleAheadTime = 0.1; // How far ahead to schedule audio (sec)
// This is calculated from lookahead, and overlaps
// with next interval (in case the timer is late)
var nextNoteTime = 0.0; // when the next note is due.
var noteLength = 0.03; // length of "beep" (in seconds)
var timerID = 0; // setInterval identifier.
var last16thNoteDrawn = -1; // the last "box" we drew on the screen
var notesInQueue = []; // the notes that have been put into the web audio,
// and may or may not have played yet. {note, time}
function nextNote() {
// Advance current note and time by a 16th note...
var secondsPerBeat = 60.0 / tempo; // Notice this picks up the CURRENT
// tempo value to calculate beat length.
nextNoteTime += 0.25 * secondsPerBeat; // Add beat length to last beat time
current16thNote++; // Advance the beat number, wrap to zero
if (current16thNote == 32) {
current16thNote = 0;
}
}
function scheduleNote( beatNumber, time ) {
var length = noteLength;
// push the note on the queue, even if we're not playing.
notesInQueue.push( { note: beatNumber, time: time } );
// create an oscillator
var osc = musicContext.createOscillator();
osc.type = 1;
osc.connect( musicContext.destination );
if (beatNumber % 16 === 0) { // beat 0 == low pitch
osc.frequency.value = 220.0;
length = 0.1;
}
else if (beatNumber % 7 === 0) {
...