I’m going to edit this here reply with some more info in a few minutes, such as some code that Trevliga gave me today that he says should do it. But I haven’t tried it yet, and I want to show you first.
Ah, sorry I have no idea of how this console works…
I have a LoupeDeck CT here, I think I’ve worked on its encoders some time ago, I will have a look. I would have to check its MIDI implementation.
If he says it works, it should work If not, I can have a look at how StreamDeck handles the encoders initially and report back, no problem.
Here’s the code he gave me:
[(config){TriggerOnLocalMidiEvents:No}]
[(init){@l_fadervalue:0}{@l_currentstep:0}]
[(rotate)
{@l_currentstep:#RANGE(@l_currentstep + (ABS(@e_tics) * @e_tics), 0, 300)#}
{@l_fadervalue:#@l_currentstep * (16383/300)#}
{nrpn:12, 110, #@l_fadervalue#}
{fader:#@l_fadervalue#}
{text:#@l_fadervalue#}]
[(nrpn:12,110,*)
{@l_fadervalue:#@e_nrpnvalue#}
{@l_currentstep:#@l_fadervalue / (16383/300)#}
{fader:#@l_fadervalue#}
{text:#@l_fadervalue#}]
It’s one thing if it works on the db knob, but it’s another thing to understand how it works so that we can apply it across the board to other controllers such as frequency knobs, shelf buttons, etc.
whenever he’s using a lowercase L with the @ before it, it’s a local variable. Whenever it’s got the # brackets, that is required to access the value of the variable as an integer or float, instead of just being able to type the variable name itself.
Every event runs inside brackets like [ ] which is what the “rotate” event is doing. Every one of those actions in { } brackets is happening all at the same time when a rotate event occurs.
So, what does this code log if you enter Cubase and inspect the MIDI Input? Remind me please, are you on CB14?
I’m on C14 and I’m going to try your request and reply shortly
I was working on what might be the longest reply I’ve ever written in my lifetime. I was researching things as I was typing, and it took me, off and on, probably over 5 hours to create the reply…and I never sent it.
The reason is that I’ve realized some things in that process, and now I’ve created a new issue that I need to resolve before I present my new “system” for high resolution MIDI, while we wait for MIDI 2.0. The wait is over - we don’t have to wait any longer, as this method that I’m trying to devise can give users Eucon-level resolution with their standard MIDI encoders, so long as the encoder can support NRPN, and as long as it can support routing each encoder to its own MIDI port.
Before I present my behemoth post (I’ll likely create a new topic due to its size and importance to me), I would like to ask you guys some clarification on how the MIDI ports work in the scripts: They are direct references to physical MIDI ports and cannot use virtual ports made inside the script, is that correct?
In other words, if we wanted to have virtual ports, we would have to do so outside of Cubase with a 3rd party like BOME or loopMIDI, then connect each one to a different encoder in our script? Vs being able to create an internal virtual port inside the script, that only the script sees?
P.S. To you guys, it won’t be anything new or exciting, since you guys already devised your own solutions. I’m looking to bring a more standardized way for the everyman user, which is also why I’m looking to standardize what an increment means, and what it represents in terms of steps. I’ll present more on this later.
In a nutshell, the new issue I’m dealing with is the realization that CC#6, the data entry controller for the MSB (most significant bit), is being shared by multiple encoders at once, unless each encoder has its own CC#6 to use exclusively.
This is almost for sure the reason why anybody who has ever complained about NRPN issues with Cubase has the issue.
Because the LSB has 32 different CCs it can use (from CC#32 - CC#63 range) but the MSB has only that one CC#6.
Even if we use different MIDI channels, that’s no good because those channels get used by other things and we need exclusive access to CC#6 for each encoder, so that the MSB is not trying to write to multiple encoders at once, or the request gets mixed up and weird stuff happens.
Hey!
I can answer some of you questions.
A physical MIDI device typically only employs one MIDI Port. It’s the equivalent of a 5-pin DIN MIDI Out connector. There are some exceptions where MIDI keyboards separate remote control features and traditional MIDI into two ports over USB.
Not necessarily “physical” ports. Rather MIDI ports defined at the operating system level. They can be physical or virtual.
Correct. However I’m not sure you can create MIDI ports inside a MIDI Remote script that are not connected to an OS level port.
There are some errors in your assertion here. MIDI CC #32-63 are LSB for MIDI CC #0-31 according to the MIDI v1.0 standard. This means that the controller #7 (Channel Volume) for example can have its resolution optionally extended by the use of controller #39. Note that this extended resolution technique is not what is defined as “NRPN”.
NRPN (Non-Registered Parameter Number) is defined as a four separate messages¹. First, two messages are sent to define the parameter number followed by two messages for the parameter value. Both the parameter number and value are 14 bits in size. Here’s an example:
Parameter: 12031
, Value: 9820
CC number | CC value | Description |
---|---|---|
98 | 127 | Parameter number LSB |
99 | 93 | Parameter number MSB |
38 | 92 | Parameter value LSB |
6 | 76 | Parameter value MSB |
¹ The use of “Running Status” may negate the need to send the parameter number when transmitting multiple RPN/NRP messages with the same parameter number.
You just listed part of my huge post that I haven’t posted yet, regarding your NRPN example at the bottom there. The part I was referring to was your last lines, CC#6, and CC#38, working together as sort of a “high resolution value engine” as I call it in my upcoming post, and that once they are working on one encoder, they should not be used for a second encoder at the same time, unless that second encoder is on a separate port or channel. The channel could work, since CC#6 is different on Channel 5 than CC#6 on Channel 8, but with all that traffic running on the port, users were having lots of issues with NRPN messages getting scrambled up.
As for the 1 port per controller thing, we have full control over the port definition per encoder or fader in the script, and I have the ability to assign a different MIDI port to every button and encoder on my Stream Deck+.
I just create a new virtual MIDI port with loopMIDI for every new port I need, then I can assign it at the bottom of the Stream Deck’s MIDI plugin.
With this in mind, I want to tell the MIDI remote script to specify which of the virtual ports will be used for each and every encoder, so that I can have high resolution on every encoder without any interference, if that makes sense.
Then, after I get the Stream Deck+ figured out, I want to build an Arduino controller that uses the same logic, to make a custom controller later.
If we are talking about NRPN (or RPN) messages, what is missing from your assertion is the parameter number. As I said in my previous post, an NRPN message must transmit the parameter number as two separate MIDI CC messages. This gives you a total of 16,384 unique NRPN parameters on a single MIDI channel.
If you’re not using NRPN specifically, you can have 32 unique 14-bit values by using CC#0-31 for the MSB together with CC#32-63 for the LSB. Utilizing all 16 MIDI channels, this gives you a total of 512 unique 14-bit values while still conforming to the MIDI v1.0 specification.
There is nothing that says you can’t disregard this specification and use all available CC numbers as MSB/LSB pairs. If you do, you would get 64 unique 14-bit CC values per channel or 1,024 in total.
I see - thank you for that info. So don’t necessarily consider NRPN being the only thing being able to equal a 14-bit value then?
I happen to be using NRPN, and you mentioned not using it specifically, but I’m curious to know how I’d even approach doing 14-bit values without NRPN.
Usually, I just set the type to NRPN vs CC, and it picks CC#38 for me automatically on my controller. I think that is where I misunderstanding. You’re saying I can change those numbers and not even use NRPN to get 14-bit values, but still use LSB and MSB?
You might be a little smarter than I am, so you might have to dumb it down a little. You guys are way above where I’m at in all of this. I’m the guy who tries to innovate or come up with ideas, and has nowhere near the skill level to pull off any of my crazy ideas.
For my needs I don’t concern myself with bit depth of controller values. I use relative MIDI CC messages. Basically, my controller sends a +1 for every “click” on the encoder turned clockwise and a -1 for every click counterclockwise. This means I can have any type of resolution I want when I write the MIDI Remote script. I can choose to have +1 from my controller increment the EQ Gain by 0.1dB or 5.0db if I so choose.
I don’t know. It’s really up to your controller what it is capable of sending.
But like I said before, there are 16384 NRPN parameter numbers available on one single MIDI channel. I can’t imagine you need more than 262,144 unique 14-bit parameters, do you?
No, I don’t need that many - in fact, I was looking to use NRPN more as a table to store values in ranges/sections, and use the same NRPN for several dB knobs at once. Such as 1-301 being the 301 steps for dB knob 1, 302-603 for dB knob 2, etc. But doing it that way is where I ran into the issue of having not enough CC#6s generating independent data for all the different NRPN encoders that were requesting CC#6 for each parameter (not independently, but as part of the 1-2 combo that it uses together with CC#38 to generate the 14-bit value each time). I’d have to either have to use different MIDI channels per encoder, or different ports.
We’re talking about the difference between what should theoretically work, and what actually works well in Cubase, regarding NRPN. But doing it your way is great, if you want to script each and every individual thing. What I’m looking to do is standardize it so that everybody can use it, and in order to do that, I have to run polls and ask people what they expect to see when they turn the dial.
I also have to try and persuade people to stop using tiny fractions of dB amounts, and the frequency poll showed that everybody wanted 1.1khz to be the next value instead of 1.01khz. Even though Waves and most plugin companies use 1.01khz next. Anyway…I’ll have something to release for Stream Deck+ owners here soon (it’s a high res SSL console controller that can do things that are unique, and don’t run out of knobs or buttons).
P.S. I have a MIDI Fighter Twister profile and I use the Stream Deck to switch banks on the Twister, since accessing those side buttons is tricky in my setup.