A shimmering pattern on a sonorous bass

This piece was inspired by the Ring Chains section of the Tutorial. I started with three related rings of notes playing different extended chords, and then mashed them in various ways using function for the Ring Chains section. I played the resulting three rings together with different synths, and adding different euclidian rhythms to each chain using the bools function. The notes were played quite fast, but were supported on a sonorous bass note generated by the :dsaw synth, and the process was repeated with the whole thing being transposed up the first five notes of a scale beofre dropping an octave and then returning to the starting note.
gverb and ixi_techno effects were added, and I also slowly increased the tempo as the piece progressed.
The code is shown below and you can hear the result on soundcloud

#triple related pattern shimmers on a bass note by Robin Newman March 2019 patternShimmer3.rb
use_debug false
set :flag,false #used to initiate finish
use_bpm 40 #starting value
#use_random_seed 5032019 #uncommment and change number get different versions
#define three related note patterns
re=(ring :c3,:e3,:g3,:c4,:e4,:g4,:c5,:e5,:g5,:c6)
rd=(ring :c3,:d3,:f3,:c4,:d4,:f4,:c5,:d5,:f5,:c6)
rf=ring(:c3,:f3,:a3,:C4,:f4,:a4,:c5,:f4,:a5,:c6)
#define range of spread parameters
b=[[3,8],[5,8],[7,11],[5,13],[8,13],[8,17],[13,17]]
pn=0.5 #set initial bass pan position
offset=0;toffset=0 #set transpose offset and offset change time
with_fx :gverb,room: 20,mix: 0.7 do
  with_fx :level,amp: 0 do |v| #control fade in and out of piece
    control v,amp: 0.7,amp_slide: 10
    with_fx :ixi_techno,phase: 10,mix: 0.4 do #add some interest to bass note
      live_loop :shimmer do
        if (vt-toffset) >= 5 #check if time to change transpose offsets {every 5 beats minimum})
          offset=(ring 0,2,4,5,7,-5).tick(:o) #get next offset value
          toffset=vt #reset offset time variable
          puts "look(:o) #{look(:o)}"
          set :flag,true if look(:o)==24 # on offset 0
        end
        puts "current offset #{offset}, current bpm #{(current_bpm*100).to_i/100.0}" #print current offset and bpm
        use_transpose [0+offset,12+offset].choose #choose transpose
        use_transpose 0 if get(:flag)
        bass=:c2 #fundamental bass note
        i=dice(6)-1 #choose next note pattern pointer
        #get note patterns for current pointer
        cur1=[re,rd,rf,re.reverse,rd.reverse,rf.reverse][i]
        cur2=[rd,rf,re, rd.reverse,rf.reverse,re.reverse][i]
        cur3=[rf,re,rd, rf.reverse,re.reverse,rd.reverse][i]
        
        p=rand_i(11)+1 #set up pick selector for next pass
        s=[1,1,1,1,1,2].choose #set up stretch for next pass
        cur4=cur1.shuffle.pick(p).stretch(s).mirror #get first part pattern to play
        cur5=cur2.shuffle.pick(p).stretch(s).mirror #get second part pattern
        cur6=cur3.shuffle.pick(p).stretch(s).mirror #get third part pattern
        
        br=rand_i(6) #choose bool spread values for first part
        br2=rand_i(6) #choose bool spread values for second part
        br3=rand_i(6) #choose bool spread values for third part
        in_thread do #play bass note for pattern duration in thread
          t=cur4.length*0.1 #duration
          pn = pn*-1 #swap pan setting each time
          #puts pn
          use_synth :dsaw #bass synth
          play bass,sustain: t,amp: 0.3,pan: pn*0.7 #play bass note
        end
        with_fx :level,amp: 0.5 do #set limit on parts volume
          cur4.length.times do
            pd=(-1)**dice(2) #choose pan setting
            use_synth :tri #part 1 synth
            #play first part with euclidian rhythm
            play cur4.tick,release: 0.1,amp: 0.8,pan: pd if bools(b[br,0],b[br,1]).look
            use_synth :saw #part 2 synth
            #play 2nd part with euclidian rhythm
            play cur5.look,release: 0.1,amp: 0.8,pan: -pd if bools(b[br2,0],b[br2,1]).look
            use_synth :fm #play fm up an octave, as its normal pitch is an octave down
            #play 3rd part with euclidian rhythm
            play 12+note(cur6.look),release: 0.1,amp: 0.8,pan: pd*0.5 if bools(b[br3,0],b[br3,1]).look
            sleep 0.1
          end
          #at end of note play sequence check for end
          if get(:flag)
            #play low bass note fading out
            synth :dsaw,note: :c1,release: 4,amp: 0.5,pan: 0
            sleep 4
            # send stop-all-jobs osc to port 4557
            osc_send "localhost",4557,"/stop-all-jobs","rbnguid"
            sleep 1 #ensures nothing else starts before stop is finished
          end
        end
        use_bpm_mul 1.004 #slow increase in tempo
      end
    end
  end
end

4 Likes

It sounds really good! Great work. The code is rather dense, pretty hard to see what’s going on just by looking at it quickly.

Hopefully the comments will help a bit. I did rather add bits starting from a fairly simple beginning. Initially I played three simple chords on a keyboard and played with them, and it grew from that. First I added the bass note, then added the transposition, with some timing to alter this, then added the tempo changes, and finally added a mechanism to stop the piece nicely.
Each of the three rings of notes are altered at random (but in the same way) so that the end result gives rings of the same length for all three which can play together ticked in times loop. Each one has different bools functions applied to give interesting rhythms.