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,
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;
85 void MidiRPNDetector::ChannelState::resetValue() noexcept
92 bool 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);
167 class MidiRPNDetectorTests :
public UnitTest
170 MidiRPNDetectorTests()
171 :
UnitTest (
"MidiRPNDetector class", UnitTestCategories::midi)
174 void runTest()
override
176 beginTest (
"7-bit RPN");
178 MidiRPNDetector detector;
180 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
181 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
182 expect (detector.parseControllerMessage (2, 6, 42, rpn));
184 expectEquals (rpn.channel, 2);
185 expectEquals (rpn.parameterNumber, 7);
186 expectEquals (rpn.value, 42);
187 expect (! rpn.isNRPN);
188 expect (! rpn.is14BitValue);
191 beginTest (
"14-bit RPN");
193 MidiRPNDetector detector;
195 expect (! detector.parseControllerMessage (1, 100, 44, rpn));
196 expect (! detector.parseControllerMessage (1, 101, 2, rpn));
197 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
198 expect (detector.parseControllerMessage (1, 6, 1, rpn));
200 expectEquals (rpn.channel, 1);
201 expectEquals (rpn.parameterNumber, 300);
202 expectEquals (rpn.value, 222);
203 expect (! rpn.isNRPN);
204 expect (rpn.is14BitValue);
207 beginTest (
"RPNs on multiple channels simultaneously");
209 MidiRPNDetector detector;
211 expect (! detector.parseControllerMessage (1, 100, 44, rpn));
212 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
213 expect (! detector.parseControllerMessage (1, 101, 2, rpn));
214 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
215 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
216 expect (detector.parseControllerMessage (2, 6, 42, rpn));
218 expectEquals (rpn.channel, 2);
219 expectEquals (rpn.parameterNumber, 7);
220 expectEquals (rpn.value, 42);
221 expect (! rpn.isNRPN);
222 expect (! rpn.is14BitValue);
224 expect (detector.parseControllerMessage (1, 6, 1, rpn));
226 expectEquals (rpn.channel, 1);
227 expectEquals (rpn.parameterNumber, 300);
228 expectEquals (rpn.value, 222);
229 expect (! rpn.isNRPN);
230 expect (rpn.is14BitValue);
233 beginTest (
"14-bit RPN with value within 7-bit range");
235 MidiRPNDetector detector;
237 expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
238 expect (! detector.parseControllerMessage (16, 101, 0, rpn));
239 expect (! detector.parseControllerMessage (16, 38, 3, rpn));
240 expect (detector.parseControllerMessage (16, 6, 0, rpn));
242 expectEquals (rpn.channel, 16);
243 expectEquals (rpn.parameterNumber, 0);
244 expectEquals (rpn.value, 3);
245 expect (! rpn.isNRPN);
246 expect (rpn.is14BitValue);
249 beginTest (
"invalid RPN (wrong order)");
251 MidiRPNDetector detector;
253 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
254 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
255 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
258 beginTest (
"14-bit RPN interspersed with unrelated CC messages");
260 MidiRPNDetector detector;
262 expect (! detector.parseControllerMessage (16, 3, 80, rpn));
263 expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
264 expect (! detector.parseControllerMessage (16, 4, 81, rpn));
265 expect (! detector.parseControllerMessage (16, 101, 0, rpn));
266 expect (! detector.parseControllerMessage (16, 5, 82, rpn));
267 expect (! detector.parseControllerMessage (16, 5, 83, rpn));
268 expect (! detector.parseControllerMessage (16, 38, 3, rpn));
269 expect (! detector.parseControllerMessage (16, 4, 84, rpn));
270 expect (! detector.parseControllerMessage (16, 3, 85, rpn));
271 expect (detector.parseControllerMessage (16, 6, 0, rpn));
273 expectEquals (rpn.channel, 16);
274 expectEquals (rpn.parameterNumber, 0);
275 expectEquals (rpn.value, 3);
276 expect (! rpn.isNRPN);
277 expect (rpn.is14BitValue);
280 beginTest (
"14-bit NRPN");
282 MidiRPNDetector detector;
284 expect (! detector.parseControllerMessage (1, 98, 44, rpn));
285 expect (! detector.parseControllerMessage (1, 99 , 2, rpn));
286 expect (! detector.parseControllerMessage (1, 38, 94, rpn));
287 expect (detector.parseControllerMessage (1, 6, 1, rpn));
289 expectEquals (rpn.channel, 1);
290 expectEquals (rpn.parameterNumber, 300);
291 expectEquals (rpn.value, 222);
293 expect (rpn.is14BitValue);
298 MidiRPNDetector detector;
300 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
302 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
303 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
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);
331 MidiRPNMessage message = { 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);
352 void expectContainsRPN (
const MidiBuffer& midiBuffer, MidiRPNMessage expected)
354 MidiBuffer::Iterator iter (midiBuffer);
355 MidiMessage midiMessage;
356 MidiRPNMessage result = MidiRPNMessage();
357 MidiRPNDetector detector;
360 while (iter.getNextEvent (midiMessage, samplePosition))
362 if (detector.parseControllerMessage (midiMessage.getChannel(),
363 midiMessage.getControllerNumber(),
364 midiMessage.getControllerValue(),
369 expectEquals (result.channel, expected.channel);
370 expectEquals (result.parameterNumber, expected.parameterNumber);
371 expectEquals (result.value, expected.value);
372 expect (result.isNRPN == expected.isNRPN);
373 expect (result.is14BitValue == expected.is14BitValue);
377 static 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.
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.
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).