LUA Scripts in Positive Feedback Loop

Home Forums General Programming LUA Scripts in Positive Feedback Loop

Viewing 20 posts - 1 through 20 (of 20 total)
  • Author
    Posts
  • #118836
    spiffo
    Participant
      • Topics: 12
      • Replies: 38
      • Total: 50

      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?

      #118837
      dnaldoog
      Participant
        • Topics: 4
        • Replies: 480
        • Total: 484
        • ★★

        Hi Spiffo,

        Use setValue(variable,false)

        #118839
        spiffo
        Participant
          • Topics: 12
          • Replies: 38
          • Total: 50

          So 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.
          #118843
          samoht
          Participant
            • Topics: 1
            • Replies: 54
            • Total: 55

            So, 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?

            #118844
            spiffo
            Participant
              • Topics: 12
              • Replies: 38
              • Total: 50

              yep, 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 value

              So 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!

              #118845
              spiffo
              Participant
                • Topics: 12
                • Replies: 38
                • Total: 50

                And 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 not

                So 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.
                #118847
                dnaldoog
                Participant
                  • Topics: 4
                  • Replies: 480
                  • Total: 484
                  • ★★

                  Hi 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)
                  --]]
                  
                  #118848
                  dnaldoog
                  Participant
                    • Topics: 4
                    • Replies: 480
                    • Total: 484
                    • ★★

                    Also see this post regarding setModulatorValue vs setValue

                    ctrlr.org/forums/topic/setmodulatorvalue-and-friends/

                    #118849
                    dnaldoog
                    Participant
                      • Topics: 4
                      • Replies: 480
                      • Total: 484
                      • ★★


                      You could also have a global toggle in the midiReceived function
                      in an init function when panel loads

                      myGlobalBlock=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!

                      ?

                      • This reply was modified 3 years, 10 months ago by dnaldoog.
                      • This reply was modified 3 years, 10 months ago by dnaldoog.
                      #118854
                      spiffo
                      Participant
                        • Topics: 12
                        • Replies: 38
                        • Total: 50

                        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:

                        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.

                        #118856
                        dnaldoog
                        Participant
                          • Topics: 4
                          • Replies: 480
                          • Total: 484
                          • ★★

                          Hi 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.
                          #118863
                          Possemo
                          Participant
                            • Topics: 14
                            • Replies: 638
                            • Total: 652
                            • ★★★

                            I 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.

                            #118867
                            goodweather
                            Participant
                              • Topics: 45
                              • Replies: 550
                              • Total: 595
                              • ★★★

                              The “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.

                              #118870
                              spiffo
                              Participant
                                • Topics: 12
                                • Replies: 38
                                • Total: 50

                                runsource = 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”

                                • This reply was modified 3 years, 10 months ago by spiffo.
                                • This reply was modified 3 years, 10 months ago by spiffo.
                                #118873
                                dnaldoog
                                Participant
                                  • Topics: 4
                                  • Replies: 480
                                  • Total: 484
                                  • ★★

                                  Hi 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, like

                                  function 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.

                                  #118874
                                  samoht
                                  Participant
                                    • Topics: 1
                                    • Replies: 54
                                    • Total: 55

                                    So, 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?

                                    • This reply was modified 3 years, 10 months ago by samoht.
                                    • This reply was modified 3 years, 10 months ago by samoht.
                                    #118877
                                    spiffo
                                    Participant
                                      • Topics: 12
                                      • Replies: 38
                                      • Total: 50

                                      So, 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 not

                                      #118878
                                      dnaldoog
                                      Participant
                                        • Topics: 4
                                        • Replies: 480
                                        • Total: 484
                                        • ★★

                                        Hi 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 to blockMe=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 test if blockMe then return end the lua function you want to block will not run. You then need to make blockMe=false at the end of any function that temporarily writes blockMe=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.
                                        #118883
                                        samoht
                                        Participant
                                          • Topics: 1
                                          • Replies: 54
                                          • Total: 55

                                          Hi 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?

                                          #118884
                                          dnaldoog
                                          Participant
                                            • Topics: 4
                                            • Replies: 480
                                            • Total: 484
                                            • ★★

                                            Hi 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!

                                          Viewing 20 posts - 1 through 20 (of 20 total)
                                          • The forum ‘Programming’ is closed to new topics and replies.
                                          There is currently 0 users and 106 guests online
                                          No users are currently active
                                          Forum Statistics
                                          Threads: 2,495, Posts: 17,374, Members: 77,605
                                          Most users ever online was 12 on January 22, 2019 3:47 pm
                                          Ctrlr