Sonic Pi 2.2 plays Bach Gigue in G Minor: Three separate versions!

With the advent of Sonic Pi 2.2 I thought it was time that I coded up some more Bach, and I decided to have a go at the Gigue in G Minor from English Suite number 3. I wanted to make it sound as authentic as possible, and decided to use the GrandPiano sample voices that I discussed here some month ago. I tidied up the code for this a little bit, and also decided to incorporate the technique to add a dynamic “volume” track as discussed in another earlier post here. The final feature I made use of was to split the program into two halves, one to generate the sample base voice and the other to generate the arrays holding the various parts and to play them. This could have used my conductor program, but I made it a little easier by directly linking them with a cue and sync command pair.

The music I used is shown below:

giguep1

giguep2

giguep3

The music is coded in three parts for each section: The right hand part, the left hand part and two small sections where a third part is heard. Initially I coded it up and played it using the :pulse synth whilst I dealt with the inevitable errors which arise in coding the music. I also then worked on the fourth “dynamics” part to adjust the volume of each section as it plays, including the use of crescendos and diminuendos which are achieved by using the sliding parameter for :amp with the fx level control.
I got the sample voice working in a separate program, and then connected the two together, by sending a cue form the end of the first part (which generated the sample voice) to a sync command at the start of the second part which played the tune. The way Sonic Pi works, functions defined in part 1 are accessible in part 2. If the function needs to amend variable which are used externally to it, then these need to be first defined in the main body of the program, to give them global scope in the program. You have to define a function used in this way in the program in which it is to be used. Examples are the lset and parts functions. Variables which are needed in both programs need to be defined separately in each program. e.g. ps which is used by the function sname. The program lets you know by generating an error if it can’t find a variable, so you can debug fairly easily. Using this technique, larger programs can be made to run on Sonic Pi (particularly on the Mac) thus overcoming the limitation on maximum program size.

The three programs are listed below. In order to avoid breaching size limits I have not added as many comments as I usually would do.

First, the synth based program using :pulse synth to play

#Bach Gigue in G minor from English Suite no 3 Coded by Robion Newman December 2014
#Synth version
set_sched_ahead_time! 3
use_debug false
s=0 #to set global scope
define :setbpm do |n| #set bpm equivalent
  s = (1.0 / 8) *(60.0/n.to_f)
end
use_synth :pulse
setbpm(180)
dsq=sq=q=qd=c=cd=cdd=m=md=0 #to setglobal scope

define :lset do
  dsq = 1 * s #demi-semi-quaver
  sq = 2 * s #semi-quaver
  q = 4 * s #quaver
  qd = 6 * s #quaver dotted
  c = 8 * s #crotchet
  cd = 12 * s #crotchet dotted
  m = 16 * s #minim
  md = 24 * s #minim dotted
end
lset
p=0.15 #dynamics
mp=0.2
mf=0.4
f=0.8
ff=1.6

define :plarray do |narray,darray,vol=0.4|
  narray.zip(darray).each do |n,d|
    play n,amp: vol,attack: dsq/10, sustain: 0.9*d-dsq/10,release: 0.1*d #play note
    sleep d #gap till next note
  end
end

define :ct do |ptr,lev,slid=0| #function to adjust level control
  control ptr,amp: lev,amp_slide: slid
end

ritq=ritqb=d1=d2=d3=d1b=d2b=d3b=n1=n2=n3=n1b=n2b=n3b=[] #define global scope
define :parts do
ritq=[q*1.02,q*1.04,q*1.06,q*1.08,q*1.1,q*1.12]
ritqb=[q*1.02,q*1.04,q*1.06,q*1.08,q*1.1,q*1.2,q*1.4,q*1.6,q*1.8]
n1=[:d5,:eb5,:d5,:c5,:bb4,:a4,:g4,:fs4,:a4,:d4,:c4,:bb3,:a3,:bb3,:d4,:g4,:a3,:g4,:fs4,:g4,:bb4,:a4,:bb4,:d5,:c5]
d1=[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#3
n1.concat [:d5,:e5,:f5,:e5,:f5,:g5,:a5,:g5,:f5,:g5,:f5,:e5,:f5,:g5,:a5,:d5,:c5,:bb4,:c5,:d5,:bb4,:c5]
d1.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+c,q,c,q]
#6
n1.concat [:a4,:bb4,:c5,:d5,:bb4,:c5,:d5,:e5,:fs5,:g5,:a5,:g5,:f5,:e5,:f5,:eb5,:d5,:c5,:d5,:c5,:bb4,:a4,:bb4,:r,:a4,:r,:a4,:g4,:a4,:r,:e4,:g4]
d1.concat [c,q,c,q,c,q,cd+c,q,cd,cd,cd+cd,cd+q,q,q,cd+cd,cd+q,q,q,cd+cd,cd+q,q,q,cd,q,c,q,q,q,cd,q,q,q]
#12
n1.concat [:f4,:g4,:a4,:g4,:a4,:bb4,:a4,:d5,:f5,:g4,:g5,:e5,:f5,:a5,:g5,:a5,:a4,:cs5,:b4,:c5,:e5,:d5,:e5,:e4,:g4,:f4]
d1.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,cd,q,q,q,q,q,q,cd,q,q,q]
#15
n1.concat [:g4,:bb4,:a4,:bb4,:cs4,:e4,:d4,:e4,:g4,:f4,:g4,:bb4,:a4,:bb4,:a4,:g4,:cs5,:bb4,:a4,:d5,:a4,:g4,:e5,:a4,:g4,:f4,:g4,:e4,:f4,:e4,:d4,:g4,:e4,:d4]
d1.concat [q,q,q,cd]+[q]*30
#18
n1.concat [:a4,:e4,:d4,:bb4,:e4,:d4,:cs4,:d4,:e4,:a3,:r,:a5,:bb5,:a5,:g5,:f5,:e5,:d5,:cs5,:e5,:a4,:g4,:f4,:e4,:f4,:a4,:d5,:e4,:d5,:cs5,:d5,:a4,:fs4,:d4]
d1.concat [q]*27+ritq+[c*1.12]
#end part 1
n2=[:r,:g4,:bb4,:a4,:g4,:f4,:e4,:d4,:cs4,:e4,:a3,:g3,:f3,:e3,:f3,:a3,:d4,:e3,:d4,:cs4,:d4,:e4,:f4,:e4,:fs4,:g4,:a4,:g4,:fs4,:g4,:fs4,:e4]
d2=[q*24]+[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+q,q,q,q,q,q,q,q,q]
#6
n2.concat [:fs4,:e4,:d4,:e4,:g4,:fs4,:g4,:a4,:bb4,:a4,:bb4,:c5,:d5,:c5,:bb4,:c5,:bb4,:a4,:bb4,:a4,:g4,:f4,:eb4,:d4,:f4,:e4,:f4,:e4,:d4,:cs4,:b3,:cs4]
d2.concat [q,q,q,q,q,q,cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,md,md,md,md,md,cd+q,q,q,c,q,cd+q,q,q,cd]
#12
n2.concat [:d4,:e4,:f4,:e4,:f4,:g4,:a4,:g4,:r]
d2.concat [cd+q,q,q,cd+q,q,q,cd,cd,cd*2+72*q+9.42*q+c*1.2] #rit at end
#end part 1
n3=[:r,:d4,:eb4,:d4,:c4,:bb3,:a3,:g3,:fs3,:a3,:d3,:c3,:bb2,:a2,:bb2,:d3,:g3,:a2,:g3,:fs3,:g3,:bb3,:a3,:bb3,:d4,:c4,:d4,:a3,:d3]
d3=[q+60*q+5*q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q]
#9

n3.concat [:eb3,:g3,:f3,:g3,:bb3,:a3,:bb3,:f3,:bb2,:c3,:eb3,:d3,:eb3,:g3,:f3,:g3,:cs3,:d3,:c3,:bb2,:c3,:bb2,:a2,:r,:a3]
d3.concat [q,q,q,q,q,q,cd+q,q,q,q,q,q,q,q,q,cd+c,q,c,q,sq,sq,c,cd,c,q]
#12
n3.concat [:bb3,:a3,:g3,:f3,:e3,:d3,:cs3,:e3,:a2,:g2,:g2,:e2,:f2,:a2,:d3,:e2,:d3,:cs3,:d3,:f3,:e3,:f3,:a3,:g3,:a3,:a2,:cs3,:b2,:cs3,:e3,:d3]
d3.concat [q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,q,q,q,cd,q,q,q,q,q,q]
#15

n3.concat [:e3,:g3,:f3,:g3,:bb3,:a3,:bb3,:g3,:f3,:e3,:f3,:g3,:a2,:r,:b2,:r,:cs3,:a2,:b2,:cs3,:d3,:r,:e3,:r]
d3.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,c,q,c,q,c,q,c,q,c,q,c,q]
#18
n3.concat [:f3,:r,:g3,:f3,:e3,:f3,:cs4,:d4,:g3,:cs4,:d4,:gs3,:cs4,:d4,:a3,:cs4,:d4,:e4,:d4,:cs4,:d4,:f3,:g3,:a3,:g3,:a3,:d3,:fs3,:a3,:d4]
d3.concat [c,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]+ritq+[c*1.12]
#end part1
n1b=[:a3,:fs3,:g3,:a3,:bb3,:c4,:d4,:eb4,:c4,:g4,:a4,:bb4,:c5,:bb4,:g4,:d4,:c5,:e4,:fs4,:g4,:e4,:f4,:e4,:cs4,:d4,:a4,:g4,:f4,:g4,:f4,:e4]
d1b=[q]*25+[cd+q,q,q,cd+q,q,q]
#24
n1b.concat [:d4,:e4,:f4,:e4,:a4,:g4,:f4,:eb4,:d4,:bb4,:a4,:g4,:a4,:g4,:fs4,:g4,:eb5,:f4,:d5,:r,:g4,:fs4,:g4,:a4,:bb4,:c5,:d5,:eb5,:c5,:g5,:a5,:bb5,:c6,:bb5,:g5,:d5,:c6,:e5,:fs5,:g5,:d5,:eb5,:f5,:c5,:d5]
d1b.concat [q,q,q,q,q,q,q,q,q,cd+q,q,q,q,q,q,c,q,c,q,11*q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#29
n1b.concat [:eb5,:f5,:e5,:f5,:e5,:d5,:e5,:f5,:c5,:d5,:eb5,:bb4,:c5,:d5,:a4,:bb4,:c5,:g4,:a4,:bb4,:g5,:ab4,:f5,:g4,:eb5,:f4,:d5,:eb4,:f4,:g4,:d4,:eb4,:c4]
d1b.concat [cd,sq,sq,sq,sq,sq,sq,q,q,q,q,q,q,q,q,q,q,q,q,c,q,c,q,c,q,c,q,q,q,q,q,q,q]
#32
n1b.concat [:b3,:c4,:d4,:eb4,:f4,:g4,:ab4,:f4,:c5,:d5,:eb5,:f5,:g5,:eb5,:c5,:f5,:a4,:b4,:eb5,:c5,:a4,:d5,:fs4,:g4,:c5,:a4,:fs4,:bb4,:d4,:eb4,:a4,:f4,:d4,:g4,:bb3,:c4]
d1b.concat [q]*36
#35
n1b.concat [:d4,:e4,:fs4,:g4,:a4,:bb4,:c5,:d5,:eb5,:d5,:bb5,:eb5,:d5,:c5,:bb4,:g5,:c5,:bb4,:ab4,:g4,:eb5,:ab4,:g4,:f4,:eb4,:c5,:eb4,:d4,:c5,:bb4,:c4,:bb4,:a4,:d4,:c5,:bb4,:e4,:d5,:c5,:fs4,:eb5,:d5]
d1b.concat [cd+q,q,q,q,q,q,q,q,q,c,q,q,q,q,c,q,q,q,q,c,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#39

n1b.concat [:g4,:c5,:bb4,:a4,:bb4,:g4,:fs4,:eb4,:d4,:g4,:d4,:c4,:a4,:d4,:c4,:bb3,:c4,:a3,:bb3,:a3,:g3,:c4,:a3,:g3,:d4,:a3,:g3,:eb4,:a3,:g3,:fs3,:g3,:a3,:bb3,:c4,:d4]
d1b.concat [q]*3*12
#42
n1b.concat [:eb4,:c4,:g4,:a4,:bb4,:c5,:d5,:bb4,:g4,:c5,:e4,:fs4,:g4,:d5,:g5,:f5,:eb5,:d5,:c5,:bb4,:a4,:g4,:fs4,:g4,:eb5,:d5,:bb4,:c5,:bb4,:a4,:g4,:g4,:d4,:bb3,:g3]
d1b.concat [q]*12+[c]+[q]*10+ritqb[0..2]+[dsq*1.08,dsq*1.08,sq*1.08]+ritqb[4..-1]+[c*1.2]
#end part 2
n2b=[:r,:eb4,:d4,:c4,:d4,:c4,:bb3,:c4,:a4,:bb3,:c4,:d4,:c4,:bb3,:c4,:bb3,:a3,:g3,:a3,:bb3,:c4,:bb3,:c4,:b3,:c4,:b3,:a3,:b3,:r]
d2b=[q*61,q,q,q,q,q,q,c,q,c,q,cd+q,q,q,cd+q,q,q,cd,q,q,q,cd,sq,sq,sq,sq,sq,sq,q*12*15+11.3*q+c*1.2]
#end part 2
n3b = [:r,:d2,:cs2,:d2,:e2,:f2,:g2,:a2,:bb2,:g2,:d3,:e3,:f3,:g3,:f3,:d3,:a2,:g3,:b2,:cs3,:d3,:c3,:bb2,:c3,:d3,:eb3,:d3,:c3,:d3,:c3,:b2]
d3b = [q*24,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+c,q,q,q,q,q,q,q]
#26
n3b.concat [:c3,:a3,:bb2,:g3,:a3,:g3,:fs3,:g3,:f3,:eb3,:d3,:e3,:fs3,:g3,:a3,:bb3,:fs3,:g3,:eb3,:c3,:d3,:g3,:c4,:g3,:a3,:bb3,:f3,:g3,:a3,:f3,:g3,:a3]
d3b.concat [c,q,c,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd,c,q,c,q,md,q,q,q,q,q,q,c,q,c,q]
#30
n3b.concat [:bb3,:fs3,:g3,:a3,:e3,:f3,:g3,:d3,:eb3,:f3,:c3,:d3,:eb3,:b2,:c3,:d3,:a2,:b2,:c3,:d3,:eb3,:f3,:g3,:ab3,:g3,:a3,:b3,:c3,:d3,:eb3,:f3,:g3,:ab3,:b2,:c3,:d3]
d3b.concat [q]*12*3
#33
n3b.concat [:eb3,:ab3,:d3,:g3,:c3,:r,:bb3,:a3,:r,:g3,:f3,:r,:eb3,:fs2,:g2,:a2,:bb2,:c3,:d3,:eb3,:c3,:g3,:a3,:bb3,:c3]
d3b.concat [c,q,c,q,c,cd,q,cd,c,q,cd,c,q,q,q,q,q,q,q,q,q,q,q,q,q]
#36
n3b.concat [:bb3,:g3,:d3,:c4,:e3,:fs3,:g3,:d3,:bb2,:ab3,:c3,:d3,:eb3,:bb2,:g2,:f3,:a2,:b2,:c3,:r,:g2,:r,:e2,:r,:fs2,:r,:g2,:r,:a2,:r]
d3b.concat [q]*18+[c,q,c,q,c,q,c,q,c,q,c,q]
#39
n3b.concat [:bb2,:r,:c3,:r,:d3,:r,:e3,:r,:fs3,:d2,:e2,:fs2,:g2,:r,:a2,:r,:bb2,:r,:c3,:r,:d3,:e3,:fs3,:g2,:a2,:bb2]
d3b.concat [c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,q,q,q,q,q,q]
#42
n3b.concat [:c3,:d3,:eb3,:fs2,:g2,:a2,:bb2,:eb3,:a2,:d4,:eb4,:d4,:c4,:bb3,:a3,:g3,:fs3,:a3,:d3,:c3,:bb2,:a2,:bb2,:g3,:c3,:d3,:c3,:d3,:g2,:bb2,:d3,:g3]
d3b.concat [q,q,q,q,q,q,c,q,c,q]+[q]*12+ritqb+[c*1.2]
end
define :part1 do
  with_fx :level do |x| #control level
    in_thread do #dynamics thread
      ct(x,mf,0)
      sleep 13*q
      ct(x,mp,6*q)
      sleep 6*q
      ct(x,mf,6*q)
      sleep 30*q #5
      ct(x,p,12*q)
      sleep 12*q
      ct(x,f,6*q)
      sleep 3*12*q+3*q #4th 9
      ct(x,p,15*q) #end at 11
      sleep 15*q+2*q
      ct(x,f,22*q) #end at 13
      sleep 34*q #till 14
      ct(x,ff,6*q)
      sleep 6*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,ff,6*q)
      sleep 6*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,ff,18*q)
      sleep 18*q
      ct(x,f,6*q)
      sleep 6*q #end mid 17
      ct(x,ff,9*q)
      sleep 9*q
      ct(x,f,8*q)
      sleep 8*q
      ct(x,ff,0) #last q of 18
      sleep 25*q
    end
    in_thread do
      plarray(n1,d1)
    end
    in_thread do
      plarray(n2,d2)
    end
    plarray(n3,d3)
  end
end
define :part2 do
  with_fx :level do |x|
    in_thread do #dynamics thread
      ct(x,mf,0)
      sleep 25*q #end at start 23
      ct(x,f,47*q) #end last q of 26
      sleep 82*q #till last beat 22
      ct(x,mf,21*q) #till 24 3rd beat
      sleep 29*q #until 3rd q 25
      ct(x,f,10) #till start 26
      sleep 16*q
      ct(x,p,18*q) #to last q 27
      sleep 21*q
      ct(x,f,9*q) #to start 29
      sleep 18*q
      ct(x,mf,9*q)
      sleep 15*q
      ct(x,f,12*q) #end 31
      sleep 12*q
      ct(x,mf,6)
      sleep 9*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,p,6*q)
      sleep 10*q
      ct(x,f,25*q)
      sleep 32*q
      ct(x,mf,17*q)
    end
    in_thread do
      plarray(n1b,d1b)
    end
    in_thread do
      plarray(n2b,d2b)
    end
    plarray(n3b,d3b)
  end
end
parts #setup parts arraya
part1
part1
part2
setbpm(170)
lset #reset length variables
parts #reset parts arrays
part2

Now the first part of the sample based program

#Bach Minuet in G Minor from English Suite 3 (part 1). Coded by Robin Newman December 2014
#sample based version in two parts synced together. Start part 2 then part 1
set_sched_ahead_time! 3

use_sample_pack '/Users/rbn/Desktop/samples/GrandPiano/' #select and adjust as necessary
#use_sample_pack '/home/pi/samples/GrandPiano'
#select loud (f) or soft (p) piano samples
ps="piano_f_"
#ps="piano_p_"
rt=2**(1.0/12)  #12th root of 2
irt=1.0/rt #inverse of above

define :sname do |sn,n| #generates sample name for selected pack
  return (sn+n).intern
end
#array holding sample info for each note: [note, sample name, rate to play]
sam = [[:c1,sname(ps,"c1"),1],[:cs1,sname(ps,"c1"),rt]]
sam.concat [[:d1,sname(ps,"ds1"),irt],[:ds1,sname(ps,"ds1"),1],[:e1,sname(ps,"ds1"),rt]]
sam.concat [[:f1,sname(ps,"fs1"),irt],[:fs1,sname(ps,"fs1"),1],[:g1,sname(ps,"fs1"),rt]]
sam.concat [[:gs1,sname(ps,"a1"),irt],[:a1,sname(ps,"a1"),1],[:as1,sname(ps,"a1"),rt]]
sam.concat [[:b1,sname(ps,"c2"),irt],[:c2,sname(ps,"c2"),1],[:cs2,sname(ps,"c2"),rt]]
sam.concat [[:d2,sname(ps,"ds2"),irt],[:ds2,sname(ps,"ds2"),1],[:e2,sname(ps,"ds2"),rt]]
sam.concat [[:f2,sname(ps,"fs2"),irt],[:fs2,sname(ps,"fs2"),1],[:g2,sname(ps,"fs2"),rt]]
sam.concat [[:gs2,sname(ps,"a2"),irt],[:a2,sname(ps,"a2"),1],[:as2,sname(ps,"a2"),rt]]
sam.concat [[:b2,sname(ps,"c3"),irt],[:c3,sname(ps,"c3"),1],[:cs3,sname(ps,"c3"),rt]]
sam.concat [[:d3,sname(ps,"ds3"),irt],[:ds3,sname(ps,"ds3"),1],[:e3,sname(ps,"ds3"),rt]]
sam.concat [[:f3,sname(ps,"fs3"),irt],[:fs3,sname(ps,"fs3"),1],[:g3,sname(ps,"fs3"),rt]]
sam.concat [[:gs3,sname(ps,"a3"),irt],[:a3,sname(ps,"a3"),1],[:as3,sname(ps,"a3"),rt]]
sam.concat [[:b3,sname(ps,"c4"),irt],[:c4,sname(ps,"c4"),1],[:cs4,sname(ps,"c4"),rt]]
sam.concat [[:d4,sname(ps,"ds4"),irt],[:ds4,sname(ps,"ds4"),1],[:e4,sname(ps,"ds4"),rt]]
sam.concat [[:f4,sname(ps,"fs4"),irt],[:fs4,sname(ps,"fs4"),1],[:g4,sname(ps,"fs4"),rt]]
sam.concat [[:gs4,sname(ps,"a4"),irt],[:a4,sname(ps,"a4"),1],[:as4,sname(ps,"a4"),rt]]
sam.concat [[:b4,sname(ps,"c5"),irt],[:c5,sname(ps,"c5"),1],[:cs5,sname(ps,"c5"),rt]]
sam.concat [[:d5,sname(ps,"ds5"),irt],[:ds5,sname(ps,"ds5"),1],[:e5,sname(ps,"ds5"),rt]]
sam.concat [[:f5,sname(ps,"fs5"),irt],[:fs5,sname(ps,"fs5"),1],[:g5,sname(ps,"fs5"),rt]]
sam.concat [[:gs5,sname(ps,"a5"),irt],[:a5,sname(ps,"a5"),1],[:as5,sname(ps,"a5"),rt]]
sam.concat [[:b5,sname(ps,"c6"),irt],[:c6,sname(ps,"c6"),1],[:cs6,sname(ps,"c6"),rt]]
sam.concat [[:d6,sname(ps,"ds6"),irt],[:ds6,sname(ps,"ds6"),1],[:e6,sname(ps,"ds6"),rt]]
sam.concat [[:f6,sname(ps,"fs6"),irt],[:fs6,sname(ps,"fs6"),1],[:g6,sname(ps,"fs6"),rt]]
sam.concat [[:gs6,sname(ps,"a6"),irt],[:a6,sname(ps,"a6"),1],[:as6,sname(ps,"a6"),rt]]
sam.concat [[:b6,sname(ps,"c7"),irt],[:c7,sname(ps,"c7"),1],[:cs7,sname(ps,"c7"),rt]]
sam.concat [[:d7,sname(ps,"ds7"),irt],[:ds7,sname(ps,"ds7"),1],[:e7,sname(ps,"ds7"),rt]]
sam.concat [[:f7,sname(ps,"fs7"),irt],[:fs7,sname(ps,"fs7"),1],[:g7,sname(ps,"fs7"),rt]]
sam.concat [[:gs7,sname(ps,"a7"),irt],[:a7,sname(ps,"a7"),1],[:as7,sname(ps,"a7"),rt]]
sam.concat [[:b7,sname(ps,"c8"),irt],[:c8,sname(ps,"c8"),1]]
#puts sam

#note aliases to allow flats
flat=[:db1,:eb1,:fb1,:gb1,:ab1,:bb1,:cb2,:db2,:eb2,:fb2,:gb2,:ab2,:bb2,:cb3,:db3,:eb3,:fb3,:gb3,:ab3,:bb3,:cb3,:db4,:eb4,:fb4,:gb4,:ab4,:bb4,:cb4,:db5,:eb5,:fb5,:gb5,:ab5,:bb5,:cb5,:db6,:eb6,:fb6,:gb6,:ab6,:bb6,:cb7,:db7,:eb7,:fb7,:gb7,:ab7,:bb7,:cb8]
sharp=[:cs1,:ds1,:e1,:fs1,:gs1,:as1,:b1,:cs2,:ds2,:e2,:fs2,:gs2,:as2,:b2,:cs3,:ds3,:e3,:fs3,:gs3,:as3,:b3,:cs4,:ds4,:e4,:fs4,:gs4,:as4,:b4,:cs5,:ds5,:e5,:fs5,:gs5,:as5,:b5,:cs6,:ds6,:e6,:fs6,:gs6,:as6,:b6,:cs7,:ds7,:e7,:fs7,:gs7,:as7,:b7]

#add es and bs with aliases
flat.concat [:es1,:es2,:es3,:es4,:es5,:es6,:es7,:bs1,:bs2,:bs3,:bs4,:bs5,:bs6,:bs7]
sharp.concat [:f1,:f2,:f3,:f4,:f5,:f6,:f7,:c2,:c3,:c4,:c5,:c6,:c7,:c8]
extra=[]
flat.zip(sharp).each do |f,s|
  extra.concat [[f,(sam.assoc(s)[1]),(sam.assoc(s)[2])]]
end
sam = sam + extra #add in flat definitions

#definition to play a sample "note" specify note, duration,pan,volume,release type as parameters
define :pl do |n,d=0.2,pan=0,v=0.8,nodamp=0|
  if nodamp == 0
    rt=d #gives reasonable result: experiment with value
  else
    rt = sample_duration(sam.assoc(n)[1]) #release is sample duration time
  end
  sample (sam.assoc(n)[1]),rate: (sam.assoc(n)[2]),attack: 0,sustain: d*0.95,release: rt,amp: v,pan: pan
end

define :ntosym do |n| #this returns the equivalent note symbol to an input integer e.g. 59 => :b4
  @note=n % 12
  @octave = n / 12 - 1
  #puts @octave #for debugging
  #puts @note
  lookup_notes = {
    0  => :c,
    1  => :cs,
    2  => :d,
    3  => :ds,
    4  => :e,
    5  => :f,
    6  => :fs,
    7  => :g,
    8  => :gs,
    9  => :a,
    10 => :as,
  11 => :b}
  return (lookup_notes[@note].to_s + @octave.to_s).to_sym #return the required note symbol
end

define :tr do |nv,shift| #this enables transposition of the note. Shift is number of semitones to move
  if shift ==0 then
    return nv
  else
    return ntosym(note(nv)+shift)
  end
end

define :plarray do |nt,dur,shift=0,vol=0.6,pan=0| #This plays associated arrays of notes and durations, transposing if set, and handling rests
  nt.zip(dur).each do |n,d|
    if n != :r then
      #puts n
      pl(tr(n,shift),d,pan)
    end
    sleep d
  end
end

cue :part2

Finally the second part of the sample based program

#BachGigueInGMinor (part 2) coded by Robin Newman, December 2014
#sample based version. (two parts synced together: staret this part first, then part 1)
sync :part2
use_sample_pack '/Users/rbn/Desktop/samples/GrandPiano/' #select and adjust as necessary
#use_sample_pack '/home/pi/samples/GrandPiano'

#select loud (f) or soft (p) piano samples
#ps="piano_f_"
ps="piano_p_"

s=0
define :setbpm do |n| #set bpm equivalent
  s = (1.0 / 8) *(60.0/n.to_f)
end
setbpm(180)
dsq=sq=q=qd=c=cd=cdd=m=md=0

define :lset do
  dsq = 1 * s #demi-semi-quaver
  sq = 2 * s #semi-quaver
  q = 4 * s #quaver
  qd = 6 * s #quaver dotted
  c = 8 * s #crotchet
  cd = 12 * s #crotchet dotted
  m = 16 * s #minim
  md = 24 * s #minim dotted
end
lset
p=0.15
mp=0.2
mf=0.4
f=0.8
ff=1.6
define :ct do |ptr,lev,slid=0|
  control ptr,amp: lev,amp_slide: slid
end

ritq=ritqb=d1=d2=d3=d1b=d2b=d3b=n1=n2=n3=n1b=n2b=n3b=[] #define global scope
define :parts do
ritq=[q*1.02,q*1.04,q*1.06,q*1.08,q*1.1,q*1.12]
ritqb=[q*1.02,q*1.04,q*1.06,q*1.08,q*1.1,q*1.2,q*1.4,q*1.6,q*1.8]
n1=[:d5,:eb5,:d5,:c5,:bb4,:a4,:g4,:fs4,:a4,:d4,:c4,:bb3,:a3,:bb3,:d4,:g4,:a3,:g4,:fs4,:g4,:bb4,:a4,:bb4,:d5,:c5]
d1=[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#3
n1.concat [:d5,:e5,:f5,:e5,:f5,:g5,:a5,:g5,:f5,:g5,:f5,:e5,:f5,:g5,:a5,:d5,:c5,:bb4,:c5,:d5,:bb4,:c5]
d1.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+c,q,c,q]
#6
n1.concat [:a4,:bb4,:c5,:d5,:bb4,:c5,:d5,:e5,:fs5,:g5,:a5,:g5,:f5,:e5,:f5,:eb5,:d5,:c5,:d5,:c5,:bb4,:a4,:bb4,:r,:a4,:r,:a4,:g4,:a4,:r,:e4,:g4]
d1.concat [c,q,c,q,c,q,cd+c,q,cd,cd,cd+cd,cd+q,q,q,cd+cd,cd+q,q,q,cd+cd,cd+q,q,q,cd,q,c,q,q,q,cd,q,q,q]
#12
n1.concat [:f4,:g4,:a4,:g4,:a4,:bb4,:a4,:d5,:f5,:g4,:g5,:e5,:f5,:a5,:g5,:a5,:a4,:cs5,:b4,:c5,:e5,:d5,:e5,:e4,:g4,:f4]
d1.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,cd,q,q,q,q,q,q,cd,q,q,q]
#15
n1.concat [:g4,:bb4,:a4,:bb4,:cs4,:e4,:d4,:e4,:g4,:f4,:g4,:bb4,:a4,:bb4,:a4,:g4,:cs5,:bb4,:a4,:d5,:a4,:g4,:e5,:a4,:g4,:f4,:g4,:e4,:f4,:e4,:d4,:g4,:e4,:d4]
d1.concat [q,q,q,cd]+[q]*30
#18
n1.concat [:a4,:e4,:d4,:bb4,:e4,:d4,:cs4,:d4,:e4,:a3,:r,:a5,:bb5,:a5,:g5,:f5,:e5,:d5,:cs5,:e5,:a4,:g4,:f4,:e4,:f4,:a4,:d5,:e4,:d5,:cs5,:d5,:a4,:fs4,:d4]
d1.concat [q]*27+ritq+[c*1.12]
#end part 1
n2=[:r,:g4,:bb4,:a4,:g4,:f4,:e4,:d4,:cs4,:e4,:a3,:g3,:f3,:e3,:f3,:a3,:d4,:e3,:d4,:cs4,:d4,:e4,:f4,:e4,:fs4,:g4,:a4,:g4,:fs4,:g4,:fs4,:e4]
d2=[q*24]+[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+q,q,q,q,q,q,q,q,q]
#6
n2.concat [:fs4,:e4,:d4,:e4,:g4,:fs4,:g4,:a4,:bb4,:a4,:bb4,:c5,:d5,:c5,:bb4,:c5,:bb4,:a4,:bb4,:a4,:g4,:f4,:eb4,:d4,:f4,:e4,:f4,:e4,:d4,:cs4,:b3,:cs4]
d2.concat [q,q,q,q,q,q,cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,md,md,md,md,md,cd+q,q,q,c,q,cd+q,q,q,cd]
#12
n2.concat [:d4,:e4,:f4,:e4,:f4,:g4,:a4,:g4,:r]
d2.concat [cd+q,q,q,cd+q,q,q,cd,cd,cd*2+72*q+9.42*q+c*1.2] #rit at end
#end part 1
n3=[:r,:d4,:eb4,:d4,:c4,:bb3,:a3,:g3,:fs3,:a3,:d3,:c3,:bb2,:a2,:bb2,:d3,:g3,:a2,:g3,:fs3,:g3,:bb3,:a3,:bb3,:d4,:c4,:d4,:a3,:d3]
d3=[q+60*q+5*q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q]
#9

n3.concat [:eb3,:g3,:f3,:g3,:bb3,:a3,:bb3,:f3,:bb2,:c3,:eb3,:d3,:eb3,:g3,:f3,:g3,:cs3,:d3,:c3,:bb2,:c3,:bb2,:a2,:r,:a3]
d3.concat [q,q,q,q,q,q,cd+q,q,q,q,q,q,q,q,q,cd+c,q,c,q,sq,sq,c,cd,c,q]
#12
n3.concat [:bb3,:a3,:g3,:f3,:e3,:d3,:cs3,:e3,:a2,:g2,:g2,:e2,:f2,:a2,:d3,:e2,:d3,:cs3,:d3,:f3,:e3,:f3,:a3,:g3,:a3,:a2,:cs3,:b2,:cs3,:e3,:d3]
d3.concat [q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,q,q,q,cd,q,q,q,q,q,q]
#15

n3.concat [:e3,:g3,:f3,:g3,:bb3,:a3,:bb3,:g3,:f3,:e3,:f3,:g3,:a2,:r,:b2,:r,:cs3,:a2,:b2,:cs3,:d3,:r,:e3,:r]
d3.concat [cd+q,q,q,cd+q,q,q,q,q,q,q,q,q,c,q,c,q,c,q,c,q,c,q,c,q]
#18
n3.concat [:f3,:r,:g3,:f3,:e3,:f3,:cs4,:d4,:g3,:cs4,:d4,:gs3,:cs4,:d4,:a3,:cs4,:d4,:e4,:d4,:cs4,:d4,:f3,:g3,:a3,:g3,:a3,:d3,:fs3,:a3,:d4]
d3.concat [c,q,cd+q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]+ritq+[c*1.12]
#end part1
n1b=[:a3,:fs3,:g3,:a3,:bb3,:c4,:d4,:eb4,:c4,:g4,:a4,:bb4,:c5,:bb4,:g4,:d4,:c5,:e4,:fs4,:g4,:e4,:f4,:e4,:cs4,:d4,:a4,:g4,:f4,:g4,:f4,:e4]
d1b=[q]*25+[cd+q,q,q,cd+q,q,q]
#24
n1b.concat [:d4,:e4,:f4,:e4,:a4,:g4,:f4,:eb4,:d4,:bb4,:a4,:g4,:a4,:g4,:fs4,:g4,:eb5,:f4,:d5,:r,:g4,:fs4,:g4,:a4,:bb4,:c5,:d5,:eb5,:c5,:g5,:a5,:bb5,:c6,:bb5,:g5,:d5,:c6,:e5,:fs5,:g5,:d5,:eb5,:f5,:c5,:d5]
d1b.concat [q,q,q,q,q,q,q,q,q,cd+q,q,q,q,q,q,c,q,c,q,11*q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#29
n1b.concat [:eb5,:f5,:e5,:f5,:e5,:d5,:e5,:f5,:c5,:d5,:eb5,:bb4,:c5,:d5,:a4,:bb4,:c5,:g4,:a4,:bb4,:g5,:ab4,:f5,:g4,:eb5,:f4,:d5,:eb4,:f4,:g4,:d4,:eb4,:c4]
d1b.concat [cd,sq,sq,sq,sq,sq,sq,q,q,q,q,q,q,q,q,q,q,q,q,c,q,c,q,c,q,c,q,q,q,q,q,q,q]
#32
n1b.concat [:b3,:c4,:d4,:eb4,:f4,:g4,:ab4,:f4,:c5,:d5,:eb5,:f5,:g5,:eb5,:c5,:f5,:a4,:b4,:eb5,:c5,:a4,:d5,:fs4,:g4,:c5,:a4,:fs4,:bb4,:d4,:eb4,:a4,:f4,:d4,:g4,:bb3,:c4]
d1b.concat [q]*36
#35
n1b.concat [:d4,:e4,:fs4,:g4,:a4,:bb4,:c5,:d5,:eb5,:d5,:bb5,:eb5,:d5,:c5,:bb4,:g5,:c5,:bb4,:ab4,:g4,:eb5,:ab4,:g4,:f4,:eb4,:c5,:eb4,:d4,:c5,:bb4,:c4,:bb4,:a4,:d4,:c5,:bb4,:e4,:d5,:c5,:fs4,:eb5,:d5]
d1b.concat [cd+q,q,q,q,q,q,q,q,q,c,q,q,q,q,c,q,q,q,q,c,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]
#39

n1b.concat [:g4,:c5,:bb4,:a4,:bb4,:g4,:fs4,:eb4,:d4,:g4,:d4,:c4,:a4,:d4,:c4,:bb3,:c4,:a3,:bb3,:a3,:g3,:c4,:a3,:g3,:d4,:a3,:g3,:eb4,:a3,:g3,:fs3,:g3,:a3,:bb3,:c4,:d4]
d1b.concat [q]*3*12
#42
n1b.concat [:eb4,:c4,:g4,:a4,:bb4,:c5,:d5,:bb4,:g4,:c5,:e4,:fs4,:g4,:d5,:g5,:f5,:eb5,:d5,:c5,:bb4,:a4,:g4,:fs4,:g4,:eb5,:d5,:bb4,:c5,:bb4,:a4,:g4,:g4,:d4,:bb3,:g3]
d1b.concat [q]*12+[c]+[q]*10+ritqb[0..2]+[dsq*1.08,dsq*1.08,sq*1.08]+ritqb[4..-1]+[c*1.2]
#end part 2
n2b=[:r,:eb4,:d4,:c4,:d4,:c4,:bb3,:c4,:a4,:bb3,:c4,:d4,:c4,:bb3,:c4,:bb3,:a3,:g3,:a3,:bb3,:c4,:bb3,:c4,:b3,:c4,:b3,:a3,:b3,:r]
d2b=[q*61,q,q,q,q,q,q,c,q,c,q,cd+q,q,q,cd+q,q,q,cd,q,q,q,cd,sq,sq,sq,sq,sq,sq,q*12*15+11.3*q+c*1.2]
#end part 2
n3b = [:r,:d2,:cs2,:d2,:e2,:f2,:g2,:a2,:bb2,:g2,:d3,:e3,:f3,:g3,:f3,:d3,:a2,:g3,:b2,:cs3,:d3,:c3,:bb2,:c3,:d3,:eb3,:d3,:c3,:d3,:c3,:b2]
d3b = [q*24,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd+c,q,q,q,q,q,q,q]
#26
n3b.concat [:c3,:a3,:bb2,:g3,:a3,:g3,:fs3,:g3,:f3,:eb3,:d3,:e3,:fs3,:g3,:a3,:bb3,:fs3,:g3,:eb3,:c3,:d3,:g3,:c4,:g3,:a3,:bb3,:f3,:g3,:a3,:f3,:g3,:a3]
d3b.concat [c,q,c,q,q,q,q,q,q,q,q,q,q,cd+q,q,q,cd,c,q,c,q,md,q,q,q,q,q,q,c,q,c,q]
#30
n3b.concat [:bb3,:fs3,:g3,:a3,:e3,:f3,:g3,:d3,:eb3,:f3,:c3,:d3,:eb3,:b2,:c3,:d3,:a2,:b2,:c3,:d3,:eb3,:f3,:g3,:ab3,:g3,:a3,:b3,:c3,:d3,:eb3,:f3,:g3,:ab3,:b2,:c3,:d3]
d3b.concat [q]*12*3
#33
n3b.concat [:eb3,:ab3,:d3,:g3,:c3,:r,:bb3,:a3,:r,:g3,:f3,:r,:eb3,:fs2,:g2,:a2,:bb2,:c3,:d3,:eb3,:c3,:g3,:a3,:bb3,:c3]
d3b.concat [c,q,c,q,c,cd,q,cd,c,q,cd,c,q,q,q,q,q,q,q,q,q,q,q,q,q]
#36
n3b.concat [:bb3,:g3,:d3,:c4,:e3,:fs3,:g3,:d3,:bb2,:ab3,:c3,:d3,:eb3,:bb2,:g2,:f3,:a2,:b2,:c3,:r,:g2,:r,:e2,:r,:fs2,:r,:g2,:r,:a2,:r]
d3b.concat [q]*18+[c,q,c,q,c,q,c,q,c,q,c,q]
#39
n3b.concat [:bb2,:r,:c3,:r,:d3,:r,:e3,:r,:fs3,:d2,:e2,:fs2,:g2,:r,:a2,:r,:bb2,:r,:c3,:r,:d3,:e3,:fs3,:g2,:a2,:bb2]
d3b.concat [c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,c,q,q,q,q,q,q,q]
#42
n3b.concat [:c3,:d3,:eb3,:fs2,:g2,:a2,:bb2,:eb3,:a2,:d4,:eb4,:d4,:c4,:bb3,:a3,:g3,:fs3,:a3,:d3,:c3,:bb2,:a2,:bb2,:g3,:c3,:d3,:c3,:d3,:g2,:bb2,:d3,:g3]
d3b.concat [q,q,q,q,q,q,c,q,c,q]+[q]*12+ritqb+[c*1.2]
end
define :part1 do
  with_fx :level do |x|
    in_thread do
      ct(x,mf,0)
      sleep 13*q
      ct(x,mp,6*q)
      sleep 6*q
      ct(x,mf,6*q)
      sleep 30*q #5
      ct(x,p,12*q)
      sleep 12*q
      ct(x,f,6*q)
      sleep 3*12*q+3*q #4th 9
      ct(x,p,15*q) #end at 11
      sleep 15*q+2*q
      ct(x,f,22*q) #end at 13
      sleep 34*q #till 14
      ct(x,ff,6*q)
      sleep 6*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,ff,6*q)
      sleep 6*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,ff,18*q)
      sleep 18*q
      ct(x,f,6*q)
      sleep 6*q #end mid 17
      ct(x,ff,9*q)
      sleep 9*q
      ct(x,f,8*q)
      sleep 8*q
      ct(x,ff,0) #last q of 18
      sleep 25*q
    end
    in_thread do
      plarray(n1,d1)
    end
    in_thread do
      plarray(n2,d2)
    end
    plarray(n3,d3)
  end
end
define :part2 do
  with_fx :level do |x|
    in_thread do
      ct(x,mf,0)
      sleep 25*q #end at start 23
      ct(x,f,47*q) #end last q of 26
      sleep 82*q #till last beat 22
      ct(x,mf,21*q) #till 24 3rd beat
      sleep 29*q #until 3rd q 25
      ct(x,f,10) #till start 26
      sleep 16*q
      ct(x,p,18*q) #to last q 27
      sleep 21*q
      ct(x,f,9*q) #to start 29
      sleep 18*q
      ct(x,mf,9*q)
      sleep 15*q
      ct(x,f,12*q) #end 31
      sleep 12*q
      ct(x,mf,6)
      sleep 9*q
      ct(x,f,3*q)
      sleep 3*q
      ct(x,p,6*q)
      sleep 10*q
      ct(x,f,25*q)
      sleep 32*q
      ct(x,mf,17*q)
    end
    in_thread do
      plarray(n1b,d1b)
    end
    in_thread do
      plarray(n2b,d2b)
    end
    plarray(n3b,d3b)
  end
end
parts
part1
part1
part2
setbpm(170)
lset
parts
part2

As you will see, the sample based and synth based programs are very similar.

In order to play the sample based program you will need the samples for the GrandPiano. In fact there are TWO sets of piano samples, and they are both contained in the download. You can select which set to use by simply altering one variable in the first part of the sample program, selecting either ps=”piano_f_” for a load percussive piano or ps=”piano_p” for a softer played set of samples.

Downloads

The GrandPiano Samples. These should be unzipped and stored in a samples folder on your RaspberryPi or on your Mac or PC, and the path in both parts of the sample programs altered accordingly.

The synth program
The sample program part 1
The sample program part 2

You can hear three recordings on SoundCloud here (played one after the other)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s