TR 808 sequencer

Hello World!

Some simple house beats. I like using a ‘sequencer’ function to control the timing, then pass it a series of Procs which define the tracks, one for each instrument - gives you an easy way to control the timing and also the expression of each beat. Also makes mixing in new instruments a breeze.

Note that the kick and snare here are samples, but the hi-hat is a noise synth; wrapping them in functions with the same interface (my_samp, my_hat) means you can treat them the same way when defining your tracks. Feels like a Sonic Pi DSL in the works. Planning to experiment with bass tracks next week :slight_smile:

BPM=120*4

Instruments={
  :kick => :my_samp,
  :snare => :my_samp,
  :hat => :my_hat
}

def my_samp(args)
  sample args[:samp], {
    :amp => args[:amp],
    :beat_stretch => args[:bs]
  }
end

def my_hat(args)
  use_synth :noise
  with_fx :rhpf, cutoff: args[:cut] do
    play args[:note], {
      :amp => args[:amp],
      :release => args[:rel]
    }
  end
end

def sequencer(procs,
              insts=Instruments,
              n=32,
              seed=13)
  use_random_seed(seed)
  n.times do |i|
    procs.keys.each do |k|
      args=procs[k].call(i)
      next unless args[:amp] > 0
      self.send(insts[k], args)
    end
    sleep 60/BPM.to_f
  end
end

Four2Floor={
  :kick => Proc.new do |i|
    pat='XXX--XX-XX----X-XX-X-XX--X-X-X-'
    {:samp => :bd_haus,
     :amp => (pat[i]=='X') ? 1 : 0,
     :bs => (0==i/16) ? 0.25 : 0.30}
  end,
  :snare => Proc.new do |i|
    {:samp => :sn_zome,
     :amp => (4==i%8) ? 1 : 0,
     :bs => 0.3}
  end,
  :hat => Proc.new do |i|
    {:amp => (rand < 0.85) ? 0.3 : 0,
     :note => :f1,
     :cut => rrand(90, 120),
     :rel => 0.0625}
  end
}

live_loop :hello_world do
  with_fx :reverb, mix: 0.25, room: 0.2 do
    sequencer(Four2Floor)
  end
end
2 Likes

Everybody uses their own method, which I’m sure makes
sense to them, or they wouldn’t bother. :slight_smile:

I use a ‘tracking’ variable to switch the audio output of various
live_loops on and off… it allows me to ‘script’ the actual song.

tracker = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

giving loop names values allows me to use them in the
script:

Can get complex, but it works for me…

Eli…

kick=0
hats=1
rim=2
bass=3
background=4
xylophone =5
voice=6
clarinet=7

live_loop :loopy do
  
  start_loop kick
  sleep 8
  stop_loop kick
  sleep 4
end
#Elevation (Final Cut)
#by Eli...

use_bpm 90
# Bass Clarinet
bass_rhythm = (ring 0.25, 0.75, 1, 0.75, 0.25, 0.5, 0.5).shuffle # makes 4 quarters or one bar on the whole
bass_line = (ring :a3, :g3,:d3, :r, :f3, :a3, :r, :g3,:a3, :r, :d3, :g3, :f3, :e3)
bass_room = (ring 100, 150, 200, 300)
bass_cycle = 32 # the complete bassline
bass_phrase = bass_cycle / 4 # One of the four patterns

bass_echo_phase = (ring 0.25, 0.5, 1, 2)

tracker = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
n = (ring :r, :r, :c2, :d3, :r, :f3, :r, :a1, :f2)

set_volume! 5

ripple = (ring, 0,1,)
ripple1 = (ring, 0,1,2)

define :start_loop do |i|
  tracker[i] = 1
end

define :stop_loop do |i|
  tracker[i] = 0
end

define :stop_all do
  tracker[0] = 0
  tracker[1] = 0
  tracker[2] = 0
  tracker[3] = 0
  tracker[4] = 0
  tracker[5] = 0
  tracker[6] = 0
  tracker[7] = 0
  tracker[8] = 0
  tracker[9] = 0
end

live_loop :beats do
  sleep 4
end

live_loop :bar do
  sleep 1
end

live_loop :kick do
  if tracker[0]>0 then
    sample :bd_ada
    sleep 1
    sample :bd_ada
    sample :sn_dolf, sustain: 0, release: 0.08, hpf: 80
    sleep 1
  else
    sleep 1
  end
end

live_loop :bass do
  if tracker[3]>0 then
    if rand(1) > 0.75
      n = (ring :r, :r, :c2, :d3, :r, :f3, :r, :a1, :f2)
    else
      n=n.shuffle
    end
    use_synth :fm
    use_transpose +0
    use_synth_defaults release: 0.125 + rrand(0, 0.2), amp: 0.5, pan: rrand(-0.5, 0.5)
    play n.look, cutoff: rrand(30, 130)
    sleep 0.25
    tick
  else
    sleep 1
  end
end

with_fx :reverb do
  live_loop :bass1 do
    if tracker[3]>0 then
      if one_in(4) then
        sleep 4
      else
        sync :bar
        use_synth :tb303
        use_synth_defaults cutoff: 85, release: 0.15, attack: 0.05, decay: 0.05,
          sustain_level: 0.3, cutoff_sustain_level: 0.7, sustain: 0.1, res: 0.6, amp: 0.2
        4.times do
          play (ring, :c2, :c2, :as1, :f2, :ds2).tick + 0.5, wave: ripple.look+1
          play (ring, :c2, :c2, :as1, :f2, :ds2).look + 0.5, wave: ripple1.look
          sleep (ring, 0.75, 0.75, 0.75, 0.75, 1).look
        end
      end
      ripple.tick
      if one_in 2 then
        ripple1.tick
        sleep 1
      end
    else
      sleep 1
    end
  end
end

with_fx :rhpf, res: 0.85, cutoff: 118, amp: 0.7 do
  live_loop :hats do
    if tracker[1]>0 then
      use_synth_defaults sustain_level: 0.5
      synth :chipnoise, sustain: 0, release: 0.09, freq_band: 15, amp: 0.1
      sleep 0.25
      if rand(1) < 0.75 then
        synth :chipnoise, sustain: 0, release: 0.09, freq_band: 15, amp: 0.05
        sleep 0.125
      else
        sleep 0.125
      end
      sleep 0.125
    else
      sleep 1
    end
  end
end

live_loop :rim do
  if tracker[2]>0 then
    with_fx :distortion do
      sleep 0.5
      use_sample_defaults amp: 0.2
      sample :elec_blip, sustain: 0.006, cutoff:110, rate: 0.8
      sleep 0.25
      sample :elec_blip, sustain: 0.005, cutoff:110, rate: 0.8 if one_in(5)
      sleep 0.25
    end
  else
    sleep 1
  end
end

live_loop :xylophone do
  if tracker[5]>0 then
    use_synth :sine
    use_synth_defaults coef: 0.1, detune: 0.1
    nlen = [1,2,3].choose
    cho = (chord_degree, [:i, :iii, :vi, :v].ring.tick, :f3, :minor, 4)
    if rand() > 0.7 then
      sync :beats
      3.times do
        play scale([:f3, :f4].choose, :minor).choose, amp: 0.25, release: nlen / 2.0
        sleep nlen / 4.0
      end
    else
      sync :bar
      play chord_invert( cho, [-1, 0, 1].choose), amp: 0.6, release: nlen
      sleep nlen
    end
  else
    sleep 0.1
  end
end

live_loop :background do
  if tracker[4]>0 then
    sync :bar
    use_synth :fm
    use_synth_defaults amp: 0.25, attack: 0.0, release: 2
    play (chord [:c4, :eb, :g4].choose, :M7)
    sleep 2
    play (chord :d4, :M7)
    sleep 2
  else
    sleep 0.1
  end
end

vol = (knit 0.75, 3, 0.125, 2, 0.25, 4, 0.35, 3).pick
vol_master = 1

live_loop :voice0 do
  if tracker[6]>0 then
    use_synth :piano
    sync :bar
    bass_line = (chord :a3, :m7, num_octaves: 2)
    sleep 0.25
    if spread([2,4].choose,16).tick
      play bass_line.look, amp: vol.look * vol_master
    end
    
  else
    sleep 0.1
  end
end

live_loop :voice1 do
  if tracker[6]>0 then
    use_synth :pluck
    voice1_line = (chord :c3, :M, num_octaves: 2)
    sync :bar
    spreader = rrand_i(3,8)
    1.times do
      if spread([2,spreader].choose,16).tick
        play voice1_line.look, attack: 0.001, amp: vol.look * vol_master
      end
      sleep 0.25
    end
  else
    sleep 0.1
  end
end

live_loop :voice2 do
  if tracker[6]>0 then
    use_synth :piano
    voice2_line = (chord :d3, :M, num_octaves: 2)
    repeater = [2,3,4].choose
    spreader = rrand_i(3,16)
    sync :bar
    repeater.times do
      if spread([2,spreader].choose,16).tick
        play voice2_line.look, amp: vol.look * vol_master
      end
      sleep 0.25
    end
  else
    sleep 0.1
  end
end

random_add = 1024

live_loop :clarinet do
  
  if tracker[7]>0 then
    use_synth :fm
    use_synth_defaults divisor: 0.5, depth: 4.0, attack: 0.05, sustain: 0, release: [bass_rhythm.look, 0.125].choose,
      amp: 0.5
    random = rand(1)
    if random  > 0.6
      bass_line = (ring :f3, :a3, :r)
    end
    if random  > 0.8
      bass_line = (ring :g3,:a3)
    end
    if random  > 0.9
      bass_line = (ring :a3, :g3,:d3, :r)
    end
    if random  < 0.6
      bass_line = (ring :d3, :g3, :f3, :e3)
    end
    with_fx :reverb, room: 0.75 do
      #with_fx :echo, phase: bass_echo_phase.look, decay: 6 do
      play bass_line.look,release: [bass_rhythm.look, 0.125].choose
      tick
    end
    sleep bass_rhythm.look
  else
    sleep 0.1
  end
end

kick=0
hats=1
rim=2
bass=3
background=4
xylophone =5
voice=6
clarinet=7

live_loop :loopy do
  
  start_loop kick
  sleep 2
  start_loop hats
  sleep 4
  start_loop rim
  sleep 4
  start_loop bass
  sleep 8
  start_loop background
  sleep 32
  stop_loop background
  sleep 8
  start_loop voice
  sleep 48
  stop_loop voice
  sleep 8
  start_loop background
  sleep 32
  stop_loop background
  sleep 8
  start_loop xylophone
  sleep 32
  stop_loop xylophone
  sleep 8
  start_loop background
  sleep 8
  start_loop clarinet
  sleep 48
  stop_loop clarinet
  sleep 8
  stop_loop background
  sleep 8
  start_loop voice
  sleep 48
  stop_loop voice
  sleep 8
  start_loop background
  sleep 48
  stop_loop background
  sleep 8
  start_loop xylophone
  sleep 32
  stop_loop xylophone
  sleep 12
  stop_all
  sample :bd_ada
  sleep 8
end
1 Like

Really nice sound :grinning: But ‘sleep’ everywhere drives me crazy! DRY is a big Ruby thing, does it not extend to SP ?

I believe that since Sonic Pi is both a musical and programming based technology that everyone can use it as they desire without commiting to a particular style.

Even though it is based off Ruby, I may be mistaken by saying this next but it isn’t necessarily rooted in the ruby paradigm. I believe it is a tool that is for creation of music and many aspects of sound design , which makes it unique.

So if you prefer to do the DRY concept of programming it make sense aa Eli said “Everybody uses their own method, which I’m sure makes
sense to them, or they wouldn’t bother. :slight_smile:

By the way , I have checked out your pieces and nice sounds and style you got there

I totally agree. I wasn’t trying to upset anyone. Surely you don’t mean my pieces ? The above is the only thing longer than 5 lines I’ve written so far!

No Problem and I know you weren’t trying to offend and you had another piece , apart from this

?

I had forgotten about that one :slight_smile:

1 Like