How to program mixing of live loops?

#1

Hi!

Do you have example of programs that launch, stop and mix different live_loops? It can be useful for using Sonic Pi as DAW.

In my recent track (github, soundcoud) I created a wrapper for live_loop:

def my_live_loop(name)
  in_thread do
    with_fx :level, amp:0 do |level_control|
      set name.to_s.concat("_level"), level_control
      loop do
        yield
      end
    end
  end
end

And I use this wrapper to control loops volume in mix method:

def mix()
  set_volume! 1
  control get["bd_level"], amp: 1.0
  control get["snare2_level"], amp: 1.0
  control get["algorave_level"], amp: 0.5
  increase = linear_slide(0.0, 0.5, 33)
  32.times do
    control get["bass_level"], amp: increase.tick(:bass)
    control get["algorave_level"], amp: 0.5 -increase.look(:bass)
    sleep 1
  end
  ...

That kind of works and it is better than having a lot of sleeps in each thread but still I don’t think this is optimal solution.

Do you have any example of using Sonic Pi to fully program the track?

1 Like
#2

you could use cue :whatever in a separate loop and have your loops sync to that cue using sync sync :whatever. Then you can comment out the cues to control whether or not your loops play. You could also expand on that by using something like cue :whatever if (spread x,y).tick or a counter function to create rhythms. I can post an example later of you want.

edit: I went ahead and made an example.

define :pattern do |pattern|
  return pattern.ring.tick == "x"
end

live_loop :cues do
  # 4-on-the-floor using patterns and spread
  cue :kick if pattern "x---x---x---x---"
  cue :kick if (spread 1,4).tick
  
  #cinquillo snares using patterns and spread
  cue :snare if pattern "x-xx-xx-"
  cue :snare if (spread 5,8).tick
  
  sleep 0.25
end

live_loop :kicks do
  sample :bd_haus, lpf: 90
  sync :kick
end

live_loop :snares do
  sample :sn_generic, lpf: 90
  sync :snare
end
2 Likes
#3

Thank you for your example. I didn’t quite follow the intention of the spread method of triggering but that’s not important for me, as I was just looking for a simple examples of syncing loops and using patterns for drums/rhythms.

There’s a bug/oversight in your example - when pattern is called twice per loop tick is going to advance each time so the result is that each drum sequence is being stepped through by 2’s (every other element). I made a simplified version that executes that patterns as expected:

define :pattern do |pattern, name|
  return pattern.ring.tick(name) == "x"
end

snare_hit = "x-xx-xx-".ring
kick_hit =  "x---x---x---x---".ring

live_loop :cues do
  cue :kick if pattern kick_hit, :kicktick
  cue :snare if pattern snare_hit, :snaretick
  sleep 0.25
end

live_loop :kicks do
  sync :kick
  sample :bd_haus
end

live_loop :snares do
  sync :snare
  sample :sn_generic
end
#4

wow, thread resurrection! nice to hear my stuff is useful to people. Yeah, I later found out that ticking twice in a loop makes things go funky.

As for the euclidean algorithms, I found a video which explains in fairly simple terms. Fun fact, you can also feed the spread function floating point numbers. spread(2.75,16) gives you a drum’ n’ bass rhythm

1 Like
#5

I took time to see what spread actually is… at first glance I assumed it to be like a range function - makes a lot more sense now!

Thank you for the link, TIL. Now I know what spread(5, 8) does. When I run it gives me the variation "x-x-xx-x" :slight_smile:

puts spread(5,8)

{run: 3, time: 0.0}
 └─ (ring true, false, true, false, true, true, false, true)