So, Phil is always playing around with the amazing Sonic Pi (By Sam Aaron)… if you’ve not got it, you really should download it… it’s an amazing & FUN tool to make music with AND learn / push your Ruby programming…
So! Phil has been working on making “live sounding” drums in Sonic Pi for a while, as well as an ability to create different patters & the ability to create structures (“songs”) – he’s come up with this:
One of the helpful aspects to this set up is, the beautifully recorded free drum samples from Judd Madden ( http://juddmadden.com/drum-samples.html ). The drum sounds in Sonic Pi are great, but Judd’s samples are absolutely superb.
Phil has commented the code as best he can, if you do try to reproduce this, you’ll need to save the drum samples into the right folders…
use_debug false
use_cue_logging false
use_bpm 120
d_root = "C:/Drums/twi"
drums_bass = "Kick/"
drums_snare = "Snares/"
drums_hat = "Hats/"
drums_cymbal = "Cymbals/"
drums_tom = "Toms/"
#......[1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
# some patterns for bass / snare
bds0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
bds1 = [1,0,0,0,0,0,0,0,0,0,0,0]
bds2 = bds1 + [2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,0,0,2,0]
bds3 = [1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0]
sns0 = bds0
sns1 = [0,0,1,0,0,0,0,0]
sns2 = sns1 + [2,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3]
sns3 = [0,0,1,0,0,0,0,0,0,0,2,0,0,0,3,0]
#some constants (rr = random range to draw from)
@rr = 12
@mc = 0
@sec = "intro"
# sections is an Array that holds arrays with "section" and a range as to when they should play.
# we later use the values to calculate how long the "main loop" sleeps for before moving to the next position/section
sections = [
["intro", (0..0).to_a],
["space", (1..1).to_a],
["build", (2..5).to_a],
["filler", (6..7).to_a],
["main", (8..15).to_a],
["filler", (16..17).to_a],
["main", (18..25).to_a],
["end", (26..26).to_a]
]
# change to true to introduce the various drums to the mix
# "parts" is a HASH that holds info on what drums to play for each section
parts = {
"intro" => {'bds' => false,
'sns' => false,
'hts' => false,
'cym' => true,
'spl' => false,
'tms' => true,
'rnd' => false},
"build" => {'bds' => true,
'sns' => false,
'hts' => true,
'cym' => true,
'spl' => false,
'tms' => false,
'rnd' => false},
"main" => {'bds' => true,
'sns' => true,
'hts' => true,
'cym' => true,
'spl' => true,
'tms' => false,
'rnd' => false},
"filler" => {'bds' => true,
'sns' => true,
'hts' => true,
'cym' => true,
'spl' => false,
'tms' => true,
'rnd' => true},
"space" => {'bds' => false,
'sns' => true,
'hts' => true,
'cym' => true,
'spl' => true,
'tms' => false,
'rnd' => false},
"end" => {'bds' => false,
'sns' => false,
'hts' => false,
'cym' => false,
'spl' => false,
'tms' => false,
'rnd' => false}
}
# a HAS that holds info on what patterns to play for what section
drumsForSections = {
"intro" => {"bds" => bds0, "sns"=> sns0},
"build" => {"bds" => bds1, "sns"=> sns0},
"main" => {"bds" => bds2, "sns"=> sns2},
"filler" => {"bds" => bds2, "sns"=> sns3},
"space" => {"bds" => bds3, "sns"=> sns3},
"end" => {"bds" => bds0, "sns"=> sns0},
}
# main counter keeps track of what section we should use
# we "sleep" for bar * (end - start) & pt in "8 beats" if the value of e-s = 0
live_loop :mainCount do
bar = 8
tick
# get the name of the section from the sections array via "look" (the value of tick on this loop)
@sec = sections[look][0]
puts @sec # show the current section name
if @sec == "end"
stop
else
if @sec == "main"
# each loop if "main" starts with a Crash Cymbal
sample d_root+drums_cymbal, "Crash C #{rand_i(4)+1}"
end
# calculate how long we should sleep for from this sections start / end numbers * 8 beats
s = sections[look][1][0]
e = sections[look][1][-1]
zzz = (e-s)*bar
if zzz == 0
zzz = 8
end
sleep zzz
end
end
# ========== drum tracks in separate live_loops
live_loop :ride do
# simple ride cymbal playing each beat, if "true"
if parts[@sec]["cym"]then
# randomise the ride sample used & vary the amp value
sample d_root+drums_cymbal, "Ride Cymbal #{rand_i(2) + 1}", amp: rand(0.4) + 0.8
end
sleep 1
end
live_loop :bd do
tick
# bass drum plays, if "true"
if parts[@sec]["bds"] then
# we look in the "drumsForSections" in the current section (e.g. "intro") then the "bds" for that section
# if the beat ISN'T a 0, we play the BD sample.
if drumsForSections[@sec]["bds"].look != 0 then
sample d_root+drums_bass, rand_i(3) + 1, amp: rand(0.4) + 0.8
# if it's the start of a bar (8 beats) we add in a bd_boom
if look % 8 == 0 then
sample :bd_boom
end
end
end
sleep 0.25
end
# an array for different types of snares
snlist = [0, "Off", "On", "Flam"]
live_loop :sn do
tick
with_fx :pan, pan: -0.25 do
# we look in the "drumsForSections" in the current section (e.g. "intro") then the "sns" for that section
if parts[@sec]["sns"] then
# if the beat ISN'T a 0, we play the Snare sample.
# and also use the number to pull in the specific snare style (Off, On, Flam)
if drumsForSections[@sec]["sns"].look != 0 then
sample d_root+drums_snare, snlist[drumsForSections[@sec]["sns"].look], pick, amp: rand(0.4) + 0.6
end
end
sleep 0.25
end
end
live_loop :splash do
tick
p = 0
# if splashes are to play ( in parts : 'spl' => true )
if parts[@sec]["spl"] then
sample d_root+drums_cymbal, "Crash", "A", pick, amp: rand(0.4) + 0.8, pan: 0.3
# add a random china bell hit for variance
if (1..3).include? rand_i(@rr) then
sleep 1.5
p = 1.5
sample d_root+drums_cymbal, "China", "Bell", pick, amp: rand(0.4) + 0.8, pan: 0.3
end
end
sleep 8 - p
end
# set up some arrays for the Tom Filler
# tom spread will sequentially play the specific tm type (2xhigh 2xmid, 2xFloor here)
tomspread = ["high", "high", "mid", "mid", "floor", "floor"].ring
# we can also pan the tom hits from left to right
tompan = [-0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6].ring
# a counter to keep track of what tom to play in tomspread
tomtick = 0
live_loop :tm do
# if "tms" is true for this section
if parts[@sec]["tms"] then
# check for "rnd" for potential tom hit randomisation
if parts[@sec]["rnd"]
if rand_i(@rr) == 0 then
sample d_root+drums_tom, tomspread[tomtick], pick, amp: rand(0.4) + 0.4, pan: tompan[tomtick]
tomtick = tomtick+1
end
else
sample d_root+drums_tom, tomspread[tomtick], pick, amp: rand(0.4) + 0.4, pan: tompan[tomtick]
tomtick = tomtick+1
end
end
sleep 0.25
end
If you have any questions or comments, do get in touch!