Hi!
I want to control the values of my master FX using code. I managed to do it using a MIDI mapping and that works fine. As coder I’m firm with code and threads, still, I could not manage to solve my problem using this forum. Here is what I’ve got:
with_fx :lpf, cutoff: 127 do |lpf|
set :lpf, lpf
live_loop :foo do
The LowPass Filter wraps around everything. Now on the top level I’ve got this MIDI mapping and it works like a breeze, using control and get I can simply update the LowPass cutoff value:
live_loop :midi_debug do
use_real_time
data = sync "/midi:grid:1/control_change"
control get(:lpf), cutoff: 127 - data[1] if data[0] == 37
BUT when I remove the MIDI mapping and try to control the cutoff value e.g. in a live_loop or in_thread it only works the first time, after changing the value once the reference returned by get seems to be messed up:
live_loop :ctrl1 do
control get(:hpf), cutoff: 0
sleep 0.0125
end
Changing the cutoff in the code above works once, e.g. I can set it to 80 and it is applied once, but setting it back to 0 again does not work. When I try to debug using puts get(:hpf) I can see that the reference changed. Not sure why. Thought that set and get where thread safe.
Taking that one step further I want of course to e.g. have a smooth line automation or and LFO mapped to the value (instead of hard coding it).
use_debug false
use_synth :tb303
with_fx :lpf, cutoff: 100 do |fx1|
with_fx :hpf,cutoff: 30 do |fx2|
set :fx1,fx1;set:fx2,fx2 #only allow this to execute ONCE: use comment
notes=scale(:e2, :major,num_octaves: 2).mirror
live_loop :play_notes do
notes.length.times do |i|
play notes[i],release: 0.2
sleep 0.2
end
end
end
end
control get(:fx1),cutoff: 100
control get(:fx2),cutoff: 30
What you have to to do is to make sure that the references to the fx calls are stored only on the FIRST run. YOu then comment out the line indicated and you can rerun having altered the valuies in the last two lines to adjust the filters.
You need to reeanble the line that stores the pointers each time you press STOP and then want to run again.
Essentially a new fxs wrapper is generated each time you press run. If you store (and use) the first value it uses the innermost wrappwer which will affect ths sound,. The additional ones are geeranted but not used. It is kludgy but it works.
Thansk a lot! That did the trick, played around using a variable fx_alive to maintain the state. That removes the issue that you have to remember to comment it out, and if you ever need to re-initialize one can comment in # set :fx_alive, nil. In my tests it worked flawlessly.
# set :fx_alive, nil
with_fx :reverb, room: 1, mix: 0 do |reverb|
with_fx :bitcrusher, sample_rate: 3000, bits: 8, mix: 0 do |bitcrusher|
with_fx :hpf, cutoff: 0 do |hpf|
with_fx :lpf, cutoff: 127 do |lpf|
with_fx :ixi_techno, mix: 0 do |ixi_techno|
if get(:fx_alive) == nil
set :fx_alive, true
set :reverb, reverb
set :bitcrusher, bitcrusher
set :hpf, hpf
set :lpf, lpf
set :ixi_techno, ixi_techno
end