Skip to content

Instantly share code, notes, and snippets.

@amosr
Created January 2, 2018 05:51
Show Gist options
  • Save amosr/2c8e2c7bc18c5c10e4972aaf1a3b416e to your computer and use it in GitHub Desktop.
Save amosr/2c8e2c7bc18c5c10e4972aaf1a3b416e to your computer and use it in GitHub Desktop.
sonic pi
# random drum machine
# an array of times for when samples should play
# we'll have a corresponding array for which
# sample to sound at a particular time
def times_beat(i)
# beats, quarter beats, and triplets
times_one = [0, 1.0/4, 1.0/3, 1.0/2.0, 2.0/3, 3.0/4]
times_one.map {|j| j + i}
end
# how likely we are to play a sound at a particular time
# the beat is a normal place to play something so 1/4 chance
# quarter beat is a little stranger so only 1/7 chance, etc
probs_one = [4, 7, 8, 6, 10, 9]
# four beats to a bar
times = (times_beat 0) + (times_beat 1) + (times_beat 2) + (times_beat 3)
probs = probs_one * 4
# lots of samples to choose from
sample_choices = [:ambi_choir, :drum_bass_hard, :drum_bass_soft, :drum_cowbell, :drum_cymbal_closed, :drum_cymbal_hard, :drum_snare_hard, :elec_triangle, :elec_snare, :elec_lo_snare, :elec_hi_snare, :elec_mid_snare, :elec_cymbal, :elec_soft_kick, :elec_filt_snare, :elec_fuzz_tom, :elec_chime, :elec_bong, :elec_twang, :elec_wood, :elec_pop, :elec_beep, :elec_blip, :elec_blip2, :elec_ping, :elec_bell, :elec_flip, :elec_tick, :elec_hollow_kick, :elec_twip, :elec_plip, :elec_blup]
# start off with no samples playing, nil for each time
# as the loop runs we will modify this a bit
# but each loop will be based on the previous to give some kind of development
samples = [nil] * times.length
live_loop :drummer do
# cool sounds need cool effects
with_fx :krush do
with_fx :flanger, feedback: 0.5 do
with_fx :slicer, phase: 0.25 do
prev = 0
# see what samples are currently playing
active = samples.select {|i| i != nil}
# play one bar, mutating the drum pattern as we go
times.length.times do |i|
# figure out how long we need to wait based on
# when we last played a note
at = times[i]
sleep (at - prev)
prev = at
# modify the pattern at this time before playing it
# turn off the sample sometimes
# we don't want the pattern to get too crowded.
# if we have many active notes, make it more likely to kill some
if one_in (times.length - active.length)
samples[i] = nil
end
# should we play a note at this time?
# if so, turn on the sample
if one_in probs[i]
# we have a lot of samples we could choose,
# but the pattern shouldn't go too crazy.
# choose one of the active samples to introduce consistency
if one_in 2 and active.length > 1
samples[i] = active.choose
else
samples[i] = sample_choices.choose
end
end
# play the thing
sample samples[i] if samples[i]
end
# sleep until the start of the next bar
sleep (prev.ceil - prev)
end
end
end
end
ch = scale :c1, :aeolian, num_octaves: 2
print ch
n = 8
def lcm_scaled(a, b)
big = 12
lcm = (a * big).round.lcm (b * big).round
return lcm / big
end
def harmony(root,harmon)
diff = (harmon - root) % 12
freq = 2**(diff / 12.0)
lcm = lcm_scaled 1, freq
return lcm
end
lengths = [0.25, 0.5, 0.25, 0.25, 0.25, 0.5, 0.125, 0.125, 0.25, 0.33333, 0.33333].ring
rests = [false, true, true, true, true, true, true].ring
live_loop :bass do
use_synth :dsaw
with_fx :slicer, phase: 0.25 do
with_fx :krush, amp: 4 do
total = 0
while true
l = lengths.tick :lengths
r = rests.tick :rests
if total + l > 1
break
end
if not r then
play ch[n], sustain: (l * 0.5)
end
sleep l
total += l
end
print total
sleep (total.ceil - total)
root = ch[0]
n_new = n
(-4.upto 4).each do |jump|
prob = harmony root, ch[n+jump]
if jump != 0 and one_in (prob + jump.abs)
n_new = n + jump
end
end
n = n_new
end
end
end
@SnowBird27
Copy link

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment