In these times, the days leading up to Christmas and the holiday season, we thought it would be appropriate and interesting to use our set of tools in our analytical toolbox and take a closer look at one of the holidays core ingredients . We are going to take an introductory look (or listen?) at the topic of generative music by examining a section of a classic Christmas song.
Generative music is a rich topic with roots dating back to the 1950s with pioneers using random number generators to create melodies. By observing the occurrences of each pitch in simple children’s melodies, probabilities could be calculated and then used to create new melodies (“Banal Tune Maker” Richard C. Pinkerton 1956). Later experiments expanded on this approach and included ways to represent rhythm, dynamics and articulation in addition to pitch information. With the advance of AI and deep learning methods more advanced methods were used in the 90s and if we fast forward to today the most cutting-edge methods work directly in the audio domain, i.e. the output is audio compared to the traditional methods that rather generated instructions that had to be played by someone/something else.
The model we are using here is one the most traditional approaches to generative music, namely the Markov chain. Rather than looking at individual pitches and calculating the probabilities we are instead using the chords as a basis. The Markov chain, in its simplest form, has a number of states and describes a process where we move from state to state in discrete time steps. The transition probabilities gives us the probability to move between certain pairs of states and can be summarized in a transition matrix. By using chords as our states the specific chord progression of a song can be viewed as an outcome of a underlying Markov chain.
To illustrate this simple concept we’ll use this short section of classic Christmas song (chords given in Roman numeral notation). Even if it is a short segment it includes some nice harmonies which is what we are looking at in this example:
Since the Markov chain only captures the pairwise relation between states (it has no memory of what has happened earlier in the sequence, to make predictions about future states we only need to know the current state) we look at the chord changes and from there can calculate the transition probabilities:
By limiting ourselves to looking at this short segment we end up with a very simple transition matrix as demonstrated above. The matrix describes the model in full, to generate a sequence we just have to choose an initial state and move from there. If we initialize our Markov chain from state I, a specific outcome (or as in this case, chord sequence) could be:
I → ii7 → V → IV → V7 → I → I7 …
To hear what these sequences could sound like I decided to implement the Markov chain in the visual programming language Max Msp. The output from the program is then sent as MIDI information (a standard communication protocol for sending musical information) in the form of note on and note off messages to other musical software that plays samples of instruments based on the received instructions.
Just listening to the chords themselves quickly becomes a little boring so I added a second voice that plays the same chords but in a broken fashion, just to add a little more interest and fill out the arrangements. The complete program then looks like this:
The tempo and utility functions provides the overall tempo of the “song”. There is also an initial state parameter that is set to 1.
The transition matrix logic is implemented as a subpatch. It takes the current state as an input and generates an outcome based on the transition probabilities.
The chord definitions are added so that we know what chord each state is supposed to represent. A manual transpose control is added.
The two voices are then sent out on two different MIDI channels. The first voice, played by the string samples, are triggered all at the same time whereas for the second voice the individual notes in the chord are stepped through one by one to achieve an arpeggio effect.
This method illustrates the strength and importance of the representation of the problem in any modelling task. By using domain knowledge in the form of basic music theory a surprisingly simple model such as Markov chain can give interesting results in this generative setting. Obviously, this is not the most sophisticated modelling approach (like said in the beginning, the ideas used here are almost 70 years old!) but could serve a starting point to add e.g. melodic elements, dynamics, etc. Numerous implementations have been made were the transitions probabilities used has been based on much larger sample sizes.
The Markovian property, i.e. that the sequence lacks memory, can sometimes result in a kind of rambling feel. That the chord progression just moves on but lacks context somehow. In this example the transition matrix was so simple that this effect was somewhat limited. Otherwise different models can be used with good results, e.g. recurrent networks such as LSTM can capture the more long-term inherent structures of the chord progressions. Perhaps we’ll be able revisit this topic in future!
(Discussion; the first pioneers claimed they didn’t create music, rather were trying to arrive at insights about the process of composition inherent in the music. )