NRPN tutorial / How to
Controlling synth parameters via CC Midi messages is well explained in many places. When one of my synth had a parameter that is controlled with NRPN, I struggled, even with the help of Google. Having spend on this several hours, I want to share with you what I learned.
My goal is to cc automate the Filter Envelope Depth of my synth (Hypersynth Xenophone) from my sequencer (Squarp Pyramid). The hardware does not really matter here, the question is general, although there are details of the hardware, that make a difference.
From the user manual EnvD is controlled by NRPN 9, with a range of 0-1000. The synth manufacturer tells me on his website that the maximum resolution in NRPN mode is 12 bit.
Turning the EnvD knob on the synth changes the values between -50 and +50. (I want to modulate it between -30 and 0, or thereabouts).
If supported by your synth, NRPN is going beyond conventional MIDI CC modulation, allowing finer resolutions (beyond values in the range of 0-127). To this end more than one item of controller data need to be send.
First, with CC99 one sends information about the Most Significant Byte (MSB), followed by CC98 sending the Least Significant Byte (LSB). With the combination of these two values, one can control up to 128x128=16384 parameters.
Most confusion arises from getting the MSB and LSB values right. This has to do with the fact that one actually needs to understand hex code. The challenge is thus to explain this without conversion of hex code
Taken together, the MSB and LSB messages specify the parameter # that I want to control (in my case “9”). This then requires further information about the values I want this parameter to take.
CC06 (data entry MSB) send the value of the parameter (“coarse”) and CC38 (data entry LSB) may be used to send fine adjustments of the values of the parameter that we want to control. Then there is also CC96 (data inc) and CC97 (data dec) that could come into play.
On my sequencer I use the first step of a sequence to send a value for CC99 (SB), on step 2 a value for CC98 (LSB) and on step 3 and further value(s) for CC06 (the parameter value).
The first step is thus to determine the CC99 value for the MSB:
Parameter # = 9 in my examples, thus 9 / 128 = 0.0070, from which we keep 0 as MSB.
For the LSB (CC98), we calculate 9 - MSB*128 = 9
To take another example, if the parameter # is 1570, then 1570/128=12.265625, from which we keep 12 as the MSB. 1570-MSB*128=34, which gives us 34 as the LSB.
So, while I got all that right, it seems, the challenge is to get the data entry MSB and LSB correct, that is, the CC06 and CC38 values, which together determine the value of the parameter (here Filter EnvD).
Struggling with this, I contacted the person who develops the Hypersynth Xenophone. It seems that one advantage of such boutique synths, is that the developers respond extremely fast. I expected several days, or no response at all but got and answer while I wrote this note.
Now, his answer is that if you transfer one byte “CC06” only a portion of the range will be changed in a quantised way. So you must configure your system/device to transfer two bytes. He then gave a few examples:
ENV depth = -50.0 >> value = 0
NRPN MSB: CC99 = 0
NRPN LSB: CC98 = 9
Data Entry MSB: CC6 = 0
Data Entry LSB: CC38 = 0
ENV depth = -30.0 >> value = 199 *
NRPN MSB: CC99 = 0
NRPN LSB: CC98 = 9
Data Entry MSB: CC6 = 1
Data Entry LSB: CC38 = 71
ENV depth = 0.0 >> value = 500 *
NRPN MSB: CC99 = 0
NRPN LSB: CC98 = 9
Data Entry MSB: CC6 = 3
Data Entry LSB: CC38 = 116
ENV depth = 1000.0 value = 1000
NRPN MSB: CC99 = 0
NRPN LSB: CC98 = 9
Data Entry MSB: CC6 = 7
Data Entry LSB: CC38 = 104
Anyone seeing a pattern? I didn’t. My synth shows on the display values from -50 to +50, my nominal value is -22 and I want to modulate it from -30 to about 0. How can I set the CC6 and CC38 values for this?
First I need to translate the scale -50 to +50 into a scale from 0 to 1000. Plotting this on a x-y plane, I have a line with the equation y=10 x + 500, where x is the value of the knob in the synth display (what I put into the equation) and y is the NRPN value. For a value of -30, I get a NPRN value of 200. The question is now how to turn this number into values for CC6 and CC38?
Lets dive deeper into NRPN messages, consisting of four CC packets. E.g.
B0 63 04
B0 62 3C
B0 06 01
B0 26 23
The “B” are the first 4 bits, standing for Control Change (CC), followed by “0” which here is the MIDI channel 1. Each control change message has two bytes of data following it. The first byte determines the CC# we are changing and the second byte tells us the value that we are changing to.
Now, the numbers above are in hex form. If you add “0x” in front of them and put this into Google, it can convert it for you. Vice versa converting to hex, you can remove the “0x” in front to have the message. So, “63” is in fact “CC 0x63”.
The “63 04” then reads “Set CC99 to 4”. CC98 is then ox62 in hex, CC06 is 0x06 in hex and CC38 is 0x26 in hex. CC06 (“coarse control” or data entry MSB) and CC38 (“fine control” or data entry LSB) are what we need to focus on.
Say, I want a value of 199 for my parameter, in binary format this is 0b11000111. Splitting this up, the last seven bits give me the LSB for CC38, 0b1000111=71. For LSB CC06 we have “1” or “0b1” to be more precise, which gives CC06=1. As we will learn below, this corresponds to a knob value of my synth on its display of -30.1.
Taking another example from above, a parameter value of 500 is in binary code 0b111110100. Converting the last seven bits, 0b1110100, gives 116 for LSB CC38. What remains is “0b11” which is in decimal “3” for our data entry MSB (CC06).
Returning to my original quest, I want to know what a knob value of -30 on the synth display corresponds to in terms of CC6 and CC38 values. Translating the -50 to +50 “x scale” into the 0 to 1000 NRPN “y scale”, I have -30 * 10 + 500 = 200. Typing “200 to binary” into Google gives me “0b11001000”. The last seven bits are “0b1001000”. Typing “0b1001000 to decimal” into Google gives me 72 for the LSB or CC38=72 and “0b1” is 1 for the MSB or CC06=1.
For a EnvD value of 0, this corresponds to a value of 500 on the NRPN scale. “500” in decimal is equal to 0b111110100 in binary. Taking the last seven bits, 1110100 gives me CC38=116 (data entry LSB) and 0b11 or CC6=3 (data entry MSB).
Since I want to modulate my EnvD parameter between -30 and 0, I choose on my sequencer values for CC06 values between 1 and 3, and for CC38 values between 72 and 116.
I can now create a table and then programme my sequencer to automate the filter envelope depth:
-30: CC99 = 0, CC98 = 9, CC6=1, CC38=72
-22: CC99 = 0, CC98 = 9, CC6=2, CC38=23
-20: CC99 = 0, CC98 = 9, CC6=2, CC38=44
-10: CC99 = 0, CC98 = 9, CC6=3, CC38=16
0: CC99 = 0, CC98 = 9, CC6=3, CC38=116
… where the CC99 and CC98 values were calculated already above. The way I enter these on the sequencer is that I choose a step (e.g. 19), send on that step the CC99 value, on the next step the CC98 value and on the third step the two values for CC6 and CC38.
Uff, that was difficult and time consuming. I therefore hope this is useful and a time saver for others.
Best
Olaf