Can't get _slide functions working

I’ve been trying for weeks to get better at controlling params for running synths and fx. I’ve found myself chasing my own tail many times (i.e. solving one problem creates another).

Most reliable solution so far uses this concept…

live_loop :control2 do
  set :t, 10
  sleep 1
end

live_loop :drums1 do
  with_fx :rlpf, cutoff: get[:t], cutoff_slide: 8 do
    sample :loop_amen, beat_stretch: 4
    sleep 4
  end
end

Using get/set to define global variables that are read by the fx definitions each pass of the live_loop.

HOWEVER…

I want to create a nice gentle slide from one cutoff frequency to the next. I want to drop a new value in to the :control2 live_loop and then hear the filter slide elegantly down/up to the new position. So I try to use cutoff_slide. But it doesn’t work.

The code above creates instantaneous jumps in Cutoff value, rather than slides.

I feel like the answer is to use “control” commands instead of “with_fx”. But that creates problems with redefining fx once they are declared (unless declared inside the self-same thread/loop, in which case they re-assert their original definition with each pass).

Can anyone show me a way to get my _slide code working?

I may be missing your point, but I think the best bet is to call your fx outside the loop, and then call a control inside of it.

Time your loop or use x.times do with a “control [cutoff]” at the beginning or end. So for yours, have it as

with_fx :rlpf, cutoff: get[:t], cutoff_slide: 8 do |lpf|
  live_loop :drums1 do

    control lpf, cutoff: get[:t]

3.times do
    sample :loop_amen, beat_stretch: 4
    sleep 4
    end 

  end
end

or maybe even…

with_fx :rlpf, cutoff: get[:t], cutoff_slide: 8 do |lpf|
  live_loop :drums1 do

sample :loop_amen, beat_stretch: 4
sleep 2
    control lpf, cutoff: get[:t]
sleep 2
2.times do
    sample :loop_amen, beat_stretch: 4
    sleep 4
    end 

  end
end

here’s something I made to tie it all together, based on one of Mr Bomb’s tutorials and your q. I like wacky sounds but this works well and you can make it more organized (pffff) on your own if you’re into that sort of thing.

#varz
n=knit(:e1,8, :gs1,4, :a1,4)

live_loop :lvlset do
  clvl = [40,50,60,70, 90, 100].choose
  set :c, clvl
  puts clvl
  sleep 4
end

#steady drums
live_loop :bdwon do
  sample :bd_tek
  sleep knit(0.5,2, 1,3).tick
end

live_loop :beedeetoo do
  sample :bd_haus, cutoff: 95
  sleep knit(1,2, 0.75,1, 0.25,5).tick
end

#movers, shakers
with_fx :reverb do
  with_fx :rlpf do |f|
    with_fx :eq, high: -0.75 do
      
      live_loop :octobass do
        
        6.times do
          play ring(:e1, :gs1, :a1).look, sustain: 2, pan: -1
          4.times do
            use_synth :chipbass
            play octs(n.tick,3).choose, pan: [1,-1].look
            
          sleep 0.25 end
        end
        control f, cutoff: get[:c], cutoff_slide: 5
        cue :dingy
    end end
end end

with_fx :distortion do |d|
  with_fx :rhpf do |hpf|
    #maybe add echo/pingpong
    live_loop :dingy do
      
      wait :octobass
      
      9.times do
        use_synth knit(:pretty_bell,33, :dull_bell,14).tick
        control d, distort: dice(9)*0.1, distort_slide: 0.5
        play [:e4,:cs3].choose, amp: 0.2, pan: [-1,1].look
        
        density 1+look%4 do
          play octs(:cs1,5).pick(2)
          sleep 0.2
          play octs(n.look,3).pick(3)
        sleep [0.3,0.45,0.8].choose end
      end
      
      sleep 4
      control hpf, cutoff: get[:c]+dice(30), cutoff_slide: 6
      
    end
end end

I came back to this a few times to make edits, & had included another thing I was working on as an example. I’ll remove the explanation because this got long and all, haha.

old post

here’s a chunk of something I’ve been working on:


with_fx :bitcrusher do |b|
  with_fx :flanger do
    with_fx :slicer, mix: 0 do |s|
      with_fx :eq, mid: 0.2 do
        live_loop :ch do
          dg = knit(:i,4, :vi,4, :ii,4, :v,4)
          
          4.times do # full cycle thru degreez = 16*0.5 = 8 beets
            4.times do
              use_random_seed 420
              play chord_degree(
              dg.tick, :db4,:major,4, invert: [0,dice(3),0].look)
              sleep 0.5
              
              control s, mix: [1,0].choose,
                phase_delay: [0.25,0.1].choose, phase: 0.05*dice
            end
            
          end
        end
end end end end


with_fx :eq, low: 0.15 do
  with_fx :slicer, wave: 3 do |sl|
    with_fx :gverb, mix: 0.3 do |g|
      use_synth :fm
      use_synth_defaults sustain: 0.1, decay: 0.4, release: 0.1
      control g,  ref_level: 0.1, tail_level: 0.75, mix: 0.2
      
      live_loop :bass do
        4.times do
          control sl, mix: [0,0.5,0].look, amp_min: halves(0.25,5).look,
            phase: choose([0.75,[0.25, 0.1, rrand(0.1,0.5)].look]),
            phase_slide: 1, invert_wave: 0
          dg = ring(:i, :vi, :ii, :v)
          density [1,2,1].tick do
          play_pattern_timed chord_degree(dg.look, :db2, :major, 4), 0.5 end
        end
      end
end end end



with_fx :bitcrusher, bits: 8, sample_rate: 25000 do
  with_fx :rlpf, res: 0.9 do |f|
    with_fx :slicer, wave: 0, phase: 0.125 do |sl|
      live_loop :str do
        use_synth :blade
        # sleep 24        
        
        4.times do
          control f, cutoff_slide: 7,
            cutoff: [100, dice(20*5), 30+dice(90)].look
          
          
          control sl, mix: 0, wave: range(0,3,1).look
          n= play :db, sustain: 8, decay: [1,1,1,18].look, attack: 0.2
          use_synth_defaults vibrato_rate: [6,3].look,
            vibrato_rate_slide: 2, vibrato_depth: 0.22
          n
          
          3.times do
            sleep 1.75
            control sl, mix: [0,1,rrand(0,1)].look,
              phase: [0.25,0.1 * dice].look
            control n, note: [:bb, :eb, :ab].tick,
              note_slide: [0.25,0.5].look,
              pan: rrand(-1,1, step: 0.5), pan_slide: 0.5
            sleep 0.25
            
            use_transpose knit(0,4, -12,4, -24,2).look
            
          end
          sleep 2
          
          
      end end
end end end

Thanks for posting some of your creations alongside some helpful ideas. I listened to and enjoyed both of them.

It still can’t get it to work for me.

I put your second idea together with a loop from my original post that updates a variable (set).

use_bpm 110

live_loop :control2 do
  set :t, 100
  sleep 0.25
end

with_fx :rlpf, cutoff: get[:t] do |lpf|
  live_loop :drums1 do
    sample :loop_amen, beat_stretch: 4
    sleep 2
    control lpf, cutoff: get[:t]
    puts get[:t]
    sleep 2
    2.times do
      sample :loop_amen, beat_stretch: 4
      sleep 4
    end
  end
end

I change the value of t in :control2. I expect the sound of the lpf to change. It doesn’t.

I watch the value of :t tick past on the console. I can see that the value of t has been updated. But the sound doesn’t change. I stop the program and restart it and, finally, the sound is updated.

Can anyone else verify these results?

I’m still confused about what is broken about this code. It looks solid to me. But I am realizing that the hierarchy of creating devices and establishing loops makes this process fraught. If someone knows of the tutorial that comprehensively describes this, please share.

Thank you.

The problem is that each time you press run a new with_fx wrapper created. However you are not altering live_loop :drums and so its code is not reevaluated and the new lpf reference is not the same as the one the live_loop is using.
The solution I use is to alter the program as below, and to comment out the line after the first run, before you rerun with an altered set:t in the control2 loop. That way the value of :lp is set only once and the correct value of lpf is use for the control. Its a bit finnicky to do but works.

Or you can change the live_loop :control2 to receive data from an external OSC call, which can be generated either from a simple program in a different Sonic Pi buffer which you run, or from a program like TouchOSC (well worth purchasing) which can send the data from a smart phone or tablet

There are several other discussions on this topic which is raised quite often. See here and here

solution 1

use_bpm 110

live_loop :control2 do
  set :t, 100
  sleep 0.25
end

with_fx :rlpf, cutoff: get[:t] do |lpf|
  set :lp,lpf #comment this line after first run BEFORE running again
#you will need to uncomment it if you alter live_loop :drums1 OR if you press stop
#before running as if for the first time.
  live_loop :drums1 do
    sample :loop_amen, beat_stretch: 4
    sleep 2
    control get(:lp), cutoff: get[:t]
    puts get[:t]
    sleep 2
    2.times do
      sample :loop_amen, beat_stretch: 4
      sleep 4
    end
  end

solution 2 EDIT initial value of :t now set and extraneous . removed from 90. in osc send program

#run in first buffer

use_bpm 110
set :t,100 #set an initial value for :t.   OR run the osc send program once before running this to set it
live_loop :control2 do
  use_real_time
  n= sync "/osc*/cutoff"
  set :t,n[0]
end

with_fx :rlpf, cutoff: get[:t] do |lpf|
  live_loop :drums1 do
    sample :loop_amen, beat_stretch: 4
    sleep 2
    control lpf, cutoff: get[:t]
    puts get[:t]
    sleep 2
    2.times do
      sample :loop_amen, beat_stretch: 4
      sleep 4
    end
  end
end

Run program below in a separate buffer whenever you want to change the cutoff value

use_osc "localhost",4560

osc "/cutoff", 90 # alter the 90 to whatever value you want (max 120)

Hmmm. I copied and pasted your “two buffer solution” into two separate buffers… but it didn’t produce the intended result.

The value changes from OSC are not received in the first buffer. The value of :t never updates.

I thought this idea sounded promising. I could run one buffer for my synths and samples, and another for my LFO’s.

But I have no experience with OSC. So I can’t debug this. No errors. Just doesn’t change the sound of the synth.

Thanks for the help. I’ll dig in to the links you sent.

Glad you enjoyed those wacky sounds, haha. It’s been really gratifying to reach a point where what I’m making actually sounds like music so I do really appreciate it!

Doesn’t it work fine if you simply write in the value you want under the control? I assume this would be more for a livecoding // jamming type of situation, correct? I’m sorry if I’m totally missing your point here, but I quickly threw together this straightforward ex:

with_fx :lpf do |lpf|
  control lpf, cutoff: 100
  # ^^ cutoff value first time around will be 100
  use_synth :sine
  live_loop :sine do
    n= ring(:a1,:c1,:e1,:g1)
    # ^^ notes to play
    c= ring(120,90,80,70,60,50,40)
    # ^^ new cutoff value options
    5.times do
      
      4.times do
        play_pattern_timed octs(n.tick,5), 0.25
        # ^^ play each note in 5 octaves
        sleep 0.25
      end
      cc= c.choose
      # ^^ pick a new cutoff value
      control lpf, cutoff: cc, cutoff_slide: 5
      # ^^ set as new cutoff, slide there over 5
      puts cc
    end
  end
end

of course, rather than using a random selector, you can simply write in the value you want. Just move the control to the top of the loop, and be aware that it will only make the change once it’s called (i.e. at the top of your loop, or bottom).

If you want to start the slide immediately, or after a note is played, just be aware that it won’t happen until the loop returns to the point where the control is.

Sorry if I am missing your point though. I tend to putz around on the forums during breaks from work or at the end of my days so… well, my reading comprehension may not be the strongest.

Good luck & feel free to clarify, I’m happy to help!

ignore this but I’m leaving it for posterity. I get what robin’s saying now & this probably doesn’t address what you actually want to do.

By the way, I get the same result here.

The sample bit of the language has a “cutoff” argument… and if you put the get[:t] as an argument after your sample call, it appears to work as expected.

Check it out:

use_bpm 110

live_loop :control2 do
  set :t, [70,80,90].tick
  sleep 8
end

live_loop :drums1 do
  sample :loop_amen, beat_stretch: 4, cutoff: get[:t]
  sleep 2
  c = get[:t]
  puts c
  
  sleep 2
  
  3.times do
    sample :loop_amen, beat_stretch: 4, cutoff: [get[:c],100].tick, cutoff_slide: 2
    sleep 4
  end
end

this is especially wrong

It actually makes me wonder if there might be something in the guts of the system related to how samples are called/looped vs the way a synth functions. I know synths are routed to supercollider, but a lot of the technical side is pretty significantly over my head here. I am sure @robin.newman is right but I don’t quite follow either, so here’s my likely hack solution.
(preface: take this with major grain of salt). In trying to make some insane sounds I’ve realized that, at times, sonicpi will breeze over certain things that should change, but it may not look at them because it thinks it already knows what’s in the loop. (/salt)

Oops. Sorry @ianridd There was an extraneous . after the 90 in the OSC send program. Also I hadn’t initialised :t in the first one. Both now edited. I’ve copied the two programs into separate buffers from the post and checked they do work.

Ok. Thanks to everyone who participated. I have achieved some limited success. Though I am not finished yet.

I am realizing that this conversation has been had many many times… which I expected. I searched for the answer to my question. I appreciate the patience that people have on here to re-state things for us beginners.

For anyone foolish enough to follow in my shoes, heres the code I eventually got into Beta form.

Note - if youre new to OSC, like I was… you will need to enable OSC in your preferences. Under MIDI settings. can’t miss it.

These two buffers will control the cutoff frequency of an lpf with a sine wave function. I love this.

BUT… if I command-R (re-run) the “part I”, the filter control will stop working. As has been stated so many times before, this will create a new wrapper for the fx and you can no longer control the fx. This is a big problem. I still am unclear how I am going to get all of this working since live coding requires near-constant re-running of the code. So if anyone can tell me how I can overcome that, I’d be grateful. I can’t practically use an arrangement that requires me to run it only one time.

Thanks everyone.

##| two buffer solution
##| part I

#run in first buffer
use_osc "localhost",4560

use_bpm 110
set :t,100

live_loop :control2 do
  use_real_time
  n = sync "/osc*/cutoff"
  set :t,n[0]
end

with_fx :rlpf, cutoff: get[:t], cutoff_slide: 0 do |lpf|
  live_loop :drums1 do
    sample :loop_amen, beat_stretch: 4
    sleep 4
  end
  
  # made a second loop just for control command
  # wanted the control to be uopdating every 16th
  # drum loop needed to cycle every measure
  live_loop :control1 do
    control lpf, cutoff: get[:t]
    puts get[:t]
    sleep 0.25
  end
end
##| two buffer solution
##| part II

use_osc "localhost",4560

# to use the sine function in line 11, you will have to map the output
# rIn provides the upper and lower limits of the input ofthe map function
# (the sine function output)
# rOut provides the upper and lower limits of the output of the map function

rIn =  [-1.0, 1.0]
rOut = [60, 120]

live_loop :LFO1 do
  #takes the output of the sine function and maps it from 60 to 120 to run
  # the cutoff frequency
  cutoffFreq = rMap(rIn, rOut, Math::sin(vt/3))
  #sends that value to osc
  osc "/cutoff", cutoffFreq
  # repeats ever sixteenth note
  sleep 0.25
end

# a mapping function
define :rMap do |rIn, rOut, v|
  dOut = rOut[1] - rOut[0]
  dIn = rIn[1] - rIn[0]
  dOut / dIn * (v - rIn[0]) + rOut[0]
end
1 Like