Notes, chords and tunes

A note, a chord, and two ways of writing a tune: as a line of text, and as ordinary lines of code.

Notes

playNote("C4")                       // middle C, for half a second
playNote("C4", 2)                    // for two seconds
playNote("C4", 2, 0.3)               // and quiet: loudness goes from 0 to 1
playNote(["C4", "E4", "G4"])         // three notes at once: a chord
playNote("C4", { length: 2, volume: 0.3, pan: -1, after: 0.5 })   // the same things by name

A note is a letter and a number: "C4" is middle C, "A4" is the A above it, "F#3" is F sharp and "Bb5" is B flat. It can also be a number, where 60 is middle C and each whole number is one key of a piano (61 is C sharp, 72 is the C above). A number with a fraction is between two keys. noteNumber("A4") gives 69 (note_number in Python).

pan is where the note is: -1 is left and 1 is right.

Chords by name

A chord is a note and a kind: "C" and "m7" make "Cm7". Wherever a note is played, a chord's name plays all its notes.

playNote("Cm7")                      // C minor seventh
playNotes("Am F C G", 0.5)           // four chords, half a second each

The kinds are major (or maj), minor (or m), dim, aug, sus2, sus4, 5, 6, m6, 7, maj7, m7, dim7, m7b5, add9, 9, maj9, m9 and octave. Every sound, synth and setting has the notes of each.

A letter followed by a number is always a note, so "C7" is the note C in octave 7. For the seventh chord write "Cdom7". For a chord in another octave put the octave after the letter: "C3m7".

Lengths

Wherever a length is wanted there are two ways to say it, and they are never mixed up:

  • A number is seconds. playNote("C4", 0.5) lasts half a second, whatever the tempo.
  • A name is a note length, measured against the tempo: playNote("C4", "quarter"). At a tempo of 120 a quarter note is half a second; at 60 it is a whole one.
NameAlso writtenHow long
"whole""1/1", "w"4 beats
"half""1/2", "h"2 beats
"quarter""1/4", "q"1 beat
"eighth""1/8", "e"half a beat
"sixteenth""1/16", "s"a quarter of a beat

A dot makes one half as long again ("quarter.", "q."), and a triplet fits three where two were ("eighth triplet", "e3").

setTempo(140)                        // beats in a minute. 120 until you say
playNote("C4", "quarter")
playNote("E4", "quarter.", { after: "half" })

beats(3) is how many seconds three beats last.

A tune as text

let tune = null

function onMouseDown() {
  if (tune) tune.stop()
  tune = playNotes("C4 E4 G4 - C5:2 G4+B4+D5 Am", 0.25, { repeat: true })
}

playNotes plays a tune a step at a time. The first thing is the notes, as text with spaces between:

In the textWhat it is
C4A note, one step long
-A rest
C5:2A note two steps long
C4:q, C4:h, C4:e, C4:s, C4:wA note with a length of its own: a quarter, a half, an eighth, a sixteenth, a whole
G4+B4+D5A chord, joined with +
AmA chord by name

The second thing is how long a step is: a number is seconds, a name is a note length (playNotes("C4 E4 G4", "eighth")), and with nothing said it is an eighth.

The notes can also be a list, where a rest is null (None in Python) and a list inside is a chord:

playNotes(["C4", null, ["C4", "E4"]], 0.25)
OptionWhat it does
repeattrue plays it round and round; a number, that many times
volumeHow loud, from 0 to 1
holdHow much of its step a note sounds for: 0.9 unless you say
after, at, beatWhen it starts

playNotes hands back the tune, so you can stop it: tune.stop().

A tune whose step is a name, or is left out, is in beats: it changes speed when the tempo changes, even while it repeats. A tune whose step is seconds does not.

The sound engine keeps the time, not your program. A tune stays even when a frame is slow, and several tunes started together stay together.

A tune written as text plays each note plain. A slide into a note, a bend or a vibrato is for one note at a time, in play, start and playNote: see Bending a note.

A tune, one note a line

playNote plays a note now. note plays the next note of a tune: each one begins where the one before it ended, so a tune is written as ordinary lines of code, with loops and ifs, and no arithmetic.

function onMouseDown() {
  setTempo(100)
  startLines()

  note("E4", "quarter")
  note("G4", "quarter")
  rest("quarter")
  note("C5", "half")
  chord("Cm", "whole")

  for (const name of ["C4", "D4", "E4"]) note(name, "eighth")
}

The same tune as text, for comparison: playNotes("E4:q G4:q -:q C5:h Cm:w C4:e D4:e E4:e").

In a line, a length is a name, or a number of beats (note("C4", 2) is a half note). With nothing said it is a quarter. Change a length and everything after it moves along.

Every synth has a line of its own

note, chord and rest write on the synth that playNote uses. Every synth you make has its own line: lead.note("C4", "eighth").

Lines written in the same go begin together, however much code is between them. Write the whole melody, then the whole bass, and they start on the same instant:

const lead = makeSynth("lead")
const bass = makeSynth("bass")

function onMouseDown() {
  startLines()
  for (const n of ["E4", "G4", "C5", "G4"]) lead.note(n, "quarter")
  bass.note("C2", "half")
  bass.note("G2", "half")
}

A section that goes round

A for loop writes a section several times. loopNotes has it go round for ever, kept in time by the sound engine, and it follows the tempo as it plays. It hands back the loop, which has stop().

const kick = makeSynth("kick")
const snare = makeSynth("snare")
let drums = null

function onMouseDown() {
  if (drums) {
    drums.stop()
    drums = null
    return
  }
  drums = loopNotes(() => {
    kick.note("C3", "quarter")
    snare.note("A3", "quarter")
  })
}

In JavaScript the section is a function. In Python it is a with block. To go round four times and then carry on, say how many: loopNotes(4, () => { … }), or with loop_notes(4):.

Starting over

A line carries on from where it ended. If it ended a while ago, the next note begins now. startLines() begins every line again from now, and lead.startLine() begins one (start_lines, start_line). A tune that is played by a click starts with startLines(), so that a second click begins it again and does not add to the end of the first.

startLines({ after: "whole" })      // every line begins a bar from now

Which way to write a tune

  • As text when the tune is a pattern: a drum beat, a bass line, a melody you can see at a glance. It is short, and it repeats with one word.
  • As code when the tune is made by the program: a melody from a list, a scale from a loop, a different ending when the player wins.

Both keep exact time, and they can play together.