God chords (or just epic chord changes)

Epic chord changes made simple.

Inspired by https://www.youtube.com/watch?v=OdVhA19P4-4

##
## file: god_chords.rb
##
## Nov 2018, play god chords, which is a sequence of major chords of certain intervals,
##           such that they are not connected in a functional harmony sense.
##

use_debug false
use_bpm 80

# create intervals producing god chords
define :f_god do |x|
  if x>60 then                    # make sure we dont get too high
    x = x-12
  end
  (ring x+3, x+4, x+6, x+8, x+9)
end

# create a chord array containing good notes to play
define :f_chord_ary do |x|
  oct = (octs x-2*12, 5).to_ary
  nts = []
  oct.each { |x| nts.push( (chord x, "M").to_ary ) }
  nts = nts.flatten
  ret = []
  nts.each { |x| ret.push(x) if x > 60 && x < 90 }
  #spark ret
  #puts ret
  ret
end

## selected a starting note
current_note = 60

live_loop :god_player do
  current_note = f_god(current_note).choose
  c = f_chord_ary(current_note)
  n = (note_info current_note).midi_string
  puts "note: #{n}, chord: #{c}"
  
  #### ----------- play chord
  use_synth :hollow
  play c, attack: rrand(2,4), release: rrand(3,5), amp: 1.9
  
  #### ----------- some long-release note here and there
  use_synth :dark_ambience
  play c[ rrand_i(2,5) ], attack: 3, release: 6, amp: 2
  
  #### ----------- play bass
  use_synth :fm
  play (note n, octave: 2), attack: 3, release: 3, amp: 0.25
  
  with_fx :gverb, mix: 0.5 do
    with_fx :whammy, grainsize: 2, mix: 0.75 do
      play (note n, octave: 4), attack: 3, release: 3, amp: rrand(0.05, 0.15)
    end
  end
  
  sleep 4
end

live_loop :looped_drum do
  #stop
  with_fx :slicer, phase: 0.125, wave: 0, mix: 1.0 do |fx|
    sample :loop_compus, beat_stretch: 4, amp: 0.6, rate: 0.5, onset: choose
  end
  s = (stretch 0.125, rrand_i(10,20)) + (stretch 0.25, rrand_i(10,20))
  sleep s.choose
end

live_loop :drum_kick do
  base_echo_mix = 0.15
  with_fx :echo, mix: base_echo_mix do |cntl|
    control cntl, mix: base_echo_mix
    m = ((stretch 0.3, 2) + (stretch base_echo_mix, 10)).shuffle.choose
    control cntl, mix: m
    #control cntl, phase: rrand(0.15,0.35), mix: ((stretch 0.1, 10) + 0.3).choose
    with_fx :distortion do
      sample :drum_bass_soft
      sleep 0.5
      sample :drum_snare_soft, rate: -0.8, release: 2, amp: 0.3
      sleep 0.5
      sample :drum_snare_soft, start: 0.08, rpitch: -rrand(1,2), amp: 0.4
      sleep 1
    end
  end
end

live_loop :hats do
  #stop
  tick
  with_fx :whammy, mix: 0.3 do
    with_fx :flanger, phase: 0.15, delay: 0.5 do
      with_fx :ixi_techno, mix: 0.8 do
        sample :drum_cymbal_soft, amp: rrand(0.2,0.4) if spread(3,9).look
        sample :drum_cymbal_soft, amp: rrand(0.1,0.2) if spread(4,11).look
        sample :drum_cymbal_soft, amp: rrand(0.1,0.15) if spread(5,7).look
        sleep 0.25
      end
    end
  end
end

Very nice! I look forward to playing with this.

EDITED:
Had a play with this today.
I inserted the code below, between the lines

  puts "note: #{n}, chord: #{c}"
  
  #### ----------- play chord
    in_thread do
      use_transpose -12
      with_fx :reverb,room: 0.8,mix: 0.7 do
        use_synth :beep
        32.times do
          play c.choose,release: 0.125,amp: 0.4,pan: rrand(-1,1)
          sleep 0.125
        end
      end
    end

which gave a nice bubbling ripple of notes above the chords.

Nice neat coding for your two functions define :f_god and define :f_chord_ary
btw, very cool! Interesting video too

very cool :slight_smile: I never tried to add a thread within a thread.

I would have probably added another live_loop with that shorter sleep times. But then I’d need to pass the chord across threads with get and set … this is much more elegant!

Thanks for sharing!