Uniform Waves: Part 4, in which things start cooking
Yes, I know, I'm 3 posts into a new piece called Uniform Waves and I haven't even started writing it. I'm not procrastinating. It just doesn't take all that long to make and explain this particular piece. But in this post I will get cracking. Below is a general description of the work I'll make.
As mentioned earlier, the piece will be for 2 pianos. It will use randomly generated melodies, like the Random Potter melody, and these will be transposed to different registers. Each pianist will have the same quantity of melodies but the melodies themselves will be different for each player. Importantly, these melodies will not just be repeated, they will be transformed, in particular, starting and ending melodies will be defined and over a given number of repetitions each note in the starting melody will transition into the ending melody. Then, the ending melody will become a starting melody, and its notes will transform into the next ending melody.
To begin, we need some melodies. To create a 6 note melody, we can use the following code:
(rnd-number 6 0 7)
This function randomly selects 6 values between 0 and 7, that is, from the list '(0 1 2 3 4 5 6 7). Why only 8 values rather than the usual 12 values? The results from this code will be used as index values rather than actual notes. For example:
(loop for n in '(2 3 2 0 1 4) collecting (nth n '(0 2 4 5 7 9 11 12))) => '(4 5 4 0 2 7)
In the code above, the list '(2 3 2 0 1 4) represent results from the rnd-number function. These values are looped through and serve as index values for the nth function applied to the list '(0 2 4 5 7 9 11 12), which is a major scale.
You may have noticed in the list above that 0 and 12 represent the same note. Normally, we use the integers from 0 to 11. For instance, if 0 is set to C, then 12 is also a C. So, why am I using a range of 8 values rather than 7? Because I will use the 8-note octatonic scale.
The octatonic scale over several octaves is given above along with index values for each note. Notice the intervallic pattern in the scale. It alternates between semitones and whole tones. If you take every other note, then you get a fully diminished seventh chord. The remaining 4 notes form another, transposed fully diminished seventh chord. Note that the index values for pitches one octave apart are +/- 8. So, transposition via index values is possible; one just adds or subtracts some multiple of 8.
With this information, we are ready to generate a collection of melodies. We will make 10 of them. First, we will determine the transpositions. There are 7 octaves on a piano, so a variable called transpositions randomly generates a list of 10 values between 0 and 6.
(setf transpositions (rnd-number 10 0 6)) => '(4 5 3 2 4 5 6 1 3 3)
Then, the values in this list are looped through. For each value, a list of 6 random values between 0 and 7, that is, a melody of index values, is created and each of its values is transposed by the result of the transposition value multiplied by 8.
(loop for trans in transpositions collecting (loop for n in (rnd-number 6 0 7) collecting (+ n (* 8 trans))))
This yields a list of sublists. Each sublist containing the "transposed" index values of a melody. If we were to assign this to a variable called melodies, then we can loop through each value in each sublist, using it as an index value for all of the notes in an octatonic scale over the piano's range. In the code below, note that I use note names instead of integers to represent notes. In the programming environment I work in, which is geared toward computer-assisted composition, this feature exists. The notation, part of the OMN (OpusModus Notation) syntax, represents notes by familiar letter names, e.g., c, d, e, etc.. Adding an s indicates sharp, adding a b represents a flat, and an integer represents the register. For example, cs4 is the c-sharp above middle c.
(setf melodies '((36 33 34 37 37 34) (43 46 47 45 42 45) (27 25 31 31 28 24) (20 20 22 22 20 21) (32 38 34 34 34 39) (46 41 46 45 47 43) (49 52 50 52 55 54) (12 10 10 8 11 13) (26 30 28 25 27 29) (25 25 25 26 28 28))) (loop for mel in melodies collecting (loop for n in mel collecting (nth n '(c1 cs1 eb1 e1 fs1 g1 a1 bb1 c2 cs2 eb2 e2 fs2 g2 a2 bb2 c3 cs3 eb3 e3 fs3 g3 a3 bb3 c4 cs4 eb4 e4 fs4 g4 a4 bb4 c5 cs5 eb5 e5 fs5 g5 a5 bb5 c6 cs6 eb6 e6 fs6 g6 a6 bb6 c7 cs7 eb7 e7 fs7 g7 a7 bb7))))
Running all of the code in this post twice would yield 2 collections of 10 melodies, each of which could be assigned to one of the piano parts. The only thing remaining to create this work, therefore, are the transitions, which will be addressed in the next, and final, post in this series.