Patterns changing gradually

Being interested in Minimal Music and generative art, I am looking for ways to have musical patterns evolve slowly over time. Below I tried to solve this with making a list containing all possible 3-part-patterns and setting up rules of possible successions of these patterns. Patterns with all three elements in different positions are not allowed to follow one another.

use_random_seed 1100

#defining the six possible variations of a 3-note-pattern with set
set :u, (ring :a3,:b3,:c4)
set :v, (ring :a3,:c4,:b3)
set :w, (ring :b3,:a3,:c4)
set :x, (ring :b3,:c4,:a3)
set :y, (ring :c4,:a3,:b3)
set :z, (ring :c4,:b3,:a3)

#setting the release of the notes
set :rel, 0.1

#setting the rhythm
set :sl, 0.125


#defining the length of each pattern
in_thread(name: :length) do
  loop do
    set :n, ([4, 8].choose)
    sleep 4
  end
end



#Choosing the variation to begin with
cue [:ua, :va, :wa, :xa, :ya, :za].choose


in_thread(name: :container) do
  #six different threads, one for each variation, defining which variations may follow the respective variation
  in_thread(name: :ua) do
    loop do
      sync :ua
      get[:n].times do
        play_pattern_timed get[:u], get[:sl], release: get[:rel]
      end
      cue [:va,:wa,:za].choose
    end
  end
  
  
  in_thread(name: :va) do
    loop do
      sync :va
      get[:n].times do
        play_pattern_timed get[:v], get[:sl], release: get[:rel]
      end
      cue [:ya,:ua,:xa].choose
    end
  end
  
  in_thread(name: :wa) do
    loop do
      sync :wa
      get[:n].times do
        play_pattern_timed get[:w], get[:sl], release: get[:rel]
      end
      cue [:ya,:ua,:xa].choose
    end
  end
  
  in_thread(name: :za) do
    loop do
      sync :za
      get[:n].times do
        play_pattern_timed get[:z], get[:sl], release: get[:rel]
      end
      cue [:ya,:ua,:xa].choose
    end
  end
  
  in_thread(name: :ya) do
    loop do
      sync :ya
      get[:n].times do
        play_pattern_timed get[:y], get[:sl], release: get[:rel]
      end
      cue [:va,:za,:wa].choose
    end
  end
  
  in_thread(name: :xa) do
    loop do
      sync :xa
      get[:n].times do
        play_pattern_timed get[:x], get[:sl], release: get[:rel]
      end
      cue [:za,:wa,:va].choose
    end
  end
end

The code seems to work like I intended, but I have some questions:

  • To actually hear sound, I have to execute ā€œrunā€ twice, why?

  • When using patterns with more elements, or patterns with changing number of elements, this approach does not seem the best. I would prefer to be able to single out two elements and be able to change their positions within the pattern; or one element, and change itĀ“s pitch. How to do that?

Cheers,

Gisbert

2 Likes

Hi Gisbert,

welcome to the Sonic Pi community!

This is not an answer but more of a hint. @scossar has done a lot of nice stuff with Sonic Pi which definitely points into the direction you seem to be interested in. You might want to have a look: https://soundcloud.com/simoncossar

Hi Martin,

thanks, I will check it out!

The very same basic concept in a musically more elaborate version, adding a specific rhythm and effects to the patterns and a drumbeat.

use_random_seed 109

#Adding effects to the bass sound
with_fx :ixi_techno do
  with_fx :distortion do
    with_fx :wobble do
      #bass sound
      use_synth :sine
      
      #defining the six possible variations of a 3-note-pattern with set
      set :u, (ring :a1,:b1,:c2)
      set :v, (ring :a1,:c2,:b1)
      set :w, (ring :b1,:a1,:c2)
      set :x, (ring :b1,:c2,:a1)
      set :y, (ring :c2,:a1,:b1)
      set :z, (ring :c2,:b1,:a1)
      
      #setting the release of the notes
      set :rel, 0.1
      
      #setting the rhythm of the bass patterns
      set :sl, [0.375, 0.375, 0.25]
      
      
      #defining the length of each pattern
      in_thread(name: :length) do
        loop do
          set :n, ([2, 4, 8].choose)
          sleep 4
        end
      end
      
      #Choosing the variation to begin with
      cue [:ua, :va, :wa, :xa, :ya, :za].choose
      
      
      in_thread(name: :container) do
        #six different threads, one for each variation, defining which variations may follow the respective variation
        in_thread(name: :ua) do
          loop do
            sync :ua
            get[:n].times do
              play_pattern_timed get[:u], get[:sl], release: get[:rel]
            end
            cue [:va,:wa,:za].choose
            cue :beat
          end
        end
        
        
        in_thread(name: :va) do
          loop do
            sync :va
            get[:n].times do
              play_pattern_timed get[:v], get[:sl], release: get[:rel]
            end
            cue [:ya,:ua,:xa].choose
            cue :beat
          end
        end
        
        in_thread(name: :wa) do
          loop do
            sync :wa
            get[:n].times do
              play_pattern_timed get[:w], get[:sl], release: get[:rel]
            end
            cue [:ya,:ua,:xa].choose
            cue :beat
          end
        end
        
        in_thread(name: :za) do
          loop do
            sync :za
            get[:n].times do
              play_pattern_timed get[:z], get[:sl], release: get[:rel]
            end
            cue [:ya,:ua,:xa].choose
            cue :beat
          end
        end
        
        in_thread(name: :ya) do
          loop do
            sync :ya
            get[:n].times do
              play_pattern_timed get[:y], get[:sl], release: get[:rel]
            end
            cue [:va,:za,:wa].choose
            cue :beat
          end
        end
        
        in_thread(name: :xa) do
          loop do
            sync :xa
            get[:n].times do
              play_pattern_timed get[:x], get[:sl], release: get[:rel]
            end
            cue [:za,:wa,:va].choose
            cue :beat
          end
        end
      end
    end
  end
end


#Accompanying beat
in_thread(name: :beat) do
  sync :beat
  loop do
    get[:n].times do
      sample :drum_heavy_kick
      sleep 0.25
      sample :drum_cymbal_pedal
      sleep 0.25
      sample :drum_bass_soft
      sample :drum_heavy_kick
      sleep 0.25
      sample :drum_cymbal_pedal
      sleep 0.125
      sample :drum_cymbal_closed
      sleep 0.125
    end
  end
end

HI Gisbert and welcome.
You have some nice ideas here. I think the reason you need to run twice is that the cue is sent b efore the sync is set up, and therefore missed the first time round. If you move the cue line to the end and put a small delay before calling it all will b e well on the first run.

#moved to the end
sleep 0.01 #small delay to make sure that sync is waiting before the cues is issued.
#Choosing the variation to begin with
cue [:ua, :va, :wa, :xa, :ya, :za].choose
2 Likes

Hi Robin,
thanks for the clarification! This way it works fine :slight_smile:

This time IĀ“m not actually seeking help, but want to post a new approach to the same question - generating patterns that slowly evolve over time. This version is partly inspired by the App Nodebeat and the concept of having one sender triggering multiple ā€˜sound satellitesā€™.

Also, the whole topic is in context of my research on forms of ā€˜Minimal Improvisationā€™.
http://www.phyla.info/?portfolio=minimal-improvisation

Thanks to @Martin for bringing up an elegant solution to create indeterminism in this thread:

I like it so much when I do NOT know what pattern will come up when I press start.

IĀ“m very happy with this code as is, but IĀ“m also interested in your feedback.

#Evolving Patterns
t = Time.now.to_i
use_random_seed t
puts rand

use_synth :sine

in_thread do
  loop do
    set :teim, (ring 0.125, 0.25, 0.375).choose
    sleep rrand_i(64, 256)
  end
end

in_thread do
  loop do
    set :taim, (ring 0.5, 0.75, 1, 1.5, 2).choose
    sleep rrand_i(64, 256)
  end
end

#Sending out regular cues
in_thread do
  loop do
    cue :zakkk
    cue :pakkk
    cue :rakkk
    cue :rikkk
    sleep get[:taim]
  end
end


#Adding individual delay to be applied to each sound creates a rhythmic pattern
in_thread do
  loop do
    #Choosing the delay which is actually applied below
    set :wa, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
    #After some time, the delay is changed, thus the pattern changes
    sleep rrand_i(16, 256)
  end
end

in_thread do
  loop do
    set :wo, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
    sleep rrand_i(16, 256)
  end
end

in_thread do
  loop do
    set :wu, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
    sleep rrand_i(16, 256)
  end
end

in_thread do
  loop do
    set :wi, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
    sleep rrand_i(16, 256)
  end
end


in_thread do
  loop do
    sync :zakkk
    #The choosen amount of delay is applied
    wait get[:wa]
    #The sound is played
    play 66, amp: rrand(0.1, 1), release: rrand(0.1, 1)
  end
end


in_thread do
  loop do
    sync :pakkk
    wait get[:wo]
    play 68, amp: rrand(0.1, 1), release: rrand(0.1, 1)
  end
end



in_thread do
  loop do
    sync :rakkk
    wait get[:wu]
    play 59, amp: rrand(0.1, 1), release: rrand(0.1, 1)
  end
end

in_thread do
  loop do
    sync :rikkk
    wait get[:wi]
    play 61, amp: rrand(0.1, 1), release: rrand(0.1, 1)
  end
end

Some things I have in mind to add in the future:

  • Change not only rhythm over time but also pitch
  • Refine the variations of dynamics, these might also be subject to long-term changes or to patterns of accent
  • Combine this way to create change with ways to create large scale form, that is mechanisms that cause repetion of certain developements
  • Combine this with interactive mechanisms, for example have the tempo of movements influence the tempo of pattern changes

Also, instead of pitches, it is interesting to use drum samples or send midi to another device. I had some fun tweaking sounds in Ableton live while Sonic Pi served as the sequencer.

1 Like

Hi Gisbert,

I see that you use in_thread and loop do. As I understand you could replace this with the live_loop because essentially it is a combination of both (even though it does a bit more namely not create a new thread when evaluating again but update the current running ones).

You can put the sync as an option into the live_loop line which means: synchronise once the referenced live_loop has started (see the Sonic Pi tutorial or e. g. https://github.com/mbutz/sonic-pi-resources/blob/master/control_rhythmic_and_melodic_processes/synchronisation-of-live-loops.rb):

live_loop :a do
  # make something
end

live_loop :b, sync: :a do
  # make something else in sync with :a
end
1 Like

Hi Martin,
supercool, thanks!

The sync & cue-examples did not use live_loop so I hesitated to use it.
But itĀ“s really great to be able to change parameters while running live_loops!

I did an updated version, also applying slow random change to the pitches:

#Evolving Patterns
t = Time.now.to_i
use_random_seed t
puts rand

use_synth :sine

#Setting the minimum rhythmic unit
live_loop :define_delay do
  set :teim, (ring 0.125, 0.25, 0.375).choose
  sleep rrand_i(64, 256)
end

#Setting the length of the repeated pattern
live_loop :define_phrase do
  set :taim, (ring 0.5, 0.75, 1, 1.5, 2).choose
  sleep rrand_i(64, 256)
end

#Setting the four different pitches
live_loop :setting_pitch_one do
  set :pitch_one, rrand(40, 85)
  sleep rrand_i(64, 512)
end

live_loop :setting_pitch_two do
  set :pitch_two, rrand(40, 85)
  sleep rrand_i(64, 512)
end

live_loop :setting_pitch_three do
  set :pitch_three, rrand(40, 85)
  sleep rrand_i(64, 512)
end

live_loop :setting_pitch_four do
  set :pitch_four, rrand(40, 85)
  sleep rrand_i(64, 512)
end

#Sending out regular cues
live_loop :cues do
  cue :zakkk
  cue :pakkk
  cue :rakkk
  cue :rikkk
  sleep get[:taim]
end


#Adding the individual delay defined above to be applied to each sound creates a rhythmic pattern
live_loop :chooser_one do
  #Choosing the delay which is actually applied below
  set :wa, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  #After some time, the delay is changed, thus the pattern changes
  sleep rrand_i(16, 256)
end

live_loop :chooser_two do
  set :wo, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end

live_loop :chooser_three do
  set :wu, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end

live_loop :chooser_four do
  set :wi, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end


live_loop :sound_one do
  sync :zakkk
  #The choosen amount of delay is applied
  wait get[:wa]
  #The sound is played
  play get[:pitch_one], amp: rrand(0.1, 1), release: rrand(0.1, 0.8)
end

live_loop :sound_two do
  sync :pakkk
  wait get[:wo]
  play get[:pitch_two], amp: rrand(0.1, 1), release: rrand(0.1, 0.8)
end

live_loop :sound_three do
  sync :rakkk
  wait get[:wu]
  play get[:pitch_three], amp: rrand(0.1, 1), release: rrand(0.1, 0.8)
end

live_loop :sound_four do
  sync :rikkk
  wait get[:wi]
  play get[:pitch_four], amp: rrand(0.1, 1), release: rrand(0.1, 0.8)
end
1 Like

I kept working on this topic, so here is some context why this is so interesting to me:
http://www.phyla.info/?p=2845

Some audio examples - drums:

[iframe]https://hearthis.at/embed/2078657/transparent_black/?hcolor=&color=&style=2&block_size=2&block_space=1&background=1&waveform=0&cover=0&autoplay=0&css=[/iframe]

Sine sounds:

[iframe]https://hearthis.at/embed/2078393/transparent_black/?hcolor=&color=&style=2&block_size=2&block_space=1&background=1&waveform=0&cover=0&autoplay=0&css=[/iframe]

Sines & Drums:

[iframe]https://hearthis.at/embed/2078659/transparent_black/?hcolor=&color=&style=2&block_size=2&block_space=1&background=1&waveform=0&cover=0&autoplay=0&css=[/iframe]

[iframe]https://hearthis.at/embed/2078658/transparent_black/?hcolor=&color=&style=2&block_size=2&block_space=1&background=1&waveform=0&cover=0&autoplay=0&css=[/iframe]

Code for sines & drums:

#Evolving synth and drums asymetrical pattern length 2
t = Time.now.to_i
use_random_seed t
puts rand

use_synth :sine

use_bpm 52

#Setting the minimum rhythmic unit
live_loop :define_delay do
  set :teim, (ring 0.1, 0.2, 0.3, 0.4).choose
  sleep rrand_i(1, 256)
end

#Setting the lengths of the repeated patterns
#Symetric patterns
live_loop :define_phrase1 do
  set :taim1, (ring 0.3, 0.4, 0.6, 1.2, 2.4).choose
  sleep rrand_i(1, 256)
end

live_loop :define_phrase2 do
  set :taim2, (ring 0.3, 0.4, 0.6, 1.2, 2.4).choose
  sleep rrand_i(1, 256)
end


#Asymetric pattern
live_loop :define_phrase3 do
  if rand < 0.5
  then
    if rand < 0.5
    then
      set :taim3a, 1
      set :taim3b, 1.4
    else
      set :taim3a, 1.4
      set :taim3b, 1
    end
  else
    if rand < 0.5
    then
      set :taim3a, 0.5
      set :taim3b, 0.7
    else
      set :taim3a, 0.7
      set :taim3b, 0.5
    end
  end
  sleep rrand_i(1, 256)
end

live_loop :define_phrase4 do
  if rand < 0.5
    if rand < 0.5
    then
      set :taim4a, 1
      set :taim4b, 1.4
    else
      set :taim4a, 1.4
      set :taim4b, 1
    end
  else
    if rand < 0.5
    then
      set :taim4a, 0.5
      set :taim4b, 0.7
    else
      set :taim4a, 0.7
      set :taim4b, 0.5
    end
  end
  sleep rrand_i(1, 256)
end


#Setting the different pitches
live_loop :setting_pitch_one do
  set :pitch_one, rrand(40, 85)
  sleep rrand_i(1, 512)
end

live_loop :setting_pitch_two do
  set :pitch_two, rrand(40, 85)
  sleep rrand_i(1, 512)
end

live_loop :setting_pitch_three do
  set :pitch_three, rrand(40, 85)
  sleep rrand_i(1, 512)
end

live_loop :setting_pitch_four do
  set :pitch_four, rrand(40, 85)
  sleep rrand_i(1, 512)
end


#Sending out regular cues
live_loop :cue1 do
  cue :zakkk
  sleep get[:taim1]
end

live_loop :cue2 do
  cue :pakkk
  sleep get[:taim2]
end

live_loop :cue3 do
  cue :rakkk
  sleep get[(ring :taim3a, :taim3b).tick]
end

live_loop :cue4 do
  cue :rikkk
  sleep get[(ring :taim4a, :taim4b).tick]
end


#Adding the individual delay defined above to be applied to each sound creates a rhythmic pattern
live_loop :chooser_one do
  #Choosing the delay which is actually applied below
  set :wa, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  #After some time, the delay is changed, thus the pattern changes
  sleep rrand_i(16, 256)
end

live_loop :chooser_two do
  set :wo, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end

live_loop :chooser_three do
  set :wu, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end

live_loop :chooser_four do
  set :wi, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:teim]
  sleep rrand_i(16, 256)
end


live_loop :releaserange do
  set :relmin, 0.1
  set :relmax, 0.4
  sleep 4
end

with_fx :distortion, distort: 0.1 do
  live_loop :sound_one do
    sync :zakkk
    #The choosen amount of delay is applied
    wait get[:wa]
    #The sound is played
    play get[:pitch_one], amp: rrand(0.1, 1), release: rrand(get[:relmin], get[:relmax])
  end
  
  live_loop :sound_two do
    sync :pakkk
    #The choosen amount of delay is applied
    wait get[:wo]
    #The sound is played
    play get[:pitch_two], amp: rrand(0.1, 1), release: rrand(get[:relmin], get[:relmax])
  end
  
  live_loop :sound_three do
    sync :rakkk
    #The choosen amount of delay is applied
    wait get[:wu]
    #The sound is played
    play get[:pitch_three], amp: rrand(0.1, 1), release: rrand(get[:relmin], get[:relmax])
  end
  
  live_loop :sound_four do
    sync :rikkk
    #The choosen amount of delay is applied
    wait get[:wi]
    #The sound is played
    play get[:pitch_four], amp: rrand(0.1, 1), release: rrand(get[:relmin], get[:relmax])
  end
end



#Setting the minimum rhythmic unit
live_loop :define_drumdelay do
  set :drumteim, (ring 0.1, 0.2, 0.3, 0.4).choose
  sleep rrand_i(1, 256)
end

#Setting the lengths of the repeated patterns
#Symetric patterns
live_loop :define_drumphrase1 do
  set :drumtaim1, (ring 0.3, 0.4, 0.6, 1.2, 2.4).choose
  sleep rrand_i(1, 256)
end

live_loop :define_drumphrase2 do
  set :drumtaim2, (ring 0.3, 0.4, 0.6, 1.2, 2.4).choose
  sleep rrand_i(1, 256)
end


#Asymetric pattern
live_loop :define_drumphrase3 do
  if rand < 0.5
    if rand < 0.5
    then
      set :drumtaim3a, 1
      set :drumtaim3b, 1.4
    else
      set :drumtaim3a, 1.4
      set :drumtaim3b, 1
    end
  else
    if rand < 0.5
    then
      set :drumtaim3a, 0.5
      set :drumtaim3b, 0.7
    else
      set :drumtaim3a, 0.7
      set :drumtaim3b, 0.5
    end
  end
  sleep rrand_i(1, 256)
end

live_loop :define_drumphrase4 do
  if rand < 0.5
    if rand < 0.5
    then
      set :drumtaim4a, 1
      set :drumtaim4b, 1.4
    else
      set :drumtaim4a, 1.4
      set :drumtaim4b, 1
    end
  else
    if rand < 0.5
    then
      set :drumtaim4a, 0.5
      set :drumtaim4b, 0.7
    else
      set :drumtaim4a, 0.7
      set :drumtaim4b, 0.5
    end
  end
  sleep rrand_i(1, 256)
end


#Sending out regular cues
live_loop :drumcue1 do
  cue :drumzakkk
  sleep get[:drumtaim1]
end


live_loop :drumcue2 do
  cue :drumpakkk
  sleep get[:drumtaim2]
end

live_loop :drumcue3 do
  cue :drumrakkk
  sleep get[(ring :drumtaim3a, :drumtaim3b).tick]
end

live_loop :drumcue4 do
  cue :drumrikkk
  sleep get[(ring :drumtaim4a, :drumtaim4b).tick]
end


#Adding the individual delay defined above to be applied to each sound creates a rhythmic pattern
live_loop :drumchooser_one do
  #Choosing the delay which is actually applied below
  set :drumwa, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:drumteim]
  #After some time, the delay is changed, thus the pattern changes
  sleep rrand_i(16, 256)
end

live_loop :drumchooser_two do
  set :drumwo, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:drumteim]
  sleep rrand_i(16, 256)
end

live_loop :drumchooser_three do
  set :drumwu, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:drumteim]
  sleep rrand_i(16, 256)
end

live_loop :drumchooser_four do
  set :drumwi, (ring 0, 1, 2, 3, 4, 5, 6, 7).choose*get[:drumteim]
  sleep rrand_i(16, 256)
end


live_loop :drumreleaserange do
  set :drumrelmin, 0.1
  set :drumrelmax, 0.4
  sleep 4
end

live_loop :drumsound_one do
  sync :drumzakkk
  #The choosen amount of delay is applied
  wait get[:drumwa]
  #The sound is played
  sample :drum_bass_soft
end

live_loop :drumsound_two do
  sync :drumpakkk
  wait get[:drumwo]
  sample :drum_cymbal_pedal
end

live_loop :drumsound_three do
  sync :drumrakkk
  wait get[:drumwu]
  sample :drum_heavy_kick
end

live_loop :drumsound_four do
  sync :drumrikkk
  wait get[:drumwi]
  sample :drum_cymbal_closed
end

Enjoy!

4 Likes

@Gisbert Thanks for sharing! Iā€™ve been working on different approaches to generative music myself using state machines / set / get, which really open up quite a lot of possibilities. I like how you are using these SonicPi features as well in your music. Your approach here is quite novel.

1 Like

@nabisco Thanks for your kind words! What are state machines?

@Gisbert a state machine is a model of computation and is often illustrated like:

However, in code, it can be thought of as a set of rules that govern how one ā€œstateā€ changes into another. In SonicPi terms, you could think of something like this as a state machine:

# Initial state
set :current_state, 0

NOTES = [:c4, :d4, :e4, :f4, :g4]

# State machine rules
RULES = {
  0 => 1,
  1 => 2,
  2 => 3,
  3 => 4,
  4 => 0
}

live_loop :update_state do
  # get current state value -- 0 on the first run
  s = get[:current_state]
  play NOTES[s]
  
  # update to next state
  set :current_state, RULES[s]
  
  sleep 1
end

This represents a ā€œcycleā€ that plays each note in NOTES once in a sort of loop. Like this:

49%20PM

There are a lot of different types of state machines, though, and most are ā€œbranchingā€ and often non-cyclical. Here is a ā€œbranchingā€ state machine that can go 1 of 3 possible directions on each state change:

# Initial state
set :current_state, 0

NOTES = [:c4, :d4, :e4, :f4, :g4]

# State machine rules
RULES = {
  0 => [1,2,3],
  1 => [2,3,4],
  2 => [3,4,0],
  3 => [4,0,1],
  4 => [0,1,2]
}

live_loop :update_state do
  # get current state value -- 0 on the first run
  s = get[:current_state]
  play NOTES[s]
  
  # update to next state
  set :current_state, RULES[s].choose
  
  sleep 1
end

That second one looks more like this:
28%20PM

2 Likes

Cool! Thanks for elaborating!
I will need some time to check this out.

1 Like

Got it, very interesting!

Now heading to your blog entry on Markov Chain Rhythms, cool stuff, thanks for sharing :smile:

Your second example is very inspiring.

I added rhythm, modified the scale and narrowed down the choices to get a more specific melodic character:

Initial state

use_random_seed 929

set :current_state, 0

NOTES = [:c4, :eb4, :f4, :g4, :bb4]
INTERONSET = [0.25, 0.25, 0.25, 0.5, 0.5]

State machine rules

RULES = {
0 => [1,2],
1 => [3,4],
2 => [1,3,4],
3 => [4,0],
4 => [0,1,2]
}

live_loop :update_state do

get current state value ā€“ 0 on the first run

s = get[:current_state]
play NOTES[s], release: rrand(0.1, 0.5)
sleep INTERONSET[s]

update to next state

set :current_state, RULES[s].choose

end

3 Likes

@Gisbert this sounds awesome! I like the randomization of the durations added in there too and the updates to the notes set. Def. gives it a lot more character. :smiley:

1 Like

@nabisco Thanks, glad you like it!

1 Like