Help with mOn-Process-Value-Change in MIDI Remote

I am trying to learn about sending data from Cubase MIDI Remote back to the device.

I have a very simple setup using an Arduino. I have one pot and one button. The pot is mapped to the selected track volume and the button is mapped to the selected track mute. On the breadboard, I have one LED. When the Arduino receives a sysex with a 0x32 in the middle byte, it turns the LED on. If it receives a sysex with a 0x33 in the middle byte, it turns the LED off. This is just to test sending and receiving sysex messages. In my script, where the button on the device is mapped to the mute, I have used mOnProcessValueChange to look at the value and, if 1 (Mute On) send the 0x32 message to turn the LED on and if the value is 0 (Mute Off), send the 0x33 message to turn the LED off. So, the LED represents the mute state.

Here is the portion of the script I am using to send the sysex to the device when the mute state changes. THIS WORKS. But, I am sure there is something I don’t understand…

var pot1 = deviceDriver.mSurface.makeKnob(0, 0, 7, 7)
pot1.mSurfaceValue.mMidiBinding.setInputPort(midiInput).bindToControlChange(0, 22)
var button1 = deviceDriver.mSurface.makeButton(8,0,7,7);
button1.mSurfaceValue.mMidiBinding.setInputPort(midiInput).bindToControlChange(0,78);

mainPage.makeValueBinding(pot1.mSurfaceValue, mainPage.mHostAccess.mTrackSelection.mMixerChannel.mValue.mVolume).setValueTakeOverModePickup();
mainPage.makeValueBinding(button1.mSurfaceValue, mainPage.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMute).setTypeToggle()
mainPage.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMute.mOnProcessValueChange = function (activeDevice, activeMapping, value){
    if(value===1){
    midiOutput.sendMidi(activeDevice, [0xF0, 0x32, 0xF7]);
    console.log(value.toString());console.log("if = 1 true");}
    else{midiOutput.sendMidi(activeDevice, [0xF0, 0x33, 0xF7]);
    console.log(value.toString());console.log("else true");}
}

When I push the button on the device to toggle the mute state, in the MIDI Remote console, I get two or even three messages. They are all the same, for example, if I turn the mute on, I get the “1 → if = 1 true” message two or three times in a row for one press of the button. I have checked my device with a separate MIDI monitor and verified that when I press the button it sends a value of 127 on CC#78 ONCE. When I release the button, it sends a value of 0 on CC#78 ONCE so I know it is properly debounced. If I use the button on my device, I get one (sometimes another) message right away and another after a short delay. If I turn the mute on or off on the Cubase GUI, I just get two messages right away.

I suspect it has something to do with the “Toggle” behavior but if Cubase MR knows that the intent is to have one HIGH/LOW cycle of the button toggle the mute state, why is it calling mOnProcessValueChange multiple times?

I also suspect I may not really understand the ProcessValue. I think it is just a raw data value from 0 to 1. 0 for off state and 1 for on state in the case of the mute button or, in the case of a volume knob, -inf to +6 dB, for example.

Anyway, I am grateful for any help in understanding it.

My ultimate goal is to pass data such as track name, value text (i.e. -4.54 dB) back to the device and display it on an LCD but first I need to understand how these onValueChange callbacks work.

JL

I cannot really answer this one, which has been observed by other users as well in the past, since I don’t know how exactly the MR mechanism is structured. I kind of understand the logic behind this, but without seeing the code of the API, providing my thoughts on this would be next to useless in our case here. @Jochen_Trappe could obviously shed some light on this one if really needed.

What I can say however, is that
a) You don’t really have to worry about these duplicates, as long as you’re just aiming for displaying feedback, messages will arrive one way or the other, and
b) if you do worry about duplicates, you may find the page.mOnIdle event useful. When this one is triggered you can safely send to your controller the very last value of your host objects.

Here’s an example for the mute state, taking advantage of the mOnIdle event:

var midiremote_api = require('midiremote_api_v1')
var deviceDriver = midiremote_api.makeDeviceDriver("Test","Mute","m.c")

var midiInput = deviceDriver.mPorts.makeMidiInput("anInput")
var midiOutput = deviceDriver.mPorts.makeMidiOutput("anOutput")

var detectionUnit=deviceDriver.makeDetectionUnit()
detectionUnit.detectPortPair(midiInput,midiOutput)
    .expectInputNameEquals("Bome MIDI Translator 1")
    .expectOutputNameEquals("Bome MIDI Translator 1")

var surface=deviceDriver.mSurface
var mapping=deviceDriver.mMapping

var buttonMute=surface.makeButton(0,0,1,1)
buttonMute.mSurfaceValue.mMidiBinding
    .setInputPort(midiInput)
    .bindToControlChange(0,0)

var page=mapping.makePage("Default")

var mMute=page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mMute
page.makeValueBinding(buttonMute.mSurfaceValue,mMute).setTypeToggle()

var muteState=-1
var muteStatePrevious=-1

mMute.mOnProcessValueChange=function(activeDevice,activeMapping,value){
    console.log("got in mOnProcessValueChange: "+value) // You'll get the previous and after states. Worry not. You may even get duplicates
    //Do nothing here except for setting a var containing the state
    muteState=value
}

page.mOnIdle=function(activeDevice,activeMapping){
    if(muteState!=muteStatePrevious){
        console.log("got in mOnIdle, muteState="+muteState)
        muteStatePrevious=muteState
    }
}

If you test this snippet, you’ll see that the “got in mOnIdle” log will be printed once, even if we have duplicates.

1 Like

Thanks for your reply. Waiting for the idle state is a good tip!