Again, thanks for your job.
With Cubase 12.0.60 and your script 1.5.0, channel names are still buggy: they only refresh when I select the track (so I need to select all of them each time I switch fader banks). Also, unused faders still display the name and color of the previous track used by this fader.
Finally, would you mind adding an option to activate/desactivate .excludeWindowZoneLeftChannels() and .excludeWindowZoneRightChannels()? It would be awesome when the .setFollowVisibility(true) will finally work
Thatās unlucky. Interestingly though, the v1.5 workaround works on my dev machine and (reportedly) for another user on 12.0.60. I could invest more time to see if I can find another workaround, but without being able to reproduce it, that time may quite possibly be wasted. I think youāll have to revert to CB 12.0.52 then (Cubase Pro 12 Downloads | Steinberg) until Steinberg fixes the issue.
Makes perfect sense I just added a set of visibility config options locally, just to find that neither .excludeWindowZoneLeftChannels() nor .excludeWindowZoneRightChannels() do currently work, which has already been reported last year (MIDI Remote - Mixer Bank follow visibility not working? - #3 by Jochen_Trappe). Iāll release the new options once they actually work in Cubase.
Kidding aside, there seems to be nothing we can do about it despite deleting the second surface when it gets too annoying. I guess weāll have to live with it when switching projects.
Ok thank you for the reply, not that bad in the end. One functional question: I have some of the function buttons set up for toggle functions. Is it somehow possible to edit the code so that they behave like that (light on/off)? If so - where would I do that?
Thanks again:)
This works out of the box for host values (e.g., Selected Track > Edit Instrument). For key commands, thereās no way to retrieve the underlying host state, so toggling the light ā while achievable script-wise ā would be meaningless. A good example for this is the PUNCH button which is bound to āTransport > Key Commands > Activate Punch Inā. Thereās no way the script can know whether āPunch Inā is active, so blindly toggling the light might not reflect the actual āPunch Inā status in Cubase. The same thing applies to all function buttons: Either they reflect the host state automatically, or thereās currently no way to make them reflect itā¦
Exactly this.
Took me some time to workaround this, by adding a generic remote just for such things, in case anyone would bother to play with this. This way my script receives such states now, but this is NOT the way to go. I think they should and hopefully be added in a next updated API.
The main problem I see with the midi remote and button states is, that the midi remote is NOT loaded at Cubase start. It is loaded AFTER a project. If the midi remote would be loaded at Cubase start, it would be easy to have all the button states, that are currently not known to our scripts. If there is a initial state (and I believe there is) of Cubase functions and buttons that are set, before a project is loaded or a new one created, then we would not need to take care about these problems and it would be a LOT easier to handle these cases.
Once a project loads, it should return values for ALL the states, buttons, faders etc. This way every midi remote should be properly āARMEDā and donāt need complex written state machines in the script.
It does return these values when you actually want to read them in your script. It is up to you to select which ones to grab, this is why you should do it inside the appropriate events. I do it all the time, solo,mute,arm,volume,pan etc etc.
I think you underestimate (same like me, to be honest) how hard are some situations to handle. My post was mainly a answer to @bjoluc and @David_781 observations. There are many buttons where you can not grab or receive the current state easily or without state machines you would need to write in a script. Solo, Mute, Volume or Pan are easy stuff .
If youāre talking about states that are not available via the API yet, of course youāre right. Other than that, which other states are you referring to? Can you give me an example, so that I can understand the situation better?
Yes, I will give you some examples. States become essential, once you want to use lights,lamps,LEDs etc.
Basically real world objects that should reflect situations visually for the user.
So letās say you want to use a red light/lamp as soon as record in the transport field is selected. Now letās assume, you want the same red light/lamp to start blinking, if the record button in the transport field is enabled AND the song is playing.
Try to script that and you will very fast see, that you canāt establish this, without writing very much code for such a simple function.
Oh well, even if this is not an example of a hostValue, I can provide you some code for this function here, and I donāt see it as a big one
page.mHostAccess.mTrackSelection.mMixerChannel.mValue.mRecordEnable.mOnProcessValueChange=function(activeDevice,activeMapping,value){
activeDevice.setState("selectedTrackArmed",value.toString())
//if not armed, do what you want with your led
// no big deal here, actually we most of the time want this function in order to change our "record-arm" leds
}
page.mHostAccess.mTransport.mValue.mStart.mOnProcessValueChange=function(activeDevice,activeMapping,value){
activeDevice.setState("isPlaying",value.toString())
//if not playing, do what you want with your led
//again, we always enter this sub, since we want to change the "Play" button's led
}
page.mHostAccess.mTransport.mTimeDisplay.mPrimary.mTransportLocator.mOnChange=function(activeDevice,activeMapping,arg2,arg3){
if(activeDevice.getState("selectedTrackArmed")=="1" && activeDevice.getState("isPlaying")=="1"){
var indexOfBeat=arg2.indexOf(".")+1
var beat=parseInt(arg2.substring(indexOfBeat,indexOfBeat+2))
var prevBeat=parseInt(activeDevice.getState("beat"))
if(beat!=prevBeat){
//toggle your led here. If you want a more frequent toggle, instead of beats, you can try 16ths or the even smaller unit
}
}
//I personally use this sub always in order to get to my display current transport location
}
To be honest, I donāt have much clue about scripting with API. Here is the code from someone who helped me with this:
// Write Automation Test for UMan
//this.chanStrip
//this.func
// Write Automation Test for UMan
var selectedTrackChannel = page.mHostAccess.mTrackSelection.mMixerChannel
var self = this;
selectedTrackChannel.mValue.mAutomationWrite.mOnTitleChange = function (context, mapping, text1, text2) {
self.selectedTrackName = text1
console.log(text1)
console.log(text2)
}
// Set the state of the selected track's Write Automation State
var self = this;
selectedTrackChannel.mValue.mAutomationWrite.mOnDisplayValueChange = function (context, mapping, text1, text2) {
switch (text1) {
case 'Off': self.writeAutomationState = 0; break;
case 'On': self.writeAutomationState = 1; break;
}
console.log(text1)
console.log(text2)
if (self.writeAutomationState == 0) {
writeAutomation.setLedOff(context)
} else if (self.transportRecordState == 0) {
writeAutomation.setLedOn(context)
} else {
writeAutomation.setLedFlashing(context)
}
}
var self = this;
var writeAutomation = mackieC4.spotErase;
var writeAutomationCvv = mackieC4.surface.makeCustomValueVariable('writeAutomationCvv');
page.makeValueBinding(writeAutomationCvv, selectedTrackChannel.mValue.mAutomationWrite).setTypeToggle() // Spot Erase button || .setValueTakeOverModeScaled()
writeAutomation.button.mSurfaceValue.mOnProcessValueChange = function (context, newValue) {
console.log('writeAutomationProcess_value')
if (newValue == 1) {
self.writeAutomationState = 1 - self.writeAutomationState;
writeAutomationCvv.setProcessValue(context, self.writeAutomationState);
console.log(self.writeAutomationState.toString())
}
if (self.writeAutomationState == 0) {
writeAutomation.setLedOff(context)
} else if (self.transportRecordState == 0) {
writeAutomation.setLedOn(context)
} else {
writeAutomation.setLedFlashing(context)
}
}
var self = this;
var transportRecord = mackieC4.chanStrip;
page.makeValueBinding(transportRecord.button.mSurfaceValue, page.mHostAccess.mTransport.mValue.mRecord).setTypeToggle() // Spot Erase button || .setValueTakeOverModeScaled()
transportRecord.button.mSurfaceValue.mOnProcessValueChange = function (context, newValue) {
console.log('transportRecordProcess_value')
self.transportRecordState = newValue;
console.log(self.transportRecordState.toString())
if (self.writeAutomationState == 0) {
writeAutomation.setLedOff(context)
} else if (self.transportRecordState == 0) {
writeAutomation.setLedOn(context)
} else {
writeAutomation.setLedFlashing(context)
}
}
var transportStop = mackieC4.function;
page.makeValueBinding(transportStop.button.mSurfaceValue, page.mHostAccess.mTransport.mValue.mStop).setTypeToggle() // Spot Erase button || .setValueTakeOverModeScaled()
transportStop.button.mSurfaceValue.mOnProcessValueChange = function (context, newValue) {
}
return page;
}
The only difference was, that the lamp/LED was bound to write automation and in case of record playback, it is flashing. As you can see, this code is much larger. If I do the same with BOME Midi Translator, I have just four lines of code.
Hi there, Iām very interested to know more details on this. BUT,I feel like weāre abusing this thread which is for a specific shared script. If you have the time, could you please open a new thread (by the tag Midi remote or even in the Lounge), with both the above code AND the BMTās one,so we can have a better look there? Iām always interested in optimisations
It might look like abusing, but I donāt think so. I donāt own a X-touch, but I am pretty sure, that the lamps are working all the same, as it is MCU based (X-touch and even the C4 from my script. Just in case people donāt know, but on a real MCU, every Lamp can have three states: off, on and flashing (cc 0, 1, 127).
And I am still referring to post 45 from this thread, that brings up the problem of not knowing the states of some important functions and therefore problematic visual reflect of these states, be it lamps,LEDs,text etc.
Just to say I was running this script on a standard MCU last night, and it works pretty well on original hardware too. Doesnāt make full use of the commands, but I managed to add a page for the āselected trackā destinations via the surface editor and even that worked, which surprised me.
So, itās easy to get the full panel (i.e. pots and faders) to control plugins and instruments too, if anyone is curious. Shame about the bug in 10.0.60 though, hopefully SB get this fixed ASAP.
@skijumptoes Thatās great news! Iāve been toying with the idea of supporting other MCU-speaking devices a few times. Script-wise, that shouldnāt be too much of a problem but Iām unsure for a couple of reasons:
I only own X-Touches
The original motivation for the script was to make Cubaseās MCU implementation X-Touch specific, although I came to notice that most of the scriptās advantages apply to other devices too.
I donāt want to over-generify the project. On the other hand, implementation-wise, it is farily generic already.
I realize adding support for other devices would mostly mean adapting the surface layout, so I wonder if it would even be worth it as the devices should already work without the script explicitly supporting them. I also wonder how many people would be interested to see more devices supported. @skijumptoes You should be able to get padding characters by searching the script for the abbreviateString function definition and replacing the hardcoded 7 with 6, for what itās worth.
Thatās right. I think your blinking-button use case is better discussed in another thread though, so we donāt annoy everyone watching this thread for updates related to the X-Touch script