Quantizing live_loop restart

Hi all, this is my first post. I have just recently gotten started with Sonic Pi, and I’m tremendously excited about the possibilities, but for now I’m stuck scratching my head with the following issue:

Let’s say I have a pattern that I’d like to start from the beginning at arbitrary times; the analogy would be a “reset” input on a sequencer. I can get a live_loop to do this with the following code:

define :play_patt do |restart = false|
live_loop :run_patt do
use_bpm tempo
if restart
tick_reset
restart = false
end
play patt.ring.tick
sleep 1
end
end

play_patt true

and then I just need to hit M-r and the loop starts from the pattern’s first element accordingly.

But if I want to quantize the loop restart, for example to only take effect when a new bar comes around, I’m trying to do this:

sync :new_bar
play_patt true

the :new_bar cue comes from this code:

live_loop :pulse do
cue :new_bar
use_bpm tempo
sleep 4
end

My problem is that the pattern restarts on the beat after the new bar. It appears that waiting for the :new_bar cue “wastes” that actual step, and the pattern restart can only happen the next time around. That’s not what I’m looking for, so I’d be quite grateful for any thoughts on how to quantize user-entered events to an upcoming bar change (or any arbitrary time), and not the next available step after that happens.

If the above doesn’t make sense, here’s an entire example that highlights the issue, with a metronome as well. Any interested respondents should see when hitting M-r, that the pattern only resets on the step after the bar changes. Any suggestions? Thanks in advance for any help.

tempo = 90
beats_per_bar = 4
patt = [:c2, :d2, :e2, :f2, :g2, :a2, :b2, :c3, :c3, :d3, :e3, :f3, :g3, :a3, :b3, :c4]

live_loop :pulse do
cue :new_bar
use_bpm tempo
sleep 4
end

live_loop :metronome do
use_bpm tempo
n = (knit 96, 1, 84, beats_per_bar - 1).tick
play n, release: 0.15
sleep 1
end

define :play_patt do |restart = false|
live_loop :run_patt do
use_bpm tempo
if restart
tick_reset
restart = false
end
play patt.ring.tick
sleep 1
end
end

sync :new_bar
play_patt true

Further to the above, I see that indents don’t make it to forum posts when pasting from the Sonic Pi editor. Any direction on the proper way to include code snippets for this newb will also be appreciated.

Try highlighting code snippet then Ctrl-Shift-9

I’m having to think back a couple of years now, so my guess may be wrong…

You are thinking that SP works in 4 beats, 1,2,3,4… I think it works in 4 beats
too… 0,1,2,3 …

If I’m wrong, fair enough…:slight_smile: My ‘Plan B’ would be, have you considered the 'at’
command:

Eli…

use_bpm 60
beats_per_bar = 4

patt = [:c2, :d2, :e2, :f2, :g2, :a2, :b2, :c3, :c3, :d3, :e3, :f3, :g3, :a3, :b3, :c4]

live_loop :new_bar do
  sleep 4
end

live_loop :metronome do
  n = (knit 96, 1, 84, beats_per_bar - 1).tick
  play n, release: 0.15
  sleep 1
end

define :hat do
  at [0] do
    sample :drum_cymbal_pedal, amp: 0.4
  end
end

live_loop :do_toms do
  sync :new_bar
  hat
  sleep 1
end

You can add three back ticks before and after code in forum post to keep indents and highlight in colours:

code...

which is: ``` before and after.

Hi,

you can use 3 backticks at the beginning and 3 at the end of

# this is a block of code
live_loop :indent do
  play :c 
  sleep 1
end

as documented here (it’s Markdown notation).

Thanks everyone for your responses, both on post formatting and my quantization question. Re: the latter, I’m pretty sure I’m not confusing 0-based and 1-based indexing; my problem seems to be that if I want to sync a command to a cue, by the time the cue rolls around, it’s too late to run what I want to run on the actual bar change (which is my quantization target). I’m able to make the following work, basically sending another, “pre-cue” to run the command of interest before the bar and live_loop “turn over”. Not particularly elegant, but it works so far. If anyone has any better ideas, I’m all ears.

‘’'
tempo = 90
beats_per_bar = 4
patt = [:c2, :d2, :e2, :f2, :g2, :a2, :b2, :c3, :c3, :d3, :e3, :f3, :g3, :a3, :b3, :c4]

live_loop :pulse do
cue :new_bar
use_bpm tempo
sleep 3.9
cue :upcoming_bar
sleep 0.1
end

live_loop :metronome do
use_bpm tempo
n = (knit 96, 1, 84, beats_per_bar - 1).tick
play n, release: 0.15
sleep 1
end

define :play_patt do |restart = false|
live_loop :run_patt do
use_bpm tempo
if restart
tick_reset
restart = false
end
play patt.ring.tick
sleep 1
end
end

sync :upcoming_bar
play_patt true
’’’

Trying to post the code again with backticks…

tempo = 90
beats_per_bar = 4
patt = [:c2, :d2, :e2, :f2, :g2, :a2, :b2, :c3, :c3, :d3, :e3, :f3, :g3, :a3, :b3, :c4]

live_loop :pulse do
  cue :new_bar
  use_bpm tempo
  sleep 3.9
  cue :upcoming_bar
  sleep 0.1
end

live_loop :metronome do
  use_bpm tempo
  n = (knit 96, 1, 84, beats_per_bar - 1).tick
  play n, release: 0.15
  sleep 1
end

define :play_patt do |restart = false|
  live_loop :run_patt do
    use_bpm tempo
    if restart
      tick_reset
      restart = false
    end
    play patt.ring.tick
    sleep 1
  end
end

sync :upcoming_bar
play_patt true

Well, if it works it works, but I’m sure there must be something we’ve missed…
Perhaps the big guns like Robin or Xav can advise.

Eli…

I am not sure but I suppose you are adressing a behaviour that I (and others) have also noticed:

I also think that this is not a behaviour to be expected but there has not been any confirmation that this is a bug.

While working with live_loop in the case I want/need to synchronise one phrase (e. g. a drum pattern) with another (e. g. bass) I usually use two metronomes to solve this. Something like that:

live_loop :beat do
  sleep 1
end

live_loop :four_bars, sync: :beat do
  sleep 16
end

live_loop :drums, sync: :four_bars do
  # code for 16-beat long drum loop
end

live_loop :bass, sync: :four_bars do
  # code for 16-beat long bass loop
end

@Martin, I think the phenomenon that you’ve noticed may be at the heart of my issue as well, with the cue not propagating when you might expect it to.

I can replicate something similar to what you noted in the post you referenced. I’m running 3.0.1 on a Mac, and the following code results in loops :b and :c not starting until :a has done a cycle:

live_loop :a do
  sleep 4
end

live_loop :b, sync: :a do
  sample :drum_heavy_kick
  sleep 1
end

live_loop :c, sync: :a do
  sample :perc_snap2
  sleep 0.5
end

Interestingly, if I add a very small delay to the start of loop :a, loops :b and :c will start immediately:

live_loop :a, delay: 0.000000001 do
  sleep 4
end

live_loop :b, sync: :a do
  sample :drum_heavy_kick
  sleep 1
end

live_loop :c, sync: :a do
  sample :perc_snap2
  sleep 0.5
end

Smarter folks than me will have to figure out what to make of this.

See @samaaron’s update at: https://github.com/samaaron/sonic-pi/issues/1730

for an explanation :wink: