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 :wink:

PD-Pi

4 Likes

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

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 :grinning:

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! :smile:

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.
I made a tutorial about it a while back: https://youtu.be/IfgafJ6nSH8?si=8YmF5oQNLU1_eNMD

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
I also made a tutorial about that :grinning:: https://youtu.be/Ise47Z5T8HQ?si=jTV6RmP99JinzGf9

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) :smiley: . 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 :wink:

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