Mozart Dice generated Waltz: revisited with Sonic Pi

Back in August 2013 I published an article on this blog detailing a program written in Python which played both the Minuet and Contredanses generated by a Dice Throwing game that Mozart devised to compose his music.
In essence, a pair of dice are thrown 16 times, and the sum of the two dice scores are used to select a bar number from a lookup table. This process is repeated 16 times, selecting the 16 bars used to constitute either the walz or the contredanse, a different lookup table and set of bars being used for these two cases. In the previous article, based on an original article by Martin Tarenskeen, I added the contredanse section, and adjusted various aspects of the program to suit the Raspberry Pi environment. A Python script used a lookup array to generate a text file, which was the source file for a musical engraving program called lilypond, which is available on the Pi, and this produced an image of the music, together with a midi file which was played using the program Timidity.

In this new article, the simulated dice throwing, and the music audio is produced using a Sonic Pi program. The program is quite long, as there are 176 bars to be specified in total, and each requires entries in four separate arrays. One to hold the right hand notes, a second the duration of these notes, and a further two doing the same for the left hand part. Sonic Pi has a built in limitation which means that the resulting program is too large to play on the Mac OSX version of the program, although happily it does play OK on the Raspberry Pi version, and also works on the Windows PC and Linux (Ubuntu) versions. However, the article assumes that you will use it on a PI, as in that case you can use the additional features described to produce a copy of the printed music as well.

The first part of the program generates the choices of the bars to be used.

use_random_seed(6470 )
#w is lookup table Mozart used to choose bar from dice scores
w=[[96, 22, 141, 41, 105, 122, 11, 30, 70, 121, 26, 9, 112, 49, 109, 14],[32, 6, 128, 63, 146, 46, 134, 81, 117, 39, 126, 56, 174, 18, 116, 83],[69, 95, 158, 13, 153, 55, 110, 24, 66, 139, 15, 132, 73, 58, 145, 79],[40, 17, 113, 85, 161, 2, 159, 100, 90, 176, 7, 34, 67, 160, 52, 170],[148, 74, 163, 45, 80, 97, 36, 107, 25, 143, 64, 125, 76, 136, 1, 93],[104, 157, 27, 167, 154, 68, 118, 91, 138, 71, 150, 29, 101, 162, 23, 151],[152, 60, 171, 53, 99, 133, 21, 127, 16, 155, 57, 175, 43, 168, 89, 172],[119, 84, 114, 50, 140, 86, 169, 94, 120, 88, 48, 166, 51, 115, 72, 111],[98, 142, 42, 156, 75, 129, 62, 123, 65, 77, 19, 82, 137, 38, 149, 8],[3, 87, 165, 61, 135, 47, 147, 33, 102, 4, 31, 164, 144, 59, 173, 78],[54, 130, 10, 103, 28, 37, 106, 5, 35, 20, 108, 92, 12, 124, 44, 131]]
use_synth :tri
dl=[]
cl=[]
#throw 16 sets of two dice and add to get choices
0.upto(15) do |i|
  d=rand_i(6)+rand_i(6)
  dl << d+2 #adjust dice total as rand_i=>0-5 so add 1 to each dice score
  cl << w[d][i] #add looked up bar number to list
end
puts "Combined dice scores "
puts dl #print dice totals
puts "List of bars from lookup table"
puts cl #print bar choices

Although Sonic Pi can generate random numbers, by design it will give the same repeatable sequence each time a program is run. This is so that a user can distribute a program and the end user will experience the same results from the random numbers generated as the original user when the program was written. So that a program can produce a different sequence, we need to manually change the random seed used. This is done in the first functional line of the program. By this mechanism we can choose a different waltz to be generated. However, when a “nice” waltz results, we can note the seed number, and use it to reproduce the same waltz at a later date.
When two dice are thrown, and the resulting numbers added together, a score of between 2 and 12 will result. A lookup table (contained in the array w) is used to select a bar for each of the 16 positions required from this total dice number. The array contains 11 lines, one corresponding to each of the totals 2..12. Each line contains 16 numbers, corresponding to the 16 bars required. The first dice total chooses a bar number from the first position in these rows from the row number given by the total -2. Thus a total of 2 gives row 0, and a total of 4 gives row 2 etc.
Two arrays dl (dice list) and cl (choice list) are built up with the dice score totals and the bar numbers chosen, and then they are printed in the output pane at the end of this section of the program.

The second section of the program contains the functions which are used to play the notes.

define :pl do |notes,dur| #plays arrays of notes and their durations
  notes.zip(dur).each do |n,d|
    play n,sustain: d*0.9,release: d*0.1,amp: 0.4
    sleep d
  end
end
define :pb do |n| #play right and left hand bar parts for bar n
  in_thread do
    pl(rn[n],rd[n])
  end
  pl(ln[n],ld[n])
end
define :pbr do #alternative left hand part for second time repeat bar
  in_thread do
    pl(rn[24],rd[24]) #right hand part always like bar 24
  end
  pl(ln[0],ld[24]) #left hand part substituted
end
define :perform do #traverses the list of bars, playing them
  0.upto(7) do |i| #first half, 8 bars (0-7)
    pb(cl[i])
  end
  0.upto(6) do |i| #repeat first 7 bars
    pb(cl[i])
  end
  pbr #2nd time bar substituting different lh part
  2.times do #second half repeats bars 8 to 15 (8 bars)
    8.upto(15) do |i|
      pb(cl[i])
    end
  end
end
define :allbars do
  1.upto(177) do |i|
    puts "Bar "+i.to_s
    puts"Right "+rn[i].to_s+" "+rd[i].to_s
    puts"Left "+ln[i].to_s+" "+ld[i].to_s
    pb(i)
    sleep 0.5
  end
end

These are pl, pb, pbr, perform and allbars.
The first of these pl takes two lists as its input parameters. The first contains a list of notes, and the second a list of their durations. It uses a construct from the Ruby language in which Sonic Pi is written to traverse these list in sync with each other.

notes.zip(dur).each do |n,d|

Corresponding elements of each list are taken in turn and assigned to the temporary variables n and d. This is done by zipping the lists together and then taking each pair of elements in turn.

play n,sustain: d*0.9,release: d*0.1,amp: 0.4
sleep d

A standard play command is used to play the note, sustaining it for 90% of its duration followed by a release for the remaining 10% of the duration. By this mechanism the notes are nearly full length but articulated from each other. The amplitude is also set to 0.4. A sleep command of the duration of the note gives the correct separation before the next note is played by the loop.
The second function pb has a single parameter which is the bar number. It uses this to play the right hand part of the bar using a call to the pl function in a thread, whilst playing the left hand part of the bar with a second call to the pl function with the left hand bar elements fed in as parameters.
The third function pbr (Play Bar Repeat) deals with the special case where the left hand of the repeat bar at the end of the first half of the minuet has a different part. Although different cards are specified for this bar, they all have the same part, as contained in bar 24. The left hand part is substituted by details stored in the 0 position of the left hand note and duration lists.
The fourth function, perform is used to play the final waltz.

define :perform do #traverses the list of bars, playing them
  0.upto(7) do |i| #first half, 8 bars (0-7)
    pb(cl[i])
  end
  0.upto(6) do |i| #repeat first 7 bars
    pb(cl[i])
  end
  pbr #2nd time bar substituting different lh part
  2.times do #second half repeats bars 8 to 15 (8 bars)
    8.upto(15) do |i|
      pb(cl[i])
    end
  end
end

It plays a loop eight times, using 0.upto(7) do |i| which generates an index variable i which can be used to play the first 8 bars using pb(cl[i]) cl[i] remember gives the bar numbers required from the list generated at the beginning of the program. It then repeats this, but only plays 7 bars (0..6) allowing the last bar in the first part to be modified by playing it using pbr rather than pb(cl[7]). It completes the playing of the waltz by using a 2.times do loop to play bars 8 to 15 (remember they number from 0 in the list) twice.
The final function, is not necessary to play the waltz, but if you comment out perform at the end of the program and uncomment allbars then it will instead perform all the 177 bars in a linear fashion from 1 to 177, at the same time printing the bar number and the contents of the left and right hand arrays elements associated with that bar. This is both for interest and to aid in debugging any mistakes in entry that may have been made.

The complete code is listed below, and there is a download link at the end of the article.

#Musikalisches Wurfelspiel KV516f by Mozart.
#Coded for Sonic Pi by Robin Newman, January 2015
#NB THIS PROGRAM IS TOO BIG TO RUN ON MACOSX SONIC PI
#Program simulates a game where the scores of two dice are added
#to choose a bar of music printed on 177 cards
#Because of the way Sonic Pi deals with random numbers,
#change the random seed number in the first line to choose
#different pieces
use_random_seed(6470 )
#w is lookup table Mozart used to choose bar from dice scores
w=[[96, 22, 141, 41, 105, 122, 11, 30, 70, 121, 26, 9, 112, 49, 109, 14],[32, 6, 128, 63, 146, 46, 134, 81, 117, 39, 126, 56, 174, 18, 116, 83],[69, 95, 158, 13, 153, 55, 110, 24, 66, 139, 15, 132, 73, 58, 145, 79],[40, 17, 113, 85, 161, 2, 159, 100, 90, 176, 7, 34, 67, 160, 52, 170],[148, 74, 163, 45, 80, 97, 36, 107, 25, 143, 64, 125, 76, 136, 1, 93],[104, 157, 27, 167, 154, 68, 118, 91, 138, 71, 150, 29, 101, 162, 23, 151],[152, 60, 171, 53, 99, 133, 21, 127, 16, 155, 57, 175, 43, 168, 89, 172],[119, 84, 114, 50, 140, 86, 169, 94, 120, 88, 48, 166, 51, 115, 72, 111],[98, 142, 42, 156, 75, 129, 62, 123, 65, 77, 19, 82, 137, 38, 149, 8],[3, 87, 165, 61, 135, 47, 147, 33, 102, 4, 31, 164, 144, 59, 173, 78],[54, 130, 10, 103, 28, 37, 106, 5, 35, 20, 108, 92, 12, 124, 44, 131]]
use_synth :tri
dl=[]
cl=[]
#throw 16 sets of two dice and add to get choices
0.upto(15) do |i|
  d=rand_i(6)+rand_i(6)
  dl << d+2 #adjust dice total as rand_i=>0-5 so add 1 to each dice score
  cl << w[d][i] #add looked up bar number to list
end
puts "Combined dice scores "
puts dl #print dice totals
puts "List of bars from lookup table"
puts cl #print bar choices
rn=[]*177;rd=[]*177;ln=[]*177;ld=[]*177 #define empty arrays for note data
define :pl do |notes,dur| #plays arrays of notes and their durations
  notes.zip(dur).each do |n,d|
    play n,sustain: d*0.9,release: d*0.1,amp: 0.4
    sleep d
  end
end
define :pb do |n| #play right and left hand bar parts for bar n
  in_thread do
    pl(rn[n],rd[n])
  end
  pl(ln[n],ld[n])
end
define :pbr do #alternative left hand part for second time repeat bar
  in_thread do
    pl(rn[24],rd[24]) #right hand part always like bar 24
  end
  pl(ln[0],ld[24]) #left hand part substituted
end
define :perform do #traverses the list of bars, playing them
  0.upto(7) do |i| #first half, 8 bars (0-7)
    pb(cl[i])
  end
  0.upto(6) do |i| #repeat first 7 bars
    pb(cl[i])
  end
  pbr #2nd time bar substituting different lh part
  2.times do #second half repeats bars 8 to 15 (8 bars)
    8.upto(15) do |i|
      pb(cl[i])
    end
  end
end
define :allbars do
  1.upto(177) do |i|
    puts "Bar "+i.to_s
    puts"Right "+rn[i].to_s+" "+rd[i].to_s
    puts"Left "+ln[i].to_s+" "+ld[i].to_s
    pb(i)
    sleep 0.5
  end
end
#set up speed multiplier for bpm 150, and then note durations
s=1.0/8*120/150;dsq=s;sq=2*s;q=4*s;c=8*s
#now define the array contents:
#ln left hand notes, ld left hand durations
#rn right hand notes, rd righthand durations
ln[0]=[:g2,:b3,:g3,:fs3,:e3]
ld[0]=[q,sq,sq,sq,sq]
rn[1]=[:f5,:d5,:g5]
rd[1]=ld[1]=rd[3]=rd[144]=rd[6]=ld[8]=ld[14]=ld[79]=ld[83]=ld[93]=ld[111]=ld[131]=ld[151]=ld[170]=ld[172]=rd[9]=ld[11]=ld[21]=ld[36]=ld[62]=ld[106]=ld[110]=ld[118]=ld[134]=ld[147]=ld[159]=ld[169]=rd[12]=rd[54]=rd[124]=rd[130]=ld[12]=ld[54]=ld[75]=ld[124]=ld[130]=ld[146]=ld[161]=rd[13]=rd[16]=rd[18]=rd[22]=rd[26]=rd[32]=rd[35]=rd[38]=rd[39]=rd[49]=rd[55]=rd[57]=rd[58]=rd[59]=rd[66]=ld[66]=rd[69]=rd[73]=rd[75]=rd[78]=rd[85]=rd[87]=rd[95]=rd[96]=rd[98]=rd[99]=rd[108]=rd[112]=rd[113]=rd[114]=ld[114]=ld[122]=ld[129]=ld[125]=ld[132]=ld[175]=rd[128]=ld[135]=rd[137]=ld[140]=rd[142]=rd[146]=rd[161]=rd[165]=rd[174]=[q,q,q]
ln[1]=[:f3,:d3,:g3]
rn[2]=[:a4,:fs4,:g4,:b4,:g5]
rd[2]=ld[5]=ld[24]=ld[30]=ld[33]=ld[81]=ld[91]=ld[94]=ld[100]=ld[107]=ld[123]=ld[127]=rd[43]=rd[44]=rd[46]=rd[48]=rd[60]=rd[68]=rd[70]=rd[105]=rd[106]=rd[120]=rd[133]=rd[152]=rd[158]=rd[168]=[q,sq,sq,sq,sq]
ln[2]=ln[86]=ln[121]=ln[133]=[[:b2,:g3],:r]
ld[2]=ld[86]=ld[121]=ld[133]=ld[3]=ld[6]=ld[32]=ld[40]=ld[41]=ld[43]=ld[51]=ld[60]=ld[69]=ld[74]=ld[84]=ld[95]=ld[115]=ld[119]=ld[136]=ld[142]=ld[148]=ld[152]=ld[167]=rd[5]=rd[24]=rd[30]=rd[33]=rd[81]=rd[91]=rd[94]=rd[100]=rd[107]=rd[123]=rd[127]=ld[7]=rd[8]=rd[14]=rd[79]=rd[83]=rd[93]=rd[111]=rd[131]=rd[151]=rd[170]=rd[172]=ld[9]=ld[10]=ld[34]=ld[13]=ld[17]=ld[45]=ld[50]=ld[61]=ld[85]=ld[103]=ld[156]=ld[15]=ld[19]=ld[48]=ld[101]=ld[108]=ld[162]=ld[16]=ld[120]=ld[18]=ld[76]=ld[87]=ld[20]=ld[139]=ld[22]=ld[53]=ld[63]=ld[80]=ld[96]=ld[104]=ld[105]=ld[153]=ld[154]=ld[157]=ld[25]=ld[70]=ld[27]=ld[113]=ld[166]=ld[28]=ld[29]=ld[31]=ld[64]=ld[35]=ld[37]=ld[46]=ld[47]=ld[55]=ld[155]=ld[163]=ld[42]=ld[128]=ld[158]=ld[44]=ld[52]=ld[72]=ld[116]=ld[145]=ld[149]=ld[173]=ld[56]=ld[92]=ld[65]=ld[117]=ld[67]=ld[168]=ld[68]=ld[165]=ld[71]=ld[88]=ld[143]=ld[176]=ld[77]=ld[78]=ld[82]=ld[25]=ld[70]=ld[90]=ld[97]=ld[99]=ld[102]=ld[109]=ld[141]=ld[160]=ld[171]=[c,q]
rn[3]=rn[144]=rn[59]=rn[87]=[:g5,:c5,:e5]
ln[3]=ln[6]=ln[32]=ln[40]=ln[41]=ln[43]=ln[51]=ln[60]=ln[69]=ln[74]=ln[84]=ln[95]=ln[115]=ln[119]=ln[136]=ln[142]=ln[148]=ln[152]=ln[167]=[[:c3,:e3],:r]
rn[4]=[:g5,:e5,:d5,:e5,:d5,:e5,:d5,:e5,:d5]
rd[4]=[q,dsq,dsq,dsq,dsq,dsq,dsq,dsq,dsq]
ln[4]=[:g3,:b3,:g3,:b3]
ld[4]=rd[19]=rd[31]=rd[56]=rd[65]=rd[77]=rd[82]=rd[89]=ld[89]=rd[102]=rd[149]=[sq,sq,q,q]
rn[5]=rn[24]=rn[30]=rn[33]=rn[81]=rn[91]=rn[94]=rn[100]=rn[107]=rn[123]=rn[127]=[[:g4,:b4,:d5,:g5],:r]
ln[5]=ln[24]=ln[30]=ln[33]=ln[81]=ln[91]=ln[94]=ln[100]=ln[107]=ln[123]=ln[127]=[:g2,:g3,:f3,:e3,:d3]
#ln[5]=ln[24]=ln[30]=ln[33]=ln[81]=ln[91]=ln[94]=ln[100]=ln[107]=ln[123]=ln[127]=[:g3,:b3,:g3,:fs3,:e3]
rn[6]=rn[174]=[:g4,:c5,:e5]
rn[7]=[:e5,:c5,:e5,:g5,:c6,:g5]
rd[7]=rd[10]=rd[11]=rd[17]=rd[21]=rd[23]=ld[23]=rd[25]=ld[26]=rd[27]=rd[28]=rd[36]=ld[38]=ld[49]=ld[57]=ld[58]=ld[59]=ld[73]=ld[98]=ld[112]=ld[137]=ld[144]=ld[174]=ld[39]=rd[40]=rd[42]=rd[45]=rd[51]=rd[52]=rd[62]=rd[64]=rd[67]=rd[72]=rd[74]=rd[76]=rd[136]=rd[148]=rd[84]=rd[88]=rd[90]=rd[97]=rd[101]=rd[104]=rd[109]=rd[110]=rd[115]=rd[116]=rd[117]=rd[118]=rd[119]=rd[126]=rd[134]=rd[136]=ld[138]=rd[141]=rd[145]=rd[147]=rd[148]=ld[150]=rd[153]=rd[154]=rd[155]=rd[157]=rd[159]=rd[160]=rd[162]=rd[163]=ld[164]=rd[169]=rd[171]=rd[176]=[sq,sq,sq,sq,sq,sq]
ln[7]=[[:c3,:g3],:r]
rn[8]=rn[14]=rn[79]=rn[83]=rn[93]=rn[111]=rn[131]=rn[151]=rn[170]=rn[172]=[:c5,:r]
ln[8]=ln[14]=ln[79]=ln[83]=ln[93]=ln[111]=ln[131]=ln[151]=ln[170]=ln[172]=[:c3,:g2,:c2]
rn[9]=[[:c5,:e5],[:b4,:d5],:r]
ln[9]=[:g3,:g3]
rn[10]=[:b4,:a4,:b4,:c5,:d5,:b4]
ln[10]=ln[34]=[:g3,:r]
rn[11]=[:e5,:c5,:b4,:a4,:g4,:fs4]
ln[11]=ln[21]=ln[36]=ln[62]=ln[106]=ln[110]=ln[118]=ln[134]=ln[147]=ln[159]=ln[169]=[:c3,:d3,:d2]
rn[12]=rn[54]=rn[124]=rn[130]=[[:e4,:c5],[:e4,:c5],[:e4,:c5]]
ln[12]=ln[54]=ln[75]=ln[124]=ln[130]=ln[146]=ln[161]=[:c3,:c3,:c3]
rn[13]=[:c5,:g4,:e4]
ln[13]=ln[17]=ln[45]=ln[50]=ln[61]=ln[85]=ln[103]=ln[156]=[[:e3,:g3],:r]
rn[15]=[:e5,:g5,:e5,:c5]
rd[15]=rd[20]=rd[47]=rd[50]=rd[53]=rd[61]=rd[86]=rd[92]=rd[121]=rd[132]=rd[135]=rd[140]=rd[143]=rd[167]=[q,sq,sq,q]
ln[15]=ln[19]=ln[48]=ln[101]=ln[108]=ln[162]=[[:c3,:g3],[:c3,:e3]]
rn[16]=[:a5,:fs5,:d5]
ln[16]=ln[120]=[[:d3,:fs3],[:c3,:fs3]]
rn[17]=[:c5,:g4,:c5,:e5,:g4,:c5]
rn[18]=[:g4,:c5,:e5]
ln[18]=ln[76]=ln[87]=[[:c3,:e3],[:c3,:g3]]
rn[19]=[:e5,:c5,:e5,:g5]
rn[20]=[:g5,:b5,:d6,:d5]
ln[20]=ln[139]=[:b2,:r]
rn[21]=[:c5,:e5,:g5,:d5,:a4,:fs5]
rn[22]=[:e5,:c5,:g4]
ln[22]=ln[53]=ln[63]=ln[80]=ln[96]=ln[104]=ln[105]=ln[153]=ln[154]=ln[157]=[:c3,:r]
rn[23]=[:f5,:e5,:d5,:e5,:f5,:g5]
ln[23]=[:f3,:e3,:d3,:e3,:f3,:g3]
rn[25]=[:d4,:fs4,:a4,:d5,:fs5,:a5]
ln[25]=ln[70]=[:d3,:c3]
rn[26]=[[:c5,:e5],[:c5,:e5],[:c5,:e5]]
ln[26]=[:c3,:e3,:g3,:e3,:c4,:c3]
rn[27]=[:f5,:e5,:f5,:d5,:c5,:b4]
ln[27]=ln[113]=ln[166]=[[:g3,:b3],:r]
rn[28]=[:fs5,:d5,:a4,:a5,:fs5,:d5]
ln[28]=[[:c3,:a3],:r]
rn[29]=[:b4,:d5,:g5,:d5,:b4]
rd[29]=rd[34]=rd[37]=rd[41]=rd[63]=rd[71]=rd[103]=rd[122]=rd[125]=rd[129]=rd[139]=rd[156]=rd[166]=rd[175]=[sq,sq,sq,sq,q]
ln[29]=[:g3,:g2]
rn[31]=[:e5,:c5,:g4,:e5]
ln[31]=ln[64]=[[:c3,:g3],[:c3,:g3]]
rn[32]=[:g4,:c5,:e5]
rn[34]=[:e5,:c5,:d5,:b4,:g4]
rn[35]=[:a4,:d5,:fs5]
ln[35]=[[:d3,:fs3],[:c3,:a3]]
rn[36]=[:a4,:e5,:d5,:g5,:fs5,:a5]
rn[37]=[:g5,:b5,:g5,:d5,:b4]
ln[37]=ln[46]=ln[47]=ln[55]=ln[155]=ln[163]=[[:b2,:d3],:r]
rn[38]=[:c5,:g4,:e5]
ln[38]=ln[49]=ln[57]=ln[58]=ln[59]=ln[73]=ln[98]=ln[112]=ln[137]=ln[144]=ln[174]=[[:c3,:e3],:g3,[:c3,:e3],:g3,[:c3,:e3],:g3]
rn[39]=[:g5,:g4,:g4]
ln[39]=[:b2,:d3,:g3,:d3,:b2,:g2]
rn[40]=[:c5,:b4,:c5,:e5,:g4,:c5]
rn[41]=[:c5,:b4,:c5,:e5,:g4]
rn[42]=[:b4,:c5,:d5,:b4,:a4,:g4]
ln[42]=ln[128]=ln[158]=[:g2,:r]
rn[43]=[:g5,:f5,:e5,:d5,:c5]
rn[44]=[:a4,:f5,:d5,:a4,:b4]
ln[44]=ln[52]=ln[72]=ln[116]=ln[145]=ln[149]=ln[173]=[:f3,:g3]
rn[45]=[:c5,:b4,:c5,:g4,:e4,:c4]
rn[46]=[:g5,:b5,:g5,:d5,:b4]
rn[47]=[:g5,:g5,:d5,:b5]
rn[48]=[:e5,:c5,:e5,:g5,:c6]
rn[49]=[:e5,:c5,:g4]
rn[50]=[:c5,:e5,:c5,:g4]
rn[51]=[:c5,:g4,:e5,:c5,:g5,:e5]
rn[52]=[:d5,:cs5,:d5,:f5,:g4,:b4]
rn[53]=[[:c5,:e5],[:c5,:e5],[:d5,:f5],[:e5,:g5]]
rn[55]=[:g5,:b5,:d5]
rn[56]=[:d5,:b4,:g4,:r]
ln[56]=ln[92]=[[:g2,:g3],:g3]
rn[57]=[:e5,:c5,:g4]
rn[58]=[:g5,:e5,:c5]
rn[60]=[:g5,:f5,:e5,:d5,:c5]
rn[61]=[:c5,:e5,:c5,:g5]
rn[62]=[:e5,:c5,:b4,:g4,:a4,:fs4]
rn[63]=[:e5,:c5,:b4,:c5,:g4]
rn[64]=[:e5,:g5,:c6,:g5,:e5,:c5]
rn[65]=[:d5,:a4,:d5,:fs5]
ln[65]=ln[117]=[[:d3,:fs3],:r]
rn[66]=[:fs5,:a5,:fs5]
ln[66]=[[:d3,:a3],[:d3,:fs3],[:c3,:d3]]
rn[67]=[:c5,:b4,:c5,:e5,:g4,:c5]
ln[67]=ln[168]=[[:c3,:e3],[:e3,:g3]]
rn[68]=[:g5,:b5,:g5,:d5,:g5]
ln[68]=ln[165]=[:b2,:r]
rn[69]=[:g5,:e5,:c5]
rn[70]=[:fs5,:a5,:fs5,:d5,:fs5]
rn[71]=[:g5,:b5,:d6,:b5,:g5]
ln[71]=ln[88]=ln[143]=ln[176]=[[:b2,:d3],[:b2,:d3]]
rn[72]=[:f5,:e5,:d5,:c5,:b4,:d5]
rn[73]=[:g5,:e5,:c5]
rn[74]=rn[76]=rn[136]=rn[148]=[:c6,:b5,:c6,:g5,:e5,:c5]
rn[75]=[[:d5,:fs5],[:d5,:fs5],[:d5,:fs5]]
rn[77]=[:g5,:b5,:g5,:d5]
ln[77]=[[:b2,:d3],[:b2,:g3]]
rn[78]=[:c5,:c4,:r]
ln[78]=[:c3,:c2]
rn[80]=[:d5,:b4,:a4,:g4,:a4,:fs5]
rd[80]=[q,dsq,dsq,dsq,dsq,q]
rn[82]=[:d5,:b4,:g4,:g5]
ln[82]=[[:b2,:g3],[:b2,:d3]]
rn[84]=[:c5,:g4,:e5,:c5,:g5,:e5]
rn[85]=[:c5,:e5,:g4]
rn[86]=[:d5,:d5,:g5,:b5]
rn[88]=[:g5,:d5,:g5,:b5,:g5,:d5]
rn[89]=[:f5,:e5,:d5,:g5]
ln[89]=[:f3,:e3,:d3,:g3]
rn[90]=[:fs5,:a5,:d6,:a5,:fs5,:a5]
ln[90]=[[:c3,:a3],[:c3,:a3]]
rn[92]=[[:b4,:d5],:g5,:b5,:d5]
rn[95]=[:g5,:e5,:c5]
rn[96]=[:e5,:c5,:g4]
rn[97]=rn[163]=[:g5,:fs5,:g5,:d5,:b4,:g4]
ln[97]=[[:b2,:d3],[:b2,:g3]]
rn[98]=[:c5,:g4,:e5]
rn[99]=[:fs5,:a5,:d5]
ln[99]=ln[102]=[[:c3,:a3],[:c3,:a3]]
rn[101]=rn[162]=[:e5,:d5,:e5,:g5,:c6,:g5]
rn[102]=[:fs5,:d5,:a4,:fs5]
rn[103]=[:c5,:e5,:c5,:g4,:e4]
rn[104]=[:e5,:d5,:e5,:g5,:c6,:g5]
rn[105]=[:fs5,:a5,:fs5,:d5,:fs5]
rn[106]=[:a4,:d5,:c5,:b4,:a4]
rn[108]=[:e5,:g5,:c6]
rn[109]=[:d5,:f5,:d5,:f5,:b4,:d5]
ln[109]=[[:f3,:a3],[:g3,:d4]]
rn[110]=[[:b4,:d5],[:a4,:c5],[:a4,:c5],[:g4,:b4],[:g4,:b4],[:fs4,:a4]]
rn[112]=[:e5,:c5,:g4]
rn[113]=[:f5,:d5,:b4]
rn[114]=[[:b4,:d5],[:b4,:d5],[:b4,:d5]]
ln[114]=[:g3,:g3,:g3]
rn[115]=[:c5,:g4,:e5,:c5,:g5,:e5]
rn[116]=[:d5,:f5,:a5,:f5,:d5,:b4]
rn[117]=[:d5,:a4,:d5,:fs5,:a5,:fs5]
rn[118]=[:e5,:a5,:g5,:b5,:fs5,:a5]
rn[119]=[:e5,:c5,:g5,:e5,:c6,:g5]
rn[120]=[:d6,:a5,:fs5,:d5,:a4]
rn[121]=[:g5,:b5,:g5,:d5]
rn[122]=[:g5,:fs5,:g5,:b5,:d5]
ln[122]=ln[129]=[[:b2,:d3],[:b2,:d3],[:b2,:d3]]
rn[125]=[:g5,:e5,:d5,:b4,:g4]
ln[125]=ln[132]=ln[175]=[:g3,:g2,:r]
rn[126]=[:c5,:g4,:c5,:e5,:g5,[:c5,:e5]]
ln[126]=[:e3,:e3,:c3]
ld[126]=[c,sq,sq]
rn[128]=[:b4,:d5,:g5]
rn[129]=[:a5,:g5,:fs5,:g5,:d5]
rn[132]=[[:c5,:e5],[:b4,:d5],[:g4,:b4],:g4]
rn[133]=[:d5,:g5,:d5,:b4,:d5]
rn[134]=[:a4,:e5,[:b4,:d5],[:a4,:c5],[:g4,:b4],[:fs4,:a4]]
rn[135]=[:fs5,:fs5,:d5,:a5]
ln[135]=[[:c3,:d3],[:c3,:d3],[:c3,:d3]]
rn[136]=[:c6,:b5,:c6,:g5,:e5,:c5]
rn[137]=[:c5,:g4,:e5]
rn[138]=[[:a4,:d5,:fs5],:g5,:fs5,:g5,:fs5,:g5,:fs5,:g5,:fs5]
rd[138]=rd[150]=[q,dsq,dsq,dsq,dsq,dsq,dsq,dsq,dsq]
ln[138]=[:d2,:d3,:cs3,:d3,:c3,:d3]
rn[139]=[:g5,:b5,:g5,:b5,:d5]
rn[140]=[:a4,:a4,:d5,:fs5]
ln[140]=[[:c3,:fs3],[:c3,:fs3],[:c3,:a3]]
rn[141]=[:d5,:e5,:f5,:d5,:c5,:b4]
ln[141]=[[:b2,:g3],:g2]
rn[142]=[:c5,:g4,:e5]
rn[143]=[:g5,:d5,:b4,:g4]
rn[145]=[:d5,:f5,:a4,:d5,:b4,:d5]
rn[146]=[[:fs4,:d5],[:d5,:fs5],[:fs5,:a5]]
rn[147]=[:e5,:c6,:b5,:g5,:a5,:fs5]
rn[148]=[:c6,:b5,:c6,:g5,:e5,:c5]
rn[149]=[:f5,:d5,:a4,:b4]
rn[150]=[[:g4,:c5,:e5],:f5,:e5,:f5,:e5,:f5,:e5,:f5,:e5]
ln[150]=[:c3,:b2,:c3,:d3,:e3,:fs3]
rn[152]=[:g5,:f5,:e5,:d5,:c5]
rn[153]=[:d5,:a4,:fs5,:d5,:a5,:fs5]
rn[154]=[:d5,:cs5,:d5,:fs5,:a5,:fs5]
rn[155]=[:g5,:b5,:g5,:d5,:b4,:g4]
rn[156]=[:c5,:g4,:e5,:c5,:g5]
rn[157]=[:e5,:d5,:e5,:g5,:c6,:g5]
rn[158]=[:b4,:d5,:b4,:a4,:g4]
rn[159]=[:e5,:g5,:d5,:c5,:b4,:a4]
rn[160]=[:c5,:b4,:c5,:e5,:g4,:c5]
ln[160]=[[:c3,:e3],[:c3,:e3]]
rn[161]=[[:fs4,:d5],[:fs4,:d5],[:fs4,:d5]]
rn[164]=[:d5,:g4]
rd[164]=[q,c]
ln[164]=[:g3,:fs3,:g3,:d3,:b2,:g2]
rn[165]=[:d5,:b4,:g4]
rn[166]=[:d5,:b5,:g5,:d5,:b4]
rn[167]=[:c5,:c5,:d5,:e5]
rn[168]=[:g5,:f5,:e5,:d5,:c5]
rn[169]=[:e5,:g5,:d5,:g5,:a4,:fs5]
rn[171]=[:b4,:c5,:d5,:e5,:f5,:d5]
ln[171]=[[:g2,:g3],[:b2,:g3]]
rn[173]=[:f5,:a5,:a4,:b4,:d5]
rd[173]=[sq,sq,q,sq,sq]
rn[175]=[:e5,:c5,:b4,:d5,:g5]
rn[176]=[:a5,:g5,:b5,:g5,:d5,:g5]

#now play the minuet or all the bars in linear order
#uncomment one of the next two lines
#allbars
perform

If you just want to play the waltzes, then that is it. Download and copy the program into a Sonic Pi workspace and run it. Change the seed number in the first line after the initial comments, and re-run to get a different waltz. However it is more fun if you go on to add the programs to generate the music manuscript as well.
Having dealt with the program, the remainder of the article discusses how to generate the musical manuscript for the waltz using the lilypond musical engraver program. If you wish to do this you must install it on your Pi. It is quite a large program occupying some 800Mb and taking several minutes to install, so make sure you have the space on your SD card and the time for it to install before doing so.
Type the following:

sudo apt-get update

and when that has finished

sudo apt-get install lilypond

When the process has finished you will also need to obtain a copy of the DiceWaltz Python programs contained in the original article. These can be downloaded here.
Unzip the programs, and if you want you can try them out as described in the original article. However in this case, we are only going to look at the minuet programs, as I have not (yet) written the contredanse program for Sonic Pi. Also, we need to use the program with the dice totals input from our Sonic Pi program rather than generated from the python script. Fortunately the script already contains an option to do this.
All we need to do is first to generate a text file dicethrows.txt into which the thow totals can be pasted from the Sonic Pi program output pane. This can be done using the nano editor by typing
nano dicethrows.txt
Then pasting in the numbers generated from the Sonic Pi Program. After these have been added you can use ctrl_X to exit, saying yes when it asks if you want to save the changes. On subsequent runs, you can select the existing line of numbers and type ctrl+K to delete it, before pasting in the new set. When dicethrows.txt is prepared, we can run the new script gosp.sh which should be downloaded from the link at the end of this article and added to the DiceWaltz-1.2.1WithContredanse folder containing the python scripts. Run it by typing ./gosp.sh

The script gosp.sh looks like this:

#!/bin/bash
python dicewaltz.py -i dicethrows.txt -e lily -o playme.ly
lilypond -fpng playme.ly
netsurf file:////home/pi/DiceWaltz-1.2.1WithContredanse/playme.png &

when you downloaded it should be placed in the top level of the DiceWaltz-1.2.1WithContredanse folder which itself should be in the Pi user home directory. This is because the call which launches the netsurf browser requires an absolute path to the playme.png file it is going to show. Also you need to set execute permissions for the script file. Type chmod 755 gosp.sh in order to add the necessary permissions. If you want to use the other programs as described in the original article you will need to set execute permissions for ALL the script and python programs. You can do this with chmod 755 *.sh and chmod 755 *.py from within the DiceWaltz-1.2.1WithContredanse folder. See the original article for further details.

The best way to see how to use everything together is to watch the video which explains the process.

Links:
The original Dice Game article
Python Scripts download
gosp.sh script zip file
SonicPiMozartDiceWaltz program

Video showing how to set up the programs

 

1 thought on “Mozart Dice generated Waltz: revisited with Sonic Pi

  1. Pingback: [Перевод] Озвучивание прошлого. Руководство для историков по преобразованию данных в звук – CHEPA website

Leave a comment