Playing Along

A page of music can wait for a learner. They play the notes, on keys on the screen or on a real keyboard, and the page marks each one: a right note turns green, and a wrong one shows in red for a moment where it was played.

A trainer in a few lines

const lead = makeSynth("keys")
const page = showNotes("E4 D4 C4 D4 E4 E4 E4:2", "quarter")
page.playAlong({ mode: "wait", synth: lead })
keyboard(page, { octave: 4, octaves: 1 })        // a dials.js keyboard plays the page

function draw() {
  background("#12261e")
  text(`${page.result.right} right, ${page.result.wrong} wrong`, width / 2, height / 2, "white", 20, "centre")
}

The line waits at each note until it is played, and the key to press is lit. The keyboard is given the page in place of a synth, so its keys play the page; synth is what the learner hears.

Wait, or keep time

page.playAlong("wait")                       // the line waits for each note
page.playAlong({ mode: "time", tempo: 60 })  // or keeps time, after one bar counted in

"time" keeps going at the tempo whether the learner is ready or not.

JavaScriptPythonWhat it does
modethe first thing given"wait" or "time"
synthsynthThe synth the played notes are heard on
tempotempoBeats a minute, when the page keeps time
countIncount_inBeats counted in before the page keeps time: one bar unless you say, 0 for none
hinthintfalse: the key to press is not lit
anyOctaveany_octavetrue: the right note in any octave counts
staffstaffWhich staff the learner plays, counted from 0

Where the notes come from

Notes reach the page through page.noteOn(note) and page.noteOff(note), from anywhere. A keyboard on the screen does it for you. A real keyboard, with MIDI, is three lines:

function onMidiNote(note, velocity) {
  if (velocity > 0) page.noteOn(note)
  else page.noteOff(note)
}

A chord is right when all its notes have been played, in any order.

How it went

page.result counts as the learner goes:

NameWhat it is
right, wrong, missedHow many notes of each
totalHow many notes there are to play
percentHow much was right
timingHow far from the beat the right notes were, in seconds, when the page keeps time
doneHas the learner reached the end?
page.playAlong("wait")
page.onRight = () => playSound("coin")
page.onWrong = () => playSound("hit")
page.onDone = (result) => console.log(result.percent + "% right")