Created
December 30, 2020 09:38
-
-
Save d0lfyn/6858ecd32d7685fc47ca54fa83a00f74 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##| 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 6 | |
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, 5) | |
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