Midi Value LUA calculation method in Ctrlr [Two’s complement, Frac Table]

Home Forums General Programming Midi Value LUA calculation method in Ctrlr [Two’s complement, Frac Table]

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #118215
    damien
    Participant
      • Topics: 15
      • Replies: 62
      • Total: 77

      Hi Ctrlr fellows,

      I am working on a script that dynamically assign Parameters to Slider Modulators in a 30 shared knobs bank.

      The min/max value changes, the visible name as well obviously, and the value calculation changes too 🙁 This is just a nightmare to be honest, Since there’s 59 algos and each have between 5 to 20 different parameters.

      For the Same Modulator depending on the Algorithm used by the unit the calculation method must change and this is where I can’t figure out the appropriate way to tell LUA to do it and how to decode the received/sent value.

      For example :

      UAParam02 is a slider modulator

      For the algo Hall reverb:

      	UAParamValue02 = midiMessage:getLuaData():getByte(XX) --requires decoding 16bits of 2 bytes
      
      	UAParam02 = panel:getModulatorByName("UAParam02")
      	UAParam02:setProperty("componentVisibility", 1, false)
      	UAParam02:getComponent():setProperty ("componentVisibleName", "Predelay 
Time", true)
              -- Calculation midi value method is 
      	UAParam02:getComponent():setProperty ("uiSliderMin", 0, true)
      	UAParam02:getComponent():setProperty("uiSliderMax", 450, true)
      	UAParam02:setModulatorValue(UAParamValue02, false, false, false)
      

      And for another algo (MultiTap Delay) the same knob must have a different behaviour

      	
      	UAParamValue02 = midiMessage:getLuaData():getByte(XX) 
      	UAParam02 = panel:getModulatorByName("UAParam02")
      	UAParam02:setProperty("componentVisibility", 1, false)
      	UAParam02:getComponent():setProperty ("componentVisibleName", "Position 
Balance 3", true)
      	-- calculation midi value method is "Signed Frac" with two's complement
              UAParam02:getComponent():setProperty ("uiSliderMin", -128, true)
      	UAParam02:getComponent():setProperty("uiSliderMax", 127, true)
      	UAParam02:setModulatorValue(UAParamValue20, false, false, false)
      

      The Ensoniq DP4 I’m working on has 6 calculation methods:

      – Positive Integer: with value ranging between 0 and 99
      – Signed Integer: with two’s complement signed integer ranging from 0 to 127
      – Positive Fraction : this uses a look up table available in the manual
      – Signed Fraction : with two’s complement signed Frac using the lookup table (0 to 99)
      – Word : 16bits, 2 bytes unsigned value from 0 to 65535
      – Word 2 : similar than Word method but with a min value of 100
      – Table : unsigned byte index of to table of +1 entries of length

      Well this is quite complicated and I have to make it the most simple way so that at the end I just have to precise the calculation method for each dynamically updated modulator.

      I read in the forum that there’s some calculation methods already implemented in the Ctrlr libraries, but the api documentations pages are unavailable.

      Can someone please help me with that so I can just add somewhere the different calculation methods if required as global formulas then use call them in a line for my different algo paramaters like in the attached code above?

      thanks a lot ctrlr people, take care and stay safe 😉

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

        So if the incoming Byte from a Midi message received is assigned to the variable
        UAParamValue02 that byte could only be a value 0-127 so there should be a MSB byte and a LSB in sequence in the sysex message (two bytes which can be combined to form a value above 128)

        Presuming the MSB byte comes first you would do something like:

        UAParamValue02MSB = midiMessage:getData():getByte(XX) *128
        UAParamValue02LSB = midiMessage:getData():getByte(XX+1)

        UAParamValue02=UAParamValue02MSB+UAParamValue02LSB

        I hope this answers your question.

        Also I don’t trust UAParam02:setModulatorValue(xx,false,false,false) or UAParam02:setModulatorValue(xx,false,true,false)

        I would do

        UAParam02: getComponent():setValue(xx,true) — or false

        In my experience setModulatorValue() sometimes doesn’t work, but I can’t say when or why.

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

          Ha, it is on a DP4 that you are working! Nice unit and would really like to have one 😉

          Different things that might help you:
          – as dnaldoog said; use setValue(xx, true) to set a value and use getModulatorValue() to get a value.
          – when you are doing your panel design and want to handle several things with the same modulator, reduce your problem to test your way of working / idea; So here, starts with 3 or 4 algo max and 4-5 modulators max.
          – do not think only Ctrlr but also Lua. I learned Lua as I discovered Ctrlr and it is a very powerful language.
          I don’t know if you are aware that you can work with named indexes in tables.
          You can have tModMin[“Effect1”][1] = xxx for example which would contain the minimum value of mod1 for Effect1.
          As you are using a string to identify the index you can also put that in a variable.
          tModMin is a table that would contain all mods min values for all effects.
          – define all your modulators at once in a single method that you call at Panel loaded so you don’t need to repeat the “getModulatorbyName()” everywhere

          function AssignModulators()
          
          	-- Main Screen
          	txtLCDprogram = panel:getModulatorByName("LCDprogram")
          	txtLCDcategory = panel:getModulatorByName("LCDcategory")
          	txtLCDparameter = panel:getModulatorByName("LCDparameter")
          	txtLCDfile = panel:getModulatorByName("LCDfile")
          	btnLoad = panel:getModulatorByName("Load")
          	btnSave = panel:getModulatorByName("Save")
          	btnRename = panel:getModulatorByName("Rename") 
          	btnInit = panel:getModulatorByName("Init")
          

          – for your calculation methods, you can’t have all calculation methods in the same modulator, I’m afraid.
          But you can see things in a different way. Except the Table, all are mods with 0 to N value.
          Table mods: use a uiCombo component that you will update the content according to the effect
          0..N mods: I would split those ones between what I call PositiveValue ones with an uiImageSlider handling an image scrolling from 0 to N and NegPosValue ones with an uiImageSlider handling image scrolling left/right according to Neg or Pos. Internally both are going 0..N but the display is different and the “Value to set when double clicked” is also different. So better to split (as well for the further calculation).

          At this stage, just build a simple panel with:
          – a combo to select among 3-4 effects
          – 4 uiImageSliders whereof 2 Pos and 2 NegPos
          – 1 uiCombo
          – the logic to display the right info according to the selected algo
          – one PositiveValue_OnChange method for all Pos mods
          – one NegPosValue_OnChange method for all NegPos mods
          – one Combo_OnChange method for all Combo mods
          – put all your fixed data values in tables (min, max, names, visibility…)
          – later on use memoryblocks for user data / dumps (don’t look at sending/receiving yet)
          If the above works fine all the rest is piece of cake (almost 😉 )

          #118226
          damien
          Participant
            • Topics: 15
            • Replies: 62
            • Total: 77

            Hi Dnaldoug and goodweather,

            That’s precious tips from both of you.
            The formula to get the two following bytes from the sysex MSB & LSB is so simple I was struggling to find it 🙂

            I’ll go this way as Dnaldoug said.

            UAParamValue02MSB = midiMessage:getData():getByte(XX) *128
            UAParamValue02LSB = midiMessage:getData():getByte(XX+1)
            UAParamValue02=UAParamValue02MSB+UAParamValue02LSB

            This is absolutely perfect and I can apply this method for each parameters.

            I’ll try also to “stringify” the different variables for each parameters and use it in a global method that will simplify the script as goodweather mentionned.

            I finished the GUI 99% every button is connected with LUA methods already. on value change like on/off or select/unselect some tabs switch occure etc that’s the 1step of my progress
            I’m currently working on decoding the sysex sent by the DP4 and updating the appropriate pots values buttons labels etc

            Next will be to assign the right sysex formula to the differents knobs depending on the current algo.
            Next will be to create a scrolling menu with the different presets and algo for the 4 units with the dedicated program change or algo index sysex message.
            Next will be to manage the sysex dump backups with the load/write functions. this is pretty easy compared to the rest.
            And last but not least, check if everything is working properly, every param change etc

            I work on this for 2 weeks now, and at the beginning I just wanted to have a “remote” from the computer to emulate the buttons actions but Ctrlr opened me some new doors to LUA. It’s so powerful I could not imagine that, once the DP4 panel will be ready I’ll work on other units like yamaha spx etc I think I started with the most difficult, the other unit with 20 algos, program change, 1 DSP and 3 routing config will be a piece of cake 🙂

            Thanks you both for your precious help. I’ll probably ring a bell for other issues.

            Damien

            Attachments:
            You must be logged in to view attached files.
            #118233
            dnaldoog
            Participant
              • Topics: 4
              • Replies: 480
              • Total: 484
              • ★★

              Glad that formula helps you with two byte values!

              ….Next will be to assign the right sysex formula to the differents knobs depending on the current algo.

              Because your panel is complex, it might be good to give some structure to the design of the lua coding.

              I would create a callback function in Ctrlr “Called when any modulator changes it’s (sic) value)” e.g. modChange. It’s a great way to have every button/slider go to one place for lua.

              What follows is one of many ways to do it, but for me you can keep a sea of functions listed in one place (the modChange() function).

              You don’t want every modulator to trigger this function so create a global set of modulators you want to change

              
              -- only modulators in this list will trigger functions
              set={
              knob1=true,
              knob2=true,
              knob3=true,
              knob4=true,
              knob5=true
              }
              

              When the callback triggers, capture the name of the modulator ‘n’ and run an associated function.

              
              modChange = function(--[[ CtrlrModulator --]] modulator, --[[ number --]] value)
              local n=L(modulator:getName())
              if set[n]==true then
              
              local t={
              
              knob1=function1(value),
              knob2=function2(value),
              knob3=function3(value),
              knob4=function4(value),
              knob5=function5(value),
              }
              
              return t[n]
              
              end
              end
              

              You might have a combo or popUp that changes knob4’s functionality:

              
              function4=function(value)
              if myComboValue:getModulatorValue()==2 then
              -- do something 
              console(String(tostring(value))) 
              ....
              elseif myComboValue:getModulatorValue()==3
              -- do something
              console(String(tostring(value*value))) 
              end
              
              end
              

              Note: it is the function itself that does all the work. All ‘functionality’ is kept local to one function. It is true you will have many different functions, but they are all triggered from the one entry point ‘modChange()’

              • This reply was modified 3 years, 11 months ago by dnaldoog.
              • This reply was modified 3 years, 11 months ago by dnaldoog. Reason: I moved the content into the previous post
              #118249
              damien
              Participant
                • Topics: 15
                • Replies: 62
                • Total: 77

                Thanks guys for your tips! I’ll decypher everything you said and I’ll adapt your method to my project.
                This combo trick used as a middleman is neat.

                thanks, I’ll get back to you very soon 😉

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

                  Extremely nice panel! Currently chasing a DP4 so…

                  Yep the functions explained by dnaldoog are the ones I typically use and explain in all my Ctrlr forum posts since long.
                  xxx_OnClick: to display some info when mouse is down
                  xxx_OnChange: action when mod is changing value
                  PositiveValue_OnChange: one method for all 0..n type of mods
                  NegPosValue_OnChange: one method for all -/+ type of mods
                  OnOff_OnChange: for double switches
                  TripleSwitch_OnChange: for all triple switches

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

                    To come back on the initial question… FYI, I implemented this feature on my Odyssey panel some time ago.
                    If you are interested I can provide you explanations or publish here.
                    32 FX algorithms, each 3 parameters that can be of different kinds, only 3 modulators to handle them.
                    So, acc. to the parameter type (int, float, table… I’m changing the behavior of the mod (min, max, display, steps).
                    When switching algorithm, the mods are changing, the previous values displayed…

                    And I have also now the DP4 that the Belgian guy was selling 😉

                  Viewing 8 posts - 1 through 8 (of 8 total)
                  • The forum ‘Programming’ is closed to new topics and replies.
                  There is currently 0 users and 88 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