Hi there,
in Sonic Pi, random streams are thread-local. This means that each thread (such as a live_loop) has its own independent stream of random numbers to work with. This is kind of analogous to having a pre-shuffled deck of cards to work with.
Every time a random function such as rand
, rrand
, choose
, etc is used, it will consume one rand from the random stream - or take one card from the pre-shuffled deck to determine the random value. This means that having just one call to, say, rand
in each live_loop will mean the random choices in each live loop are isolated from each other as they are each working with their own independent deck of pre-shuffled cards.
If you put more than one call to rand
in a live_loop, then you’re taking more than one card from the deck. This means that the calls will interfere with each other. So, say you’re using the specific order of the top 8 cards on the deck to drive your bassline, if you were to then use every other card (because you started consuming cards for the pan opt) then your bassline will inevitably change.
To fix this, you should either work with a new thread, or if that’s not possible (as it seems to be in your case) you can use the handy rand_back
function to undo a call to rand and effectively put a card back on the deck.
So, try this:
use_bpm 133
live_loop :melle do
with_fx :octaver, sub_amp: 2, amp: 1.5, mix: 0.4 do
with_fx :reverb, room: 0.6, mix: 0.6 do
use_synth :saw
use_random_seed (knit, 9864, 4, 235, 4).tick(:a)
sleep 1
14.times do
play scale(:c3, :ionian, num_octaves: 2).choose, amp: 0.15, pan: rrand(-1, 1), release: 0.5 if spread(10, 14).tick
rand_back
sleep 0.5
end
end
end
end
However, this won’t completely work as expected as you’re only calling the rrand
for pan:
if the spread value suggests it should. This is because you’re adding an if
at the end of the line so it doesn’t execute every time - whereas the rand_back
is executed every time.
For it to work as expected, we need to only call rand_back
when the rrand
is called.
We can therefore either put both the play
and rand_back
within the same larger if
statement:
if spread(10, 14).tick
play scale(:c3, :ionian, num_octaves: 2).choose, amp: 0.15, pan: rrand(-1, 1), release: 0.5
rand_back
end
Or my prefered solution is to use on:
instead of if
. That way the call to rrand
happens every time, but the synth is only triggered when the spread value is appropriate (whereas with the call to if
not only is the synth not triggered, but the whole line isn’t executed and therefore not the rrand
).
use_bpm 133
live_loop :melle do
with_fx :octaver, sub_amp: 2, amp: 1.5, mix: 0.4 do
with_fx :reverb, room: 0.6, mix: 0.6 do
use_synth :saw
use_random_seed (knit, 9864, 4, 235, 4).tick(:a)
sleep 1
14.times do
play scale(:c3, :ionian, num_octaves: 2).choose, amp: 0.15, pan: rrand(-1, 1), release: 0.5, on: spread(10, 14).tick
rand_back
sleep 0.5
end
end
end
end
Hope that this helps!