Cubase 12.0.50 MIDI Remote "Parameter Bank" controls

I’ll answer myself on this one too, as I just found a way around to do it. Probably not the best way but works great so far.
Basically what I did is add the pages as blank ones as one of the first things in the script. This way they are available when the scripts creates action bindings.
To fill it in on my pseudo script from above.

// This is the added code to make them available
var sendsPage = deviceDriver.mMapping.makePage('Sends')
var sendsPage = deviceDriver.mMapping.makePage('ChannelStrip')
etc...

var sendsPage = makePageSends()
var channelStripPage = makePageChannelStrip()
var insertsPage = makePageInserts()


function makePageSends() {
    var page = makePageWithDefaults('Sends')
   ... etc
    return page
}

function makePageChannelStrip() {
    var page = makePageWithDefaults('ChannelStrip')
   ... etc
    return page
}
...etc

function makePageWithDefaults(name) {
    var page = deviceDriver.mMapping.makePage(name)
    ...etc    
    return page
}

...etc

And I can change to the page with this command as an example:

page.makeActionBinding(surfaceElements.channelControls[0].page_button.mSurfaceValue, eqPage.mAction.mActivate)

Starting to enjoy all the functionality.
I have another question I was hoping to clear up, maybe @Jochen_Trappe knows.

When hoovering over a surface element that has been mapped as an ActionBinding, is there a way to get that information/title/name (so I can send it to the MIDI controller display):
Here’s are two examples:

Skærmbillede 2022-11-21 kl. 23.25.06

And also there’s more info when hoovering over a surface elements that has been ValueBind. In the picture below I can only get “HiPass” and “H-Delay Stereo”, using mOnTitleChange

It would be really awesome and helpful if we could get more of those infos available in our script somehow, to get better overview of what the MIDI device is doing.

Thanks as always in advance

Hi Thomas,
may I ask how you exactly send parameter names and values to external displays?
Thanks in advance,
Emre

Using following code I am able to control the first parameter of a plugin which is assigned in the Remote Editor. How can I control the rest of my assigned parameters?

var knob1 = deviceDriver.mSurface.makeKnob(0, 0, 1, 1.5)

knob1.mSurfaceValue.mMidiBinding
.setInputPort(midiInput)
.setOutputPort(midiOutput)
.bindToControlChange (0, 21) // channel 0, cc 21

var HostInsertViewer = page.mHostAccess.mTrackSelection.mMixerChannel.mInsertAndStripEffects.makeInsertEffectViewer(‘’)
.followPluginWindowInFocus ()

var ChannelInsertParameter = HostInsertViewer.mParameterBankZone.makeParameterValue()
page.makeValueBinding(knob1.mSurfaceValue, ChannelInsertParameter)

If I recall correctly, make another call to the …makeParameterValue() and it will give you the next one

Brilliant, thanks a lot robw, this works!
I also managed to push the value to an external (MCU) display, but don’t know how to grab the parameter NAME. So for instance I can display “3.3k” from my inserted SSL plugin, but not “HM Freq”, any help?
Heres my code for one knobs (well, not my code, but copied bits and pieces from here and there):

var hostSelectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel

var knob1 = deviceDriver.mSurface.makeKnob(0, 0, 1, 1.5)

knob1.mSurfaceValue.mMidiBinding
.setInputPort(midiInput)
.setOutputPort(midiOutput)
.bindToControlChange (0, 21) // channel 0, cc 21

var HostInsertViewer = hostSelectedTrackChannel.mInsertAndStripEffects.makeInsertEffectViewer(‘’)
.followPluginWindowInFocus ()

var ChannelInsertParameter1 = HostInsertViewer.mParameterBankZone.makeParameterValue()
var ChannelInsertParameter2 = HostInsertViewer.mParameterBankZone.makeParameterValue()
var ChannelInsertParameter3 = HostInsertViewer.mParameterBankZone.makeParameterValue()

page.makeValueBinding(knob1.mSurfaceValue, ChannelInsertParameter3)

ChannelInsertParameter3.mOnDisplayValueChange = function (activeDevice, activeMapping, value) {
    //console.log(value)
    var dataDisplay = [0xf0, 0x00, 0x00, 0x66, 0x14, 0x12, 0x38];
    var dataDisplayReset = [0xf0, 0x00, 0x00, 0x66, 0x14, 0x12, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7]
    for (var i = 0, len = value.length; i < len; ++i)
        dataDisplay.push(value.charCodeAt(i))
        dataDisplay.push(0xF7)
        midiOutput.sendMidi(activeDevice, dataDisplayReset)
        midiOutput.sendMidi(activeDevice, dataDisplay)
    }

I’ve got a question that, after reading through this thread, someone here may be able to answer, I hope. It’s related to the insert effect parameters discussions, but with a slightly different application to the usual.
I’m building a software-based control surface, and I’ve created a zone for insert plug-in parameter knobs (kind of like the plug-in Remote Control Editor layout) that follow the plug-in in focus. However, because I’m creating the parameter knobs dynamically, I’d like MIDI Remote to somehow get the number of parameters for the in-focus plug-in. Hopefully this helps explain it:
Surface Layout:

function makeInsertParams(x, y) {
  var params = {}
  var w = 2
  var h = 1
  var currX = x
  var currY = y
  var noOfParams = // number of parameters per insert plug-in
  for (var i = 1; i <= noOfParams; ++i) {
    var param = 'param' + i
    if (i % 8 == 0) {
      params[param] = surface.makeKnob(currX, currY, w, h)
      params[param].mSurfaceValue.mMidiBinding.setInputPort(midiInput).bindToControlChange(1, i)
      currX = currX - (w * 7)
      currY = currY + h
    } else {
      params[param] = surface.makeKnob(currX, currY, w, h)
      params[param].mSurfaceValue.mMidiBinding.setInputPort(midiInput).bindToControlChange(1, i)
      currX = currX + w
    }
    params[param].mSurfaceValue.mOnProcessValueChange = function (context, newValue) {
      midiOutput.sendMidi(context, newValue)
    }
  }
  return params
}

Host Mapping

var page = deviceDriver.mMapping.makePage(name)
var hostSelectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel
var insertViewer = hostSelectedTrackChannel.mInsertAndStripEffects.makeInsertEffectViewer('Inserts Viewer').followPluginWindowInFocus()
var insertsParamZone = insertViewer.mParameterBankZone
var noOfParams = // insertViewer.numberOfParameters (or similar)...
for (var i = 1; i <= noOfParams; ++i) {
  var param = 'param' + i
  var piParam = surfaceElements.params[param]
  var piParamValue = piParam.mSurfaceValue
  page.makeValueBinding(piParamValue, insertsParamZone.makeParameterValue())
    }

Is there something in the API that can look at an insert plug-in in edit mode and “get” the number of editable parameters? For example, if a plug-in has 160 parameters, then the MIDI Remote would dynamically create 160 knobs in the parameters zone (left of screen):

If there isn’t, I guess I’ll create a feature request instead.

Thanking y’all in advance.

1 Like

Sorry - I have a further question that may be best answered by @Jochen_Trappe , but maybe someone has stumbled across it before.
As it stands, value binding a parameter knob to an insert plug-in parameter can be done by:
(SurfaceValue, HostInsertEffectViewer.HostPluginParameterBankZone.makeParameterValue())
However, it appears that there’s no way to determine the parameter number the parameter knob is bound to. The binding defaults to Parameter 1 and additional parameter knobs are bound to the plug-in parameters in sequential order (Parameter 2, Parameter 3… Parameter n) . I guess this wouldn’t be such an issue if there weren’t unmapped plug-in parameters, like Parameters 14 and 21 below:

So, my question is, do either of the MR_HostPluginParameterBank Zone or MR_HostPluginParameterBankValue classes have methods for:

  1. Returning a number that represents a plug-in’s number of active parameters (from my previous post)?

  2. Binding a chosen parameter’s value to a surface value, say, Parameter 6 to parameter knob 2?

  3. If you’re keeping the existing sequential order of binding new parameter values, is there a way to skip/ignore the unmapped parameters, such as adding Parameters 1, 2, 3, …, 13, 15, 16, …, 20, 22, 23, … in the example above?

Sorry for the long posts - I hope they make sense! :roll_eyes:

I see no automatic way to do this.
The way I dealt with it is by creating maps of controls for each effect. At first I finished with channelStrip plugins, but with third party vsts I left it for now :slight_smile:

Long story short, you do something like this:

mapOfStripControls[constSubPageCompressor]['Standard Compressor']=[0,1,2,3,19,4,18,5,6,7,8,9,10,11,12,13]

The numbers you see in this list are some of my controller’s knobs/faders/buttons.
I have assigned these controls to custom variables. When these variables are triggered, I’m searching their index in the above list to alter the value of another custom variable binded to the specific param of the plugin.

I guess it’s a bit complicated, but it works,though not auto obviously :frowning:

Check my video, you’ll see params changing on the screen while I’m turning knobs in not a serial way (sorry, this is out of view unfortunately):

Hi @m.c !

Thanks for your response.

I’m happy to say that I believe I’m getting closer to a solution. I’ve finally sorted out accessing a plugin’s automatically-generated param labels (the Main Label field in the Remote Control Editor) and add them to an array. There always seems to be duplicate param controls assigned to a plugin, so I think the next step will be to filter the duplicate params from the array, leaving unique params only, then use the array’s param elements somehow when mapping surface parameter knobs to the unique params.

Like you, I think this process is unnecessarily long and convoluted. I’m glad to see you’ve worked out a solution that works for you. I believe the MIDI Remote API is a continuallly-evolving project for Steinberg, so hopefully these posts will help inform their development.

Ηi again, just some notes-warnings:

As I’ve said earlier, I’ve mapped all channelStrip effects. This works great!

However, concerning insert effects and plugin parameters and though I’ve successfully mapped some of them, just for testing puproses, you have to deal with it creating your own banks/shortcuts system and that apart from time consuming, can lead to mapping errors when for e.g. a plugin is updated and its params are reindexed. This might cause issues and can turn our project not easily maintainable. I have some thoughts on this one, which I’m going to present in detail once I upload my Arturia Keylab MK2 script and see what other users think about them.
.
So, for now, I’ve turned to mapping these plugins in the default way, i.e. makeZones and banks of zones. This way, unfortunately I map everything to faders and knobs, while it is obvious that a button should be mapped to a button, a fader to a fader and a knob to a knob in my opinion. But at least it doesn’t suffer from the issue described earlier.

Now, concerning the duplicates you see and I’ve noticed too, I believe this may be intentional in order to keep some of them in other banks as well. But who know?

I completely agree with you, this API is in evolving state, and I find the whole process great :slight_smile:

Ah, the Endorphin rush when it all… finally…works! :slight_smile:

2 Likes

So, I wonder what would happen if different MIDI CCs are bound to duplicates of a parameter?

I think expanding the makeParameterValue() method to include a parameter number (makeParameterValue(parameter number)), or even better, a parameter label (eg. makeParameterValue(‘RevTime’)) could provide a way to accurately choose, map and bind plug-in parameters to surface elements and MIDI CC or note events and avoid duplicates.

I’m looking forward to checking out your script!

In the latest version of my script, I abandoned the mapping process of plugins (except from the EQ and pregain). So, now, exactly as you say, multiple CCs trigger the same (duplicate param). I don’t know exactly the internal handling but it works fine, at least so it seems. (Perhaps it duplicates the step of change but I haven’t noticed something bad)

Very good suggestion! I have another one as a feature-request about the type of the param to bind to. To me, it’s much better to bind a button to a button and so on.
https://forums.steinberg.net/t/mparameterbankzone-additional-property/831806

Now, if you really want and have the time to map your plugins, I’ll tell you about my initial script:
I was creating a gigaintic paramZone (I was looping through 200+ params with makeParameterValue) as if my controller surface supports this size.
By using in testing the sub

param.mOnTitleChange=function(activeDevice,activeMapping,pluginName,paramName){}

I grabbed every parameter. When finished, I created multiple customVars (200) and I’ve mapped the ones to the parameters I wanted, avoiding duplicates and also, correctly mapping buttons to buttons and so on.

However, I worried about the consistency of so many params getting handled and this is the reason I abandoned it, apart from the possibility of the plugin’s creator, changing params.

If you think you want to try this approach, I can share the code, no problem :slight_smile:

Hi saxmand,
have you found a solution on how to enable and choose channel strip effects by scripting?
Thanks in advance, Emre

No. I’m using SoundFlow scripts for now.
Hopefully we will see much more stuff in the MIDI remote in C13/N13.

What a pity, many thanks anyway!

Soundflow works with Cubendo? I thought it was just Pro Tools

It works with any program in MacOS.
It just doesn’t have a lot of build in functionality. So it takes a bit to get more out of it.
I think where it definitely beats KeyboardMaestro is the fact that it has surfaces available, so you can use your iPad to control commands.

Works with most of my VSTi but with some plugins I am unable to save my settings after „learn“, they allways switch to their initial settings (Ps-20, Retrologue2…