Home › Forums › General › Programming › Midi Value LUA calculation method in Ctrlr [Two’s complement, Frac Table]
Tagged: Calculation method, Lua, midi value
- This topic has 7 replies, 3 voices, and was last updated 3 years, 8 months ago by goodweather.
-
AuthorPosts
-
May 6, 2020 at 3:22 am #118215
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 😉
May 6, 2020 at 4:46 am #118216So 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.
May 6, 2020 at 12:14 pm #118217Ha, 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()” everywherefunction 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 😉 )May 6, 2020 at 10:04 pm #118226Hi 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 etcNext 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 etcI 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.May 7, 2020 at 1:33 am #118233Glad 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()’
May 7, 2020 at 10:02 pm #118249Thanks 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 😉
May 8, 2020 at 2:39 pm #118270Extremely 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 switchesAugust 24, 2020 at 12:10 pm #119514To 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 😉
-
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.