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 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • #118215
    damien
    Participant
    • Topics: 14
    • Replies: 60
    • Total: 74

    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
    dnaldoogdnaldoog
    Participant
    • Topics: 3
    • Replies: 377
    • Total: 380
    • ★★

    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
    goodweathergoodweather
    Participant
    • Topics: 41
    • Replies: 499
    • Total: 540
    • ★★★

    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: 14
    • Replies: 60
    • Total: 74

    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
    dnaldoogdnaldoog
    Participant
    • Topics: 3
    • Replies: 377
    • Total: 380
    • ★★

    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 2 months ago by dnaldoogdnaldoog.
    • This reply was modified 2 months ago by dnaldoogdnaldoog. Reason: I moved the content into the previous post
    #118249
    damien
    Participant
    • Topics: 14
    • Replies: 60
    • Total: 74

    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
    goodweathergoodweather
    Participant
    • Topics: 41
    • Replies: 499
    • Total: 540
    • ★★★

    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

Viewing 7 posts - 1 through 7 (of 7 total)
  • You must be logged in to reply to this topic.
There is currently 1 user and 29 guests online
Chefetage
Forum Statistics
Threads: 2,394, Posts: 16,752, Members: 59,355
Most users ever online was 12 on January 22, 2019 3:47 pm
Do NOT follow this link or you will be banned from the site!