Sonic Pi cover of Max Cooper - Spectrum (Official video by Christian Stangl)

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
#
# ------------------------------------------------------------

1 Like

Awesome work so far! Excited to see how you progress with your Todo list :slight_smile:

1 Like