Home › Forums › General › Programming › LUA Scripts in Positive Feedback Loop
- This topic has 19 replies, 5 voices, and was last updated 3 years, 10 months ago by dnaldoog.
-
AuthorPosts
-
June 20, 2020 at 2:38 pm #118836
A constant headache I have is where I get unintentional LUA Script triggering.
When updating a Modulator you can use setModulatorValue(variable, false, false, false) to inhibit any MIDI CC or SysEx that is set in the MIDI Section of the Modulator or (variable, false, true, false) if you want the the Modulator to generate a MIDI Message, and this is really handy.
But if you have luaModulatorValueChange set to trigger a LUA Script, I’ve yet to find a way of inhibiting it from running if I don’t want it to when that Modulator Value Changes. So I’m constantly running into issues where one script triggers another, etc, giving very undesirable consequences.
Am I missing something obvious or does anyone have any cunning strategy for dealing with this?
June 20, 2020 at 3:30 pm #118837Hi Spiffo,
Use
setValue(variable,false)
June 20, 2020 at 5:12 pm #118839So just to clarify then, if I substitute:
setModulatorValue(variable, false, false, false)
for
setValue(variable, false)
No MIDI Message will be sent from the Modulator and no LUA Script will be triggered either?
@param newValue the value to set
@param force force value change
*/
void setValue(const int newValue, const bool force=false, const bool mute=false);
void setValue(const int newValue, const bool force=false);I lifted the above from github but it doesn’t seem to shed much light on the subject, force what, mute what exactly?
I think I need to do some testing.- This reply was modified 3 years, 10 months ago by spiffo.
June 20, 2020 at 8:34 pm #118843So, you have a script that intentionally changes the value of a modulator but that unintentionally triggers a lua script, activated by that modulator when the value of that modulator changes?
I think it’s a matter of avoiding this design unless Atom can imagine and build a method in ctrlr that makes that in some cases the luaModulatorValueChange can be turned off. A new lua/juce command?
June 20, 2020 at 8:46 pm #118844yep, I was kinda wondering if someone would say something like that, at the time I could not thnk of another way to do it.
I’ve finished testing the setValue(variable, boolean, boolean) and here are my results:
setValue(var, force, mute)
mute = if true MIDI never sent, if false MIDI is sent only if the Modulator changes value
force = if true LUA Script always runs, if false LUA script only runs if Modulator changes valueSo basically you can mute the MIDI going out but you can NOT stop the LUA, if the Mod changes value it’s going to get triggered!
June 20, 2020 at 9:09 pm #118845And some quick testing of setModulatorValue(var, boolean, boolean, boolean)
setModulatorValue(var, vst, midi, ui)
vst & ui appear to do nothing, I think that is well known?
midi if set to true the panel sends a MIDI Message whether the Modulator changes value or not
midi if set to false the panel does NOT send a midi message whether the Modulator changes value or notSo my conclusion is that dnaldoog is correct, I am better off using setValue, it gives a much better range of control over what happens, but it still won’t stop those LUA scripts from running if the Mod changes value 🙁
Thanks, guys!
- This reply was modified 3 years, 10 months ago by spiffo.
June 21, 2020 at 12:27 am #118847Hi Spiffo!
Use the source
I think this is where you can use that mysterious third parameter to a callback function ‘source’ – I haven’t tested this and it may take some experimenting, but something like:
if source == 2 then --... do something elseif source == 4 --... do something else end -- --------------------------------------------------------- --[[ https://github.com/RomanKubiak/ctrlr/blob/de28dc3ad3591a5832f1e38ce8adabc9369b1011/Source/Lua/CtrlrLuaModulator.cpp value("initialValue", 0), value("changedByHost", 1), value("changedByMidiIn", 2), value("changedByMidiController", 3), value("changedByGUI", 4), value("changedByLua", 5), value("changedByProgram", 6), value("changedByLink", 7), value("changeByUnknown", 8) --]]
June 21, 2020 at 12:31 am #118848Also see this post regarding setModulatorValue vs setValue
ctrlr.org/forums/topic/setmodulatorvalue-and-friends/
June 21, 2020 at 1:21 am #118849
You could also have a global toggle in the midiReceived function
in an init function when panel loadsmyGlobalBlock=false
then:
midiRecieved=function(--[[ CtrlrMidiMessage --]] midi) myGlobalBlock=true -- run midi received code --uiSlider will be triggered but code not run myLfo:setValue(val,false) -- could also set to true here myGlobalBlock=false -- reset back to false end
and in the callback function attached to the uiSlider myLfo function:
if myGlobalBlock==false then -- run code end
Again untested pseudo code, but something to consider and play around with!
?
June 21, 2020 at 1:33 pm #118854Use the source
I think this is where you can use that mysterious third parameter to a callback function ‘source’ – I haven’t tested this and it may take some experimenting, but something like:
I’ve been staring at this stuff, but not being a coder by trade, actually an Electronics Engineer so much happier with hardware, I can’t make that much sense of it:
https://github.com/RomanKubiak/ctrlr/blob/master/Source/Lua/CtrlrLuaModulator.cpp
processor.setValueGeneric (CtrlrModulatorValue (newValue, CtrlrModulatorValue::changedByLua), force, false);
The line above, does that mean that when the Modulator Value gets set it also records that it was changedbyLUA?
value(“changedByLua”, 5),
That line above is at the bottom of the page, so does that mean that 5 is passed into the function?
If you aren’t a coder, this reference material is difficult to interpret for the newbie.
June 21, 2020 at 2:21 pm #118856Hi Spiffo,
I have tried to unravel what’s going on there, but it is confusing. I think I would need to have a deeper understanding of C++ than I do to really know what’s going on, but what I meant by value(“changedByLua”,5) is that if you change a modulator using lua ie from a function triggered by an incoming midi message or another modulator you will notice ‘source’ passes in 5. If the user adjusts the dial, you will see 4 passed in.
I discovered this and have used it in the C-PLG150-AN, but have not really read about it on the forums. I’m sure it would be referred to somewhere else though. ctrlr.org/c-plg150-an/
So if you had a function like:
runsource = function(--[[ CtrlrModulator --]] mod, --[[ number --]] value, --[[ number --]] source) panel:getLabel("d"):setText(""..source) end
… all you would need to do to filter out non-user GUI changes to the modulator:
runsource = function(--[[ CtrlrModulator --]] mod, --[[ number --]] value, --[[ number --]] source) if source == 4 then --run the code end end
See attached panel.
- This reply was modified 3 years, 10 months ago by dnaldoog. Reason: reworded confusing text
Attachments:
You must be logged in to view attached files.June 21, 2020 at 6:17 pm #118863I did never manage to get these flags working correctly in all cases. In particular, Lua scripts are always triggered in most cases. Also, on instances there is a problem on startup. It will trigger a load of modulators on startup sending a big mess to midi-out. Only way for me: use toggle variabal as dnaldoog suggested. I use it like this:
if doNotSend then return end
This is short and painless.. more or less.
June 22, 2020 at 10:41 am #118867The “source” parameter is working fine.
To prevent Lua functions to be fired you indeed need to set a boolean, add a test at the beginning of all your “OnChange” methods, launch a timer to reset the boolean after all methods have gone through the test.
I’m using this for loading data in all modulators from a file.
Before starting the load, I set bLoadingProgram=true. In each OnChange methods i’m testing if bLoadingProgram == true and doing a direct return in that case.
All methods will be triggered due to the load of each parameters.
I also start a timer at load. Set it to enough time to have all your methods processed but not too much.
When stopping the timer, reset the boolean to false so your methods are executed nicely on manual turn of a button.June 22, 2020 at 2:12 pm #118870runsource = function(–[[ CtrlrModulator –]] mod, –[[ number –]] value, –[[ number –]] source)
Is that just an alternatively way of writing:
function runsource(mod,value,source) ?
I’ve just tried and both ways seem to work, so this could definitely be a way forward!
Also I thought maybe you could just pass the source into the function like:
function runsource(source) but you can’t it seems, you need to do the full (mod,value,source) as they all appear to be passed into the function it that particular order.To prevent Lua functions to be fired you indeed need to set a boolean, add a test at the beginning of all your “OnChange” methods, launch a timer to reset the boolean after all methods have gone through the test.
I’m using this for loading data in all modulators from a file.
Before starting the load, I set bLoadingProgram=true. In each OnChange methods i’m testing if bLoadingProgram == true and doing a direct return in that case.
All methods will be triggered due to the load of each parameters.
I also start a timer at load. Set it to enough time to have all your methods processed but not too much.
When stopping the timer, reset the boolean to false so your methods are executed nicely on manual turn of a button.Yep that could be another way, I already have a Test & Timer running at startup to stop any unnecessary activity but another Test and another Timer for stopping certain scripts from running when not needed would be another way forward.
“The more you learn, the more you realise how little you know”
June 22, 2020 at 2:43 pm #118873Hi Spiffo,
This is taken from the lua manual PIL lua.org/pil/6.html
A somewhat difficult notion in Lua is that functions, like all other values, are anonymous; they do not have names. When we talk about a function name, say print, we are actually talking about a variable that holds that function.
If functions are values, are there any expressions that create functions? Yes. In fact, the usual way to write a function in Lua, likefunction foo (x) return 2*x end
is just an instance of what we call syntactic sugar; in other words, it is just a pretty way to write
foo = function (x) return 2*x end
… so in other words either format is fine!
Yes you must include (mod,value,source) – It may be possible to just include function(mod) if you only use ‘mod’ in the function, or function(mod,value) but there’s no good reason for doing that that I can imagine.
Adapting Possemo’s code, you could simply do something like:
if source ~= 4 then return end
at the head of each function you want to block.
June 22, 2020 at 2:48 pm #118874So, you have a script that intentionally changes the value of a modulator but that you don’t want to unintentionally trigger a lua script, activated by that modulator when the value of that modulator changes.
For this purpose you have written another Lua script that sorts out the source of the value change.In my eyes the problem is this: if the modulatorValue change is not allowed to trigger a Lua script, how is it possible then, when the modulator becomes the command to change value, to trigger a lua script that sorts out the source of his value change to block another Lua script, triggered by that same value change?
So the Lua script to block another lua script when the modulator changes value must be triggered by the modulator BEFORE the command to change value arrives! If not so, the script is blocked by itself.
But how can this be done?June 22, 2020 at 3:19 pm #118877So, you have a script that intentionally changes the value of a modulator but that you don’t want to unintentionally trigger a lua script, activated by that modulator when the value of that modulator changes.
For this purpose you have written another Lua script that sorts out the source of the value change.Well something like that but not exactly. My original post was just to see what methods people were using to block LUA Scripts from running when they don’t need to.
And everyone has been very helpful and I now have essentially 3 methods of attack:
1 Use setValue instead of setModulatorValue, you can stop LUA Scripts triggering if the Modulator doesn’t change value
2 Use Variables and Timers to stop any acivity for a certain amount of time
3 Pass the Mod, value & source into the function and use the source in an if statement to determine whether the script runs or notJune 22, 2020 at 3:31 pm #118878Hi Samoht – Not sure I follow, but the idea is to set up some sort of way to detect whether the user changed a value by moving the ‘dial’ or pressing a button or whether the uiSlider/uiButton etc is being modified by lua, for example an incoming midi message that updates the gui.
So the idea is that the parameter ‘source’ passes in an integer value of 4 if the user moved the control, otherwise another number (usually 5?).
Personally I have only used this method once, because I only discovered it towards the end of coding the last panel I did.
What I usually do is have a ‘global’ variable that is initialised to let’s say
blockMe=false
on init (when the panel loads). When a midi message is received and processed by a function or another control changes the modulator, whose lua function we are trying to disable, that other function will temporarily ‘switch’ the global variable toblockMe=true
so when the modulator you want to block is changed it won’t run the lua code it normally runs. So if you have at the beginning of the function you want to block a testif blockMe then return end
the lua function you want to block will not run. You then need to makeblockMe=false
at the end of any function that temporarily writesblockMe=true
. You can do this with timers as Goodweather points out, but this method should work in theory.If the modulator you want to block just sends MIDI via lua you could also try:
panel:setPropertyInt("panelMidiPauseOut",1)
and then
panel:setPropertyInt("panelMidiPauseOut",0)
in that modifying function.
- This reply was modified 3 years, 10 months ago by dnaldoog.
June 23, 2020 at 9:46 am #118883Hi Dnaldoog,
I’ve found there is much to learn in your ‘Roland JD-990 Bulk Dump utility’ panel.
In this panel you are using ‘source’ as argument in the call of several functions (prepareFileSave, myResetProgram, uploadSysex). Would you like to explain how precisely it works in this panel?June 23, 2020 at 10:52 am #118884Hi Samoht,
Thank you for looking at that panel. If I could do it again, I would do it differently.
Those particular functions don’t use the ‘source’ parameter. It is just generated as a template when you attach a function to a modulator in Ctrlr called when the modulator value changes.
Where I do use it is in a function selector_change in the panel C-PLG-150-AN ctrlr.org/c-plg150-an although I’ve forgotten why 🙁 Something to do with changing the arguments to a class constructor there. That panel is quite complex, at least for me, so simpler panels like the ‘Roland JD-990 Bulk Dump utility’ are probably much easier to sift through!
-
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.