Following up the thread on chord progressions here I have explored the field a bit further.
The piece shows some chord patterns as used in Jazz and also a modulation from key F to C and back. The improvisation loop uses the notes from the scales associated with the chords and keys, plus some random modifications.
### Jazz Improvisations
use_debug false
use_random_seed 30
use_bpm 120
# progressions = list of degrees (or steps)
p1 = [:i, :ii, :v, :i]
p2 = [:ii, :i, :v, :i]
p3 = [:iii, :vii, :vi, :ii]
p4 = [:vii, :ii, :v, :i]
my_piece = (ring
{:prog => p1, :key => :F2, :mode => :major},
{:prog => p2, :key => :C3, :mode => :major},
{:prog => p3, :key => :C3, :mode => :major},
{:prog => p4, :key => :A2, :mode => :harmonic_minor},
)
# degree - mode associations
# see https://en.wikipedia.org/wiki/Mode_(music)#Modern_modes
scales = {
:i => :ionian,
:ii => :dorian,
:iii => :phrygian,
:iv => :lydian,
:v => :mixolydian,
:vi => :aeolian,
:vii => :locrian
}
scales_m = {
:i => :melodic_minor_asc,
:ii => :hex_phrygian,
:iii => :lydian_minor,
:iv => :minor_pentatonic,
:v => :augmented,
:vi => :minor_pentatonic,
:vii => :super_locrian
}
live_loop :parse_progressions, auto_cue: false, delay: 0.2 do
pr = my_piece.tick
pr[:prog].each do |deg|
if pr[:mode] == :major
mode = scales[deg]
else
mode = scales_m[deg]
end
c_chord = (chord_degree deg, pr[:key], pr[:mode], 4)
puts pr[:key], note_info(c_chord[0]), mode
set :chord, c_chord
set :mode, mode
sleep 4
end
end
with_fx :reverb, mix: 0.4, room: 0.7 do
live_loop :my_drums, auto_cue: false do
sync :chord
define :p do |i|
a = 1.0
case i
when 0
sample :drum_heavy_kick, amp: a*1.5
when 1
sample :drum_snare_soft, amp: a*1.5
when 2
sample :drum_cymbal_closed, amp: a*0.7
end
end
tick_reset
24.times do |n|
tick
p(0) if ("x-----------------------"[look]=="x")
p(1) if ("--------------------x---"[look]=="x")
p(2) if ("x--x-xx--x-xx--x-xx--x-x"[look]=="x")
sleep 1.0/6 if n < 23
end
end
end
with_synth :fm do
use_synth_defaults amp: 0.6, attack: 0.01, sustain: 0.9, release: 0.1, divisor: 2
live_loop :bass, auto_cue: false do
sync :chord
sca = scale get(:chord)[0], get(:mode)
notes = (knit sca[0], 3, sca[1], 1, sca[2], 2, sca[4], 2).pick(4)
notes.each_with_index do |n, i|
play n
sleep 1 if i < 3
end
end
end
with_fx :reverb, mix: 0.4, room: 0.7 do
with_synth :piano do
use_synth_defaults amp: 1.8, hard: 0.65, sustain: 0.2, release: 1.3
live_loop :piano, auto_cue: false do
sync :chord
cho = get(:chord)
tick_reset
12.times do |n|
play cho if ("x---x--x--x-"[tick]=="x")
sleep 1.0/3 if n < 11
end
end
end
end
with_fx :echo, mix: 0.3, decay: 0.5, phase: 1.0/6 do
with_synth :pulse do
use_synth_defaults amp: 0.5, sustain: 0.1
live_loop :melody, auto_cue: false do
sync :chord
sca = scale get(:chord)[0], get(:mode), num_octaves: 3
num_notes = (knit 12, 4, 9, 1).choose
start = rrand_i(0, sca.length - num_notes)
notes = sca[start, num_notes]
notes = notes.reverse if one_in(3)
notes.each_with_index do |n, i|
n = notes[i - 1] if one_in(6) and i > 0
play n, release: 6.0/num_notes unless one_in(15)
sleep 4.0/num_notes if i < num_notes - 1
end
end
end
end