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?
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.
Thx Robin that will be my new approach.
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.
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
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
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
Yes you are right. I’ve edited the original to remove the in-threads
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
I don’t think I have this problem, with this code* the loops seem to stay synced, even after re-runs with new use_bpm
*re above code from @scientificsound
- Is there an issue with the code (eg will the loop timing logic result in async loops?)
If there is an issue (or even if not!)
2. is the at
usage recommended, eg when to use at vs sync|cue|delay|sleep
, or are they basically equivalent and personal preference?
- Can this be achieved using sync_bpm ?
(This seems like this is === and slightly less keystrokes than sync and use_bpm)
Also I couldn’t see any example syntax for the init block argument,
4. is there an example available?
I tried adding wrapped in quotes as the {blok}
I passed was invalid, eg
live_loop :drum, sync: :main, init: "play 42" do
and
live_loop :drum, sync: :main, init: "puts 'test'" do
and get no error, but expected behaviour isn’t observed, making me think live_loop init: is intended for other usage (or my syntax is wrong!)
Many thanks for any more insights!
In order to change BPM in transitions during live coding - the best way is to use the Link BPM to drive the BPM for all your Live Loops (which is now the default). If you use ‘use_bpm’ with a numeric BPM then your’e using a static BPM and you’re in charge of managing any updates. If you don’t call ‘use_bpm’ or use the :link
argument, then the current thread’s BPM will be set to the Link clock which you can dynamically change (with all threads in Link BPM mode changing their BPM to match). You can also put the Link clock in network sync mode to sync with other Link-powered software across the network.
the init:
opt for live_loop
is just for setting an initial seed value which is passed in as an implicit argument and then replaced with the last value returned at the end of the live loop which is threaded back round.
See example #6 in the live loop documentation for an example of this in action:
live_loop :foo do |a|
puts a
sleep 1
a += 1
end
which will print 0, 1, 2, 3, 4, 5…
If you use the init:
opt you can change the initial value:
live_loop :foo, init: 10 do |a|
puts a
sleep 1
a += 1
end
This will print 10, 11, 12, 13…
Hope this helps.
Thanks for clarifying
I’ve just taken another script from the threads that was shared, and commented out the use_bpm
command to test the link_clock, wasn’t sure if I had to connect at first but the 0 devices is just the number of other connected devices, and I found the shorcuts for tap tempo and Link
Couple of things
- I can’t tab-focus the text box (it’s mapped to codeEditor-indent)
Is there a way to focus, without using the mouse?
I looked at the code to try to work out how it works but it’s a little intimidating, I imagine it’s not as simple as adding a few lines to add that element to the focus list
- can the clock be dynamically changed via a command?
I checked the docs on link / link_sync, and measures and beats are mentioned, but not bpm.
Kindest Regards
Yep, see the menu item View → Focus BPM Scrubber (shortcut Control-Shift-B)
Yep - set_link_bpm!