Last active
October 24, 2022 23:25
-
-
Save ltlian/4c59f7cafa12c9015a5e68cbc08ccc3a to your computer and use it in GitHub Desktop.
Generative music with Sonic PI
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
# Read more about Sonic PI: | |
# https://sonic-pi.net/ | |
# https://github.com/sonic-pi-net | |
BEGIN { | |
use_random_seed 0 | |
set_link_bpm! 100 | |
root_1 = :c2 | |
root_2 = :gs1 | |
root_3 = :as1 | |
key_1 = [:c, :d, :ds, :f, :g, :as] | |
key_2 = [:ds, :gs, :c, :as] | |
key_3 = [:c, :d, :ds, :f] | |
chord_1 = [:c4, :g4, :c5, :ds5] | |
chord_2 = [:gs4, :ds4, :gs4, :c4] | |
chord_3 = [:as4, :f4, :as4, :d4] | |
notes_1 = note_range root_1 + 48, root_1 + 60, pitches: key_1 | |
notes_2 = note_range root_2 + 48, root_2 + 60, pitches: key_2 | |
notes_3 = note_range root_3 + 48, root_3 + 60, pitches: key_3 | |
times = [] | |
while times.sum <= 12 do | |
times.append(choose([0.25, 0.25, 0.5, choose([1, 2, 3, 4])])) | |
end | |
set :key, key_1 | |
set :chords, chord_1 | |
set :times, times | |
set :root, root_1 | |
} | |
in_thread do | |
live_loop :main do | |
link 16 | |
set :key, key_1 | |
set :chords, chord_1 | |
set :lead, notes_1.pick(times.count) | |
set :root, root_1 | |
set :segment, tick | |
sleep 12 | |
link 16 | |
set :key, key_1 | |
set :chords, chord_1 | |
set :lead, notes_1.pick(times.count) | |
set :root, root_1 | |
set :segment, tick | |
sleep 12 | |
link 16 | |
set :key, key_2 | |
set :chords, chord_2 | |
set :lead, notes_2.pick(times.count) | |
set :root, root_2 | |
set :segment, tick | |
sleep 12 | |
link 16 | |
set :key, key_3 | |
set :chords, chord_3 | |
set :lead, notes_3.pick(times.count) | |
set :root, root_3 | |
set :segment, tick | |
sleep 12 | |
end | |
end | |
in_thread do | |
live_loop :bass do | |
with_synth :bass_foundation do | |
root = sync :root | |
in_thread do | |
4.times do | |
play root, sustain: 1, amp: 0.5 | |
sleep 4 | |
end | |
end | |
end | |
end | |
end | |
in_thread do | |
live_loop :perc do | |
sync :segment | |
in_thread do | |
4.times do | |
perc_bar() | |
link | |
end | |
end | |
end | |
end | |
def perc_bar() | |
sample :drum_bass_soft, amp: 0.7 | |
sleep 0.5 | |
sample :drum_bass_soft, amp: 0.3 | |
sleep 0.5 | |
sample :drum_cymbal_closed | |
sample :drum_snare_soft, amp: 0.7 | |
sleep 0.75 | |
sample :drum_bass_soft, amp: 0.3 | |
sleep 0.25 | |
sample :drum_cymbal_closed | |
sample :drum_bass_soft, amp: 0.7 | |
sleep 0.5 | |
sample :drum_bass_soft, amp: 0.3 | |
sleep 0.5 | |
sample :drum_cymbal_closed | |
sample :drum_snare_soft, amp: 0.7 | |
sleep 0.5 | |
sample :drum_bass_soft, amp: 0.3 | |
end | |
in_thread do | |
with_synth :subpulse do | |
with_fx :ping_pong, phase: 0.75, pan_start: 0.75 do | |
live_loop :arp do | |
use_octave 3 | |
note = choose(note_range get[:root], get[:root] + 15, pitches: get[:key]) | |
mod = [(beat % 16) - ((get[:segment] || 0) + 8), 0].max / choose([8, 10]) | |
play note, amp: rrand(0.2, 0.8 - [mod, 0.8].min), release: 0.2 + mod | |
sleep choose([1.5, 2.5]) | |
link 1 | |
end | |
end | |
end | |
end | |
in_thread do | |
with_synth :tech_saws do | |
with_fx :ping_pong, phase: 0.2, max_phase: 3, pan_start: 0.75 do | |
live_loop :chords do | |
with_fx :reverb do | |
with_fx :flanger do | |
chords = sync :chords | |
play_chord chords, attack: 2, release: 7, amp: 0.4 | |
end | |
end | |
end | |
end | |
end | |
end | |
def get_chord (note, key) | |
if key.nil? | |
[note] | |
else | |
rng = (note_range :c6, :c7, pitches: key) | |
idx = rng.index(note + 0) | |
if idx.nil? | |
[note] | |
elsif one_in 3 | |
[note, rng[idx + 1]] | |
elsif one_in 2 | |
[rng[idx - 2], note, rng[idx + 1]] | |
else | |
[rng[idx - 2], note] | |
end | |
end | |
end | |
in_thread do | |
with_synth :blade do | |
with_fx :ping_pong, phase: 0.75, max_phase: 3, mix: 0.33 do | |
live_loop :lead_in do | |
use_octave -2 | |
lead = sync :lead | |
if one_in 3 | |
shuffle = choose([0.25, 0]) | |
sleep 15 + shuffle * 2 | |
l = play choose(lead), sustain: 0.75 - choose([0, shuffle]), release: 0.1, amp: rrand(0.4, 1) | |
sleep 0.5 - shuffle | |
control l, note: choose(lead) | |
end | |
end | |
live_loop :lead do | |
use_octave -2 | |
lead = sync :lead | |
in_thread do | |
get[:times].each_with_index do |t, i| | |
if one_in 4 | |
play lead[i], sustain: t, release: 0.1, amp: rrand(0.4, 1) | |
elsif one_in 2 | |
# ghost | |
elsif one_in 2 | |
play lead[i], release: 0.5, decay: 0, amp: rrand(0.4, 1) | |
else | |
play lead[i], release: 1, decay: 0, amp: rrand(0.4, 1) | |
end | |
sleep t | |
end | |
end | |
end | |
end | |
end | |
end | |
in_thread do | |
with_synth :winwood_lead do | |
with_fx :ping_pong, phase: 0.75, max_phase: 3, mix: 0.33, amp: 0.35 do | |
live_loop :lead_canon do | |
use_octave -2 | |
lead = sync :lead | |
key = get[:key] | |
root = get[:root] | |
in_thread do | |
get[:times].each_with_index do |t, i| | |
on 4 < i && i < choose([9, 12]) do | |
with_swing 2, 1 do | |
canon = get_chord(lead[i], key) | |
play_chord(canon, sustain: choose([0.1, 0.2, t]), release: 0.1, ramp_ratio: 0) | |
end | |
end | |
sleep t | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment