MIDI Remote API: `mOnProcessVal ueChange` not executed when calling `setProcessValue`

I would expect the script

var midiremote_api = require("midiremote_api_v1");
var deviceDriver = midiremote_api.makeDeviceDriver("company", "device", "author");
var page = deviceDriver.mMapping.makePage("Page");

var surfaceValue = deviceDriver.mSurface.makeCustomValueVariable("surfaceValue");
var hostValue = page.mCustom.makeHostValueVariable("hostValue");

surfaceValue.mOnProcessValueChange = function (context, value) {
  console.log("surfaceValue changed to " + value.toString());
};

hostValue.mOnProcessValueChange = function (context, value) {
  console.log("hostValue changed to " + value.toString());
};

page.makeValueBinding(surfaceValue, hostValue);

deviceDriver.mOnActivate = function (context) {
  console.log("Setting surfaceValue to 1...");
  surfaceValue.setProcessValue(context, 1);
};

(with the same repro steps and system info as in this post) to log

Setting surfaceValue to 1...
surfaceValue changed to 1
hostValue changed to 1

Instead, it only logs Setting surfaceValue to 1....
Clearly, mOnProcessValueChange is neither invoked on surfaceValue, nor on hostValue (which is bound to surfaceValue and thus should change with it). Is this expected behavior or a bug? Thanks in advance for looking into this!

Hi, I don’t know if this is the expected behavior, however I’ve seen in my script that inside mOnActivate, be it the deviceDriver or a page, I’m not using custom vars, I’m using states instead.

The way I see it, when the activation event is raised, we get a place to initialize states. By the way, why would you need to raise a second event (i.e. a mOnProcessValueChange) here? Perhaps there is a workaround.

Hi @m.c,
thanks for seconding this! By “states” you mean plain JavaScript variables or something magical I do not yet know?

The custom surface value was just to simplify the repro. Let’s say I have a lamp (surface.makeLamp()) that I would like to activate when the driver is activated. Then I would setProcessValue the mSurfaceValue and send MIDI in an mOnProcessValueChange handler of the lamp’s mSurfaceValue.
There certainly are workarounds, but I’ve taken a lot of these already and in my current situation (not the lamp one), it would just add an unjustified amount of code and complexity to my script. If this is expected for whatever reason, I’ll work around it, otherwise I’d very happily wait for a fix :sweat_smile:

States are defined using activeDevice.setState(“stateName”,“stateValue”)
So, if I understand correctly, you want to somehow initialize your hardware controller’s elements upon activating?

Oh right, you name it!

That’s one of the use cases. In that case, I can also just send out MIDI directly as a workaround. In another example, custom value variables represent encoder LED ring display modes that I added as properties of the MR_PushEncoder surface elements (mDisplayModeValue) and I’d like to send out custom MIDI (via mOnProcessValueChange) when I set/bind them. Having custom value variables attached to encoder surface elements is very convenient for separating the midi binding and host mapping steps: In a first step I create all surface elements, then I can pass them around as a nested object, bind them to MIDI in a second step, and in a third step map surface elements to host values/commands/actions without bothering about MIDI messages. I’d like to keep that separation :blush: If I don’t need to bind surface values, I can also build (/hack?) my own surface value replacement based on activeDevice.set/getState(), with onProcessValueChange working. But that’s not why I’m here – I’d like the API to work as expected or limitations to be clearly documented to save our fellow dev friends some precious time… Anyway, thanks for taking the time to help here!

Hi @Jochen_Trappe,
sorry for bumping this. Could you consider taking a quick look at this in the next few weeks? Thanks!

Why not setting your vars inside a page.mOnActivate ONCE (by creating a state flag) instead of the deviceDriver.mOnActivate ?

After all, you always have a start up page, or am I missing something here?