Home › Forums › General › Programming › uiCombo not responding to MIDI CC
- This topic has 35 replies, 5 voices, and was last updated 4 years, 8 months ago by goodweather.
-
AuthorPosts
-
May 13, 2018 at 10:29 am #83854
Hi there,
So I’m still tinkering with my panel and have made some improvements and ironed out a few bugs. Now for completeness there is an issue I have noticed that would be good to address, it is as follows.
When entering values on the synth Ctrlr uiSliders mirror those changes perfectly. However Ctrlr uiCombos do not!
I am not referring to receiving tone edit Sysex dumps these work fine, the issue is with CC messages transmitted by the synth during parameter edits made via the synth.
For example I have a uiCombo with three values in the Combo contents window, these are:
16′
8′
4′The MIDI data for these is:
$08 (08) $yy yy= $00-$1f (0-31) 16' $20-$3f (32-63) 8' $40-$7f (64-127) 4'
So do I need amend the ‘Expression to evaluate when calculating modulator value from midi message value field’? Do I need to attach a method to the ‘Called to calculate new modulator value from midi value’ popup? I have fiddled around with both of these but not really knowing what I am doing all attempts failed.
Any assistance is always appreciated.
Thanks.Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 13, 2018 at 2:02 pm #83861I haven’t studied this problem so far but did you check what message the synth sends? E.g. when you entered in the Combo this:
16’=0
8’=32
4’=64But the synth sends something different like 16’=31 it would be clear that it does not work. If it does not work for some reason I would try a script attached to “Called to calculate new modulator value from a MIDI value”. Here’s what the Lua editor makes when you add a new method selecting the right template:
myNewMethod = function(–[[ CtrlrModulator –]] modulator, –[[ CtrlrMidiMessage –]] midiMessage, –[[ number –]] numericMidiValue)
return numericMidiValue
end
May 13, 2018 at 9:15 pm #83918Thanks Possemo,
Indeed to your first point the synth actually returns:
$54 (84) 16’
$24 (36) 8’
$00 (0) 4’To your second point I attached the script as suggested, however this had no effect.
I will have a further dabble with scripts and see what I can achieve, I’ll report any kind of success.Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 14, 2018 at 11:54 am #83942So the synth returns completely different values? The range seems to be upside down compared to your previous list.
The script does not do anything, it is an empty template. You would have to enter code that converts the received values into the combo values. But I would first check if the synth really sends the wrong values. If it is a bug in the firmware there would be no other way than making a script that converts the wrong values into right ones.
- This reply was modified 5 years, 10 months ago by Possemo.
May 15, 2018 at 12:05 am #83952Oh dear, the joys of dyscalculia.
My error that should have read:
$00 (0) 16’
$24 (36) 8’
$54 (84) 4’So the synth firmware is fine, it is my firmware that is buggy!
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 15, 2018 at 9:16 am #83954No problem, I have a touch of dyslexia and in school numbers were not my friends either but I am learning to live with it – now at the age of 49… he he.
Well then, did you try to set the uiCombo to the same values as the ones the synth sends? The uiCombo is an awkward modulator with a couple of bugs. Maybe it just won’t react to incoming messages whatever you do. In this case my last resort would be to make a script. I will try to help you on that.
May 15, 2018 at 9:20 pm #83961Thanks Possemo,
I too have Dyslexia, however as I child my next door neighbour was a teacher and I had one to one tuition which helped a lot. But I still have problems if I am flustered or in a hurry and sometimes I cannot connect the middle of a journey although I can picture both the start and the finish. However on the plus side it means I can often approach problem solving from a different angle.
Well I tried adjusting the uiCombo values to match the synth values but with no avail, so I think the script route is best way forward.
I have a script that recognises incoming CC, but I would like to omit the MIDI channel character from this. I tried using BigInteger and (bi:getBitRangeAsInt(1,1), but didn’t entirely know what I was doing.
midiCcID = midiMessage:getLuaData():getByte(0) if midiCcID == 0xB0 then console("CC Detected") end
I am guessing I need to make a script for each uiCombo and attach it via the “Called to calculate new modulator value from a MIDI value” menu. Would that be correct? As opposed to one long script for all.
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 16, 2018 at 1:01 pm #83965My idea for this problem would be as follows:
Make a slider with the same midi cc. You can hide this slider or put it do a different layer and make the layer invisible. This one should react to the incoming midi cc, so you don’t have to deal with that in the script. Then add a script to this slider “when modulator value changes”. In this script you set the uiCombo accordingly when the slider gets the specific incoming values.
May 24, 2018 at 12:50 am #84092That seems like a good workaround, I have quite a lot of uiCombos on my panel however. With this in mind I have persevered with Lua scripting with some success.
So I have added the following to my ‘midiMessageReceived’ script which is attached to ‘Called when panels receives a MIDImessage’
midiMessageReceived = function(midiMessage) midiCcID = midiMessage:getData():getByte(0) if midiCcID == 0xB0 or midiCcID == 0xB1 or midiCcID == 0xB2 or midiCcID == 0xB3 or midiCcID == 0xB4 or midiCcID == 0xB5 or midiCcID == 0xB6 or midiCcID == 0xB7 or midiCcID == 0xB8 or midiCcID == 0xB9 or midiCcID == 0xBA or midiCcID == 0xBB or midiCcID == 0xBC or midiCcID == 0xBD or midiCcID == 0xBE or midiCcID == 0xBF then console ("CC Detected") end midiCcMod = midiMessage:getData():getByte(1) if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) end end
Then I have a method for each uiCombo that is scripted as per the following.
dcoOneRangeMessage = function(midiMessage) midiCcData = midiMessage:getData():getByte(2) if midiCcData == 0x00 then DCO1Range:setModulatorValue((0), false, false, false) elseif midiCcData == 0x24 then DCO1Range:setModulatorValue((1), false, false, false) elseif midiCcData == 0x54 then DCO1Range:setModulatorValue((2), false, false, false) end end
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 24, 2018 at 8:40 am #84093If you have lots of these uiCombos this is probably the the best way doing it. Instead of setModulatorValue you could use setValueMapped and assign the value directly:
midiCcData = midiMessage:getData():getByte(2)
DCO1Range:setValueMapped(midiCcData, false, false)But this has the disadvantage that the modulator will send the new CC value to MIDI-Out – usually you don’t want that to happen.
May 24, 2018 at 12:25 pm #84095Thanks for the info I will try setValueMapped tonight and see what the result is.
Due to my lack of Lua knowledge I am not sure if the way I have formatted the first script is correct. In that I wish for it only to proceed to
midiCcData = midiMessage:getData():getByte(2)
if the result of
midiCcID = midiMessage:getData():getByte(0)
is positive. I have a suspicion that currently the second question is independent of the first.Could you confirm and or advise if this is the case please. Cheers.
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 24, 2018 at 9:29 pm #84100yea then you should include midiCcData in the first if-statement:
midiMessageReceived = function(midiMessage) midiCcID = midiMessage:getData():getByte(0) if midiCcID == 0xB0 or midiCcID == 0xB1 or midiCcID == 0xB2 or midiCcID == 0xB3 or midiCcID == 0xB4 or midiCcID == 0xB5 or midiCcID == 0xB6 or midiCcID == 0xB7 or midiCcID == 0xB8 or midiCcID == 0xB9 or midiCcID == 0xBA or midiCcID == 0xBB or midiCcID == 0xBC or midiCcID == 0xBD or midiCcID == 0xBE or midiCcID == 0xBF then console ("CC Detected") midiCcMod = midiMessage:getData():getByte(1) if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) end end end
the many “or’s” could be replaced by “greater or equal than” and “smaller or equal than”:
midiMessageReceived = function(midiMessage) midiCcID = midiMessage:getData():getByte(0) if midiCcID >= 0xB0 and midiCcID <= 0xBF then console ("CC Detected") midiCcMod = midiMessage:getData():getByte(1) if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) end end end
I haven’t tested it but in theory it should work. Maybe it does not work with hex number but I wouldn’t see why. If it does not work for some weird reason you could use decimal numbers – replace 0xB0 with 176 and 0xBF with 191.
May 24, 2018 at 11:13 pm #84101Hey Possemo, that works brilliantly. I tested the >= and <= across all sixteen MIDI channels to be on the safe side and it works perfectly. Many thanks for your invaluable assistance.
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalMay 25, 2018 at 2:24 pm #84106fine, one last thing I always do: remove the console output when you have finished debugging. the cosole() command slows down performance significantly. If you just send a fixed string like in your example it is probably not that bad but I would remove it anyway.
- This reply was modified 5 years, 9 months ago by Possemo.
June 17, 2018 at 10:58 pm #84303I’m back!
OK all worked well until I exported a VST instance and then tried to use it in my DAW. I have several issues to sort but thought I would address this one first.
So I have attached a message that I get on panel launch / boot (as I drop it into the DAW). This relates to one of the many methods that are attached to the uiCombos. Here is the code for that particular method:
lfoModeMessage = function(midiMessage) -- This variable stops index issues during panel bootup if panel:getRestoreState() == true or panel:getProgramState() == true then return end midiCcData = midiMessage:getData():getByte(2) -- Value Byte if midiCcData >= 0x00 and midiCcData <= 0x43 then LFOMode:setModulatorValue((0), false, false, false) elseif midiCcData >= 0x44 and midiCcData <= 0x7F then LFOMode:setModulatorValue((1), false, false, false) end end
Here is an abridged version of the method that precedes it:
midiMessageReceived = function(midiMessage) if panel:getRestoreState() == true or panel:getProgramState() == true then return end midiCcID = midiMessage:getData():getByte(0) -- Controller Byte if midiCcID >= 0xB0 and midiCcID <= 0xBF then -- MIDI Channels midiCcMod = midiMessage:getData():getByte(1) -- Parameter Byte if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) elseif midiCcMod == 0x10 then lfoModeMessage(midiMessage) elseif midiCcMod == 0x67 then atLevelMessage(midiMessage) end end end
This is line 14:
midiCcData = midiMessage:getData():getByte(2) -- Value Byte
Thanks.
Attachments:
You must be logged in to view attached files.Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalJune 18, 2018 at 11:54 am #84307OK so I tried adding this to lfoModeMessage:
elseif midiCcData == nil then return
It stopped the error at boot but also stopped the method working at all.
So I am wondering if this might work instead:
midiMessageReceived = function(midiMessage) if panel:getRestoreState() == true or panel:getProgramState() == true then return end midiCcID = midiMessage:getData():getByte(0) -- Controller Byte if midiCcID >= 0xB0 and midiCcID <= 0xBF then -- MIDI Channels elseif midiCcID == nil then return midiCcMod = midiMessage:getData():getByte(1) -- Parameter Byte if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) elseif midiCcMod == 0x10 then lfoModeMessage(midiMessage) elseif midiCcMod == 0x67 then atLevelMessage(midiMessage) end end end
Any thoughts or pointers in the right direction are always welcome.
Here is some noise I organised into an acceptable format:
https://soundcloud.com/lfo2vco/a-dark-crystalJune 18, 2018 at 1:11 pm #84308I think the “check if nil” is a good idea. But arrange it differently. You have to place the procedure between IF and ELSEIF:
midiMessageReceived = function(midiMessage) if panel:getRestoreState() == true or panel:getProgramState() == true then return end -- Controller Byte midiCcID = midiMessage:getData():getByte(0) -- MIDI Channels if midiCcID >= 0xB0 and midiCcID <= 0xBF then -- Parameter Byte midiCcMod = midiMessage:getData():getByte(1) if midiCcMod == 0x08 then dcoOneRangeMessage(midiMessage) elseif midiCcMod == 0x10 then lfoModeMessage(midiMessage) elseif midiCcMod == 0x67 then atLevelMessage(midiMessage) end elseif midiCcID == nil then return end end
And – because of the weird error message which shows a part of a comment I would put them on a new line. Maybe it does weird things when placing them to the same line as the code.
June 18, 2018 at 8:12 pm #84315Copy data to another variable. Becouse if another midi message arraive you have midimessage overwriten. Do it first like this on the beginning
local dataRecived=midiMessage:getData ()Then operate on dataRecived as your midiData
- This reply was modified 5 years, 9 months ago by daimondamps.
June 18, 2018 at 9:14 pm #84317As Ctrlr is not multi-threaded (at least in almost all cases) I don’t think that it will update midiMessage while the Lua script is running. But I am putting the message in a var too because this way I have to write :getData() only once. So – yea it is a good idea anyway.
June 19, 2018 at 10:43 am #84328Why not to use ready class for message type recognition. `module(L)
[
class_(“MidiMessage”)
.def(constructor<>())
.def(constructor())
.def(constructor())
.def(constructor())
.def(constructor())
.def(constructor())
.def(constructor())
.def(constructor())
.def(“getRawData”, &MidiMessage::getRawData)
.def(“getRawDataSize”, &MidiMessage::getRawDataSize)
.def(“getTimeStamp”, &MidiMessage::getTimeStamp)
.def(“setTimeStamp”, &MidiMessage::setTimeStamp)
.def(“addToTimeStamp”, &MidiMessage::addToTimeStamp)
.def(“getChannel”, &MidiMessage::getChannel)
.def(“isForChannel”, &MidiMessage::isForChannel)
.def(“setChannel”, &MidiMessage::setChannel)
.def(“isSysEx”, &MidiMessage::isSysEx)
.def(“getSysExData”, &MidiMessage::getSysExData)
.def(“getSysExDataSize”, &MidiMessage::getSysExDataSize)
.def(“isNoteOn”, &MidiMessage::isNoteOn)
.def(“isNoteOff”, &MidiMessage::isNoteOff)
.def(“isNoteOnOrOff”, &MidiMessage::isNoteOnOrOff)
.def(“getNoteNumber”, &MidiMessage::getNoteNumber)
.def(“setNoteNumber”, &MidiMessage::setNoteNumber)
.def(“getVelocity”, &MidiMessage::getVelocity)
.def(“getFloatVelocity”, &MidiMessage::getFloatVelocity)
.def(“setVelocity”, &MidiMessage::setVelocity)
.def(“multiplyVelocity”, &MidiMessage::multiplyVelocity)
.def(“isSustainPedalOn”, &MidiMessage::isSustainPedalOn)
.def(“isSustainPedalOff”, &MidiMessage::isSustainPedalOff)
.def(“isSostenutoPedalOn”, &MidiMessage::isSostenutoPedalOn)
.def(“isSostenutoPedalOff”, &MidiMessage::isSostenutoPedalOff)
.def(“isSoftPedalOn”, &MidiMessage::isSoftPedalOn)
.def(“isSoftPedalOff”, &MidiMessage::isSoftPedalOff)
.def(“isProgramChange”, &MidiMessage::isProgramChange)
.def(“getProgramChangeNumber”, &MidiMessage::getProgramChangeNumber)
.def(“isPitchWheel”, &MidiMessage::isPitchWheel)
.def(“getPitchWheelValue”, &MidiMessage::getPitchWheelValue)
.def(“isAftertouch”, &MidiMessage::isAftertouch)
.def(“getAfterTouchValue”, &MidiMessage::getAfterTouchValue)
.def(“isChannelPressure”, &MidiMessage::isChannelPressure)
.def(“getChannelPressureValue”, &MidiMessage::getChannelPressureValue)
.def(“isController”, &MidiMessage::isController)
.def(“getControllerNumber”, &MidiMessage::getControllerNumber)
.def(“getControllerValue”, &MidiMessage::getControllerValue)
.def(“isControllerOfType”, &MidiMessage::isControllerOfType)
.def(“isAllNotesOff”, &MidiMessage::isAllNotesOff)
.def(“isAllSoundOff”, &MidiMessage::isAllSoundOff)
.def(“isMetaEvent”, &MidiMessage::isMetaEvent)
.def(“getMetaEventType”, &MidiMessage::getMetaEventType)
.def(“getMetaEventData”, &MidiMessage::getMetaEventData)
.def(“getMetaEventLength”, &MidiMessage::getMetaEventLength)
.def(“isTrackMetaEvent”, &MidiMessage::isTrackMetaEvent)
.def(“isEndOfTrackMetaEvent”, &MidiMessage::isEndOfTrackMetaEvent)
.def(“isTrackNameEvent”, &MidiMessage::isTrackNameEvent)
.def(“isTextMetaEvent”, &MidiMessage::isTextMetaEvent)
.def(“getTextFromTextMetaEvent”, &MidiMessage::getTextFromTextMetaEvent)
.def(“isTempoMetaEvent”, &MidiMessage::isTempoMetaEvent)
.def(“getTempoMetaEventTickLength”, &MidiMessage::getTempoMetaEventTickLength)
.def(“getTempoSecondsPerQuarterNote”, &MidiMessage::getTempoSecondsPerQuarterNote)
.def(“isTimeSignatureMetaEvent”, &MidiMessage::isTimeSignatureMetaEvent)
.def(“getTimeSignatureInfo”, &MidiMessage::getTimeSignatureInfo)
.def(“isKeySignatureMetaEvent”, &MidiMessage::isKeySignatureMetaEvent)
.def(“getKeySignatureNumberOfSharpsOrFlats”, &MidiMessage::getKeySignatureNumberOfSharpsOrFlats)
.def(“isMidiChannelMetaEvent”, &MidiMessage::isMidiChannelMetaEvent)
.def(“getMidiChannelMetaEventChannel”, &MidiMessage::getMidiChannelMetaEventChannel)
.def(“isActiveSense”, &MidiMessage::isActiveSense)
.def(“isMidiStart”, &MidiMessage::isMidiStart)
.def(“isMidiContinue”, &MidiMessage::isMidiContinue)
.def(“isMidiStop”, &MidiMessage::isMidiStop)
.def(“isMidiClock”, &MidiMessage::isMidiClock)
.def(“isSongPositionPointer”, &MidiMessage::isSongPositionPointer)
.def(“getSongPositionPointerMidiBeat”, &MidiMessage::getSongPositionPointerMidiBeat)
.def(“isQuarterFrame”, &MidiMessage::isQuarterFrame)
.def(“getQuarterFrameSequenceNumber”, &MidiMessage::getQuarterFrameSequenceNumber)
.def(“getQuarterFrameValue”, &MidiMessage::getQuarterFrameValue)
.def(“isFullFrame”, &MidiMessage::isFullFrame)
.def(“isMidiMachineControlMessage”, &MidiMessage::isMidiMachineControlMessage)
.def(“getMidiMachineControlCommand”, &MidiMessage::getMidiMachineControlCommand)
.def(“isMidiMachineControlGoto”, &MidiMessage::isMidiMachineControlGoto)
.enum_(“SmtpeTimecodeType”)
[
value(“fps24”, 0),
value(“fps25”, 1),
value(“fps30drop”, 2),
value(“fps30”, 3)
]
// CAUSES COMPILATION ERROR .def(“getFullFrameParameters”, (void (MidiMessage::*)(int &, int &, int &, int &, MidiMessage::SmpteTimecodeType &) const noexcept)&MidiMessage::getFullFrameParameters)
.enum_(“MidiMachineControlCommand”)
[
value(“mmc_stop”, 1),
value(“mmc_play”, 2),
value(“mmc_deferredplay”, 3),
value(“mmc_fastforward”, 4),
value(“mmc_rewind”, 5),
value(“mmc_recordStart”, 6),
value(“mmc_recordStop”, 7),
value(“mmc_pause”, 9)
]
.scope
[
def(“noteOn”, (MidiMessage (*)(int, int, float) noexcept)&MidiMessage::noteOn),
def(“noteOn”, (MidiMessage (*)(int, int, uint8) noexcept)&MidiMessage::noteOn),
def(“noteOff”, &MidiMessage::noteOff),
def(“programChange”, &MidiMessage::programChange),
def(“pitchWheel”, &MidiMessage::pitchWheel),
def(“aftertouchChange”, &MidiMessage::aftertouchChange),
def(“channelPressureChange”, &MidiMessage::channelPressureChange),
def(“controllerEvent”, &MidiMessage::controllerEvent),
def(“allNotesOff”, &MidiMessage::allNotesOff),
def(“allSoundOff”, &MidiMessage::allSoundOff),
def(“allControllersOff”, &MidiMessage::allControllersOff),
def(“endOfTrack”, &MidiMessage::endOfTrack),
def(“tempoMetaEvent”, &MidiMessage::tempoMetaEvent),
def(“timeSignatureMetaEvent”, &MidiMessage::timeSignatureMetaEvent),
def(“midiChannelMetaEvent”, &MidiMessage::midiChannelMetaEvent),
def(“midiStart”, &MidiMessage::midiStart),
def(“midiContinue”, &MidiMessage::midiContinue),
def(“midiStop”, &MidiMessage::midiStop),
def(“midiClock”, &MidiMessage::midiClock),
def(“songPositionPointer”, &MidiMessage::songPositionPointer),
def(“quarterFrame”, &MidiMessage::quarterFrame),
def(“fullFrame”, (MidiMessage (*)(int,int,int,int,MidiMessage::SmpteTimecodeType))&MidiMessage::fullFrame),
def(“midiMachineControlCommand”, &MidiMessage::midiMachineControlCommand),
def(“midiMachineControlGoto”, &MidiMessage::midiMachineControlGoto),
def(“masterVolume”, &MidiMessage::masterVolume),
def(“createSysExMessage”, &MidiMessage::createSysExMessage),
def(“readVariableLengthVal”, &MidiMessage::readVariableLengthVal),
def(“getMessageLengthFromFirstByte”, &MidiMessage::getMessageLengthFromFirstByte),
def(“getMidiNoteName”, &MidiMessage::getMidiNoteName),
def(“getMidiNoteInHertz”, &MidiMessage::getMidiNoteInHertz),
def(“getGMInstrumentName”, &MidiMessage::getGMInstrumentName),
def(“getGMInstrumentBankName”, &MidiMessage::getGMInstrumentBankName),
def(“getRhythmInstrumentName”, &MidiMessage::getRhythmInstrumentName),
def(“getControllerName”, &MidiMessage::getControllerName)
]
];
}` -
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.