Chapter 4

Transformation and Process

Topics: Musical patterns and meaning, minimalism, Steve Reich, Mod functions, musical canon, J.S. Bach, Arvo Pärt, viewing musical material, software development process, computer-aided music composition.

4.1 Overview

Being able to write down and represent music is an important skill that we have examined in some detail in the previous chapters. In this chapter we focus on another important skill, transforming music to create variations and developing it into longer and more interesting compositions. More broadly, this chapter explores foundational programming skills required to manipulate data. But first, a little background to provide context.

4.2 Gestures, Emotion, and Musical Structure

The contrast between the composer’s and audience’s experience of music was discussed by Arnold Schoenberg, a 20th century composer who developed a system of serial (algorithmic) music composition, which avoided tonality by requiring an even distribution of all the 12 chromatic scale tones. On the issue of musical structure existing as space and time, he commented that, “Music is an art which takes place in time. But the way in which a work presents itself to a composer … is independent of this; time is regarded as space. In writing the work down, space is transformed into time. For the hearer this takes place the other way round; it is only after the work has run its course in time that it can be seen as a whole—its idea, its form, and its content” (quoted in Cook 1990: 40).

A common conception of musical fragments is as gestures or sequences of sound with characteristic shape, which appear as movement in pitch and time space. Like animation, a series of notes can provide the illusion of movement even though it is only a series of stationary events. For example, a scale of ascending tones may appear as a rising gesture. These musical impressions emerge from the overall effect of individual scale notes, and even when the pattern is interrupted with a brief descending tone, the overall shape of the line is maintained. This tendency of musical sequences to be perceived as gestural curves was observed by Roger Scruton, who wrote that, “It seems then that in our most basic apprehension of music there lies a complex system of metaphor, which is a true description of no material fact” (Scruton 1983).

This metaphorical aspect of musical structures goes beyond the gestural nature of musical shapes in time and space to include the ways in which these combine to indicate musical styles and emotions. Particular musical patterns can be characteristic of particular musical styles, or even of individual composers. David Cope called such frequently found gestures stylistic signatures (Cope 2004). Musical metaphors are even more direct when depicting emotional states, for example, the slow tempo and wide vibrato that imitate the despondent movement and quivering lip of a very sad person, or the violent staccato bowing of Bernard Herman’s score for the stabbing featured in the “shower” scene from Alfred Hitchcock’s film Psycho.

4.2.1 Musical Patterns

Many experiments have been done by psychologists to determine how we hear musical lines. It should be noted that the tendencies in our imaginative perception are not simply choices about how things appear to us, but are the result of how our brain attempts to group events and always seeks to find patterns in what we hear. In musical terms, the patterns that appear in musical material are the basis for the texture and the form of music. These structural elements are designed by the composer and then described in a medium, for example, in written notation or, in our case, Python code. This compositional process requires the imagining of musical structures and then their description. Interestingly, this is the reverse of the listeners’ experience, where they hear the music unfold over time, then retrospectively construct the form from their memory of passing events, or more particularly from the lines, shapes, and textures they perceived as the events unfolded.

There is a connection between music’s structure and its meaning and enjoyment. Understanding some of the psychology of perception that underpins these sound-gesture metaphors assists the composer to better create a desired musical experience. The roots of psychological concerns about how people perceive patterns in a holistic way can be traced back to the Gestalt psychology movement that originated in Europe in the early decades of the 20th century. The movement’s core principle is that the mind tends to impart structure and organization to its experiences, and that a system’s functioning cannot be wholly understood solely in terms of its parts. The experiments of Gestalt psychologists were particularly focused on visual perception; however, they also made connections to audible perception of music. The Gestalt psychologists examined a range of phenomenal qualities and derived a series of rules or laws about ways in which humans organize their experiences. These include:

  • The law of proximity, where objects that are closer (in space, time, pitch, and so on) are grouped together;
  • The law of symmetry, where things that create a trend or pattern are perceived as a closed region; and
  • The law of good continuation, where a direction implied by object relations remains expected even in the face of interruption, change, or inconsistency.

The Gestalt psychologists also tended to associate the recognition of complex patterns with intelligence or creativity, seeing the best thinking as being novel rather than reproductive. They tended to believe that the mind operated to impose logical organization upon the world, as it was perceived.

A holistic and schema-based view of pattern recognition was not limited to the Gestalt movement. Other approaches to understanding perception were presented by psychologists such as Jean Piaget and James J. Gibson. In these approaches, mental representations were thought of as interactions with experiences in the world rather than the imposition of organizational schema on the mind of the individual. Piaget’s work was in the area of child development, where he conducted experiments and observations to study how the young mind’s understanding of the physical world evolved with age. J. J. Gibson’s work focused on how understanding arose from interpretation of cues in the environment; these cues he called environmental affordances. Gibson argued that many behaviors were based on instinctive or automatic responses, which did not require mental processing at all, but could be refined through learning and experience. More recent work in cognitive science has elaborated on these views (Gardner 1985).

These views of mental models and perceived organization need to be kept in mind by the composer, that is, that the listener will perceive sequences of notes and durations as having higher-order organization and meaning when grouped into phrases, riffs, chords, rhythms, melodies, and so on. This is particularly important for a composer operating at the potentially more abstract level of algorithmic composition. In this chapter we will examine some useful compositional patterns and show how they can be coded in Python.

4.3 Minimalism

There are various musical forms and styles. One of the most intriguing ones is minimalism.

Definition: Minimalism refers to an artistic movement that uses a limited number of elements to create the strongest possible effect.

Minimalism emerged in the mid to late 20th century as a reaction to the complexity (and some would say, intellectual arrogance) of early 20th century music (e.g., 12-tone music). As a movement, it is a rebooting of sorts, that is, an attempt to return to basics.

Minimalist music usually employs repetition and layering of simple musical patterns to generating intricate musical textures and structures.* Minimalist composers include La Monte Young, Terry Riley, Steve Reich, and Philip Glass. Minimalist music is sometimes known as systems music—this refers to the system of rules created by the composer, which is applied to simple musical material to generate intricate musical experiences. Sometimes, this may result in sparse works (such as those of La Monte Young and Philip Glass, which feature drones and slowly overlapping phrases) or very repetitive works (such as Harold Budd’s “Lovely Thing,” which consists of one chord played softly over and over for about 15 minutes, or Erik Satie’s “Vexations,” where a short section is repeated hundreds of times). Another famous minimalist piece is Terry Riley’s “In C,”, which features repeated material with very limited harmonic changes over about an hour of performance.

Music from non-Western cultures, which relies heavily on repetition, has had an influence on minimalist composers. Steve Reich, for example, was inspired by the repetition of simple phrases and rhythms in the music of Bali and Ghana.

4.3.1 Repetition and Phasing

Repetition is a common musical technique that can be used to extend music or to create slowly evolving changes like those used by minimalist composers. Computers excel at mundane repetitive tasks and so this section will explore how repetition can be put to effective musical use. Computers have already found a significant role in popular music styles, particularly electronic dance music, where the use of repetition is pervasive. While some exact repetition provides music with coherence and structure, too much repetition can often be dull or boring. Music that relies on repetition often introduces variety in one parameter to provide sufficient interest that we continue to pay attention to the evolving change. Electronic dance music, for example, uses small timbral changes to maintain interest—usually achieved by sweeping a highly resonant low-pass filter over the sound source.

Phasing is a technique notably used by Steve Reich that adds interest to repetition. Phasing involves taking a musical phrase (melodic or rhythmic) and overlaying it with copies of itself that are not aligned. Copies can be played back at different speeds, causing changes in alignment over time, which generate various perceptual artifacts.

4.3.2 Case Study: Steve Reich, “Piano Phase” (1967)

This case study demonstrates how to recreate Steve Reich’s “Piano Phase,” a minimalist piece for two pianos involving tempo differences and repetition.

One way of achieving phasing is to independently vary the playback speed of two identical looped phrases. This is a subtle effect and, if the speed variation is only minor, adds timbral variety through phase cancellation to the more obvious rhythmic evolution. This technique emerged from Reich’s early experiments with tempo phasing using tape players. Each tape machine used the same tape loop of pre-recorded material. However, one tape player was set to a slightly faster playback speed than the other. Once Reich understood this musical process well, he transferred it to compositions for acoustic instruments.

In “Piano Phase,” two pianists have the same short phrase to play on separate pianos. They begin together, then after some time one pianist speeds up slightly, causing the phase effect. When the faster part is one quarter note ahead (i.e., aligning the first and the second note of the overlaid musical material), the faster pianist reverts to playing at the original tempo. This process is repeated several times, with the phase distance increasing each time. This provides a staircase effect of stable and phasing sections.

In the code example below, we recreate a section of Steve Reich’s “Piano Phase,” where the two parts play at different speeds. The speed difference is quite small, 0.5 beats-per-minute (quarter notes per minute), so the phase shift is quite gradual, but nevertheless the result is dramatic.

# pianoPhase.py
# Recreates Steve Reich's minimalist piece, Piano Phase.
from music import *
pianoPart	= Part(PIANO, 0)	# create piano part
phrase1	= Phrase(0.0)	# create two phrases
phrase2	= Phrase(0.0)
# write music in a convenient way
pitchList	= [E4, FS4, B4, CS5, D5, FS4, E4, CS5, B4, FS4, D5, CS5]
durationList	= [SN, SN, SN, SN, SN, SN, SN, SN, SN, SN, SN, SN]
# add the same notes to both phrases
phrase1.addNoteList(pitchList, durationList)
phrase2.addNoteList(pitchList, durationList)
Mod.repeat(phrase1, 41)	# repeat first phrase 41 times
Mod.repeat(phrase2, 41)	# repeat second phrase 41 times
phrase1.setTempo(100.0)	# set tempo to 100 beats-per-minute
phrase2.setTempo(100.5)	# set tempo to 100.5 beats-per-minute
pianoPart.addPhrase(phrase1)	# add phrases to part
pianoPart.addPhrase(phrase2)
Write.midi(pianoPart, "pianoPhase.mid")	# save music to a MIDI file
Play.midi(pianoPart)	# and play it.

Notice how the two parts start in synchrony and then slowly fall out of phase, creating different melodic and rhythmic artifacts exploiting our brain’s need to organize unrelated events into meaningful patterns. Steve Reich’s “Piano Phase” could be viewed as a statement about our perceptions and experiences in the world we live in (e.g., how much of this is real and how much of it is an artifact of our mind’s need to organize—or does it make a difference)? Quite a powerful effect.

The program also demonstrates how to use the function Mod.repeat() to repeat a phrase. This function can also be used to repeat parts and scores. There will be more on the Mod class and its functions later in this chapter.

The above example demonstrates how, through computer programming, we can easily surpass the musical capabilities of a single performer on a traditional instrument. The rest of the book is full of such examples.

4.4 Modifying Musical Material (Mod Functions)

Musical transformations are widely used in Western music composition. The music library contains many common compositional transformations for phrases, parts, and scores. These functions are included in the Mod class.

We have already been using functions from other classes in the music library such as Note, Phrase, Part, and Score. For example, addNote() is a function of the Phrase class, and setInstrument() is a function of the Part class.

The Mod class has functions that allow transformation (hence the name “Mod”—short for “modify”) of musical material stored in phrases, parts, and scores. While the arguments for (i.e., the values passed to) each function vary slightly, the general structure of calling Mod functions is:

Mod.functionName(data, argument1, argument2,...)

Here are two examples:

Mod.append(phrase1, phrase2)
Mod.repeat(phrase1, 4)

The first example modifies phrase1 by adding to its end all the notes from phrase2. The second example repeats phrase1 so that it plays four times (i.e., this is the same as appending phrase1 to itself three times — why?).

All the functions in the Mod class follow the same syntactic pattern. The first argument is always the musical data to be modified. Subsequent arguments describe the way in which the first argument should be modified; subsequent arguments are never altered. For example, in Mod.append(phrase1, phrase2) the second argument, phrase2, is not altered. It is the first argument, phrase1, that is altered to include the notes stored in phrase2.

Many functions in the Mod class come in different flavors, that is, several functions have the same name but work with different arguments. For example, the Mod class contains several append functions.

Mod.append(phrase1, phrase2)
Mod.append(part1, part2)
Mod.append(score1, score2)

In most cases the function names are self-explanatory. Below we present some useful Mod functions for Phrase objects. Most of these functions also apply to Part and Score objects. We organize them into functions that modify volume, functions that modify length, functions that modify pitch, and functions that use randomness to modify different musical aspects.

4.4.1 Modifying Volume

The following functions modify the volume (or dynamic) of notes in a phrase.

Function

Description

Mod.accent(phrase, meter)

Increase volume (accent) of the first quarter note beat of each measure in phrase, where meter is the number of beats per measure (e.g., 4.0).

Mod.accent(phrase, meter, beats, amount)

Same as above, except we provide a list of beats (e.g., [2, 3]) to accent and amount of accent (e.g., 15).

Mod.compress(phrase, ratio)

Compress (or expand) the dynamic range of phrase, by the provided compression (or expansion) ratio (e.g., 4.0).*

Mod.crescendo(phrase,

time1, time2, vol1, vol2)

Increase volume in phrase from vol1 at time time1, to vol2 at time time2.

Mod.fadeIn(phrase, length)

Starting from zero volume, increase volume gradually over length quarter notes to reach the normal phrase volume.

Mod.fadeOut(phrase, length)

Starting from the normal phrase volume, decrease volume gradually over length quarter note to reach zero volume.

Mod.normalize(phrase)

Increase note volumes proportionally in phrase, so the loudest note is at maximum level.

* Use cycle() when you wish to fit a particular length. Use repeat() when you wish to repeat a number of times, regardless of length. When repeating overlapping phrases of different lengths, cycle() will guarantee they all end at approximately the same time.

4.4.2 Modifying Duration

The following functions modify the length of a phrase in various ways.

Function

Description

Mod.append(phrase1, phrase2)

Modifies phrase1 by appending to it the notes of phrase2.

Mod.elongate(phrase, factor)

Change (elongate) the length of notes in phrase by the provided scaling factor. If the factor is less than 1.0 it shrinks the duration (e.g., 0.5 reduces the duration to half—which is the same as doubling the speed or tempo).

Mod.changeLength(phrase, beats)

Change (scale) the duration in phrase, so its total duration equals the provided number of beats (quarter notes).

Mod.cycle(phrase, beats)

Repeats phrase until it spans the specified number of beats (quarter notes). Repetition stops with the note that reaches (or exceeds) the provided length (i.e., the last repetition of phrase may be incomplete).

Mod.palindrome(phrase)

Doubles the length of phrase, by appending a copy of itself in reverse order.

Mod.repeat(phrase, times)

Same as cycle(), expect we specify the number of times to repeat the phrase regardless of length (i.e., the last repetition of phrase is always complete).*

Mod.quantize(phrase, quantum)

Rounds (quantizes) the start time and duration of each note in phrase to fit multiples of quantum (e.g., 1.0). The smaller the quantum, the lesser the amount of change. A large quantum results in music that sounds mechanical.

* Use cycle() when you wish to fit a particular length. Use repeat() when you wish to repeat a number of times, regardless of length. When repeating overlapping phrases of different lengths, cycle() will guarantee they all end at approximately the same time.

4.4.3 Modifying Pitch

The following functions modify the melody (note pitches) of a phrase in various ways.

Function

Description

Mod.invert(phrase, pitch)

Mirror (invert or flip) the pitch of all notes in phrase relative to pitch.

Mod.transpose(phrase, interval)

Shift the pitch of every note in phrase by interval (number of chromatic steps, e.g., −12 lowers by an octave; 12 raises by an octave).

Mod.retrograde(phrase)

Reverse the order of the notes in phrase.

Mod.rotate(phrase, times)

Move (rotate) the notes around the phrase (i.e., last note becoming first, first note becoming second, second note becoming third, and so on), where times indicates how many times (i.e., how many notes) to rotate.

4.4.4 Modifying with Randomness

The following functions transform musical material using randomness in various ways.

Function

Description

Mod.shuffle(phrase)

Randomly reorganize the order of the notes in phrase.

Mod.mutate(phrase)

Mutate phrase by changing one pitch and one duration value. The new pitch is selected randomly between the lowest and the highest note of phrase. The random duration is selected from those in the existing notes.

Mod.randomize(phrase, pitchAmount)

Randomizes pitches in phrase by a value within +/- the specified pitchAmount.

Mod.randomize(phrase, pitchAmount, durationAmount)

Same as above, plus specify random variation of the duration (plus or minus durationAmount).

See Appendix B for additional Mod functions and descriptions of what they do. Soon we will discuss how to define our own functions and classes. This way we can implement additional transformations, as we desire. Learning how to do this is part of the essence of programming music.

4.5 Musical Canon

A canon is a structurally intriguing example of polyphonic music, and one of the oldest musical forms. Composers create canons by taking a musical theme (also known as subject) and making one or more copies of it and then overlaying them offset in time. If done well, the end result can be quite amazing. Although not traditionally thought of as such, Steve Reich’s “Piano Phase” is a type of musical canon.

Definition: A musical canon (or round) is a musical structure where a melody is played against one or more displaced copies of itself.

One well-known and simple example is the nursery rhyme, “Row Your Boat” — we will see it next. As you might imagine, there are many more canons in music history — some quite elaborate. Later in the chapter, we will see two canons by J. S. Bach. Another interesting example is the first movement of Béla Bartók’s “Sonata for Two Pianos and Percussion.”

4.5.1 Case Study: Traditional “Row Your Boat”

The following program illustrates how to create a musical canon. It also demonstrates how, through programming, your computer is transformed into a musical instrument that exceeds the capabilities of a single human performer on a traditional instrument. This computer music instrument can render a quite complicated piece of music. Also, unlike other playback environments (e.g., your digital music player), these pieces can be easily modified by making changes in the code. This is very enabling; imagine being able, through the press of a button, to change the musical parameters of a piece (i.e., when a certain voice starts, or which sounds to use to play a particular melody or chords).

The program in this section creates a melody as a round (canon) in three parts. It uses the Phrase.copy() function to create a copy of a musical phrase. This is very useful when you have several musical phrases that differ in small ways. Instead of having to create them all from scratch (which can be time-consuming), you can create one phase and then make copies of it. This way you can modify individual copies any way you like, without affecting the original phrase.

In our example below, the phrases differ in two ways:

  1. The start time (i.e., when they start in the piece) and
  2. The instrument associated with them.

This program also demonstrates how to use functions from the Mod class. As mentioned earlier, classes in Python are one way to organize (modularize) functionality and related code. Below, we use the Mod.transpose() function to move all the pitches in a phrase up or down by a number of chromatic steps. Using a positive number with Mod.transpose() moves the whole phrase up by that number of chromatic steps (semitones), i.e., this number is added to the pitch values. A negative number moves the whole phrase down by that number of chromatic steps, i.e., the number is subtracted from the pitch values.

Notice how comments are used to elucidate or describe the musical process. Again, when you program, it is advisable to first write good comments, which capture your thought process, and then write the corresponding code. This will save you considerable time in the long run.

# rowYourBoat.py
# Demonstrates how to build a musical canon.
from music import *
# Create the necessary musical data
rowYourBoatScore = Score("Row Your Boat", 108.0) # tempo is 108 bpm
flutePart	= Part(FLUTE, 0)	# flute part on channel 0
trumpetPart	= Part(TRUMPET, 1)	# trumpet part on channel 1
clarinetPart	= Part(CLARINET, 2)	# clarinet part on channel 2
themePhrase	= Phrase(0.0)	# theme starts at the beginning
# "Row, row, row your boat gently down the stream"
pitches1	= [C4, C4, C4, D4, E4, E4, D4, E4, F4, G4]
durations1 = [QN, QN, DEN, SN, QN, DEN, SN, DEN, SN, HN]
# "merrily, merrily, merrily, merrily"
pitches2	= [C5, C5, C5, G4, G4, G4, E4, E4, E4, C4, C4, C4]
durations2	= [ENT, ENT, ENT, ENT, ENT, ENT, ENT, ENT, ENT, ENT, ENT, ENT]
# "life is but a dream."
pitches3	= [G4,	F4, E4,	D4, C4]
durations3 = [DEN, SN, DEN, SN, HN]
# add the notes to the theme
themePhrase.addNoteList(pitches1, durations1)
themePhrase.addNoteList(pitches2, durations2)
themePhrase.addNoteList(pitches3, durations3)
# make two new phrases and change start times to make a round
response1Phrase = themePhrase.copy()
response2Phrase = themePhrase.copy()
response1Phrase.setStartTime(4.0)	# start after 4 quarter notes
response2Phrase.setStartTime(8.0)	# start after 8 quarter notes
# play different parts in different registers
Mod.transpose(themePhrase, 12)	# one octave higher
Mod.transpose(response2Phrase, -12)	# one octave lower
# play each phrase twice
Mod.repeat(themePhrase, 2)
Mod.repeat(response1Phrase, 2)
Mod.repeat(response2Phrase, 2)
# add phrases to corresponding parts
flutePart.addPhrase(themePhrase)
trumpetPart.addPhrase(response1Phrase)
clarinetPart.addPhrase(response2Phrase)
# add parts to score
rowYourBoatScore.addPart(flutePart)
rowYourBoatScore.addPart(trumpetPart)
rowYourBoatScore.addPart(clarinetPart)
# play score as MIDI
Play.midi(rowYourBoatScore)
# write score to MIDI file
Write.midi(rowYourBoatScore, "rowYourBoat.mid")

Notice how the comments provide the lyrics — this a helpful way to recognize different melodic lines. Also, notice how comments are used to elucidate or describe the musical process.

4.5.1.1 Exercise

Extend the above code to include a fourth part. This part should start after the third part (with the distance equal to that between the last two parts). Use an instrument of your choice to play this part, and a pitch register of your choice (using Mod.transpose(), as demonstrated in the code above).

4.5.2 Analyzing the Musical Process

The musical process for creating canons is a formalized and well-understood case of transforming a theme and combining it with variations. Studying it will give us insights into, and practice with, capturing a musical process in code. This is the basis for creating arbitrary computer music programs.

As seen in the code above, the steps in creating a canon are as follows:

  1. Create a melodic phrase (theme).
  2. Make copies of that phrase.
  3. Transform the copies of the phrase; in “Row Your Boat” above, we change when phrases start in the piece.
  4. Add each phrase to a different part with its own instrument.

Humans develop processes (or algorithms) for accomplishing important tasks , such as creating a musical canon. As we discussed in Chapter 1, any field of knowledge, from cooking to building houses, to healing people, to gardening, to solving math problems, to designing bridges, to repairing automobiles, to playing games, to making music involves algorithms for achieving tasks within that particular domain.

Definition: An algorithm is a sequence of steps for accomplishing a given task—in our case, a musical task.

We will explore musical algorithms in more detail in Chapter 5. For now let’s examine the interesting sections of “Row Your Boat” code in more detail.

4.5.2.1 Creating Musical Material

The first thing in programming any musical process is to create the necessary musical data objects. The code below initializes a score, the three different parts/instruments, and the theme phrase.

# Create the necessary musical data
rowYourBoatScore = Score("Row Your Boat", 108) # tempo is 108 bpm
flutePart = Part(FLUTE, 0)	# flute part on channel 0
trumpetPart = Part(TRUMPET, 1)	# trumpet part on channel 1
clarinetPart = Part(CLARINET, 2)	# clarinet part on channel 2
themePhrase = Phrase(0.0)	# theme starts at the beginning

The score object is created with a title and tempo. Then three parts are created and set to different instruments and channels. This will allow us to use three instruments to play the round. The phrase themePhrase starts at the beginning of the piece.

The next step is to create the actual notes. As seen in the previous chapter, the music library allows us to enter notes quickly using lists, as follows:

# "Row, row, row your boat gently down the stream"
pitches1 	= [C4, C4, C4, D4, E4, E4, D4, E4, F4, G4]
durations1	= [QN, QN, DEN, SN, QN, DEN, SN, DEN, SN, HN]

The first note is a C4, QN (i.e., see the first element in both the pitches1 and durations1 lists); the second note is also a C4, QN; the third note is a C4, EN; and so on. Again, both lists need to have the same number of elements, otherwise we get an error.

Once we have specified the two lists, we can add them in a phrase using the addNoteList() function of the Phrase object called themePhrase.

themePhrase.addNoteList(pitches1, durations1)

4.5.2.2 Making Copies of Musical Material

To create a canon we need to start the melody again and again with a delay between each entry. In this example, we want a three-part round, so we create three phrases each starting at a different position. The first phrase starts at the beginning of the piece.

themePhrase = Phrase(0.0)	# theme starts at the beginning

After we add a note list to the above phrase, we make copies using the Phrase.copy() function. This allows us to modify the copies in desired ways without affecting the original.

response1Phrase = themePhrase.copy()
response2Phrase = themePhrase.copy()

4.5.2.3 Shifting Musical Material in Time

At this point, response1Phrase and response2Phrase are identical copies of themePhrase, including their start time. To adjust their start time as prescribed by this canon, we use the Phrase.setStartTime() function, which accepts a value indicating the new start time. The start time is in quarter notes (and fractions of them). Again, the beginning of the music is at 0.0 time.

response1Phrase.setStartTime(4.0)	# start after 4 quarter notes
response2Phrase.setStartTime(8.0)	# start after 8 quarter notes

The code above sets response1Phrase to start at the fifth quarter note position, and response2Phrase at the ninth quarter note position.

4.5.2.4 Transposing Musical Material

In order to hear the parts a little more clearly, we set them to different registers (octave ranges) by transposing them. Transposition means shifting a melody up or down in pitch. This can be done easily with the Mod.transpose() function.

Mod.transpose(themePhrase, 12)	# one octave higher
Mod.transpose(response2Phrase, -12)	# one octave lower

Here themePhrase is transposed up one octave (twelve chromatic steps), and response2Phrase transposed down one octave.

4.5.2.5 Combining Music Material

Up to now we have created the score, three parts and three phrases. However, they exist independently (see Figure 4.1).

Figure 4.1

Image of An unorganized collection of music library data objects

An unorganized collection of music library data objects.

We need to combine the musical material into a single score (to create the hierarchical structure shown in Figure. 3.2). This way we can listen to all the music simultaneously, when we play the score, that is, Play.midi(score). We can do this in any order, as long as we put phrases into the appropriate part(s), and the parts into the score.

In the above code, we first put the phrases into the parts. We use the addPhrase() function of the flute part to store the theme in it (themePhrase). We use the same functions of the trumpet and clarinet parts to put in them the first and second responses, respectively.

# add phrases to corresponding parts
flutePart.addPhrase(themePhrase)
trumpetPart.addPhrase(response1Phrase)
clarinetPart.addPhrase(response2Phrase)

Then we store the three parts in the score, using the score’s addPart() function.

# add parts to score
rowYourBoatScore.addPart(flutePart)
rowYourBoatScore.addPart(trumpetPart)
rowYourBoatScore.addPart(clarinetPart)

4.5.2.6 Saving and Playing Musical Material

Finally, we play the score in real time and also save it as a MIDI file:

# play score as MIDI
Play.midi(rowYourBoatScore)
# write score to MIDI file
Write.midi(rowYourBoatScore, "rowYourBoat.mid")

Now it is time to look at a more elaborate example of a musical cannon.

4.5.3 Case Study: J.S. Bach—Goldberg Ground, Canon 1 (BWV 1087)

In 1741, Johann Sebastian Bach (1685–1750), one of the most important composers of all time (and an expert in connecting numbers and music), wrote the Goldberg Variations (BWV 988), for harpsichord. This work consists of an aria and a set of 30 variations, and is an amazing example of the transformation of a theme to create variations.

Then, in 1974 an unknown manuscript was discovered in France, written in Bach’s hand, containing 14 canons on the first eight notes of the Goldberg aria. These canon variations were previously unknown (except for canons 11 and 13). These canons are very important. They encapsulate Bach’s ideas for how music, number, and the universe are all connected together.

Bach did not provide the complete music for these canons. Instead, he specified the theme and then wrote cryptic notations (riddles) for the reader to solve. Solving the riddle unlocked the music by providing the musical process to generate it. Generally, Bach’s canons are constructed by layering copies of the theme that are transformed using one or more of the following rules (canonic devices):

  • Shifting in time
  • Retrograde (reversing the order of notes—horizontal mirroring)
  • Inversion (mirroring the notes around a pivot note—vertical mirroring)
  • Augmentation (stretching the duration of notes, e.g., double their duration)
  • Diminution (shrinking the duration of notes, e.g., halve their duration).

Canon symmetries and rules were so important to Bach that he used them in his personal seal (see Figure 4.2). This seal is characteristic of the ornamental style of the Baroque period and consists of his initials (the letters J, S, and B), their mirror, an interweaving of them (possibly representing his musical work, as a reflection of the symmetries found in nature), and a crown at the top (possibly representing the royal and/or religious context within which this work took place).

Figure 4.2

Image of J. S. Bach’s seal consisting of his initials and a canonic interweaving of them under a crown

J. S. Bach’s seal consisting of his initials and a canonic interweaving of them under a crown.

These canonic rules are implemented, through the music library, as follows:

  • Create a phrase with the melody (theme).
  • Create copies (phrase.copy()) of the original phrase.
  • Use phrase.setStartTime() or Mod.retrograde(), Mod.invert(), or Mod.elongate() to modify each copy.
  • Put resulting phrases into a Part and Score.

The following program demonstrates how to use the Mod functions to “unlock” (or create) the first of these 14 canons. It is built from a theme consisting of eight notes and reversed version (retrograde) played simultaneously. For more information, see (Smith 1996).

# JS_Bach.Canon_1.GoldbergGround.BWV1087.py
#
# This program recreates J.S. Bach's Canon No. 1 of the Fourteen on
# the Goldberg Ground.
#
# This canon is constructed using the Goldberg ground as the subject
# (soggetto) combined with the retrograde of itself.
from music import *
# how many times to repeat the theme
times = 6
# define the data structure
score	= Score("J.S. Bach, Canon 1, Goldberg Ground (BWV1087)", 100)
part	= Part()
voice1	= Phrase(0.0)
# create musical material (soggetto)
pitches	= [G3, FS3, E3, D3, B2, C3, D3, G2]
durations	= [QN, QN, QN, QN, QN, QN, QN, QN]
voice1.addNoteList(pitches, durations)
# create 2nd voice
voice2 = voice1.copy()
Mod. retrograde(voice2)	# follower is retrograde of leader
# combine musical material
part.addPhrase(voice1)
part.addPhrase(voice2)
score.addPart(part)
# repeat canon as desired
Mod.repeat(score, times)
# write score to a MIDI file
Write. midi(score, "JS_Bach.Canon_1.GoldbergGround.BWV1087.mid")

4.5.4 Case Study: Trias Harmonica canon (BWV 1072)

J.S. Bach (1685–1750) created many beautiful canons (see Figure 4.3). We present the implementation of another one, namely, the Trias Harmonica (BWV 1072). Like all canons, the Trias Harmonica involves repetition and layering of melodic phrases; it consists of two parts with four separate voices each—a total of eight overlaid phrases.

Figure 4.3

Image of J. S. Bach holding the Canon triplex a 6 vocibus, BWV 1087, one of the goldberg canons

J. S. Bach holding the Canon triplex a 6 vocibus, BWV 1087, one of the goldberg canons (painted by Haussmann in 1746).

This canon was particularly significant to Bach. The name trias (“τριάς”, or triad) refers to the triunity of the divine in the Christian tradition, that is, “three in one and one in three” (Bach was a devout Lutheran). The Trias Harmonica canon interweaves a major triad (C4, E4, G4—representing the divine) with the minor triad (D4, F4, A4—representing man). Also, it uses a dotted quarter note (i.e., 1.5) as the duration for the major triad, and an eighth note (i.e., 0.5) for the minor triad, emphasizing the 1/3 relationship between the trinity and man (i.e., the son in Christian theology). It is believed that here Bach attempted to musically represent the harmony he believed existed between the natural and spiritual world (Smith 1996).

# JS_Bach.Canon.TriasHarmonica.BWV1072.py
#
# This program creates J.S. Bach's 'Trias Harmonica' BWV 1072 canon.
#
# This canon is constructed using two parts (choirs), each consisting
# of four voices. The first part's voices use the original theme,
# each separated by a half-note delay. The second part's voices use 
# the inverted theme delayed by a quarter note, each separated by
# a half-note delay.
#
from music import *
# define the theme (for choir 1)
pitches1  = [C4, D4, E4, F4, G4, F4, E4, D4]
durations1 = [DQN, EN, DQN, EN, DQN, EN, DQN, EN]
# define the inverted theme (for choir 2)
pitches2  = [G4, F4, E4, D4, C4, D4, E4, F4]
durations2 = [DQN, EN, DQN, EN, DQN, EN, DQN, EN]
# how many times to repeat the theme
times = 8
# choir 1 - 4 voices separated by half note
choir1 = Part()
voice1 = Phrase(0.0)
voice1.addNoteList(pitches1, durations1)
Mod.repeat(voice1, times)	# repeat a number of times
voice1.addNote(C4, DQN)	# add final note
voice2 = voice1.copy()	# voice 2 is a copy of voice 1
voice2.setStartTime(HN)	# separated by half note
voice3 = voice1.copy()	# voice 3 is a copy of voice 1
voice3.setStartTime(HN*2)	# separated by two half notes
voice4 = voice1.copy()	# voice 4 is a copy of voice 1
voice3.setStartTime(HN*3)	# separated by three half notes
choir1.addPhrase(voice1)
choir1.addPhrase(voice2)
choir1.addPhrase(voice3)
choir1.addPhrase(voice4)
# choir 2 - 4 voices inverted, delayed by quarter note,
# separated by a half note.
choir2 = Part()
voice5 = Phrase(QN)	# delayed by quarter note
voice5.addNoteList(pitches2, durations2)
Mod.repeat(voice5, times)	# repeat a number of times
voice5.addNote(G4, DQN)	# add final note
voice6 = voice5.copy()	# voice 6 is a copy of voice 5
voice6.setStartTime(QN + HN)	# separated by half note
voice7 = voice5.copy()	# voice 7 is a copy of voice 5
voice7.setStartTime(QN + HN*2)	# separated by two half notes
voice8 = voice5.copy()	# voice 8 is a copy of voice 5
voice8.setStartTime(QN + HN*3)	# separated by three half notes
choir2.addPhrase(voice5)
choir2.addPhrase(voice6)
choir2.addPhrase(voice7)
choir2.addPhrase(voice8)
# score
canon = Score("J.S. Bach, Trias Harmonica (BWV 1072)", 100)
canon.addPart(choir1)
canon.addPart(choir2)
# write it to a MIDI file
Write.midi(canon, "JS_Bach.Canon.TriasHarmonica.BWV1072.mid")

4.5.5 Exercises

Write code that reconstructs more J. S. Bach canons:

  1. J. S. Bach’s “Canon a 2. perpetuus” (BWV 1075).
  2. J. S. Bach’s “Canon Super Fa Mi a 7 Post Tempus Musicus” (BWV 1078).
  3. Find additional canons online (e.g., Smith 1996).

4.5.6 Case Study: Arvo Pärt—“Cantus in Memoriam” (1977)

Arvo Pärt’s “Cantus in Memoriam Benjamin Britten” is a minimalistically composed, yet very powerful piece for string orchestra and bell, based on Pärt’s tintinnabuli style. It was written to mourn the passing of Benjamin Britten, an English composer, whom Pärt considered a kindred spirit. Pärt, being in Estonia at the time (on the wrong side of the Iron Curtain), never met Britten, who died in England in 1976.

This version of the piece is slightly simplified compared to the original score. It introduces a single voice descending in stepwise motion the A aeolian (natural minor) scale. This voice is repeated at half tempo several times, creating beautiful harmonic combinations stemming from all permutations of aeolian-scale notes.

Although Pärt’s score lists all the notes spelled out, below we construct the piece using Bach’s canon approach. In other words, we state the theme and apply canonic rules (copying, shifting in time, and elongation) to generate the final piece. This implementation allows us to better appreciate Arvo Pärt’s compositional style (as reflected in this piece); also it may provide inspiration for things to try in your own music composition explorations.

# ArvoPart.CantusInMemoriam.py
#
# Recreates a variation of Arvo Part's "Cantus in Memoriam Benjamin 
# Britten" (1977) for string orchestra and bell, using Mod functions.
from music import *
# musical parameters
repetitions = 12	# length of piece
tempo = 112		# tempo of piece
bar = WN+HN		# length of a measure
# create musical data structure
cantusScore = Score("Cantus in Memoriam Benjamin Britten", tempo)
bellPart = Part(TUBULAR_BELLS, 0)
violinPart = Part(VIOLIN, 1)
# bell
bellPitches  = [REST, A4, REST, REST, A4, REST, REST, A4]
bellDurations = [bar/2, bar/2, bar, bar/2, bar/2, bar, bar/2, bar/2]
bellPhrase = Phrase(0.0)
bellPhrase.addNoteList(bellPitches, bellDurations)
bellPart.addPhrase(bellPhrase)
# violin - define descending aeolian scale and rhythms
pitches = [A5, G5, F5, E5, D5, C5, B4, A4]
durations = [HN, QN, HN, QN, HN, QN, HN, QN]
# violin 1
violin1Phrase = Phrase(bar * 6.5) # start after 6 and 1/2 measures
violin1Phrase.addNoteList(pitches, durations)
# violin 2
violin2Phrase = violin1Phrase.copy()
violin2Phrase.setStartTime(bar * 7.0)	# start after 7 measures
Mod.elongate(violin2Phrase, 2.0)	# double durations
Mod.transpose(violin2Phrase, -12)	# an octave lower
# violin 3
violin3Phrase = violin2Phrase.copy()
violin3Phrase.setStartTime(bar * 8.0)	# start after 8 measures
Mod.elongate(violin3Phrase, 2.0)	# double durations
Mod.transpose(violin3Phrase, -12)	# an octave lower
# violin 4
violin4Phrase = violin3Phrase.copy()
violin4Phrase.setStartTime(bar * 10.0)	# start after 10 measures
Mod.elongate(violin4Phrase, 2.0)	# double durations
Mod.transpose(violin4Phrase, -12)	# an octave lower
# repeat phrases enough times
Mod.repeat(violin1Phrase, 8 * repetitions)
Mod.repeat(violin2Phrase, 4 * repetitions)
Mod.repeat(violin3Phrase, 2 * repetitions)
Mod.repeat(violin4Phrase, repetitions)
# violin part
violinPart.addPhrase(violin1Phrase)
violinPart.addPhrase(violin2Phrase)
violinPart.addPhrase(violin3Phrase)
violinPart.addPhrase(violin4Phrase)
# score
cantusScore.addPart(bellPart)
cantusScore.addPart(violinPart)
# fade in
Mod.fadeIn(cantusScore, WN * repetitions)
# view and write
View.sketch(cantusScore)
Play.midi(cantusScore)
Wr ite.midi (cantusScore, "ArvoPart.CantusInMemoriam.mid")

Notice how the above is similar to the canons we have seen. Also, notice the introduction of function View.sketch(), which generates a visual representation of the musical material. More about this and other View functions after the next exercise. For now, observe the visual structure of the piece over time. Seasoned composers work at the macro level, that is, they first make a high-level, visual sketch of a piece before they decide the smaller-scale details. Having seen this structure, can you also hear it in the piece?

4.5.7 Exercises

  1. Create a variation of the above piece using the C major scale.
  2. Modify the code so that the voices move upwards.
  3. Instead of starting with the fastest moving voice, start with the slowest moving one. Then add the faster voices, while keeping relative proportions and start times.
  4. The musical outcome of (3) may remind you one of the pieces we have already studied. Which one and why? What are the common elements? Explore the history of the two composers and hypothesize on how this creative connection may have come about.

4.6 Viewing Music

The case study above demonstrates another music library class, namely, View. This class contains several functions which help visualize musical material. The View functions work with Phrase, Part, and Score objects. There are several different views available, namely, View.notation(), View.pianoRoll(), View.internal(), View.sketch(), each with its own benefits and limitations.

4.6.1 Notation Display

The View.notation() function provides a limited notational facility for displaying musical material in Western notation. For example, to view the notation of a phrase stored in variable phrase, you would use View.notation(phrase). This function will select a treble, bass, or piano staff, as required, to display the music. The time signature will default to 4/4 and the key to C major, unless otherwise specified (e.g., see Figure 4.4). Accidentals (black notes on the piano) will be shown with a sharp (#) or flat () symbol before them.

Figure 4.4

Image of Notation output from the “Theme and Variations” program

Notation output from the “Theme and Variations” program (seen later in the chapter).

An interesting feature of this view is that it allows you to edit the music material interactively. You can move notes by dragging the note heads. Also, you can add new notes by clicking on an empty place on the staff. Although it is not a full-blown music notation editor, View.notation() allows you to do some exploration and experimentation.§ Once modified, the edited musical material may be saved as a MIDI file through the available menus.

One possibility is to create initial musical material through a Python program. Then use View.notation() to experiment with changes. If you like the outcome, you can save the modified material to a MIDI file and use a full-blown editor to finalize the piece.

It is important to note that View.notation() cannot save these modifications back in your Python code. If you would like your code to generate the modified material, you will have to make these changes manually.

4.6.2 Piano Roll Display

The View.pianoRoll() function displays music in a piano roll view. This notation resembles the piano rolls used in player pianos, that is, long strips of paper with holes where notes are meant to be played. By loading a piano roll into a player piano, the piano would automatically play these notes.

In the output produced by View.pianoRoll() notes appear as rectangles on a staff. The dark horizontal lines make up the standard treble and bass staffs, while the gray staffs indicate upper treble and lower bass ranges two octaves away. Accidentals (black notes on the piano) are shown with a sharp (#) sign in front, just as on the notation display. Phrase boundaries are drawn as rectangles around note groups, and notes in each part are shown in the same color. The depth of color indicates the dynamic level of the note, darker shades for louder notes. The ruler along the bottom displays the timeline and can be used to adjust the time scale by dragging. Quarter note position numbers are displayed when ruler size permits (Figure 4.5).

Figure 4.5

Image of Piano roll output from the “Theme and Variations” program

Piano roll output from the “Theme and Variations” program.

4.6.3 Internal Values Display

While a visual display of the score provides a graphical overview of the score, sometimes it is useful to see the precise data values. This is done with the View.internal() function. It outputs a textual list of the important values of the musical material, organized in terms of score, parts, phrases, and notes (as provided). This output can be especially handy for debugging code, if you are getting unexpected musical results (see Figure 4.6).

Figure 4.6

Image of Internal values output (excerpt) from “Theme and Variations” program

Internal values output (excerpt) from “Theme and Variations” program.

4.6.4 Sketch Display

The last display provided by the View class is the View.sketch() function. This function provides a graphical representation that resembles a piano roll, except that individual notes are drawn with thin lines. What makes the display particularly interesting is that you can draw music with the mouse (by clicking on the display and dragging). The type of music generated is very particular given the constraints and affordances of the sketch interface. Similarly to all other graphical notations, the modified musical material can be saved into a MIDI file, for later processing, if desired (see Figure 4.7).

Figure 4.7

Image of Sketch output from the “Theme and Variations” program

Sketch output from the “Theme and Variations” program.

4.6.5 Exercises

Write a program that opens up a blank sketch display. Experiment drawing various lines and hearing the result. Try to produce an interesting music composition this way. Save the musical material into a MIDI file. Write a second program that reads in this MIDI file using the following:

score = Score()
Read.midi(score, "nameOfMidiFile.mid")

where “nameOfMidiFile.mid” is the name of the MIDI file containing your music material generated through the Sketch display. Explore the application of various Mod functions to this score, such as Mod.randomize() and Mod.quantize(), to transform this musical material in interesting ways.

4.7 The Software Development Process

Just as musical composition is a creative act, so too is software development. Both also benefit from systematic planning and processes. The lifecycle of a computer program starts from when we come up with the original idea and extends to designing the algorithm, to writing some code, to testing and refining it, to using the program for its intended task, to updating the program to serve new needs, and to reusing some of the code in newer programs. Most programs, once written, are (re)used in some way; they are rarely thrown away. Keep this in mind as you embark on your software development journey.

The software development process consists mainly of design, implementation, testing, and documentation. These steps are not necessarily sequential. As in most creative processes, they are interwoven into the lifecycle of a program.

4.7.1 Design

An early phase in developing software is to identify what it is we are building. This can be a simple statement or a quite elaborate description. It is OK to try out some ideas in code first, but to make significant progress a software developer needs to use a piece of paper (or a whiteboard) to draw out ideas and steps required to achieve these ideas. The following maxim captures this:

Advice: Two hours of design can save you 20 hours of coding.

Computers need to be told what to do; it is our responsibility to first identify these steps and then translate them to a language (such as Python) that the computer understands. Although at times we might feel otherwise (and it is this mystification that makes computers so exciting), at the end of the day, computers are just following instructions; they have no creative intent. Computer programs reflect the creativity of the software developer and user.

Fact: A software developer is like a music composer.

When programming and composing are combined (i.e., to write software for algorithmic music), the challenge for the musician is to write instructions that lead to interesting and expressive music. Musical algorithms can describe how each of the musical elements is specified and varied as the piece proceeds. This can include control over the pitch, duration, and loudness of notes, the timbre of sounds, the use of structural features such as repetition and variation, as well as tempo, volume, balance, and so on.

4.7.2 Implementation

Once we have come up with the steps (or algorithm) to create a musical artifact, we can then translate it to a programming language. In this book we use Python (a textual programming language which is simple and thus great for beginners). We have extended this language with several libraries for generating sounds and music, as well as for processing images, and for creating graphical user interfaces. These activities are necessary for modern music making using computers. These libraries will be presented in later chapters.

4.7.3 Testing

Once some code has been written, it can be tested to see if it works as intended. This is very important. A program should not only run (i.e., without crashing) it also needs to perform the intended task precisely. If it does not, we modify the design of the program until we get it to work appropriately.

Normally, there are two types of programming errors that testing reveals:

  • Syntax errors
  • Logical errors

Syntax errors are usually caused by simple mistakes, such as typos. They result in a “program crash”—that is, the program does not run or terminates unexpectedly, producing a (usually cryptic) error message, such as the following:

Traceback (most recent call last):
 File "pentatonicMelody3.py", line 21, in <module>
  for i in range(numnotes - 2):
NameError: name 'numnotes' is not defined

Most syntax errors are easy to fix. To do so, you should read error messages backwards, that is, starting from the bottom line. For example, the above error indicates that a word you typed in your program is not recognized (i.e., “NameError”). The message indicates that this particular word occurs on line 21 in your program. Did you type the word correctly?

Fact: Once you learn how to read error messages, syntax errors are easy to fix.

On the other hand, logical errors make a program produce wrong results or not work as intended. For example, a design error in the musical algorithm above would be to use the wrong musical scale. Although the program would run successfully (i.e., without any error messages generated by the computer), the musical outcome would be incorrect.

Design errors are hard to discover, unless we test our programs often and throughout the software development process.

Advice: Test your code sooner rather than later and as often as possible.

Seasoned programmers know that logical errors cost very little to fix, if caught early. Python makes it easy to write short excerpts of code and test them. It is advisable to develop programs incrementally. Write a little code and test it. Then write some more and test it.

4.7.4 Documentation—Good Style and Comments

Every programming language allows programmers to include comments inside their code. Comments are phrases written in human language (e.g., English) to explain a particular idea or task being performed by a part of the code. Comments are intended for humans and are ignored by the computer.

In Python comments are denoted with the “#” character—anything between “#” and the end of the line is ignored by the computer. We use this convention to capture our thoughts when they are fresh as we are coding, so that we can remember later essential ideas about our code.

Advice: If you cannot phrase it in English (or other native tongue), you cannot code it.

Fact: Seasoned programmers comment before they code.

Seasoned programmers will first write comments describing the desired goal and then translate those comments to Python code. (Some will even consider how to test their code before writing it.) Although this practice may appear counterproductive, it can actually save time in the long run.

4.8 Case Study: Computer-Aided Music Composition

For centuries musicians have taken existing music and created their own variations of it. Since the 1950s, researchers have been exploring how to utilize computers in this activity. One great example is David Cope’s EMI (Experiments in Musical Intelligence) software, which has analyzed and produced musical works in the style of various composers (Cope 2001; 2013). Cope’s fascinating research into what constitutes musical creativity and how much of it can be algorithmically encoded has produced a wide variety of musical pieces, some of which have been performed by orchestras and recorded. His latest program, called Emily Howell, has been used to produce two commercially available CDs.

The following program demonstrates how various Mod functions may be used to harness the computer’s ability to create novel music from existing material. Although very simplistic compared to David Cope’s EMI, this program demonstrates how to begin developing computer-aided composition tools to help with writer’s block, or to inspire new melodic or harmonic explorations.

In this case study, we start with a theme provided by a human composer. Each musical variation algorithmically (programmatically) develops the material from the original theme. The goal here is not to create a near-perfect musical piece—that would be difficult to do with what we know so far.** Instead, we aim for a piece with reasonable musicality—a piece that can be used to explore musical possibilities, and get new ideas. To do so, we try to make the variations

  1. subtle enough so that the relationship with the original is evident, but also
  2. novel enough that they are interesting and surprising.

In this case study three variations, var1, var2, and var3, are created by copying the original theme and applying Mod functions. The last variation, var4, is an exact copy of the original.

# themeAndVariations.py
#
# Demonstrates how to automatically develop musical material
# using a theme and transforming it through Mod functions.
#
# Here we start with the theme, continue with a few interesting
# variations, and close with the theme for recapitulation.
from music import *
# create theme
pitches = (C4, E4, G4, A4, B4, A4, B4, C5]
durations = [EN, EN, QN, SN, SN, SN, SN, QN]
theme = Phrase()
theme.addNoteList(pitches, durations)
# variation 1
# vary all pitches in theme, but keep the same
# rhythm pattern (for stability)
var1 = theme.copy()	# preserve original (make a copy)
Mod.randomize(var1, 3)	# randomize each pitch (max of +/- 3)
	# (later we force them into the scale)
# variation 2
# slow down theme, and change two pitches using
# a random value from within the theme range
var2 = theme.copy()
Mod.elongate(var2, 2.0)	# double its time length
Mod.mutate(var2)	# change one pitch and duration value
Mod.mutate(var2)	# and another (could be the same)
# variation 3
# reverse the theme, and lower it one octave
var3 = theme.copy()
Mod.retrograde(var3)	# reverse notes
Mod.transpose(var3, -12)	# lower one octave
# recapitulation
# repeat the theme for closing (i.e., return home)
var4 = theme.copy()	# we need a copy (a phrase can be added
	# to a part only once)
# add theme and variations in the right order (since we
# didn't specify start times, they will play in sequence)
part = Part()
part.addPhrase(theme)
part.addPhrase(var1)
part.addPhrase(var2)
part.addPhrase(var3)
part.addPhrase(var4)
# now, fix all notes to be in the C major scale,
# and with durations that line up with SN intervals
Mod.quantize(part, SN, MAJOR_SCALE, 0)
# provide alternate views
View.pianoRoll(part)
View.internal(part)
View.sketch(part)
M od.consolidate(part) # merge phrases into one phrase, so that...
Vie w.notation(part) #...notate() can display all the notes
# and play
Play.midi(part)

Notice how each variation has a distinctive character by being transformed in particular and unique ways.

Fact: By combining Mod functions in creative, yet well-designed ways, you can create processes for transforming musical material to explore compositional spaces. These processes may involve chance, so every time you run them, you get novel material.

In the above program, the first variation changes all the pitches in the theme by a random interval of +/–3; however, it retains the same note durations, thus preserving the rhythm pattern. This introduces change, but also provides some stability, to support flow. Notice how we make a copy of the theme before modifying it, otherwise the Mod functions would be changing the original, which is something we do not want.

The second variation slows down the theme and makes a couple of pitch and duration changes. The third plays the theme backwards and one octave lower. The fourth variation is really a recapitulation—a straight copy of the theme, to “return home,” so to speak. Recapitulations are important in music to provide a sense of closure.

Another thing to notice is that (as stated in Chapter 3), when phrases do not have explicit start times, they play back sequentially in the order added to the part. If you use explicit start times, you specify precisely when they play back. That is a simple way to create overlapping phrases. When providing explicit start times for phrases, the order you add them to a part is inconsequential.

After the theme and variations are added into the part, we use Mod.quantize() to “straighten out” any excessive rhythmic or pitch oddities that might have been introduced by the transformation process. This compositional approach of changing (modifying) and constraining (quantizing) reflects two sides of creative processes that always need to be kept in balance, novelty and familiarity.††

4.8.1 Exercise

Starting with a theme, write various programs like the above to explore a new compositional idea. In addition to transforming melodies, explore ways to transform harmonies, for example, chord progressions. Results from this activity may evolve into a set of tools to assist you in your compositional practice. Your imagination is the limit.

4.9 Summary

This chapter presented patterns of musical structure and organization. It discussed minimalism and musical canons, and showed us how to transform musical material using Mod functions, such as transpose(), elongate(), and repeat(). We learned how to recreate well-known musical works, by transcribing only a small part of the work, namely, the theme, and working from the theme to generate the remaining work, through well-defined algorithmic processes (canonic devices). This makes us realize that, although modern computers are a recent development in the history of music (and humanity), well-defined algorithmic processes have existed and benefited musical (and other) creators throughout history. J.S. Bach was one of the early masters in exploring such material and processes.

Additionally, we learned different ways to view musical material, provided by the music library, namely, as Western notation, piano roll, textual data, and sketch view. Finally, we began discussing the software development process—a high-level algorithm for designing, implementing, and evaluating (i.e., testing) a program. The objective here is to learn how to develop better programs, more efficiently, and thus better utilize our creative time.


* In a way, this mimics the simple processes of nature and how these (through repetition and transformation) generate the complex world we live in.

It should be noted that there are some exceptionally skilled pianists who can play both piano parts in Steve Reich’s “Piano Phase” at the same time —one part per hand.

All canons involve some form of systematic transformation of copies of the musical theme. Earlier in the chapter, we saw the Mod class, which gives us a wide variety of systematic transformation functions to potentially use with canon construction.

§ For anything other than a few notes, you will be better served by regular music notation editors, such as Noteflight and Sibelius.

One could think of player pianos as programmable music boxes. The piano roll provided the instructions on what music to play and when. If you think about it, this is very similar to the function of your Python program, that is, your programs are like elaborate piano rolls for your computer to play. Additionally, these programs allow for functionality that piano rolls cannot possibly support (such as selection, iteration, randomness, interaction—as we will see soon).

** Developing more intelligent music composition programs can be accomplished using more advanced methods from Artificial Intelligence and Computational Creativity, which is beyond the scope of this book.

†† The same principle (of balancing novelty and familiarity) is applied to variation 1 (by keeping the same durations) and with repeating the opening theme at the end of the piece.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset