Skip to content

Instantly share code, notes, and snippets.

@d0lfyn
Created December 30, 2020 09:09
Show Gist options
  • Save d0lfyn/324cf49a611f74d61cf7a9bf7f244a22 to your computer and use it in GitHub Desktop.
Save d0lfyn/324cf49a611f74d61cf7a9bf7f244a22 to your computer and use it in GitHub Desktop.
A moody configuration for my Sonic Pi polyphony program
##| polyphony
##| v0.4
##| by d0lfyn (twitter: @0delphini)
##|
##| a simple generator for polyphony in 4 parts
##|
##| history:
##| v0.3
##| + add patterns
##| v0.4
##| + add turn-waiting
##| + add quits
##| + add pattern generation
##| + add patterns bank
##| + add pattern switching
use_bpm 600
use_synth :fm
use_random_seed 2
set :base_note, 0
set :note_1, 0
set :note_2, 0
set :note_3, 0
##| for manual patterns, specify notes in 0-indexed position on scale
set :patterns, []
set :pattern, []
set :pattern_length_min, 4
set :pattern_length_max, 16
set :pattern_generation_factor, 50
set :pattern_repetition_factor, 4
set :pattern_switch_factor, 25
set :pattern_play_delay, 20
set :PATTERN_NOTE_VALUE, 0
set :PATTERN_NOTE_DURATION, 1
set :scale, scale(:c3, :minor)
set :quit_factor, 20
set :quit_time_min, 50
set :quit_time_max, 80
set :turn, 1
define :base do
generate_pattern
play_the_pattern :base_note, 0
loop do
sync :time
if get[:base_note] % 8 == get[:pattern][0][get[:PATTERN_NOTE_VALUE]] % 8 &&
one_in(get[:pattern_repetition_factor])
play_the_pattern :base_note, 0
else
duration = choose_next_duration
play_now get[:base_note], 0, choose_next_amp, duration - 0.01
set :base_note, get[:base_note] + choose_next_interval
sleep duration - 0.01
end
if is_root(get[:base_note]) && one_in(get[:quit_factor])
break
end
end
end
define :contra do |transposition, time_state_note|
while(!(is_above_or_equal get[:base_note], get[time_state_note]) ||
!(is_harmonious get[:base_note], get[time_state_note]))
sync :time
sleep 0.99
end
play_the_pattern time_state_note, transposition
loop do
sync :time
if get[time_state_note] % 8 == get[:pattern][0][get[:PATTERN_NOTE_VALUE]] % 8 &&
one_in(get[:pattern_repetition_factor])
play_the_pattern time_state_note, transposition
else
duration = choose_next_duration
play_now get[time_state_note], transposition, choose_next_amp, duration - 0.01
interval = choose_next_interval
while(!(is_above_or_equal get[:base_note], get[time_state_note] + interval) ||
!(is_harmonious get[:base_note], get[time_state_note] + interval))
interval = choose_next_interval
end
set time_state_note, get[time_state_note] + choose_next_interval
sleep duration - 0.01
end
if is_root(get[time_state_note]) && one_in(get[:quit_factor])
break
end
end
end
define :choose_next_amp do
##| return look % 4 == 0 ? 0.2 : 0.1
return 0.1
end
define :choose_next_duration do
return rrand_i(1, 25)
end
define :choose_next_interval do
return choose([dice(2) - 1, dice(3) - 1, dice(4) - 1,
dice(5) - 1, dice(6) - 1, dice(7) - 1,
-1 * (dice(2) - 1), -1 * (dice(3) - 1), -1 * (dice(4) - 1),
-1 * (dice(5) - 1), -1 * (dice(6) - 1), -1 * (dice(7) - 1)])
end
define :generate_pattern do
pattern = []
length = rrand_i(get[:pattern_length_min], get[:pattern_length_max])
next_note = rand_i(8)
while length >= 0
next_note += choose_next_interval
pattern.push [next_note, choose_next_duration]
length -= 1
end
set :patterns, get[:patterns].take(get[:patterns].length).push(pattern)
set :pattern, pattern
end
define :is_above_or_equal do |note_1, note_2|
difference = note_2 % 8 - note_1 % 8
return difference >= 0
end
define :is_harmonious do |note_1, note_2|
difference = note_2 % 8 - note_1 % 8
return difference == 0 || difference == 2 || difference == 4 || difference == 5
end
define :is_root do |note_number|
return note_number % 8 == 0
end
define :play_beat do
sync :time
sample :drum_bass_soft, amp: 0.3, sustain: 0, release: 4
sleep 4
sample :drum_bass_soft, amp: 0.2, sustain: 0, release: 4
sleep 4
sample :drum_bass_soft, amp: 0.3, sustain: 0, release: 4
sleep 4
sample :drum_bass_soft, amp: 0.2, sustain: 0, release: 4
sleep 3.99
loop do
sync :time
sample :drum_bass_soft, amp: 0.3, sustain: 0, release: 4
sample :drum_cymbal_closed, amp: 0.1, sustain: 0, release: 2
sleep 2
sample :drum_cymbal_closed, amp: 0.05, sustain: 0, release: 2
sleep 2
sample :drum_bass_soft, amp: 0.2, sustain: 0, release: 4
sample :drum_snare_soft, amp: 0.3, sustain: 0, release: 4
sample :drum_cymbal_closed, amp: 0.1, sustain: 0, release: 2
sleep 2
sample :drum_cymbal_closed, amp: 0.05, sustain: 0, release: 2
sleep 1.99
end
end
define :play_now do |next_note, transposition, amplitude, duration|
play get[:scale][next_note] + transposition * 12, amp: amplitude, sustain: 0, release: duration
end
define :play_the_pattern do |time_state_note, transposition|
pattern = get[:pattern].take(get[:pattern].length)
sync :time
for i in 0..(pattern.length - 1)
offset = i == pattern.length - 1 ? 0.01 : 0
play_now pattern[i][get[:PATTERN_NOTE_VALUE]], transposition, choose_next_amp + 0.1,
pattern[i][get[:PATTERN_NOTE_DURATION]] - offset
set time_state_note, pattern[i][get[:PATTERN_NOTE_VALUE]]
sleep pattern[i][get[:PATTERN_NOTE_DURATION]] - offset
end
end
define :quit do
sleep rrand_i(get[:quit_time_min], get[:quit_time_max])
end
define :switch_pattern do
set :pattern, get[:patterns].choose
end
define :wait_till_turn do |pTurn|
while (get[:turn] != pTurn)
sync :time
sleep 0.99
end
quit
set :turn, get[:turn] + 1
end
live_loop :keep_time do
cue :time
tick
sleep 1
end
in_thread(name: :pattern_play) do
loop do
if one_in(get[:pattern_generation_factor])
generate_pattern
end
if get[:patterns].length > 0 && one_in(get[:pattern_switch_factor])
switch_pattern
end
sleep get[:pattern_play_delay]
end
end
in_thread(name: :play_0) do
loop do
base
quit
end
end
in_thread(name: :play_1) do
wait_till_turn 1
loop do
contra 1, :note_1
quit
end
end
in_thread(name: :play_2) do
wait_till_turn 2
loop do
contra 2, :note_2
quit
end
end
in_thread(name: :play_3) do
wait_till_turn 3
loop do
contra 3, :note_3
quit
end
end
##| in_thread(name: :beat) do
##| play_beat
##| end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment