More real randomization

Hi, I have opened an issue ticket in Github, and only later discovered this forum. My ticket is rather a question, so admins, please feel free to just close it on github if you will.
Here I paste what I wrote there:

I have read documentation and tutorials on random methods. I do understand that reproducible behavior is in the philosophy of Sonic pi.
However I am trying to come up with a way to get random number on each run. It does not have to be random per se, I only want it appear random, i.e. different on every run. I would use it as an argument for use_random_seed.
The reason I want this kind of behavior is because Iā€™m using Sonic pi for my guitar practice. Iā€™m trying to build routines that would print out random notes, chords, scales, etc from predefined collections and then play them after some sleep time. The idea is that this playback should be as a reference or confirmation for me that what I played on my guitar was indeed what I was supposed to play.
Now I do understand that I can edit the seed before every run, but that is not the level of automation that I am aiming for.
Here comes my question: is there a method in Sonic pi DSL, or accessible outside of DSL that I could use to make a seed from itā€™s return? A hash, a time-stamp, or any other value that I could process into a different value on every run?

Any ideas appreciated.
TIA

2 Likes

Hi,

maybe you could use something like:

t = Time.now.to_i
use_random_seed t
puts rand

which uses a timestamp to change the random_seed constantly. But - as @samaaron told on different occasions - using native ruby stuff is a bit like the Wild West. You should not be sure whether and how long the laws of Sonic Pi will accept and support that. But the code bit above seems to work. Someone with more internal knowledge might have a better idea.

3 Likes

Sounds like a simple use of rand_i(number) would work hereā€¦

Eliā€¦
,
live_loop :loopy do

number = rand_i(10000)
puts number
use_random_seed number
sleep 5

end

2 Likes

Martin, thank you this is just what I needed. I should have thought of it my self :slight_smile: I know itā€™s ruby and at the same time itā€™s not. Didnā€™t even try using Time class methods - thought it wasnā€™t accessible :smiley:

I love ruby, it is a shame it is stripped down in SonicPi, although I understand the motivation behind this.

1 Like

Eli, thank you, but this is not the solution. As you may or may not know all randomization functions in SonicPi are not actually random. They just appear random.
rand_i(10000) will always return 7500 on first iteration of any run. Also every sequential iterations will follow the same pattern. This behavior is intentional in SonicPi as the code should always produce identical outcome on every run. In other words the behavior has to be reproducible.
However for my specific use for guitar practice, I didā€™n want the pattern to be the same on every run. And for that I need an ever changing seed. As in Martinā€™s reply, Time.now() provides me exactly that.

1 Like

Hokayā€¦ I misread your intention. :slight_smile:

Eliā€¦

Hi, @Martin is right:

use_random_seed Time.now.to_i

is the best approach for doing what you want. Heā€™s also right in that itā€™s unsupported, so behaviour might change in the future, but donā€™t let that stop you from using it!

2 Likes

Thanks yā€™all, been meaning to ask that one for a while, I had a feeling it would be something like that, how I learned to do true random in lua.

#keys E(4)ā€¦G(7)ā€¦(A9)ā€¦C(0)ā€¦D(2)

key=9; mn=[];for jn in 1ā€¦1024
mn[jn]=key+(hz_to_midi(11*jn)); end
mn[0]=:r

c=[9,8,6,9, 6,6,6,6, 8,8,6,6];o=[1,2,4]
m=[2,0,4,0,3,4,0,2,4,0,4,0,3,4,0,0]

use_bpm 80
live_loop :keys do
for i in 0ā€¦95; x=i/8; y=i%16
r=rand_i(3); s=rand_i(3); t=rand_i(3)
synth :piano, note: mn[c[x]*m[y]*o[r]]-24
synth :piano, note: mn[c[x]*m[y]*o[s]]-24
synth :piano, note: mn[c[x]*m[y]*o[t]]-24
sleep 0.25; end; end

Hello.

For more real random I use

r=Random.rand(1..10) 

for random numbers from 1 to 10 included.

Hi,

I just have had some time on a train and went nuts with tick and randomnessā€¦ I came up with that code:

live_loop :ambient do
  t = Time.now.to_i
  use_random_seed t
  puts "Time: #{t}"
  z = [58,60,63,66,68,70,72,74].choose
  n = ((chord :c, :m7) + [z]).sort
  v = (line 0.25, 1, steps: 100).reflect
  p = (line -0.85, 0.85, steps: 100).reflect
  with_fx :reverb, room: 0.75, mix: rrand(0,1) do
    s = synth :fm, note: n.tick(:n), attack: [0,0,0,0,2].choose, release: [0.5,0.5,0.5,2].choose, amp: v.tick, pan: p.look, depth: 0.1, divisor: 1
    control s, amp: v.tick, amp_slide: 0.25, pan: p.look, pan_slide: 0.25, depth: 2, depth_slide: 1.5
  end
  sleep 0.25
end

Nothing really special, but what I like about it are two things: 1. seems to have a somehow purposeful harmonic sequence (for me despite the disharmonic bits in it) allthough it hasnā€™t actually. At least not from the constructional perspective. 2. There seem to be two independant voices at work but there is only one line (where the attack/release switches between long and short, which mainly gives that impression).

2 Likes

This sounds great Martin. Thanks for sharing

This is beautiful. Seriously.

I forked Martinā€™s randomness experiment, changing it to fit my need (Iā€™m using it in a darker-sounding track), and also amplifying the randomness by a lot. Because the seed will only change once every beat, I added an increase/decrease by a random number (determined by the previous random seed). This, with the panning and the Prophet synth, leads to one of the trippiest riffs I have ever experienced. Period.

live_loop :ambient do
  t = Time.now.to_i + rrand_i(-1000000000000000000000000000000000000, 1000000000000000000000000000000000000)
  use_random_seed t
  puts "Time: #{t}"
  z = [58,60,63,66,68,70,72,74].choose
  n = ((chord :c, :m7) + [z]).sort
  v = (line 0.25, 1).reflect
  p = (line -0.85, 0.85, steps: 150).reflect
  with_fx :reverb, room: 0.75, mix: rrand(0,1) do
    s = synth :prophet, note: n.tick(:n), attack: [0,0,0,0,2].choose, release: [0.5,0.5,0.5,2].choose, amp: v.tick, pan: p.look
    s = synth :dark_ambience, note: n.tick(:n), attack: [0, 0.125, 0.25, 0.5, 0.625, 0.75, 0.825, 1].choose, release: [0.5,0.5,0.5,2].choose, amp: 1, pan: p.look, cutoff: 128, noise: [0,1,2,3,4].choose, ring: [rrand(0.1, 50), rrand(0.1, 50), rrand(0.1, 50)].choose
    control s, amp: v.tick, amp_slide: [0.0625, 0.25].choose, pan: p.look, pan_slide: 0.25, depth: 2, depth_slide: 1.5
  end
  sleep 0.25
end

Nice! For an even darker twist, try lowering the octave and applying the prophetā€™s built-in low pass filter randomly:

live_loop :ambient do
  use_octave -2
  t = Time.now.to_i + rrand_i(-1000000000000000000000000000000000000, 1000000000000000000000000000000000000)
  use_random_seed t
  puts "Time: #{t}"
  z = [58,60,63,66,68,70,72,74].choose
  n = ((chord :c, :m7) + [z]).sort
  v = (line 0.25, 1).reflect
  p = (line -0.85, 0.85, steps: 150).reflect
  with_fx :reverb, room: 0.75, mix: rrand(0,1) do
    s = synth :prophet, note: n.tick(:n), attack: [0,0,0,0,2].choose, release: [0.5,0.5,0.5,2].choose, amp: v.tick, pan: p.look, cutoff: rrand(70, 120)
    s = synth :dark_ambience, note: n.tick(:n), attack: [0, 0.125, 0.25, 0.5, 0.625, 0.75, 0.825, 1].choose, release: [0.5,0.5,0.5,2].choose, amp: 1, pan: p.look, cutoff: 128, noise: [0,1,2,3,4].choose, ring: [rrand(0.1, 50), rrand(0.1, 50), rrand(0.1, 50)].choose
    control s, amp: v.tick, amp_slide: [0.0625, 0.25].choose, pan: p.look, pan_slide: 0.25, depth: 2, depth_slide: 1.5
  end
  sleep 0.25
end

I actually fiddled with it a bit further and did lower the octave, although I completely forgot the Prophet LPF. I used the :distortion FX as well to make it sound a bit more twisted, although I opted (heh, heh.) to not use any randomization with the distortion level, simply for the sake of reducing load time.

What do you mean by ā€˜load timeā€™? :slight_smile:

I use an 8-year-old laptop and havenā€™t gotten around to upgrading/replacing it yet so it takes awhile to do pretty much anything, which includes loading FX/synths. The only reason I use it as opposed to my RPi 3B is because it has better audio quality (well, that and my nephew broke my USB keyboardā€¦)

Iā€™m still not quite sure what you mean by ā€œloading FX/synthsā€. All the synthdefs are loaded at boot time, so thereā€™s no loading going on. Only the samples are loaded on-the-fly (which you can pre-empt by using the load_sample fn).

When you say ā€œloading FX/synthsā€ what are you observing? Are you seeing timing issues?

I misspoke (mis-typed?). As you say, the FX and synths are loaded at boot-time. Iā€™ve been meaning to replace the audio card in my lappy for some time now (I got a custom one about 5 years ago and itā€™s starting to wear down between my SP usage and my Reaper usage), so itā€™s more likely than not just a hardware issue ā€” the rendering of the audio is whatā€™s slow, I believe. Iā€™ve been having this issue when playing tracks in Reaper as well, so itā€™s definitely not a problem with SP.

Sorry for the lack of clarity.

1 Like