Open the-drunk-coder opened 8 years ago
This is intended. The definition of the live loop is modified at runtime, so changing an effect only works inside the loop.
hzulla is right here. For reasons of efficiency with_fx
is only evaluated once where possible (i.e. we don't recreate it if it already exists in that thread). There's a little bit in the Tutorial section about loops and fx (6.2 FX in Practice) but maybe we should also write something into the docs for with_fx
to make this clearer.
If you want to understand what's happening with the body of live_loop
Sam gives quite a good overview of the implementation in his StrangeLoop talk https://youtu.be/YlRTTzlhquo?t=22m36s If you have 10 minutes or so to watch that video it will explain better than I can :)
It's currently intended, although I spent quite a while last year thinking about how to support the 'obvious' behaviour in a sensible way (I couldn't figure it out).
The real issue is that with_fx
affects the current thread and any threads created or code run inside its block. The first time you run a with_fx
block containing a live_loop
a new thread is created for the live_loop
which then works with that FX. However, the second time, no new threads are created within the with_fx
block as the live_loop
already exists. This means that a new FX is created but is instantly removed as it is affecting no synths or threads.
I'll see if I can find some more time to think about a sensible 'fix' but for now it's intended behaviour.
Hmm ok i'd say a good fix for now would be to document it, as from the documentation i wouldn't have guessed this is the intended behaviour at all ... from the user standpoint, it doesn't really feel like creating something new, but rather changing a parameter on an already running effect ...
Staying with the "guitar effects" analogy employed by the documentation, why would i have to stop playing the guitar to turn a knob (assuming i have an expression pedal or agile toes, that is).
But i can also see that it's hard to explain to somebody who doesn't know the internals ...
Well, the live loop is only replaced with the new code once the old code of the loop has finished its current run. Does that help as an explanation?
Well, i more or less understand what's going on, but the explanations have been really technical so far, so they probably wouldn't really help technically less proficient users ...
Plus it's still counter-intuitive ... from what i got so far, it's the only part of Sonic Pi where a parameter change doesn't have an effect when re-running the code.
I mean, explaining this with a simple (hardware-) analogy would be like: "Ok, so you're running your synth through this delay. To change the delay time, please stop your synth, turn off the power, change the parameter, and re-start everything"
I think, as workaround, i can live with using the "loop in a live loop" approach, like:
live_loop :foo do
with_fx :reverb, mix:0.2 do
8.times do
play 70
sleep 0.5
end
end
end
A little less reactive, but ok ...
The thing to understand is that with_fx
always creates a new FX synth. So in your original example, every time you pressed run, you were creating a new :bitcrusher
FX and not modifying the old one.
Your 'workaround' is actually the recommended way of working with FX in Sonic Pi and is the best way to live code them. Your pattern is even supported by the reps:
opt which removes the need to add an explicit iteration:
live_loop :foo do
with_fx :reverb, mix:0.2, reps: 8 do
play 70
sleep 0.5
end
end
I'll definitely improve the docs though - thanks for bringing this to my attention :-)
Affected version: Sonic Pi v2.8.0-dev-a3737, running on Arch Linux (x64)
I can't tell if this is intended behaviour, but when i try to wrap some effects around a _liveloop, change some parameters, and re-run the buffer (that is, without completely stopping in between), the effects aren't reacting to the change.
Example:
If i want to change the bitrate here, i have to stop the run first (using Stop or Alt-R), then start it again. Otherwise, there'll be no change at all ...
It works fine if the effect is specified within the live loop. It also works using a "normal" loop, instead of a _liveloop.