The algorithm I use for most of my pieces is that first I find all the time_steps that contain notes not in the key of the chorale. Then I go about making those sections longer using a variety of elongation techniques. The code looks like this:
probability = ([0.2, 0.1, 0.6, 0.1, 0.15, 0.04, 0.05, 0.1, 0.1])
if type == 'any': type = rng.choice(['tile', 'repeat', 'tile_and_reverse', 'reverse_and_repeat',
'shuffle_and_tile', 'tile_and_roll', 'tile_and_repeat', 'repeat_and_tile',
'tile_reverse_odd'], p = probability)
I let the system choose which type of elongation. But over time, it’s certain to choose ’tile_and_reverse’ about 60% of the time. That is accomplished with this line of code:
clseg = np.flip(np.tile(clseg, factor), axis = 1)
This basically repeats a section of the piece, consisting of a certain number of voices performing over time_steps, then reverses the repeated sections. Retrograde.
All that is to say that the music is predetermined probabilistically, but not explicitly.
But if a certain chorale is dominated by ranges of the chorale that include notes not in the root key of the chorale, then there are a lot of repetitions. For this piece I chose five chorales that have that condition. So the extensions go on for a long time. In fact, in this prelude, each chorale lasts about 20 minutes, and there are five of them. You can do the math. I wouldn’t recommend this unless you like repetitive sounding music. Maybe skip around.
Tuned in Kellner’s Well Temperament.