Music Theory Foundations in a Few Lines of Code
I wrote some code to demonstrate the underlying syntax of Western music. This article will cover the basics of notes, the chromatic scale, and the creation of diatonic scales. You can view the full application here to see further implementation of chord triads and arpeggiated extensions.
Western instruments are all based on a twelve-note system. They can be represented in a varieties of ways. For example, you could write them down on sheet music or wrap the note names around a circle.
These twelve chromatic notes can easily be placed into an array. Each element is occupied by a note from the 12-tone chromatic pallet.notes = ["c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"]
Music is a language based on the combination of notes (musical pitch) and rhythm. This app deals strictly with musical pitch. As shown above, we begin by identifying the twelve notes that are underlying all music. We arrange them in a linear progression so that they occupy and form a 12-element array.
The next type of scale will probably be more familiar to readers. Formally called the major scale, it is also known as solfeggio (do-re-mi-fa-so-la-ti-do). The examples below highlight the major scale as a heptagon,
cMajorScale = [] cMajorScale.push(notes[0], notes[2], notes[4], notes[5], notes[7], notes[9], notes[11], notes[0])
We are able to target seven notes in the chromatic scale and push them into a new array called cMajorScale. This seven note scale can then be called to display the correct notes. Note that the eighth note (octave) is the same as the first note, indicating the repetitive nature of the scale.
The major scale is a template of intervals that can be applied to all 12 notes, forming a total of twelve possible major scales. Below is some code I wrote in Ruby. It features the same major scale interval pattern used previously, but this time I double the length of the notes array and run an each loop that pushes the scales to a master array called allMajorScales:
notes = ["c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b", "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"]allMajorScales = [] notes.each() do |n|
allMajorScales.push([n, notes[notes.index(n)+2], notes[notes.index(n)+4], notes[notes.index(n)+5], notes[notes.index(n)+7], notes[notes.index(n)+9], notes[notes.index(n)+11], n])end
Since this each loop pushes a full major scale to each element of allMajorScales, I can retrieve any major scale by targeting the correct position. For example, C is the first note in the notes array is C, and so allMajorScales[0] produces the C Major Scale. By extension, allMajorScales[1] produces the C# Major Scale, allMajorScales[7] produces the G Major Scale and so forth.
Here is that Ruby code, running in IRB within terminal:
The same interval logic applies to all of the scales (modes) in the Western system. You can take this principle further by targeting notes within the scale arrays to retrieve triads and chord extensions. If you would like to learn more, please view the full application here.