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;
58MidiRPNDetector::ChannelState::ChannelState() noexcept
59 : parameterMSB (0xff), parameterLSB (0xff), valueMSB (0xff), valueLSB (0xff), isNRPN (false)
63bool MidiRPNDetector::ChannelState::handleController (
int channel,
66 MidiRPNMessage& result)
noexcept
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;
85void MidiRPNDetector::ChannelState::resetValue() noexcept
92bool MidiRPNDetector::ChannelState::sendIfReady (
int channel, MidiRPNMessage& result)
noexcept
94 if (parameterMSB < 0x80 && parameterLSB < 0x80)
98 result.channel = channel;
99 result.parameterNumber = (parameterMSB << 7) + parameterLSB;
100 result.isNRPN = isNRPN;
104 result.value = (valueMSB << 7) + valueLSB;
105 result.is14BitValue =
true;
109 result.value = valueMSB;
110 result.is14BitValue =
false;
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);
166class MidiRPNDetectorTests :
public UnitTest
169 MidiRPNDetectorTests() :
UnitTest (
"MidiRPNDetector class",
"MIDI/MPE") {}
171 void runTest()
override
173 beginTest (
"7-bit RPN");
175 MidiRPNDetector detector;
177 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
178 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
179 expect (detector.parseControllerMessage (2, 6, 42, rpn));
181 expectEquals (rpn.channel, 2);
182 expectEquals (rpn.parameterNumber, 7);
183 expectEquals (rpn.value, 42);
184 expect (! rpn.isNRPN);
185 expect (! rpn.is14BitValue);
188 beginTest (
"14-bit RPN");
190 MidiRPNDetector detector;
192 expect (! detector.parseControllerMessage (1, 100, 44, rpn));
193 expect (! detector.parseControllerMessage (1, 101, 2, rpn));
194 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
195 expect (detector.parseControllerMessage (1, 6, 1, rpn));
197 expectEquals (rpn.channel, 1);
198 expectEquals (rpn.parameterNumber, 300);
199 expectEquals (rpn.value, 222);
200 expect (! rpn.isNRPN);
201 expect (rpn.is14BitValue);
204 beginTest (
"RPNs on multiple channels simultaneously");
206 MidiRPNDetector detector;
208 expect (! detector.parseControllerMessage (1, 100, 44, rpn));
209 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
210 expect (! detector.parseControllerMessage (1, 101, 2, rpn));
211 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
212 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
213 expect (detector.parseControllerMessage (2, 6, 42, rpn));
215 expectEquals (rpn.channel, 2);
216 expectEquals (rpn.parameterNumber, 7);
217 expectEquals (rpn.value, 42);
218 expect (! rpn.isNRPN);
219 expect (! rpn.is14BitValue);
221 expect (detector.parseControllerMessage (1, 6, 1, rpn));
223 expectEquals (rpn.channel, 1);
224 expectEquals (rpn.parameterNumber, 300);
225 expectEquals (rpn.value, 222);
226 expect (! rpn.isNRPN);
227 expect (rpn.is14BitValue);
230 beginTest (
"14-bit RPN with value within 7-bit range");
232 MidiRPNDetector detector;
234 expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
235 expect (! detector.parseControllerMessage (16, 101, 0, rpn));
236 expect (! detector.parseControllerMessage (16, 38, 3, rpn));
237 expect (detector.parseControllerMessage (16, 6, 0, rpn));
239 expectEquals (rpn.channel, 16);
240 expectEquals (rpn.parameterNumber, 0);
241 expectEquals (rpn.value, 3);
242 expect (! rpn.isNRPN);
243 expect (rpn.is14BitValue);
246 beginTest (
"invalid RPN (wrong order)");
248 MidiRPNDetector detector;
250 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
251 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
252 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
255 beginTest (
"14-bit RPN interspersed with unrelated CC messages");
257 MidiRPNDetector detector;
259 expect (! detector.parseControllerMessage (16, 3, 80, rpn));
260 expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
261 expect (! detector.parseControllerMessage (16, 4, 81, rpn));
262 expect (! detector.parseControllerMessage (16, 101, 0, rpn));
263 expect (! detector.parseControllerMessage (16, 5, 82, rpn));
264 expect (! detector.parseControllerMessage (16, 5, 83, rpn));
265 expect (! detector.parseControllerMessage (16, 38, 3, rpn));
266 expect (! detector.parseControllerMessage (16, 4, 84, rpn));
267 expect (! detector.parseControllerMessage (16, 3, 85, rpn));
268 expect (detector.parseControllerMessage (16, 6, 0, rpn));
270 expectEquals (rpn.channel, 16);
271 expectEquals (rpn.parameterNumber, 0);
272 expectEquals (rpn.value, 3);
273 expect (! rpn.isNRPN);
274 expect (rpn.is14BitValue);
277 beginTest (
"14-bit NRPN");
279 MidiRPNDetector detector;
281 expect (! detector.parseControllerMessage (1, 98, 44, rpn));
282 expect (! detector.parseControllerMessage (1, 99 , 2, rpn));
283 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
284 expect (detector.parseControllerMessage (1, 6, 1, rpn));
286 expectEquals (rpn.channel, 1);
287 expectEquals (rpn.parameterNumber, 300);
288 expectEquals (rpn.value, 222);
290 expect (rpn.is14BitValue);
295 MidiRPNDetector detector;
297 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
299 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
300 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
305static MidiRPNDetectorTests MidiRPNDetectorUnitTests;
308class MidiRPNGeneratorTests :
public UnitTest
311 MidiRPNGeneratorTests() : UnitTest (
"MidiRPNGenerator class",
"MIDI/MPE") {}
313 void runTest()
override
315 beginTest (
"generating RPN/NRPN");
318 MidiBuffer buffer = MidiRPNGenerator::generate (1, 23, 1337,
true,
true);
319 expectContainsRPN (buffer, 1, 23, 1337,
true,
true);
322 MidiBuffer buffer = MidiRPNGenerator::generate (16, 101, 34,
false,
false);
323 expectContainsRPN (buffer, 16, 101, 34,
false,
false);
326 MidiRPNMessage message = { 16, 101, 34,
false,
false };
327 MidiBuffer buffer = MidiRPNGenerator::generate (message);
328 expectContainsRPN (buffer, message);
335 void expectContainsRPN (
const MidiBuffer& midiBuffer,
342 MidiRPNMessage expected = { channel, parameterNumber, value, isNRPN, is14BitValue };
343 expectContainsRPN (midiBuffer, expected);
347 void expectContainsRPN (
const MidiBuffer& midiBuffer, MidiRPNMessage expected)
349 MidiBuffer::Iterator iter (midiBuffer);
350 MidiMessage midiMessage;
351 MidiRPNMessage result = MidiRPNMessage();
352 MidiRPNDetector detector;
355 while (iter.getNextEvent (midiMessage, samplePosition))
357 if (detector.parseControllerMessage (midiMessage.getChannel(),
358 midiMessage.getControllerNumber(),
359 midiMessage.getControllerValue(),
364 expectEquals (result.channel, expected.channel);
365 expectEquals (result.parameterNumber, expected.parameterNumber);
366 expectEquals (result.value, expected.value);
367 expect (result.isNRPN == expected.isNRPN);
368 expect (result.is14BitValue == expected.is14BitValue);
372static MidiRPNGeneratorTests MidiRPNGeneratorUnitTests;
Holds a sequence of time-stamped midi events.
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
Adds an event to the buffer.
Encapsulates a MIDI message.
MidiRPNDetector() noexcept
Constructor.
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...
void reset() noexcept
Resets the RPN detector's internal state, so that it forgets about previously received MIDI CC messag...
~MidiRPNDetector() noexcept
Destructor.
static MidiBuffer generate(MidiRPNMessage message)
Generates a MIDI sequence representing the given RPN or NRPN message.
This is a base class for classes that perform a unit test.
bool isNRPN
True if this message is an NRPN; false if it is an RPN.
bool is14BitValue
True if the value uses 14-bit resolution (LSB + MSB); false if the value is 7-bit (MSB only).
int channel
Midi channel of the message, in the range 1 to 16.
int parameterNumber
The 14-bit parameter index, in the range 0 to 16383 (0x3fff).
int value
The parameter value, in the range 0 to 16383 (0x3fff).
Represents a MIDI RPN (registered parameter number) or NRPN (non-registered parameter number) message...