When generating random melodies in the previous post, I didn't randomly select integers to represent notes. Instead, the integers represented index values. Since I'm using the octatonic scale in this work, I showed how transposing by an octave could be achieved by adding (or subtracting) 8 from the value. You would have rightly criticized that as unnecessary to get octave transpositions. I would have been fine to just get the correct pitch integer and transpose it by 12. So, why would I do it this way? In truth, it has nothing to do with transposing the melodies but instead with dealing with mapping pitches within a scale (or mode) during transitions between these melodies. To clarify, let us first explore the generation of a transition between two melodies.
The math behind creating a transition between two numerical values is straightforward. For example, if we have a starting value of 35 and a final value of 50 and want to gradually increase from 35 to 50, then we subtract the two values - this yields 15 - and divide the result by the number of steps we would like between the start and final values. Let's keep this simple. We assume 15 steps in this example. 15 divided by 15 is 1. Then, starting with 35, we successively add 1, accumulating until we reach 50.
50 - 35 = 15
15 / 15 = 1
[35, 36, 37, 38, ... , 50]
Here we can see why using index values is necessary in order to maintain the scale. If the values in [35, 36, 37, 38, ... , 50] represented notes, then we would end up using all semitones rather than just the pitches within the desired scale.
The example above creates a transition between two values. But how do you deal with this if you have lists of values? For instance, how do we create transitions between two lists of index values such as '(36 33 34 37 37 34) and '(43 46 47 45 42 45)?
We can use a loop, taking the first, then second, then third, etc. values from each list, finding the distance between them, dividing that by the number of steps and accumulating from the start value to the final value. But I don't need to write that program because it comes as a function in the OpusModus library.
(gen-transition '(36 33 34 37 37 34) '(43 46 47 45 42 45) 15 1)
The function gen-transition takes 2 lists of equal length, a value for the number of steps, and a curve values - you might want to make the transition exponential, for instance - and returns a list of sublists, in which each sublist is a transition. The code above will yield the following:
'((36.0 36.5 37.0 37.5 38.0 38.5 39.0 39.5 40.0 40.5 41.0 41.5 42.0 42.5 43.0)
(33.0 33.92857 34.857143 35.785713 36.714287 37.642857 38.57143 39.5 40.42857 41.357143 42.285713 43.214287 44.142857 45.07143 46.0)
(34.0 34.92857 35.857143 36.785713 37.714287 38.642857 39.57143 40.5 41.42857 42.357143 43.285713 44.214287 45.142857 46.07143 47.0)
(37.0 37.57143 38.142857 38.714287 39.285713 39.857143 40.42857 41.0 41.57143 42.142857 42.714287 43.285713 43.857143 44.42857 45.0)
(37.0 37.357143 37.714287 38.07143 38.42857 38.785713 39.142857 39.5 39.857143 40.214287 40.57143 40.92857 41.285713 41.642857 42.0)
(34.0 34.785713 35.57143 36.357143 37.142857 37.92857 38.714287 39.5 40.285713 41.07143 41.857143 42.642857 43.42857 44.214287 45.0))
There are two problems with these results. First, we no longer have integers, which is important since we will use the results as index values. There is, for instance, no 38.714287th index, only a 38th and a 39th. Fortunately, the function is ready for this scenario and allows us to add what is called a keyword, which changes a default within the function. The keyword :rounded set to t, which stands for true, yields what we need.
(gen-transition '(36 33 34 37 37 34) '(43 46 47 45 42 45) 15 1 :rounded t)
'((36 36 37 38 38 38 39 40 40 40 41 42 42 42 43)
(33 34 35 36 37 38 39 40 40 41 42 43 44 45 46)
(34 35 36 37 38 39 40 40 41 42 43 44 45 46 47)
(37 38 38 39 39 40 40 41 42 42 43 43 44 44 45)
(37 37 38 38 38 39 39 40 40 40 41 41 41 42 42)
(34 35 36 36 37 38 39 40 40 41 42 43 43 44 45))
Can we now start calling up notes via these index values? Not really, due to the second problem. Notice that the first list of '(36 33 34 37 37 34) in the gen-transition function is now the first value in each sublist. So, we need to take the first values in each list and make them a sublist, then the second values in each list and make them a sublist, etc. Again, there is a function for this.
(setf t-table '((36 36 37 38 38 38 39 40 40 40 41 42 42 42 43)
(33 34 35 36 37 38 39 40 40 41 42 43 44 45 46)
(34 35 36 37 38 39 40 40 41 42 43 44 45 46 47)
(37 38 38 39 39 40 40 41 42 42 43 43 44 44 45)
(37 37 38 38 38 39 39 40 40 40 41 41 41 42 42)
(34 35 36 36 37 38 39 40 40 41 42 43 43 44 45))
(gen-combine (first t-table) (second t-table) (third t-table)
(fourth t-table) (fifth t-table) (sixth t-table))
Assigning the list of transition to the variable name t-table, we take each sublist and give it to the function gen-combine as an argument. It, then, carries out the process explained above. With this complete, we can begin calling up notes based on index values to get our transforming melodies. If we carry out the process above with a series of 10 melodies, we get all of the pitch data for a piano part. Note that the final melody in one process must become the start melody in the succeeding process. This is shown for the first 3 transitions below in the chart using our collection of melodies.
(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)))
We need our friend random permutation at this point. Earlier I addressed the ways that a uniform distribution and random permutation differ. There is one aspect that wasn't mentioned that is important for completing this new work. Since a randomly permuted list always includes the same values as the original list, it stands that if the list is a series of numbers that every random permutation will sum to the same value of the original. Order in addition doesn't matter. With the results of a uniform distribution, each new list, even if equally long, will likely sum to a different value. I want to ensure that each piano part is the same length. I know that each melody will be the same length, so there's no problem there. But what about the transitions? If I create two series of randomly generated transitional lengths using a uniform distribution, then they will (most likely) sum to different lengths and each piano part will last a different amount of time. Below is an example.
(setf iterations-1 (rnd-number 9 15 40)) => '(18 32 20 37 38 26 27 30 37)
(setf iterations-2 (rnd-number 9 15 40)) => '(22 16 38 25 38 39 36 38 25)
(find-sum iterations-1) => 265
(find-sum iterations-2) => 277
Randomly generating 9 values between 15 and 40 to serve as the number of iterations between adjacent melodies, the first list, set to the variable iterations-1 sums to 265, while the iterations-2 sums to 277. (The find-sum function is quite handy here.) That means that the second piano part will be 12 beats longer than the first piano's. This is easy to solve with random permutation.
(setf iterations-1 (rnd-number 9 15 40)) => '(18 32 20 37 38 26 27 30 37)
(setf iterations-2 (rnd-order iterations-1) => '(32 30 38 37 37 26 20 27 18)
(find-sum iterations-1) => 265
(find-sum iterations-2) => 265
In the code above the values for iteration-2 are generated not via a uniform distribution, but instead a random permutation of iterations-1 values. With this, each part has unique melodies, each is transposed to a unique register and takes a unique amount of time to transition, but we are ensured that the parts are equal in length.
Of course, this presumes that the rhythm is straightforward, which it is. Uniform Waves is an evocative piece. The dynamics are pp throughout, the pedal is depressed by each player for the duration of the work, and the rhythm - really more a speed - is a fast, but even, triplet sixteenth value for all notes. Finally, one small way I distinguish the two piano parts is through different octatonic scales. Piano 1 uses the OCT(0,1) scale, while piano 2 uses the OCT(2,3). (These names derives from the first two pitches in each scale.)
Note that in the resulting work the values for the melodies and transition lengths differ from those used in the examples above, but the principle is the same.
Comentarios