39 jassert (midiChannel >= 1 && midiChannel <= 16);
40 jassert (controllerNumber >= 0 && controllerNumber < 128);
41 jassert (controllerValue >= 0 && controllerValue < 128);
43 return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue, result);
48 for (
int i = 0; i < 16; ++i)
50 states[i].parameterMSB = 0xff;
51 states[i].parameterLSB = 0xff;
52 states[i].resetValue();
53 states[i].isNRPN =
false;
58 MidiRPNDetector::ChannelState::ChannelState() noexcept
59 : parameterMSB (0xff), parameterLSB (0xff), valueMSB (0xff), valueLSB (0xff), isNRPN (
false)
63 bool MidiRPNDetector::ChannelState::handleController (
int channel,
68 switch (controllerNumber)
70 case 0x62: parameterLSB = uint8 (value); resetValue(); isNRPN =
true;
break;
71 case 0x63: parameterMSB = uint8 (value); resetValue(); isNRPN =
true;
break;
73 case 0x64: parameterLSB = uint8 (value); resetValue(); isNRPN =
false;
break;
74 case 0x65: parameterMSB = uint8 (value); resetValue(); isNRPN =
false;
break;
76 case 0x06: valueMSB = uint8 (value);
return sendIfReady (channel, result);
77 case 0x26: valueLSB = uint8 (value);
break;
85 void MidiRPNDetector::ChannelState::resetValue() noexcept
92 bool MidiRPNDetector::ChannelState::sendIfReady (
int channel,
MidiRPNMessage& result) noexcept
94 if (parameterMSB < 0x80 && parameterLSB < 0x80)
104 result.
value = (valueMSB << 7) + valueLSB;
109 result.
value = valueMSB;
123 return generate (message.
channel,
136 jassert (midiChannel > 0 && midiChannel <= 16);
137 jassert (parameterNumber >= 0 && parameterNumber < 16384);
138 jassert (value >= 0 && value < (use14BitValue ? 16384 : 128));
140 uint8 parameterLSB = uint8 (parameterNumber & 0x0000007f);
141 uint8 parameterMSB = uint8 (parameterNumber >> 7);
143 uint8 valueLSB = use14BitValue ? uint8 (value & 0x0000007f) : 0x00;
144 uint8 valueMSB = use14BitValue ? uint8 (value >> 7) : uint8 (value);
146 uint8 channelByte = uint8 (0xb0 + midiChannel - 1);
167 class MidiRPNDetectorTests :
public UnitTest 170 MidiRPNDetectorTests()
171 :
UnitTest (
"MidiRPNDetector class", UnitTestCategories::midi)
174 void runTest()
override 176 beginTest (
"7-bit RPN");
186 expectEquals (rpn.
value, 42);
191 beginTest (
"14-bit RPN");
202 expectEquals (rpn.
value, 222);
207 beginTest (
"RPNs on multiple channels simultaneously");
220 expectEquals (rpn.
value, 42);
228 expectEquals (rpn.
value, 222);
233 beginTest (
"14-bit RPN with value within 7-bit range");
242 expectEquals (rpn.
channel, 16);
244 expectEquals (rpn.
value, 3);
249 beginTest (
"invalid RPN (wrong order)");
258 beginTest (
"14-bit RPN interspersed with unrelated CC messages");
273 expectEquals (rpn.
channel, 16);
275 expectEquals (rpn.
value, 3);
280 beginTest (
"14-bit NRPN");
291 expectEquals (rpn.
value, 222);
308 static MidiRPNDetectorTests MidiRPNDetectorUnitTests;
311 class MidiRPNGeneratorTests :
public UnitTest 314 MidiRPNGeneratorTests()
315 :
UnitTest (
"MidiRPNGenerator class", UnitTestCategories::midi)
318 void runTest()
override 320 beginTest (
"generating RPN/NRPN");
324 expectContainsRPN (buffer, 1, 23, 1337,
true,
true);
328 expectContainsRPN (buffer, 16, 101, 34,
false,
false);
333 expectContainsRPN (buffer, message);
340 void expectContainsRPN (
const MidiBuffer& midiBuffer,
347 MidiRPNMessage expected = { channel, parameterNumber, value, isNRPN, is14BitValue };
348 expectContainsRPN (midiBuffer, expected);
377 static MidiRPNGeneratorTests MidiRPNGeneratorUnitTests;
Encapsulates a MIDI message.
~MidiRPNDetector() noexcept
Destructor.
static MidiBuffer generate(MidiRPNMessage message)
Generates a MIDI sequence representing the given RPN or NRPN message.
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
Retrieves a copy of the next event from the buffer.
MidiRPNDetector() noexcept
Constructor.
int channel
Midi channel of the message, in the range 1 to 16.
bool is14BitValue
True if the value uses 14-bit resolution (LSB + MSB); false if the value is 7-bit (MSB only)...
int value
The parameter value, in the range 0 to 16383 (0x3fff).
This is a base class for classes that perform a unit test.
int getControllerNumber() const noexcept
Returns the controller number of a controller message.
int getChannel() const noexcept
Returns the midi channel associated with the message.
void reset() noexcept
Resets the RPN detector's internal state, so that it forgets about previously received MIDI CC messag...
Represents a MIDI RPN (registered parameter number) or NRPN (non-registered parameter number) message...
bool isNRPN
True if this message is an NRPN; false if it is an RPN.
int parameterNumber
The 14-bit parameter index, in the range 0 to 16383 (0x3fff).
Holds a sequence of time-stamped midi events.
int getControllerValue() const noexcept
Returns the controller value from a controller message.
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
Adds an event to the buffer.
Used to iterate through the events in a MidiBuffer.
bool parseControllerMessage(int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage &result) noexcept
Takes the next in a stream of incoming MIDI CC messages and returns true if it forms the last of a se...
Parses a stream of MIDI data to assemble RPN and NRPN messages from their constituent MIDI CC message...