OpenShot Audio Library | OpenShotAudio  0.3.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
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
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)
const uint8 * getRawData() const noexcept
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
Definition: juce_String.h:296
static String toHexString(IntegerType number)
Definition: juce_String.h:1053