Changing BPM in Transitions during Live Coding


#1

I have been doing a lot more live coding lately (actually performing in virtual worlds (Sansar by Linden Labs), at my 10 year old grandkid’s Science Technology Engineering and Math Club and at an eclectic Open Mic which has mostly poets reading their stuff (man when did swear words become art). In any case, I find transitions from song to song very difficult. One of my main problems is changing the beats per minute when doing a shift from one groove to another one. The only way I have found to make the change in beats per minute is to actually Stop the song with the Stop button. Is there another way?


#2

YOu can use the command use_bpm n where n is the rate you want. This has a scope of the current thread, so you need to put it in each live loop you want to change. You can use the set and get commands to set the bpm value in the main program and then get it in each live look you want to change.
I’ve just been using it this afternoon to do just that.

eg

set :bpm , 100


live_loop :test do
  use_bpm get(:bpm) #gets 100
  play 72, release: 0.2
  sleep 1
end

You can run this, then change the 100 in the first line to say 150 and rerun without stopping. The tempo will change.


#3

Thx Robin that will be my new approach.


#4

You may also want to look in to using the command “ramp.” You can combine it with use_bpm to ramp the bpm from say 100 to 150 at whatever speed you want. This is better for build up and slow down transitions. I have even tried using it within a song to make a slow break down section and then speed back up for a more dynamic sounding song.


#5

Hi all,

Does anyone know how I would go about changing the tempo for multiple live loops at once? Based on a few different post on this forum and the totorials, I’ve put together some test code that syncs three live loops to one master loop.

The loops stay synced if I start with them all commented out and add them in one at a time, as well as if I change any options in each loop once they are running. Unfortunately, when I try and use the method described above to change the tempo, the beeps often fall out of sync from the drums, sometimes to the point where they “disappear” entirely - it seems to be a function of when I re-run the code during the 8 beat :main loop. I’ve observed the problem when changing the tempo in the 60 - 90 bpm range.

use_debug true
use_synth :tb303
use_bpm 60
##| sleep 0.01
set(:bpm, current_bpm)
print 'current bpm: ' + current_bpm.to_s

##| set(:bpm, 60) # this doesn't fix the problem either...
##| print 'current bpm: ' + current_bpm.to_s

live_loop :main, delay: 0.001 do # delay solves the delayed start problem
  print 'main loop'
  use_bpm get(:bpm)
  sleep 8 ### THE SLEEP TIME OF THE MAIN LOOP SHOULD BE >= ALL OTHER LOOPS
end

live_loop :beep, sync: :main do
  print 'beeps'
  use_bpm get(:bpm)
  with_fx :panslicer, phase: 0.125, mix: 1 do
    play 42, release: 0.48, amp: 0.3
  end
  sleep 4 # this occurs every 4 beats (on 1 & 5)... but can only start on beat 1 (of 8)
end

live_loop :snare, sync: :main do
  use_bpm get(:bpm)
  sleep 1 # on 2, 4, 6, 8... but can only start on beat 1 (of 8)
  print 'snare'
  with_fx :echo, phase: 0.125, mix: 1, amp: 1 do
    sample :drum_snare_hard
  end
  sleep 1
end

live_loop :drum, sync: :main do
  use_bpm get(:bpm)
  print 'kick'
  with_fx :echo, decay: 6, mix: 1, amp: 1 do
    sample :bd_haus
  end
  sleep 2 # on 1, 3, 5, 7... but can only start on beat 1 (of 8)
end

Also, I don’t know if it has any impact on the problem, but when I run my code, I get the following warning:

{run: 612, time: 0.001, thread: :live_loop_main}
├─ Timing warning: running slightly behind…
└─ "main loop"

Does anyone have any suggestions on how to solve this problem? Or perhaps I’m not approaching live looping in the most logical way? Adding the “sync: :main” option to the live_loop definition (rather than inside the block) made the most sense to me, but maybe I need to rethink that technique…? I also tried using the “sync_bpm: :main” option, but that doesn’t help either.

Thanks in advance for your help!

Cheers,
-eric


#6

Try this alternative approach using multiple at commands in separate in_thread statements inside the main live_loop.

I’ve included a separate live_loop to randomly adjust the bpm. The main live_loop will pick up the current value each time it starts. The delay: in the main loop is to make sure the initial bpm is set before the live_loop starts first time.

#example using multiple at commands by Robin Newman
use_debug false

live_loop :randbpm do #random adjustment of bpm
  set :bpm,rrand_i(40,120)
  sleep rrand(4,12) #changed at random time intervals
end


live_loop :main,delay: 0.01 do #delay makes sure initial bmp set
  
  use_bpm get(:bpm) #one bpm adjusts everything
  puts"using bpm #{get(:bpm)}"
  puts"atart main"
  
  #in_thread do #NB the in_thread wrappers are superfluous...see next post

    #NB at must have a space after it before the [
    at [0,4] do #elapsed time 0=> beat 1,4=> beat 5
      puts "beeps"      
      with_fx :panslicer, phase: 0.125, mix: 1 do
        play 42, release: 0.48, amp: 0.3
      end
    end
  #end
  
  #in_thread do
    at [1,3,5,7] do #elapsed time 1=> beat 2 etc
      print 'snare'
      with_fx :echo, phase: 0.125, mix: 1, amp: 1 do
        sample :drum_snare_hard
      end
    end
 #end
  
  #in_thread do
    at [0,1,2,3,4,5,6,7] do      
      print 'kick'
      with_fx :echo, decay: 6, mix: 1, amp: 1 do
        sample :bd_haus
      end
    end
  #end
  
  sleep 8
end

#7

Hi @robin.newman,

as far as I understood (and checked the example), you can skip the in_thread: “Note, all code within the block is executed in its own thread…” (from Help > at). Or am I mistaken?

Happy new year!!

Martin


#8

Yes you are right. I’ve edited the original to remove the in-threads


#10

Thank you Robin and Martin! It seems that the at function is exactly what I’ve been missing.

I get the impression from many of the tutorials/documentation that I’ve read that it’s generally good practice to run separate live_loops for various elements (or at least that’s what is most intuitive to me). The at method seems to let me use this general structure while also using a single main live_loop to keep everything in sync, so I can easily add/modify single elements (the key being to just have a common sleep time for each live_loop to avoid things getting weird if the tempo changes).

Also, I was able to extend the flexibility of this at looping technique using the spread function to quickly create beat sequences with the following structure:

beat_inds = spread(2,8) # --> (ring true, false, false, false, true, false, false, false)
at beat_inds.each_index.select{ |i| beat_inds[i] == true } do # same as at [0,4]

Hopefully this technique can be useful to others. In general, it seems there’s a ton of useful “hidden” ruby functionality built into Sonic Pi.

Cheers,
-eric