Chord progression tool

I was reading about, and playing with, chord progressions. I used this little interface to play with things.

define :chrd do |deg, tonic, sca|
  n = 3
  if deg.match?('7')
    n = 4
    deg = deg.slice(0,deg.length-1).to_sym
  end
  
  return (chord_degree deg, tonic, sca, n)
end

p1 = [:i,:v,:vi,:iv]
p2 = [:i,:iv,:v,:iv]
p3 = [:ii7,:v7,:i7]
p4 = [:i,:i,:i,:i,:iv,:iv,:i,:i,:v,:iv,:i,:i]
p5 = [:i,:vi,:iv,:v]
p6 = [:i,:v,:vi,:iii,:iv,:i,:iv,:v]



live_loop :chord_progs do
  use_synth :prophet
  progression = p3
  tonic = 62.5
  myScale = :mixolydian
  
  progression.each do |deg|
    play (chrd deg, tonic, myScale),\
      sustain: 1
    sleep 1
  end
  stop
end

3 Likes

This is great. Had a play with it this afternoon and came up with this:

#chord progressions doodles by Robn Newman Jan 2021
#developed from initial code by theibbster
use_debug false
define :chrd do |deg, tonic, sca|
  n = 3
  if deg.match?('7')
    n = 4
    deg = deg.slice(0,deg.length-1).to_sym
  end
  return (chord_degree deg, tonic, sca, n)
end

p1 = [:i,:v,:vi,:iv]
p2 = [:i,:iv,:v,:iv]
p3 = [:ii7,:v7,:i7]
p4 = [:i,:i,:i,:i,:iv,:iv,:i,:i,:v,:iv,:i,:i]
p5 = [:i,:vi,:iv,:v]
p6 = [:i,:v,:vi,:iii,:iv,:i,:iv,:v]
pl=(ring p1,p2,p3,p4,p5,p6).shuffle #set up ring of progressions

with_fx :reverb,room: 0.8,mix: 0.7 do #add reverb
  with_fx :level,amp: 1 do |vol| #vary vol as piece progresses
    set :vol,vol #stopre ref to fx_level for control
    
    live_loop :chord_progs do
      progression = pl.tick #get next progresion
      tick_set :tt,look/6 #define tick for tonic changes
      tonic = (ring 62.5,62.5+7,62.5-5,62.5-12,62.5+7-12,62.5-5-12).look(:tt)
      #puts tonic
      #choose scale from specified list
      myScale = (ring :major,:mixolydian,:minor,:minor_pentatonic,:dorian,:aeolian).choose# or tick(:sc)
      #process next progression
      progression.each_with_index  do |deg,i|
        nl=(chrd deg, tonic, myScale) #get notes to play
        use_synth :dsaw #play bass note with dsaw
        play nl[0]-12,\
          sustain: (nl.length)*0.9*0.095,release: 0.005,\
          amp: 0.7,pan: (-1)**i #alternate notes on pan +-1
        use_synth :pulse #use pulse for fast notes
        nl.each do |n| #play notes in sequence
          play n,\
            sustain: 0.095,release: 0.005,\
            amp: 0.5,pan: (-1)**tick(:iloop) #alternate notes on pan +-1
          sleep 0.1
        end
      end#progression
    end#liveloop
  end#level
end#reverb
live_loop :vet do #control level output on 10 sec up/down ramp
  vlev=[0.4,1].tick
  control get(:vol),amp: vlev,amp_slide: 10
  sleep 10
end

Whole range of possibilities to play with. Made a nice piece to try out my experimental .deb install for SP3.3.0beta4 on my Pi400!

1 Like

I really enjoyed what you did with it, Robin! Lots of bits for me to learn from.

I played with your code for about 10 minutes and ruined it by adding some drums :grin:

#ruined with drums by theibbster
#from: chord progressions doodles by Robin Newman Jan 2021
#from: initial code by theibbster
use_debug false
define :chrd do |deg, tonic, sca|
  n = 3
  if deg.match?('7')
    n = 4
    deg = deg.slice(0,deg.length-1).to_sym
  end
  return (chord_degree deg, tonic, sca, n)
end

p1 = [:i,:v,:vi,:iv]
p2 = [:i,:iv,:v,:iv]
p3 = [:ii7,:v7,:i7]
p4 = [:i,:i,:i,:i,:iv,:iv,:i,:i,:v,:iv,:i,:i]
p5 = [:i,:vi,:iv,:v]
p6 = [:i,:v,:vi,:iii,:iv,:i,:iv,:v]
pl=(ring p1,p2,p3,p4,p5,p6).shuffle #set up ring of progressions

with_fx :reverb,room: 0.8,mix: 0.7 do #add reverb
  with_fx :level,amp: 1 do |vol| #vary vol as piece progresses
    set :vol,vol #stopre ref to fx_level for control
    
    live_loop :chord_progs do
      progression = pl.tick #get next progresion
      tick_set :tt,look/6 #define tick for tonic changes
      tonic = (ring 62.5,62.5+7,62.5-5,62.5-12,62.5+7-12,62.5-5-12).look(:tt)
      #puts tonic
      #choose scale from specified list
      myScale = (ring :major,:mixolydian,:minor,:minor_pentatonic,:dorian,:aeolian).choose# or tick(:sc)
      #process next progression
      progression.each_with_index  do |deg,i|
        nl=(chrd deg, tonic, myScale) #get notes to play
        use_synth :dsaw #play bass note with dsaw
        play nl[0]-12,\
          sustain: (nl.length)*0.9*0.095,release: 0.005,\
          amp: 0.7,pan: (-1)**i #alternate notes on pan +-1
        use_synth :pulse #use pulse for fast notes
        nl.each do |n| #play notes in sequence
          play n,\
            sustain: 0.095,release: 0.005,\
            amp: 0.5,pan: (-1)**tick(:iloop) #alternate notes on pan +-1
          sleep 0.1
        end
      end#progression
    end#liveloop
  end#level
end#reverb
live_loop :vet do #control level output on 10 sec up/down ramp
  vlev=[0.4,1].tick
  control get(:vol),amp: vlev,amp_slide: 10
  control get(:vol2),amp: vlev*1.1, amp_slide: 5
  sleep 10
end

live_loop :triplethats do
  off = rrand(-0.025, 0.025)
  samp = :drum_cymbal_soft
  use_sample_defaults lpf: 115
  with_fx :level, amp: 1.1 do |vol2|
    set :vol2, vol2
    with_bpm 120 do
      sample samp, amp: rrand(0.75,1)
      sleep 1
      sample samp, amp: rrand(0.75,0.95), pan: rrand(0.1,0.25)
      sleep 2.0/3 + off
      sample samp, amp: rrand(0.45,0.7), pan: rrand(-0.25,-0.1)
      sleep 1.0/3 - off
    end
  end
end

live_loop :bd do
  with_bpm 120 do
    sample :bd_boom, amp: 1.2
    sleep 1
  end
end

Cool. Suggest you move the live_loop :vet to the end so that :vol2 is defined before you use it.
Also Lots of variations if you set a random seed at the start eg use_random_seed 6148
Drums are dfficult becuase the timing for each progression is different as they have differing lengths. Tricky to match the rhythms.

1 Like

Thanks for the advice. I’m going to try to make my own with more thought out timings so I can match drums. Still got a lot to learn :slightly_smiling_face:

I also thought about chord progressions, some month ago.
This was my idea: https://github.com/stahnirockt/Sonic-ChordProgression

1 Like

Ok, I’ve come up with something after a little jamming today.I don’t think it’s too good, but I had fun making this.

use_sched_ahead_time 2
define :chrd do |deg, tonic, sca|
  n = 3
  if deg.match?('7')
    n = 4
    deg = deg.slice(0,deg.length-1).to_sym
  end
  
  return (chord_degree deg, tonic, sca, n)
end

define :play_lead do |n,s|
  use_synth :blade
  play n, amp: rrand(0.75,0.8), sustain: 0.2*s, release: 0.5*s,\
    vibrato_rate: 8, vibrato_depth: 0.3, vibrato_delay: 0.25
end


define :strum do |notes, s=1|
  notes = one_in(4) ? notes.scale(0.999) : notes
  time_warp 0 do
    notes.each do |n|
      play_lead n, s
      sleep rrand(0.08,0.12)
    end #notes
  end #time_warp
end #strum function

p1 = [:i7,:v,:vi,:iv]
p2 = [:i7,:iv,:v,:iv]
p3 = [:ii7,:v7,:i7]

t1 = [2,1,1]
t2 = [1.5,1.5,1]
t3 = [1,1,1,1]


use_bpm 110
live_loop :chord_setter do
  progression = [p1,p2,p3].choose
  tonic = 62.5
  myScale = :mixolydian
  progression.each do |deg|
    set :chord, (chrd deg, tonic, myScale)
    sleep rrand_i(2,4)
  end
end

live_loop :lead do
  t = [t1,t2,t3].choose.shuffle
  t.each do |s|
    strum (get :chord), s
    sleep s
  end#t.each
end #:lead loop

live_loop :bass, sync: :lead do
  use_synth :fm
  c = (get :chord)
  n = one_in(3) ? c[0] - 12 : c[1]-12
  play n, amp: 0.5, release: 1.5, divisor: 2, depth: 3
  sleep 1
end

live_loop :rhythm, sync: :lead do
  sample :elec_cymbal, amp: [0.2, 0.1, 0.2].tick
  off = rrand(-0.025, 0.025)
  sleep [1,2.0/3+off,1.0/3-off].look
end

live_loop :bd, sync: :lead do
  sample :bd_gas
  sleep 1
end