Sonic Pi cover of Max Cooper - Spectrum (Official video by Christian Stangl)
Draft 1
## 220328 21:32 1.draft of a cover
## My cover draft1 https://youtu.be/eB2VtPJy0YY
## What can we learn by doing a Sonic Pi cover of Max Cooper's Spectrum?
## Max Cooper - Spectrum (Official video by Christian Stangl)
## https://youtu.be/we2rXhKv0mQ original
## How to start building a cover in Sonic Pi?
## 1) Used Ableton "TAP" to find bpm
## 2) Imported a WAV of the track in Ableton to use Abletons "Convert drums to new midi track" on the first 1-2 bars to find the nice chord rythm.
## 3) Played around on guitar/keyboard to find notes in chords and bass.
## The hardest part, since there are a lot of filters on the chords, so notes are hard to hear clearly.
## How do we create structure in a song like this?
## Ended up using the "Clumsy mixer" from https://github.com/mbutz/sonicpi-leuphana-ws1718/blob/master/session-03/live-loop-syncing-2.rb
## I think this is a great solution, since we are free to start and stop live_loops without messing up the song structure,
## which I did, when I tried to create structure with a counter.
## To do
# Create the rest of the chord progression
# Sound level of chords + lfo on rythm
# Ring on different synths on chords
# Buildups / sweeps
# Random samples random places
# Idea: https://sampleswap.org/filebrowser-new.php?d=VOCALS+and+SPOKEN+WORD%2FSpeak+and+Spell%2FCIRCUITBENT%2F
# Idea: audio out to soundcard with "sound out"? https://sonic-pi.net/tutorial.html#section-13-3
# Forum post https://in-thread.sonic-pi.net/t/live-coding-preview-functionality/6638/2
use_bpm 110 # Tempo
w=1 # sleep values for notes
h=0.5
q=0.25
s=0.125
live_loop :met do # Metronom for sync
sleep w+w # w+w to get "kick and snare" on the right places in "drums"
end
# Song structure Intro A B C
# ----------------------------------
# chords = 1 1 1 synth* fx #:saw #:piano :tech_saws :dpulse :saw # :dtri
# sub_bass = 1 1
# melody = 1
# hihat1 = * "*" = as you like
# hihat2 = *
# drums = 0 (1) 1 2/3*
# ----------------------------------
# Idea: change synth to get to part C, D, E
#########################################
## "Clumsy" on/off Mixer ##
#########################################
## 1 starts, 0 stops the loops
chords = 1 # sync to met
sub_bass = 0 # sync to chords
melody = 1 # sync to chords # Plays 1.time in intro (sleeps before playing)
hihat1 = 0 # # Clicky hihat with tabla samples
hihat2 = 0 # # Noise hihat
drums = 0 # # 0 (No kick in intro on 3/4, kick on last 1/4)
# # 1 Only kick
# # 2 Kick+random snare
# # 3 Kick+snare -X-X (used most of the song)
# # (4 Kick+snare-X-X+random snare - needs to be adjusted)
#########################################
## Set amp levels here?
## Set LFO on chords here?
## Fade out?
#########################################
# Rythm of chords
rythm = [1,1,0,1, 0,0,1,0, 0,1,0,1, 0,0,1,0, 1,0,0,1, 0,0,1,0, 0,1,0,1, 0,0,1,0]
with_fx :reverb, room: 0.7 do
live_loop :chords, sync: :met do
stop if chords < 1
use_synth :saw #:saw #:piano(+12?) :tech_saws :dpulse :saw # :dtri(loud volume)
r= rrand(0.25,0.55) #mel
#a=1
#a = range(4,0.25, inclusive: true, steps: 0.05125).mirror.tick(:b) # hmm - should this be here or in each define?
a_chord = range(2,0.25, inclusive: true, steps: 0.05125).mirror.tick(:b) # hmm - should this be here or in each define? 0.25 to low?
#a=1
32.times do |i|
c = range(50,90, steps: 20).mirror.tick(:a)
#a = range(2,0.25, inclusive: true, steps: 0.05125).mirror.tick(:b) # fades on amp not quite right yet should be from high to low to high
play_chord [:bb1, :f3,:cs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:f1, :f3,:gs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
# ----------------------------------------------------------------------------------------
32.times do |i|
c = range(50,90, steps: 20).mirror.tick(:a)
a = range(4,0.25, inclusive: true, steps: 0.05125).mirror.tick(:b) # fades on amp not quite right yet should be \_/
play_chord [:bb1, :f3,:cs4,:es5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:f1, :f3,:gs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:es5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5], release: r, cutoff: c, amp: a_chord if rythm[i] == 1
sleep q
end
# ----------------------------------------------------------------------------------------
# missing stuff here
end
live_loop :sub_bass, sync: :chords do
stop if sub_bass < 1
use_synth :sine
a_bass=0.8
r= rrand(0.25,0.55)
32.times do |i|
c = range(50,90, steps: 20).mirror.tick(:a)
#a = range(4,0.25, inclusive: true, steps: 0.05125).mirror.tick(:b) # fades on amp not quite right yet should be from high to low to high
play_chord [:bb1, :f3,:cs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:f1, :f3,:gs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
# ------------------------------------------------------------------------------------------------
32.times do |i|
c = range(50,90, steps: 20).mirror.tick(:a)
play_chord [:bb1, :f3,:cs4,:es5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:f1, :f3,:gs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:es5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
32.times do |i|
c = range(50,90, steps: 10).mirror.tick(:a)
play_chord [:fs1, :as3,:cs4,:ds5].take(1), release: r, cutoff: c, amp: a_bass if rythm[i] == 1
sleep q
end
# ------------------------------------------------------------------------------------------------
end
# Obo like small melody behind chords #why does the "a" modulation go on amp here?? Should it be seperate scope?
live_loop :melody, sync: :chords do
stop if melody < 1
use_synth :square
a1=0.5
sleep 16*3*q
play :bb4, attack: 8*q, release: 2*q, amp: a1, cutoff: 70
sleep 8*q+2*q
play :eb4, attack: 8*q, decay: 2*q, sustain: (16+4)*q, release: w, amp: a1, cutoff: 70
sleep 8*q+2*q+(16+4)*q+w
play :f4, attack: 8*q, release: 2*q, amp: a1, cutoff: 70
play :as4, attack: 8*q, release: 2*q, amp: a1, cutoff: 70
sleep 8*q+2*q
play :bb3, attack: 8*q, decay: 2*q, sustain: (16+4)*q, release: w*4, amp: a1, cutoff: 70 # to loud volume + weird sin() movement
sleep 16*3*q
#play :gs2, attack: 8*q, decay: 2*q, sustain: (32)*q, release: w, amp: a, cutoff: 70
#:cs
# missing some stuff here
end
live_loop :hihat1, sync: :met do
stop if hihat1 < 1
use_synth :noise
sample :tabla_ke2, rate: rrand(2,5), finish: 0.5, amp: rrand_i(0.5,1), pan: ring(-0.5,0.5).choose if spread(3,5).tick(:h) and one_in(4)
sample :tabla_re, rate: rrand(1,4), amp: rrand_i(0.5,1.5), pan: ring(-0.35,0.35).choose if spread(5,7).tick(:h) #and one_in(4)
sleep q
end
live_loop :hihat2, sync: :met do
stop if hihat2 < 1
use_synth :noise
play :c5, release: 0.01, amp: rrand(0.25,1), pan: ring(-0.7,0.7).choose if spread(11,16).tick(:h) #and one_in(1)
sample :tabla_te_m, rate: rrand(3,4), amp: rrand_i(0.5,1), pan: ring(-0.25,0.25).choose if spread(5,7).tick(:h) #and one_in(4)
sleep q
end
end #end of reverb
live_loop :drums, sync: :met do
stop if drums < 1
a_kick = 1
a_snare = 0.8
case drums #case snare_form #https://www.rubyguides.com/2015/10/ruby-case/
when 1
sample :bd_haus, cutoff: 70, amp: a_kick
sleep w
sample :bd_haus, cutoff: 70, amp: a_kick
sleep w
when 2
sample :bd_haus, cutoff: 70, amp: a_kick
sleep w
sample :bd_haus, cutoff: 70, amp: a_kick
sample :sn_generic, cutoff: 110, finish: rrand(0.03,0.06), pan: rrand(0.5,-0.5), rate: rrand(2,4), amp: a_snare if one_in(4) # plays once a while
sleep w
when 3
sample :bd_haus, cutoff: 70, amp: a_kick
sleep w
sample :bd_haus, cutoff: 70, amp: a_kick
sample :sn_generic, cutoff: 110, finish: 0.09, pan: rrand(0.15,-0.15), rate: rrand(2.5,3), amp: a_snare # snare on -X-X
sleep w
when 4
sample :bd_haus, cutoff: 70, amp: a_kick
sleep w
sample :bd_haus, cutoff: 70, amp: a_kick
sample :sn_generic, cutoff: 110, finish: 0.06, pan: rrand(0.15,-0.15), rate: rrand(2.5,3), amp: a_snare # snare on -X-X
sleep q
sleep q
sample :sn_generic, cutoff: 110, finish: 0.04, pan: rrand(0.15,-0.15), rate: rrand(2.5,3), amp: a_snare if one_in(3)
sleep q
sample :sn_generic, cutoff: 110, finish: 0.02, pan: rrand(0.15,-0.15), rate: rrand(2.5,3), amp: a_snare if one_in(3)
sleep q
end
end
# ------------------------------------------------------------
# Idea to Visuals with Hydra
# Create rotating stone like thingys
# Original - jumpoff point
# https://hydra.ojack.xyz/?code=JTJGJTJGR2xpdGNoJTIwUml2ZXIlMEElMkYlMkZGbG9yJTIwZGUlMjBGdWVnbyUwQSUyRiUyRmh0dHBzJTNBJTJGJTJGZmxvcmRlZnVlZ28uZ2l0aHViLmlvJTJGJTBBdm9yb25vaSg4JTJDMSklMEEubXVsdChvc2MoMTAlMkMwLjElMkMoKSUzRCUzRU1hdGguc2luKHRpbWUpKjMpLnNhdHVyYXRlKDMpLmthbGVpZCgyMDApKSUwQS5tb2R1bGF0ZShvMCUyQzAuNSklMEEuYWRkKG8wJTJDMC44KSUwQS5zY3JvbGxZKC0wLjAxKSUwQS5zY2FsZSgwLjk5KSUwQS5tb2R1bGF0ZSh2b3Jvbm9pKDglMkMxKSUyQzAuMDA4KSUwQS5sdW1hKDAuMyklMEEub3V0KDApJTBBJTBBJTBBc3BlZWQlMjAlM0QlMjAwLjAxJTBBJTBBJTBBJTBB
#
# ------------------------------------------------------------