OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_MidiRPN.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
29
33
37 MidiRPNMessage& result) noexcept
38{
39 jassert (midiChannel >= 1 && midiChannel <= 16);
40 jassert (controllerNumber >= 0 && controllerNumber < 128);
41 jassert (controllerValue >= 0 && controllerValue < 128);
42
43 return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue, result);
44}
45
47{
48 for (int i = 0; i < 16; ++i)
49 {
50 states[i].parameterMSB = 0xff;
51 states[i].parameterLSB = 0xff;
52 states[i].resetValue();
53 states[i].isNRPN = false;
54 }
55}
56
57//==============================================================================
58MidiRPNDetector::ChannelState::ChannelState() noexcept
59 : parameterMSB (0xff), parameterLSB (0xff), valueMSB (0xff), valueLSB (0xff), isNRPN (false)
60{
61}
62
63bool MidiRPNDetector::ChannelState::handleController (int channel,
64 int controllerNumber,
65 int value,
66 MidiRPNMessage& result) noexcept
67{
68 switch (controllerNumber)
69 {
70 case 0x62: parameterLSB = uint8 (value); resetValue(); isNRPN = true; break;
71 case 0x63: parameterMSB = uint8 (value); resetValue(); isNRPN = true; break;
72
73 case 0x64: parameterLSB = uint8 (value); resetValue(); isNRPN = false; break;
74 case 0x65: parameterMSB = uint8 (value); resetValue(); isNRPN = false; break;
75
76 case 0x06: valueMSB = uint8 (value); return sendIfReady (channel, result);
77 case 0x26: valueLSB = uint8 (value); break;
78
79 default: break;
80 }
81
82 return false;
83}
84
85void MidiRPNDetector::ChannelState::resetValue() noexcept
86{
87 valueMSB = 0xff;
88 valueLSB = 0xff;
89}
90
91//==============================================================================
92bool MidiRPNDetector::ChannelState::sendIfReady (int channel, MidiRPNMessage& result) noexcept
93{
94 if (parameterMSB < 0x80 && parameterLSB < 0x80)
95 {
96 if (valueMSB < 0x80)
97 {
98 result.channel = channel;
99 result.parameterNumber = (parameterMSB << 7) + parameterLSB;
100 result.isNRPN = isNRPN;
101
102 if (valueLSB < 0x80)
103 {
104 result.value = (valueMSB << 7) + valueLSB;
105 result.is14BitValue = true;
106 }
107 else
108 {
109 result.value = valueMSB;
110 result.is14BitValue = false;
111 }
112
113 return true;
114 }
115 }
116
117 return false;
118}
119
120//==============================================================================
122{
123 return generate (message.channel,
124 message.parameterNumber,
125 message.value,
126 message.isNRPN,
127 message.is14BitValue);
128}
129
131 int parameterNumber,
132 int value,
133 bool isNRPN,
134 bool use14BitValue)
135{
136 jassert (midiChannel > 0 && midiChannel <= 16);
137 jassert (parameterNumber >= 0 && parameterNumber < 16384);
138 jassert (value >= 0 && value < (use14BitValue ? 16384 : 128));
139
140 uint8 parameterLSB = uint8 (parameterNumber & 0x0000007f);
141 uint8 parameterMSB = uint8 (parameterNumber >> 7);
142
143 uint8 valueLSB = use14BitValue ? uint8 (value & 0x0000007f) : 0x00;
144 uint8 valueMSB = use14BitValue ? uint8 (value >> 7) : uint8 (value);
145
146 uint8 channelByte = uint8 (0xb0 + midiChannel - 1);
147
148 MidiBuffer buffer;
149
150 buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x62 : 0x64, parameterLSB), 0);
151 buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x63 : 0x65, parameterMSB), 0);
152
153 // sending the value LSB is optional, but must come before sending the value MSB:
154 if (use14BitValue)
155 buffer.addEvent (MidiMessage (channelByte, 0x26, valueLSB), 0);
156
157 buffer.addEvent (MidiMessage (channelByte, 0x06, valueMSB), 0);
158
159 return buffer;
160}
161
162
163//==============================================================================
164//==============================================================================
165#if JUCE_UNIT_TESTS
166
167class MidiRPNDetectorTests : public UnitTest
168{
169public:
171 : UnitTest ("MidiRPNDetector class", UnitTestCategories::midi)
172 {}
173
174 void runTest() override
175 {
176 beginTest ("7-bit RPN");
177 {
178 MidiRPNDetector detector;
179 MidiRPNMessage rpn;
180 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
181 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
182 expect (detector.parseControllerMessage (2, 6, 42, rpn));
183
184 expectEquals (rpn.channel, 2);
185 expectEquals (rpn.parameterNumber, 7);
186 expectEquals (rpn.value, 42);
187 expect (! rpn.isNRPN);
188 expect (! rpn.is14BitValue);
189 }
190
191 beginTest ("14-bit RPN");
192 {
193 MidiRPNDetector detector;
194 MidiRPNMessage rpn;
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));
199
200 expectEquals (rpn.channel, 1);
201 expectEquals (rpn.parameterNumber, 300);
202 expectEquals (rpn.value, 222);
203 expect (! rpn.isNRPN);
204 expect (rpn.is14BitValue);
205 }
206
207 beginTest ("RPNs on multiple channels simultaneously");
208 {
209 MidiRPNDetector detector;
210 MidiRPNMessage rpn;
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));
217
218 expectEquals (rpn.channel, 2);
219 expectEquals (rpn.parameterNumber, 7);
220 expectEquals (rpn.value, 42);
221 expect (! rpn.isNRPN);
222 expect (! rpn.is14BitValue);
223
224 expect (detector.parseControllerMessage (1, 6, 1, rpn));
225
226 expectEquals (rpn.channel, 1);
227 expectEquals (rpn.parameterNumber, 300);
228 expectEquals (rpn.value, 222);
229 expect (! rpn.isNRPN);
230 expect (rpn.is14BitValue);
231 }
232
233 beginTest ("14-bit RPN with value within 7-bit range");
234 {
235 MidiRPNDetector detector;
236 MidiRPNMessage rpn;
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));
241
242 expectEquals (rpn.channel, 16);
243 expectEquals (rpn.parameterNumber, 0);
244 expectEquals (rpn.value, 3);
245 expect (! rpn.isNRPN);
246 expect (rpn.is14BitValue);
247 }
248
249 beginTest ("invalid RPN (wrong order)");
250 {
251 MidiRPNDetector detector;
252 MidiRPNMessage rpn;
253 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
254 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
255 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
256 }
257
258 beginTest ("14-bit RPN interspersed with unrelated CC messages");
259 {
260 MidiRPNDetector detector;
261 MidiRPNMessage rpn;
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));
272
273 expectEquals (rpn.channel, 16);
274 expectEquals (rpn.parameterNumber, 0);
275 expectEquals (rpn.value, 3);
276 expect (! rpn.isNRPN);
277 expect (rpn.is14BitValue);
278 }
279
280 beginTest ("14-bit NRPN");
281 {
282 MidiRPNDetector detector;
283 MidiRPNMessage rpn;
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));
288
289 expectEquals (rpn.channel, 1);
290 expectEquals (rpn.parameterNumber, 300);
291 expectEquals (rpn.value, 222);
292 expect (rpn.isNRPN);
293 expect (rpn.is14BitValue);
294 }
295
296 beginTest ("reset");
297 {
298 MidiRPNDetector detector;
299 MidiRPNMessage rpn;
300 expect (! detector.parseControllerMessage (2, 101, 0, rpn));
301 detector.reset();
302 expect (! detector.parseControllerMessage (2, 100, 7, rpn));
303 expect (! detector.parseControllerMessage (2, 6, 42, rpn));
304 }
305 }
306};
307
308static MidiRPNDetectorTests MidiRPNDetectorUnitTests;
309
310//==============================================================================
311class MidiRPNGeneratorTests : public UnitTest
312{
313public:
315 : UnitTest ("MidiRPNGenerator class", UnitTestCategories::midi)
316 {}
317
318 void runTest() override
319 {
320 beginTest ("generating RPN/NRPN");
321 {
322 {
323 MidiBuffer buffer = MidiRPNGenerator::generate (1, 23, 1337, true, true);
324 expectContainsRPN (buffer, 1, 23, 1337, true, true);
325 }
326 {
327 MidiBuffer buffer = MidiRPNGenerator::generate (16, 101, 34, false, false);
328 expectContainsRPN (buffer, 16, 101, 34, false, false);
329 }
330 {
331 MidiRPNMessage message = { 16, 101, 34, false, false };
332 MidiBuffer buffer = MidiRPNGenerator::generate (message);
333 expectContainsRPN (buffer, message);
334 }
335 }
336 }
337
338private:
339 //==============================================================================
340 void expectContainsRPN (const MidiBuffer& midiBuffer,
341 int channel,
342 int parameterNumber,
343 int value,
344 bool isNRPN,
345 bool is14BitValue)
346 {
347 MidiRPNMessage expected = { channel, parameterNumber, value, isNRPN, is14BitValue };
349 }
350
351 //==============================================================================
352 void expectContainsRPN (const MidiBuffer& midiBuffer, MidiRPNMessage expected)
353 {
354 MidiBuffer::Iterator iter (midiBuffer);
355 MidiMessage midiMessage;
356 MidiRPNMessage result = MidiRPNMessage();
357 MidiRPNDetector detector;
358 int samplePosition; // not actually used, so no need to initialise.
359
360 while (iter.getNextEvent (midiMessage, samplePosition))
361 {
362 if (detector.parseControllerMessage (midiMessage.getChannel(),
363 midiMessage.getControllerNumber(),
364 midiMessage.getControllerValue(),
365 result))
366 break;
367 }
368
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);
374 }
375};
376
377static MidiRPNGeneratorTests MidiRPNGeneratorUnitTests;
378
379#endif
380
381} // namespace juce
Array()=default
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
bool parseControllerMessage(int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage &result) noexcept
void reset() noexcept
static MidiBuffer generate(MidiRPNMessage message)