28 inline uint8 initialByte (
const int type,
const int channel)
noexcept
30 return (uint8) (type | jlimit (0, 15, channel - 1));
33 inline uint8 validVelocity (
const int v)
noexcept
35 return (uint8) jlimit (0, 127, v);
42 jassert (v >= 0 && v <= 1.0f);
45 return MidiHelpers::validVelocity (roundToInt (v * 127.0f));
49 const float pitchbendRange)
noexcept
52 jassert (std::abs (pitchbend) <= pitchbendRange);
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));
67 const auto limit = jmin (maxBytesToUse, 4);
69 for (
int numBytesUsed = 0; numBytesUsed < limit; ++numBytesUsed)
71 const auto i = data[numBytesUsed];
72 v = (v << 7) + (i & 0x7f);
75 return { (int) v, numBytesUsed + 1 };
94 if (++numBytesUsed > 6)
97 v = (v << 7) + (i & 0x7f);
107 jassert (firstByte >= 0x80 && firstByte != 0xf0 && firstByte != 0xf7);
109 static const char messageLengths[] =
111 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
112 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
113 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
114 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
115 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
116 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
117 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
118 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
121 return messageLengths[firstByte & 0x7f];
128 packedData.asBytes[0] = 0xf0;
129 packedData.asBytes[1] = 0xf7;
133 : timeStamp (t), size (dataSize)
135 jassert (dataSize > 0);
139 memcpy (allocateSpace (dataSize), d, (
size_t) dataSize);
143 : timeStamp (t), size (1)
145 packedData.asBytes[0] = (uint8) byte1;
148 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 1);
152 : timeStamp (t), size (2)
154 packedData.asBytes[0] = (uint8) byte1;
155 packedData.asBytes[1] = (uint8) byte2;
158 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 2);
162 : timeStamp (t), size (3)
164 packedData.asBytes[0] = (uint8) byte1;
165 packedData.asBytes[1] = (uint8) byte2;
166 packedData.asBytes[2] = (uint8) byte3;
169 jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 3);
173 : timeStamp (other.timeStamp), size (other.size)
175 if (isHeapAllocated())
176 memcpy (allocateSpace (size), other.getData(), (
size_t) size);
178 packedData.allocatedData = other.packedData.allocatedData;
182 : timeStamp (newTimeStamp), size (other.size)
184 if (isHeapAllocated())
185 memcpy (allocateSpace (size), other.getData(), (
size_t) size);
187 packedData.allocatedData = other.packedData.allocatedData;
191 double t,
bool sysexHasEmbeddedLength)
194 auto src =
static_cast<const uint8*
> (srcData);
195 auto byte = (
unsigned int) *src;
199 byte = (
unsigned int) lastStatusByte;
214 bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
215 int numVariableLengthSysexBytes = 0;
227 if (haveReadAllLengthBytes)
230 ++numVariableLengthSysexBytes;
232 else if (! haveReadAllLengthBytes)
234 haveReadAllLengthBytes =
true;
235 ++numVariableLengthSysexBytes;
241 src += numVariableLengthSysexBytes;
242 size = 1 + (int) (d - src);
244 auto dest = allocateSpace (size);
245 *dest = (uint8)
byte;
246 memcpy (dest + 1, src, (
size_t) (size - 1));
248 numBytesUsed += (numVariableLengthSysexBytes + size);
250 else if (
byte == 0xff)
253 size = jmin (sz + 1, bytesLeft.bytesUsed + 2 + bytesLeft.value);
255 auto dest = allocateSpace (size);
256 *dest = (uint8)
byte;
257 memcpy (dest + 1, src, (
size_t) size - 1);
259 numBytesUsed += size;
264 packedData.asBytes[0] = (uint8)
byte;
268 packedData.asBytes[1] = (sz > 0 ? src[0] : 0);
271 packedData.asBytes[2] = (sz > 1 ? src[1] : 0);
274 numBytesUsed += jmin (size, sz + 1);
279 packedData.allocatedData =
nullptr;
288 if (other.isHeapAllocated())
290 auto* newStorage =
static_cast<uint8*
> (isHeapAllocated()
291 ? std::realloc (packedData.allocatedData, (
size_t) other.size)
292 : std::malloc ((
size_t) other.size));
294 if (newStorage ==
nullptr)
295 throw std::bad_alloc{};
297 packedData.allocatedData = newStorage;
298 memcpy (packedData.allocatedData, other.packedData.allocatedData, (
size_t) other.size);
302 if (isHeapAllocated())
303 std::free (packedData.allocatedData);
305 packedData.allocatedData = other.packedData.allocatedData;
308 timeStamp = other.timeStamp;
316 : timeStamp (other.timeStamp), size (other.size)
318 packedData.allocatedData = other.packedData.allocatedData;
324 packedData.allocatedData = other.packedData.allocatedData;
325 timeStamp = other.timeStamp;
333 if (isHeapAllocated())
334 std::free (packedData.allocatedData);
337uint8* MidiMessage::allocateSpace (
int bytes)
339 if (bytes > (
int)
sizeof (packedData))
341 auto d =
static_cast<uint8*
> (std::malloc ((
size_t) bytes));
342 packedData.allocatedData = d;
346 return packedData.asBytes;
376 return { *
this, newTimestamp };
383 if ((data[0] & 0xf0) != 0xf0)
384 return (data[0] & 0xf) + 1;
391 jassert (channel > 0 && channel <= 16);
393 auto data = getRawData();
395 return ((data[0] & 0xf) == channel - 1)
396 && ((data[0] & 0xf0) != 0xf0);
401 jassert (channel > 0 && channel <= 16);
403 auto data = getData();
405 if ((data[0] & 0xf0) != (uint8) 0xf0)
406 data[0] = (uint8) ((data[0] & (uint8) 0xf0)
407 | (uint8) (channel - 1));
412 auto data = getRawData();
414 return ((data[0] & 0xf0) == 0x90)
415 && (returnTrueForVelocity0 || data[2] != 0);
420 auto data = getRawData();
422 return ((data[0] & 0xf0) == 0x80)
423 || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
429 return (d == 0x90) || (d == 0x80);
439 if (isNoteOnOrOff() || isAftertouch())
440 getData()[1] = (uint8) (newNoteNumber & 127);
459 getData()[2] = floatValueToMidiByte (newVelocity);
466 auto data = getData();
467 data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
484 const int aftertouchValue)
noexcept
486 jassert (channel > 0 && channel <= 16);
487 jassert (isPositiveAndBelow (noteNum, 128));
488 jassert (isPositiveAndBelow (aftertouchValue, 128));
490 return MidiMessage (MidiHelpers::initialByte (0xa0, channel),
492 aftertouchValue & 0x7f);
508 jassert (channel > 0 && channel <= 16);
509 jassert (isPositiveAndBelow (pressure, 128));
511 return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
537 jassert (channel > 0 && channel <= 16);
539 return MidiMessage (MidiHelpers::initialByte (0xc0, channel), programNumber & 0x7f);
551 return data[1] | (data[2] << 7);
556 jassert (channel > 0 && channel <= 16);
557 jassert (isPositiveAndBelow (position, 0x4000));
559 return MidiMessage (MidiHelpers::initialByte (0xe0, channel),
560 position & 127, (position >> 7) & 127);
570 auto data = getRawData();
571 return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
589 jassert (channel > 0 && channel <= 16);
591 return MidiMessage (MidiHelpers::initialByte (0xb0, channel),
592 controllerType & 127, value & 127);
597 jassert (channel > 0 && channel <= 16);
598 jassert (isPositiveAndBelow (noteNumber, 128));
600 return MidiMessage (MidiHelpers::initialByte (0x90, channel),
601 noteNumber & 127, MidiHelpers::validVelocity (velocity));
606 return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
611 jassert (channel > 0 && channel <= 16);
612 jassert (isPositiveAndBelow (noteNumber, 128));
614 return MidiMessage (MidiHelpers::initialByte (0x80, channel),
615 noteNumber & 127, MidiHelpers::validVelocity (velocity));
620 return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
625 jassert (channel > 0 && channel <= 16);
626 jassert (isPositiveAndBelow (noteNumber, 128));
628 return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, 0);
633 return controllerEvent (channel, 123, 0);
639 return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
644 return controllerEvent (channel, 120, 0);
650 return data[1] == 120 && (data[0] & 0xf0) == 0xb0;
656 return (data[0] & 0xf0) == 0xb0 && data[1] == 121;
661 return controllerEvent (channel, 121, 0);
666 auto vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000));
668 return { 0xf0, 0x7f, 0x7f, 0x04, 0x01, vol & 0x7f, vol >> 7, 0xf7 };
682 memcpy (m + 1, sysexData, (
size_t) dataSize);
683 m[dataSize + 1] = 0xf7;
700 return isSysEx() ? size - 2 : 0;
710 return (size < 2 || *data != 0xff) ? -1 : data[1];
720 return jmax (0, jmin (size - 2 -
var.bytesUsed,
var.value));
732 return d +
var.bytesUsed;
741 return t > 0 && t < 16;
754 jassert (type > 0 && type < 16);
758 const size_t textSize = text.
text.sizeInBytes() - 1;
761 size_t n =
sizeof (header);
763 header[--n] = (uint8) (textSize & 0x7f);
765 for (
size_t i = textSize; (i >>= 7) != 0;)
766 header[--n] = (uint8) ((i & 0x7f) | 0x80);
768 header[--n] = (uint8) type;
771 const size_t headerLen =
sizeof (header) - n;
772 const int totalSize = (int) (headerLen + textSize);
774 auto dest = result.allocateSpace (totalSize);
775 result.size = totalSize;
777 memcpy (dest, header + n, headerLen);
778 memcpy (dest + headerLen, text.
text.getAddress(), textSize);
800 return (((
unsigned int) d[0] << 16)
801 | ((
unsigned int) d[1] << 8)
810 if (! isTempoMetaEvent())
811 return 0.5 / timeFormat;
813 return getTempoSecondsPerQuarterNote() / timeFormat;
816 const int frameCode = (-timeFormat) >> 8;
817 double framesPerSecond;
821 case 24: framesPerSecond = 24.0;
break;
822 case 25: framesPerSecond = 25.0;
break;
823 case 29: framesPerSecond = 30.0 * 1000.0 / 1001.0;
break;
824 case 30: framesPerSecond = 30.0;
break;
825 default: framesPerSecond = 30.0;
break;
828 return (1.0 / framesPerSecond) / (timeFormat & 0xff);
833 return { 0xff, 81, 3,
834 (uint8) (microsecondsPerQuarterNote >> 16),
835 (uint8) (microsecondsPerQuarterNote >> 8),
836 (uint8) microsecondsPerQuarterNote };
842 return (data[1] == 0x58) && (*data == (uint8) 0xff);
847 if (isTimeSignatureMetaEvent())
849 auto d = getMetaEventData();
851 denominator = 1 << d[1];
865 while (n < denominator)
871 return { 0xff, 0x58, 0x04, numerator, powerOfTwo, 1, 96 };
876 return { 0xff, 0x20, 0x01, jlimit (0, 0xff, channel - 1) };
896 jassert (numberOfSharpsOrFlats >= -7 && numberOfSharpsOrFlats <= 7);
898 return { 0xff, 0x59, 0x02, numberOfSharpsOrFlats, isMinorKey ? 1 : 0 };
903 return { 0xff, 0x2f, 0x00 };
913 positionInMidiBeats & 127,
914 (positionInMidiBeats >> 7) & 127 };
935 return MidiMessage (0xf1, (sequenceNumber << 4) | value);
942 return data[0] == 0xf0
952 jassert (isFullFrame());
954 auto data = getRawData();
956 hours = data[5] & 0x1f;
965 return { 0xf0, 0x7f, 0x7f, 0x01, 0x01,
966 (hours & 0x01f) | (timecodeType << 5),
967 minutes, seconds, frames,
975 return data[0] == 0xf0
990 return { 0xf0, 0x7f, 0, 6, command, 0xf7 };
996 auto data = getRawData();
1006 hours = data[7] % 24;
1019 return { 0xf0, 0x7f, 0, 6, 0x44, 6, 1, hours, minutes, seconds, frames, 0xf7 };
1025 static const char*
const sharpNoteNames[] = {
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B" };
1026 static const char*
const flatNoteNames[] = {
"C",
"Db",
"D",
"Eb",
"E",
"F",
"Gb",
"G",
"Ab",
"A",
"Bb",
"B" };
1028 if (isPositiveAndBelow (note, 128))
1030 String s (useSharps ? sharpNoteNames[note % 12]
1031 : flatNoteNames [note % 12]);
1033 if (includeOctaveNumber)
1034 s << (note / 12 + (octaveNumForMiddleC - 5));
1044 return frequencyOfA * std::pow (2.0, (noteNumber - 69) / 12.0);
1049 return ((1 << (noteNumber % 12)) & 0x054a) != 0;
1054 static const char* names[] =
1056 NEEDS_TRANS (
"Acoustic Grand Piano"), NEEDS_TRANS (
"Bright Acoustic Piano"), NEEDS_TRANS (
"Electric Grand Piano"), NEEDS_TRANS (
"Honky-tonk Piano"),
1057 NEEDS_TRANS (
"Electric Piano 1"), NEEDS_TRANS (
"Electric Piano 2"), NEEDS_TRANS (
"Harpsichord"), NEEDS_TRANS (
"Clavinet"),
1058 NEEDS_TRANS (
"Celesta"), NEEDS_TRANS (
"Glockenspiel"), NEEDS_TRANS (
"Music Box"), NEEDS_TRANS (
"Vibraphone"),
1059 NEEDS_TRANS (
"Marimba"), NEEDS_TRANS (
"Xylophone"), NEEDS_TRANS (
"Tubular Bells"), NEEDS_TRANS (
"Dulcimer"),
1060 NEEDS_TRANS (
"Drawbar Organ"), NEEDS_TRANS (
"Percussive Organ"), NEEDS_TRANS (
"Rock Organ"), NEEDS_TRANS (
"Church Organ"),
1061 NEEDS_TRANS (
"Reed Organ"), NEEDS_TRANS (
"Accordion"), NEEDS_TRANS (
"Harmonica"), NEEDS_TRANS (
"Tango Accordion"),
1062 NEEDS_TRANS (
"Acoustic Guitar (nylon)"), NEEDS_TRANS (
"Acoustic Guitar (steel)"), NEEDS_TRANS (
"Electric Guitar (jazz)"), NEEDS_TRANS (
"Electric Guitar (clean)"),
1063 NEEDS_TRANS (
"Electric Guitar (mute)"), NEEDS_TRANS (
"Overdriven Guitar"), NEEDS_TRANS (
"Distortion Guitar"), NEEDS_TRANS (
"Guitar Harmonics"),
1064 NEEDS_TRANS (
"Acoustic Bass"), NEEDS_TRANS (
"Electric Bass (finger)"), NEEDS_TRANS (
"Electric Bass (pick)"), NEEDS_TRANS (
"Fretless Bass"),
1065 NEEDS_TRANS (
"Slap Bass 1"), NEEDS_TRANS (
"Slap Bass 2"), NEEDS_TRANS (
"Synth Bass 1"), NEEDS_TRANS (
"Synth Bass 2"),
1066 NEEDS_TRANS (
"Violin"), NEEDS_TRANS (
"Viola"), NEEDS_TRANS (
"Cello"), NEEDS_TRANS (
"Contrabass"),
1067 NEEDS_TRANS (
"Tremolo Strings"), NEEDS_TRANS (
"Pizzicato Strings"), NEEDS_TRANS (
"Orchestral Harp"), NEEDS_TRANS (
"Timpani"),
1068 NEEDS_TRANS (
"String Ensemble 1"), NEEDS_TRANS (
"String Ensemble 2"), NEEDS_TRANS (
"SynthStrings 1"), NEEDS_TRANS (
"SynthStrings 2"),
1069 NEEDS_TRANS (
"Choir Aahs"), NEEDS_TRANS (
"Voice Oohs"), NEEDS_TRANS (
"Synth Voice"), NEEDS_TRANS (
"Orchestra Hit"),
1070 NEEDS_TRANS (
"Trumpet"), NEEDS_TRANS (
"Trombone"), NEEDS_TRANS (
"Tuba"), NEEDS_TRANS (
"Muted Trumpet"),
1071 NEEDS_TRANS (
"French Horn"), NEEDS_TRANS (
"Brass Section"), NEEDS_TRANS (
"SynthBrass 1"), NEEDS_TRANS (
"SynthBrass 2"),
1072 NEEDS_TRANS (
"Soprano Sax"), NEEDS_TRANS (
"Alto Sax"), NEEDS_TRANS (
"Tenor Sax"), NEEDS_TRANS (
"Baritone Sax"),
1073 NEEDS_TRANS (
"Oboe"), NEEDS_TRANS (
"English Horn"), NEEDS_TRANS (
"Bassoon"), NEEDS_TRANS (
"Clarinet"),
1074 NEEDS_TRANS (
"Piccolo"), NEEDS_TRANS (
"Flute"), NEEDS_TRANS (
"Recorder"), NEEDS_TRANS (
"Pan Flute"),
1075 NEEDS_TRANS (
"Blown Bottle"), NEEDS_TRANS (
"Shakuhachi"), NEEDS_TRANS (
"Whistle"), NEEDS_TRANS (
"Ocarina"),
1076 NEEDS_TRANS (
"Lead 1 (square)"), NEEDS_TRANS (
"Lead 2 (sawtooth)"), NEEDS_TRANS (
"Lead 3 (calliope)"), NEEDS_TRANS (
"Lead 4 (chiff)"),
1077 NEEDS_TRANS (
"Lead 5 (charang)"), NEEDS_TRANS (
"Lead 6 (voice)"), NEEDS_TRANS (
"Lead 7 (fifths)"), NEEDS_TRANS (
"Lead 8 (bass+lead)"),
1078 NEEDS_TRANS (
"Pad 1 (new age)"), NEEDS_TRANS (
"Pad 2 (warm)"), NEEDS_TRANS (
"Pad 3 (polysynth)"), NEEDS_TRANS (
"Pad 4 (choir)"),
1079 NEEDS_TRANS (
"Pad 5 (bowed)"), NEEDS_TRANS (
"Pad 6 (metallic)"), NEEDS_TRANS (
"Pad 7 (halo)"), NEEDS_TRANS (
"Pad 8 (sweep)"),
1080 NEEDS_TRANS (
"FX 1 (rain)"), NEEDS_TRANS (
"FX 2 (soundtrack)"), NEEDS_TRANS (
"FX 3 (crystal)"), NEEDS_TRANS (
"FX 4 (atmosphere)"),
1081 NEEDS_TRANS (
"FX 5 (brightness)"), NEEDS_TRANS (
"FX 6 (goblins)"), NEEDS_TRANS (
"FX 7 (echoes)"), NEEDS_TRANS (
"FX 8 (sci-fi)"),
1082 NEEDS_TRANS (
"Sitar"), NEEDS_TRANS (
"Banjo"), NEEDS_TRANS (
"Shamisen"), NEEDS_TRANS (
"Koto"),
1083 NEEDS_TRANS (
"Kalimba"), NEEDS_TRANS (
"Bag pipe"), NEEDS_TRANS (
"Fiddle"), NEEDS_TRANS (
"Shanai"),
1084 NEEDS_TRANS (
"Tinkle Bell"), NEEDS_TRANS (
"Agogo"), NEEDS_TRANS (
"Steel Drums"), NEEDS_TRANS (
"Woodblock"),
1085 NEEDS_TRANS (
"Taiko Drum"), NEEDS_TRANS (
"Melodic Tom"), NEEDS_TRANS (
"Synth Drum"), NEEDS_TRANS (
"Reverse Cymbal"),
1086 NEEDS_TRANS (
"Guitar Fret Noise"), NEEDS_TRANS (
"Breath Noise"), NEEDS_TRANS (
"Seashore"), NEEDS_TRANS (
"Bird Tweet"),
1087 NEEDS_TRANS (
"Telephone Ring"), NEEDS_TRANS (
"Helicopter"), NEEDS_TRANS (
"Applause"), NEEDS_TRANS (
"Gunshot")
1090 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] :
nullptr;
1095 static const char* names[] =
1097 NEEDS_TRANS (
"Piano"), NEEDS_TRANS (
"Chromatic Percussion"), NEEDS_TRANS (
"Organ"), NEEDS_TRANS (
"Guitar"),
1098 NEEDS_TRANS (
"Bass"), NEEDS_TRANS (
"Strings"), NEEDS_TRANS (
"Ensemble"), NEEDS_TRANS (
"Brass"),
1099 NEEDS_TRANS (
"Reed"), NEEDS_TRANS (
"Pipe"), NEEDS_TRANS (
"Synth Lead"), NEEDS_TRANS (
"Synth Pad"),
1100 NEEDS_TRANS (
"Synth Effects"), NEEDS_TRANS (
"Ethnic"), NEEDS_TRANS (
"Percussive"), NEEDS_TRANS (
"Sound Effects")
1103 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] :
nullptr;
1108 static const char* names[] =
1110 NEEDS_TRANS (
"Acoustic Bass Drum"), NEEDS_TRANS (
"Bass Drum 1"), NEEDS_TRANS (
"Side Stick"), NEEDS_TRANS (
"Acoustic Snare"),
1111 NEEDS_TRANS (
"Hand Clap"), NEEDS_TRANS (
"Electric Snare"), NEEDS_TRANS (
"Low Floor Tom"), NEEDS_TRANS (
"Closed Hi-Hat"),
1112 NEEDS_TRANS (
"High Floor Tom"), NEEDS_TRANS (
"Pedal Hi-Hat"), NEEDS_TRANS (
"Low Tom"), NEEDS_TRANS (
"Open Hi-Hat"),
1113 NEEDS_TRANS (
"Low-Mid Tom"), NEEDS_TRANS (
"Hi-Mid Tom"), NEEDS_TRANS (
"Crash Cymbal 1"), NEEDS_TRANS (
"High Tom"),
1114 NEEDS_TRANS (
"Ride Cymbal 1"), NEEDS_TRANS (
"Chinese Cymbal"), NEEDS_TRANS (
"Ride Bell"), NEEDS_TRANS (
"Tambourine"),
1115 NEEDS_TRANS (
"Splash Cymbal"), NEEDS_TRANS (
"Cowbell"), NEEDS_TRANS (
"Crash Cymbal 2"), NEEDS_TRANS (
"Vibraslap"),
1116 NEEDS_TRANS (
"Ride Cymbal 2"), NEEDS_TRANS (
"Hi Bongo"), NEEDS_TRANS (
"Low Bongo"), NEEDS_TRANS (
"Mute Hi Conga"),
1117 NEEDS_TRANS (
"Open Hi Conga"), NEEDS_TRANS (
"Low Conga"), NEEDS_TRANS (
"High Timbale"), NEEDS_TRANS (
"Low Timbale"),
1118 NEEDS_TRANS (
"High Agogo"), NEEDS_TRANS (
"Low Agogo"), NEEDS_TRANS (
"Cabasa"), NEEDS_TRANS (
"Maracas"),
1119 NEEDS_TRANS (
"Short Whistle"), NEEDS_TRANS (
"Long Whistle"), NEEDS_TRANS (
"Short Guiro"), NEEDS_TRANS (
"Long Guiro"),
1120 NEEDS_TRANS (
"Claves"), NEEDS_TRANS (
"Hi Wood Block"), NEEDS_TRANS (
"Low Wood Block"), NEEDS_TRANS (
"Mute Cuica"),
1121 NEEDS_TRANS (
"Open Cuica"), NEEDS_TRANS (
"Mute Triangle"), NEEDS_TRANS (
"Open Triangle")
1124 return (n >= 35 && n <= 81) ? names[n - 35] :
nullptr;
1129 static const char* names[] =
1131 NEEDS_TRANS (
"Bank Select"), NEEDS_TRANS (
"Modulation Wheel (coarse)"), NEEDS_TRANS (
"Breath controller (coarse)"),
1133 NEEDS_TRANS (
"Foot Pedal (coarse)"), NEEDS_TRANS (
"Portamento Time (coarse)"), NEEDS_TRANS (
"Data Entry (coarse)"),
1134 NEEDS_TRANS (
"Volume (coarse)"), NEEDS_TRANS (
"Balance (coarse)"),
1136 NEEDS_TRANS (
"Pan position (coarse)"), NEEDS_TRANS (
"Expression (coarse)"), NEEDS_TRANS (
"Effect Control 1 (coarse)"),
1137 NEEDS_TRANS (
"Effect Control 2 (coarse)"),
1139 NEEDS_TRANS (
"General Purpose Slider 1"), NEEDS_TRANS (
"General Purpose Slider 2"),
1140 NEEDS_TRANS (
"General Purpose Slider 3"), NEEDS_TRANS (
"General Purpose Slider 4"),
1141 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1142 NEEDS_TRANS (
"Bank Select (fine)"), NEEDS_TRANS (
"Modulation Wheel (fine)"), NEEDS_TRANS (
"Breath controller (fine)"),
1144 NEEDS_TRANS (
"Foot Pedal (fine)"), NEEDS_TRANS (
"Portamento Time (fine)"), NEEDS_TRANS (
"Data Entry (fine)"), NEEDS_TRANS (
"Volume (fine)"),
1145 NEEDS_TRANS (
"Balance (fine)"),
nullptr, NEEDS_TRANS (
"Pan position (fine)"), NEEDS_TRANS (
"Expression (fine)"),
1146 NEEDS_TRANS (
"Effect Control 1 (fine)"), NEEDS_TRANS (
"Effect Control 2 (fine)"),
1147 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1148 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1149 NEEDS_TRANS (
"Hold Pedal (on/off)"), NEEDS_TRANS (
"Portamento (on/off)"), NEEDS_TRANS (
"Sustenuto Pedal (on/off)"), NEEDS_TRANS (
"Soft Pedal (on/off)"),
1150 NEEDS_TRANS (
"Legato Pedal (on/off)"), NEEDS_TRANS (
"Hold 2 Pedal (on/off)"), NEEDS_TRANS (
"Sound Variation"), NEEDS_TRANS (
"Sound Timbre"),
1151 NEEDS_TRANS (
"Sound Release Time"), NEEDS_TRANS (
"Sound Attack Time"), NEEDS_TRANS (
"Sound Brightness"), NEEDS_TRANS (
"Sound Control 6"),
1152 NEEDS_TRANS (
"Sound Control 7"), NEEDS_TRANS (
"Sound Control 8"), NEEDS_TRANS (
"Sound Control 9"), NEEDS_TRANS (
"Sound Control 10"),
1153 NEEDS_TRANS (
"General Purpose Button 1 (on/off)"), NEEDS_TRANS (
"General Purpose Button 2 (on/off)"),
1154 NEEDS_TRANS (
"General Purpose Button 3 (on/off)"), NEEDS_TRANS (
"General Purpose Button 4 (on/off)"),
1155 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1156 NEEDS_TRANS (
"Reverb Level"), NEEDS_TRANS (
"Tremolo Level"), NEEDS_TRANS (
"Chorus Level"), NEEDS_TRANS (
"Celeste Level"),
1157 NEEDS_TRANS (
"Phaser Level"), NEEDS_TRANS (
"Data Button increment"), NEEDS_TRANS (
"Data Button decrement"), NEEDS_TRANS (
"Non-registered Parameter (fine)"),
1158 NEEDS_TRANS (
"Non-registered Parameter (coarse)"), NEEDS_TRANS (
"Registered Parameter (fine)"), NEEDS_TRANS (
"Registered Parameter (coarse)"),
1159 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1160 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
1161 NEEDS_TRANS (
"All Sound Off"), NEEDS_TRANS (
"All Controllers Off"), NEEDS_TRANS (
"Local Keyboard (on/off)"), NEEDS_TRANS (
"All Notes Off"),
1162 NEEDS_TRANS (
"Omni Mode Off"), NEEDS_TRANS (
"Omni Mode On"), NEEDS_TRANS (
"Mono Operation"), NEEDS_TRANS (
"Poly Operation")
1165 return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] :
nullptr;
1172struct MidiMessageTest final :
public UnitTest
1175 :
UnitTest (
"MidiMessage", UnitTestCategories::midi)
1178 void runTest()
override
1183 beginTest (
"ReadVariableLengthValue should return valid, backward-compatible results");
1185 const std::vector<uint8> inputs[]
1193 { 0x81, 0x80, 0x00 },
1194 { 0xc0, 0x80, 0x00 },
1195 { 0xff, 0xff, 0x7f },
1196 { 0x81, 0x80, 0x80, 0x00 },
1197 { 0xc0, 0x80, 0x80, 0x00 },
1198 { 0xff, 0xff, 0xff, 0x7f }
1217 expectEquals (std::distance (begin (inputs), end (inputs)),
1218 std::distance (begin (outputs), end (outputs)));
1222 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
1223 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1225 for (const auto& input : inputs)
1229 while (copy.size() < 16)
1232 const auto result = MidiMessage::readVariableLengthValue (copy.data(),
1235 expect (result.isValid());
1236 expectEquals (result.value, outputs[index]);
1237 expectEquals (result.bytesUsed, (
int) inputs[index].size());
1239 int legacyNumUsed = 0;
1240 const auto legacyResult = MidiMessage::readVariableLengthVal (copy.data(),
1243 expectEquals (result.value, legacyResult);
1244 expectEquals (result.bytesUsed, legacyNumUsed);
1249 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1250 JUCE_END_IGNORE_WARNINGS_MSVC
1253 beginTest (
"ReadVariableLengthVal should return 0 if input is truncated");
1255 for (
size_t i = 0; i != 16; ++i)
1257 std::vector<uint8> input;
1258 input.resize (i, 0xFF);
1260 const auto result = MidiMessage::readVariableLengthValue (input.data(),
1261 (
int) input.size());
1263 expect (! result.isValid());
1264 expectEquals (result.value, 0);
1265 expectEquals (result.bytesUsed, 0);
1269 const std::vector<uint8> metaEvents[]
1273 { 0xff, 0x00, 0x02, 0x00, 0x00 },
1274 { 0xff, 0x01, 0x00 },
1275 { 0xff, 0x02, 0x00 },
1276 { 0xff, 0x03, 0x00 },
1277 { 0xff, 0x04, 0x00 },
1278 { 0xff, 0x05, 0x00 },
1279 { 0xff, 0x06, 0x00 },
1280 { 0xff, 0x07, 0x00 },
1281 { 0xff, 0x20, 0x01, 0x00 },
1282 { 0xff, 0x2f, 0x00 },
1283 { 0xff, 0x51, 0x03, 0x01, 0x02, 0x03 },
1284 { 0xff, 0x54, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05 },
1285 { 0xff, 0x58, 0x04, 0x01, 0x02, 0x03, 0x04 },
1286 { 0xff, 0x59, 0x02, 0x01, 0x02 },
1287 { 0xff, 0x7f, 0x00 },
1290 beginTest (
"MidiMessage data constructor works for well-formed meta-events");
1292 const auto status = (uint8) 0x90;
1294 for (
const auto& input : metaEvents)
1297 const MidiMessage msg (input.data(), (
int) input.size(), bytesUsed, status);
1299 expect (msg.isMetaEvent());
1300 expectEquals (msg.getMetaEventLength(), (
int) input.size() - 3);
1301 expectEquals (msg.getMetaEventType(), (
int) input[1]);
1305 beginTest (
"MidiMessage data constructor works for malformed meta-events");
1307 const auto status = (uint8) 0x90;
1309 const auto runTest = [&] (
const std::vector<uint8>& input)
1312 const MidiMessage msg (input.data(), (
int) input.size(), bytesUsed, status);
1314 expect (msg.isMetaEvent());
1315 expectEquals (msg.getMetaEventLength(), jmax (0, (
int) input.size() - 3));
1316 expectEquals (msg.getMetaEventType(), input.size() >= 2 ? input[1] : -1);
1321 for (
const auto& input : metaEvents)
1332static MidiMessageTest midiMessageTests;
bool isTrackMetaEvent() const noexcept
static MidiMessage createSysExMessage(const void *sysexData, int dataSize)
static MidiMessage tempoMetaEvent(int microsecondsPerQuarterNote) noexcept
static MidiMessage midiStart() noexcept
const uint8 * getSysExData() const noexcept
String getDescription() const
static const char * getGMInstrumentBankName(int midiBankNumber)
bool isAftertouch() const noexcept
void setNoteNumber(int newNoteNumber) noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
int getKeySignatureNumberOfSharpsOrFlats() const noexcept
int getSongPositionPointerMidiBeat() const noexcept
void multiplyVelocity(float scaleFactor) noexcept
void getFullFrameParameters(int &hours, int &minutes, int &seconds, int &frames, SmpteTimecodeType &timecodeType) const noexcept
float getFloatVelocity() const noexcept
bool isMidiMachineControlMessage() const noexcept
int getChannel() const noexcept
static bool isMidiNoteBlack(int noteNumber) noexcept
static MidiMessage aftertouchChange(int channel, int noteNumber, int aftertouchAmount) noexcept
static int readVariableLengthVal(const uint8 *data, int &numBytesUsed) noexcept
int getQuarterFrameSequenceNumber() const noexcept
int getSysExDataSize() const noexcept
bool isQuarterFrame() const noexcept
const uint8 * getRawData() const noexcept
bool isTextMetaEvent() const noexcept
void setVelocity(float newVelocity) noexcept
int getMetaEventType() const noexcept
bool isProgramChange() const noexcept
bool isController() const noexcept
void getTimeSignatureInfo(int &numerator, int &denominator) const noexcept
bool isAllSoundOff() const noexcept
bool isSoftPedalOn() const noexcept
int getControllerNumber() const noexcept
bool isMidiStart() const noexcept
static double getMidiNoteInHertz(int noteNumber, double frequencyOfA=440.0) noexcept
int getQuarterFrameValue() const noexcept
bool isTrackNameEvent() const noexcept
int getChannelPressureValue() const noexcept
static MidiMessage pitchWheel(int channel, int position) noexcept
bool isForChannel(int channelNumber) const noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
const uint8 * getMetaEventData() const noexcept
bool isKeySignatureMetaEvent() const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
static MidiMessage quarterFrame(int sequenceNumber, int value) noexcept
bool isPitchWheel() const noexcept
bool isSustainPedalOn() const noexcept
bool isMidiContinue() const noexcept
static MidiMessage midiStop() noexcept
static MidiMessage timeSignatureMetaEvent(int numerator, int denominator)
bool isSostenutoPedalOn() const noexcept
static uint16 pitchbendToPitchwheelPos(float pitchbendInSemitones, float pitchbendRangeInSemitones) noexcept
int getNoteNumber() const noexcept
static MidiMessage midiChannelMetaEvent(int channel) noexcept
int getProgramChangeNumber() const noexcept
static const char * getGMInstrumentName(int midiInstrumentNumber)
bool isSostenutoPedalOff() const noexcept
int getMidiChannelMetaEventChannel() const noexcept
MidiMachineControlCommand
bool isTimeSignatureMetaEvent() const noexcept
static MidiMessage allNotesOff(int channel) noexcept
static MidiMessage controllerEvent(int channel, int controllerType, int value) noexcept
bool isControllerOfType(int controllerType) const noexcept
bool isTempoMetaEvent() const noexcept
static uint8 floatValueToMidiByte(float valueBetween0and1) noexcept
static MidiMessage keySignatureMetaEvent(int numberOfSharpsOrFlats, bool isMinorKey)
static MidiMessage midiClock() noexcept
bool isResetAllControllers() const noexcept
static MidiMessage fullFrame(int hours, int minutes, int seconds, int frames, SmpteTimecodeType timecodeType)
bool isSoftPedalOff() const noexcept
int getMetaEventLength() const noexcept
bool isMidiStop() const noexcept
MidiMessage & operator=(const MidiMessage &other)
bool isActiveSense() const noexcept
double getTempoSecondsPerQuarterNote() const noexcept
static MidiMessage masterVolume(float volume)
int getAfterTouchValue() const noexcept
static MidiMessage textMetaEvent(int type, StringRef text)
static MidiMessage channelPressureChange(int channel, int pressure) noexcept
bool isFullFrame() const noexcept
double getTempoMetaEventTickLength(short timeFormat) const noexcept
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
bool isEndOfTrackMetaEvent() const noexcept
bool isNoteOnOrOff() const noexcept
static MidiMessage midiContinue() noexcept
int getControllerValue() const noexcept
static String getMidiNoteName(int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
static MidiMessage midiMachineControlGoto(int hours, int minutes, int seconds, int frames)
bool isAllNotesOff() const noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
bool isMidiMachineControlGoto(int &hours, int &minutes, int &seconds, int &frames) const noexcept
bool isKeySignatureMajorKey() const noexcept
bool isMidiChannelMetaEvent() const noexcept
MidiMachineControlCommand getMidiMachineControlCommand() const noexcept
bool isMetaEvent() const noexcept
uint8 getVelocity() const noexcept
static const char * getRhythmInstrumentName(int midiNoteNumber)
static MidiMessage programChange(int channel, int programNumber) noexcept
bool isChannelPressure() const noexcept
bool isSysEx() const noexcept
static MidiMessage songPositionPointer(int positionInMidiBeats) noexcept
static MidiMessage endOfTrack() noexcept
bool isMidiClock() const noexcept
String getTextFromTextMetaEvent() const
static MidiMessage midiMachineControlCommand(MidiMachineControlCommand command)
static MidiMessage allSoundOff(int channel) noexcept
static VariableLengthValue readVariableLengthValue(const uint8 *data, int maxBytesToUse) noexcept
void setChannel(int newChannelNumber) noexcept
static const char * getControllerName(int controllerNumber)
bool isSongPositionPointer() const noexcept
bool isSustainPedalOff() const noexcept
int getRawDataSize() const noexcept
static MidiMessage allControllersOff(int channel) noexcept
MidiMessage withTimeStamp(double newTimestamp) const
int getPitchWheelValue() const noexcept
String::CharPointerType text
bool isEmpty() const noexcept
static String toHexString(IntegerType number)