Constrained 'random' melody generator

Hi everyone,
I am still very much in my infancy as a Sonic Pi musician, and present below a super simple constrained random melody generator. I have seen Markov chains in use here and elsewhere to this end, but the maths is beyond me I’m sorry to say. It steps through a sequence of pitches, generating a repeating pattern of neighbour and near-neighbour notes.

``````
myNotes = (ring 48, 51, 53, 55, 58, 60, 63, 65, 67, 70, 72)
/ random motifs, moving thru ring /
live_loop :take4 do
|x|
rnd = rrand_i(0, 50)
use_random_seed rnd

play myNotes[x] # play 1st note of group in order
sleep 0.5
3.times do
play myNotes [rrand_i(x, (x+4)% myNotes.length)]
/ this seeks to prevent larger leaps /
sleep [0.25, 0.25, 0.5].tick
end
sleep 1
x = x + 1
end
``````

This will do for now, but I’ll continue to noodle with it today. Any and all suggestions humbly welcomed

PD-Pi

4 Likes

Hello @brendanmac great stuff, really…Could you just explain this line of code with more details? :

``````play myNotes [rrand_i(x, (x+4)% myNotes.length)]
``````

I just changed 2 ou 3 things to make it sound like an african instrument or something like that. With “phase: 6” my idea is to create a kind of polyphony…
Thanks for attention

``````with_fx :reverb, room: 0.8, mix: 0.3 do
with_fx :echo, phase: 6 do
myNotes = (ring 48, 51, 53, 55, 58, 60, 63, 65, 67, 70, 72)
/ random motifs, moving thru ring /
live_loop :take4 do
|x|
rnd = rrand_i(0, 50)
use_random_seed rnd

play myNotes[x] # play 1st note of group in order
sleep 0.5
3.times do
use_synth :pretty_bell
play myNotes [rrand_i(x, (x+4)% myNotes.length)]
/ this seeks to prevent larger leaps /
sleep [0.25, 0.25, 0.5,0.5,0.25].tick
end
sleep 1
x = x + 1
end

end
end
``````
1 Like

Hi @beryann
that specific line constrains the range of random notes chosen from the larger array - first time through the inner loop x = 0, so it chooses 3 notes between index 0 and 4, then the next time x = 1 so chooses between 1 and 5 etc, such that the little motif rises through the scale (array). The modulus (%) ensures the random index is within (and not beyond) the total length of the array. It is far from perfect, and I am still tinkering with it but happy that you have made some use of it.

PD-Pi

1 Like

. . . and your use of echo is a perfect and simple way to impose a little order on the patterns!!

1 Like

I see…that’s great! thanks to have shared it @brendanmac ok i see now what you want to do…This is very interesting in any case and deserves to be studied carefully!

This is fantastic! Thank you thank you!

1 Like

Very cool take on making smoother random melodies.
Ive also experimented with trying to add move stepwise motion and reduce the number of large leaps in randomized melodies.

Something I noticed in your code was the use of trying to randomize the use_random_seed argument

``````rnd = rrand_i(0, 50)
use_random_seed rnd
``````

However, the way Sonic Pi is set up, this will always produce the same results. If you print the rnd variable, it will always go 47, 25, 27, 46 etc. You can read more about this behavior in the docs, under Appendix A.9 Randomization

You can use

``````use_random_seed Time.Now.to_i
``````

which will always return a different value and give more true randomness to your code.

1 Like

Hi @mrbombmusic and thanks for replying (and even bigger thanks for your indispensable tutorial series too!!).

I will def check out those two links, but I am aware of the repetitive results when trying to randomise a random seed (after watching and digesting every single one of your videos) . And I chose the upper bound 50 because it gives me ‘some’ randomisation, any lower and the random seed sticks in predictable ways.

Is using Time.now computationally expensive? I’ll give it a rattle and see what effect it has.

Thanks again
PD-Pi

ps I’m having waaaay too much fun with :pluck this week, and have written a really cool generative plucked/bowed autoharp thingy, which I may integrate with the melody generator above. Video coming soon

1 Like

update

This serves my immediate needs better; using constrained randomisation (rand % n) I can control the variety and length of patterns - whether that’s riffs, percussion, bass, any event really. This is barebones and can be developed with greater control over sleep times etc. But it does what I - and hopefully some of you - want. I found that using Time.now was too random, and using my OP method was not random enough. HTH

``````live_loop :rndy do |i|
tick

variety = 3 #how many different riffs?
length = 4 #how many pitches in riffs?

rnd =  (ring 1,7,23,53).look * i % variety
use_random_seed rnd
puts rnd

length.times do
play (scale :c4, :minor_pentatonic).choose, release: 0.5, amp: 0.4
sleep 0.5
end

i += 1
end
``````

The numbers in the ring are arbitrary, ymmv.

PD-Pi