Skip to content

Instantly share code, notes, and snippets.

@Nanomancer
Last active December 1, 2019 13:17
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nanomancer/c68e1beb384c9eb0cce8 to your computer and use it in GitHub Desktop.
Save Nanomancer/c68e1beb384c9eb0cce8 to your computer and use it in GitHub Desktop.
Sonic Pi code (Ruby) for piece entitled 'Transmission' based around MIDI note tuned resonators
## Transmission - Origin Unknown -Tuned Resonators in C minor
## Random Seed Version: 746742
## Coded by Nanomancer - Distributed under Creative Commons Non-Commercial Attribution license - :)
## 26.03.2016
## Watch a video produced with screen grabs of the code and Nebulae:
## https://www.youtube.com/watch?v=5fwGHAdoaXA&feature=youtu.be
#######################
max_t = 8 # Adjust the run time of the piece
load_samples [:ambi_drone, :ambi_haunted_hum, :ambi_lunar_land]
$global_clock = 0
use_bpm 60
set_volume! 5
set_sched_ahead_time! 2
use_cue_logging false
# SEED = 471646
# SEED = 32625
# SEED = 489370
SEED = 746742
# SEED = Time.now.usec # uncomment this to get a different run every time
# puts "Epoch seed: #{SEED}"
use_random_seed SEED
#### Sync for video ####
#sleep 2
#sample :elec_blip, amp: 0.2
#puts "SYNC"
#sleep 8
################ FUNCTIONS ########################
define :stopwatch do |int, max, fade|
## interval in seconds (display for log timer),
## max in mins, fade in secs
count = 0
set_mixer_control! amp: 1, amp_slide: 0.1
with_bpm 60 do
ctrl = true
while count / 60.0 <= max
if count % int == 0
puts "Time: #{count / 60.0} Minutes"
end
count += 1
sleep 1
$global_clock = count / 60.0
if count >= (max*60) - fade && ctrl == true
set_mixer_control! amp: 0.01, amp_slide: fade
puts "Stopping - #{fade} sec fadeout"
ctrl = false # stops this block from running more than once
end
end
end
end
define :autocue do |id, time|
# send a cue after a specified time in decimal minutes, id must be a key
# call in the loop you're syncing to
return cue id if $global_clock >= time
end
define :autostop do |time|
# same as :autocue but for stopping - call in the loop you want to stop
return stop if $global_clock >= time
end
define :mk_rand_scale do |scale, len = 8|
# random scale that may contain the same note more than once
rand_s = []
len.times do
rand_s << scale.choose
end
return rand_s.ring
end
############# CLOCK #####################
in_thread do
stopwatch(30, max_t, max_t*60*0.1)
end
############## BASS #########################
live_loop :pulsar, sync: :pulse, auto_cue: false do
use_synth :growl
autostop(rrand max_t*0.75, max_t)
puts "Pulsar"
notes = (knit :c3, 2, :ds3, 1, :c3, 1)
with_fx :reverb, mix: 0.3, room: 0.3, amp: 1 do
notes.size.times do
cut = range(55, 90, step: 5).mirror.ring.tick(:cut) # filter sweeps up & down
play notes.tick, amp: 0.25, attack: 1.125,
sustain: 1.25, release: 3, cutoff: cut, res: 0.2
sleep 8
end
end
if one_in 3 then sleep [8, 16, 24].choose end
end
############## TUNED RESONATED DRONE #########################
live_loop :drone, auto_cue: false do
autostop(max_t)
autocue(:prb, (rrand 0, max_t*0.3)) # cues up all the other loops, within specified time range
autocue(:pulse, (rrand 0, max_t*0.4))
autocue(:stc, (rrand 0, max_t*0.3))
autocue(:trans, (rrand max_t*0.2, max_t*0.5))
scl = scale(:c5, :harmonic_minor, num_octaves: 1)[0..4]
notes = mk_rand_scale(scl, 4)
puts "Drone sequence: #{notes}"
notes.size.times do
frq = midi_to_hz(notes.tick) # converts scale to frequency for resonator effect
del = 1.0 / frq # plug this into SP's echo...
# use echo to produced tuned resonance - avoid setting decay too high!
with_fx :echo, amp: 1, mix: 1, phase: del, decay: 2 do
sample :ambi_drone, attack: 0.6,
pan: 0, amp: 1, rate: 0.5, cutoff: 117.5
sleep 8
end
end
end
############## TUNED RESONATED HUM #########################
live_loop :probe, sync: :prb, auto_cue: false do
autostop(rrand max_t*0.7, max_t)
notes = (ring 63, 65, 68, 71, 72).shuffle
vol = 1
puts "Probe sequence: #{notes}"
4.times do
phase = [0.25, 0.5, 0.75, 1, 1.5, 2].choose
with_fx :lpf, res: 0.1, cutoff: rrand(70, 85) do
with_fx :compressor, threshold: 0.4 do
with_fx :slicer, mix: rrand(0.25, 0.75),
smooth_up: phase * 0.5, smooth_down: phase * 0.125, phase: phase do
with_fx :reverb, mix: rrand(0.6, 0.8), room: [0.6, 0.7, 0.8].choose do
2.times do
frq = midi_to_hz(notes.tick)
puts "Probe freq: #{frq.round(2)} | Mod: #{phase}"
with_fx :echo, amp: 0.8, mix: 0.85, phase: 1.0 / frq, decay: 2.5 do
sample :ambi_haunted_hum,
beat_stretch: 4,
pan: [0.75, -0.75].ring.look,
amp: vol,
rate: (ring 0.25, -0.25).tick(:ambi) # play forward, then reverse
end
sleep 16
end
end
sleep [12, 16, 24, 32].choose
end
end
end
end
end
############## TUNED RINGMOD / SYNTH #########################
scales_arr = []
2.times do
scl = scale([:c5, :c6].choose, :harmonic_minor, num_octaves: 2)
scales_arr << mk_rand_scale(scl, 3)
end
live_loop :transmission, sync: :trans, auto_cue: false do
use_synth :blade
autostop(rrand max_t*0.8, max_t) # (rrand_i 5, 7)
chd = chord(:c1, :minor, num_octaves: 2).shuffle
notes = scales_arr.choose
slp = [[3,3,2], [4,4,2], [6,6,3], [8,8,4]].choose.ring
puts "Transmission pattern: #{slp}"
(slp.size * 2).times do
att, sus, rel = slp.tick * 0.3, slp.look * 0.2, slp.look * 0.5
phase = [0.25, 0.5, 0.75, 1].choose
mod_frq = rdist(0.0125, 0.5) * midi_to_hz(chd.tick(:chd))
with_fx :echo, mix: 0.25, phase: 1.5, decay: 4 do
with_fx :ring_mod, freq: mod_frq do
with_fx :slicer, mix: rrand(0.125, 0.75),
smooth_up: phase * 0.5, smooth_down: phase * 0.125, phase: phase do
play notes.look, amp: 0.09, attack: att,
sustain: sus, release: rel, cutoff: 85
sleep slp.look
end
end
end
end
sleep [4, 8, 12, 16, 20, 32].choose
end
############## Filtered noise with Filter LFO(ish) #########################
live_loop :static, sync: :stc, auto_cue: false do
use_synth :bnoise
autostop(rrand max_t*0.6, max_t)
scl = scale(:c2, :harmonic_minor, num_octaves: 2).choose
mod_frq = midi_to_hz(scl)
phs = [0.125, 0.5, 0.25, 0.75, 1].choose
len = [8, 10, 12, 16, 24, 32].choose
puts "Static - AM: #{phs} | Len: #{len}"
with_fx :hpf, cutoff: 60 do
with_fx :ring_mod, freq: mod_frq do
with_fx :slicer, smooth_up: phs*0.25,
mix: rrand(0.3,0.9), phase: phs do
with_fx :reverb, mix: 0.5, room: 0.6 do
cut = rrand(70, 120) # set initial cutoff freq
amt = rrand(70, 120) # set secondary cutoff freq
s = play :c4, amp: 0.0375, attack: len*0.5,
release: len*0.5, cutoff: cut,
cutoff_slide: len*0.5, res: (rrand 0.01, 0.6)
control s, cutoff: amt # slide to secondary
sleep len*0.5
control s, cutoff: cut # slide back to initial
sleep len*0.5
end
end
end
end
if len <= 6 then sleep(2)
else sleep [10, 16, 20, 24].choose end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment