Reggaeton dembow rhythm with Sonic Pi


#1

This is my first approach for creating a reggaeton rythm with Sonic Pi.

Suggestions to improve it are much appreciated!

# Reggaeton - Dembow rythm
# https://en.wikipedia.org/wiki/Dembow
use_bpm 95

define :beat1 do |pat|
  (ring
   *pat
   .split(" ")
   .map{|bar| bar.split("")}
   .flatten
   .map{|d| d=="1" ? 1 : 0})
end

inst1 = Hash[
  :k0  => :bd_haus,
  :s0  => :drum_snare_hard,
  :h0 => :drum_cymbal_closed
]

pat1 = Hash[
  :k0 => "1--- 1--- 1--- 1---",
  :s0 => "---1 --1- ---1 --1-",
  :h0 => "1-1- 1-1- 1-1- 1-1-"
]

live_loop :main do
  tick
  sample inst1[:k0] if beat1(pat1[:k0]).look == 1
  sample inst1[:s0] if beat1(pat1[:s0]).look == 1
  sample inst1[:h0] if beat1(pat1[:h0]).look == 1
  sleep 0.25
end

#2

You could make it even more compact by using true and fasle in the beat1 function.

# Reggaeton - Dembow rythm
# https://en.wikipedia.org/wiki/Dembow
use_bpm 95

define :beat1 do |pat|
  (ring
   *pat
   .split(" ")
   .map{|bar| bar.split("")}
   .flatten
   .map{|d| d=="1" ? true : false})
end

inst1 = Hash[
  :k0  => :bd_haus,
  :s0  => :drum_snare_hard,
  :h0 => :drum_cymbal_closed
]

pat1 = Hash[
  :k0 => "1--- 1--- 1--- 1---",
  :s0 => "---1 --1- ---1 --1-",
  :h0 => "1-1- 1-1- 1-1- 1-1-"
]

puts beat1 "1--- 1--- 1--- 1---" #to show what it does:can be omitted 

live_loop :main do
  tick
  sample inst1[:k0] if beat1(pat1[:k0]).look
  sample inst1[:s0] if beat1(pat1[:s0]).look
  sample inst1[:h0] if beat1(pat1[:h0]).look
  sleep 0.25

end

Your approach gives nice compact code, but it is not for the beginner to Sonic Pi as it involves some hefty Ruby concepts.


#3

I agree, the code is quite complicated because it “maps” the drums pattern into a string hash for the sake of simplicity.

Certainly it could be refactored into something simpler coding the drums into a single live loop. I’ll try to do that


#4

Great work!

Another tip: you can simplify the triggering logic further - regardless of whether the values are 1, 0, true or false by using the on: opt instead of Ruby’s trailing if:

  sample inst1[:h0], on: beat1(pat1[:h0]).look

This allows you to put the conditional logic in any place in the opts of sample, so you could increase the amp with:

  sample inst1[:h0], on: beat1(pat1[:h0]).look, amp: 2

Also, beware of using Ruby code that’s not in the tutorial. You can totally do it, but it’s important to point out that it’s not supported and may change in a future release :slight_smile:


#5

it is not for the beginner to Sonic Pi as it involves some hefty Ruby concepts.

I realize I may be getting in over my head but could you speak to what some of these concepts are and why one might use them in Sonic Pi. I am often curious when I see people that post code which uses non-SPi Ruby as to what the benefits might be to writing it that way or if it opens up possibilities which cannot be accessed using regular Sonic PI Ruby. (I am aware that it does run a risk of not being supported in the future).

This seems like a good example since it is something which can easily be done using very basic code:

use_bpm 95

live_loop :kick do
  sample :bd_haus
  sleep 1
end

live_loop :snare do
  sleep 0.75
  sample :drum_snare_hard
  sleep 0.75
  sample :drum_snare_hard
  sleep 0.5
end

live_loop :hats do
  sample :drum_cymbal_closed
  sleep 0.5
end

Thanks


#6

In this case the Ruby “power bits” are contained in the function beat1 and in the use of hashes.
The former can be understood if you break it down into its constitutuent parts.
The following program does this in 5 stages.
When you run it you will see the effect of each additional stage. The various stages are linked together by a . which means apply the following method to what has gone before.
You see this for example when .tick or .look are applie or .choose and .shuffle to mention but a few.
In the original program listing the function is laid out over several lines. I have here presented it linearly, adding stages for each new test function. You can see the effect in the printed outputs.

define :test1 do |pat|
  (ring *pat)
end
define :test2 do |pat|
  (ring *pat.split(" "))
end
define :test3 do |pat|
  (ring *pat.split(" ").map{|bar| bar.split("")})
end
define :test4 do |pat|
  (ring *pat.split(" ").map{|bar| bar.split("")}.flatten)
end
define :test5 do |pat|
  (ring *pat.split(" ").map{|bar| bar.split("")}.flatten.map{|d| d=="1" ? 0 : 1})
end

puts "test 1 does this", (test1 "1--- 1--- 1--- 1---")
puts "test 2 does this", (test2 "1--- 1--- 1--- 1---")
puts "test 3 does this", (test3 "1--- 1--- 1--- 1---")
puts "test 4 does this", (test4 "1--- 1--- 1--- 1---")
puts "test 5 does this", (test5 "1--- 1--- 1--- 1---")

If you follow through the various stages you will see the effect of the .split and .map and .flatten methods.

The hash function can be thought of as setting up a lookup list. Thus for the hash inst0 you can use the lookup keys :k0 :s0 and :h0 to retrieve the associated sample name.

Although, as you show, you can write out the program in standard SP syntax, The advantage of the beat1 function is that it enables you visually to see the rhythms very easily, and also you can easily try out different rhythmic patterns without having to rewrite the code, only alter the data strings.

However, as Sam says, you use Ruby constructs at your own risk, and what works today may not necessarily work in future versions. Also it can make it difficult to follow exactly what a program is doing.


#7

This is exactly how I would refactor this, plain and simple Sp code.

We have lost the ability to visually see the rhythm pattern, but anyway reggaeton do not change the rhytm. ever :smiley:


#8

Ditto (Bah… post has to be 20 characters long… Blah Blah, Yakettie-Shmakettie)

Eli…


#9

Hi @victormartin,

no need to give up the visual aid (you can also use line wraps to make it even more clear, see cym). And if you set the amp you can even skip the if (or as @samaaron reminded me of: the on) and add some dynamics:

use_bpm 95

kik = (ring 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0.5)
snr = (ring 0,0,0,1, 0,0.25,1,0, 0,0,0,1, 0,0,1,0)
cym = (ring
       1,0,0.5,0,
       1,0,0.5,0,
       1,0,0.5,0,
       1,0,0.5,0.25)

live_loop :main do
  sample :bd_haus, amp: kik.tick
  sample :drum_snare_hard, amp: snr.look
  sample :drum_cymbal_closed, amp: cym.look
  sleep 0.25
end

Though, admittedly, @mrbombmusic’s solution is - to my experience - performancewise a good one (as soon as you’ll start to use several live_loops).


#10

I do like the idea of seeing the rhythmic patterns. That has been something that took some getting used to when switching from a regular DAW to Sonic Pi.

To try and incorporate the visual rhythmic pattern, I reworked the code using bools, although there is are a few more lines of code as a result

use_bpm 95

b = (bools, 1, 0, 0, 0, 1, 0, 0, 0)
s = (bools, 0, 0, 0, 1, 0, 0, 1, 0)
h = (bools, 1, 0, 1, 0, 1, 0, 1, 0)

live_loop :dembass do
  if b.tick
    sample :bd_haus
    sleep 0.25
  else
    sleep 0.25
  end
end

live_loop :demsnare do
  if s.tick
    sample :drum_snare_hard
    sleep 0.25
  else
    sleep 0.25
  end
end

live_loop :demhat do
  if h.tick
    sample :drum_cymbal_closed
    sleep 0.25
  else
    sleep 0.25
  end
end


#11

wow, party up in here! dembow, dembow dembow dembow…

it would be fun to get all the dancehall riddims into sonic pi form! break out all the classics

actually, i made a basic moombahton beat a while back

# utility functions
counter = {
  :sixteenth => 1,
  :bar => 1
}

define :count do |counter|
  counter[:sixteenth] += 1
  if counter[:sixteenth] % 16 == 0 then
    counter[:sixteenth] = 1
    counter[:bar] += 1
  end
end

define :make do |pat|
  (ring *pat.split(" ").map{|bar| bar.split("")}.flatten.map{|d| d=="1" ? 1 : 0})
end
#######################################
#######################################
use_bpm 100

track2 = {
  :k0 => {:pat => "1--- 1--- 1--- 1--- 1--- 1--- 1--- 1---", :inst => :bd_808},
  :k1 => {:pat => "---1 --1- ---1 --1- ---1 --1- ---1 --1-", :inst => :bd_pure},
  :h0 => {:pat => "1-11 -11- 1--- --11 --11 1--- --11 -11-", :inst => :perc_snap2},
  
  :e0 => {:pat => "---- ---- ---- ---- ---- ---- ---- 1---", :inst => :vinyl_hiss},
  :t1 => {:pat => "---- ---- ---- ---- ---- ---- ---- 1---", :inst => :tabla_re}
}

live_loop :main do
  tick
  with_fx :reverb, amp: 2 do
    with_fx :distortion, distort: 0.5 do
      use_synth :beep
      sample track2[:k0][:inst], amp: make(track2[:k0][:pat]).look
      sample track2[:k1][:inst], amp: make(track2[:k1][:pat]).look
      sample track2[:h0][:inst], amp: make(track2[:h0][:pat]).look*0.05
    end
  end
  sample track2[:e0][:inst], amp: make(track2[:e0][:pat]).look
  sample track2[:t1][:inst], amp: make(track2[:t1][:pat]).look
  
  puts counter; count(counter)
  sleep 0.25
end

i wanted to point out a few changes that might be useful, so here’s an example that’s a little closer to the original, and i’ll talk through some of the modifications, and the rationale behind some of what’s in there:

use_bpm 120

define :make do |pat|
  (ring *pat.split(" ").map{|bar| bar.split("")}.flatten.map{|d| d=="1" ? 1 : 0})
end

track1 = {
  :c0 => {:pat => "1--- 1--- 1--- 1--- 1--- 1--- 1--- 1---", :inst => chord(:E3, :m)},
  :c1 => {:pat => "---- ---- ---- --1- ---- ---- ---- --1-", :inst => chord(:E4, :m)},
  :d0 => {:pat => "1111 ---- 1111 ---- 1111 ---- 1111 ----", :inst => :sn_dolf},
  :bd => {:pat => "---- 1--- ---- 1--- ---- 1--- ---- 1---", :inst => :bass_hit_c},
  :b0 => {:pat => "1--- ---- 1--- ---- ---- ---- ---- ----", :inst => :E0},
  :b1 => {:pat => "--1- 1-1- ---- 1--- 1--- 1--- 1--- 1---", :inst => :E1}
}

live_loop :main do
  tick
  use_synth :beep
  play   track1[:c0][:inst], amp: make(track1[:c0][:pat]).look
  play   track1[:c1][:inst], amp: make(track1[:c1][:pat]).look
  sample track1[:b0][:inst], amp: make(track1[:b0][:pat]).look
  sample track1[:d0][:inst], amp: make(track1[:d0][:pat]).look*0.1
  
  use_synth :mod_beep
  play   track1[:b0][:inst], amp: make(track1[:b0][:pat]).look
  play   track1[:b1][:inst], amp: make(track1[:b1][:pat]).look
  sleep 0.25
end

you might notice a few things in here: the first is that the only reason Hash[] was in there initially is that I didn’t realize ruby had the {} notation, which is a little more compact (and also a little more universal to other languages, like javascript and python). the instrument specifier has been moved to sit alongside the pattern, and the combination i’ve called a “track,” to sit well with the translation from a midi “track.” the former “beat1” function is renamed to “make”, which a programmer i suppose would recognize for its functionality, which is to “assemble” the executable form from the text format. you may notice also that this is an attempt to integrate synthesizer notes with with the original format, which was using only samples. i think there’s still more work that could be done to make that work a little better.

similar to suggestion by @samaaron, rather than if, this is now directly injecting the numerical value into a meaningful sonic pi parameter, in this case the amplitude of the note (i didn’t know about “on”). the idea to this point, is to allow the notes to be specified as the sequence 1,2,3,4,5,6,7,8,9,x, to map to volume values 0.1 to 1.0. this would allow for, say

track1 = {
  :c0 => {:pat => "x--- x--- x--- x--- x--- x--- x--- x---", :inst => chord(:E3, :m)},
  :c1 => {:pat => "---- ---- ---- --8- ---- ---- ---- --8-", :inst => chord(:E4, :m)},
  :d0 => {:pat => "1111 ---- 1111 ---- 1111 ---- 1111 ----", :inst => :sn_dolf},
  :bd => {:pat => "---- 7--- ---- 7--- ---- 7--- ---- 7---", :inst => :bass_hit_c},
  :b0 => {:pat => "x--- ---- x--- ---- ---- ---- ---- ----", :inst => :E0},
  :b1 => {:pat => "--x- x-x- ---- x--- x--- x--- x--- x---", :inst => :E1}
}

the idea is that in beat creation, a person might just lay out the beat using x’s, which is familiar and straightforward. then the next step is drawing in velocity, which in a lot of cases is nearly as important as timing information, so it might make sense to give it equivalent level of importance in the notation system (as opposed to a separate curve for velocity values). i could see the potential for future modifications here though, as this is more attuned to rhythmic musical styles, where in a more melody-oriented system, note duration might take a more prominent role

nevertheless, for current purposes, this formulation retains the uniform spacing per beat, which is important for musical interpretability (the added spacing in decimal values unfortunately break the visual direct mapping to, for example, a midi layout in a daw).

while i’m not necessarily opposed to the relative simplicity of a straightforward ring, the added visual noise of the commas i find distract from the basics of laying out a musical, or rhythmic, idea. the original formulation of this notation came about when i was using Tidal, and the format of the notation can use characters without any kind of separator, as in the following:

d1 $ density 0.5 $ stack [
sound "0 ~ ~ ~  ~ ~ 0 ~  ~ ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~  ~ ~ 0 ~  ~ ~ 0 ~  ~ 0 ~ ~" # sound "bd",
sound "~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~" # sound "sn:5",
sound "~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~  ~ ~ ~ ~  0 ~ ~ ~" # sound "cp:2",
sound "0 ~ 0 0  0 ~ 0 0  0 ~ 0 0  0 ~ 0 0  0 ~ 0 0  0 ~ 0 0  0 ~ 0 0  ~ ~ 0 0" # sound "hh" # gain "0.9",
sound "0 ~ 0 ~  ~ ~ 0 ~  0 ~ 0 ~  ~ ~ 0 ~  0 ~ 0 ~  ~ ~ 0 ~  0 ~ 0 0  ~ ~ 0 ~" # sound "cp:3" # gain "0.8"
]

this was the actual original form of the notation. the compactness and straightforwardness which would be appealing to musicians is what i think is important to retain

it is a good idea to have a clear notion of how something like this translates to idiomatic Sonic Pi, of the type in the tutorials. that gives a good sense of the tradeoffs being made. to that end, i had the idea of translating the beats of the Amen break into this notation, and seeing what’s difficult and where it starts to fall apart. then translating that into idiomatic sonic pi i think would be a very useful thing


#12

Rubber Dub… I also wrote a Dub ‘helper’ called ‘Dub Generation’ complete with own
scripting methods and examples… Nobody seemed interested so I never posted it here.

Eli…

# Rubber Dub
# Coded by: KniKnoo. https://gist.github.com/kniknoo/9bba301ab048cbfa350777d39a6098f6
# Remixed by: Just Eli... https://soundcloud.com/just-eli-139271289/

use_bpm 75
use_debug false
use_random_seed 98736

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

n = (ring :r, :r, :d2, :d3, :f3, :r, :d1, :f2)

fade_in = (line 0, 2, inclusive: true, steps: 40).ramp
fade_in1 = (line 0, 3, inclusive: true, steps: 15).ramp
fade_out = (line 3, 1, inclusive: true, steps: 40).ramp
fade_out1 = (line 2, 0.5, inclusive: true, steps: 15).ramp
fade_out2 = (line 3, 1.5, inclusive: true, steps: 40).ramp
fade_through = fade_in+fade_out
fade_through1 = fade_in+fade_out1
fade_through2 = fade_in+fade_out2

dchord = chord(:g4, :minor, num_octaves: 3)
synth_cutoffs = range(60, 100, 0.5).mirror
synth_rhythm = (ring 1.5, 1.5, 1)
synth_transpositions = (stretch 0, 36) + (stretch -12, 6) + (stretch 12, 6)
synth_phases = (stretch 0.75, 15) + [0.25]
synth_pans = (ring -0.5, 0.5)
synth_volume = 1

dubpad_cutoffs = range(70, 100, 5).mirror
dubpad_phases = (ring 8, 8, 8, 0.5)
dubpad_mixes = (ring 0.5, 0.5, 0.5, 0)
dchord = chord(:g4, :minor, num_octaves: 3)

# Repeat a loop.
define :repeat_loop do |i|
  tracker[i] = 2
end


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
  tracker[10] = 0
  tracker[11] = 0
  
end


define :sn_roll do #|length|
  in_thread do
    sn_amp = 0.05
    4.times do
      sample :sn_dolf, amp: sn_amp, sustain: 0, release: 0.125
      sleep 0.0625
      sn_amp += 0.07
    end
  end
end

define :dubpad do |ch, amp|
  with_fx :echo, amp: amp, mix: dubpad_mixes.look,
  phase: 1.5, decay: 2 do
    with_fx :reverb, room: 0.8 do
      with_fx :ixi_techno, phase: dubpad_phases.tick, cutoff_min: 70 do
        with_synth :tb303 do
          with_synth_defaults attack: 0.1, release: 8,
          cutoff: dubpad_cutoffs.look, res: 0.5 do
            play_chord ch
            play_chord ch.map { |n| n + 0.3 } # Detune chord
          end
        end
      end
    end
  end
end

live_loop :bar do
  sleep 1
end

live_loop :beats do
  sync :bar
  sleep 4
end

live_loop :kick do
  if tracker[0]>0 then
    sample :drum_heavy_kick
    sleep 1
  else
    sleep 1
  end
end

with_fx :reverb, mix: 0.35, room: 0.1, damp: 0.9 do
  live_loop :snare do
    if tracker[1]>0 then
      use_sample_defaults sustain: 0, release: 0.25
      sleep 0.75
      sn_roll if rand > 0.8
      sleep 0.25
      sample :sn_dolf
      del = [0.25, 0.5, 0.75].choose
      cue :bass
      sleep del
      sample :drum_snare_soft, amp: 0.7 if rand > 0.5
      sleep 1 - del
    else
      sleep 1
    end
  end
end


live_loop :hats do
  if tracker[2]>0 then
    sample :drum_cymbal_closed, sustain: 0.125, amp: 0.3 if rand > 0.9
    sleep 0.5
    sample :drum_cymbal_closed, sustain: 0.125, amp: 0.5
    sleep 0.5
  else
    sleep 1
  end
end

live_loop :hats2 do
  if tracker[2]>0 then
    sample [:elec_tick, :elec_blip].choose, sustain: 0.006, amp: 0.8, hpf: 100 if rand > 0.3
    sleep 0.25
  else
    sleep 1
  end
end

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

with_fx :gverb, mix: 0.1, room: 20, amp: 0.6 do
  live_loop :skank do
    if tracker[4]>0 then
      with_fx :bitcrusher, mix: 0.7, amp: 0.5, bits: 8, sample_rate: 3136 do
        use_synth :dpulse
        use_synth_defaults release: 0.125
        sleep 0.5
        if rand > 0.8
          with_fx :echo, phase: [0.25, 0.333, 0.375, 0.75].choose, decay: 4, mix: 0.5 do
            play (chord, :g4, :m, invert: -1)
          end
        else
          play (chord, :g4, :m, invert: -1)
        end
        3.times do
          sleep 1
          play (chord, :g4, :m, invert: -1)
        end
        sleep 0.5
      end
      
    else
      sleep 1
    end
  end
end

with_fx :echo, mix: 0.8, phase: 0.75, decay: 4 do
  with_fx :flanger, stereo_invert_wave: 1, feedback: 0.5, amp: 0.5 do
    
    live_loop :lead do
      if tracker[5]== 1 then
        with_fx :flanger, stereo_invert_wave: 1, feedback: 0.5, amp: 0.5 do
          sync :bass
          sync :bass
          use_synth :mod_beep
          rps = (range 6, 9).choose
          use_synth_defaults res: 0.9, attack: 0.25, noise: 2, release: 2 , cutoff: 100, amp: 0.2,
            note_slide: 0.02, sustain: 0.25 * rps / 1.25, decay: 0.25 * rps / 1.25, sustain_level: 0.8,
            mod_range: 0.5, mod_phase: 0.125, mod_wave: 2, pulse_width: 0.2
          mynote = (note_range, :g4, :g6, pitches: (scale, :g, :minor_pentatonic))
          play mynote.reverse.tick
          rps.times do
            control note: mynote.tick - [0, 12].choose
            sleep [0.25, 0.25, 0.5, 0.5, 0.75].choose
          end
          tracker[5] = 0
          sleep 2.5
        end
      else
        sleep 1
      end
    end
    
    if tracker[5] > 0 then
      with_fx :flanger, stereo_invert_wave: 1, feedback: 0.5, amp: 0.5 do
        sync :bass
        sync :bass
        use_synth :mod_beep
        rps = (range 6, 9).choose
        use_synth_defaults res: 0.9, attack: 0.25, noise: 2, release: 2 , cutoff: 100, amp: 0.2,
          note_slide: 0.02, sustain: 0.25 * rps / 1.25, decay: 0.25 * rps / 1.25, sustain_level: 0.8,
          mod_range: 0.5, mod_phase: 0.125, mod_wave: 2, pulse_width: 0.2
        mynote = (note_range, :g4, :g6, pitches: (scale, :g, :minor_pentatonic))
        play mynote.reverse.tick
        rps.times do
          control note: mynote.tick - [0, 12].choose
          sleep [0.25, 0.25, 0.5, 0.5, 0.75].choose
        end
        sleep 2.5
      end
    else
      sleep 1
    end
    
  end
end

live_loop :boom do
  sync :kick
  if tracker[6] == 1 then
    with_fx :reverb, room: 1 do
      sample :bd_boom, amp: 3
    end
    sample :drum_tom_hi_hard, amp: 3, rate: 0.2
    tracker[6]=0
    sleep 4
  end
  
  if tracker[6]>0 then
    with_fx :reverb, room: 1 do
      sample :bd_boom, amp: 1
    end
    sample :drum_tom_hi_hard, amp: 3, rate: 0.2
    sleep 4
  else
    sleep 1
  end
end

live_loop :alien_woosh do
  sync :kick
  if tracker[7] == 1 then
    with_fx :reverb, room: 1 do
      sample :ambi_dark_woosh
      tracker[7]=0
      sleep 4
    end
  end
  
  if tracker[7]>0 then
    with_fx :reverb, room: 1 do
      sample :ambi_dark_woosh
      sleep 4
    end
  else
    sleep 1
  end
end

live_loop :zawa do
  sync :kick
  if tracker[8] == 1 then
    with_fx :reverb, room: 1 do
      with_fx :slicer do
        with_fx :pitch_shift, pitch: -12 do
          use_synth :zawa
          
          [3,5,6,7,8,10].choose.times do |i|
            play chord(:e3, :minor).choose, release: [0.2, 0.4, 0.6, 0.8, 1].choose, pan: [1,0,-1].choose, cutoff: rrand(80, 110)
            tracker[8]=0
            sleep [0.25,0.5,0.75].choose
          end
        end
      end
    end
  end
end

live_loop :pad do
  sync :kick
  if tracker[9] == 1 then
    dubpad dchord, 0.125
    tracker[9] = 0
    sleep 16
  end
  if tracker[9] > 0 then
    dubpad dchord, 0.125
    sleep 16
  end
  sleep 0.1
end

live_loop :synth do
  sync :kick
  if tracker[10] == 1 then
    ch = invert_chord(dchord, rand_i(3))
    sleep synth_rhythm.tick
    # get random values for 1-shot synth.
    tick_advance = rrand_i(0,10)
    tick_advance.times do
      tick
    end
    with_fx :echo, amp: synth_volume, mix: 0.3,
    decay: 8, phase: synth_phases.look do
      with_fx :pan, pan: synth_pans.look do
        with_fx :reverb, room: 0.7, damp: 0.8 do
          with_synth_defaults attack: 0.05, release: 0.3 do
            with_transpose synth_transpositions.look do
              with_synth :sine do
                play_chord ch
              end
              cutoff = synth_cutoffs.look
              with_fx :ixi_techno, cutoff_min: cutoff,
              cutoff_max: cutoff - 30, phase: 1, res: 0.3 do
                with_synth :dsaw do
                  play_chord ch, attack: 0.1
                  tracker[10] = 0
                end
              end
            end
          end
        end
      end
    end
  end
  
  if tracker[10] > 0 then
    ch = invert_chord(dchord, rand_i(3))
    sleep synth_rhythm.tick
    with_fx :echo, amp: synth_volume, mix: 0.3,
    decay: 8, phase: synth_phases.look do
      with_fx :pan, pan: synth_pans.look do
        with_fx :reverb, room: 0.7, damp: 0.8 do
          with_synth_defaults attack: 0.05, release: 0.3 do
            with_transpose synth_transpositions.look do
              with_synth :sine do
                play_chord ch
              end
              cutoff = synth_cutoffs.look
              with_fx :ixi_techno, cutoff_min: cutoff,
              cutoff_max: cutoff - 30, phase: 1, res: 0.3 do
                with_synth :dsaw do
                  play_chord ch, attack: 0.1
                end
              end
            end
          end
        end
      end
    end
  else
    sleep 0.1
  end
end

live_loop :burp do
  sync :kick
  if tracker[11] == 1 then
    with_fx :reverb, room: 1 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        with_fx :slicer do
          with_fx :pitch_shift, pitch: 12 do
            sample :misc_burp, rate: 0.2, amp: 3
            tracker[11] = 0
            sleep 4
          end
        end
      end
    end
  end
  
  if tracker[11]>0 then
    with_fx :reverb, room: 1 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        with_fx :slicer do
          with_fx :pitch_shift, pitch: 12 do
            sample :misc_burp, rate: 0.2, amp: 3
            sleep 4
          end
        end
      end
    end
  else
    sleep 1
  end
end

kick = 0
snare = 1
hats = 2
bass = 3
skank = 4
lead = 5
boom = 6
alien_whoosh = 7
zawa = 8
dub_pad = 9
dub_synth = 10
burp= 11
boom = 6

start_loop lead
sleep 8

repeat_loop kick
sleep 2
repeat_loop snare
repeat_loop hats
sleep 4
repeat_loop bass
sleep 4
repeat_loop skank
sleep 4
start_loop lead
sleep 8
repeat_loop dub_pad
sleep 16
stop_loop dub_pad
repeat_loop dub_synth
sleep 32
start_loop zawa
sleep 8
start_loop burp
sleep 12
start_loop boom
sleep 12
start_loop burp
sleep 12
start_loop zawa
sleep 12
stop_loop dub_synth
sleep 8
repeat_loop dub_pad
sleep 12
start_loop lead
sleep 16
stop_loop dub_pad
sleep 4
start_loop lead
sleep 16
start_loop zawa
sleep 4
stop_all
"                              Dub Generation" # V3.0
#___________________________________________________________________________________
"TRACK"#___0___1___2___3___4___5___6___7___8___9__10___11___12___13__14___15___16__17__18 |
track =   [2 , 0 , 2 , 0 , 2 , 2 , 0 , 0 , 2 , 2, 0 ,  0 ,  0 ,  0 , 0 ,  0 ,  0 , 0 , 0  ]
"             0 to deactivate, 1 for 1-shot effect, 2 for continuous loop."#              |
#_________________________________________________________________________________________|
"                           ALT-R or CLICK 'RUN to ACTIVATE"
#_________________________________________________________________________________________|

#_Track_______Track______________Track_____________Track_______
#           |                  |                 | 12 Dub Pad  \
# 0 Kick    | 6  Rim           | 12 Whoosh       |              |
# 1 Boom    | 7  Bass          | 13 Train        |              |
# 2 Beat 1  | 8  Skank         | 14 Zawa         |              |
# 3 Beat 2  | 9  Swirl         | 15 Burp         |              |
# 4 Snare   | 10 Guitar 1      | 16 Ghostly keys |              |
#_5 Hat     | 11_Guitar 2      | 17 Synth tune   |              |
#___________|__________________|_________________|______________/
#
#   See end of code for examples of how to make and use 'script' mode.
# Complete script language is in the associated document, DUB Scripting.
#
#      Note: Not all effect/volume changes are instantaneous...
#             you will need to judge them for yourself.
#
#                           Control Panel by: Eli...
#
# Extra 'BOOM' added for my friend Xomby.  'Respec'...






















x=0
use_bpm 75

kick = 0
boom = 1
base_drum = 2
secondary_drum = 3
snare = 4
hat = 5
rim = 6
bass = 7
skank = 8
lead = 9
guitar1 = 10
guitar2 = 11
alien_whoosh = 12
train = 13
zawa = 14
burp = 15
ghostly_keys = 16
dub_synth = 17
dub_pad = 18

synth_cutoffs = range(60, 100, 0.5).mirror
synth_rhythm = (ring 1.5, 1.5, 1)
synth_transpositions = (stretch 0, 36) + (stretch -12, 6) + (stretch 12, 6)
synth_phases = (stretch 0.75, 15) + [0.25]
synth_pans = (ring -0.5, 0.5)
synth_volume = 1

dubpad_cutoffs = range(70, 100, 5).mirror
dubpad_phases = (ring 8, 8, 8, 0.5)
dubpad_mixes = (ring 0.5, 0.5, 0.5, 0)
dchord = chord(:e3, :minor, num_octaves: 3)
dubpad_volume = 1

n = (ring :r, :r, :d2, :d3, :f3, :r, :d1, :f2)

define :combo do |s, t, u|
  start_loop s
  start_loop t
  start_loop u
  sleep 4
  stop_loop s
  stop_loop t
  stop_loop u
end

define :sn_roll do #|length|
  in_thread do
    sn_amp = 0.05
    4.times do
      sample :sn_dolf, amp: sn_amp, sustain: 0, release: 0.125
      sleep 0.0625
      sn_amp += 0.07
    end
  end
end

define :dubpad do |ch, amp=0.25|
  with_fx :echo, amp: amp, mix: dubpad_mixes.look,
  phase: 1.5, decay: 2 do
    with_fx :reverb, room: 0.8 do
      with_fx :ixi_techno, phase: dubpad_phases.tick, cutoff_min: 70 do
        with_synth :tb303 do
          with_synth_defaults attack: 0.1, release: 8,
          cutoff: dubpad_cutoffs.look, res: 0.5 do
            play_chord ch
            play_chord ch.map { |n| n + 0.3 } # Detune chord
          end
        end
      end
    end
  end
end

# Repeat a loop.
define :repeat_loop do |i|
  track[i] = 2
end

# Bring in a loop.
define :start_loop do |i|
  track[i] = 1
end

# Remove a loop.
define :stop_loop do |i|
  track[i] = 0
end

live_loop :kick do
  if track[0] > 0 then
    sample :bd_tek, amp: 0.2
    sleep 1
    if track[0] == 1 then
      track[0] = 0
    end
  else
    sleep 0.25
  end
end

live_loop :boom do
  sync :kick
  if track[1] > 0 then
    with_fx :reverb, room: 1 do
      sample :bd_boom, amp: 3
    end
    sample :drum_tom_hi_hard, amp: 3, rate: 0.2
    if track[1] == 1 then
      track[1]=0
      sleep 1
    end
  else
    sleep 1
  end
end

live_loop :base_drums do
  sync :kick
  if track[2] > 0 then
    with_fx :reverb, room: 0.5, phase: 0.5 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        2.times do
          sample :drum_heavy_kick, amp: 1, release: 1
          sleep 1.5
          sample :drum_snare_hard, amp: 0.3, release: 1
          sleep 1.5
        end
        if track[2] == 1 then
          track[2]=0
          
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :secondary_drums do
  sync :kick
  if track[3] > 0 then
    with_fx :reverb, room: 0.5, phase: 0.5 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        sleep 1.5
        
        sample :drum_snare_hard, amp: 0.3, release: 1
        sleep 1.5
        
        sample :drum_heavy_kick, amp: 0.8, release: 1
        sleep 1.5
        
        sample :drum_snare_hard, amp: 0.5, release: 1
        sleep 0.5
        
        sample :drum_bass_soft, amp: 0.25, release: 1
        sleep 0.25
        sample :drum_bass_hard, amp: 0.75, release: 1
        sleep 0.25
        sample :drum_bass_soft, amp: 0.5, release: 1
        sleep 0.5
        if track[3] == 1 then
          track[3]=0
        end
        
      end
    end
  else
    sleep 1
  end
end

with_fx :reverb, mix: 0.35, room: 0.1, damp: 0.9 do
  live_loop :snare do
    if track[4]>0 then
      use_sample_defaults sustain: 0, release: 0.25
      sleep 0.75
      sn_roll if rand > 0.8
      sleep 0.25
      sample :sn_dolf
      del = [0.25, 0.5, 0.75].choose
      cue :bass
      sleep del
      sample :drum_snare_soft, amp: 0.7 if rand > 0.5
      sleep 1 - del
      if track[4] == 1 then
        track[4] = 0
      end
    else
      sleep 1
    end
  end
end



live_loop :hat1 do
  if track[5]>0 then
    sample :drum_cymbal_closed, sustain: 0.125, amp: 0.3 if rand > 0.9
    sleep 0.5
    sample :drum_cymbal_closed, sustain: 0.125, amp: 0.5
    sleep 0.5
    if track[5] == 1 then
      track[5] = 0
    end
  else
    sleep 1
  end
end


live_loop :rim do
  if track[6]>0 then
    sample [:elec_tick, :elec_blip].choose, sustain: 0.006, amp: 0.8, hpf: 100 if rand > 0.3
    sleep 0.25
    if track[6] == 1 then
      track[6] = 0
    end
  else
    sleep 1
  end
end


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


with_fx :gverb, mix: 0.1, room: 20, amp: 0.6 do
  live_loop :skank do
    if track[8]>0 then
      with_fx :bitcrusher, mix: 0.7, amp: 0.5, bits: 8, sample_rate: 3136 do
        use_synth :dpulse
        use_synth_defaults release: 0.125
        sleep 0.5
        if rand > 0.8
          with_fx :echo, phase: [0.25, 0.333, 0.375, 0.75].choose, decay: 4, mix: 0.5 do
            play (chord, :g4, :m, invert: -1)
          end
        else
          play (chord, :g4, :m, invert: -1)
        end
        3.times do
          sleep 1
          play (chord, :g4, :m, invert: -1)
        end
        sleep 0.5
        if track[8] == 1 then
          track[8] == 0
        end
      end
    else
      sleep 1
    end
  end
end


with_fx :echo, mix: 0.8, phase: 0.75, decay: 4 do
  with_fx :flanger, stereo_invert_wave: 1, feedback: 0.5, amp: 0.5 do
    
    live_loop :lead do
      if track[9] > 0 then
        with_fx :flanger, stereo_invert_wave: 1, feedback: 0.5, amp: 0.5 do
          sync :bass
          sync :bass
          use_synth :mod_beep
          rps = (range 6, 9).choose
          use_synth_defaults res: 0.9, attack: 0.25, noise: 2, release: 2 , cutoff: 100, amp: 0.2,
            note_slide: 0.02, sustain: 0.25 * rps / 1.25, decay: 0.25 * rps / 1.25, sustain_level: 0.8,
            mod_range: 0.5, mod_phase: 0.125, mod_wave: 2, pulse_width: 0.2
          mynote = (note_range, :g4, :g6, pitches: (scale, :g, :minor_pentatonic))
          play mynote.reverse.tick
          rps.times do
            control note: mynote.tick - [0, 12].choose
            sleep [0.25, 0.25, 0.5, 0.5, 0.75].choose
          end
          if track[9]== 1 then
            tracker[9] = 0
          end
          sleep 2.5
        end
      else
        sleep 1
      end
    end
    
  end
end

live_loop :guitar1 do
  sync :kick
  if track[10] > 0 then
    with_fx :reverb, room: 1 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        with_fx :slicer do
          sample :guit_em9, rate: 1
          sleep 4
          if track[10] == 1 then
            track[10]=0
            sleep 1
          end
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :guitar2 do
  sync :kick
  if track[11] > 0 then
    with_fx :reverb, room: 1 do
      with_fx :pitch_shift, pitch: -6 do
        sample :guit_e_fifths, rate: 1
        sleep 4
        if track[11] == 1 then
          track[11] = 0
          sleep 1
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :alien_woosh do
  sync :kick
  if track[12] > 0 then
    with_fx :reverb, room: 1 do
      sample :ambi_dark_woosh
      sleep 4
      if track[12] == 1 then
        track[12]=0
        sleep 1
      end
    end
  else
    sleep 1
  end
end

live_loop :train do |s|
  sync :kick
  if track[13] > 0 then
    with_fx :reverb, room: 0.5, phase: 0.5 do
      if s
        sleep 2
        end_release = 4
      else
        end_release = 6
      end
      use_synth :bnoise
      play :Cs3, amp: 0.5, pan: -1
      sleep 0.25
      play :Es3, amp: 0.25, pan: 1
      sleep 0.5
      play :Cs2, amp: 0.4, pan: -1
      sleep 0.25
      play :Es2, amp: 0.25, pan: 1
      sleep 0.5
      play :Ds3, amp: 0.3, pan: -1
      sleep 0.25
      play :Bs3, amp: 0.25, pan: 1
      sleep 0.5
      play :Ds2, amp: 0.3, pan: -1
      sleep 0.25
      play :Bs2, amp: 0.25, pan: 1, release: end_release
      if track[13] == 1 then
        track[13]=0
        sleep 1.5
      end
    end
  else
    sleep 1
  end
end

live_loop :zawa do
  sync :kick
  if track[14] > 0 then
    with_fx :reverb, room: 1 do
      with_fx :slicer do
        with_fx :pitch_shift, pitch: -12 do
          use_synth :zawa
          [3,5,6,7,8,10].choose.times do |i|
            play chord(:e4, :minor).choose, release: [0.2, 0.4, 0.6, 0.8, 1].choose, pan: [1,0,-1].choose, cutoff: rrand(80, 110)
            sleep [0.25,0.5,0.75].choose
            if track[14] == 1 then
              track[14]=0
              sleep [0.25,0.5,0.75].choose
            end
          end
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :burp do
  sync :kick
  if track[15] > 0 then
    with_fx :reverb, room: 1 do
      with_fx :echo, mix: 0.3, phase: 0.25 do
        with_fx :slicer do
          with_fx :pitch_shift, pitch: 12 do
            sample :misc_burp, rate: 0.2, amp: 3
            sleep 4
            if track[15] == 1 then
              track[15] = 0
              sleep 4
            end
          end
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :ghostly_keys do
  sync :kick
  if track[16] > 0 then
    with_fx :reverb, room: 0.8 do
      with_fx :echo, delay: 0.5, decay: 4 do
        use_synth :dark_ambience
        play chord([:b3, :b4, :e3, :e4].choose, :minor).choose,
          amp: 1.5, release: 6
        [5,6,7,8,9,10].choose.times do |i|
          use_synth :piano
          play chord([:b1, :b2, :b3, :e1, :e2, :e3].choose,
          :minor).choose, cutoff: rrand(40, 100),
            amp: 0.75, attack: 0, release: rrand(1, 2),
            cutoff_max: 110, pan: [-1, 0, 1].choose
          sleep [0.25, 0.5, 0.5, 0.5, 1, 1].choose
          if track[16] == 1 then
            track[16] = 0
            sleep 1
          end
        end
      end
    end
  else
    sleep 1
  end
end

live_loop :synth do
  sync :kick
  if track[17] > 0 then
    ch = invert_chord(dchord, rand_i(3))
    sleep synth_rhythm.tick
    # get random values for 1-shot synth.
    tick_advance = rrand_i(0,10)
    tick_advance.times do
      tick
    end
    with_fx :echo, amp: synth_volume, mix: 0.3,
    decay: 8, phase: synth_phases.look do
      with_fx :pan, pan: synth_pans.look do
        with_fx :reverb, room: 0.7, damp: 0.8 do
          with_synth_defaults attack: 0.05, release: 0.3 do
            with_transpose synth_transpositions.look do
              with_synth :sine do
                play_chord ch
              end
              cutoff = synth_cutoffs.look
              with_fx :ixi_techno, cutoff_min: cutoff,
              cutoff_max: cutoff - 30, phase: 1, res: 0.3 do
                with_synth :dsaw do
                  play_chord ch, attack: 0.1
                  sleep synth_rhythm.look
                  if track[17] == 1 then
                    track[17] = 0
                  end
                end
              end
            end
          end
        end
      end
    end
    
  else
    sleep 0.1
  end
end

live_loop :pad do
  sync :kick
  if track[18] > 0 then
    dubpad dchord, 0.25
    sleep 16
    if track[18] == 1 then
      track[18] = 0
      sleep 1
    end
  else
    sleep 1
  end
end

comment do
  repeat_loop dub_synth
  sleep 5
  repeat_loop alien_whoosh
  repeat_loop boom
  repeat_loop base_drum
  repeat_loop secondary_drum
  sleep 1
  stop_loop alien_whoosh
  stop_loop boom
  sleep 16
  stop_loop secondary_drum
  combo alien_whoosh, dub_pad, zawa
  sleep 4
  combo boom, base_guitar, secondary_guitar
  sleep 4
  combo train, base_guitar, alien_whoosh
  sleep 4
  combo boom, base_guitar, zawa
  sleep 4
  combo alien_whoosh, base_guitar, train
  sleep 4
  combo boom, base_guitar, zawa
  sleep 4
  combo boom, base_guitar, burp
  sleep 4
  combo burp, base_guitar, ghostly_keys
  sleep 4
  combo secondary_guitar, base_guitar, ghostly_keys
  
  sleep 5
  
  stop_loop boom
  stop_loop base_drum
  stop_loop secondary_drum
  stop_loop dub_synth
end