OpenShot Audio Library | OpenShotAudio: juce_MidiMessage.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

Loading...
Searching...
No Matches
juce_MidiMessage.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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
26namespace MidiHelpers
27{
28 inline uint8 initialByte (const int type, const int channel) noexcept
29 {
30 return (uint8) (type | jlimit (0, 15, channel - 1));
31 }
32
33 inline uint8 validVelocity (const int v) noexcept
34 {
35 return (uint8) jlimit (0, 127, v);
36 }
37}
38
39//==============================================================================
40uint8 MidiMessage::floatValueToMidiByte (const float v) noexcept
41{
42 jassert (v >= 0 && v <= 1.0f); // if your value is > 1, maybe you're passing an
43 // integer value to a float method by mistake?
44
45 return MidiHelpers::validVelocity (roundToInt (v * 127.0f));
46}
47
48uint16 MidiMessage::pitchbendToPitchwheelPos (const float pitchbend,
49 const float pitchbendRange) noexcept
50{
51 // can't translate a pitchbend value that is outside of the given range!
52 jassert (std::abs (pitchbend) <= pitchbendRange);
53
54 return static_cast<uint16> (pitchbend > 0.0f
55 ? jmap (pitchbend, 0.0f, pitchbendRange, 8192.0f, 16383.0f)
56 : jmap (pitchbend, -pitchbendRange, 0.0f, 0.0f, 8192.0f));
57}
58
59//==============================================================================
60 MidiMessage::VariableLengthValue MidiMessage::readVariableLengthValue (const uint8* data, int maxBytesToUse) noexcept
61{
62 uint32 v = 0;
63
64 // The largest allowable variable-length value is 0x0f'ff'ff'ff which is
65 // represented by the 4-byte stream 0xff 0xff 0xff 0x7f.
66 // Longer bytestreams risk overflowing a 32-bit signed int.
67 const auto limit = jmin (maxBytesToUse, 4);
68
69 for (int numBytesUsed = 0; numBytesUsed < limit; ++numBytesUsed)
70 {
71 const auto i = data[numBytesUsed];
72 v = (v << 7) + (i & 0x7f);
73
74 if (! (i & 0x80))
75 return { (int) v, numBytesUsed + 1 };
76 }
77
78 // If this is hit, the input was malformed. Either there were not enough
79 // bytes of input to construct a full value, or no terminating byte was
80 // found. This implementation only supports variable-length values of up
81 // to four bytes.
82 return {};
83}
84
85 int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
86{
87 numBytesUsed = 0;
88 int v = 0, i;
89
90 do
91 {
92 i = (int) *data++;
93
94 if (++numBytesUsed > 6)
95 break;
96
97 v = (v << 7) + (i & 0x7f);
98
99 } while (i & 0x80);
100
101 return v;
102}
103
104 int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
105{
106 // this method only works for valid starting bytes of a short midi message
107 jassert (firstByte >= 0x80 && firstByte != 0xf0 && firstByte != 0xf7);
108
109 static const char messageLengths[] =
110 {
111 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
112 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
113 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
114 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
115 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
116 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
117 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
118 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
119 };
120
121 return messageLengths[firstByte & 0x7f];
122}
123
124//==============================================================================
125MidiMessage::MidiMessage() noexcept
126 : size (2)
127{
128 packedData.asBytes[0] = 0xf0;
129 packedData.asBytes[1] = 0xf7;
130}
131
132 MidiMessage::MidiMessage (const void* const d, const int dataSize, const double t)
133 : timeStamp (t), size (dataSize)
134{
135 jassert (dataSize > 0);
136 // this checks that the length matches the data..
137 jassert (dataSize > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
138
139 memcpy (allocateSpace (dataSize), d, (size_t) dataSize);
140}
141
142 MidiMessage::MidiMessage (const int byte1, const double t) noexcept
143 : timeStamp (t), size (1)
144{
145 packedData.asBytes[0] = (uint8) byte1;
146
147 // check that the length matches the data..
148 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 1);
149}
150
151 MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
152 : timeStamp (t), size (2)
153{
154 packedData.asBytes[0] = (uint8) byte1;
155 packedData.asBytes[1] = (uint8) byte2;
156
157 // check that the length matches the data..
158 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 2);
159}
160
161 MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
162 : timeStamp (t), size (3)
163{
164 packedData.asBytes[0] = (uint8) byte1;
165 packedData.asBytes[1] = (uint8) byte2;
166 packedData.asBytes[2] = (uint8) byte3;
167
168 // check that the length matches the data..
169 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 3);
170}
171
172 MidiMessage::MidiMessage (const MidiMessage& other)
173 : timeStamp (other.timeStamp), size (other.size)
174{
175 if (isHeapAllocated())
176 memcpy (allocateSpace (size), other.getData(), (size_t) size);
177 else
178 packedData.allocatedData = other.packedData.allocatedData;
179}
180
181 MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
182 : timeStamp (newTimeStamp), size (other.size)
183{
184 if (isHeapAllocated())
185 memcpy (allocateSpace (size), other.getData(), (size_t) size);
186 else
187 packedData.allocatedData = other.packedData.allocatedData;
188}
189
190 MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte,
191 double t, bool sysexHasEmbeddedLength)
192 : timeStamp (t)
193{
194 auto src = static_cast<const uint8*> (srcData);
195 auto byte = (unsigned int) *src;
196
197 if (byte < 0x80)
198 {
199 byte = (unsigned int) lastStatusByte;
200 numBytesUsed = -1;
201 }
202 else
203 {
204 numBytesUsed = 0;
205 --sz;
206 ++src;
207 }
208
209 if (byte >= 0x80)
210 {
211 if (byte == 0xf0)
212 {
213 auto d = src;
214 bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
215 int numVariableLengthSysexBytes = 0;
216
217 while (d < src + sz)
218 {
219 if (*d >= 0x80)
220 {
221 if (*d == 0xf7)
222 {
223 ++d; // include the trailing 0xf7 when we hit it
224 break;
225 }
226
227 if (haveReadAllLengthBytes) // if we see a 0x80 bit set after the initial data length
228 break; // bytes, assume it's the end of the sysex
229
230 ++numVariableLengthSysexBytes;
231 }
232 else if (! haveReadAllLengthBytes)
233 {
234 haveReadAllLengthBytes = true;
235 ++numVariableLengthSysexBytes;
236 }
237
238 ++d;
239 }
240
241 src += numVariableLengthSysexBytes;
242 size = 1 + (int) (d - src);
243
244 auto dest = allocateSpace (size);
245 *dest = (uint8) byte;
246 memcpy (dest + 1, src, (size_t) (size - 1));
247
248 numBytesUsed += (numVariableLengthSysexBytes + size); // (these aren't counted in the size)
249 }
250 else if (byte == 0xff)
251 {
252 const auto bytesLeft = readVariableLengthValue (src + 1, sz - 1);
253 size = jmin (sz + 1, bytesLeft.bytesUsed + 2 + bytesLeft.value);
254
255 auto dest = allocateSpace (size);
256 *dest = (uint8) byte;
257 memcpy (dest + 1, src, (size_t) size - 1);
258
259 numBytesUsed += size;
260 }
261 else
262 {
263 size = getMessageLengthFromFirstByte ((uint8) byte);
264 packedData.asBytes[0] = (uint8) byte;
265
266 if (size > 1)
267 {
268 packedData.asBytes[1] = (sz > 0 ? src[0] : 0);
269
270 if (size > 2)
271 packedData.asBytes[2] = (sz > 1 ? src[1] : 0);
272 }
273
274 numBytesUsed += jmin (size, sz + 1);
275 }
276 }
277 else
278 {
279 packedData.allocatedData = nullptr;
280 size = 0;
281 }
282}
283
284 MidiMessage& MidiMessage::operator= (const MidiMessage& other)
285{
286 if (this != &other)
287 {
288 if (other.isHeapAllocated())
289 {
290 auto* newStorage = static_cast<uint8*> (isHeapAllocated()
291 ? std::realloc (packedData.allocatedData, (size_t) other.size)
292 : std::malloc ((size_t) other.size));
293
294 if (newStorage == nullptr)
295 throw std::bad_alloc{}; // The midi message has not been adjusted at this point
296
297 packedData.allocatedData = newStorage;
298 memcpy (packedData.allocatedData, other.packedData.allocatedData, (size_t) other.size);
299 }
300 else
301 {
302 if (isHeapAllocated())
303 std::free (packedData.allocatedData);
304
305 packedData.allocatedData = other.packedData.allocatedData;
306 }
307
308 timeStamp = other.timeStamp;
309 size = other.size;
310 }
311
312 return *this;
313}
314
315 MidiMessage::MidiMessage (MidiMessage&& other) noexcept
316 : timeStamp (other.timeStamp), size (other.size)
317{
318 packedData.allocatedData = other.packedData.allocatedData;
319 other.size = 0;
320}
321
322 MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
323{
324 packedData.allocatedData = other.packedData.allocatedData;
325 timeStamp = other.timeStamp;
326 size = other.size;
327 other.size = 0;
328 return *this;
329}
330
331MidiMessage::~MidiMessage() noexcept
332{
333 if (isHeapAllocated())
334 std::free (packedData.allocatedData);
335}
336
337uint8* MidiMessage::allocateSpace (int bytes)
338{
339 if (bytes > (int) sizeof (packedData))
340 {
341 auto d = static_cast<uint8*> (std::malloc ((size_t) bytes));
342 packedData.allocatedData = d;
343 return d;
344 }
345
346 return packedData.asBytes;
347}
348
349 String MidiMessage::getDescription() const
350{
351 if (isNoteOn()) return "Note on " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
352 if (isNoteOff()) return "Note off " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
353 if (isProgramChange()) return "Program change " + String (getProgramChangeNumber()) + " Channel " + String (getChannel());
354 if (isPitchWheel()) return "Pitch wheel " + String (getPitchWheelValue()) + " Channel " + String (getChannel());
355 if (isAftertouch()) return "Aftertouch " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + ": " + String (getAfterTouchValue()) + " Channel " + String (getChannel());
356 if (isChannelPressure()) return "Channel pressure " + String (getChannelPressureValue()) + " Channel " + String (getChannel());
357 if (isAllNotesOff()) return "All notes off Channel " + String (getChannel());
358 if (isAllSoundOff()) return "All sound off Channel " + String (getChannel());
359 if (isMetaEvent()) return "Meta event";
360
361 if (isController())
362 {
363 String name (MidiMessage::getControllerName (getControllerNumber()));
364
365 if (name.isEmpty())
366 name = String (getControllerNumber());
367
368 return "Controller " + name + ": " + String (getControllerValue()) + " Channel " + String (getChannel());
369 }
370
371 return String::toHexString (getRawData(), getRawDataSize());
372}
373
374 MidiMessage MidiMessage::withTimeStamp (double newTimestamp) const
375{
376 return { *this, newTimestamp };
377}
378
379 int MidiMessage::getChannel() const noexcept
380{
381 auto data = getRawData();
382
383 if ((data[0] & 0xf0) != 0xf0)
384 return (data[0] & 0xf) + 1;
385
386 return 0;
387}
388
389 bool MidiMessage::isForChannel (const int channel) const noexcept
390{
391 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
392
393 auto data = getRawData();
394
395 return ((data[0] & 0xf) == channel - 1)
396 && ((data[0] & 0xf0) != 0xf0);
397}
398
399 void MidiMessage::setChannel (const int channel) noexcept
400{
401 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
402
403 auto data = getData();
404
405 if ((data[0] & 0xf0) != (uint8) 0xf0)
406 data[0] = (uint8) ((data[0] & (uint8) 0xf0)
407 | (uint8) (channel - 1));
408}
409
410 bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
411{
412 auto data = getRawData();
413
414 return ((data[0] & 0xf0) == 0x90)
415 && (returnTrueForVelocity0 || data[2] != 0);
416}
417
418 bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
419{
420 auto data = getRawData();
421
422 return ((data[0] & 0xf0) == 0x80)
423 || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
424}
425
426 bool MidiMessage::isNoteOnOrOff() const noexcept
427{
428 auto d = getRawData()[0] & 0xf0;
429 return (d == 0x90) || (d == 0x80);
430}
431
432 int MidiMessage::getNoteNumber() const noexcept
433{
434 return getRawData()[1];
435}
436
437 void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
438{
439 if (isNoteOnOrOff() || isAftertouch())
440 getData()[1] = (uint8) (newNoteNumber & 127);
441}
442
443uint8 MidiMessage::getVelocity() const noexcept
444{
445 if (isNoteOnOrOff())
446 return getRawData()[2];
447
448 return 0;
449}
450
451 float MidiMessage::getFloatVelocity() const noexcept
452{
453 return getVelocity() * (1.0f / 127.0f);
454}
455
456 void MidiMessage::setVelocity (const float newVelocity) noexcept
457{
458 if (isNoteOnOrOff())
459 getData()[2] = floatValueToMidiByte (newVelocity);
460}
461
462 void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
463{
464 if (isNoteOnOrOff())
465 {
466 auto data = getData();
467 data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
468 }
469}
470
471 bool MidiMessage::isAftertouch() const noexcept
472{
473 return (getRawData()[0] & 0xf0) == 0xa0;
474}
475
476 int MidiMessage::getAfterTouchValue() const noexcept
477{
478 jassert (isAftertouch());
479 return getRawData()[2];
480}
481
482 MidiMessage MidiMessage::aftertouchChange (const int channel,
483 const int noteNum,
484 const int aftertouchValue) noexcept
485{
486 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
487 jassert (isPositiveAndBelow (noteNum, 128));
488 jassert (isPositiveAndBelow (aftertouchValue, 128));
489
490 return MidiMessage (MidiHelpers::initialByte (0xa0, channel),
491 noteNum & 0x7f,
492 aftertouchValue & 0x7f);
493}
494
495 bool MidiMessage::isChannelPressure() const noexcept
496{
497 return (getRawData()[0] & 0xf0) == 0xd0;
498}
499
500 int MidiMessage::getChannelPressureValue() const noexcept
501{
502 jassert (isChannelPressure());
503 return getRawData()[1];
504}
505
506 MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
507{
508 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
509 jassert (isPositiveAndBelow (pressure, 128));
510
511 return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
512}
513
514 bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
515 bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
516
517 bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
518 bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
519
520 bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
521 bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
522
523
524 bool MidiMessage::isProgramChange() const noexcept
525{
526 return (getRawData()[0] & 0xf0) == 0xc0;
527}
528
529 int MidiMessage::getProgramChangeNumber() const noexcept
530{
531 jassert (isProgramChange());
532 return getRawData()[1];
533}
534
535 MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
536{
537 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
538
539 return MidiMessage (MidiHelpers::initialByte (0xc0, channel), programNumber & 0x7f);
540}
541
542 bool MidiMessage::isPitchWheel() const noexcept
543{
544 return (getRawData()[0] & 0xf0) == 0xe0;
545}
546
547 int MidiMessage::getPitchWheelValue() const noexcept
548{
549 jassert (isPitchWheel());
550 auto data = getRawData();
551 return data[1] | (data[2] << 7);
552}
553
554 MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noexcept
555{
556 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
557 jassert (isPositiveAndBelow (position, 0x4000));
558
559 return MidiMessage (MidiHelpers::initialByte (0xe0, channel),
560 position & 127, (position >> 7) & 127);
561}
562
563 bool MidiMessage::isController() const noexcept
564{
565 return (getRawData()[0] & 0xf0) == 0xb0;
566}
567
568 bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
569{
570 auto data = getRawData();
571 return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
572}
573
574 int MidiMessage::getControllerNumber() const noexcept
575{
576 jassert (isController());
577 return getRawData()[1];
578}
579
580 int MidiMessage::getControllerValue() const noexcept
581{
582 jassert (isController());
583 return getRawData()[2];
584}
585
586 MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
587{
588 // the channel must be between 1 and 16 inclusive
589 jassert (channel > 0 && channel <= 16);
590
591 return MidiMessage (MidiHelpers::initialByte (0xb0, channel),
592 controllerType & 127, value & 127);
593}
594
595 MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept
596{
597 jassert (channel > 0 && channel <= 16);
598 jassert (isPositiveAndBelow (noteNumber, 128));
599
600 return MidiMessage (MidiHelpers::initialByte (0x90, channel),
601 noteNumber & 127, MidiHelpers::validVelocity (velocity));
602}
603
604 MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept
605{
606 return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
607}
608
609 MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept
610{
611 jassert (channel > 0 && channel <= 16);
612 jassert (isPositiveAndBelow (noteNumber, 128));
613
614 return MidiMessage (MidiHelpers::initialByte (0x80, channel),
615 noteNumber & 127, MidiHelpers::validVelocity (velocity));
616}
617
618 MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, float velocity) noexcept
619{
620 return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
621}
622
623 MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber) noexcept
624{
625 jassert (channel > 0 && channel <= 16);
626 jassert (isPositiveAndBelow (noteNumber, 128));
627
628 return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, 0);
629}
630
631 MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
632{
633 return controllerEvent (channel, 123, 0);
634}
635
636 bool MidiMessage::isAllNotesOff() const noexcept
637{
638 auto data = getRawData();
639 return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
640}
641
642 MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
643{
644 return controllerEvent (channel, 120, 0);
645}
646
647 bool MidiMessage::isAllSoundOff() const noexcept
648{
649 auto data = getRawData();
650 return data[1] == 120 && (data[0] & 0xf0) == 0xb0;
651}
652
653 bool MidiMessage::isResetAllControllers() const noexcept
654{
655 auto data = getRawData();
656 return (data[0] & 0xf0) == 0xb0 && data[1] == 121;
657}
658
659 MidiMessage MidiMessage::allControllersOff (const int channel) noexcept
660{
661 return controllerEvent (channel, 121, 0);
662}
663
664 MidiMessage MidiMessage::masterVolume (const float volume)
665{
666 auto vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000));
667
668 return { 0xf0, 0x7f, 0x7f, 0x04, 0x01, vol & 0x7f, vol >> 7, 0xf7 };
669}
670
671//==============================================================================
672 bool MidiMessage::isSysEx() const noexcept
673{
674 return *getRawData() == 0xf0;
675}
676
677 MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
678{
679 HeapBlock<uint8> m (dataSize + 2);
680
681 m[0] = 0xf0;
682 memcpy (m + 1, sysexData, (size_t) dataSize);
683 m[dataSize + 1] = 0xf7;
684
685 return MidiMessage (m, dataSize + 2);
686}
687
688 MidiMessage MidiMessage::createSysExMessage (Span<const std::byte> data)
689{
690 return createSysExMessage (data.data(), (int) data.size());
691}
692
693 const uint8* MidiMessage::getSysExData() const noexcept
694{
695 return isSysEx() ? getRawData() + 1 : nullptr;
696}
697
698 int MidiMessage::getSysExDataSize() const noexcept
699{
700 return isSysEx() ? size - 2 : 0;
701}
702
703//==============================================================================
704 bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
705 bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
706
707 int MidiMessage::getMetaEventType() const noexcept
708{
709 auto data = getRawData();
710 return (size < 2 || *data != 0xff) ? -1 : data[1];
711}
712
713 int MidiMessage::getMetaEventLength() const noexcept
714{
715 auto data = getRawData();
716
717 if (*data == 0xff)
718 {
719 const auto var = readVariableLengthValue (data + 2, size - 2);
720 return jmax (0, jmin (size - 2 - var.bytesUsed, var.value));
721 }
722
723 return 0;
724}
725
726 const uint8* MidiMessage::getMetaEventData() const noexcept
727{
728 jassert (isMetaEvent());
729
730 auto d = getRawData() + 2;
731 const auto var = readVariableLengthValue (d, size - 2);
732 return d + var.bytesUsed;
733}
734
735 bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; }
736 bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; }
737
738 bool MidiMessage::isTextMetaEvent() const noexcept
739{
740 auto t = getMetaEventType();
741 return t > 0 && t < 16;
742}
743
744 String MidiMessage::getTextFromTextMetaEvent() const
745{
746 auto textData = reinterpret_cast<const char*> (getMetaEventData());
747
748 return String (CharPointer_UTF8 (textData),
749 CharPointer_UTF8 (textData + getMetaEventLength()));
750}
751
752 MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
753{
754 jassert (type > 0 && type < 16);
755
756 MidiMessage result;
757
758 const size_t textSize = text.text.sizeInBytes() - 1;
759
760 uint8 header[8];
761 size_t n = sizeof (header);
762
763 header[--n] = (uint8) (textSize & 0x7f);
764
765 for (size_t i = textSize; (i >>= 7) != 0;)
766 header[--n] = (uint8) ((i & 0x7f) | 0x80);
767
768 header[--n] = (uint8) type;
769 header[--n] = 0xff;
770
771 const size_t headerLen = sizeof (header) - n;
772 const int totalSize = (int) (headerLen + textSize);
773
774 auto dest = result.allocateSpace (totalSize);
775 result.size = totalSize;
776
777 memcpy (dest, header + n, headerLen);
778 memcpy (dest + headerLen, text.text.getAddress(), textSize);
779
780 return result;
781}
782
783 bool MidiMessage::isTrackNameEvent() const noexcept { auto data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
784 bool MidiMessage::isTempoMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
785 bool MidiMessage::isMidiChannelMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
786
787 int MidiMessage::getMidiChannelMetaEventChannel() const noexcept
788{
789 jassert (isMidiChannelMetaEvent());
790 return getRawData()[3] + 1;
791}
792
793 double MidiMessage::getTempoSecondsPerQuarterNote() const noexcept
794{
795 if (! isTempoMetaEvent())
796 return 0.0;
797
798 auto d = getMetaEventData();
799
800 return (((unsigned int) d[0] << 16)
801 | ((unsigned int) d[1] << 8)
802 | d[2])
803 / 1000000.0;
804}
805
806 double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const noexcept
807{
808 if (timeFormat > 0)
809 {
810 if (! isTempoMetaEvent())
811 return 0.5 / timeFormat;
812
813 return getTempoSecondsPerQuarterNote() / timeFormat;
814 }
815
816 const int frameCode = (-timeFormat) >> 8;
817 double framesPerSecond;
818
819 switch (frameCode)
820 {
821 case 24: framesPerSecond = 24.0; break;
822 case 25: framesPerSecond = 25.0; break;
823 case 29: framesPerSecond = 30.0 * 1000.0 / 1001.0; break;
824 case 30: framesPerSecond = 30.0; break;
825 default: framesPerSecond = 30.0; break;
826 }
827
828 return (1.0 / framesPerSecond) / (timeFormat & 0xff);
829}
830
831 MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept
832{
833 return { 0xff, 81, 3,
834 (uint8) (microsecondsPerQuarterNote >> 16),
835 (uint8) (microsecondsPerQuarterNote >> 8),
836 (uint8) microsecondsPerQuarterNote };
837}
838
839 bool MidiMessage::isTimeSignatureMetaEvent() const noexcept
840{
841 auto data = getRawData();
842 return (data[1] == 0x58) && (*data == (uint8) 0xff);
843}
844
845 void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const noexcept
846{
847 if (isTimeSignatureMetaEvent())
848 {
849 auto d = getMetaEventData();
850 numerator = d[0];
851 denominator = 1 << d[1];
852 }
853 else
854 {
855 numerator = 4;
856 denominator = 4;
857 }
858}
859
860 MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator)
861{
862 int n = 1;
863 int powerOfTwo = 0;
864
865 while (n < denominator)
866 {
867 n <<= 1;
868 ++powerOfTwo;
869 }
870
871 return { 0xff, 0x58, 0x04, numerator, powerOfTwo, 1, 96 };
872}
873
874 MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept
875{
876 return { 0xff, 0x20, 0x01, jlimit (0, 0xff, channel - 1) };
877}
878
879 bool MidiMessage::isKeySignatureMetaEvent() const noexcept
880{
881 return getMetaEventType() == 0x59;
882}
883
884 int MidiMessage::getKeySignatureNumberOfSharpsOrFlats() const noexcept
885{
886 return (int) (int8) getMetaEventData()[0];
887}
888
889 bool MidiMessage::isKeySignatureMajorKey() const noexcept
890{
891 return getMetaEventData()[1] == 0;
892}
893
894 MidiMessage MidiMessage::keySignatureMetaEvent (int numberOfSharpsOrFlats, bool isMinorKey)
895{
896 jassert (numberOfSharpsOrFlats >= -7 && numberOfSharpsOrFlats <= 7);
897
898 return { 0xff, 0x59, 0x02, numberOfSharpsOrFlats, isMinorKey ? 1 : 0 };
899}
900
901 MidiMessage MidiMessage::endOfTrack() noexcept
902{
903 return { 0xff, 0x2f, 0x00 };
904}
905
906//==============================================================================
907 bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
908 int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { auto data = getRawData(); return data[1] | (data[2] << 7); }
909
910 MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
911{
912 return { 0xf2,
913 positionInMidiBeats & 127,
914 (positionInMidiBeats >> 7) & 127 };
915}
916
917 bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
918 MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
919
920 bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
921 MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
922
923 bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
924 MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
925
926 bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
927 MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
928
929 bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
930 int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
931 int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
932
933 MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
934{
935 return MidiMessage (0xf1, (sequenceNumber << 4) | value);
936}
937
938 bool MidiMessage::isFullFrame() const noexcept
939{
940 auto data = getRawData();
941
942 return data[0] == 0xf0
943 && data[1] == 0x7f
944 && size >= 10
945 && data[3] == 0x01
946 && data[4] == 0x01;
947}
948
949 void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames,
950 MidiMessage::SmpteTimecodeType& timecodeType) const noexcept
951{
952 jassert (isFullFrame());
953
954 auto data = getRawData();
955 timecodeType = (SmpteTimecodeType) (data[5] >> 5);
956 hours = data[5] & 0x1f;
957 minutes = data[6];
958 seconds = data[7];
959 frames = data[8];
960}
961
962 MidiMessage MidiMessage::fullFrame (int hours, int minutes, int seconds, int frames,
963 MidiMessage::SmpteTimecodeType timecodeType)
964{
965 return { 0xf0, 0x7f, 0x7f, 0x01, 0x01,
966 (hours & 0x01f) | (timecodeType << 5),
967 minutes, seconds, frames,
968 0xf7 };
969}
970
971 bool MidiMessage::isMidiMachineControlMessage() const noexcept
972{
973 auto data = getRawData();
974
975 return data[0] == 0xf0
976 && data[1] == 0x7f
977 && data[3] == 0x06
978 && size > 5;
979}
980
981 MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand() const noexcept
982{
983 jassert (isMidiMachineControlMessage());
984
985 return (MidiMachineControlCommand) getRawData()[4];
986}
987
988 MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command)
989{
990 return { 0xf0, 0x7f, 0, 6, command, 0xf7 };
991}
992
993//==============================================================================
994 bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
995{
996 auto data = getRawData();
997
998 if (size >= 12
999 && data[0] == 0xf0
1000 && data[1] == 0x7f
1001 && data[3] == 0x06
1002 && data[4] == 0x44
1003 && data[5] == 0x06
1004 && data[6] == 0x01)
1005 {
1006 hours = data[7] % 24; // (that some machines send out hours > 24)
1007 minutes = data[8];
1008 seconds = data[9];
1009 frames = data[10];
1010
1011 return true;
1012 }
1013
1014 return false;
1015}
1016
1017 MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames)
1018{
1019 return { 0xf0, 0x7f, 0, 6, 0x44, 6, 1, hours, minutes, seconds, frames, 0xf7 };
1020}
1021
1022//==============================================================================
1023 String MidiMessage::getMidiNoteName (int note, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
1024{
1025 static const char* const sharpNoteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
1026 static const char* const flatNoteNames[] = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
1027
1028 if (isPositiveAndBelow (note, 128))
1029 {
1030 String s (useSharps ? sharpNoteNames[note % 12]
1031 : flatNoteNames [note % 12]);
1032
1033 if (includeOctaveNumber)
1034 s << (note / 12 + (octaveNumForMiddleC - 5));
1035
1036 return s;
1037 }
1038
1039 return {};
1040}
1041
1042 double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
1043{
1044 return frequencyOfA * std::pow (2.0, (noteNumber - 69) / 12.0);
1045}
1046
1047 bool MidiMessage::isMidiNoteBlack (int noteNumber) noexcept
1048{
1049 return ((1 << (noteNumber % 12)) & 0x054a) != 0;
1050}
1051
1052 const char* MidiMessage::getGMInstrumentName (const int n)
1053{
1054 static const char* names[] =
1055 {
1056 NEEDS_TRANS ("Acoustic Grand Piano"), NEEDS_TRANS ("Bright Acoustic Piano"), NEEDS_TRANS ("Electric Grand Piano"), NEEDS_TRANS ("Honky-tonk Piano"),
1057 NEEDS_TRANS ("Electric Piano 1"), NEEDS_TRANS ("Electric Piano 2"), NEEDS_TRANS ("Harpsichord"), NEEDS_TRANS ("Clavinet"),
1058 NEEDS_TRANS ("Celesta"), NEEDS_TRANS ("Glockenspiel"), NEEDS_TRANS ("Music Box"), NEEDS_TRANS ("Vibraphone"),
1059 NEEDS_TRANS ("Marimba"), NEEDS_TRANS ("Xylophone"), NEEDS_TRANS ("Tubular Bells"), NEEDS_TRANS ("Dulcimer"),
1060 NEEDS_TRANS ("Drawbar Organ"), NEEDS_TRANS ("Percussive Organ"), NEEDS_TRANS ("Rock Organ"), NEEDS_TRANS ("Church Organ"),
1061 NEEDS_TRANS ("Reed Organ"), NEEDS_TRANS ("Accordion"), NEEDS_TRANS ("Harmonica"), NEEDS_TRANS ("Tango Accordion"),
1062 NEEDS_TRANS ("Acoustic Guitar (nylon)"), NEEDS_TRANS ("Acoustic Guitar (steel)"), NEEDS_TRANS ("Electric Guitar (jazz)"), NEEDS_TRANS ("Electric Guitar (clean)"),
1063 NEEDS_TRANS ("Electric Guitar (mute)"), NEEDS_TRANS ("Overdriven Guitar"), NEEDS_TRANS ("Distortion Guitar"), NEEDS_TRANS ("Guitar Harmonics"),
1064 NEEDS_TRANS ("Acoustic Bass"), NEEDS_TRANS ("Electric Bass (finger)"), NEEDS_TRANS ("Electric Bass (pick)"), NEEDS_TRANS ("Fretless Bass"),
1065 NEEDS_TRANS ("Slap Bass 1"), NEEDS_TRANS ("Slap Bass 2"), NEEDS_TRANS ("Synth Bass 1"), NEEDS_TRANS ("Synth Bass 2"),
1066 NEEDS_TRANS ("Violin"), NEEDS_TRANS ("Viola"), NEEDS_TRANS ("Cello"), NEEDS_TRANS ("Contrabass"),
1067 NEEDS_TRANS ("Tremolo Strings"), NEEDS_TRANS ("Pizzicato Strings"), NEEDS_TRANS ("Orchestral Harp"), NEEDS_TRANS ("Timpani"),
1068 NEEDS_TRANS ("String Ensemble 1"), NEEDS_TRANS ("String Ensemble 2"), NEEDS_TRANS ("SynthStrings 1"), NEEDS_TRANS ("SynthStrings 2"),
1069 NEEDS_TRANS ("Choir Aahs"), NEEDS_TRANS ("Voice Oohs"), NEEDS_TRANS ("Synth Voice"), NEEDS_TRANS ("Orchestra Hit"),
1070 NEEDS_TRANS ("Trumpet"), NEEDS_TRANS ("Trombone"), NEEDS_TRANS ("Tuba"), NEEDS_TRANS ("Muted Trumpet"),
1071 NEEDS_TRANS ("French Horn"), NEEDS_TRANS ("Brass Section"), NEEDS_TRANS ("SynthBrass 1"), NEEDS_TRANS ("SynthBrass 2"),
1072 NEEDS_TRANS ("Soprano Sax"), NEEDS_TRANS ("Alto Sax"), NEEDS_TRANS ("Tenor Sax"), NEEDS_TRANS ("Baritone Sax"),
1073 NEEDS_TRANS ("Oboe"), NEEDS_TRANS ("English Horn"), NEEDS_TRANS ("Bassoon"), NEEDS_TRANS ("Clarinet"),
1074 NEEDS_TRANS ("Piccolo"), NEEDS_TRANS ("Flute"), NEEDS_TRANS ("Recorder"), NEEDS_TRANS ("Pan Flute"),
1075 NEEDS_TRANS ("Blown Bottle"), NEEDS_TRANS ("Shakuhachi"), NEEDS_TRANS ("Whistle"), NEEDS_TRANS ("Ocarina"),
1076 NEEDS_TRANS ("Lead 1 (square)"), NEEDS_TRANS ("Lead 2 (sawtooth)"), NEEDS_TRANS ("Lead 3 (calliope)"), NEEDS_TRANS ("Lead 4 (chiff)"),
1077 NEEDS_TRANS ("Lead 5 (charang)"), NEEDS_TRANS ("Lead 6 (voice)"), NEEDS_TRANS ("Lead 7 (fifths)"), NEEDS_TRANS ("Lead 8 (bass+lead)"),
1078 NEEDS_TRANS ("Pad 1 (new age)"), NEEDS_TRANS ("Pad 2 (warm)"), NEEDS_TRANS ("Pad 3 (polysynth)"), NEEDS_TRANS ("Pad 4 (choir)"),
1079 NEEDS_TRANS ("Pad 5 (bowed)"), NEEDS_TRANS ("Pad 6 (metallic)"), NEEDS_TRANS ("Pad 7 (halo)"), NEEDS_TRANS ("Pad 8 (sweep)"),
1080 NEEDS_TRANS ("FX 1 (rain)"), NEEDS_TRANS ("FX 2 (soundtrack)"), NEEDS_TRANS ("FX 3 (crystal)"), NEEDS_TRANS ("FX 4 (atmosphere)"),
1081 NEEDS_TRANS ("FX 5 (brightness)"), NEEDS_TRANS ("FX 6 (goblins)"), NEEDS_TRANS ("FX 7 (echoes)"), NEEDS_TRANS ("FX 8 (sci-fi)"),
1082 NEEDS_TRANS ("Sitar"), NEEDS_TRANS ("Banjo"), NEEDS_TRANS ("Shamisen"), NEEDS_TRANS ("Koto"),
1083 NEEDS_TRANS ("Kalimba"), NEEDS_TRANS ("Bag pipe"), NEEDS_TRANS ("Fiddle"), NEEDS_TRANS ("Shanai"),
1084 NEEDS_TRANS ("Tinkle Bell"), NEEDS_TRANS ("Agogo"), NEEDS_TRANS ("Steel Drums"), NEEDS_TRANS ("Woodblock"),
1085 NEEDS_TRANS ("Taiko Drum"), NEEDS_TRANS ("Melodic Tom"), NEEDS_TRANS ("Synth Drum"), NEEDS_TRANS ("Reverse Cymbal"),
1086 NEEDS_TRANS ("Guitar Fret Noise"), NEEDS_TRANS ("Breath Noise"), NEEDS_TRANS ("Seashore"), NEEDS_TRANS ("Bird Tweet"),
1087 NEEDS_TRANS ("Telephone Ring"), NEEDS_TRANS ("Helicopter"), NEEDS_TRANS ("Applause"), NEEDS_TRANS ("Gunshot")
1088 };
1089
1090 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1091}
1092
1093 const char* MidiMessage::getGMInstrumentBankName (const int n)
1094{
1095 static const char* names[] =
1096 {
1097 NEEDS_TRANS ("Piano"), NEEDS_TRANS ("Chromatic Percussion"), NEEDS_TRANS ("Organ"), NEEDS_TRANS ("Guitar"),
1098 NEEDS_TRANS ("Bass"), NEEDS_TRANS ("Strings"), NEEDS_TRANS ("Ensemble"), NEEDS_TRANS ("Brass"),
1099 NEEDS_TRANS ("Reed"), NEEDS_TRANS ("Pipe"), NEEDS_TRANS ("Synth Lead"), NEEDS_TRANS ("Synth Pad"),
1100 NEEDS_TRANS ("Synth Effects"), NEEDS_TRANS ("Ethnic"), NEEDS_TRANS ("Percussive"), NEEDS_TRANS ("Sound Effects")
1101 };
1102
1103 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1104}
1105
1106 const char* MidiMessage::getRhythmInstrumentName (const int n)
1107{
1108 static const char* names[] =
1109 {
1110 NEEDS_TRANS ("Acoustic Bass Drum"), NEEDS_TRANS ("Bass Drum 1"), NEEDS_TRANS ("Side Stick"), NEEDS_TRANS ("Acoustic Snare"),
1111 NEEDS_TRANS ("Hand Clap"), NEEDS_TRANS ("Electric Snare"), NEEDS_TRANS ("Low Floor Tom"), NEEDS_TRANS ("Closed Hi-Hat"),
1112 NEEDS_TRANS ("High Floor Tom"), NEEDS_TRANS ("Pedal Hi-Hat"), NEEDS_TRANS ("Low Tom"), NEEDS_TRANS ("Open Hi-Hat"),
1113 NEEDS_TRANS ("Low-Mid Tom"), NEEDS_TRANS ("Hi-Mid Tom"), NEEDS_TRANS ("Crash Cymbal 1"), NEEDS_TRANS ("High Tom"),
1114 NEEDS_TRANS ("Ride Cymbal 1"), NEEDS_TRANS ("Chinese Cymbal"), NEEDS_TRANS ("Ride Bell"), NEEDS_TRANS ("Tambourine"),
1115 NEEDS_TRANS ("Splash Cymbal"), NEEDS_TRANS ("Cowbell"), NEEDS_TRANS ("Crash Cymbal 2"), NEEDS_TRANS ("Vibraslap"),
1116 NEEDS_TRANS ("Ride Cymbal 2"), NEEDS_TRANS ("Hi Bongo"), NEEDS_TRANS ("Low Bongo"), NEEDS_TRANS ("Mute Hi Conga"),
1117 NEEDS_TRANS ("Open Hi Conga"), NEEDS_TRANS ("Low Conga"), NEEDS_TRANS ("High Timbale"), NEEDS_TRANS ("Low Timbale"),
1118 NEEDS_TRANS ("High Agogo"), NEEDS_TRANS ("Low Agogo"), NEEDS_TRANS ("Cabasa"), NEEDS_TRANS ("Maracas"),
1119 NEEDS_TRANS ("Short Whistle"), NEEDS_TRANS ("Long Whistle"), NEEDS_TRANS ("Short Guiro"), NEEDS_TRANS ("Long Guiro"),
1120 NEEDS_TRANS ("Claves"), NEEDS_TRANS ("Hi Wood Block"), NEEDS_TRANS ("Low Wood Block"), NEEDS_TRANS ("Mute Cuica"),
1121 NEEDS_TRANS ("Open Cuica"), NEEDS_TRANS ("Mute Triangle"), NEEDS_TRANS ("Open Triangle")
1122 };
1123
1124 return (n >= 35 && n <= 81) ? names[n - 35] : nullptr;
1125}
1126
1127 const char* MidiMessage::getControllerName (const int n)
1128{
1129 static const char* names[] =
1130 {
1131 NEEDS_TRANS ("Bank Select"), NEEDS_TRANS ("Modulation Wheel (coarse)"), NEEDS_TRANS ("Breath controller (coarse)"),
1132 nullptr,
1133 NEEDS_TRANS ("Foot Pedal (coarse)"), NEEDS_TRANS ("Portamento Time (coarse)"), NEEDS_TRANS ("Data Entry (coarse)"),
1134 NEEDS_TRANS ("Volume (coarse)"), NEEDS_TRANS ("Balance (coarse)"),
1135 nullptr,
1136 NEEDS_TRANS ("Pan position (coarse)"), NEEDS_TRANS ("Expression (coarse)"), NEEDS_TRANS ("Effect Control 1 (coarse)"),
1137 NEEDS_TRANS ("Effect Control 2 (coarse)"),
1138 nullptr, nullptr,
1139 NEEDS_TRANS ("General Purpose Slider 1"), NEEDS_TRANS ("General Purpose Slider 2"),
1140 NEEDS_TRANS ("General Purpose Slider 3"), NEEDS_TRANS ("General Purpose Slider 4"),
1141 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1142 NEEDS_TRANS ("Bank Select (fine)"), NEEDS_TRANS ("Modulation Wheel (fine)"), NEEDS_TRANS ("Breath controller (fine)"),
1143 nullptr,
1144 NEEDS_TRANS ("Foot Pedal (fine)"), NEEDS_TRANS ("Portamento Time (fine)"), NEEDS_TRANS ("Data Entry (fine)"), NEEDS_TRANS ("Volume (fine)"),
1145 NEEDS_TRANS ("Balance (fine)"), nullptr, NEEDS_TRANS ("Pan position (fine)"), NEEDS_TRANS ("Expression (fine)"),
1146 NEEDS_TRANS ("Effect Control 1 (fine)"), NEEDS_TRANS ("Effect Control 2 (fine)"),
1147 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1148 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1149 NEEDS_TRANS ("Hold Pedal (on/off)"), NEEDS_TRANS ("Portamento (on/off)"), NEEDS_TRANS ("Sustenuto Pedal (on/off)"), NEEDS_TRANS ("Soft Pedal (on/off)"),
1150 NEEDS_TRANS ("Legato Pedal (on/off)"), NEEDS_TRANS ("Hold 2 Pedal (on/off)"), NEEDS_TRANS ("Sound Variation"), NEEDS_TRANS ("Sound Timbre"),
1151 NEEDS_TRANS ("Sound Release Time"), NEEDS_TRANS ("Sound Attack Time"), NEEDS_TRANS ("Sound Brightness"), NEEDS_TRANS ("Sound Control 6"),
1152 NEEDS_TRANS ("Sound Control 7"), NEEDS_TRANS ("Sound Control 8"), NEEDS_TRANS ("Sound Control 9"), NEEDS_TRANS ("Sound Control 10"),
1153 NEEDS_TRANS ("General Purpose Button 1 (on/off)"), NEEDS_TRANS ("General Purpose Button 2 (on/off)"),
1154 NEEDS_TRANS ("General Purpose Button 3 (on/off)"), NEEDS_TRANS ("General Purpose Button 4 (on/off)"),
1155 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1156 NEEDS_TRANS ("Reverb Level"), NEEDS_TRANS ("Tremolo Level"), NEEDS_TRANS ("Chorus Level"), NEEDS_TRANS ("Celeste Level"),
1157 NEEDS_TRANS ("Phaser Level"), NEEDS_TRANS ("Data Button increment"), NEEDS_TRANS ("Data Button decrement"), NEEDS_TRANS ("Non-registered Parameter (fine)"),
1158 NEEDS_TRANS ("Non-registered Parameter (coarse)"), NEEDS_TRANS ("Registered Parameter (fine)"), NEEDS_TRANS ("Registered Parameter (coarse)"),
1159 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1160 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1161 NEEDS_TRANS ("All Sound Off"), NEEDS_TRANS ("All Controllers Off"), NEEDS_TRANS ("Local Keyboard (on/off)"), NEEDS_TRANS ("All Notes Off"),
1162 NEEDS_TRANS ("Omni Mode Off"), NEEDS_TRANS ("Omni Mode On"), NEEDS_TRANS ("Mono Operation"), NEEDS_TRANS ("Poly Operation")
1163 };
1164
1165 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1166}
1167
1168//==============================================================================
1169//==============================================================================
1170#if JUCE_UNIT_TESTS
1171
1172struct MidiMessageTest final : public UnitTest
1173{
1174 MidiMessageTest()
1175 : UnitTest ("MidiMessage", UnitTestCategories::midi)
1176 {}
1177
1178 void runTest() override
1179 {
1180 using std::begin;
1181 using std::end;
1182
1183 beginTest ("ReadVariableLengthValue should return valid, backward-compatible results");
1184 {
1185 const std::vector<uint8> inputs[]
1186 {
1187 { 0x00 },
1188 { 0x40 },
1189 { 0x7f },
1190 { 0x81, 0x00 },
1191 { 0xc0, 0x00 },
1192 { 0xff, 0x7f },
1193 { 0x81, 0x80, 0x00 },
1194 { 0xc0, 0x80, 0x00 },
1195 { 0xff, 0xff, 0x7f },
1196 { 0x81, 0x80, 0x80, 0x00 },
1197 { 0xc0, 0x80, 0x80, 0x00 },
1198 { 0xff, 0xff, 0xff, 0x7f }
1199 };
1200
1201 const int outputs[]
1202 {
1203 0x00,
1204 0x40,
1205 0x7f,
1206 0x80,
1207 0x2000,
1208 0x3fff,
1209 0x4000,
1210 0x100000,
1211 0x1fffff,
1212 0x200000,
1213 0x8000000,
1214 0xfffffff,
1215 };
1216
1217 expectEquals (std::distance (begin (inputs), end (inputs)),
1218 std::distance (begin (outputs), end (outputs)));
1219
1220 size_t index = 0;
1221
1222 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
1223 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1224
1225 for (const auto& input : inputs)
1226 {
1227 auto copy = input;
1228
1229 while (copy.size() < 16)
1230 copy.push_back (0);
1231
1232 const auto result = MidiMessage::readVariableLengthValue (copy.data(),
1233 (int) copy.size());
1234
1235 expect (result.isValid());
1236 expectEquals (result.value, outputs[index]);
1237 expectEquals (result.bytesUsed, (int) inputs[index].size());
1238
1239 int legacyNumUsed = 0;
1240 const auto legacyResult = MidiMessage::readVariableLengthVal (copy.data(),
1241 legacyNumUsed);
1242
1243 expectEquals (result.value, legacyResult);
1244 expectEquals (result.bytesUsed, legacyNumUsed);
1245
1246 ++index;
1247 }
1248
1249 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1250 JUCE_END_IGNORE_WARNINGS_MSVC
1251 }
1252
1253 beginTest ("ReadVariableLengthVal should return 0 if input is truncated");
1254 {
1255 for (size_t i = 0; i != 16; ++i)
1256 {
1257 std::vector<uint8> input;
1258 input.resize (i, 0xFF);
1259
1260 const auto result = MidiMessage::readVariableLengthValue (input.data(),
1261 (int) input.size());
1262
1263 expect (! result.isValid());
1264 expectEquals (result.value, 0);
1265 expectEquals (result.bytesUsed, 0);
1266 }
1267 }
1268
1269 const std::vector<uint8> metaEvents[]
1270 {
1271 // Format is 0xff, followed by a 'kind' byte, followed by a variable-length
1272 // 'data-length' value, followed by that many data bytes
1273 { 0xff, 0x00, 0x02, 0x00, 0x00 }, // Sequence number
1274 { 0xff, 0x01, 0x00 }, // Text event
1275 { 0xff, 0x02, 0x00 }, // Copyright notice
1276 { 0xff, 0x03, 0x00 }, // Track name
1277 { 0xff, 0x04, 0x00 }, // Instrument name
1278 { 0xff, 0x05, 0x00 }, // Lyric
1279 { 0xff, 0x06, 0x00 }, // Marker
1280 { 0xff, 0x07, 0x00 }, // Cue point
1281 { 0xff, 0x20, 0x01, 0x00 }, // Channel prefix
1282 { 0xff, 0x2f, 0x00 }, // End of track
1283 { 0xff, 0x51, 0x03, 0x01, 0x02, 0x03 }, // Set tempo
1284 { 0xff, 0x54, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05 }, // SMPTE offset
1285 { 0xff, 0x58, 0x04, 0x01, 0x02, 0x03, 0x04 }, // Time signature
1286 { 0xff, 0x59, 0x02, 0x01, 0x02 }, // Key signature
1287 { 0xff, 0x7f, 0x00 }, // Sequencer-specific
1288 };
1289
1290 beginTest ("MidiMessage data constructor works for well-formed meta-events");
1291 {
1292 const auto status = (uint8) 0x90;
1293
1294 for (const auto& input : metaEvents)
1295 {
1296 int bytesUsed = 0;
1297 const MidiMessage msg (input.data(), (int) input.size(), bytesUsed, status);
1298
1299 expect (msg.isMetaEvent());
1300 expectEquals (msg.getMetaEventLength(), (int) input.size() - 3);
1301 expectEquals (msg.getMetaEventType(), (int) input[1]);
1302 }
1303 }
1304
1305 beginTest ("MidiMessage data constructor works for malformed meta-events");
1306 {
1307 const auto status = (uint8) 0x90;
1308
1309 const auto runTest = [&] (const std::vector<uint8>& input)
1310 {
1311 int bytesUsed = 0;
1312 const MidiMessage msg (input.data(), (int) input.size(), bytesUsed, status);
1313
1314 expect (msg.isMetaEvent());
1315 expectEquals (msg.getMetaEventLength(), jmax (0, (int) input.size() - 3));
1316 expectEquals (msg.getMetaEventType(), input.size() >= 2 ? input[1] : -1);
1317 };
1318
1319 runTest ({ 0xff });
1320
1321 for (const auto& input : metaEvents)
1322 {
1323 auto copy = input;
1324 copy[2] = 0x40; // Set the size of the message to more bytes than are present
1325
1326 runTest (copy);
1327 }
1328 }
1329 }
1330};
1331
1332static MidiMessageTest midiMessageTests;
1333
1334#endif
1335
1336} // namespace juce
juce::CharPointer_UTF8
Definition juce_CharPointer_UTF8.h:35
juce::HeapBlock
Definition juce_HeapBlock.h:87
juce::MidiMessage
Definition juce_MidiMessage.h:35
juce::MidiMessage::isTrackMetaEvent
bool isTrackMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:735
juce::MidiMessage::createSysExMessage
static MidiMessage createSysExMessage(const void *sysexData, int dataSize)
Definition juce_MidiMessage.cpp:677
juce::MidiMessage::tempoMetaEvent
static MidiMessage tempoMetaEvent(int microsecondsPerQuarterNote) noexcept
Definition juce_MidiMessage.cpp:831
juce::MidiMessage::midiStart
static MidiMessage midiStart() noexcept
Definition juce_MidiMessage.cpp:918
juce::MidiMessage::~MidiMessage
~MidiMessage() noexcept
Definition juce_MidiMessage.cpp:331
juce::MidiMessage::getSysExData
const uint8 * getSysExData() const noexcept
Definition juce_MidiMessage.cpp:693
juce::MidiMessage::getDescription
String getDescription() const
Definition juce_MidiMessage.cpp:349
juce::MidiMessage::getGMInstrumentBankName
static const char * getGMInstrumentBankName(int midiBankNumber)
Definition juce_MidiMessage.cpp:1093
juce::MidiMessage::isAftertouch
bool isAftertouch() const noexcept
Definition juce_MidiMessage.cpp:471
juce::MidiMessage::setNoteNumber
void setNoteNumber(int newNoteNumber) noexcept
Definition juce_MidiMessage.cpp:437
juce::MidiMessage::isNoteOn
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
Definition juce_MidiMessage.cpp:410
juce::MidiMessage::getKeySignatureNumberOfSharpsOrFlats
int getKeySignatureNumberOfSharpsOrFlats() const noexcept
Definition juce_MidiMessage.cpp:884
juce::MidiMessage::getSongPositionPointerMidiBeat
int getSongPositionPointerMidiBeat() const noexcept
Definition juce_MidiMessage.cpp:908
juce::MidiMessage::multiplyVelocity
void multiplyVelocity(float scaleFactor) noexcept
Definition juce_MidiMessage.cpp:462
juce::MidiMessage::getFullFrameParameters
void getFullFrameParameters(int &hours, int &minutes, int &seconds, int &frames, SmpteTimecodeType &timecodeType) const noexcept
Definition juce_MidiMessage.cpp:949
juce::MidiMessage::getFloatVelocity
float getFloatVelocity() const noexcept
Definition juce_MidiMessage.cpp:451
juce::MidiMessage::isMidiMachineControlMessage
bool isMidiMachineControlMessage() const noexcept
Definition juce_MidiMessage.cpp:971
juce::MidiMessage::getChannel
int getChannel() const noexcept
Definition juce_MidiMessage.cpp:379
juce::MidiMessage::isMidiNoteBlack
static bool isMidiNoteBlack(int noteNumber) noexcept
Definition juce_MidiMessage.cpp:1047
juce::MidiMessage::aftertouchChange
static MidiMessage aftertouchChange(int channel, int noteNumber, int aftertouchAmount) noexcept
Definition juce_MidiMessage.cpp:482
juce::MidiMessage::readVariableLengthVal
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
Definition juce_MidiMessage.cpp:85
juce::MidiMessage::getQuarterFrameSequenceNumber
int getQuarterFrameSequenceNumber() const noexcept
Definition juce_MidiMessage.cpp:930
juce::MidiMessage::getSysExDataSize
int getSysExDataSize() const noexcept
Definition juce_MidiMessage.cpp:698
juce::MidiMessage::isQuarterFrame
bool isQuarterFrame() const noexcept
Definition juce_MidiMessage.cpp:929
juce::MidiMessage::getRawData
const uint8 * getRawData() const noexcept
Definition juce_MidiMessage.h:134
juce::MidiMessage::isTextMetaEvent
bool isTextMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:738
juce::MidiMessage::setVelocity
void setVelocity(float newVelocity) noexcept
Definition juce_MidiMessage.cpp:456
juce::MidiMessage::getMetaEventType
int getMetaEventType() const noexcept
Definition juce_MidiMessage.cpp:707
juce::MidiMessage::isProgramChange
bool isProgramChange() const noexcept
Definition juce_MidiMessage.cpp:524
juce::MidiMessage::isController
bool isController() const noexcept
Definition juce_MidiMessage.cpp:563
juce::MidiMessage::getTimeSignatureInfo
void getTimeSignatureInfo(int &numerator, int &denominator) const noexcept
Definition juce_MidiMessage.cpp:845
juce::MidiMessage::isAllSoundOff
bool isAllSoundOff() const noexcept
Definition juce_MidiMessage.cpp:647
juce::MidiMessage::isSoftPedalOn
bool isSoftPedalOn() const noexcept
Definition juce_MidiMessage.cpp:520
juce::MidiMessage::getControllerNumber
int getControllerNumber() const noexcept
Definition juce_MidiMessage.cpp:574
juce::MidiMessage::isMidiStart
bool isMidiStart() const noexcept
Definition juce_MidiMessage.cpp:917
juce::MidiMessage::getMidiNoteInHertz
static double getMidiNoteInHertz(int noteNumber, double frequencyOfA=440.0) noexcept
Definition juce_MidiMessage.cpp:1042
juce::MidiMessage::getQuarterFrameValue
int getQuarterFrameValue() const noexcept
Definition juce_MidiMessage.cpp:931
juce::MidiMessage::isTrackNameEvent
bool isTrackNameEvent() const noexcept
Definition juce_MidiMessage.cpp:783
juce::MidiMessage::getChannelPressureValue
int getChannelPressureValue() const noexcept
Definition juce_MidiMessage.cpp:500
juce::MidiMessage::pitchWheel
static MidiMessage pitchWheel(int channel, int position) noexcept
Definition juce_MidiMessage.cpp:554
juce::MidiMessage::isForChannel
bool isForChannel(int channelNumber) const noexcept
Definition juce_MidiMessage.cpp:389
juce::MidiMessage::isNoteOff
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
Definition juce_MidiMessage.cpp:418
juce::MidiMessage::getMetaEventData
const uint8 * getMetaEventData() const noexcept
Definition juce_MidiMessage.cpp:726
juce::MidiMessage::isKeySignatureMetaEvent
bool isKeySignatureMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:879
juce::MidiMessage::noteOn
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
Definition juce_MidiMessage.cpp:604
juce::MidiMessage::quarterFrame
static MidiMessage quarterFrame(int sequenceNumber, int value) noexcept
Definition juce_MidiMessage.cpp:933
juce::MidiMessage::isPitchWheel
bool isPitchWheel() const noexcept
Definition juce_MidiMessage.cpp:542
juce::MidiMessage::isSustainPedalOn
bool isSustainPedalOn() const noexcept
Definition juce_MidiMessage.cpp:514
juce::MidiMessage::isMidiContinue
bool isMidiContinue() const noexcept
Definition juce_MidiMessage.cpp:920
juce::MidiMessage::midiStop
static MidiMessage midiStop() noexcept
Definition juce_MidiMessage.cpp:924
juce::MidiMessage::timeSignatureMetaEvent
static MidiMessage timeSignatureMetaEvent(int numerator, int denominator)
Definition juce_MidiMessage.cpp:860
juce::MidiMessage::isSostenutoPedalOn
bool isSostenutoPedalOn() const noexcept
Definition juce_MidiMessage.cpp:517
juce::MidiMessage::pitchbendToPitchwheelPos
static uint16 pitchbendToPitchwheelPos(float pitchbendInSemitones, float pitchbendRangeInSemitones) noexcept
Definition juce_MidiMessage.cpp:48
juce::MidiMessage::getNoteNumber
int getNoteNumber() const noexcept
Definition juce_MidiMessage.cpp:432
juce::MidiMessage::midiChannelMetaEvent
static MidiMessage midiChannelMetaEvent(int channel) noexcept
Definition juce_MidiMessage.cpp:874
juce::MidiMessage::getProgramChangeNumber
int getProgramChangeNumber() const noexcept
Definition juce_MidiMessage.cpp:529
juce::MidiMessage::getGMInstrumentName
static const char * getGMInstrumentName(int midiInstrumentNumber)
Definition juce_MidiMessage.cpp:1052
juce::MidiMessage::isSostenutoPedalOff
bool isSostenutoPedalOff() const noexcept
Definition juce_MidiMessage.cpp:518
juce::MidiMessage::getMidiChannelMetaEventChannel
int getMidiChannelMetaEventChannel() const noexcept
Definition juce_MidiMessage.cpp:787
juce::MidiMessage::MidiMachineControlCommand
MidiMachineControlCommand
Definition juce_MidiMessage.h:808
juce::MidiMessage::isTimeSignatureMetaEvent
bool isTimeSignatureMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:839
juce::MidiMessage::allNotesOff
static MidiMessage allNotesOff(int channel) noexcept
Definition juce_MidiMessage.cpp:631
juce::MidiMessage::controllerEvent
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
Definition juce_MidiMessage.cpp:586
juce::MidiMessage::isControllerOfType
bool isControllerOfType(int controllerType) const noexcept
Definition juce_MidiMessage.cpp:568
juce::MidiMessage::isTempoMetaEvent
bool isTempoMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:784
juce::MidiMessage::floatValueToMidiByte
static uint8 floatValueToMidiByte(float valueBetween0and1) noexcept
Definition juce_MidiMessage.cpp:40
juce::MidiMessage::keySignatureMetaEvent
static MidiMessage keySignatureMetaEvent(int numberOfSharpsOrFlats, bool isMinorKey)
Definition juce_MidiMessage.cpp:894
juce::MidiMessage::midiClock
static MidiMessage midiClock() noexcept
Definition juce_MidiMessage.cpp:927
juce::MidiMessage::isResetAllControllers
bool isResetAllControllers() const noexcept
Definition juce_MidiMessage.cpp:653
juce::MidiMessage::fullFrame
static MidiMessage fullFrame(int hours, int minutes, int seconds, int frames, SmpteTimecodeType timecodeType)
Definition juce_MidiMessage.cpp:962
juce::MidiMessage::isSoftPedalOff
bool isSoftPedalOff() const noexcept
Definition juce_MidiMessage.cpp:521
juce::MidiMessage::getMetaEventLength
int getMetaEventLength() const noexcept
Definition juce_MidiMessage.cpp:713
juce::MidiMessage::isMidiStop
bool isMidiStop() const noexcept
Definition juce_MidiMessage.cpp:923
juce::MidiMessage::operator=
MidiMessage & operator=(const MidiMessage &other)
Definition juce_MidiMessage.cpp:284
juce::MidiMessage::isActiveSense
bool isActiveSense() const noexcept
Definition juce_MidiMessage.cpp:705
juce::MidiMessage::getTempoSecondsPerQuarterNote
double getTempoSecondsPerQuarterNote() const noexcept
Definition juce_MidiMessage.cpp:793
juce::MidiMessage::masterVolume
static MidiMessage masterVolume(float volume)
Definition juce_MidiMessage.cpp:664
juce::MidiMessage::getAfterTouchValue
int getAfterTouchValue() const noexcept
Definition juce_MidiMessage.cpp:476
juce::MidiMessage::textMetaEvent
static MidiMessage textMetaEvent(int type, StringRef text)
Definition juce_MidiMessage.cpp:752
juce::MidiMessage::MidiMessage
MidiMessage() noexcept
Definition juce_MidiMessage.cpp:125
juce::MidiMessage::channelPressureChange
static MidiMessage channelPressureChange(int channel, int pressure) noexcept
Definition juce_MidiMessage.cpp:506
juce::MidiMessage::isFullFrame
bool isFullFrame() const noexcept
Definition juce_MidiMessage.cpp:938
juce::MidiMessage::getTempoMetaEventTickLength
double getTempoMetaEventTickLength(short timeFormat) const noexcept
Definition juce_MidiMessage.cpp:806
juce::MidiMessage::getMessageLengthFromFirstByte
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
Definition juce_MidiMessage.cpp:104
juce::MidiMessage::isEndOfTrackMetaEvent
bool isEndOfTrackMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:736
juce::MidiMessage::isNoteOnOrOff
bool isNoteOnOrOff() const noexcept
Definition juce_MidiMessage.cpp:426
juce::MidiMessage::midiContinue
static MidiMessage midiContinue() noexcept
Definition juce_MidiMessage.cpp:921
juce::MidiMessage::getControllerValue
int getControllerValue() const noexcept
Definition juce_MidiMessage.cpp:580
juce::MidiMessage::getMidiNoteName
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
Definition juce_MidiMessage.cpp:1023
juce::MidiMessage::midiMachineControlGoto
static MidiMessage midiMachineControlGoto(int hours, int minutes, int seconds, int frames)
Definition juce_MidiMessage.cpp:1017
juce::MidiMessage::isAllNotesOff
bool isAllNotesOff() const noexcept
Definition juce_MidiMessage.cpp:636
juce::MidiMessage::noteOff
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
Definition juce_MidiMessage.cpp:618
juce::MidiMessage::isMidiMachineControlGoto
bool isMidiMachineControlGoto(int &hours, int &minutes, int &seconds, int &frames) const noexcept
Definition juce_MidiMessage.cpp:994
juce::MidiMessage::isKeySignatureMajorKey
bool isKeySignatureMajorKey() const noexcept
Definition juce_MidiMessage.cpp:889
juce::MidiMessage::isMidiChannelMetaEvent
bool isMidiChannelMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:785
juce::MidiMessage::getMidiMachineControlCommand
MidiMachineControlCommand getMidiMachineControlCommand() const noexcept
Definition juce_MidiMessage.cpp:981
juce::MidiMessage::isMetaEvent
bool isMetaEvent() const noexcept
Definition juce_MidiMessage.cpp:704
juce::MidiMessage::getVelocity
uint8 getVelocity() const noexcept
Definition juce_MidiMessage.cpp:443
juce::MidiMessage::getRhythmInstrumentName
static const char * getRhythmInstrumentName(int midiNoteNumber)
Definition juce_MidiMessage.cpp:1106
juce::MidiMessage::programChange
static MidiMessage programChange(int channel, int programNumber) noexcept
Definition juce_MidiMessage.cpp:535
juce::MidiMessage::isChannelPressure
bool isChannelPressure() const noexcept
Definition juce_MidiMessage.cpp:495
juce::MidiMessage::isSysEx
bool isSysEx() const noexcept
Definition juce_MidiMessage.cpp:672
juce::MidiMessage::songPositionPointer
static MidiMessage songPositionPointer(int positionInMidiBeats) noexcept
Definition juce_MidiMessage.cpp:910
juce::MidiMessage::endOfTrack
static MidiMessage endOfTrack() noexcept
Definition juce_MidiMessage.cpp:901
juce::MidiMessage::isMidiClock
bool isMidiClock() const noexcept
Definition juce_MidiMessage.cpp:926
juce::MidiMessage::getTextFromTextMetaEvent
String getTextFromTextMetaEvent() const
Definition juce_MidiMessage.cpp:744
juce::MidiMessage::SmpteTimecodeType
SmpteTimecodeType
Definition juce_MidiMessage.h:774
juce::MidiMessage::midiMachineControlCommand
static MidiMessage midiMachineControlCommand(MidiMachineControlCommand command)
Definition juce_MidiMessage.cpp:988
juce::MidiMessage::allSoundOff
static MidiMessage allSoundOff(int channel) noexcept
Definition juce_MidiMessage.cpp:642
juce::MidiMessage::readVariableLengthValue
static VariableLengthValue readVariableLengthValue(const uint8 *data, int maxBytesToUse) noexcept
Definition juce_MidiMessage.cpp:60
juce::MidiMessage::setChannel
void setChannel(int newChannelNumber) noexcept
Definition juce_MidiMessage.cpp:399
juce::MidiMessage::getControllerName
static const char * getControllerName(int controllerNumber)
Definition juce_MidiMessage.cpp:1127
juce::MidiMessage::isSongPositionPointer
bool isSongPositionPointer() const noexcept
Definition juce_MidiMessage.cpp:907
juce::MidiMessage::isSustainPedalOff
bool isSustainPedalOff() const noexcept
Definition juce_MidiMessage.cpp:515
juce::MidiMessage::getRawDataSize
int getRawDataSize() const noexcept
Definition juce_MidiMessage.h:139
juce::MidiMessage::allControllersOff
static MidiMessage allControllersOff(int channel) noexcept
Definition juce_MidiMessage.cpp:659
juce::MidiMessage::withTimeStamp
MidiMessage withTimeStamp(double newTimestamp) const
Definition juce_MidiMessage.cpp:374
juce::MidiMessage::getPitchWheelValue
int getPitchWheelValue() const noexcept
Definition juce_MidiMessage.cpp:547
juce::Span
Definition juce_Span.h:96
juce::StringRef
Definition juce_StringRef.h:62
juce::StringRef::text
String::CharPointerType text
Definition juce_StringRef.h:130
juce::String
Definition juce_String.h:53
juce::String::isEmpty
bool isEmpty() const noexcept
Definition juce_String.h:310
juce::String::toHexString
static String toHexString(IntegerType number)
Definition juce_String.h:1097
juce::UnitTest
Definition juce_UnitTest.h:70
juce::var
Definition juce_Variant.h:42
juce::MidiMessage::VariableLengthValue
Definition juce_MidiMessage.h:888