Building a Better Bach with Markov Chains CS701 Implementation Project, Timothy Crocker December 18, 2015 1 Abstract For my implementation project, I explored the field of algorithmic music composition and created a music composition program that generates simple pieces of music using Markov chains. Music creation is a task composers have attempted to automate and distill into rule sets for centuries, using sundry techniques from the algorithms for voice leading and counterpoint developed for human composers centuries ago, to complex computer-aided techniques employed today[2] [5]. One particularly fruitful approach is to use simple probabilistic models to generate music[1][8]; I sought to implement such a process myself. My program uses a combination of real-world corpora and configurable parameters to generate a rhythmic progression, a harmonic progression, and a harmonic line that combine to form a piece of music. The resultant works are simple in structure, but make musical sense and often include novel and idiomatic musical ideas. 2 Markov Chains 2.1 Definition A Markov chain is a type of stochastic process that obeys the Markov property. The process consists of a set of states S = {x 1, x 2, x 3,, x n } and a set of pairwise transition probabilities over this state space; at each advance in time, the chain uses the transition probabilities associated with its current state to determine which state to move to next. In this project I use discrete-time Markov chains, in which the chain advances on discrete intervals. Markov chains obey the Markov property; that is, if X t is a random variable representing the state of the chain at time t, P (X t+1 X t = x, X t 1 = y,, X 1 = z) = P (X t+1 X t = x). At any point in time, the behavior of the chain depends only upon recent events, not upon events further in the past; the future and the distant past are independent[3]. 1
Figure 1: Left: A state diagram of a three-state Markov chain; edges are labelled with transition probabilities. Right: A transition matrix encoding of the same Markov chain. Source: https : //en.wikipedia.org/wiki/markov c hain Markov chains can be easily represented with a directed graph or state machine, where each x i S is represented by a node in the graph, and every x y edge is labeled with the corresponding transition probability P (X t+1 = y X t = x). The same information can be encoded in a transition matrix in which entry (x, y) represents the transition probability P (X t+1 = y X t = x); this representation makes it easy for a computer to perform random walks along the Markov chain. 2.2 Higher Order Chains The order of a Markov chain is the memory of the chain; a chain of order m considers the state of the chain at the previous m time intervals when assigning transition probabilities. Thus for an order m chain, P (X t+1 X t = x, X t 1 = y,..., X 1 = z) = P (X t+1 X t = x, X t 1 = y,..., X t m = z). A chain of order m > 1 can be recombined into a new chain of order 1, where the states of the new chain correspond to m-tuples of states of the original chain; there is no functional difference between these two chains when performing a random walk, but this refactoring makes interacting with chains of differing orders more uniform and consistent.[3] In the context of algorithmic music composition, using higher order chains to produce melodic and harmonic material makes for more musically idiomatic results, since a longer memory induces chains to capture and reproduce the entirety of longer musical ornaments and devices. However, since m-order chains perform random walks along m-tuples of states, the state space grows exponentially with chain order, and so as the order increases it becomes increasingly difficult to adequately populate the corresponding transition matrix. When incorporating a corpus of existing music to determine transition probabilities, the problem becomes apparent: many m-tuples of notes may appear only once, or not at all, in the training music; if the order is large enough, and the training set 2
small enough, the chain will happily parrot back a training piece in its entirety, since each m-tuple state leads deterministically to the next! My program uses chains of order at most 2 to produce its results. 3 Implementation 3.1 Tools I wrote my composition program in Python. In addition to being a user-friendly language that I am comfortable working with, Python enabled me to take advantage of a couple useful libraries. Since my program lent itself to the use of large and cumbersome matrices, I used NumPy (http://www.numpy.org/) to initialize and normalize these matrices. I also discovered a specialized Python library called Music21 (http://web.mit.edu/music21/), an MIT-developed library intended for musicology use. Music21 proved to be an invaluable asset over the course of the project; it allowed me to easily parse existing pieces of music, create and arrange note events within a MIDI file, and output results as MIDI and XML files. Music21 also included some useful musical corpora of digitized Bach and Mozart works that were immensely valuable in synthesizing Markov chains. 3.2 Model My program generates pieces of music in the Dorian mode and common time; the length and key signature of each piece is variable. 3.2.1 Rhythm The first step in my program s process is to generate a rhythmic template for the composition. The program is tasked with filling a certain number of beats with rhythmic information (by default, 48 beats for 12 bars in common time); it does so by taking a walk on a rhythmic value Markov chain, and appending the rhythmic unit selected at each step to the template until the desired piece length is reached. This Markov chain is first order (i.e. each rhythmic unit selection depends only upon the immediately preceding rhythmic unit), but its states encode information about both the rhythmic unit and location of that unit in the bar. To keep beats distinct, and to produce sensible rhythmic patterns, there are three possible types of rhythmic units, each constituting a single beat in length: a single quarter note, a pair of eighth notes, four sixteenth notes. Since each of these units can fall on any of the four beats in a measure, the rhythm transition matrix is 12x12 in size. The rhythm chain s state encodes information about location in the bar to capture some common patterns in Western music: in a four-beat measure, emphasis often falls on beats one and three, so we d like to slightly favor quarter notes on these beats, and smaller rhythmic denominations on the interstitial beats. 3
The state encoding allows the chain to balance this consideration with higherlevel patterns like following sixteenth notes with additional sixteenth notes. I designed the rhythm matrix by hand, without using data from my corpora. Throughout my process, I tweaked this matrix s transition probabilities to my tastes; my project includes a file that lists a set of interesting or distinctive alternative matrices. Figure 2: A 12-by-12 rhythm matrix used to generate a rhythmic template. Each state encodes a beat number and a rhythmic unit. 3.2.2 Harmony After deciding on a rhythmic underpinning for the piece, my program uses another Markov chain to generate a harmonic progression that determines the piece s bass line and bends the melody to favor certain chord tones. The program generates one harmony per bar, and every harmony lasts for an entire bar. The harmonic Markov chain has seven states, one for each scale degree; this chain also has order one. When the harmonic progression is complete, it is used to create a simple bass line for the piece: for each bar, the current harmonic state s scale degree is played doubled as an octave in a lower register. This octave event lasts for the whole bar, but its MIDI velocity is lowered so that it doesn t drown out the melody. Harmonic progression was a later addition to my program; I implemented it because I was unsatisfied with the meandering, structureless behavior of my generated pieces. Laying melody over a harmonic progression adds much-needed high level structure to compositions, and allows for some basic polyphony. Like the rhythm chain, I created the harmonic chain by hand. The chain used in the final program favors V-I and IV-I cadences, though I also created alternative chains that move more randomly around all seven scale degrees, or deterministically follow the I-V-vi-IV progression ubiquitous in popular music. My final program cheats a bit to ensure that the piece s key is established by beginning and ending every piece on the I chord. 4
3.2.3 Corpora Parsing and Melody Generation The final and most interesting part of my program s music generation is the melodic generation phase. A piece s melody is generated using a second order melody chain (for implementation purposes, the second order chain is represented by a first order chain of note tuples). Each state corresponds to the ordered tuple of the previous two pitches; in order for the program to be key agnostic, each pitch is represented by its relative distance in half-steps from the tonic, so the states are numbered 0,1,2,...,11. The matrix is 144 x 12: one row for each of the 12 x 12 = 144 pitch tuples, and one column for each possible subsequent note; when performing a random walk, the next state tuple is obtained by taking the second element of the note tuple (the previous note) and combining it with the newly selected note. This practice avoids the construction of an extremely sparse square matrix (consider: if we constructed a square 144 x 144 matrix whose columns were indexed by note tuples as well, the state (G,A) would have nonzero transition probabilities only for states of the form (A, X), since the first note in the new tuple must always be the second note of the old tuple). The transition probabilities for the melody matrix are computed using realworld data. Starting with a matrix of all zeroes, the program scans through pieces of music, and increments entry (i, j) whenever note pair i is followed by note j. After reading through all pieces of music, each row is normalized to yield the final transition matrix. Since the pieces of music chosen have a powerful effect on the character of the generated music, the training material must be careful selected and prepared. Since I have decided to generate pieces in major keys, the training music must be in a major key, and selections must be truncated before any modulation is introduced. Also, the training pieces should ideally be written in a similar style. Each training piece is read into the program as a tuple of a destination file and a tonic note; supplying the tonic allows me to use pieces in disparate major keys, since each interval in the piece can then be measured relative to the tonic and stored appropriately in my key independent transition matrix. The pieces of music I use, from the Music21 corpus and elsewhere, supply my program with several thousand note instances. I use these existing pieces not to emulate the style of existing composers (a second-order chain is unlikely to capture macro stylistic traits), but to quickly populate a large matrix with transition probabilities that are known to be musically sensible.[8] 5
Figure 3: Reading in several works from the Music21 corpus. The tonic of each piece must be passed to the program. Since the generated melody is eventually layered on top of the rhythmic template, the length of the walk performed on the melodic chain is equal to the number of note events specified by the rhythmic template. At each transition along the walk, the harmonic progression influences transition probabilities to guide the melody towards harmonically logical choices. Every state in the harmonic chain has an associated set of pitches it favors, typically the scale degree triad built using the harmonic state as the root. When making a transition between states, transition probabilities are altered using a mask that takes into account the biases of the current underlying harmony. Each mask multiplies each transition probability by a scale factor, and then the transition matrix row is renormalized. This mechanism allows the harmony chain to impose its structure on the randomness of the melodic chain. The melody composition operates within a configurable octave range. To avoid jarring jumps in the melody, after selecting the next pitch in the melody, the pitch s octave is assigned in such a way that it causes the smallest intervallic leap while still remaining within the octave range. Once the melody generation is complete, each melody note is turned into a Music21 Note object, and is assigned a MIDI pitch and a duration according to the rhythm template event at the same index. These objects are compiled into a single music stream, which gets output as.mid and.xml files. 4 Output My program produces short pieces with evident musical structure, and they often include brief moments of novel, interesting musical material. I m quite satisfied with my results, and I m happy with how my a priori rhythm and harmony modifications complement and mold the stochastic melody. The structure of my program makes it easy to experiment with different rhythmic and harmonic patterns, and changes to these can cause significant change in the character of the output. Some samples are available at: http://www.cs.middlebury.edu/ tecrocker/impproj/ 6
Figure 4: An excerpt of a 12 bar piece created using my program. 5 Future Work My program can be improved in many ways. Currently, rhythm generation and melody generation are totally separate processes, but in actual composition the two are closely intertwined. It might be interesting to have one process influence the other, perhaps by encouraging harmonically important events to occur on quarter notes. I could also use my corpora to greater effect, not only to create a larger sample space, but also to replace artificial transition probabilities in my rhythm and harmony chains. References [1] Charles Ames. The markov process as a compositional model: a survey and tutorial. Leonardo, pages 175 187, 1989. [2] John Biles. Genjam: A genetic algorithm for generating jazz solos. In ICMA, 1994. [3] Wikipedia editors. Markov chain. https://en.wikipedia.org/wiki/ Markov_chain. [4] K. McAlpine, E. Miranda, and S Hoggar. Making music with algorithms: A case-study system. Computer Music Journal, 23(2):19 30, 1999. [5] F. Pachet, P. Roy, and G Barbieri. Finite-length markov processes with constraints. In IJCAI, pages 635 642, 2011. [6] K. Verbeurgt, M. Dinolfo, and M Fayer. Extracting patterns in music for composition via markov chains. Lecture Notes in Computer Science, 3029:1123 1132, 2004. 7