# "Launch" fx at midi\_cc

**URL:** <https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995>\
**Category:** \[P\] Patreon Support\
**Created:** [April 21, 2018, 9:42am UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995 "2018-04-21T09:42:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![sanju0](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/sanju0/32/1610_2.png) [@sanju0](https://in-thread.sonic-pi.net/u/sanju0)\
**Post date:** [April 21, 2018, 9:42am UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/1 "2018-04-21T09:42:06Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [April 21, 2018, 2:47pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/2 "2018-04-21T14:47:11Z")

</div>

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.

```ruby

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

```

---

<div class="post-metadata">

**Author:** ![sanju0](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/sanju0/32/1610_2.png) [@sanju0](https://in-thread.sonic-pi.net/u/sanju0)\
**Post date:** [April 21, 2018, 3:44pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/3 "2018-04-21T15:44:26Z")

</div>

Thanks for your reply Robin!

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

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [April 21, 2018, 4:52pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/4 "2018-04-21T16:52:27Z")

</div>

I can stop and start a live\_loop by putting it inside a function definition, (see [here](http://in-thread.sonic-pi.net/t/something-wrong-using-nilclass/975/20?u=robin.newman) 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.

---

<div class="post-metadata">

**Author:** ![sanju0](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/sanju0/32/1610_2.png) [@sanju0](https://in-thread.sonic-pi.net/u/sanju0)\
**Post date:** [April 21, 2018, 5:05pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/5 "2018-04-21T17:05:22Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![ds604](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/ds604/32/422_2.png) [@ds604](https://in-thread.sonic-pi.net/u/ds604)\
**Post date:** [April 21, 2018, 5:22pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/6 "2018-04-21T17:22:20Z")

</div>

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

> **[const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)**
>
> Constants are block-scoped, much like variables defined using the let keyword. The value of a constant can't be changed through reassignment, and it can't be redeclared.

---

<div class="post-metadata">

**Author:** ![sanju0](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/sanju0/32/1610_2.png) [@sanju0](https://in-thread.sonic-pi.net/u/sanju0)\
**Post date:** [April 21, 2018, 6:05pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/7 "2018-04-21T18:05:34Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![sanju0](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/sanju0/32/1610_2.png) [@sanju0](https://in-thread.sonic-pi.net/u/sanju0)\
**Post date:** [April 21, 2018, 6:26pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/8 "2018-04-21T18:26:12Z")

</div>

Awww I don’t think it works for me 😣  
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

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [April 21, 2018, 6:28pm UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/9 "2018-04-21T18:28:21Z")

</div>

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](http://in-thread.sonic-pi.net/t/osc-loop-machine-makeymakey/850/20?u=robin.newman) where I used a generic definition that could be used several times.

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [April 22, 2018, 10:48am UTC](https://in-thread.sonic-pi.net/t/launch-fx-at-midi-cc/995/10 "2018-04-22T10:48:34Z")

</div>

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.

```ruby
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

```
