API: mOnTitleChange and mOnColorChange broken for some bindings

Since Cubase v12.0.60, the mOnTitleChange and mOnColorChange callbacks of a surface variable bound to a MixerBankChannel’s mVolume value are not invoked when navigating the corresponding MixerBankZone.

Here’s a code snippet to demonstrate what I mean:


var surfaceValue = deviceDriver.mSurface.makeCustomValueVariable("surfaceValue");
var mixerBankZone = page.mHostAccess.mMixConsole.makeMixerBankZone();
var channel = mixerBankZone.makeMixerBankChannel();

page.makeValueBinding(surfaceValue, channel.mValue.mVolume);

surfaceValue.mOnColorChange = function () {
  console.log("This is not logged when navigating the MixerBankZone.");
};
surfaceValue.mOnTitleChange = function () {
  console.log("This one neither.");
};

As a result, track colors or titles are not updated in some scripts. @Xion shared what might be an instance of this or a similar problem in

This issue smells like the automated Remote API testing is lacking a bit. I would very much appreciate if basic functionality like this could be fully tested for. I don’t want to get nervous whenever a new Cubase patch release is published. I really like the MIDI Remote API, but I feel like it could use some love.

4 Likes

Well done for the demonstration @bjoluc
As I said, unplugin/plugin the device (or disable/enable the script) allows to retrieve colours but it’s very restrictive.

I suppose we have to wait for a new update now…

1 Like

It’s kind of funny because earlier this morning I decided to add to my controller the ability to set its select buttons to the tracks’ colour. I quickly saw what you describe, though the mOnColor finally gets triggered upon changing the selected track (or for example enabling/disabling it). So I abandoned for now this process. I guess my timing was bad :laughing:

2 Likes

HI there just an update on my comment.
If we use this:

channel.mOnTitleChange=(function(activeDevice,activeMapping,title){
            console.log("in channel "+this.youChannelsIndex+"  title="+title)
          }).bind({yourChannelsIndex})

it seems that we always get the title update.

Same thing goes for the mOnColor, BUT not if user just changes the colour of the track. This colour is updated upon a channel change unfortunately.

Right, Cubase fires channel.mOnColorChange and channel.mOnTitleChange (for what it’s worth, even channel.mValue.mSelected.mOn... and channel.mValue.mVolume.mOn...), but not surfaceValue.mOnColorChange and surfaceValue.mOnTitleChange.
Moreover, I found that binding a surface variable to channel.mValue.mSelected makes the surface value callbacks work on my dev machine, but reportedly not for all users of my X-Touch script on Cubase 12.0.60.
@m.c You were able to repro the issue with a surface variable bound to channel.mValue.mSelected too, right? I can’t break it locally, but it is broken for at least one X-Touch script user and for @Xion with the Launckey MK3 37 script.

I’m not using a direct mOnTitleChange on the surface value for this one, so I cannot really reply on this, since I’m not on my dev-pc right now.
But why the need to use this instead of the channel.mOnTitle? Just curious.

But I will check this upon testing.

1 Like

In case of the Launckey MK3 37 script, the pads change color depending on value bindings (channel selection or solo/mute).
In my X-Touch script, it’s not necessary, just a bit hacky otherwise as I would need to move some MIDI binding (color handling) code to the host mapping modules. I’ll probably do this if my current workaround proofs to break for more users too.

Much appreciated, thanks :pray:

1 Like

Ah, so no info is available for sysex to these pads?

The event yourChannelByIndex.mValue.mSelected.mOnColorChange=(function(activeDevice,activeMapping,r,g,b,a,active){ console.log("on selected "+this.index+" r="+r+", g="+g+", b="+b+", active="+active) }).bind({index})

works as expected, when we change track. In fact, it brings up all other channels’ colours as well:

Oh, sorry, I think I wasn’t clear enough with

The script uses sub pages to bind the pads (button surface elements’ mSurfaceValues) either to channel.mValue.mSelected or channel.mValue.mSolo/mMute. So when switching subpages, the buttons’ mSurfaceValues change colors while the channel colors remain the same. In that case, myButton.mSurfaceValue.mOnColorChange is crucial.

I think channel.mValue.mSelected.mOnColorChange has never been broken, but would you mind checking the .mOnColorChange of a surface value bound to channel.mValue.mSelected? For me, it works when the variable is bound to channel.mValue.mSelected, but not when it’s bound to channel.mValue.mVolume

Sure I could try both, still, do you get an mOnChange for the mVolume at the same time you don’t get the mOnColor? I mean, maybe, just maybe, the colorChange is actually just the colours when a change happens to the volume, for instance?

Yup :roll_eyes: Weirdly, when I change mVolume via MIDI, I get a retrospective mOnColorChange, but when I change it in Cubase, I don’t.

That seems to be the case indeed (but only if the volume change happens via a MIDI binding) :grinning:

OK, so I’ve prepared a test script. BOTH surfaceValues binded to mVolume and mSelected of a mixerBankZone channel, got triggered ONLY upon the page’s activation. I somehow think that they’ve took this functionality out maybe because it would be an overkill (?) for the performance. BUT I mostly suspect that this is the expected behaviour, since the surfaceValues functions do not include the activeMapping argument. That means - again maybe - that they can deal with their context (which is the activeDevice) but not with a page (which is the activeMapping).
Anyway, just speculations, here’s the test:

var midiremote_api = require('midiremote_api_v1')

var driver=midiremote_api.makeDeviceDriver("testscript","testScript","someone")

var midiIn=driver.mPorts.makeMidiInput("midiIn")
var midiOut=driver.mPorts.makeMidiOutput("midiOut")

driver.makeDetectionUnit().detectPortPair(midiIn,midiOut)
    .expectInputNameContains("MIDI")
    .expectInputNameContains("MIDI")

var surface=driver.mSurface

var faders=[]
var selectButtons=[]
for(var faderIndex=0;faderIndex<8;faderIndex++){
    
    var fader=surface.makeFader(faderIndex,0,1,5)
    fader.mSurfaceValue.mMidiBinding.setInputPort(midiIn).setOutputPort(midiOut).bindToPitchBend(faderIndex)
    faders.push(fader)

    var selectButton=surface.makeButton(faderIndex,5,1,1)
    selectButton.mSurfaceValue.mMidiBinding.setInputPort(midiIn).setOutputPort(midiOut).bindToNote(0,24+faderIndex)
    selectButtons.push(selectButton)

}


var page=driver.mMapping.makePage("page")

var mixerBankZone=page.mHostAccess.mMixConsole.makeMixerBankZone("mixerBankZone")
mixerBankZone.excludeInputChannels()
mixerBankZone.excludeOutputChannels()

for(var channelIndex=0;channelIndex<8;channelIndex++){
    
    var mixerBankChannel=mixerBankZone.makeMixerBankChannel()
    var faderSurfaceValue=faders[channelIndex].mSurfaceValue
    var buttonSurfaceValue=selectButtons[channelIndex].mSurfaceValue
    page.makeValueBinding(faderSurfaceValue,mixerBankChannel.mValue.mVolume)
    page.makeValueBinding(buttonSurfaceValue,mixerBankChannel.mValue.mSelected)
    
    //both surfaceValues triggered ONLY upon page's activation
    //********************************************************
    faderSurfaceValue.mOnColorChange=(function(activeDevice,r,g,b,a,active){
        console.log("SURFACE mVolume-mOnColor received on index"+this.channelIndex+": r="+r+", g="+g+", b="+b+", active="+active)
    }).bind({channelIndex})

    buttonSurfaceValue.mOnColorChange=(function(activeDevice,r,g,b,a,active){
        console.log("SURFACE mSelect-mOnColor received on index"+this.channelIndex+": r="+r+", g="+g+", b="+b+", active="+active)
    }).bind({channelIndex})
    //********************************************************
    
    
    //These get triggered as expected
    mixerBankChannel.mValue.mVolume.mOnColorChange=(function(activeDevice,activeMapping,r,g,b,a,active){
        console.log("mVolume-mOnColor received on index"+this.channelIndex+": r="+r+", g="+g+", b="+b+", active="+active)
    }).bind({channelIndex})

    mixerBankChannel.mValue.mSelected.mOnColorChange=(function(activeDevice,activeMapping,r,g,b,a,active){
        console.log("mSelect-mOnColor received on index"+this.channelIndex+": r="+r+", g="+g+", b="+b+", active="+active)
    }).bind({channelIndex})

}

page.mOnActivate=function(activeDevice){
    var faderSurfaceValue=faders[0].mSurfaceValue
    faderSurfaceValue.mOnColorChange=function(activeDevice,r,g,b,a,active){
        console.log("ON ACTIVATE SURFACE mVolume-mOnColor received: r="+r+", g="+g+", b="+b+", active="+active)
    }
}





Thanks for reproducing @m.c. Since this thread is not very popular, I’m tagging @Jochen_Trappe here (assuming he’s the right guy for the job).

What do you mean by this? I find this thread very popular and useful actually :slight_smile:

It has only 213 views and few likes/votes, that’s all. I don’t know if Steinberg employees systematically search the forum to track issues.

Likes/votes are typically for feature requests, not issues/bugs.
That said, I don’t think the Cubase team pays too much attention to it.

Any word on this yet @Jochen_Trappe ? People have kindly spent hours supporting the API, and they’re now broken and having to spend more hours to find a way around it.

And yet no feedback from Steinberg!? Please give us an update.

2 Likes

2 months now since the last update. Can we expect a new update in order to repair what 12.0.60 broke ?

1 Like

Interestingly, I stumbled upon a “workaround” for this yesterday. I have absolutely no clue why it works, but apparently, it does. My repro snippet can be changed like this:

  var surfaceValue = deviceDriver.mSurface.makeCustomValueVariable("surfaceValue");
  var mixerBankZone = page.mHostAccess.mMixConsole.makeMixerBankZone();
  var channel = mixerBankZone.makeMixerBankChannel();
  
  page.makeValueBinding(surfaceValue, channel.mValue.mVolume);
+ page.makeValueBinding(surfaceValue, channel.mValue.mVolume); // Yes, a duplicate binding :O

  surfaceValue.mOnColorChange = function () {
-   console.log("This is not logged when navigating the MixerBankZone.");
+   console.log("This is logged when navigating the MixerBankZone.");
  };
  surfaceValue.mOnTitleChange = function () {
-   console.log("This one neither.");
+   console.log("This one too.");
  };

:magic_wand: :sparkles:

4 Likes