I’ve stopped posting here and am now only posting using Substack here: https://microtonalnotes.substack.com/
I’ve been trying new tuning algorithms to find the optimum low number ratios to tune Bach chorales. James Kukula on the Facebook group Microtonal Music and Theory suggested I explore Simulated Annealing to find the optimum tuning. I asked my friendly local LMM running granite-code:20B for some advice, and it helpfully coded up the algorithm for me.
The basic idea is that you start with a cent value for each of the four notes in each chord, then change it until you reach a chord that scores well on an analysis function. The key trick of Simulated Annealing is that you start by probabilistically accepting non-optimum values for an interval instead of the very lowest number ratio. As you repeat the process, you gradually lower the temperature controlling how likely you are to reject the optimum. Eventually, after enough repetitions, you are only accepting the optimum choices. This avoids the situation where the first choice you make causes the options for subsequent choices to be bad. You want to avoid what are called local minima, suboptimal arrangements that you arrive at by blindly only accepting the optimum at the start. Sometimes if you start out sub-optimally for the first few intervals, the sum of all the ratios in an interval is lower.
In my case, I start with a tonality diamond to a variable limit. I’ve found through repeated grid searches that either the 31-limit or 47-limit produce the best scores. I split the 4-note chord into 6 separate intervals, then run a function that returns all the valid intervals that could be used for each of the six intervals. Valid means:
It is an interval in the tonality diamond, made up of all the intervals with numerators and denominators from 2 through the specified limit. If the limit is 5, for example, the diamond includes the ratios 3:2, 4:3, 5:4. As we increase the limit to 31, you are offered ratios like 31:30, 25:37, and other decidedly not low number ratios. I tried some low limits, like 15, and the results were poor.
Ensure that none of the selected intervals will change the underlying midi note value, the 12-tone equal temperament value of each note in the chord. If the ratio is too large, such that adding a cent value to the interval would round to a D sharp instead of a D natural, it is excluded from the returned value. I generally find 10-15 valid ratios to choose from.
I return a list of indices into the tonality diamond structure, each of which includes the ratio value in floating point, the cent value of the interval, and sum of the numerator and denominator of the ratio.
In this way the algorithm can tune a chord to cent values that represent low number ratios.
I then have the option of choosing from the list of valid ratios the one that has the lowest number ratio. Or not. Simulated Annealing starts out with a high temperature, then with each iteration, it lowers the temperature by a ratio. In my case, I did many grid searches and determined that starting with a temperature of 64.0, then multiplying it by a cooling rate of 0.998 with each pass, results in the lowest number ratios. I started out with temperatures of tens of thousands, and cooling rates closer to 1.0, but found that they did not improve the results.
I achieved better results by systematically rearranging the order of the notes in the chord, then ran the simulated annealing multiple times. This lowered the scores significantly. I use a python library called numpy, which includes a function called roll, which takes a 4-note chord and rearranges it. If I start with C E G A#, a roll of one returns E G A# C, two returns G A# C E, and so forth. I found a rolls of 0,1,2,3,4,5 for every chord produces the lowest scores. Even the simulated annealing gets stuck at local minima and simply running the same chord through the algorithm more than once, it picks a better arrangement.
I score each chord by simply adding the sum of the numerator and denominator for each of the six intervals. This produces the score for the chord. I’ve been using this for several months now, running several different Bach chorales through the algorithm. I start with a set of midi values for each note in each chord, and convert it to a number from 0-11, plus a separate value for the octave. Then I run it through the annealing process which produces a 4-note chord in cents. What I noticed recently is that this is precisely what Harry Partch was getting at in his famous (to me) “One Footed Bride” chart.
Partch used this chart in his great book “Genesis of a Music”, page 135. He identifies ratios by several adjectives: Power, Emotion, Approach, and Suspense. But the important value is how far the ratio sticks out: low number rations like 3:2 and 4:3 stick way out and indicate strength; higher number ratios like 5:4 and 8:5 stick out less; still higher number ratios like 7:6 and 8:7 stick out even less. In other words, there is greater strength the lower number the ratio reduces to. That’s just what my scoring algorithm is doing: tuning each chord to the lowest number ratio possible for each chord. In honor of the Partch One-footed bride, I tuned Bach’s Wedding Chorales BWV154-164. Audio files are at the bottom of this post.
I started out in my algorithm search achieving average scores for the six intervals in a 4-note chord of around 60. This implies that on average, each chord used six intervals where the sum of the numerator and denominator for the interval was around 10. Imagine a chord consisting of [‘G♮’, ‘D♮’, ‘B♮’, ‘G♮’], which in midi is represented by [7, 2, 11, 7], once you remove the octave. If I choose the ratios [ 700 202 1086 700] for each of the four notes, I end up with the six intervals tuned to the following ratios. The first two numbers are the relative notes in the chord, 0 being the first, 1 the second, 2 the third and so forth. Python always starts with zero instead of 1. The first interval (0,1) is 4/3 with sums to 7. The second (0,2) is 5/4 which sums to 9. the third (0,3) is the same note in both cases, G♮’, the fourth (1,2) is 5/4 sums to 8. Do that for all six and you end up with a score of 40. (7+9+0+8+7+9=40). The score for this chord is therefore 40. Pretty good. Tuned to just, with the lowest number ratios:
[(0, 1, ‘ 498’, ‘ 4/3 ‘), (0, 2, ‘ 386’, ‘ 5/4 ‘), (0, 3, ‘ 0’, ‘ 1 ‘), (1, 2, ‘ 884’, ‘ 5/3 ‘), (1, 3, ‘ 498’, ‘ 4/3 ‘), (2, 3, ‘ 386’, ‘ 5/4 ‘)]
Do this for all the chords in a chorale, sum the numerators and denominators of all the six intervals in each chord and evaluate it based on the lowest possible score. When I started using the simulated annealing, with all 24 permutations of each chord, I began getting average scores around 55. Grid searches for the optimum hyperparameters of the algorithm reduced the averages to below 50 for most chorales. But the problem now is that it would take an hour or more to calculate the optimum.
I implemented several caching schemes, to speed up the interval ratio lookups, and scoring. I also use the numpy function called unique, which examines all the chords and eliminates any that are duplicates, returning just the unique ones, and a list of those removed so they can be restored. This eliminated 40% of the chords that had to be tuned.
By default, python only runs on a single CPU regardless of how many I have in my servers. I solved that by asking a new granite model, granite3.1-moe:3B, to suggest ways to parallelize the python. It came up with a brilliant solution which allowed me to exploit multiple cores in my servers.
I quickly discovered that most of my servers advertised multiple threads on Intel and AMD chips. But just because each core provided two virtual cores, it turned out that during CPU intensive processing only one was active at a time. My 12-core server that offered 24 threads took just as long when I parallelized it 12 ways as 24 ways.
The latest Intel chips have abandoned multi-threading, because the majority of workloads get very little benefit from it. I’m in the process of getting one built now, with 24 real cores. I was able to test it and found that it performed well at 3.7 gHz, tuning 10 chorales in 15 minutes across all 20 cores. I had to switch off turbo to 5.7 gHz because of heat problems. I’m working on solving that now.
The final result is a set of tunings for chorales that have very low number ratios. That means that I have lots of chords with tunings that are not in normal 12-tone equal temperament. That includes some with ratios like the third beat of measure 7 of bwv263, chord number 104, with a score of 107. This high score caused by tuning the notes [‘D♮’, ‘G♯’, ‘F♮’, ‘B♮’]. Here is measure 6 and 7:
104: [2, 8, 5, 11] [‘D♮’, ‘G♯’, ‘F♮’, ‘B♮’] [ 200, 782, 466, 1084] 107
104: [(0, 1, ‘ 582’, ‘ 7/5 ‘), (0, 2, ‘ 266’, ‘ 7/6 ‘), (0, 3, ‘ 884’, ‘ 5/3 ‘), (1, 2, ‘ 316’, ‘ 6/5 ‘), (1, 3, ‘ 302′, ’25/21’), (2, 3, ‘ 618’, ‘ 10/7’)]
It includes several relatively high number ratios: 7:5, 7:6, 25:21, and 10:7. But it’s just a passing tone that quickly resolves away from that diminished chord. Bach loves the tension that diminished chords produce. Think stacked minor thirds.
One of the problems with this method of tuning chords individually is that it picks the best cent value for each chord regardless of the surrounding chords. Notes can change cent values from one chord to the next, even though they are the same midi value. For example, in the two measure excerpt above, measures six and seven of bwv163, the first D eighth note in the soprano part of measure 6 has been chosen to have a cent value of 202, while the one that follows is at 200 cents. To resolve that change, I slide from 202 down to 200 over the duration of those 9 eighth notes in the chords. This is too small to notice. But the slides in measure three are more prominent, where I have to move a G♮ in the alto part from 700 cents all the way up to 749 cents. The measure starts with a G major chord, then quickly gets weird. But over the five separate chords from the beginning of the measure to the halfway point, the alto voice has to cover half a semi-tone. It’s subtle. I’ve slowed the performance down to make the movements less obvious.
Over the course of this chorale there are 183 separate slides, but with all the repetitions, they are all using these 9 glissandi:
glide# decimal cents ratio
1500 0.9988 -2 1
1501 1.0012 2 1
1502 1.0116 20 51/50
1503 0.9977 -4 1
1504 1.0287 49 36/35
1505 0.9857 -25 49/50
1506 0.9885 -20 49/50
1507 0.9834 -29 49/50
1508 0.98 -35 49/50
Csound has no trouble with slides.
To summarize, the key technologies brought to bear on this musical challenge were:
Code up a way to determine the valid intervals that could be used for each interval in the chord
Find the optimum tonality diamond limit value to reduce the average score: 31 and 43
Code up a scoring algorithm to evaluate chords for their use of low number ratios
Cache the results of calls to determine the valid intervals and chord scores. I achieved 98% cache hits on the ratio selection, and 88% on the scoring. This reduced the workload to accomplish the tuning.
Find a way to slide from one cent value of a note to another for notes that had the same midi value but different cent values. This took some special Csound coding.
Build a simulated annealing algorithm that could find the optimal chord tuning in cents based on low number ratios
Find a way to parallelize the algorithm so each core in the CPU could work on a different chord.
Determine the optimum rearrangement scheme to send chords with different arrangements through the simulated annealing function.
Compress the chorale so each unique chord would only have to be tuned once, no matter how many times it appeared in the chorale.
Send the chord through a mix of sampled brass and woodwind instruments from the McGill University Master Samples using Csound.
Here is BWV263 from the Wedding Chorales by J.S.Bach:
BWV257:
And BWV258:
These pieces can be described as a re-tuning and orchestrating the chorales from the St. John Passion into fantasias. All the orchestrations are done by aleatoric algorithms I write in python. I create several variations on each chorale, then listen to them and make modifications until I find one of each that sounds interesting. The … Continue reading Re-tuning and Orchestration of J.S.Bach Chorales from the Passion of St. John
I made this version after I’ve updated the algorithm to prevent moving the B♮ and F♯ from 1100 and 602 cents respectively. This avoids some of the strange jumps between chords. The solution is a bit crude, but I think I can improve on it. I may need to pay attention to some of the other notes, even though those two are the most common ones in the chorale. Next up is the D♮ at 216 cents.
I added some code to list out the cents and ratios of each chord as it passes by. Here are the first few chords in the chorale, and then two from later. The first four numbers are the cent values of the chords. 1100 cents is a B♮, 602 is an F♯, 216 is a D♮, and 1100 is another B♮. The next set are the intervals in the chord stated in ratios and cents. The algorithm favors low integer numbered ratios, and is willing to go pretty far away from 12 TET to find them. For example the second to the last one includes an 8/7, which is far from 12 TET.
([1100, 602, 216, 1100]) [('1/1', 0), ('4/3', 498), ('5/4', 386), ('5/3', 884)]
([1100, 714, 398, 398]) [('3/2', 702), ('5/4', 386), ('6/5', 316), ('1/1', 0)]
([1100, 714, 398, 602]) [('4/3', 498), ('5/4', 386), ('6/5', 316), ('9/8', 204)]
([1100, 216, 1100, 714]) [('5/4', 386), ('5/3', 884), ('5/3', 884), ('5/4', 386)]
...
([699, 930, 348, 117]) [('7/5', 582), ('8/7', 231), ('7/5', 582), ('8/7', 231)]
([602, 918, 420, 216]) [('5/4', 386), ('6/5', 316), ('4/3', 498), ('9/8', 204)]
The goal of this exercise was to create some code that could automatically turn any 12 TET chorale, real or synthetic, into a just intonation chorale, all by itself. The program reads in the MIDI file and searches for a justly tuned chord that will minimize the size of the ratios in the intervals between notes in a chord, while staying reasonably close to the 12 TET note. It tries to minimize those two values, distance and ratio numerator / denominator size, to come up with cent values for the intervals in each chord. I then check to make sure I haven’t moved either of the critical notes, B♮ and F♯.
A lot of the assumptions I made about adaptive tuning were terribly naive. It’s hard. I thought all I had to do was find a chord that contained only low integer ratios by taking each interval of the chord individually. But that ended up with sub-optimal chords, since each interval competed for what the cent value of a given note should be. I ended up re-voicing those that were the most difficult, running some chords through the algorithm to tune the notes in the chord, then re-voicing them back to the way they were. The numpy function roll() provided a means to transform the chords until they found a good tuning. It takes about three and a half minutes to do a 177-chord chorale. I think I can improve that if I remove some of the debugging code.
This is another in the series of Vertically Adaptive Tuning of Herzliebster, with some fixes made to the tuning optimization to search harder for just tunings that meet the criteria I set down. The last one, #17, included some wolf chords. These were caused by conflicts between different intervals in a chord. I check all six intervals between the four notes of each chord. I’d start with note 0 to note 1, then 0 to 2, 0-3, then 1-2, 1-3, finally 2-3. Doing the checks in that order guaranteed that notes 2 and 3 were subject to change by a later comparison interval. That wasn’t going to work, so I made some changes to ensure that a change would only take place if it was for the improved the score of the entire chord, not just one interval at the expense of another.
I’ve had much better results if I try different voicing of chords. For example, I was struggling to find code that would produce good results for the MIDI F# major chord: [66, 64, 61, 46], which is note names: [‘F♯’ ‘E♮’ ‘C♯’ ‘A♯’]. It’s just a revoiced F# major scale, but I could not find a set of intervals where all six resulted in consonant chords. I the four notes two at a time, and that means six choices, which sometimes conflict. But when I run four different voicings through, it finds the best ones every time. The Numpy function roll takes a four-note array and moves it over by 0,1,2,3 places, creating four different chords. There must be some bug in my code, because after I do that, it works great.
for inx in np.arange(4):
result = find_intervals(np.roll(chord_in_1200,inx), range = range)
score = score_chord_cents(result)
if score < best_score: best_choice = result best_score = score
Next step is to start the horizonal optimizations.
This is another attempt at creating an adaptive tuning that fit’s my preferences as a composer. This version starts by loading a set of acceptable ratios into an array. I chose to load those that I found when studying the Tonality Diamond to the 31 Limit. It’s a set of the 213 ratios that mathematics can come up with using the overtones and undertones of a note. I stick to those ratios, because they include the most consonant of intervals, along with the challenging but interesting ones.
I then wrote some code to transform a Bach chorale known in the Music21 corpus as ‘bwv244.3’, from the St. Matthew Passion. It’s one I’ve used a few times over the years.
Using some python code I wrote, it takes each chord in the chorale, and searches for the optimal based on using the lowest possible integer ratios in the tonality diamond that are closest to the 12 tone equal temperament cents of the notes in the chorale. I optimize based on the sum of three values:
I add them up and use that to score, with the lowest score winning a slot in the final chord. I do that for all the intervals in each four notes in each chord in the chorale. Given Soprano, Alto, Tenor, Bass, I optimize the intervals from S to A, S to T, S to B, A to T, A to B, and T to B. That’s six compares. The final chord tuning is the result of wining the lowest score for each interval.
At present, I’m not advanced enough in my exploration of adaptive tuning to consider the prior or future notes. I put that in the “horizontally adaptive tuning” category to be dealt with later.
This one sounds pretty neat. It only goes off into crazy land by around 4:30. I think the leading tones throw my code for a loop.
I’ve been looking at different adaptive tuning systems, and none do what I want. My preference, which is probably crazy, is a tuning that will find the optimum tuning for a chord, on my terms. In this case, I want the ratios between notes in a chord to use the lowest possible integer ratios. That means I will favor 7/4 of 9/5, even though it’s typical for a just flatted 7th to use a 9/5. I also favor 7/5 over 10/7, even though it might create some awkward moments.
I brought this about with some python code the attempts to find the 72 EDO tuning for each chord that minimizes the size of the ratios between the notes in a chord. The source material is a real Bach chorale used in the St. Matthew Passion, known as Herzliebster. All chorales have four notes. So I wrote code that evaluated a chord by looking at the ratio distance from each note to every other note. That’s six compares: Given soprano, alto, tenor, bass as SATB, then the combinations to evaluate are S to A, S to T, S to B, A to T, A to B, and T to B.
Then I did the same after changing one of the voices by on 72 EDO step, and scored that. I continued that so that I evaluated all six combinations modified by -3 to +3 72 EDO steps, or 50 cents up and 50 cents down, in 16.67 cent steps. The result was a Vertically Adaptive Tuning of Herzliebster. Vertical means I only looked at each chord all by itself. I haven’t written the code that would permit evaluation of one chord to the previous or succeeding step, which is Horizontal Adaptive Tuning. But it’s a start.
There may be some notes that sound strange here:
Your browser does not support the audio element.
This version uses a D minor just scale. I transposed a C minor just scale into D and ended up with these ratios.
In numpy for python:
edo_12_ratio_strings = np.array(['1', '25/24', '10/9', '32/27', '5/4', '4/3', '25/18', '40/27', '55/36', '5/3', '16/9', '50/27', '2'], dtype='
Or in scala form:! d_minor_just
!
Transposition of a c minor just into d
12
!
25/24
10/9
32/27
5/4
4/3
25/18
40/27
55/36
5/3
16/9
50/27
2/1``
There are some real wolves in this scale, almost enough to get me to go back to one of the tempered ones I've used lately. Victorian Rational Well Temperament is wonderful in most keys. But it has the nasty effect of having prominent beating in others. This d minor just scale that I used for this piece has the interesting characteristic of really celebrating the wolves. They scream out at the top of their lungs when the hit some of the keys.
This piece is based on a synthetic chorale manufactured by TonicNet. It's number 3,640, one of many in D minor. It has a pitch class entropy score of 3.28, which is fairly high, but not extreme, compared to others. I used music21 to determine the triad chords used in the chorale:
b minor (2)
F# major (2)
b minor
F# major
b minor
d minor (finally!)
g minor
D major
g minor
F major (3)
a minor
C major
d minor (4)
F major (2)
Bb major
F major
So even though it's in d minor, according to music21, it starts in b minor and ends in F major. I don't think this is typical of Bach. But the way TonicNet works is it tries at every moment to choose the next triad that Bach would have chosen at that time-step of the piece. It doesn't look back to consider what it did previously, except in a very limited way. It's kind of guaranteed to sound like it's just wandering around aimlessly imitating Bach without duplicating his technique.
Listen here:
Your browser does not support the audio element.
This is early results of exploring the highly entropic chorales created by the TonicNet model.
I built a chorale generating notebook in python that created 4900 examples using the TonicNet model, and then ran those through an evaluation routine (using muspy) to find those that had the highest degree of pitch entropy. There were at least 1000 that included all 12 tones in the tempered scale.
I then chose a few that were in the key of D major. All were strange and wonderful chorales. TonicNet writes them out as MIDI files, with a kind of piano-roll format of four voices and a certain number of notes in each voice, all 1/16th notes. If a note is being played, then a MIDI number appears in the slot for that time-step.
You need some logic to turn this piano roll type notation into notes with duration.
I then repeat each note 15 times, turning every 1/16th note into 1/16th less than a whole note. I then apply masks to turn notes off to create arpeggiations. Or for the woodwinds, I just have long held notes.
I transposed the Victorial Rational Well Temperament from the scala scale archive into the key of D. Some of the ratios may seem kind of extreme, but that’s what was required to accurately reflect the ratios in the temperament when transposed. This is the result of that:
! secor_vrwt_D_major.scl
!
George Secor's Victorian rational well-temperament (based on Ellis #2) in D
12
!
4073/3857
3096/2755
654/551
24284/19285
27841/20871
5436/3857
722832/482125
6107/3857
32472/19285
6863/3857
36336/19285
2/1
I then created a finger piano arpeggio vamp with eight voices, and added a double woodwind quartet (oboes, clarinets, french horns, bassoons) playing slow chords. Both voices simply took the notes that the TonicNet model created. I modified some characteristics, including envelopes, volume, timbre, and other factors. The features are changed at the 1/3 and 2/3 points in the piece. The result is a sweet sounding exploration of what the model thought Bach might do.
Your browser does not support the audio element.
The traditional 12 tone scale can be described in python code as np.array([‘C♮’, ‘D♭’, ‘D♮’, ‘E♭’, ‘E♮’, ‘F♮’, ‘G♭’, ‘G♮’, ‘A♭’, ‘A♮’, ‘B♭’, ‘B♮’]), or the enharmonic equivalent as np.array([‘C♮’, ‘C♮’, ‘D♮’, ‘D♮’, ‘E♮’, ‘F♮’, ‘F♮’, ‘G♮’, ‘G♮’, ‘A♮’, ‘A♮’, ‘B♮’]). Those are basically the notes that Bach used to notate his music (with the exception of B♮ which was called “H” and “B♭” was called “B”). Go figure.
I’m working on a way to improve the sound of some synthetic chorales generated by the Deep Neural Network model known as TonicNet. I’m most interested in the synthetic chorales that have a high degree of pitch entropy. I use the python library known as muspy to evaluate the generated chorales looking for those that have a high pitch class entropy.
The pitch class entropy is defined as the Shannon entropy of the normalized note pitch class histogram.
The formula according the the muspy documentation is:
It basically gives a higher score if the pitches used include a lot of notes not in the root scale of the piece. A score over 3 contains a lot of notes outside the root key.
I used the TonicNet neural network to synthesize around 5000 unique chorales in S-A-T-B format, four voices, any number of notes each. I selected the highest scoring chorales, in terms of Pitch Class Entropy, and studied them for some ideas.
I tried retuning them using some standard Well Temperaments, and obtained some nice results. But I thought I might be able to improve on them if I used an adaptive tuning. William A. Sethares has a paper on the subject here: adaptive tuning.
I still need to code it up. But I thought it would be useful to describe what I am trying to accomplish first.
I’ve made a number of changes over the past few weeks to the code that creates the music files. Many involved fixing bugs. Some of them were associated with the slides, others with varying the duration of some sections probobalistically. There are four paths through the model, and making sure the timing is accurate in each is important. You wouldn’t want the bass flute playing the verse when the balloon drums were on the bridge, for example. I also spent some time making sure that if a part repeated a section, the second time through would be quieter than the first. And the tempo of the trills was off, due to the duration of the notes being longer than they should be. I was adding 10% to each notes duration, and that messed up the timing of the trills. What was supposed to finish 8 ups and downs in the space of a half note, would actually not finish before the note should have ended.
I have some other enhancements I want to work on, but I think I have to leave this piece and move to another.
Listen here:
Your browser does not support the audio element.
After completing the previous version of this piece on January 4, I thought it would be neat if I added the ability to slide some of the notes in the bass flute. Little did I know it would open up dozens of bugs in my python code. It took me a month and a half to sort out the issues. But now I can include slides in arbitrary note strings.
I had already created the ability to enter specific streams of notes in a text string.
inputs_array_64 = "n0o4u0e1v69d12 n3d4 n4 n5 n6o0 n7o4 d6n0 n1 n3 n2 n4 e8v78d1n6 n7"
This is similar to the way my old Pascal code worked. I specify notes with letters for each of the six features each note possesses:
My latest enhancement was to add a new feature, the glissando. The value for g indicates how many time_steps should be combined to have a continuous glissando between notes. See it’s use in the next example:
inputs_array_64 = "n0o4g0u0e1v69d12 n3d4g12 n4 n5 g0n6o0 n7o4 d6n0 g18n1 n3 n2 g0n4 e8v78d1n6 n7"
In this example, we start off with g0, which means no slide. Then on the second note, we have a glissando over 12 time steps. In this case that includes the notes n3, n4, and n5. I then create a function table that transits those notes over 12 time steps. Then in note five, we reset to g0 for no glissando. Note 8 starts another glissando over 18 time steps. I build a slide that transits n1, n3, n2, since each note has a duration of 6 time steps. The result is relatively simple to slide wherever I want in the scale. My code calculates the closest note automatically, changing octaves to do so when it would result in a smaller slide.
One of the consequence for glissandi on samples that already have vibrato is that a slide up by a whole step results in a speed up of the vibrato. This can get annoying if the distance traveled is several steps. My code automatically compensates for this “muchkinization” effect by changing the up sample feature in the background to avoid this effect. In this way, rising or falling glissandi don’t have mistimed vibrato. If I want, I can deliberately set the up sample feature to higher or lower samples. In the case of this piece, the bass flute part is played by four different flutes, with four different up sample values: -1, 0, +1, +2 from the calculated sample.
Glissandi can have many other controls, including how long to spend on the slide compared to the destination note, different durations to stay at different notes, different velocities for different notes. I’ve not yet implemented these controls in the text input file, but I have them buried in the code for later exploitation.
Listen here:
Your browser does not support the audio element.
Today’s version is for an ensemble of finger pianos, balloon drums, baritone guitar, bass flutes, clarinets, oboes, french horn, and bassoons, with their bass versions. It’s tuned to the 15-limit of the Partch Tonality Diamond.
I wrote it using a python notebook and code that’s available on github here. It has everything you need to duplicate the results. Or actually, since the piece is heavily reliant on probabilities, you can create one that is not exactly like any other.
The structure is in the form of a vamp and a bridge, each around a minute and half in length. The vamp features the woodwinds pretending to be a horn section, with the bass flutes playing slides and trills. Everyone plays tetrachords based on the 4,5,6,7/8 to 9,11,13,15/8 overtones. The bridge has the woodwinds playing one long sliding chord through a set of changes. I assume circular breathing. The bass flute plays the melody, such as it is. Throughout the bass line and percussion is playing the same tetrachords on finger pianos, balloon drums, and a baritone guitar. Tetrachords are four note chords. During the bridge the chords go through some changes that I’ve used in the past.
You can listen to the results here:
Your browser does not support the audio element.
There are a lot of parameters to modify. This one includes fading in of the instruments over the first minute, and fading them out at the end.
Your browser does not support the audio element.
I’ve been working on some python code to explore the tonality diamond to the 31-limit. This piece is one of the first to result in some “music”. It’s derived from a set of chord changes based on the 15-limit diamond. It starts out with a vamp on the otonality of 16/9, then proceeds to a bridge made up of nine chords:
# mode root rank inversion
bridge_keys = np.array([["oton","16/9","A", 1],
["oton", "8/7", "A", 3],
["uton", "9/8", "A", 3],
["oton", "16/15", "A", 4],
["uton", "1/1", "A", 2],
["oton", "1/1", "A", 1],
["uton", "7/4", "A", 4],
["uton", "15/8", "A", 4],
["oton","16/9","A", 3]])
I divide the 31-limit diamond up into what I call “ranks”. Rank “A” in the otonality is 8,10,12,14/8. Rank “B” is 9,11,13,15. I’ll get to the other ranks after I am more comfortable with the tools I’m using these days. Instead of using my old standby Pascal code to translate text into Csound, I’ve written a collection of python functions, dictionaries, and data structures. It’s a pretty steep learning curve. But I think there is potential here. Take a listen.
Your browser does not support the audio element.
This is another attempt to use the chord changes from Balloon Drum Music in another context. Scored this time for Bass Flute, Finger Piano, Balloon Drums, Oboe, Clarinet, French Horn and Bassoon. This is just the vamp on the verse in 16/9 otonality.
Your browser does not support the audio element.
This piece is made up of 17 short pieces based on a journey through the tonality diamond. They each consist of a vamp and a bridge. The vamp is in the same key for several measures, and the bridge follows a set of rapid chord changes as shown in the list below. vamp: otonality on … Continue reading Balloon Drum Music for Small Ensemble #17
Today’s work results from trying to isolate the variables that create the most interesting set of five dances based on the TonicNet Chorales. In this version the keys are F# minor, B minor, E major, A major and D major, tuned in Kellner’s Well Temperament. As before, I chose them because they have many segments … Continue reading Five Dances based on TonicNet Chorales #46
This one is based on chorales in a circle of fifths: The chorales start out in F# minor and then B minor, E major, A major, and the final one in D major. It has a nice bouncy feel. I added some Balloon Drums.
I’ve been using Pandas dataframes to analyze the synthetic chorales I’ve created. I started by generating 500 of them. Then I use lots of python code to learn more about the chorales. Each chorale produced by the TonicNet GRU model consists of a variable number of time steps, each consisting of Soprano, Alto, Tenor, & … Continue reading Five more Preludes based on TonicNet Chorales #22
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, … Continue reading A Very Long Version of Five Preludes from TonicNet chorales for Finger Piano
Today’s contribution uses synthetic chorales manufactured by a TonicNet model in the keys of E♭ major and C♮ minor, which use the same notes. This one is also tuned using Kellner’s Well Temperament. Scored for finger piano. I set it up so that all the five chorales would be about the same length, and I … Continue reading Five more Preludes on TonicNet Synthetic Chorales #7
These are based on four of the synthetic chorales that I manufactured using the TonicNet GRU deep neural network model. They are in A minor, C major, A minor, C major, and repeat the first at the end in A minor. Each uses a different arpeggiation matrix. The tempos are based on how many notes … Continue reading 5 Preludes on TonicNet Synthetic Chorales #3
This is one that uses five synthetic chorales manufactured by the TonicNet model, all in the key of F# minor. It’s scored for solo finger piano. There’s a short pause between each chorale. The tuning is Kellner’s Well Temperament. I took the idea from Bach’s Well Tempered Clavier Prelude #1, where he moved through a … Continue reading Fantasia on some TonicNet Chorales #1
Today’s submission is based on a chorale synthesized by TonicNet, created by Omar Reacha. His paper, Improving Polyphonic Music Models with Feature-Rich Encoding from 26 Nov 2019 uses a type of deep neural network called the Gated Recurrent Unit to generate very nice Bach chorales. Here is the Paper and Code. He used that network … Continue reading Fantasia on some chorales made by TonicNet #14
This another version of the piece I’ve been working on for a while, based on a COCONET deep neural network generated synthetic chorale. The original chorale was Look Down from Heaven (BWV 2.6, K 7, R 262) Ach Gott, vom Himmel sieh darein (BWV 2.6, K 7, R 262), but it’s gone through the model … Continue reading Look Down for Finger Piano, Strings, Balloon Drums, and Springs #65
This post is going to trace the path that our national anthem took as it went through a neural network and probabilistic algorithms in its journey to produce some music. It started out as a midi file downloaded from the internet. Here is the first few measures as played on a quartet of bassoons with … Continue reading How The Star Spangled Banner became “Not the Star Spangled Banner”
This one has some adjustments and increased tempo. Also tuned to Victorian Rational Well Temperament.
I used to play in a woodwind quintet in college, and it was a lot of fun. Sometimes a professor would sit in if someone wasn’t available, and we could really get cooking then. My instrument was the clarinet at the time. I wrote some music for the group, but it wasn’t very good. Some … Continue reading Not the Star Spangled Banner #15
I’ve been trying out lots of modifications to the Sacred Head Fantasia on a Synthetic Chorale. Today’s post is number 115. It’s more dense than before, starting with 24 voices, and then selectively trimming some voices in each of nine sections.
I increased the potential number of voices, and added Balloon Drums, Long Strings, and a few more finger pianos. Now it sounds like an orchestra of zithers. Big ones, and giant bass kalimbas. These are all samples from instruments I’ve built over the years. There are times that remind me of Hawaii Slack Guitars. I … Continue reading Oh God, Look Down from Heaven #38
This is based on the coconet model transforming another Bach chorale. Ach Gott, vom Himmel sieh darein (Oh God, Look Down From Heaven). This chorale uses a lot of notes outide the primary key of D minor. Coconet did his best to harmonize it. I scored it for some samples that I made myself, and … Continue reading Oh God, Look Down from Heaven (BWV 2.6, K 7, R 262) Ach Gott, vom Himmel sieh darein #15
This one was an experiment with a tuning that works well in the primary keys of the chorale, but goes into strange territory with notes outside those triads. It’s designed to sound good with the following triads: D major, A major, G major, B minor, F# major, and E minor. But there is more to … Continue reading Sacred Head in the Wolf’s Lair
I built a machine that cranks these out by the dozen. This one is interesting. I also implemented a few new routines, one that flips sections horizontally, and another that tiles sections. The former reverses the direction of a short segment, the latter repeats a section over and over. With all the masking going on, … Continue reading Sacred Head #44
This is another fantasia on the output of the coconet Deep Neural Network Model, scored for a primarily percussion ensemble. I fed a real chorale into the model, with the exception of one of four voices, and it predicts the missing voice. I repeat the process until I have 4 chorales all made up by … Continue reading Fantasia on an Artificial Chorale that sounds a lot like “O Sacred Head Now Wounded”
I fed another Bach chorale through the coconet model. This one is Wachet doch, erwacht, ihr Schläfer (BWV 78.7, K 188, R 297), which is the same as BWV 353 Jesu, der du meine Seele. I call it “Wake Up, Wake Up, you Sleepers”. I removed one of the SATB voices, and had the model … Continue reading Fantasia on an Artificial Chorale #31
I’ve been working on the algorithmic aspect of this music making enterprise for a while. What I’m doing is not strictly Deep Learning, and not just algorithmic music either. It’s more of a hybrid of the two. In this case, I took one of the 16 voice chorales made with the coconet deep learning model, … Continue reading Fantasia on an Artificial Chorale #30
This one is based on synthetic chorale #90, which is the one with the lowest note entropy. I take voices 9 through 15, which equates to A, T, B, S, A, T, B, where we have two altos, two tenors, two basses and a soprano voice. With more notes, there are more wrong notes, so … Continue reading Another Fantasy on and Artificial Chorale
I want to stress up front that this is an experiment in making music. I’m fascinated by deep learning in all its magical incantations, but I’m using it as just one of many tools in my musical toolbox. At present, I’m using deep learning techniques to generate artificial chorales based on Bach using the coconet … Continue reading Fantasy on an Artificial Chorale #13
Today’s version fixes a few mistakes: Increased the use of louder and softer samples by increasing the velocity variability Added a copy of the 4 voices to make 8 voices in total, then modified each to improve the arpeggiation variability Added some octave variability in new places in the flow Changed the base fantasy chorale … Continue reading Fantasy on an Artificial Chorale #11
This is a piece that originated as Bach’s BWV 180 Schmücke dich, o liebe Seele, reprocessed by the coconet deep learning model. I split the chorale up into 32 1/16th note segments, which is what the model was built to handle. I zero’d out one of the voices, and had the model remake that voice … Continue reading Fantasy on an Artificial Chorale #10
This one was done a different way than the previous versions. Previously I had created 16 voice chorales by preserving just the bass part and letting the model figure out the other notes. What I created were four different versions of harmonizing a bass line. Each knew nothing of what the other ones had created, … Continue reading A new approach to artificial chorales – #8
This set of variations have all been the result of taking four different chorale renditions and mashing them together to make a 16 part chorale. The problem is that chorale #1 has no knowledge of what chorale #2,3,or 4 are up to. That means that each may find a different path to their solution and … Continue reading Yet another artificial chorale #8
Today’s addition includes some arpeggios based on the outputs of the coconet chorale building model, as modified by me. I made this by building a set of masks that would silence some of the notes in the arrays. My current data structure consists of 16 voice lines. Each line contains 264 slots, each a 1/16th … Continue reading Another Artificial Chorale – with arpeggios – #7
This is another in the series of Artificial Bach Chorales created by the coconet deep learning neural network. I take the output of the neural network and combine four predictions on top of each other. Imaging four piano players in the four corners of the room told to improvise a chorale based on the bass … Continue reading Artificial Bach – Schmücke dich, o liebe Seele #4
This is a complete performance of Schuman’s Three-Score Set, with each set played straight, and followed by several variations. The variations transform the themes in a variety of ways. The tuning is all scales derived from otonal scales in the tonality diamond to the 31-limit. The specific scales change frequently. In the scores shown below, you can see in the middle the otonal scale for each measure segment.
http://ripnread.com/listen/Machine7-t42.mp3 or download here:
Machine7 – Three Score Set – with variations – #42
This the theme and a set of variations on set III from Schuman’s Three-Score Set. The theme is played straight. For the variations I take each segment of a measure and play it, then make many alterations to it quickly and comprehensively, then move on to the next measure segment. For example, I might play the first half of measure 2, then make changes to the tempo, rhythm, notes, and other characteristics, until moving to the second half of measure 2. And so on. So it keeps coming back to the theme, but intersperses variations as it goes on.
In the graphic of the score below, I’ve added the otonal scales for each segment. In measure 0, you can see the C#. That’s an otonality based on 16:15 above C. Then, the third part of measure 2 I switch to the 1:1 otonality. Measure 4 uses notes from the G# otonality, with G# meaning 8:5 above C, followed by D+, which is 8:7 above C.
There are many slides, usually from one note to the next in a sequence. Other slides are within a chord, as at the end of measure 2, repeated at measures 19 & 20.
http://ripnread.com/listen/Machine7-t37.mp3 or download here:
Machine 7: William Schuman – Three-Score Set – variations on set 3 – #37
This is another version of the set II from Schuman’s Three-Score Set, with variations. Each of the variations messes a bit more with the note order, duration, envelopes, octaves, dynamics, glissandi, and rhythms to create something progressively less like the original, until it’s almost completely unrecognizable. But the chords are the same throughout. It’s like a machine that destroys the material as it progresses. For this version, I shortened some of the variations, and included a repeating bridge between variations.
http://ripnread.com/listen/Machine7-t33.mp3 or download here:
Machine 7: William Schuman – Three-Score Set – variations on set 2 – #33
This is a more or less final version of the set II from Schuman’s Three-Score Set, with variations. Each of the variations messes a bit more with the note order, duration, envelopes, octaves, dynamics, glissandi, and rhythms to create something progressively less like the original, until it’s almost completely unrecognizable. But the chords are the same throughout. It’s like a machine that destroys the material as it progresses.
http://ripnread.com/listen/Machine7-t26.mp3 or download here:
Machine 7: William Schuman – Three-Score Set – variations on set 2 – #26
Today’s post is a very short trial run on variations on set 2. For now, it only includes the first two measures. They consist of four bitonal chords:
Each of the variations messes a bit more with the note order, duration, envelopes, octaves, dynamics, glissandi, and rhythms to create something progressively less like the original, until it’s completely unrecognizable. But the chords are the same throughout. My plan is to add more measures over time.
http://ripnread.com/listen/Machine7-t22.mp3 or download here:
Machine 7: William Schuman – Three-Score Set – variations on set 2 – #22
Today’s post is three variations on set 1. The first has minimal alterations, just tempo and glides. The second uses the Drunkard’s walk to wander around the set. The third is much more wide open, with notes taken from one measure and durations from another.
http://ripnread.com/listen/Machine7-t20.mp3 or download here:
Machine 7: William Schuman – Three-Score Set – 3 variations on set 1 – #20
This is aother variation on set one. Lots of similar and dissimilar variations of each measure in the set. The order of the measures is backwards or forwards, with some Drunkard’s Walk, and some sequential.
http://ripnread.com/listen/Machine7-t14.mp3 or download here:
Machine7 – William Schuman – Three-Score Set – #14
This is a variation on set one, the 20 measure piece that uses fourth chords and a melody line. I stripped out the notes and the durations, then mixed them up a bit. I’m still working through the material here.
http://ripnread.com/listen/Machine7-t10.mp3 or download here:
Machine7 – William Schuman – Three-Score Set – #10
This is much like yesterday’s version. I increased the volume a bit, so it’s now using some louder samples in the Bosendorfer sample set, and I’ve changed my own source code to make it simpler to modify going forward. I plan to play with the durations and the pitches a bit next.
http://ripnread.com/listen/Machine7-t6.mp3 or download here:
Machine7 – William Schuman – Three-Score Set – #6