"Launch" fx at midi_cc

Hi,

I’d like to activate an fx only when a certain button of my midi interface is pressed. For that, I’ve written this code

defonce :effects do
  {
    'fx_114'=> nil
  }
end

live_loop :fx do
  use_real_time
  n, val = sync "/midi/launch_control/0/14/control_change"
  control effects['fx_114'], mix: val/127
end


with_fx :slicer, mix: 0 do |fx_114|
  effects['fx_114']=fx_114
  live_loop :a do
    sample :ambi_choir, beat_stretch: 4
    sleep 4
  end
  live_loop :b, sync: :a do
    stop
    sample :ambi_drone, beat_stretch: 4
    sleep 4
  end
end

What I’m trying to do here is storing a reference of the fx inside effects[fx_114] and call it to activate/deactivate in the :fx live_loop. If I run this code, its working OK for the :a live_loop, but when I comment the stop command inside the :b live_loop and run it, the fx affects only the sound inside :b, and the a: live_loop loses it.

If I run both live_loops (:a and :b) from the beginnig it’s working too, but I’d like to be able to stop/run live_loops without loosing the effect.

Any ideas on this?
Thanks

I had a play with this today and tried various solutions with varying degrees of success. In the end I decided on leaving the live loops running all the time, but switching their volume to 0 when not required. By syncing changes to the start of loop a you can simulate stopping and restarting loop b. Or you can just change the volume at any time.

I found it more convenient to experiment using OSC to give the external inputs, but this is easily changed back to midi_cc inputs.

Here is what I came up with. I used TouchOSC with three toggle switches, running on a tablet at 192.168.1.240 These switches send data 1 when turned on and 0 when turned off
I used time_state values to pass data to the loops controlling the mix and the volumes.


set :mval,0 #set initial mix value
set :vola,0
set :volb,0

#initialise virtual toggle switches on TouchOSC
osc_send "192.168.1.240",9000, "/1/toggle1",1
osc_send "192.168.1.240",9000, "/1/toggle2",1
osc_send "192.168.1.240",9000, "/1/toggle4",0

use_osc "localhost",4559 #send initial OSC messages to Sonic Pi
osc "/1/toggle1",1 #turn on live_loop a
osc "/1/toggle2",1 #turn on live_loop b
osc "/1/toggle4",0 #turn off mix on slicer



with_fx :slicer,mix: 0 do |m1| #applied to all enclosed live loops
  in_thread do
    loop do
      control m1,mix: get(:mval)
      sleep 0.05
    end
  end
  
  with_fx :level, amp: 1 do |vol| #control volume of live_loopa
    in_thread do
      loop do
        control vol,amp: get(:vola)
        sleep 0.05
      end
    end
    live_loop :a do
      sample :ambi_choir, beat_stretch: 4
      sleep 4
    end #live_loop
  end #fx level a
  
  with_fx :level, amp: 1 do |vol| #control volume of live_loop b
    in_thread do
      loop do
        control vol,amp: get(:volb)
        sleep 0.05
      end
    end
    live_loop :b,sync: :a do
      sample :ambi_drone, beat_stretch: 4
      sleep 4
    end #live_loop
  end #fx level b
  
  
end #fx slicer



live_loop :getVol1 do #control 2nd live_loop on/off
  use_real_time
  b= sync "/osc/1/toggle1" #returns 0 or 1
  if b[0]==1
    set :vola,1
  else
    set :vola,0
  end
  puts "vola is #{get(:vola)}"
end


live_loop :getVol2 do #control 2nd live_loop on/off
  use_real_time
  b= sync "/osc/1/toggle2" #returns 0 or 1
  sync :a #change at start of loop a #omit if you want to change immediately
  if b[0]==1
    set :volb,1
  else
    set :volb,0
  end
  puts "volb is #{get(:volb)}"
end


live_loop :getMix do #control fx mix
  use_real_time
  b = sync "/osc/1/toggle4" #returns 0 or 1
  set :mval,b[0]
  puts "mix value #{get(:mval)}"
end
1 Like

Thanks for your reply Robin!

So… I guess it is something that can’t be done stopping and running threads?

I can stop and start a live_loop by putting it inside a function definition, (see here for an example ) and I managed to do this with your program embedded in an fx :slicer. However, with two live_loops the slicing phase was not synced for the two live_loops.

1 Like

OK. I can live with no synced phase :slight_smile: I’ll check that code.
Thanks!

sorry for OT, but i just looked up “defonce,” since i hadn’t seen that before. do you know if it’s the same as using “const” instead of “var” in javascript? it sounds like it from the description, but i wasn’t sure if there’s some subtle difference or something

Javascript const are read-only variables.
In Sonic Pi, defonce is used for defining values only on the first execution of the code, to avoid the reset of the variables each time you re-run it.

Awww I don’t think it works for me :persevere:
Having two live_loops inside of a define means that both are played or both are stopped at the same time. I’d like to be able start/stop them individually.
Thank you very much anyway, Robin

I did it using two separate defines, one for each live loop. I have used the technique with several live loops starting and stopping in this program where I used a generic definition that could be used several times.

1 Like

here is a version using two switchable live loops with fx slicer applied.
It works, except that the phase of the slcier is not synced between the two loops, unless you uncomment the line indicated in live_loop :control2. In that case it takes two passes of loop a before loop starts, but the slicer is synced between them.

set :mval,0
#send osc to intialise toggle switcheds on TouchOSC
osc_send "192.168.1.240",9000,"/1/toggle1",1
osc_send "192.168.1.240",9000,"/1/toggle2",1
osc_send "192.168.1.240",9000,"/1/toggle4",0
use_osc "localhost",4559
#end osc to start livel_loop :a and :b
osc "/1/toggle1",1
osc "/1/toggle2",1
define :doLoop1 do
  set :go1,true
  
  with_fx :slicer, mix: 0 do |m1| #control volume of live_loopa
    in_thread do
      loop do
        control m1,mix: get(:mval)
        sleep 0.05
      end
    end
    live_loop :a do
      sample :ambi_choir, beat_stretch: 4
      sleep 4
      stop if get(:go1)==false
    end #live_loop
  end
end

define :doLoop2 do
  set :go2,true
  
  with_fx :slicer, amp: 1 do |m2| #control volume of live_loopa
    in_thread do
      loop do
        control m2,mix: get(:mval)
        sleep 0.05
      end
    end
    live_loop :b,sync: :a do
      sample :ambi_drone, beat_stretch: 4
      sleep 4
      stop if get(:go2)==false
    end #live_loop
  end
end


live_loop :control1 do
  use_real_time
  b = sync "/osc/1/toggle1"
  if b[0]==1
    doLoop1
  else
    set :go1,false
  end
end

live_loop :control2 do
  use_real_time
  b = sync "/osc/1/toggle2"
  if b[0]==1
    #sync :a #uncomment to sync slicer pulsesd, but delays turn on one cuycle
    doLoop2
  else
    set :go2,false
  end
end

live_loop :controlSlicer do
  use_real_time
  b = sync "/osc/1/toggle4"
  set :mval,b[0]
end
1 Like