OpenShot Library | libopenshot-audio  0.2.0
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 
23 namespace juce
24 {
25 
26 namespace 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 //==============================================================================
40 uint8 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 
48 uint16 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 int 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 
79 int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
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 
107 MidiMessage::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 
117 MidiMessage::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 
126 MidiMessage::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 
136 MidiMessage::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 
156 MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
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 
165 MidiMessage::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;
189  bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
190  int numVariableLengthSysexBytes = 0;
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 
205  ++numVariableLengthSysexBytes;
206  }
207  else if (! haveReadAllLengthBytes)
208  {
209  haveReadAllLengthBytes = true;
210  ++numVariableLengthSysexBytes;
211  }
212 
213  ++d;
214  }
215 
216  src += numVariableLengthSysexBytes;
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 
317 uint8* 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 
354 MidiMessage MidiMessage::withTimeStamp (double newTimestamp) const
355 {
356  return { *this, newTimestamp };
357 }
358 
359 int MidiMessage::getChannel() const noexcept
360 {
361  auto data = getRawData();
362 
363  if ((data[0] & 0xf0) != 0xf0)
364  return (data[0] & 0xf) + 1;
365 
366  return 0;
367 }
368 
369 bool 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 
379 void 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 
390 bool 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 
398 bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
399 {
400  auto data = getRawData();
401 
402  return ((data[0] & 0xf0) == 0x80)
403  || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
404 }
405 
406 bool MidiMessage::isNoteOnOrOff() const noexcept
407 {
408  auto d = getRawData()[0] & 0xf0;
409  return (d == 0x90) || (d == 0x80);
410 }
411 
412 int MidiMessage::getNoteNumber() const noexcept
413 {
414  return getRawData()[1];
415 }
416 
417 void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
418 {
419  if (isNoteOnOrOff() || isAftertouch())
420  getData()[1] = (uint8) (newNoteNumber & 127);
421 }
422 
423 uint8 MidiMessage::getVelocity() const noexcept
424 {
425  if (isNoteOnOrOff())
426  return getRawData()[2];
427 
428  return 0;
429 }
430 
431 float MidiMessage::getFloatVelocity() const noexcept
432 {
433  return getVelocity() * (1.0f / 127.0f);
434 }
435 
436 void MidiMessage::setVelocity (const float newVelocity) noexcept
437 {
438  if (isNoteOnOrOff())
439  getData()[2] = floatValueToMidiByte (newVelocity);
440 }
441 
442 void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
443 {
444  if (isNoteOnOrOff())
445  {
446  auto data = getData();
447  data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
448  }
449 }
450 
451 bool MidiMessage::isAftertouch() const noexcept
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 
475 bool MidiMessage::isChannelPressure() const noexcept
476 {
477  return (getRawData()[0] & 0xf0) == 0xd0;
478 }
479 
481 {
482  jassert (isChannelPressure());
483  return getRawData()[1];
484 }
485 
486 MidiMessage 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 
494 bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
495 bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
496 
497 bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
498 bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
499 
500 bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
501 bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
502 
503 
504 bool MidiMessage::isProgramChange() const noexcept
505 {
506  return (getRawData()[0] & 0xf0) == 0xc0;
507 }
508 
510 {
511  jassert (isProgramChange());
512  return getRawData()[1];
513 }
514 
515 MidiMessage 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 
522 bool MidiMessage::isPitchWheel() const noexcept
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 
534 MidiMessage 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 
543 bool MidiMessage::isController() const noexcept
544 {
545  return (getRawData()[0] & 0xf0) == 0xb0;
546 }
547 
548 bool 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 
566 MidiMessage 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 
575 MidiMessage 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 
584 MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept
585 {
586  return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
587 }
588 
589 MidiMessage 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 
598 MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, float velocity) noexcept
599 {
600  return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
601 }
602 
603 MidiMessage 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 
611 MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
612 {
613  return controllerEvent (channel, 123, 0);
614 }
615 
616 bool MidiMessage::isAllNotesOff() const noexcept
617 {
618  auto data = getRawData();
619  return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
620 }
621 
622 MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
623 {
624  return controllerEvent (channel, 120, 0);
625 }
626 
627 bool MidiMessage::isAllSoundOff() const noexcept
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 
639 MidiMessage 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 //==============================================================================
652 bool MidiMessage::isSysEx() const noexcept
653 {
654  return *getRawData() == 0xf0;
655 }
656 
657 MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
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 
668 const uint8* MidiMessage::getSysExData() const noexcept
669 {
670  return isSysEx() ? getRawData() + 1 : nullptr;
671 }
672 
673 int MidiMessage::getSysExDataSize() const noexcept
674 {
675  return isSysEx() ? size - 2 : 0;
676 }
677 
678 //==============================================================================
679 bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
680 bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
681 
682 int MidiMessage::getMetaEventType() const noexcept
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 
701 const uint8* MidiMessage::getMetaEventData() const noexcept
702 {
703  jassert (isMetaEvent());
704 
705  int n;
706  auto d = getRawData() + 2;
707  readVariableLengthVal (d, n);
708  return d + n;
709 }
710 
711 bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; }
712 bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; }
713 
714 bool MidiMessage::isTextMetaEvent() const noexcept
715 {
716  auto t = getMetaEventType();
717  return t > 0 && t < 16;
718 }
719 
721 {
722  auto textData = reinterpret_cast<const char*> (getMetaEventData());
723 
724  return String (CharPointer_UTF8 (textData),
725  CharPointer_UTF8 (textData + getMetaEventLength()));
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 
759 bool MidiMessage::isTrackNameEvent() const noexcept { auto data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
760 bool MidiMessage::isTempoMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
761 bool MidiMessage::isMidiChannelMetaEvent() const noexcept { auto data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
762 
764 {
765  jassert (isMidiChannelMetaEvent());
766  return getRawData()[3] + 1;
767 }
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 
782 double 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 
807 MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept
808 {
809  return { 0xff, 81, 3,
810  (uint8) (microsecondsPerQuarterNote >> 16),
811  (uint8) (microsecondsPerQuarterNote >> 8),
812  (uint8) microsecondsPerQuarterNote };
813 }
814 
816 {
817  auto data = getRawData();
818  return (data[1] == 0x58) && (*data == (uint8) 0xff);
819 }
820 
821 void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const noexcept
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 
836 MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator)
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 
850 MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept
851 {
852  return { 0xff, 0x20, 0x01, jlimit (0, 0xff, channel - 1) };
853 }
854 
856 {
857  return getMetaEventType() == 0x59;
858 }
859 
861 {
862  return (int) (int8) getMetaEventData()[0];
863 }
864 
866 {
867  return getMetaEventData()[1] == 0;
868 }
869 
870 MidiMessage MidiMessage::keySignatureMetaEvent (int numberOfSharpsOrFlats, bool isMinorKey)
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 //==============================================================================
883 bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
884 int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { auto data = getRawData(); return data[1] | (data[2] << 7); }
885 
886 MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
887 {
888  return { 0xf2,
889  positionInMidiBeats & 127,
890  (positionInMidiBeats >> 7) & 127 };
891 }
892 
893 bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
894 MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
895 
896 bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
897 MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
898 
899 bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
900 MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
901 
902 bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
903 MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
904 
905 bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
906 int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
907 int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
908 
909 MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
910 {
911  return MidiMessage (0xf1, (sequenceNumber << 4) | value);
912 }
913 
914 bool MidiMessage::isFullFrame() const noexcept
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 
925 void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames,
926  MidiMessage::SmpteTimecodeType& timecodeType) const noexcept
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 
938 MidiMessage MidiMessage::fullFrame (int hours, int minutes, int seconds, int frames,
939  MidiMessage::SmpteTimecodeType timecodeType)
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 
958 {
959  jassert (isMidiMachineControlMessage());
960 
962 }
963 
965 {
966  return { 0xf0, 0x7f, 0, 6, command, 0xf7 };
967 }
968 
969 //==============================================================================
970 bool 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 
993 MidiMessage 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 //==============================================================================
999 String MidiMessage::getMidiNoteName (int note, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
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  {
1006  String s (useSharps ? sharpNoteNames[note % 12]
1007  : flatNoteNames [note % 12]);
1008 
1009  if (includeOctaveNumber)
1010  s << (note / 12 + (octaveNumForMiddleC - 5));
1011 
1012  return s;
1013  }
1014 
1015  return {};
1016 }
1017 
1018 double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
1019 {
1020  return frequencyOfA * std::pow (2.0, (noteNumber - 69) / 12.0);
1021 }
1022 
1023 bool MidiMessage::isMidiNoteBlack (int noteNumber) noexcept
1024 {
1025  return ((1 << (noteNumber % 12)) & 0x054a) != 0;
1026 }
1027 
1028 const 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 
1069 const char* MidiMessage::getGMInstrumentBankName (const int n)
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 
1082 const char* MidiMessage::getRhythmInstrumentName (const int n)
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 
1103 const 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
juce::MidiMessage::getMidiNoteInHertz
static double getMidiNoteInHertz(int noteNumber, double frequencyOfA=440.0) noexcept
Returns the frequency of a midi note number.
Definition: juce_MidiMessage.cpp:1018
juce::MidiMessage::timeSignatureMetaEvent
static MidiMessage timeSignatureMetaEvent(int numerator, int denominator)
Creates a time-signature meta-event.
Definition: juce_MidiMessage.cpp:836
juce::MidiMessage::isChannelPressure
bool isChannelPressure() const noexcept
Returns true if the message is a channel-pressure change event.
Definition: juce_MidiMessage.cpp:475
juce::MidiMessage::isForChannel
bool isForChannel(int channelNumber) const noexcept
Returns true if the message applies to the given midi channel.
Definition: juce_MidiMessage.cpp:369
juce::MidiMessage::getControllerValue
int getControllerValue() const noexcept
Returns the controller value from a controller message.
Definition: juce_MidiMessage.cpp:560
juce::MidiMessage::readVariableLengthVal
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
Reads a midi variable-length integer.
Definition: juce_MidiMessage.cpp:60
juce::MidiMessage::isFullFrame
bool isFullFrame() const noexcept
Returns true if this is a full-frame midi timecode message.
Definition: juce_MidiMessage.cpp:914
juce::CharPointer_UTF8::getAddress
CharType * getAddress() const noexcept
Returns the address that this pointer is pointing to.
Definition: juce_CharPointer_UTF8.h:71
juce::StringRef
A simple class for holding temporary references to a string literal or String.
Definition: juce_StringRef.h:65
juce::MidiMessage::isNoteOn
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
Returns true if this message is a 'key-down' event.
Definition: juce_MidiMessage.cpp:390
juce::MidiMessage::isMidiStop
bool isMidiStop() const noexcept
Returns true if this is a midi stop event.
Definition: juce_MidiMessage.cpp:899
juce::MidiMessage::isSustainPedalOff
bool isSustainPedalOff() const noexcept
Returns true if this message is a 'sustain pedal up' controller message.
Definition: juce_MidiMessage.cpp:495
juce::MidiMessage::isMidiChannelMetaEvent
bool isMidiChannelMetaEvent() const noexcept
Returns true if this is a 'channel' meta-event.
Definition: juce_MidiMessage.cpp:761
juce::MidiMessage::getTempoSecondsPerQuarterNote
double getTempoSecondsPerQuarterNote() const noexcept
Calculates the seconds-per-quarter-note from a tempo meta-event.
Definition: juce_MidiMessage.cpp:769
juce::MidiMessage::getTimeSignatureInfo
void getTimeSignatureInfo(int &numerator, int &denominator) const noexcept
Returns the time-signature values from a time-signature meta-event.
Definition: juce_MidiMessage.cpp:821
juce::MidiMessage::endOfTrack
static MidiMessage endOfTrack() noexcept
Creates an end-of-track meta-event.
Definition: juce_MidiMessage.cpp:877
juce::MidiMessage::getControllerName
static const char * getControllerName(int controllerNumber)
Returns the name of a controller type number, or nullptr if unknown for this controller number.
Definition: juce_MidiMessage.cpp:1103
juce::HeapBlock< uint8 >
juce::MidiMessage::quarterFrame
static MidiMessage quarterFrame(int sequenceNumber, int value) noexcept
Creates a quarter-frame MTC message.
Definition: juce_MidiMessage.cpp:909
juce::MidiMessage::masterVolume
static MidiMessage masterVolume(float volume)
Creates a master-volume change message.
Definition: juce_MidiMessage.cpp:644
juce::MidiMessage::isMidiClock
bool isMidiClock() const noexcept
Returns true if this is a midi clock event.
Definition: juce_MidiMessage.cpp:902
juce::MidiMessage::allControllersOff
static MidiMessage allControllersOff(int channel) noexcept
Creates an all-controllers-off message.
Definition: juce_MidiMessage.cpp:639
juce::MidiMessage::getVelocity
uint8 getVelocity() const noexcept
Returns the velocity of a note-on or note-off message.
Definition: juce_MidiMessage.cpp:423
juce::MidiMessage::isPitchWheel
bool isPitchWheel() const noexcept
Returns true if the message is a pitch-wheel move.
Definition: juce_MidiMessage.cpp:522
juce::MidiMessage::channelPressureChange
static MidiMessage channelPressureChange(int channel, int pressure) noexcept
Creates a channel-pressure change event.
Definition: juce_MidiMessage.cpp:486
juce::MidiMessage::getTextFromTextMetaEvent
String getTextFromTextMetaEvent() const
Returns the text from a text meta-event.
Definition: juce_MidiMessage.cpp:720
juce::MidiMessage::isProgramChange
bool isProgramChange() const noexcept
Returns true if the message is a program (patch) change message.
Definition: juce_MidiMessage.cpp:504
juce::MidiMessage::isMetaEvent
bool isMetaEvent() const noexcept
Returns true if this event is a meta-event.
Definition: juce_MidiMessage.cpp:679
juce::MidiMessage::getQuarterFrameSequenceNumber
int getQuarterFrameSequenceNumber() const noexcept
Returns the sequence number of a quarter-frame midi timecode message.
Definition: juce_MidiMessage.cpp:906
juce::MidiMessage::MidiMessage
MidiMessage() noexcept
Creates an active-sense message.
Definition: juce_MidiMessage.cpp:100
juce::MidiMessage::floatValueToMidiByte
static uint8 floatValueToMidiByte(float valueBetween0and1) noexcept
Converts a floating-point value between 0 and 1 to a MIDI 7-bit value between 0 and 127.
Definition: juce_MidiMessage.cpp:40
juce::MidiMessage::setChannel
void setChannel(int newChannelNumber) noexcept
Changes the message's midi channel.
Definition: juce_MidiMessage.cpp:379
juce::MidiMessage::getFullFrameParameters
void getFullFrameParameters(int &hours, int &minutes, int &seconds, int &frames, SmpteTimecodeType &timecodeType) const noexcept
Extracts the timecode information from a full-frame midi timecode message.
Definition: juce_MidiMessage.cpp:925
juce::MidiMessage::midiContinue
static MidiMessage midiContinue() noexcept
Creates a midi continue event.
Definition: juce_MidiMessage.cpp:897
juce::MidiMessage::isKeySignatureMetaEvent
bool isKeySignatureMetaEvent() const noexcept
Returns true if this is a 'key-signature' meta-event.
Definition: juce_MidiMessage.cpp:855
juce::MidiMessage::isKeySignatureMajorKey
bool isKeySignatureMajorKey() const noexcept
Returns true if this key-signature event is major, or false if it's minor.
Definition: juce_MidiMessage.cpp:865
juce::MidiMessage::setNoteNumber
void setNoteNumber(int newNoteNumber) noexcept
Changes the midi note number of a note-on or note-off message.
Definition: juce_MidiMessage.cpp:417
juce::MidiMessage::allNotesOff
static MidiMessage allNotesOff(int channel) noexcept
Creates an all-notes-off message.
Definition: juce_MidiMessage.cpp:611
juce::MidiMessage::isSustainPedalOn
bool isSustainPedalOn() const noexcept
Returns true if this message is a 'sustain pedal down' controller message.
Definition: juce_MidiMessage.cpp:494
juce::MidiMessage::getRawData
const uint8 * getRawData() const noexcept
Returns a pointer to the raw midi data.
Definition: juce_MidiMessage.h:137
juce::MidiMessage::isMidiMachineControlGoto
bool isMidiMachineControlGoto(int &hours, int &minutes, int &seconds, int &frames) const noexcept
Checks whether this is an MMC "goto" message.
Definition: juce_MidiMessage.cpp:970
juce::MidiMessage::isActiveSense
bool isActiveSense() const noexcept
Returns true if this is an active-sense message.
Definition: juce_MidiMessage.cpp:680
juce::MidiMessage::getSongPositionPointerMidiBeat
int getSongPositionPointerMidiBeat() const noexcept
Returns the midi beat-number of a song-position-pointer message.
Definition: juce_MidiMessage.cpp:884
juce::String::toHexString
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
Definition: juce_String.h:1055
juce::MidiMessage::getMetaEventData
const uint8 * getMetaEventData() const noexcept
Returns a pointer to the data in a meta-event.
Definition: juce_MidiMessage.cpp:701
juce::MidiMessage::getMidiMachineControlCommand
MidiMachineControlCommand getMidiMachineControlCommand() const noexcept
For an MMC message, this returns its type.
Definition: juce_MidiMessage.cpp:957
juce::MidiMessage::getRawDataSize
int getRawDataSize() const noexcept
Returns the number of bytes of data in the message.
Definition: juce_MidiMessage.h:142
juce::MidiMessage::~MidiMessage
~MidiMessage() noexcept
Destructor.
Definition: juce_MidiMessage.cpp:311
juce::MidiMessage::isSostenutoPedalOn
bool isSostenutoPedalOn() const noexcept
Returns true if this message is a 'sostenuto pedal down' controller message.
Definition: juce_MidiMessage.cpp:497
juce::MidiMessage::operator=
MidiMessage & operator=(const MidiMessage &other)
Copies this message from another one.
Definition: juce_MidiMessage.cpp:267
juce::MidiMessage::isNoteOnOrOff
bool isNoteOnOrOff() const noexcept
Returns true if this message is a 'key-down' or 'key-up' event.
Definition: juce_MidiMessage.cpp:406
juce::MidiMessage::pitchWheel
static MidiMessage pitchWheel(int channel, int position) noexcept
Creates a pitch-wheel move message.
Definition: juce_MidiMessage.cpp:534
juce::StringRef::text
String::CharPointerType text
The text that is referenced.
Definition: juce_StringRef.h:126
juce::MidiMessage::getAfterTouchValue
int getAfterTouchValue() const noexcept
Returns the amount of aftertouch from an aftertouch messages.
Definition: juce_MidiMessage.cpp:456
juce::MidiMessage::isResetAllControllers
bool isResetAllControllers() const noexcept
Checks whether this message is a reset all controllers message.
Definition: juce_MidiMessage.cpp:633
juce::MidiMessage::isTempoMetaEvent
bool isTempoMetaEvent() const noexcept
Returns true if this is a 'tempo' meta-event.
Definition: juce_MidiMessage.cpp:760
juce::MidiMessage::isQuarterFrame
bool isQuarterFrame() const noexcept
Returns true if this is a quarter-frame midi timecode message.
Definition: juce_MidiMessage.cpp:905
juce::MidiMessage::isMidiStart
bool isMidiStart() const noexcept
Returns true if this is a midi start event.
Definition: juce_MidiMessage.cpp:893
juce::MidiMessage::isMidiMachineControlMessage
bool isMidiMachineControlMessage() const noexcept
Checks whether this is an MMC message.
Definition: juce_MidiMessage.cpp:947
juce::MidiMessage::getGMInstrumentName
static const char * getGMInstrumentName(int midiInstrumentNumber)
Returns the standard name of a GM instrument, or nullptr if unknown for this index.
Definition: juce_MidiMessage.cpp:1028
juce::MidiMessage::midiMachineControlCommand
static MidiMessage midiMachineControlCommand(MidiMachineControlCommand command)
Creates an MMC message.
Definition: juce_MidiMessage.cpp:964
juce::MidiMessage::isAllNotesOff
bool isAllNotesOff() const noexcept
Checks whether this message is an all-notes-off message.
Definition: juce_MidiMessage.cpp:616
juce::MidiMessage::getMessageLengthFromFirstByte
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
Based on the first byte of a short midi message, this uses a lookup table to return the message lengt...
Definition: juce_MidiMessage.cpp:79
juce::MidiMessage::noteOn
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
Creates a key-down message (using a floating-point velocity).
Definition: juce_MidiMessage.cpp:584
juce::MidiMessage::midiMachineControlGoto
static MidiMessage midiMachineControlGoto(int hours, int minutes, int seconds, int frames)
Creates an MMC "goto" message.
Definition: juce_MidiMessage.cpp:993
juce::MidiMessage::tempoMetaEvent
static MidiMessage tempoMetaEvent(int microsecondsPerQuarterNote) noexcept
Creates a tempo meta-event.
Definition: juce_MidiMessage.cpp:807
juce::MidiMessage::getGMInstrumentBankName
static const char * getGMInstrumentBankName(int midiBankNumber)
Returns the name of a bank of GM instruments, or nullptr if unknown for this bank number.
Definition: juce_MidiMessage.cpp:1069
juce::MidiMessage::programChange
static MidiMessage programChange(int channel, int programNumber) noexcept
Creates a program-change message.
Definition: juce_MidiMessage.cpp:515
juce::MidiMessage::midiChannelMetaEvent
static MidiMessage midiChannelMetaEvent(int channel) noexcept
Creates a midi channel meta-event.
Definition: juce_MidiMessage.cpp:850
juce::MidiMessage::midiStop
static MidiMessage midiStop() noexcept
Creates a midi stop event.
Definition: juce_MidiMessage.cpp:900
juce::MidiMessage::isNoteOff
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
Returns true if this message is a 'key-up' event.
Definition: juce_MidiMessage.cpp:398
juce::MidiMessage::songPositionPointer
static MidiMessage songPositionPointer(int positionInMidiBeats) noexcept
Creates a song-position-pointer message.
Definition: juce_MidiMessage.cpp:886
juce::MidiMessage
Encapsulates a MIDI message.
Definition: juce_MidiMessage.h:38
juce::MidiMessage::isTextMetaEvent
bool isTextMetaEvent() const noexcept
Returns true if this is a 'text' meta-event.
Definition: juce_MidiMessage.cpp:714
juce::CharPointer_UTF8::sizeInBytes
size_t sizeInBytes() const noexcept
Returns the number of bytes that are used to represent this string.
Definition: juce_CharPointer_UTF8.h:279
juce::MidiMessage::isMidiNoteBlack
static bool isMidiNoteBlack(int noteNumber) noexcept
Returns true if the given midi note number is a black key.
Definition: juce_MidiMessage.cpp:1023
juce::MidiMessage::isSoftPedalOff
bool isSoftPedalOff() const noexcept
Returns true if this message is a 'soft pedal up' controller message.
Definition: juce_MidiMessage.cpp:501
juce::String::isEmpty
bool isEmpty() const noexcept
Returns true if the string contains no characters.
Definition: juce_String.h:300
juce::MidiMessage::textMetaEvent
static MidiMessage textMetaEvent(int type, StringRef text)
Creates a text meta-event.
Definition: juce_MidiMessage.cpp:728
juce::MidiMessage::getRhythmInstrumentName
static const char * getRhythmInstrumentName(int midiNoteNumber)
Returns the standard name of a channel 10 percussion sound, or nullptr if unknown for this note numbe...
Definition: juce_MidiMessage.cpp:1082
juce::MidiMessage::getQuarterFrameValue
int getQuarterFrameValue() const noexcept
Returns the value from a quarter-frame message.
Definition: juce_MidiMessage.cpp:907
juce::MidiMessage::getMetaEventLength
int getMetaEventLength() const noexcept
Returns the length of the data for a meta-event.
Definition: juce_MidiMessage.cpp:688
juce::MidiMessage::setVelocity
void setVelocity(float newVelocity) noexcept
Changes the velocity of a note-on or note-off message.
Definition: juce_MidiMessage.cpp:436
juce::MidiMessage::pitchbendToPitchwheelPos
static uint16 pitchbendToPitchwheelPos(float pitchbendInSemitones, float pitchbendRangeInSemitones) noexcept
Converts a pitchbend value in semitones to a MIDI 14-bit pitchwheel position value.
Definition: juce_MidiMessage.cpp:48
juce::MidiMessage::withTimeStamp
MidiMessage withTimeStamp(double newTimestamp) const
Return a copy of this message with a new timestamp.
Definition: juce_MidiMessage.cpp:354
juce::MidiMessage::getSysExData
const uint8 * getSysExData() const noexcept
Returns a pointer to the sysex data inside the message.
Definition: juce_MidiMessage.cpp:668
juce::MidiMessage::fullFrame
static MidiMessage fullFrame(int hours, int minutes, int seconds, int frames, SmpteTimecodeType timecodeType)
Creates a full-frame MTC message.
Definition: juce_MidiMessage.cpp:938
juce::MidiMessage::isTrackNameEvent
bool isTrackNameEvent() const noexcept
Returns true if this is an 'track name' meta-event.
Definition: juce_MidiMessage.cpp:759
juce::MidiMessage::getNoteNumber
int getNoteNumber() const noexcept
Returns the midi note number for note-on and note-off messages.
Definition: juce_MidiMessage.cpp:412
juce::CharPointer_UTF8
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
Definition: juce_CharPointer_UTF8.h:38
juce::MidiMessage::midiStart
static MidiMessage midiStart() noexcept
Creates a midi start event.
Definition: juce_MidiMessage.cpp:894
juce::MidiMessage::multiplyVelocity
void multiplyVelocity(float scaleFactor) noexcept
Multiplies the velocity of a note-on or note-off message by a given amount.
Definition: juce_MidiMessage.cpp:442
juce::MidiMessage::getTempoMetaEventTickLength
double getTempoMetaEventTickLength(short timeFormat) const noexcept
Returns the tick length from a tempo meta-event.
Definition: juce_MidiMessage.cpp:782
juce::MidiMessage::getProgramChangeNumber
int getProgramChangeNumber() const noexcept
Returns the new program number of a program change message.
Definition: juce_MidiMessage.cpp:509
juce::MidiMessage::isTrackMetaEvent
bool isTrackMetaEvent() const noexcept
Returns true if this is a 'track' meta-event.
Definition: juce_MidiMessage.cpp:711
juce::MidiMessage::isSongPositionPointer
bool isSongPositionPointer() const noexcept
Returns true if this is a song-position-pointer message.
Definition: juce_MidiMessage.cpp:883
juce::MidiMessage::isSostenutoPedalOff
bool isSostenutoPedalOff() const noexcept
Returns true if this message is a 'sostenuto pedal up' controller message.
Definition: juce_MidiMessage.cpp:498
juce::MidiMessage::getDescription
String getDescription() const
Returns a human-readable description of the midi message as a string, for example "Note On C#3 Veloci...
Definition: juce_MidiMessage.cpp:329
juce::MidiMessage::getMidiNoteName
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
Returns the name of a midi note number.
Definition: juce_MidiMessage.cpp:999
juce::MidiMessage::getMetaEventType
int getMetaEventType() const noexcept
Returns a meta-event's type number.
Definition: juce_MidiMessage.cpp:682
juce::MidiMessage::isMidiContinue
bool isMidiContinue() const noexcept
Returns true if this is a midi continue event.
Definition: juce_MidiMessage.cpp:896
juce::MidiMessage::aftertouchChange
static MidiMessage aftertouchChange(int channel, int noteNumber, int aftertouchAmount) noexcept
Creates an aftertouch message.
Definition: juce_MidiMessage.cpp:462
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::MidiMessage::isSoftPedalOn
bool isSoftPedalOn() const noexcept
Returns true if this message is a 'soft pedal down' controller message.
Definition: juce_MidiMessage.cpp:500
juce::MidiMessage::getSysExDataSize
int getSysExDataSize() const noexcept
Returns the size of the sysex data.
Definition: juce_MidiMessage.cpp:673
juce::MidiMessage::isController
bool isController() const noexcept
Returns true if this is a midi controller message.
Definition: juce_MidiMessage.cpp:543
juce::MidiMessage::getFloatVelocity
float getFloatVelocity() const noexcept
Returns the velocity of a note-on or note-off message.
Definition: juce_MidiMessage.cpp:431
juce::MidiMessage::isEndOfTrackMetaEvent
bool isEndOfTrackMetaEvent() const noexcept
Returns true if this is an 'end-of-track' meta-event.
Definition: juce_MidiMessage.cpp:712
juce::MidiMessage::keySignatureMetaEvent
static MidiMessage keySignatureMetaEvent(int numberOfSharpsOrFlats, bool isMinorKey)
Creates a key-signature meta-event.
Definition: juce_MidiMessage.cpp:870
juce::MidiMessage::SmpteTimecodeType
SmpteTimecodeType
SMPTE timecode types.
Definition: juce_MidiMessage.h:769
juce::MidiMessage::MidiMachineControlCommand
MidiMachineControlCommand
Types of MMC command.
Definition: juce_MidiMessage.h:803
juce::MidiMessage::isTimeSignatureMetaEvent
bool isTimeSignatureMetaEvent() const noexcept
Returns true if this is a 'time-signature' meta-event.
Definition: juce_MidiMessage.cpp:815
juce::MidiMessage::getPitchWheelValue
int getPitchWheelValue() const noexcept
Returns the pitch wheel position from a pitch-wheel move message.
Definition: juce_MidiMessage.cpp:527
juce::MidiMessage::midiClock
static MidiMessage midiClock() noexcept
Creates a midi clock event.
Definition: juce_MidiMessage.cpp:903
juce::MidiMessage::getMidiChannelMetaEventChannel
int getMidiChannelMetaEventChannel() const noexcept
Returns the channel number from a channel meta-event.
Definition: juce_MidiMessage.cpp:763
juce::MidiMessage::isSysEx
bool isSysEx() const noexcept
Returns true if this is a system-exclusive message.
Definition: juce_MidiMessage.cpp:652
juce::MidiMessage::createSysExMessage
static MidiMessage createSysExMessage(const void *sysexData, int dataSize)
Creates a system-exclusive message.
Definition: juce_MidiMessage.cpp:657
juce::MidiMessage::getChannel
int getChannel() const noexcept
Returns the midi channel associated with the message.
Definition: juce_MidiMessage.cpp:359
juce::MidiMessage::allSoundOff
static MidiMessage allSoundOff(int channel) noexcept
Creates an all-sound-off message.
Definition: juce_MidiMessage.cpp:622
juce::MidiMessage::getKeySignatureNumberOfSharpsOrFlats
int getKeySignatureNumberOfSharpsOrFlats() const noexcept
Returns the key from a key-signature meta-event.
Definition: juce_MidiMessage.cpp:860
juce::MidiMessage::controllerEvent
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
Creates a controller message.
Definition: juce_MidiMessage.cpp:566
juce::MidiMessage::noteOff
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
Creates a key-up message.
Definition: juce_MidiMessage.cpp:598
juce::MidiMessage::getControllerNumber
int getControllerNumber() const noexcept
Returns the controller number of a controller message.
Definition: juce_MidiMessage.cpp:554
juce::MidiMessage::isControllerOfType
bool isControllerOfType(int controllerType) const noexcept
Returns true if this message is a controller message and if it has the specified controller type.
Definition: juce_MidiMessage.cpp:548
juce::MidiMessage::getChannelPressureValue
int getChannelPressureValue() const noexcept
Returns the pressure from a channel pressure change message.
Definition: juce_MidiMessage.cpp:480
juce::MidiMessage::isAllSoundOff
bool isAllSoundOff() const noexcept
Checks whether this message is an all-sound-off message.
Definition: juce_MidiMessage.cpp:627
juce::MidiMessage::isAftertouch
bool isAftertouch() const noexcept
Returns true if the message is an aftertouch event.
Definition: juce_MidiMessage.cpp:451