How can I make an even-spaced polyrhythm?

I often use “spread” for making polyrhythmic songs but would like to know if there’s a way that I can instead evenly space notes over a bar such that multiple time-signatures are overlapping.

For example I want one live_loop to be playing a note sequence in 4/4 while another overlaps it in 5/4. This would mean that the bar’s sleep must be divided by 5. I fear if I divide the sleep by 5 it will return a rounded number which will eventually lead to the loops straying out of time. Or can I perhaps sync the 5/4 loop up such that no straying happens?

Or maybe a better way would be if each loop had an independent bpm… I’m not sure how to do that though.

I’m sure someone must have done this so what’s the best way to go about it?

Here’s one I did before.

Thanks. I may end up playing around with that but not sure that it would be ideal for what I’m doing. I’d still prefer a simple coded way so I can manipulate the coded for my purposes. I’d especially like if I could use “ring” to cycle through time signatures part way through the bars for some really intricate stuff. I assume if you built a whole interface which which is capable of dividing the sleep into equal segments without the aforementioned issues then you must know how to accomplish this within SonicPi itself.

Keep It Simple and Stupid ^^

live_loop :foo do; tick
  sample :perc_bell if bools(1,0,0,0).look
  sample :perc_bell2 if bools(1,0,0,0,0).look
  sleep 1
end

EDIT: Oh wait this doesn’t accomplish what I want I don’t think. I want to the notes evenly spaced over a bar. For example 4 notes played equally spaced over the course of 1 sleep while another loop plays 5 notes played equally spaced over the length of one sleep. How can I do that?

Ahh wow I feel stupid focusing on the sleep when I could have just kept that constant. This is great and I think I can see a way to manipulate the time signature realtime or with rings so thats good.

Here is a cut down of my project. The idea is that you specify 1 beat as the length for each different sample stream. Thus you can have :bd_haus say played once per cycle.
Or you could have two …elec_twips played with equal spacing in 1 beat, and so on for three, four… samples per beat. You do this simply by adjusting the sleep time and using a loop to play the sample the number of times required. eg

4.times do
  sample :bd_haus
  sleep 1.0/4
end

You can put this in a definition with a few more bells and whistles, and run this definition inside a live loop.

define :pl do |s,n,p=0,a=0,sp| #params samplename,beats/cycle,pan,amp,spread value
  t=1.0/n
  sp = [[n,sp].min,1].max #this line restricts the range of sp from 1..n
  use_bpm get(:bpm) #set current bpm
  n.times do #play number of samples per cycle for current element
    sample s,amp: a,pan: p if spread(sp,n).tick
    sleep t
  end
end

I add pan and amp settings, and a spread function with range spread(1,n) up to spread(n,n) where n is the number of pulses per beat.
The whole program them becomes

set :bpm,45

define :pl do |s,n,p=0,a=0,sp| #params samplename,beats/cycle,pan,amp,spread value
  t=1.0/n
  sp = [[n,sp].min,1].max
  use_bpm get(:bpm) #set current bpm
  n.times do #play number of samples per cycle for current element
    sample s,amp: a,pan: p if spread(sp,n).tick
    sleep t
  end
end

live_loop :metro do
  use_bpm get(:bpm)
  sleep 1
end

live_loop :s1,sync: :metro do
  pl(:elec_twip,6,-1,1,3)
end

live_loop :s2,sync: :metro do
  pl(:bd_haus,5,1,1,3)
end
live_loop :s3,sync: :metro do
  pl(:drum_snare_soft,3,-0.5,1,2)
end
live_loop :s4,sync: :metro do
  pl(:elec_wood,7,-0.7,0.5,3)
end
live_loop :s5,sync: :metro do
  pl(:elec_flip,11,-0.5,1,8)
end

The metro loop keeps everything in sync. You can alter any of the paramters for one of the playing loops to adjust sample, number of pulses per beat, pan, amp and spread setting. When you rerun the new settings are taken up next time the live loop starts.
You could use boolean lists instead of spread, and pass in parameters if you want, and you can have further live loops to increase the number of samples used.
You can also adjust the tempo using the first line, and the new value is picked up when the next cycle starts keeping everything in sync.

Ahh perfect. Yeah thanks for showing how you kept that all in sync. I’m excited to try this out!