NRPN question

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Hello,

I'm working on the NRPN implementation for a synth at the moment.
I'm a little bit confused about the right way to implement it, since a lot of hosts don't handle NRPNs really good, and the implementations vary a lot.

I have problems using the Data Entry Slider CCs.
the spec (http://atom.maczo.pl/~atom/stuff/tech/midispec.htm) says:
Number: 6 (coarse) 38 (fine)

using fruity loops as host, this works as long as the value range is >127.
then fruity loops is sending both controllers, 6 and 38, with the right value (6 = upper 7 bit, 38 = lower 7 bit).

but when i define a range below 127 only the coarse value is send.
this confuses me, because when using a 14 bit value, the coarse value is shiftet 7 bits to the left. so for a parameter with the range 0-10 i get nrpn messages from 0-1280 with a step size of 128 out of fruity loops.

It works if i omit the left shift, but I'm not sure how other host and controller softwares handle the nrpns. so whats the right way to do this?

julian

Post

The FL implementation you have observed does has a fair point. If the range is 127 or less, then it's sufficient to use the MSB only.

You could make it configurable btw, just in case the receiving synth expects the payload in the LSB instead of the MSB.
My MusicCalc is temporary offline.
We are the KVR collective. Resistance is futile. You will be assimilated. :borg:

Post

so i'm on the safe side if I omit the left shift for ranges below 128?
is this the way NRPNs should be treated?
Are other hosts and controllers using this scheme, too?

julian

Post

Theoretically (since I don't know all hosts) but any MIDI CC that have the coarse/fine pair work the following: You send the coarse value, and then the fine. For small adjustements, you keep sending the fine (CC # and value). When you need to go further, you send again a MIDI CC # for the coarse, with a vlue inscrease of 1, and again the MIDI CC # for the fine, Let's say you want to perform a volume crescendo, using the coarse and fine values. You send MIDI CC # 7 with a value of 64, then keep sending MIDI CC # 38 with increasing values from 0 until 127, Then again a MIDI CC # 7 with a value of 65, and again MIDI CC # 38 with values from 0 until 127, etc.
If you only need a range from 0 to 127, then you just ignore the fine MIDI CC and use just the coarse MIDI CC (for the volume, for example, almost all the builders use just the coarse MIDI CC).
NRPNs, AFAIK, work pretty much the same way. I presume that, in absence of a value for the LSB, it fills it with a value of 00.
Fernando (FMR)

Post

ok - thanks for the clarification :-D

Post

Hi there,

sorry for bumping an old thread, but there is still one point which confuses me about NRPNs:

As far as I understand it so far, the order of sent data messages is: first MSB and then LSB.
However, the description says that the LSB is optional, and can be omitted if only a resolution of 128 values is required.

Now, when I am receiving NRPN messages, how do I know whether a LSB message is going to come or not?

If I decide to wait for the LSB, and only do something with the complete message, i.e. 128*MSB + LSB, then I might wait forever, if the controller decides to send only the MSB.

If, on the other hand, I want to act immediately on the MSB data, then I will first use the rough data (128*MSB) and then, after receiving the LSB I set the parameter to the complete value 128*MSB+LSB, which surely would lead to strange cracks in the sound...


Another point, I am wondering about, is whether I should allow the user to use CC's 6 and 38 (and accordingly the ones for setting the NRPN or RPN number) directly for MIDI Learn, or whether I should disallow them and reserve them for NRPN/RPN?


Any thought on this are welcome.

Thanks,
Martin

Post

Status bit, I think. (All MIDI status messages have MSBit bit on. That's why controller and key values are out of 128 instead of 256).

Just off the top of my head though, I haven't implemented them yet so there could be more to it than that.

Incidentally, that's also how "Running Status" works and the reason why note-on velocity 0 means note-off. This way notes can be packed together without having to send a new Status byte.

(Note that most hosts I'm aware of convert running status to regular 3 byte MIDI messages automatically.)

Post

hi Admiral,

thanks for the response.


I am not sure whether it is the status bit, as this is filtered out by the host. I made some tests, which puzzle me even more...

I used: reaper, arturia modular, and ipad with TB Midi Stuff as controller. In the plugin, I used Midi Learn to assign a NRPN for some parameter. In the TB Midi Stuff, I set up two sliders, one sending NRPN with fine control (MSB+LSB), and one sending only the MSB. I "trained" the plugin with the MSB+LSB slider. Monitoring the MIDI messages shows that the controller sent always groups of 4 messages (NRPN num MSB+LSB; DATA MBS+LSB).

Then I used the slider, which sent only the MSB data (and indeed, the MIDi monitor showed only groups of 3 messages)

Still, the plugin reacted promptly on the messages.

The groups of 4 (or 3 respectively) always had slightly different time stamps. So, I am still wondering how the plugin knows what to expect. Is there some (short) time-out at work? I.e. the plugin waits for a 4th message within a given time, and if it does not follow, reacts on the MSB only. Or does it simply ignore the LSB message?

Any ideas?

Cheers,
Martin

Post

I don't really know about NRPNs, but I have come across a similar problem with MSB/LSB CC values, where I also don't know whether MSB only or MSB+LSB is going to be sent. What I do is I track both the MSB and LSB values, but I initially set the LSB value to 0xFF to indicate it is undefined. If I receive the MSB, and the LSB still has its undefined value, then I assume MSB only (i.e. normalized value = MSB / 127). If I receive the LSB, then I assume MSB+LSB (normalized value = (tracked MSB * 128 + LSB) / 16383). If I receive the MSB, and the LSB has a valid value, then I assume MSB+LSB (normalized value = (MSB * 128 + tracked LSB) / 16383).

Post

FL should not mess with the meaning of MSB bytes.

To my mind it should be as simple as MSB is MSB and LSB is LSB. So you don't care if you receive one in front of the other you just place it at the right position of the 14-bit value. You could default the LSB to some value you like because that is not always used (specs say you need to set LSB to zero if an MSB is received - that also suggests you send MSB first) but the principle should stay the same (and simple).

[2c]
Grtx, Marc Jacobi.
VST.NET | MIDI.NET

Post

Tale wrote:I don't really know about NRPNs, but I have come across a similar problem with MSB/LSB CC values, where I also don't know whether MSB only or MSB+LSB is going to be sent. What I do is I track both the MSB and LSB values, but I initially set the LSB value to 0xFF to indicate it is undefined. If I receive the MSB, and the LSB still has its undefined value, then I assume MSB only (i.e. normalized value = MSB / 127). If I receive the LSB, then I assume MSB+LSB (normalized value = (tracked MSB * 128 + LSB) / 16383). If I receive the MSB, and the LSB has a valid value, then I assume MSB+LSB (normalized value = (MSB * 128 + tracked LSB) / 16383).
Thanks, but I am still wondering whether with this mechanism, your LSB value is lagging behind ?

Assume you start from scratch, i.e. both MSB and LSB are initialized to 0xFF.

Assume, you recieve the following sequence of messages:

MSB: 1
LSB: 32

MSB: 2
LSB: 64

MSB: 3
LSB: 96

MSB:5
LSB: 0

etc., which should give rise to a linear slope.

Now, as you don't know whether you are ever going to receive a LSB message, you need to act on the first MSB and use the value 128*1 + 0 = 128.

DO you then, when you receive the LSB act again with 128*1 + 32 = 160 (which would be the value you want)?
You would then set the LSB tracker to 32.

On the next MSB you would use 2*128+32 = 288, and only on the next LSB get the full 2*128+64 = 320. And so on...

The biggest "error" would be on the MSB=5, LSB=0 event, where you would first use an MSB=5,LSB=96 value, before you get the correct value of MSB=5 LSB=0.

You see that this generates a number of spurious events with slightly wrong values. Are you somehow filtering them out? (I would not see how..). Or do you rely on the fact that this small "noise" disappears when smoothing the parameter changes through a simple filter?

As I am smoothing all parameters anyway, I think that it is not really an issue, and will try to implement your method tracking the LSB and MSB values (obviously separately for each parameter).


Cheers,
Martin

Post

Not 100% positive of this, but won't both the MSB and LSB messages be sent with the same timestamp? If you received [MSB=4, LSB=1] and [MSB=3, LSB= 96] in the same timestamp, you'd have to react on the values that you received last anyways. If you receive [MSB=5, LSB=90] followed by [MSB=6], then without receiving a final LSB, you can only assume LSB=0.

Post

Jimbrowski-one wrote:Not 100% positive of this, but won't both the MSB and LSB messages be sent with the same timestamp? If you received [MSB=4, LSB=1] and [MSB=3, LSB= 96] in the same timestamp, you'd have to react on the values that you received last anyways. If you receive [MSB=5, LSB=90] followed by [MSB=6], then without receiving a final LSB, you can only assume LSB=0.
At least, according to my MidiOx monitor, they did not have the same time stamp. They were close, so, I guess, one could implement a certain timeout. If both occur in the same buffer, it should be ok. It could only be problematic, if they appear in different blocks.

Anyway, I hope that I have some time next weekend, to try the tracking and smoothing method...

Cheers,
Martin

Post

MIDI events aren't timestamped. (The host timestamps them when it receives them. But two MIDI messages can never come in at exactly the same time as it's a serial interface and at a relatively slow baud rate.)

I'm not sure what happens to NRPNs when passed through a host, as I've never had a controller that sends them to test with. What are you using, Martin?

I'm guessing you just wait for the LSBs to update your value. :shrug:

Post

martin_l wrote:You see that this generates a number of spurious events with slightly wrong values. Are you somehow filtering them out? (I would not see how..). Or do you rely on the fact that this small "noise" disappears when smoothing the parameter changes through a simple filter?
Yeah, I am relying on a smoothing filter that is already there anyway. However, I have just checked, and the filter's output still looks rather whobbly.

My colleague suggested also keeping track of the previous MSB value, so you can check if the MSB value went up or down. If it went up, then you set the LSB value to 0. If the MSB value is smaller than the previous one, then you set the LSB value to 127. That way the 128*MSB+LSB value will at least move into the right direction. The drawback here is that if you ever come across a MIDI controller or host that sends the MSB/LSB values in the wrong order, then the LSB value is effectively ignored, but at least the MSB value is still processed immediately.

Post Reply

Return to “DSP and Plugin Development”