OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_MidiMessage.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
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
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//==============================================================================
60int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
61{
62 numBytesUsed = 0;
63 int v = 0, i;
64
65 do
66 {
67 i = (int) *data++;
68
69 if (++numBytesUsed > 6)
70 break;
71
72 v = (v << 7) + (i & 0x7f);
73
74 } while (i & 0x80);
75
76 return v;
77}
78
80{
81 // this method only works for valid starting bytes of a short midi message
82 jassert (firstByte >= 0x80 && firstByte != 0xf0 && firstByte != 0xf7);
83
84 static const char messageLengths[] =
85 {
86 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
87 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
88 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
89 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
90 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
91 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
92 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
93 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
94 };
95
96 return messageLengths[firstByte & 0x7f];
97}
98
99//==============================================================================
101 : size (2)
102{
103 packedData.asBytes[0] = 0xf0;
104 packedData.asBytes[1] = 0xf7;
105}
106
107MidiMessage::MidiMessage (const void* const d, const int dataSize, const double t)
108 : timeStamp (t), size (dataSize)
109{
110 jassert (dataSize > 0);
111 // this checks that the length matches the data..
112 jassert (dataSize > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
113
114 memcpy (allocateSpace (dataSize), d, (size_t) dataSize);
115}
116
117MidiMessage::MidiMessage (const int byte1, const double t) noexcept
118 : timeStamp (t), size (1)
119{
120 packedData.asBytes[0] = (uint8) byte1;
121
122 // check that the length matches the data..
123 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 1);
124}
125
126MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
127 : timeStamp (t), size (2)
128{
129 packedData.asBytes[0] = (uint8) byte1;
130 packedData.asBytes[1] = (uint8) byte2;
131
132 // check that the length matches the data..
133 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 2);
134}
135
136MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
137 : timeStamp (t), size (3)
138{
139 packedData.asBytes[0] = (uint8) byte1;
140 packedData.asBytes[1] = (uint8) byte2;
141 packedData.asBytes[2] = (uint8) byte3;
142
143 // check that the length matches the data..
144 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 3);
145}
146
148 : timeStamp (other.timeStamp), size (other.size)
149{
150 if (isHeapAllocated())
151 memcpy (allocateSpace (size), other.getData(), (size_t) size);
152 else
153 packedData.allocatedData = other.packedData.allocatedData;
154}
155
157 : timeStamp (newTimeStamp), size (other.size)
158{
159 if (isHeapAllocated())
160 memcpy (allocateSpace (size), other.getData(), (size_t) size);
161 else
162 packedData.allocatedData = other.packedData.allocatedData;
163}
164
165MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte,
166 double t, bool sysexHasEmbeddedLength)
167 : timeStamp (t)
168{
169 auto src = static_cast<const uint8*> (srcData);
170 auto byte = (unsigned int) *src;
171
172 if (byte < 0x80)
173 {
174 byte = (unsigned int) lastStatusByte;
175 numBytesUsed = -1;
176 }
177 else
178 {
179 numBytesUsed = 0;
180 --sz;
181 ++src;
182 }
183
184 if (byte >= 0x80)
185 {
186 if (byte == 0xf0)
187 {
188 auto d = src;
191
192 while (d < src + sz)
193 {
194 if (*d >= 0x80)
195 {
196 if (*d == 0xf7)
197 {
198 ++d; // include the trailing 0xf7 when we hit it
199 break;
200 }
201
202 if (haveReadAllLengthBytes) // if we see a 0x80 bit set after the initial data length
203 break; // bytes, assume it's the end of the sysex
204
206 }
207 else if (! haveReadAllLengthBytes)
208 {
211 }
212
213 ++d;
214 }
215
217 size = 1 + (int) (d - src);
218
219 auto dest = allocateSpace (size);
220 *dest = (uint8) byte;
221 memcpy (dest + 1, src, (size_t) (size - 1));
222
223 numBytesUsed += (numVariableLengthSysexBytes + size); // (these aren't counted in the size)
224 }
225 else if (byte == 0xff)
226 {
227 if (sz == 1)
228 {
229 size = 1;
230 }
231 else
232 {
233 int n;
234 const int bytesLeft = readVariableLengthVal (src + 1, n);
235 size = jmin (sz + 1, n + 2 + bytesLeft);
236 }
237
238 auto dest = allocateSpace (size);
239 *dest = (uint8) byte;
240 memcpy (dest + 1, src, (size_t) size - 1);
241
242 numBytesUsed += size;
243 }
244 else
245 {
246 size = getMessageLengthFromFirstByte ((uint8) byte);
247 packedData.asBytes[0] = (uint8) byte;
248
249 if (size > 1)
250 {
251 packedData.asBytes[1] = (sz > 0 ? src[0] : 0);
252
253 if (size > 2)
254 packedData.asBytes[2] = (sz > 1 ? src[1] : 0);
255 }
256
257 numBytesUsed += jmin (size, sz + 1);
258 }
259 }
260 else
261 {
262 packedData.allocatedData = nullptr;
263 size = 0;
264 }
265}
266
268{
269 if (this != &other)
270 {
271 if (other.isHeapAllocated())
272 {
273 if (isHeapAllocated())
274 packedData.allocatedData = static_cast<uint8*> (std::realloc (packedData.allocatedData, (size_t) other.size));
275 else
276 packedData.allocatedData = static_cast<uint8*> (std::malloc ((size_t) other.size));
277
278 memcpy (packedData.allocatedData, other.packedData.allocatedData, (size_t) other.size);
279 }
280 else
281 {
282 if (isHeapAllocated())
283 std::free (packedData.allocatedData);
284
285 packedData.allocatedData = other.packedData.allocatedData;
286 }
287
288 timeStamp = other.timeStamp;
289 size = other.size;
290 }
291
292 return *this;
293}
294
296 : timeStamp (other.timeStamp), size (other.size)
297{
298 packedData.allocatedData = other.packedData.allocatedData;
299 other.size = 0;
300}
301
303{
304 packedData.allocatedData = other.packedData.allocatedData;
305 timeStamp = other.timeStamp;
306 size = other.size;
307 other.size = 0;
308 return *this;
309}
310
312{
313 if (isHeapAllocated())
314 std::free (packedData.allocatedData);
315}
316
317uint8* MidiMessage::allocateSpace (int bytes)
318{
319 if (bytes > (int) sizeof (packedData))
320 {
321 auto d = static_cast<uint8*> (std::malloc ((size_t) bytes));
322 packedData.allocatedData = d;
323 return d;
324 }
325
326 return packedData.asBytes;
327}
328
330{
331 if (isNoteOn()) return "Note on " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
332 if (isNoteOff()) return "Note off " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
333 if (isProgramChange()) return "Program change " + String (getProgramChangeNumber()) + " Channel " + String (getChannel());
334 if (isPitchWheel()) return "Pitch wheel " + String (getPitchWheelValue()) + " Channel " + String (getChannel());
335 if (isAftertouch()) return "Aftertouch " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + ": " + String (getAfterTouchValue()) + " Channel " + String (getChannel());
336 if (isChannelPressure()) return "Channel pressure " + String (getChannelPressureValue()) + " Channel " + String (getChannel());
337 if (isAllNotesOff()) return "All notes off Channel " + String (getChannel());
338 if (isAllSoundOff()) return "All sound off Channel " + String (getChannel());
339 if (isMetaEvent()) return "Meta event";
340
341 if (isController())
342 {
344
345 if (name.isEmpty())
346 name = String (getControllerNumber());
347
348 return "Controller " + name + ": " + String (getControllerValue()) + " Channel " + String (getChannel());
349 }
350
352}
353
355{
356 return { *this, newTimestamp };
357}
358
360{
361 auto data = getRawData();
362
363 if ((data[0] & 0xf0) != 0xf0)
364 return (data[0] & 0xf) + 1;
365
366 return 0;
367}
368
369bool MidiMessage::isForChannel (const int channel) const noexcept
370{
371 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
372
373 auto data = getRawData();
374
375 return ((data[0] & 0xf) == channel - 1)
376 && ((data[0] & 0xf0) != 0xf0);
377}
378
379void MidiMessage::setChannel (const int channel) noexcept
380{
381 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
382
383 auto data = getData();
384
385 if ((data[0] & 0xf0) != (uint8) 0xf0)
386 data[0] = (uint8) ((data[0] & (uint8) 0xf0)
387 | (uint8)(channel - 1));
388}
389
390bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
391{
392 auto data = getRawData();
393
394 return ((data[0] & 0xf0) == 0x90)
395 && (returnTrueForVelocity0 || data[2] != 0);
396}
397
399{
400 auto data = getRawData();
401
402 return ((data[0] & 0xf0) == 0x80)
403 || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
404}
405
407{
408 auto d = getRawData()[0] & 0xf0;
409 return (d == 0x90) || (d == 0x80);
410}
411
413{
414 return getRawData()[1];
415}
416
418{
419 if (isNoteOnOrOff() || isAftertouch())
420 getData()[1] = (uint8) (newNoteNumber & 127);
421}
422
424{
425 if (isNoteOnOrOff())
426 return getRawData()[2];
427
428 return 0;
429}
430
432{
433 return getVelocity() * (1.0f / 127.0f);
434}
435
436void MidiMessage::setVelocity (const float newVelocity) noexcept
437{
438 if (isNoteOnOrOff())
439 getData()[2] = floatValueToMidiByte (newVelocity);
440}
441
443{
444 if (isNoteOnOrOff())
445 {
446 auto data = getData();
447 data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
448 }
449}
450
452{
453 return (getRawData()[0] & 0xf0) == 0xa0;
454}
455
457{
458 jassert (isAftertouch());
459 return getRawData()[2];
460}
461
463 const int noteNum,
464 const int aftertouchValue) noexcept
465{
466 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
467 jassert (isPositiveAndBelow (noteNum, 128));
468 jassert (isPositiveAndBelow (aftertouchValue, 128));
469
470 return MidiMessage (MidiHelpers::initialByte (0xa0, channel),
471 noteNum & 0x7f,
472 aftertouchValue & 0x7f);
473}
474
476{
477 return (getRawData()[0] & 0xf0) == 0xd0;
478}
479
481{
482 jassert (isChannelPressure());
483 return getRawData()[1];
484}
485
486MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
487{
488 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
489 jassert (isPositiveAndBelow (pressure, 128));
490
491 return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
492}
493
496
499
502
503
505{
506 return (getRawData()[0] & 0xf0) == 0xc0;
507}
508
510{
511 jassert (isProgramChange());
512 return getRawData()[1];
513}
514
515MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
516{
517 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
518
519 return MidiMessage (MidiHelpers::initialByte (0xc0, channel), programNumber & 0x7f);
520}
521
523{
524 return (getRawData()[0] & 0xf0) == 0xe0;
525}
526
528{
529 jassert (isPitchWheel());
530 auto data = getRawData();
531 return data[1] | (data[2] << 7);
532}
533
534MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noexcept
535{
536 jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
537 jassert (isPositiveAndBelow (position, 0x4000));
538
539 return MidiMessage (MidiHelpers::initialByte (0xe0, channel),
540 position & 127, (position >> 7) & 127);
541}
542
544{
545 return (getRawData()[0] & 0xf0) == 0xb0;
546}
547
548bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
549{
550 auto data = getRawData();
551 return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
552}
553
555{
556 jassert (isController());
557 return getRawData()[1];
558}
559
561{
562 jassert (isController());
563 return getRawData()[2];
564}
565
566MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
567{
568 // the channel must be between 1 and 16 inclusive
569 jassert (channel > 0 && channel <= 16);
570
571 return MidiMessage (MidiHelpers::initialByte (0xb0, channel),
572 controllerType & 127, value & 127);
573}
574
575MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept
576{
577 jassert (channel > 0 && channel <= 16);
578 jassert (isPositiveAndBelow (noteNumber, 128));
579
580 return MidiMessage (MidiHelpers::initialByte (0x90, channel),
581 noteNumber & 127, MidiHelpers::validVelocity (velocity));
582}
583
584MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept
585{
586 return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
587}
588
589MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept
590{
591 jassert (channel > 0 && channel <= 16);
592 jassert (isPositiveAndBelow (noteNumber, 128));
593
594 return MidiMessage (MidiHelpers::initialByte (0x80, channel),
595 noteNumber & 127, MidiHelpers::validVelocity (velocity));
596}
597
598MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, float velocity) noexcept
599{
600 return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
601}
602
603MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber) noexcept
604{
605 jassert (channel > 0 && channel <= 16);
606 jassert (isPositiveAndBelow (noteNumber, 128));
607
608 return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, 0);
609}
610
611MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
612{
613 return controllerEvent (channel, 123, 0);
614}
615
617{
618 auto data = getRawData();
619 return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
620}
621
622MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
623{
624 return controllerEvent (channel, 120, 0);
625}
626
628{
629 auto data = getRawData();
630 return data[1] == 120 && (data[0] & 0xf0) == 0xb0;
631}
632
634{
635 auto data = getRawData();
636 return (data[0] & 0xf0) == 0xb0 && data[1] == 121;
637}
638
639MidiMessage MidiMessage::allControllersOff (const int channel) noexcept
640{
641 return controllerEvent (channel, 121, 0);
642}
643
645{
646 auto vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000));
647
648 return { 0xf0, 0x7f, 0x7f, 0x04, 0x01, vol & 0x7f, vol >> 7, 0xf7 };
649}
650
651//==============================================================================
653{
654 return *getRawData() == 0xf0;
655}
656
658{
659 HeapBlock<uint8> m (dataSize + 2);
660
661 m[0] = 0xf0;
662 memcpy (m + 1, sysexData, (size_t) dataSize);
663 m[dataSize + 1] = 0xf7;
664
665 return MidiMessage (m, dataSize + 2);
666}
667
669{
670 return isSysEx() ? getRawData() + 1 : nullptr;
671}
672
674{
675 return isSysEx() ? size - 2 : 0;
676}
677
678//==============================================================================
681
683{
684 auto data = getRawData();
685 return *data != 0xff ? -1 : data[1];
686}
687
689{
690 auto data = getRawData();
691
692 if (*data == 0xff)
693 {
694 int n;
695 return jmin (size - 2, readVariableLengthVal (data + 2, n));
696 }
697
698 return 0;
699}
700
702{
703 jassert (isMetaEvent());
704
705 int n;
706 auto d = getRawData() + 2;
708 return d + n;
709}
710
713
715{
716 auto t = getMetaEventType();
717 return t > 0 && t < 16;
718}
719
721{
722 auto textData = reinterpret_cast<const char*> (getMetaEventData());
723
726}
727
729{
730 jassert (type > 0 && type < 16);
731
732 MidiMessage result;
733
734 const size_t textSize = text.text.sizeInBytes() - 1;
735
736 uint8 header[8];
737 size_t n = sizeof (header);
738
739 header[--n] = (uint8) (textSize & 0x7f);
740
741 for (size_t i = textSize; (i >>= 7) != 0;)
742 header[--n] = (uint8) ((i & 0x7f) | 0x80);
743
744 header[--n] = (uint8) type;
745 header[--n] = 0xff;
746
747 const size_t headerLen = sizeof (header) - n;
748 const int totalSize = (int) (headerLen + textSize);
749
750 auto dest = result.allocateSpace (totalSize);
751 result.size = totalSize;
752
753 memcpy (dest, header + n, headerLen);
754 memcpy (dest + headerLen, text.text.getAddress(), textSize);
755
756 return result;
757}
758
759bool MidiMessage::isTrackNameEvent() const noexcept { auto data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
760bool MidiMessage::isTempoMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
761bool MidiMessage::isMidiChannelMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
762
768
770{
771 if (! isTempoMetaEvent())
772 return 0.0;
773
774 auto d = getMetaEventData();
775
776 return (((unsigned int) d[0] << 16)
777 | ((unsigned int) d[1] << 8)
778 | d[2])
779 / 1000000.0;
780}
781
782double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const noexcept
783{
784 if (timeFormat > 0)
785 {
786 if (! isTempoMetaEvent())
787 return 0.5 / timeFormat;
788
789 return getTempoSecondsPerQuarterNote() / timeFormat;
790 }
791
792 const int frameCode = (-timeFormat) >> 8;
793 double framesPerSecond;
794
795 switch (frameCode)
796 {
797 case 24: framesPerSecond = 24.0; break;
798 case 25: framesPerSecond = 25.0; break;
799 case 29: framesPerSecond = 30.0 * 1000.0 / 1001.0; break;
800 case 30: framesPerSecond = 30.0; break;
801 default: framesPerSecond = 30.0; break;
802 }
803
804 return (1.0 / framesPerSecond) / (timeFormat & 0xff);
805}
806
808{
809 return { 0xff, 81, 3,
810 (uint8) (microsecondsPerQuarterNote >> 16),
811 (uint8) (microsecondsPerQuarterNote >> 8),
813}
814
816{
817 auto data = getRawData();
818 return (data[1] == 0x58) && (*data == (uint8) 0xff);
819}
820
822{
823 if (isTimeSignatureMetaEvent())
824 {
825 auto d = getMetaEventData();
826 numerator = d[0];
827 denominator = 1 << d[1];
828 }
829 else
830 {
831 numerator = 4;
832 denominator = 4;
833 }
834}
835
837{
838 int n = 1;
839 int powerOfTwo = 0;
840
841 while (n < denominator)
842 {
843 n <<= 1;
844 ++powerOfTwo;
845 }
846
847 return { 0xff, 0x58, 0x04, numerator, powerOfTwo, 1, 96 };
848}
849
851{
852 return { 0xff, 0x20, 0x01, jlimit (0, 0xff, channel - 1) };
853}
854
859
864
869
871{
872 jassert (numberOfSharpsOrFlats >= -7 && numberOfSharpsOrFlats <= 7);
873
874 return { 0xff, 0x59, 0x02, numberOfSharpsOrFlats, isMinorKey ? 1 : 0 };
875}
876
878{
879 return { 0xff, 0x2f, 0x00 };
880}
881
882//==============================================================================
884int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { auto data = getRawData(); return data[1] | (data[2] << 7); }
885
887{
888 return { 0xf2,
890 (positionInMidiBeats >> 7) & 127 };
891}
892
895
898
901
904
907int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
908
909MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
910{
911 return MidiMessage (0xf1, (sequenceNumber << 4) | value);
912}
913
915{
916 auto data = getRawData();
917
918 return data[0] == 0xf0
919 && data[1] == 0x7f
920 && size >= 10
921 && data[3] == 0x01
922 && data[4] == 0x01;
923}
924
925void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames,
927{
928 jassert (isFullFrame());
929
930 auto data = getRawData();
931 timecodeType = (SmpteTimecodeType) (data[5] >> 5);
932 hours = data[5] & 0x1f;
933 minutes = data[6];
934 seconds = data[7];
935 frames = data[8];
936}
937
938MidiMessage MidiMessage::fullFrame (int hours, int minutes, int seconds, int frames,
940{
941 return { 0xf0, 0x7f, 0x7f, 0x01, 0x01,
942 (hours & 0x01f) | (timecodeType << 5),
943 minutes, seconds, frames,
944 0xf7 };
945}
946
948{
949 auto data = getRawData();
950
951 return data[0] == 0xf0
952 && data[1] == 0x7f
953 && data[3] == 0x06
954 && size > 5;
955}
956
963
965{
966 return { 0xf0, 0x7f, 0, 6, command, 0xf7 };
967}
968
969//==============================================================================
970bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
971{
972 auto data = getRawData();
973
974 if (size >= 12
975 && data[0] == 0xf0
976 && data[1] == 0x7f
977 && data[3] == 0x06
978 && data[4] == 0x44
979 && data[5] == 0x06
980 && data[6] == 0x01)
981 {
982 hours = data[7] % 24; // (that some machines send out hours > 24)
983 minutes = data[8];
984 seconds = data[9];
985 frames = data[10];
986
987 return true;
988 }
989
990 return false;
991}
992
993MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames)
994{
995 return { 0xf0, 0x7f, 0, 6, 0x44, 6, 1, hours, minutes, seconds, frames, 0xf7 };
996}
997
998//==============================================================================
1000{
1001 static const char* const sharpNoteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
1002 static const char* const flatNoteNames[] = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
1003
1004 if (isPositiveAndBelow (note, 128))
1005 {
1007 : flatNoteNames [note % 12]);
1008
1010 s << (note / 12 + (octaveNumForMiddleC - 5));
1011
1012 return s;
1013 }
1014
1015 return {};
1016}
1017
1018double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
1019{
1020 return frequencyOfA * std::pow (2.0, (noteNumber - 69) / 12.0);
1021}
1022
1024{
1025 return ((1 << (noteNumber % 12)) & 0x054a) != 0;
1026}
1027
1028const char* MidiMessage::getGMInstrumentName (const int n)
1029{
1030 static const char* names[] =
1031 {
1032 NEEDS_TRANS("Acoustic Grand Piano"), NEEDS_TRANS("Bright Acoustic Piano"), NEEDS_TRANS("Electric Grand Piano"), NEEDS_TRANS("Honky-tonk Piano"),
1033 NEEDS_TRANS("Electric Piano 1"), NEEDS_TRANS("Electric Piano 2"), NEEDS_TRANS("Harpsichord"), NEEDS_TRANS("Clavinet"),
1034 NEEDS_TRANS("Celesta"), NEEDS_TRANS("Glockenspiel"), NEEDS_TRANS("Music Box"), NEEDS_TRANS("Vibraphone"),
1035 NEEDS_TRANS("Marimba"), NEEDS_TRANS("Xylophone"), NEEDS_TRANS("Tubular Bells"), NEEDS_TRANS("Dulcimer"),
1036 NEEDS_TRANS("Drawbar Organ"), NEEDS_TRANS("Percussive Organ"), NEEDS_TRANS("Rock Organ"), NEEDS_TRANS("Church Organ"),
1037 NEEDS_TRANS("Reed Organ"), NEEDS_TRANS("Accordion"), NEEDS_TRANS("Harmonica"), NEEDS_TRANS("Tango Accordion"),
1038 NEEDS_TRANS("Acoustic Guitar (nylon)"), NEEDS_TRANS("Acoustic Guitar (steel)"), NEEDS_TRANS("Electric Guitar (jazz)"), NEEDS_TRANS("Electric Guitar (clean)"),
1039 NEEDS_TRANS("Electric Guitar (mute)"), NEEDS_TRANS("Overdriven Guitar"), NEEDS_TRANS("Distortion Guitar"), NEEDS_TRANS("Guitar Harmonics"),
1040 NEEDS_TRANS("Acoustic Bass"), NEEDS_TRANS("Electric Bass (finger)"), NEEDS_TRANS("Electric Bass (pick)"), NEEDS_TRANS("Fretless Bass"),
1041 NEEDS_TRANS("Slap Bass 1"), NEEDS_TRANS("Slap Bass 2"), NEEDS_TRANS("Synth Bass 1"), NEEDS_TRANS("Synth Bass 2"),
1042 NEEDS_TRANS("Violin"), NEEDS_TRANS("Viola"), NEEDS_TRANS("Cello"), NEEDS_TRANS("Contrabass"),
1043 NEEDS_TRANS("Tremolo Strings"), NEEDS_TRANS("Pizzicato Strings"), NEEDS_TRANS("Orchestral Harp"), NEEDS_TRANS("Timpani"),
1044 NEEDS_TRANS("String Ensemble 1"), NEEDS_TRANS("String Ensemble 2"), NEEDS_TRANS("SynthStrings 1"), NEEDS_TRANS("SynthStrings 2"),
1045 NEEDS_TRANS("Choir Aahs"), NEEDS_TRANS("Voice Oohs"), NEEDS_TRANS("Synth Voice"), NEEDS_TRANS("Orchestra Hit"),
1046 NEEDS_TRANS("Trumpet"), NEEDS_TRANS("Trombone"), NEEDS_TRANS("Tuba"), NEEDS_TRANS("Muted Trumpet"),
1047 NEEDS_TRANS("French Horn"), NEEDS_TRANS("Brass Section"), NEEDS_TRANS("SynthBrass 1"), NEEDS_TRANS("SynthBrass 2"),
1048 NEEDS_TRANS("Soprano Sax"), NEEDS_TRANS("Alto Sax"), NEEDS_TRANS("Tenor Sax"), NEEDS_TRANS("Baritone Sax"),
1049 NEEDS_TRANS("Oboe"), NEEDS_TRANS("English Horn"), NEEDS_TRANS("Bassoon"), NEEDS_TRANS("Clarinet"),
1050 NEEDS_TRANS("Piccolo"), NEEDS_TRANS("Flute"), NEEDS_TRANS("Recorder"), NEEDS_TRANS("Pan Flute"),
1051 NEEDS_TRANS("Blown Bottle"), NEEDS_TRANS("Shakuhachi"), NEEDS_TRANS("Whistle"), NEEDS_TRANS("Ocarina"),
1052 NEEDS_TRANS("Lead 1 (square)"), NEEDS_TRANS("Lead 2 (sawtooth)"), NEEDS_TRANS("Lead 3 (calliope)"), NEEDS_TRANS("Lead 4 (chiff)"),
1053 NEEDS_TRANS("Lead 5 (charang)"), NEEDS_TRANS("Lead 6 (voice)"), NEEDS_TRANS("Lead 7 (fifths)"), NEEDS_TRANS("Lead 8 (bass+lead)"),
1054 NEEDS_TRANS("Pad 1 (new age)"), NEEDS_TRANS("Pad 2 (warm)"), NEEDS_TRANS("Pad 3 (polysynth)"), NEEDS_TRANS("Pad 4 (choir)"),
1055 NEEDS_TRANS("Pad 5 (bowed)"), NEEDS_TRANS("Pad 6 (metallic)"), NEEDS_TRANS("Pad 7 (halo)"), NEEDS_TRANS("Pad 8 (sweep)"),
1056 NEEDS_TRANS("FX 1 (rain)"), NEEDS_TRANS("FX 2 (soundtrack)"), NEEDS_TRANS("FX 3 (crystal)"), NEEDS_TRANS("FX 4 (atmosphere)"),
1057 NEEDS_TRANS("FX 5 (brightness)"), NEEDS_TRANS("FX 6 (goblins)"), NEEDS_TRANS("FX 7 (echoes)"), NEEDS_TRANS("FX 8 (sci-fi)"),
1058 NEEDS_TRANS("Sitar"), NEEDS_TRANS("Banjo"), NEEDS_TRANS("Shamisen"), NEEDS_TRANS("Koto"),
1059 NEEDS_TRANS("Kalimba"), NEEDS_TRANS("Bag pipe"), NEEDS_TRANS("Fiddle"), NEEDS_TRANS("Shanai"),
1060 NEEDS_TRANS("Tinkle Bell"), NEEDS_TRANS("Agogo"), NEEDS_TRANS("Steel Drums"), NEEDS_TRANS("Woodblock"),
1061 NEEDS_TRANS("Taiko Drum"), NEEDS_TRANS("Melodic Tom"), NEEDS_TRANS("Synth Drum"), NEEDS_TRANS("Reverse Cymbal"),
1062 NEEDS_TRANS("Guitar Fret Noise"), NEEDS_TRANS("Breath Noise"), NEEDS_TRANS("Seashore"), NEEDS_TRANS("Bird Tweet"),
1063 NEEDS_TRANS("Telephone Ring"), NEEDS_TRANS("Helicopter"), NEEDS_TRANS("Applause"), NEEDS_TRANS("Gunshot")
1064 };
1065
1066 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1067}
1068
1070{
1071 static const char* names[] =
1072 {
1073 NEEDS_TRANS("Piano"), NEEDS_TRANS("Chromatic Percussion"), NEEDS_TRANS("Organ"), NEEDS_TRANS("Guitar"),
1074 NEEDS_TRANS("Bass"), NEEDS_TRANS("Strings"), NEEDS_TRANS("Ensemble"), NEEDS_TRANS("Brass"),
1075 NEEDS_TRANS("Reed"), NEEDS_TRANS("Pipe"), NEEDS_TRANS("Synth Lead"), NEEDS_TRANS("Synth Pad"),
1076 NEEDS_TRANS("Synth Effects"), NEEDS_TRANS("Ethnic"), NEEDS_TRANS("Percussive"), NEEDS_TRANS("Sound Effects")
1077 };
1078
1079 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1080}
1081
1083{
1084 static const char* names[] =
1085 {
1086 NEEDS_TRANS("Acoustic Bass Drum"), NEEDS_TRANS("Bass Drum 1"), NEEDS_TRANS("Side Stick"), NEEDS_TRANS("Acoustic Snare"),
1087 NEEDS_TRANS("Hand Clap"), NEEDS_TRANS("Electric Snare"), NEEDS_TRANS("Low Floor Tom"), NEEDS_TRANS("Closed Hi-Hat"),
1088 NEEDS_TRANS("High Floor Tom"), NEEDS_TRANS("Pedal Hi-Hat"), NEEDS_TRANS("Low Tom"), NEEDS_TRANS("Open Hi-Hat"),
1089 NEEDS_TRANS("Low-Mid Tom"), NEEDS_TRANS("Hi-Mid Tom"), NEEDS_TRANS("Crash Cymbal 1"), NEEDS_TRANS("High Tom"),
1090 NEEDS_TRANS("Ride Cymbal 1"), NEEDS_TRANS("Chinese Cymbal"), NEEDS_TRANS("Ride Bell"), NEEDS_TRANS("Tambourine"),
1091 NEEDS_TRANS("Splash Cymbal"), NEEDS_TRANS("Cowbell"), NEEDS_TRANS("Crash Cymbal 2"), NEEDS_TRANS("Vibraslap"),
1092 NEEDS_TRANS("Ride Cymbal 2"), NEEDS_TRANS("Hi Bongo"), NEEDS_TRANS("Low Bongo"), NEEDS_TRANS("Mute Hi Conga"),
1093 NEEDS_TRANS("Open Hi Conga"), NEEDS_TRANS("Low Conga"), NEEDS_TRANS("High Timbale"), NEEDS_TRANS("Low Timbale"),
1094 NEEDS_TRANS("High Agogo"), NEEDS_TRANS("Low Agogo"), NEEDS_TRANS("Cabasa"), NEEDS_TRANS("Maracas"),
1095 NEEDS_TRANS("Short Whistle"), NEEDS_TRANS("Long Whistle"), NEEDS_TRANS("Short Guiro"), NEEDS_TRANS("Long Guiro"),
1096 NEEDS_TRANS("Claves"), NEEDS_TRANS("Hi Wood Block"), NEEDS_TRANS("Low Wood Block"), NEEDS_TRANS("Mute Cuica"),
1097 NEEDS_TRANS("Open Cuica"), NEEDS_TRANS("Mute Triangle"), NEEDS_TRANS("Open Triangle")
1098 };
1099
1100 return (n >= 35 && n <= 81) ? names[n - 35] : nullptr;
1101}
1102
1103const char* MidiMessage::getControllerName (const int n)
1104{
1105 static const char* names[] =
1106 {
1107 NEEDS_TRANS("Bank Select"), NEEDS_TRANS("Modulation Wheel (coarse)"), NEEDS_TRANS("Breath controller (coarse)"),
1108 nullptr,
1109 NEEDS_TRANS("Foot Pedal (coarse)"), NEEDS_TRANS("Portamento Time (coarse)"), NEEDS_TRANS("Data Entry (coarse)"),
1110 NEEDS_TRANS("Volume (coarse)"), NEEDS_TRANS("Balance (coarse)"),
1111 nullptr,
1112 NEEDS_TRANS("Pan position (coarse)"), NEEDS_TRANS("Expression (coarse)"), NEEDS_TRANS("Effect Control 1 (coarse)"),
1113 NEEDS_TRANS("Effect Control 2 (coarse)"),
1114 nullptr, nullptr,
1115 NEEDS_TRANS("General Purpose Slider 1"), NEEDS_TRANS("General Purpose Slider 2"),
1116 NEEDS_TRANS("General Purpose Slider 3"), NEEDS_TRANS("General Purpose Slider 4"),
1117 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1118 NEEDS_TRANS("Bank Select (fine)"), NEEDS_TRANS("Modulation Wheel (fine)"), NEEDS_TRANS("Breath controller (fine)"),
1119 nullptr,
1120 NEEDS_TRANS("Foot Pedal (fine)"), NEEDS_TRANS("Portamento Time (fine)"), NEEDS_TRANS("Data Entry (fine)"), NEEDS_TRANS("Volume (fine)"),
1121 NEEDS_TRANS("Balance (fine)"), nullptr, NEEDS_TRANS("Pan position (fine)"), NEEDS_TRANS("Expression (fine)"),
1122 NEEDS_TRANS("Effect Control 1 (fine)"), NEEDS_TRANS("Effect Control 2 (fine)"),
1123 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1124 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1125 NEEDS_TRANS("Hold Pedal (on/off)"), NEEDS_TRANS("Portamento (on/off)"), NEEDS_TRANS("Sustenuto Pedal (on/off)"), NEEDS_TRANS("Soft Pedal (on/off)"),
1126 NEEDS_TRANS("Legato Pedal (on/off)"), NEEDS_TRANS("Hold 2 Pedal (on/off)"), NEEDS_TRANS("Sound Variation"), NEEDS_TRANS("Sound Timbre"),
1127 NEEDS_TRANS("Sound Release Time"), NEEDS_TRANS("Sound Attack Time"), NEEDS_TRANS("Sound Brightness"), NEEDS_TRANS("Sound Control 6"),
1128 NEEDS_TRANS("Sound Control 7"), NEEDS_TRANS("Sound Control 8"), NEEDS_TRANS("Sound Control 9"), NEEDS_TRANS("Sound Control 10"),
1129 NEEDS_TRANS("General Purpose Button 1 (on/off)"), NEEDS_TRANS("General Purpose Button 2 (on/off)"),
1130 NEEDS_TRANS("General Purpose Button 3 (on/off)"), NEEDS_TRANS("General Purpose Button 4 (on/off)"),
1131 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1132 NEEDS_TRANS("Reverb Level"), NEEDS_TRANS("Tremolo Level"), NEEDS_TRANS("Chorus Level"), NEEDS_TRANS("Celeste Level"),
1133 NEEDS_TRANS("Phaser Level"), NEEDS_TRANS("Data Button increment"), NEEDS_TRANS("Data Button decrement"), NEEDS_TRANS("Non-registered Parameter (fine)"),
1134 NEEDS_TRANS("Non-registered Parameter (coarse)"), NEEDS_TRANS("Registered Parameter (fine)"), NEEDS_TRANS("Registered Parameter (coarse)"),
1135 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1136 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1137 NEEDS_TRANS("All Sound Off"), NEEDS_TRANS("All Controllers Off"), NEEDS_TRANS("Local Keyboard (on/off)"), NEEDS_TRANS("All Notes Off"),
1138 NEEDS_TRANS("Omni Mode Off"), NEEDS_TRANS("Omni Mode On"), NEEDS_TRANS("Mono Operation"), NEEDS_TRANS("Poly Operation")
1139 };
1140
1141 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
1142}
1143
1144} // namespace juce
int size() const noexcept
Definition juce_Array.h:215
bool isTrackMetaEvent() const noexcept
static MidiMessage createSysExMessage(const void *sysexData, int dataSize)
static MidiMessage tempoMetaEvent(int microsecondsPerQuarterNote) noexcept
static MidiMessage midiStart() noexcept
const uint8 * getSysExData() const noexcept
String getDescription() const
static const char * getGMInstrumentBankName(int midiBankNumber)
bool isAftertouch() const noexcept
void setNoteNumber(int newNoteNumber) noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
int getKeySignatureNumberOfSharpsOrFlats() const noexcept
int getSongPositionPointerMidiBeat() const noexcept
void multiplyVelocity(float scaleFactor) noexcept
void getFullFrameParameters(int &hours, int &minutes, int &seconds, int &frames, SmpteTimecodeType &timecodeType) const noexcept
float getFloatVelocity() const noexcept
bool isMidiMachineControlMessage() const noexcept
int getChannel() const noexcept
static bool isMidiNoteBlack(int noteNumber) noexcept
static MidiMessage aftertouchChange(int channel, int noteNumber, int aftertouchAmount) noexcept
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
int getQuarterFrameSequenceNumber() const noexcept
int getSysExDataSize() const noexcept
bool isQuarterFrame() const noexcept
const uint8 * getRawData() const noexcept
bool isTextMetaEvent() const noexcept
void setVelocity(float newVelocity) noexcept
int getMetaEventType() const noexcept
bool isProgramChange() const noexcept
bool isController() const noexcept
void getTimeSignatureInfo(int &numerator, int &denominator) const noexcept
bool isAllSoundOff() const noexcept
bool isSoftPedalOn() const noexcept
int getControllerNumber() const noexcept
bool isMidiStart() const noexcept
static double getMidiNoteInHertz(int noteNumber, double frequencyOfA=440.0) noexcept
int getQuarterFrameValue() const noexcept
bool isTrackNameEvent() const noexcept
int getChannelPressureValue() const noexcept
static MidiMessage pitchWheel(int channel, int position) noexcept
bool isForChannel(int channelNumber) const noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
const uint8 * getMetaEventData() const noexcept
bool isKeySignatureMetaEvent() const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
static MidiMessage quarterFrame(int sequenceNumber, int value) noexcept
bool isPitchWheel() const noexcept
bool isSustainPedalOn() const noexcept
bool isMidiContinue() const noexcept
static MidiMessage midiStop() noexcept
static MidiMessage timeSignatureMetaEvent(int numerator, int denominator)
bool isSostenutoPedalOn() const noexcept
static uint16 pitchbendToPitchwheelPos(float pitchbendInSemitones, float pitchbendRangeInSemitones) noexcept
int getNoteNumber() const noexcept
static MidiMessage midiChannelMetaEvent(int channel) noexcept
int getProgramChangeNumber() const noexcept
static const char * getGMInstrumentName(int midiInstrumentNumber)
bool isSostenutoPedalOff() const noexcept
int getMidiChannelMetaEventChannel() const noexcept
bool isTimeSignatureMetaEvent() const noexcept
static MidiMessage allNotesOff(int channel) noexcept
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
bool isControllerOfType(int controllerType) const noexcept
bool isTempoMetaEvent() const noexcept
static uint8 floatValueToMidiByte(float valueBetween0and1) noexcept
static MidiMessage keySignatureMetaEvent(int numberOfSharpsOrFlats, bool isMinorKey)
static MidiMessage midiClock() noexcept
bool isResetAllControllers() const noexcept
static MidiMessage fullFrame(int hours, int minutes, int seconds, int frames, SmpteTimecodeType timecodeType)
bool isSoftPedalOff() const noexcept
int getMetaEventLength() const noexcept
bool isMidiStop() const noexcept
MidiMessage & operator=(const MidiMessage &other)
bool isActiveSense() const noexcept
double getTempoSecondsPerQuarterNote() const noexcept
static MidiMessage masterVolume(float volume)
int getAfterTouchValue() const noexcept
static MidiMessage textMetaEvent(int type, StringRef text)
static MidiMessage channelPressureChange(int channel, int pressure) noexcept
bool isFullFrame() const noexcept
double getTempoMetaEventTickLength(short timeFormat) const noexcept
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
bool isEndOfTrackMetaEvent() const noexcept
bool isNoteOnOrOff() const noexcept
static MidiMessage midiContinue() noexcept
int getControllerValue() const noexcept
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
static MidiMessage midiMachineControlGoto(int hours, int minutes, int seconds, int frames)
bool isAllNotesOff() const noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
bool isMidiMachineControlGoto(int &hours, int &minutes, int &seconds, int &frames) const noexcept
bool isKeySignatureMajorKey() const noexcept
bool isMidiChannelMetaEvent() const noexcept
MidiMachineControlCommand getMidiMachineControlCommand() const noexcept
bool isMetaEvent() const noexcept
uint8 getVelocity() const noexcept
static const char * getRhythmInstrumentName(int midiNoteNumber)
static MidiMessage programChange(int channel, int programNumber) noexcept
bool isChannelPressure() const noexcept
bool isSysEx() const noexcept
static MidiMessage songPositionPointer(int positionInMidiBeats) noexcept
static MidiMessage endOfTrack() noexcept
bool isMidiClock() const noexcept
String getTextFromTextMetaEvent() const
static MidiMessage midiMachineControlCommand(MidiMachineControlCommand command)
static MidiMessage allSoundOff(int channel) noexcept
void setChannel(int newChannelNumber) noexcept
static const char * getControllerName(int controllerNumber)
bool isSongPositionPointer() const noexcept
bool isSustainPedalOff() const noexcept
int getRawDataSize() const noexcept
static MidiMessage allControllersOff(int channel) noexcept
MidiMessage withTimeStamp(double newTimestamp) const
int getPitchWheelValue() const noexcept
String::CharPointerType text
bool isEmpty() const noexcept
static String toHexString(IntegerType number)