Some Generative Music Stuff

Hello Sonic Pi community,
Here’s a little experiment with generative music. It’s rather monotonus, but I couldn’t figure out a way off reusing generated sections. It is also very resource intensive.
Greetings
Loop

# Melody Maker

# Coded by Loopiloop


#---options---

#set random seed. play around with this value
use_random_seed 93847

#root of the key
key_root = rrand_i(48, 60)

#quality of the key
key_qual = :major

#chord progression
chordprog = (ring :i, :v, :vi, :iv)


#---setup---

#pattern of accents for every beat
accent = (ring 1, 0, 0, 0)

#the melody is created randomly out of the first four notes of each chord
c = (ring 0, 1, 2, 3)

#generating melodies
melody_1 = c.pick(16) #square lead
melody_2 = c.pick(16) #square base
melody_3 = c.pick(16) #wave lead

#this variable is used to create random lists of boleans and for on-off patterns
ft = (ring 0, 1)

#generating rythms
onoff_1 = ft.pick(16) #square lead
onoff_2 = ft.pick(16) #square base
onoff_3 = ft.pick(16) #wave lead
onoff_4 = ft.pick(16) #drums

#define how much score a pattern gets for a note in each position
importance = (ring 4, 0, 1 ,0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0)

#add samples to list for automated sample choice and load them
drum = [:drum_bass_soft, :drum_bass_hard]
load_samples drum

#current position within the song in bars
cprogpos = 0

#current position within the song in sixteenth notes
sixteenth = 0

#offset of currently evaluated variation in relation to original pattern
evaluate_n = 0

#position in evaluated variation
evaluate_i = 0

#square lead evaluation variables
evaluate_s_1 = 0 #score of current variation
evaluate_t_1 = 0 #score of best variation
evaluate_r_1= 0 #offset of best variation

#square base evaluation variables
evaluate_s_2 = 0 #score of current variation
evaluate_t_2 = 0 #score of best variation
evaluate_r_2 = 0 #offset of best variation

#wave lead evaluation variables
evaluate_s_3 = 0 #score of current variation
evaluate_t_3 = 0 #score of best variation
evaluate_r_3 = 0 #offset of best variation

#drums evaluation variables
evaluate_s_4 = 0 #score of current variation
evaluate_t_4 = 0 #score of best variation
evaluate_r_4 = 0 #offset of best variation


#---pattern optimization---

#iterate through pattern variations
16.times do
  
  #return to first position
  evaluate_i = 0
  
  #reset scores
  evaluate_s_1 = 0 #square lead
  evaluate_s_2 = 0 #square base
  evaluate_s_3 = 0 #wave lead
  evaluate_s_4 = 0 #drums
  
  #iterate through positions
  16.times do
    
    #square lead
    #if theres a note at the current position
    if 1 == onoff_1[evaluate_n + evaluate_i]
      #add importance of the current position to the score
      evaluate_s_1 = evaluate_s_1 + importance[evaluate_i]
    end
    
    #square base
    #if theres a note at the current position
    if 1 == onoff_2[evaluate_n + evaluate_i]
      #add importance of the current position to the score
      evaluate_s_2 = evaluate_s_2 + importance[evaluate_i]
    end
    
    #wave lead
    #if theres a note at the current position
    if 1 == onoff_3[evaluate_n + evaluate_i]
      #add importance of the current position to the score
      evaluate_s_3 = evaluate_s_3 + importance[evaluate_i]
    end
    
    #drums
    #if theres a note at the current position
    if 1 == onoff_4[evaluate_n + evaluate_i]
      #add importance of the current position to the score
      evaluate_s_4 = evaluate_s_4 + importance[evaluate_i]
    end
    
    #move to next position
    evaluate_i = evaluate_i +1
  end
  
  #square lead
  #if current variant was better then the so far best variant
  if  evaluate_s_1 > evaluate_t_1
    #set variant high score to score of current one
    evaluate_t_1 = evaluate_s_1
    #set offset of best variant to offset of current one
    evaluate_r_1 = evaluate_n
  end
  
  #square base
  #if current variant was better then the so far best variant
  if  evaluate_s_2 > evaluate_t_2
    #set variant high score to score of current one
    evaluate_t_2 = evaluate_s_2
    #set offset of best variant to offset of current one
    evaluate_r_2 = evaluate_n
  end
  
  #wave lead
  #if current variant was better then the so far best variant
  if  evaluate_s_3 > evaluate_t_3
    #set variant high score to score of current one
    evaluate_t_3 = evaluate_s_3
    #set offset of best variant to offset of current one
    evaluate_r_3 = evaluate_n
  end
  
  #drums
  #if current variant was better then the so far best variant
  if  evaluate_s_4 > evaluate_t_4
    #set variant high score to score of current one
    evaluate_t_4 = evaluate_s_4
    #set offset of best variant to offset of current one
    evaluate_r_4 = evaluate_n
  end
  
  #move to next variant
  evaluate_n = evaluate_n + 1
end


#---playing the music---

#do forever
  live_loop :main do
    
    #iterate through four bars
    4.times do
      
      #iterate through sixteen sixteenth notes
      16.times do
        
        #synth for the square instuments
        use_synth :chiplead
        
        #square lead
        play (chord_degree chordprog[cprogpos], key_root, key_qual)[melody_1[sixteenth]],on: onoff_1[sixteenth+evaluate_r_1], release: 0.25, amp: 0.25
        
        #square lead base an octave lower
        play (chord_degree chordprog[cprogpos], key_root, key_qual)[melody_2[sixteenth]]-12,on: onoff_2[sixteenth+evaluate_r_2], release: 0.25, amp: 0.25
        
        #only on eighth notes
        if ft[sixteenth+1]
          
          #synth for wave lead
          use_synth :chipbass
          
          #wave lead
          play (chord_degree chordprog[cprogpos], key_root, key_qual)[melody_3[sixteenth]],on: onoff_3[sixteenth+evaluate_r_3], release: 0.25, amp: 0.5
        end
        
        #drums according to accent pattern
        sample drum[accent[sixteenth]],amp: 1
        
        #move to next sixteenth
        sixteenth = sixteenth + 1
        
        #wait for current sixteenth to end
        sleep 0.125
      end
      
      #move to next chord
      cprogpos = cprogpos + 1
    end
  end
 
3 Likes

There’s a few optimisations you can make, where there are Sonic Pi functions designed to simplify a few of the things you do here, if you’re interested. Either way, a nice little experiment :slight_smile:

I’d like to learn. Could you help me with the optimization a bit? What functions should I look into specifically?

Anywhere where you find yourself iterating through a collection with x = x + 1 for example, or indexing into it with list[x], you can use (ring ...).tick and (ring ...).look respectively :slight_smile:
https://sonic-pi.net/tutorial#section-9-4

Also, if you’re finding yourself using if x == 0 or if x == 1, where x is from a ring of 0s and 1s, you can change the ring to use the (bools ...) function instead - which is a handy shortcut for constructing rings of booleans :slight_smile: (There are a few other functions that build rings in various forms - see the bottom of Sonic Pi - Tutorial for example)

2 Likes

What about sections like theese though?

foo_1[x + offset_1]
foo_2[x + offset_2]
x = x+1
live_loop :main do
  i = 0
  4.times do
    print n + i
    i = i + 1
  end
  n = n + 1
end

tick and look will still work :slight_smile:
The tick function basically just increments a thread-local (eg scoped to the current thread or live_loop) counter - and look returns its current value.
So, for the first of those examples you mention, you could do this:

foo_1.look(offset: offset_1)]
foo_2.look(offset: offset_2)]
tick

and the second:

live_loop :main do
  tick_reset(:i)
  4.times do
    puts look(:n) + look(:i)
    tick(:i)
  end
  tick(:n)
end

(Or something along those lines, I’ve not tested them in Sonic Pi directly).

Have a look at the documentation for those functions in the Lang help section for further details :slight_smile:

I found that it also helps to give every instrument their own live loop

1 Like

Updated version. Still a lot of room for improvement though. I’m working on it.
Just found out how to concatenate. This will make future updates much less complicated and way more optimized.

# Melody Maker

# Coded by Loopiloop


#---initializing randomness---

#set random seed. play around with this value
use_random_seed 989947

#determining the element seeds
r_seed = (range 0, 99999).pick(100)

#---options---
#root of the key
key_root = rrand_i(48, 60)

#quality of the key
key_qual = :major

#chord progression
chordprog = (ring :i, :v, :vi, :iv)


#---defining variables---

#this variable is used to create random lists of boleans and for on-off patterns
ft = (bools 0, 1)

#the melody is created randomly out of the first four notes of each chord
r_3 = (ring 0, 1, 2, 3)

wl_section=(ring 2, 3, 2, 3, 2, 3, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5)

#define how much score a pattern gets for a note in each position
importance = (ring 4, 0, 1 ,0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0)

#add samples to list for automated sample choice and load them
drum = [:drum_bass_hard, :drum_snare_soft, :drum_snare_hard, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_hard, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_hard, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_hard, :drum_snare_soft]
load_samples drum


#---defining functions---

#generating rythms

#in: seed for generation
gr_seed = 0

#calc: score of current pattern
gr_score = 0

#calc: score of best pattern
gr_best= 0

#out: rythm as ring
gr_rythm = (ring 0)

#out: offset for optimization
gr_offset = 0

#out: melody
gr_melody = (ring 0)

#start of definition
define :gr_generate_rythm do
  
  #load seed for this rythm
  use_random_seed gr_seed
  
  #generate original pattern
  gr_rythm = ft.pick(16)
  
  gr_melody = r_3.pick(16)
  
  #reset best score
  gr_best = 0
  
  #reset best pattern
  gr_offset = 0
  
  #iterate through pattern variations
  tick_set:gr_pattern, -1
  16.times do
    
    #move to next pattern
    tick(:gr_pattern)
    
    #reset score
    gr_score = 0
    
    #iterate through position
    tick_set:gr_position, -1
    16.times do
      
      #move to next position
      tick(:gr_position)
      
      #if theres a note at the current position
      if gr_rythm.look(:gr_position, offset: look(:gr_pattern))
        #add importance of the current position to the score
        gr_score = gr_score + importance.look(:gr_position)
      end
      
    end
    
    #if current variant was better then the so far best variant
    if  gr_score > gr_best
      #set variant high score to score of current one
      gr_best = gr_score
      #set offset of best variant to offset of current one
      gr_offset = look(:gr_pattern)
    end
    
  end
  
end


#---playing the music---

#repeat forever
#square lead
live_loop :sl do
  
  #load rythm
  gr_seed = r_seed[0]
  gr_generate_rythm
  melody_1 = gr_melody
  onoff_1 = gr_rythm
  evaluate_r_1 = gr_offset
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #synth for the square instuments
      use_synth :chiplead
      
      #square lead
      play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_1.tick(:sixteenth)],on: onoff_1.look(:sixteenth, offset: evaluate_r_1), release: 0.25, amp: 0.25
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#square base
live_loop :sb do
  
  #load rythm
  gr_seed = r_seed[1]
  gr_generate_rythm
  melody_2 = gr_melody
  onoff_2 = gr_rythm
  evaluate_r_2 = gr_offset
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #only on eighth notes
      if ft.tick(:sixteenth)#, offset: 1)
        
        #synth for the square instuments
        use_synth :chiplead
        
        #square lead
        play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_2.look(:sixteenth)]-12,on: onoff_2.look(:sixteenth, offset: evaluate_r_2), release: 0.25, amp: 0.25
        
      end
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#wave lead
live_loop :wl do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #load rythm
    gr_seed = r_seed[wl_section.look(:cprogpos)]
    gr_generate_rythm
    melody_3 = gr_melody
    onoff_3 = gr_rythm
    evaluate_r_3 = gr_offset
    
    #iterate through sixteen sixteenth notes
    16.times do
      #synth for wave lead
      use_synth :chipbass
      
      #wave lead
      play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_3.tick(:sixteenth)],on: onoff_3.look(:sixteenth, offset: evaluate_r_3), release: 0.25, amp: 0.5
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#drums
live_loop :dr do
  
  #load rythm
  gr_seed = r_seed[6]
  gr_generate_rythm
  onoff_4 = gr_rythm
  evaluate_r_4 = gr_offset
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      #synth for wave lead
      use_synth :chipbass
      
      #drums according to accent pattern
      sample drum.tick(:sixteenth),amp: 0.75, on: onoff_4.look(:sixteenth, offset: evaluate_r_4)
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end
1 Like

Yet another update

# Melody Maker

# Coded by Loopiloop


#---initializing randomness---

#set random seed. play around with this value
use_random_seed 4586819


#---options---
#root of the key
key_root = rrand_i(36, 48)

#quality of the key
key_qual = :major

#chord progression
chordprog = (ring :i, :v, :vi, :iv)

#add samples to list for automated sample choice and load them
drum = [:drum_bass_hard, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft]
load_samples drum

#---defining variables---

#this variable is used to create random lists of boleans and for on-off patterns
ft = (bools 0, 1)

#the melody is created randomly out of the first four notes of each chord
r_3 = (ring 0, 1, 2, 3)

#define how much score a pattern gets for a note in each position
importance = (ring 3, 0, 1, 0, 2, 0, 1, 0)

#collection of melodies, their rythms and their offsets with melodie 0 being silence
rythm = (ring (knit false, 16))
melody = (ring (knit 0, 16))
offset = (ring 0)

#section structure
section_1 = (knit 14, 15, 0, 1)+(ring 16, 17, 16, 17, 16, 17)
section_2 = (knit 3, 16, 4, 8)
section_3 = (knit 0, 7) + (ring 5, 6, 6, 7, 8, 6, 6, 7, 9, 10, 11, 10, 11, 10, 11, 12, 13)

#channel content
melody_1 = (ring)
onoff_1 = (ring)
evaluate_r_1 = (ring)

melody_2 = (ring)
onoff_2 = (ring)
evaluate_r_2 = (ring)

melody_3 = (ring)
onoff_3 = (ring)
evaluate_r_3 = (ring)

melody_4 = (ring)
onoff_4 = (ring)
evaluate_r_4 = (ring)

#---defining functions---

#generating rythms

#in: seed for generation
gr_seed = 0

#calc: score of current pattern
gr_score = 0

#calc: score of best pattern
gr_best = 0

#out: rythm as ring
gr_rythm = (ring 0)

#out: offset for optimization
gr_offset = 0

#out: melody
gr_melody = (ring 0)

#start of definition
define :gr_generate_rythm do
  
  #generate original pattern
  gr_rythm = ft.pick(16)
  
  gr_melody = r_3.pick(16)
  
  #reset best score
  gr_best = 0
  
  #reset best pattern
  gr_offset = 0
  
  #iterate through pattern variations
  tick_set:gr_pattern, -1
  16.times do
    
    #move to next pattern
    tick(:gr_pattern)
    
    #reset score
    gr_score = 0
    
    #iterate through position
    tick_set:gr_position, -1
    16.times do
      
      #move to next position
      tick(:gr_position)
      
      #if theres a note at the current position
      if gr_rythm.look(:gr_position, offset: look(:gr_pattern))
        #add importance of the current position to the score
        gr_score = gr_score + importance.look(:gr_position)
      end
      
    end
    
    #if current variant was better then the so far best variant
    if  gr_score > gr_best
      #set variant high score to score of current one
      gr_best = gr_score
      #set offset of best variant to offset of current one
      gr_offset = look(:gr_pattern)
    end
    
  end
  
end


#---generating song---

#generate 20 motives
20.times do
  gr_generate_rythm
  melody = melody + (ring gr_melody)
  rythm = rythm + (ring gr_rythm)
  offset = offset + (ring gr_offset)
end


24.times do
  
  melody_1 = melody_1 + (ring melody[section_1.tick(:gen_1)])
  onoff_1 = onoff_1  + (ring rythm[section_1.look(:gen_1)])
  evaluate_r_1 = evaluate_r_1  + (ring offset[section_1.look(:gen_1)])
  
end

24.times do
  
  melody_2 = melody_2 + (ring melody[section_2.tick(:gen_2)])
  onoff_2 = onoff_2  + (ring rythm[section_2.look(:gen_2)])
  evaluate_r_2 = evaluate_r_2  + (ring offset[section_2.look(:gen_2)])
  
end

24.times do
  
  melody_3 = melody_3 + (ring melody[section_3.tick(:gen_3)])
  onoff_3 = onoff_3  + (ring rythm[section_3.look(:gen_3)])
  evaluate_r_3 = evaluate_r_3  + (ring offset[section_3.look(:gen_3)])
  
end

melody_4 = melody_4 + (ring melody[2])
onoff_4 = onoff_4  + (ring rythm[2])
evaluate_r_4 = evaluate_r_4  + (ring offset[6])


#---playing the music---

#repeat forever
#square lead
live_loop :sl do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #only on eighth notes
      
      #synth for the square instuments
      use_synth :chiplead
      
      #square lead
      play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_1.look(:cprogpos).tick(:sixteenth)],on: onoff_1.look(:cprogpos).look(:sixteenth, offset: evaluate_r_1.look(:cprogpos)), release: 0.25, amp: 0.75
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#square base
live_loop :sb do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #only on eighth notes
      if ft.tick(:sixteenth)#, offset: 1)
        
        #synth for the square instuments
        use_synth :chiplead
        
        #square base
        play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_2.look(:cprogpos).look(:sixteenth)]-12,on: onoff_2.look(:cprogpos).look(:sixteenth, offset: evaluate_r_2.look(:cprogpos)), release: 0.25, amp: 0.75
        
      end
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#wave lead
live_loop :wl do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #synth for the square instuments
      use_synth :chipbass
      
      #wave lead
      play (chord_degree chordprog.look(:cprogpos), key_root, key_qual)[melody_3.look(:cprogpos).tick(:sixteenth)]+12,on: onoff_3.look(:cprogpos).look(:sixteenth, offset: evaluate_r_3.look(:cprogpos)), release: 0.25, amp: 0.5
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#drums
live_loop :dr do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #drums according to accent pattern
      sample drum.tick(:sixteenth),amp: 1, on: onoff_4[0].tick(:sixteenth, offset: evaluate_r_4[0])
      
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

1 Like

Big chord progression update

# Melody Maker

# Coded by Loopiloop


#---initializing randomness---

#set random seed. play around with this value
use_random_seed 4889219


#---options---
#root of the key
key_root = rrand_i(36, 48)

#quality of the key
key_qual = (ring :major, :minor).choose

#chord progression
if key_qual == :major
  chordprog = (ring (ring :i, :vi, :iv, :v), (ring :i, :vi, :ii, :v), (ring :i, :v, :vi, :iv), (ring :i, :iv, :vi, :v), (ring :i, :iii, :iv, :v), (ring :i, :iv, :i, :v), (ring :i, :iv, :ii, :v), (ring :i, :iv, :v, :vi)).choose
else
  chordprog = (ring (ring :i, :vi, :iii, :vii), (ring :i, :iv, :v, :i), (ring :vi, :vii, :i, :i), (ring :i, :vii, :vi, :vii)).choose
end

#add samples to list for automated sample choice and load them
drum = [:drum_bass_hard, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft,:drum_bass_soft, :drum_snare_soft, :drum_snare_soft, :drum_snare_soft]
load_samples drum

#---defining variables---

#this variable is used to create random lists of boleans and for on-off patterns
ft = (bools 0, 1)

#the melody is created randomly out of the first four notes of each chord
r_3 = (ring 0, 1, 2, 3)

#define how much score a pattern gets for a note in each position
importance = (ring 3, 0, 1, 0, 2, 0, 1, 0)

#collection of melodies, their rythms and their offsets with melodie 0 being silence
rythm = (ring (knit false, 16))
melody = (ring (knit 0, 16))
offset = (ring 0)

#section structure
section_1 = (knit 14, 15, 0, 1)+(ring 16, 17, 16, 17, 16, 17)
section_2 = (knit 3, 16, 4, 8)
section_3 = (knit 0, 7) + (ring 5, 6, 6, 7, 8, 6, 6, 7, 9, 10, 11, 10, 11, 10, 11, 12, 13)

#channel content
melody_1 = (ring)
onoff_1 = (ring)
evaluate_r_1 = (ring)

melody_2 = (ring)
onoff_2 = (ring)
evaluate_r_2 = (ring)

melody_3 = (ring)
onoff_3 = (ring)
evaluate_r_3 = (ring)

melody_4 = (ring)
onoff_4 = (ring)
evaluate_r_4 = (ring)

#---defining functions---

#generating rythms

#in: seed for generation
gr_seed = 0

#calc: score of current pattern
gr_score = 0

#calc: score of best pattern
gr_best = 0

#out: rythm as ring
gr_rythm = (ring 0)

#out: offset for optimization
gr_offset = 0

#out: melody
gr_melody = (ring 0)

#start of definition
define :gr_generate_rythm do
  
  #generate original pattern
  gr_rythm = ft.pick(16)
  
  gr_melody = r_3.pick(16)
  
  #reset best score
  gr_best = 0
  
  #reset best pattern
  gr_offset = 0
  
  #iterate through pattern variations
  tick_set:gr_pattern, -1
  16.times do
    
    #move to next pattern
    tick(:gr_pattern)
    
    #reset score
    gr_score = 0
    
    #iterate through position
    tick_set:gr_position, -1
    16.times do
      
      #move to next position
      tick(:gr_position)
      
      #if theres a note at the current position
      if gr_rythm.look(:gr_position, offset: look(:gr_pattern))
        #add importance of the current position to the score
        gr_score = gr_score + importance.look(:gr_position)
      end
      
    end
    
    #if current variant was better then the so far best variant
    if  gr_score > gr_best
      #set variant high score to score of current one
      gr_best = gr_score
      #set offset of best variant to offset of current one
      gr_offset = look(:gr_pattern)
    end
    
  end
  
end


#aligning chords

#in: t(chord :e, :minor)
ca_shift_chord = (ring)

#in: target note
ca_target_note = 0

#out: shifted chord
ca_result_chord = (ring)

#start of definition
define :ca_chord_alignment do
  
  #determine direction in which we must move
  if note(ca_target_note) < ca_shift_chord[0]
    ca_direction = -1
  else
    ca_direction = 1
  end
  
  #current inversion
  ca_i = 0
  #reset smallest distance
  ca_score = 9999
  
  20.times do
    #determine distance to target
    ca_distance = (chord_invert ca_shift_chord, ca_i)[0] - note(ca_target_note)
    
    #get absolute value of distance
    if ca_distance < 0
      ca_distance = ca_distance * -1
    end
    
    #if distance is smaller than current smallest distance
    if ca_distance < ca_score
      
      #set new smallest distance
      ca_score = ca_distance
      
      #set result to new best fit
      ca_result_chord = (chord_invert ca_shift_chord, ca_i)
    end
    
    #move to next inversion
    ca_i = ca_i + ca_direction
  end
  
end


#---generating song---

#base root for all chords
ca_target_note = (chord_degree chordprog.choose, key_root, key_qual).choose

#generate 20 motives
20.times do
  gr_generate_rythm
  melody = melody + (ring gr_melody)
  rythm = rythm + (ring gr_rythm)
  offset = offset + (ring gr_offset)
end


24.times do
  
  melody_1 = melody_1 + (ring melody[section_1.tick(:gen_1)])
  onoff_1 = onoff_1  + (ring rythm[section_1.look(:gen_1)])
  evaluate_r_1 = evaluate_r_1  + (ring offset[section_1.look(:gen_1)])
  
end

24.times do
  
  melody_2 = melody_2 + (ring melody[section_2.tick(:gen_2)])
  onoff_2 = onoff_2  + (ring rythm[section_2.look(:gen_2)])
  evaluate_r_2 = evaluate_r_2  + (ring offset[section_2.look(:gen_2)])
  
end

24.times do
  
  melody_3 = melody_3 + (ring melody[section_3.tick(:gen_3)])
  onoff_3 = onoff_3  + (ring rythm[section_3.look(:gen_3)])
  evaluate_r_3 = evaluate_r_3  + (ring offset[section_3.look(:gen_3)])
  
end

melody_4 = melody_4 + (ring melody[2])
onoff_4 = onoff_4  + (ring rythm[2])
evaluate_r_4 = evaluate_r_4  + (ring offset[6])


#---playing the music---

#repeat forever
#square lead
live_loop :sl do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #only on eighth notes
      
      #synth for the square instuments
      use_synth :chiplead
      
      #square lead
      ca_shift_chord = (chord_degree chordprog.look(:cprogpos), key_root, key_qual)
      ca_chord_alignment
      play ca_result_chord[melody_1.look(:cprogpos).tick(:sixteenth)]+12,on: onoff_1.look(:cprogpos).look(:sixteenth, offset: evaluate_r_1.look(:cprogpos)), release: 0.25, amp: 0.75
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#square base
live_loop :sb do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #only on eighth notes
      if ft.tick(:sixteenth)#, offset: 1)
        
        #synth for the square instuments
        use_synth :chiplead
        
        #square base
        ca_shift_chord =(chord_degree chordprog.look(:cprogpos), key_root, key_qual)
        ca_chord_alignment
        play ca_result_chord[melody_2.look(:cprogpos).look(:sixteenth)],on: onoff_2.look(:cprogpos).look(:sixteenth, offset: evaluate_r_2.look(:cprogpos)), release: 0.25, amp: 0.75
        
      end
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#wave lead
live_loop :wl do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #synth for the square instuments
      use_synth :chipbass
      
      #wave lead
      ca_shift_chord = (chord_degree chordprog.look(:cprogpos), key_root, key_qual)
      ca_chord_alignment
      play ca_result_chord[melody_3.look(:cprogpos).tick(:sixteenth)]+12,on: onoff_3.look(:cprogpos).look(:sixteenth, offset: evaluate_r_3.look(:cprogpos)), release: 0.25, amp: 0.5
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

#repeat forever
#drums
live_loop :dr do
  
  #iterate through four bars
  4.times do
    
    #move to next chord
    tick(:cprogpos)
    
    #iterate through sixteen sixteenth notes
    16.times do
      
      #drums according to accent pattern
      sample drum.tick(:sixteenth),amp: 1, on: onoff_4[0].tick(:sixteenth, offset: evaluate_r_4[0])
      
      
      #wait for current sixteenth to end
      sleep 0.125
    end
    
  end
end

4 Likes