| Exercise 9.1 - Harmonic Sequences |
1 |
2 |
|
Last time, we used a counter to track progress through a piece and selectively layer a mix by muting or unmuting channels - enabled by a series of if statements. In this tutorial, we will combine counters with arrays that allow us to use a prescribed specific sequences of chords or note patterns. These techniques can be used to replicate both linear and cyclic harmonic or melodic progressions, commonly found in music.
This tutorial will also introduce several important built-in functions you can use in formulas to manipulate multiple notes at once - to clear, move, copy, or otherwise process blocks or ranges of cells (e.g. whole arrays).
We explore these concepts in the recreation of a piece of minimalist piano music, The Departure by Max Richter, written for the HBO TV Series The Leftovers. This piece has a well-defined chord progression and simple melody.
Create a chord sequence based on array data:
-
The pattern provides the arrays Chords , which contains a palette of six three-note chords, and Sequence , which specifies the order in which they are to be played.
- Our current position in the sequence is stored in Index , which we use to access the corresponding entry in Sequence , to find out which chord to use (as specified in its parameters). Insert the following in the freeform code at Ex 9.1 and play the pattern:
' Work out chord number
.param = @Sequence[@Index]
The cell will display the number of the current chord. At the start, @Index is 1, so the expression equates to @Sequence[1], the parameter for which is "01", identifying the first chord in the palette. When @Index increments, it references the next row, which identifies a repeat of the same chord ("01") - continuing through the sequence 1,1,2,2,6,6,1,1,3,5,1,4.
- Having worked out the number of the chord to use, we will extract the corresponding group of pitches from the Chords array using the group() function, which works as follows:
range = group(n, @array)
This function searches through the specified array, looking for the nth group of pitches (separated by empty rows) and returns a reference to just the range of cells in that group.
- Use this function with the previously worked out chord number, to copy the required pitches from Chords to Chord , using the copy() function:
' Extract chord pitches
copy(group(.param, @Chords), @Chord)
The copy() function takes one or two arguments. With two, the first identifies the source range of cells, and the second identifies the destination. If the second is omitted, the current cell (and the cells that follow) become the destination. Here, we specify the source as a group of cells within the @Chords array and the destination as the @Chord array.
- Now we know our chord, we map it to a note pattern stored in Arpeggio , using the arp() function:
' Apply arpeggio using chord pitches
arp(@Arpeggio, @Chord)
The arp() function takes two arguments. The first identifies the note pattern to use; the second, the pitches to apply to it. Pitches can be specified as an array or range of cells, or as a list of specific pitches enclosed in braces, e.g. { C-5, E-5, G-5 }. The pitches specified are mapped onto those in the note pattern, in the order they are seen, and the result is placed at the current location in the pattern. Note that the process of copying the pattern will overwrite (and hide) our previously visible .param value, indicating the chord number.
- Playing the pattern, you should hear the full chord sequence as rippling arpeggios on the piano.
Note how @Index is sequenced to repeat the last four chords until the end of the piece (at Bar 31). The code to update @Bar and @Index is in cell [2:4], at the start of the bar, and simply uses the counter techniques seen previously.
- In this example, the steps are broken down to help illustrate the process, which could also be completed in single line, without using the Chord array:
arp(@Arpeggio, group(@Sequence[@Index], @Chords))
- When ready, move to part 2, to add the melody.
| Exercise 9.2 - Melodic Sequences |
1 |
2 |
|
While harmonic progressions and textures often feature repeating note patterns, like the arpeggio in the previous exercise, melodic phrases can be longer, spread over several bars or the whole piece. However, they may still have rhythmic patterns that can be exploited by code.
In this exercise, we'll use an array of notes to specify a melodic part for the piece, where notes are iteratively read and placed at set locations in the bar, as the piece progresses.
Use an array to step through the right hand part:
-
The notes of the melody only ever appear at three different positions in the bar - aligned with the three labels Ex 9.2 (a) , Ex 9.2 (b) , and Ex 9.2 (c) . We'll add code to each of these cells to read the required pitch from the Melody array.
- For the .pitch formula in the first location, insert the following code:
@Bar >= 10 ? @Melody[@Bar - 10].pitch : none
This formula uses the current bar number (stored in @Bar) to reference a pitch in the first column of the @Melody array. However, the melody only enters in the eighth bar, so we first enclose the lookup in an if statement that only inserts a note after Bar 8 (or else nothing). Moreover, because the melody starts here, we need to subtract the number of the first bar of our melody from the @Bar counter, so that we're looking at @Melody[0].pitch when @Bar = 8.
- Ensure formula dependencies are visible (Ctrl-D) and play the pattern. Notice how the first note of the melody is iteratively read from the first column of the array - stopping and starting notes. You may also notice that neighbouring the channel doubles certain notes, when they are below a certain register.
- For the other two notes, we use the same expression as above, but instead take pitches from the second and third column:
@Melody[2:@Bar - 10s].pitch
@Melody[3:@Bar - 10].pitch
This illustrates how you can use arrays in either dimension (x and/or y). In this example, we've iterated down, but we could just as easily step left-to-right, if this is how you would prefer to arrange your pattern. Chord progressions, for example, can make sense as vertical lists of pitches for each chord, arranged and stepped through horizontally for the progression.
- Having completed the code, audition the full piece.