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.
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. More information is provided in the reference textbook.
This code sample (Ch. 4, p. 94) createsSteve Reich’s “Piano Phase”, a minimalist piece for two pianos involving tempo differences and repetition. 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# Plays Steve Reich's minimalist piece, Piano Phase (1967).frommusicimport*pianoPart=Part(PIANO,0)# create piano partphrase1=Phrase(0.0)# create two phrasesphrase2=Phrase(0.0)# write music in a convenient waypitchList=[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 phrasesphrase1.addNoteList(pitchList,durationList)phrase2.addNoteList(pitchList,durationList)Mod.repeat(phrase1,41)# repeat first phrase 41 timesMod.repeat(phrase2,41)# repeat second phrase 41 timesphrase1.setTempo(100.0)# set tempo to 100 beats-per-minutephrase2.setTempo(100.5)# set tempo to 100.5 beats-per-minutepianoPart.addPhrase(phrase1)# add phrases to partpianoPart.addPhrase(phrase2)Play.midi(pianoPart)# play music
It plays this sound:
A Variation
Here is a variation of this piece utilizing more Mod functions and adding a bass voice.
It plays this sound:
Create a simple musical canon, “Row Your Boat”
This code sample (Ch. 4, p. 99) demonstrates how to create a musical canon.
# rowYourBoat.py# Demonstrates how to build a musical canon.frommusicimport*# Create the necessary musical datarowYourBoatScore=Score("Row Your Boat",108.0)# tempo is 108 bpmflutePart=Part(FLUTE,0)# flute part on channel 0trumpetPart=Part(TRUMPET,1)# trumpet part on channel 1clarinetPart=Part(CLARINET,2)# clarinet part on channel 2themePhrase=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 themethemePhrase.addNoteList(pitches1,durations1)themePhrase.addNoteList(pitches2,durations2)themePhrase.addNoteList(pitches3,durations3)# make two new phrases and change start times to make a roundresponse1Phrase=themePhrase.copy()response2Phrase=themePhrase.copy()response1Phrase.setStartTime(4.0)# start after 4 quarter notesresponse2Phrase.setStartTime(8.0)# start after 8 quarter notes# play different parts in different registersMod.transpose(themePhrase,12)# one octave higherMod.transpose(response2Phrase,-12)# one octave lower# play each phrase twiceMod.repeat(themePhrase,2)Mod.repeat(response1Phrase,2)Mod.repeat(response2Phrase,2)# add phrases to corresponding partsflutePart.addPhrase(themePhrase)trumpetPart.addPhrase(response1Phrase)clarinetPart.addPhrase(response2Phrase)# add parts to scorerowYourBoatScore.addPart(flutePart)rowYourBoatScore.addPart(trumpetPart)rowYourBoatScore.addPart(clarinetPart)# play scorePlay.midi(rowYourBoatScore)
It plays this sound:
Create J.S. Bach’s Canon No. 1 on the Goldberg Ground (BWV 1087)
In 1741, Johann Sebastian Bach (1685 – 1750) wrote the Goldberg Variations (BWV 988) for harpsichord. In 1974 an unknown manuscript was discovered, written in Bach’s hand, containing 14 canons on the first eight notes of the Goldberg aria.
The following program (Ch. 4, p. 106) demonstrates how to use Mod functions to create the first of these 14 canons. It is built from a theme consisting of eight notes and reversed version (retrograde) played simultaneously.
# JS_Bach.Canon_1.GoldbergGround.BWV1087.py## This program (re)creates 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.#frommusicimport*# how many times to repeat the themetimes=6# define the data structurescore=Score("J.S. Bach, Canon 1, Goldberg Ground (BWV1087)",100)part=Part()voice1=Phrase(0.0)# create musical material (soggetto)pitches=[G3,F3,E3,D3,B2,C3,D3,G2]rhythms=[QN,QN,QN,QN,QN,QN,QN,QN]voice1.addNoteList(pitches,rhythms)# create 2nd voicevoice2=voice1.copy()Mod.retrograde(voice2)# follower is retrograde of leader# combine musical materialpart.addPhrase(voice1)part.addPhrase(voice2)score.addPart(part)# repeat canon as desiredMod.repeat(score,times)# play score and write it to a MIDI filePlay.midi(score)Write.midi(score,"JS_Bach.Canon_1.GoldbergGround.BWV1087.mid")
This code sample (Ch. 4, p. 108) creates the Trias Harmonica canon (BWV 1072). The Trias Harmonica consists of two parts with four separate voices each – a total of 8 overlaid phrases.
# 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.#frommusicimport*# 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 themetimes=8# choir 1 - 4 voices separated by half notechoir1=Part()voice1=Phrase(0.0)voice1.addNoteList(pitches1,durations1)Mod.repeat(voice1,times)# repeat a number of timesvoice1.addNote(C4,DQN)# add final notevoice2=voice1.copy()# voice 2 is a copy of voice 1voice2.setStartTime(HN)# separated by half notevoice3=voice1.copy()# voice 3 is a copy of voice 1voice3.setStartTime(HN*2)# separated by two half notesvoice4=voice1.copy()# voice 4 is a copy of voice 1voice4.setStartTime(HN*3)# separated by three half noteschoir1.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 notevoice5.addNoteList(pitches2,durations2)Mod.repeat(voice5,times)# repeat a number of timesvoice5.addNote(G4,DQN)# add final notevoice6=voice5.copy()# voice 6 is a copy of voice 5voice6.setStartTime(QN+HN)# separated by half notevoice7=voice5.copy()# voice 7 is a copy of voice 5voice7.setStartTime(QN+HN*2)# separated by two half notesvoice8=voice5.copy()# voice 8 is a copy of voice 5voice8.setStartTime(QN+HN*3)# separated by three half notechoir2.addPhrase(voice5)choir2.addPhrase(voice6)choir2.addPhrase(voice7)choir2.addPhrase(voice8)# scorecanon=Score("J.S. Bach, Trias Harmonica (BWV 1072)",100)canon.addPart(choir1)canon.addPart(choir2)# play score, and write it to a MIDI filePlay.midi(canon)Write.midi(canon,"JS_Bach.Canon.TriasHarmonica.BWV1072.mid")
It plays this sound:
Create Arvo Part’s “Cantus in Memoriam Benjamin Britten” (1977)
This code sample (Ch. 4, p. 110) creates Arvo Pärt’s “Cantus in Memoriam Benjamin Britten”. It creates a single voice descending in stepwise motion the A natural minor scale. This voice is repeated at half tempo several times, creating beautiful harmonic combinations stemming from all permutations of aeolian-scale notes. This is a slightly simplified version of the original piece.
# ArvoPart.CantusInMemoriam.py## Recreates a variation of Arvo Part's "Cantus in Memoriam Benjamin# Britten" (1977) for string orchestra and bell, using Mod functions.frommusicimport*# musical parametersrepetitions=2# length of piecetempo=112# tempo of piecebar=WN+HN# length of a measure# create musical data structurecantusScore=Score("Cantus in Memoriam Benjamin Britten",tempo)bellPart=Part(TUBULAR_BELLS,0)violinPart=Part(VIOLIN,1)# bellbellPitches=[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 rhythmspitches=[A5,G5,F5,E5,D5,C5,B4,A4]durations=[HN,QN,HN,QN,HN,QN,HN,QN]# violin 1violin1Phrase=Phrase(bar*6.5)# start after 6 and 1/2 measuresviolin1Phrase.addNoteList(pitches,durations)# violin 2violin2Phrase=violin1Phrase.copy()violin2Phrase.setStartTime(bar*7.0)# start after 7 measuresMod.elongate(violin2Phrase,2.0)# double durationsMod.transpose(violin2Phrase,-12)# an octave lower# violin 3violin3Phrase=violin2Phrase.copy()violin3Phrase.setStartTime(bar*8.0)# start after 8 measuresMod.elongate(violin3Phrase,2.0)# double durationsMod.transpose(violin3Phrase,-12)# an octave lower# violin 4violin4Phrase=violin3Phrase.copy()violin4Phrase.setStartTime(bar*10.0)# start after 10 measuresMod.elongate(violin4Phrase,2.0)# double durationsMod.transpose(violin4Phrase,-12)# an octave lower# repeat phrases enough timesMod.repeat(violin1Phrase,8*repetitions)Mod.repeat(violin2Phrase,4*repetitions)Mod.repeat(violin3Phrase,2*repetitions)Mod.repeat(violin4Phrase,repetitions)# violin partviolinPart.addPhrase(violin1Phrase)violinPart.addPhrase(violin2Phrase)violinPart.addPhrase(violin3Phrase)violinPart.addPhrase(violin4Phrase)# scorecantusScore.addPart(bellPart)cantusScore.addPart(violinPart)# fade in, and fade outMod.fadeIn(cantusScore,WN)Mod.fadeOut(cantusScore,WN*12)# view, play, and writeView.sketch(cantusScore)Play.midi(cantusScore)Write.midi(cantusScore,"ArvoPart.CantusInMemoriam.mid")
It plays this sound:
Create variations automatically from a theme
The following program (Ch. 4, p. 121) demonstrates how to use various Mod functions to create novel music from existing material. For simplicity, this aims for a piece with reasonable (but not perfect) musicality – a piece that can be used to explore musical possibilities, and get new ideas. Since randomness is involved, every time this program runs will create new variations (some better than others).
# 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.frommusicimport*# create themepitches=[C4,E4,G4,A4,B4,A4,B4,C5]rhythms=[EN,EN,QN,SN,SN,SN,SN,QN]theme=Phrase()theme.addNoteList(pitches,rhythms)# variation 1# vary all pitches in theme, but keep the same# rhythmic 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 rangevar2=theme.copy()Mod.elongate(var2,2.0)# double its time lengthMod.mutate(var2)# change one pitch and rhythm valueMod.mutate(var2)# and another (could be the same)# variation 3# reverse the theme, and lower it one octavevar3=theme.copy()Mod.retrograde(var3)# reverse notesMod.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 rhythm values that line up with SN intervalsMod.quantize(part,SN,MAJOR_SCALE,0)# provide alternate viewsView.pianoRoll(part)View.internal(part)View.sketch(part)Mod.consolidate(part)# merge phrases into one phrase, so that...View.notate(part)# ...notate() can display all the notes# and playPlay.midi(part)