23namespace juce::universal_midi_packets
26constexpr uint8_t
operator""_u8 (
unsigned long long int i) {
return static_cast<uint8_t
> (i); }
27constexpr uint16_t
operator""_u16 (
unsigned long long int i) {
return static_cast<uint16_t
> (i); }
28constexpr uint32_t
operator""_u32 (
unsigned long long int i) {
return static_cast<uint32_t
> (i); }
29constexpr uint64_t
operator""_u64 (
unsigned long long int i) {
return static_cast<uint64_t
> (i); }
31class UniversalMidiPacketTests final :
public UnitTest
34 UniversalMidiPacketTests()
35 :
UnitTest (
"Universal MIDI Packet", UnitTestCategories::midi)
39 void runTest()
override
43 beginTest (
"Short bytestream midi messages can be round-tripped through the UMP converter");
45 Midi1ToBytestreamTranslator translator (0);
47 forEachNonSysExTestMessage (random, [&] (
const MidiMessage& m)
49 const auto packets = toMidi1 (m);
50 expect (packets.size() == 1);
53 const auto msgType = Utils::getMessageType (packets.data()[0]);
54 expect (msgType == ((m.getRawData()[0] >> 0x4) == 0xf ? 0x1 : 0x2));
56 translator.dispatch (View {packets.data() },
58 [&] (
const BytestreamMidiView& roundTripped)
60 expect (equal (m, roundTripped.getMessage()));
65 beginTest (
"Bytestream SysEx converts to universal packets");
69 const auto packets = toMidi1 (createRandomSysEx (random, 0));
70 expect (packets.size() == 2);
72 expect (packets.data()[0] == 0x30000000);
73 expect (packets.data()[1] == 0x00000000);
77 const auto message = createRandomSysEx (random, 1);
78 const auto packets = toMidi1 (message);
79 expect (packets.size() == 2);
81 const auto* sysEx = message.getSysExData();
84 std::byte { sysEx[0] },
86 expect (packets.data()[1] == 0x00000000);
90 const auto message = createRandomSysEx (random, 6);
91 const auto packets = toMidi1 (message);
92 expect (packets.size() == 2);
94 const auto* sysEx = message.getSysExData();
95 expect (packets.data()[0] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x06 }, std::byte { sysEx[0] }, std::byte { sysEx[1] }));
96 expect (packets.data()[1] ==
Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] }));
100 const auto message = createRandomSysEx (random, 12);
101 const auto packets = toMidi1 (message);
102 expect (packets.size() == 4);
104 const auto* sysEx = message.getSysExData();
105 expect (packets.data()[0] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x16 }, std::byte { sysEx[0] }, std::byte { sysEx[1] }));
106 expect (packets.data()[1] ==
Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] }));
107 expect (packets.data()[2] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x36 }, std::byte { sysEx[6] }, std::byte { sysEx[7] }));
108 expect (packets.data()[3] ==
Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] }));
112 const auto message = createRandomSysEx (random, 13);
113 const auto packets = toMidi1 (message);
114 expect (packets.size() == 6);
116 const auto* sysEx = message.getSysExData();
117 expect (packets.data()[0] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x16 }, std::byte { sysEx[0] }, std::byte { sysEx[1] }));
118 expect (packets.data()[1] ==
Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] }));
119 expect (packets.data()[2] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x26 }, std::byte { sysEx[6] }, std::byte { sysEx[7] }));
120 expect (packets.data()[3] ==
Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] }));
121 expect (packets.data()[4] ==
Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x31 }, std::byte { sysEx[12] }, std::byte { 0 }));
122 expect (packets.data()[5] == 0x00000000);
126 ToBytestreamDispatcher converter (0);
129 const auto checkRoundTrip = [&] (
const MidiBuffer& expected)
131 for (
const auto meta : expected)
132 Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto p) { packets.add (p); });
135 converter.dispatch (packets.data(),
136 packets.data() + packets.size(),
138 [&] (
const BytestreamMidiView& roundTripped)
140 output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
144 expect (equal (expected, output));
147 beginTest (
"Long SysEx bytestream midi messages can be round-tripped through the UMP converter");
149 for (
auto length : { 0, 1, 2, 3, 4, 5, 6, 7, 13, 20, 100, 1000 })
152 expected.addEvent (createRandomSysEx (random,
size_t (length)), 0);
153 checkRoundTrip (expected);
157 beginTest (
"UMP SysEx7 messages interspersed with utility messages convert to bytestream");
159 const auto sysEx = createRandomSysEx (random, 100);
160 const auto originalPackets = toMidi1 (sysEx);
162 Packets modifiedPackets;
164 const auto addRandomUtilityUMP = [&]
166 const auto newPacket = createRandomUtilityUMP (random);
167 modifiedPackets.add (View (newPacket.data()));
170 for (
const auto& packet : originalPackets)
172 addRandomUtilityUMP();
173 modifiedPackets.add (packet);
174 addRandomUtilityUMP();
178 converter.dispatch (modifiedPackets.data(),
179 modifiedPackets.data() + modifiedPackets.size(),
181 [&] (
const BytestreamMidiView& roundTripped)
183 output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
187 expect (output.getNumEvents() == 1);
189 for (
const auto meta : output)
190 expect (equal (meta.getMessage(), sysEx));
193 beginTest (
"UMP SysEx7 messages interspersed with System Realtime messages convert to bytestream");
195 const auto sysEx = createRandomSysEx (random, 200);
196 const auto originalPackets = toMidi1 (sysEx);
198 Packets modifiedPackets;
199 MidiBuffer realtimeMessages;
201 const auto addRandomRealtimeUMP = [&]
203 const auto newPacket = createRandomRealtimeUMP (random);
204 modifiedPackets.add (View (newPacket.data()));
208 for (
const auto& packet : originalPackets)
210 addRandomRealtimeUMP();
211 modifiedPackets.add (packet);
212 addRandomRealtimeUMP();
216 converter.dispatch (modifiedPackets.data(),
217 modifiedPackets.data() + modifiedPackets.size(),
219 [&] (
const BytestreamMidiView& roundTripped)
221 output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
224 const auto numOutputs = output.getNumEvents();
225 const auto numInputs = realtimeMessages.getNumEvents();
226 expect (numOutputs == numInputs + 1);
228 if (numOutputs == numInputs + 1)
230 const auto isMetadataEquivalent = [] (
const MidiMessageMetadata& a,
231 const MidiMessageMetadata& b)
233 return equal (a.getMessage(), b.getMessage());
236 auto it = output.begin();
238 for (
const auto meta : realtimeMessages)
240 if (! isMetadataEquivalent (*it, meta))
242 expect (equal ((*it).getMessage(), sysEx));
246 expect (isMetadataEquivalent (*it, meta));
252 beginTest (
"UMP SysEx7 messages interspersed with System Realtime and Utility messages convert to bytestream");
254 const auto sysEx = createRandomSysEx (random, 300);
255 const auto originalPackets = toMidi1 (sysEx);
257 Packets modifiedPackets;
258 MidiBuffer realtimeMessages;
260 const auto addRandomRealtimeUMP = [&]
262 const auto newPacket = createRandomRealtimeUMP (random);
263 modifiedPackets.add (View (newPacket.data()));
267 const auto addRandomUtilityUMP = [&]
269 const auto newPacket = createRandomUtilityUMP (random);
270 modifiedPackets.add (View (newPacket.data()));
273 for (
const auto& packet : originalPackets)
275 addRandomRealtimeUMP();
276 addRandomUtilityUMP();
277 modifiedPackets.add (packet);
278 addRandomRealtimeUMP();
279 addRandomUtilityUMP();
283 converter.dispatch (modifiedPackets.data(),
284 modifiedPackets.data() + modifiedPackets.size(),
286 [&] (
const BytestreamMidiView& roundTripped)
288 output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
291 const auto numOutputs = output.getNumEvents();
292 const auto numInputs = realtimeMessages.getNumEvents();
293 expect (numOutputs == numInputs + 1);
295 if (numOutputs == numInputs + 1)
297 const auto isMetadataEquivalent = [] (
const MidiMessageMetadata& a,
const MidiMessageMetadata& b)
299 return equal (a.getMessage(), b.getMessage());
302 auto it = output.begin();
304 for (
const auto meta : realtimeMessages)
306 if (! isMetadataEquivalent (*it, meta))
308 expect (equal ((*it).getMessage(), sysEx));
312 expect (isMetadataEquivalent (*it, meta));
318 beginTest (
"SysEx messages are terminated by non-Utility, non-Realtime messages");
320 const auto noteOn = [&]
327 const auto noteOnPackets = [&]
331 for (
const auto meta : noteOn)
332 Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto packet) { p.add (packet); });
337 const auto sysEx = createRandomSysEx (random, 300);
339 const auto originalPackets = toMidi1 (sysEx);
341 const auto modifiedPackets = [&]
345 const auto insertionPoint = std::next (originalPackets.begin(), 10);
346 std::for_each (originalPackets.begin(),
348 [&] (
const View& view) { p.add (view); });
350 for (
const auto& view : noteOnPackets)
353 std::for_each (insertionPoint,
354 originalPackets.end(),
355 [&] (
const View& view) { p.add (view); });
364 const auto pushToOutput = [&] (
const Packets& p)
366 converter.dispatch (p.data(),
369 [&] (
const BytestreamMidiView& roundTripped)
371 output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
375 pushToOutput (modifiedPackets);
378 expect (equal (output, noteOn));
380 const auto newSysEx = createRandomSysEx (random, 300);
381 const auto newSysExPackets = toMidi1 (newSysEx);
388 pushToOutput (newSysExPackets);
390 expect (output.getNumEvents() == 1);
392 for (
const auto meta : output)
393 expect (equal (meta.getMessage(), newSysEx));
399 const auto baselineScale = [] (uint32_t srcVal, uint32_t srcBits, uint32_t dstBits)
401 const auto scaleBits = (uint32_t) (dstBits - srcBits);
403 auto bitShiftedValue = (uint32_t) (srcVal << scaleBits);
405 const auto srcCenter = (uint32_t) (1 << (srcBits - 1));
407 if (srcVal <= srcCenter)
408 return bitShiftedValue;
410 const auto repeatBits = (uint32_t) (srcBits - 1);
411 const auto repeatMask = (uint32_t) ((1 << repeatBits) - 1);
413 auto repeatValue = (uint32_t) (srcVal & repeatMask);
415 if (scaleBits > repeatBits)
416 repeatValue <<= scaleBits - repeatBits;
418 repeatValue >>= repeatBits - scaleBits;
420 while (repeatValue != 0)
422 bitShiftedValue |= repeatValue;
423 repeatValue >>= repeatBits;
426 return bitShiftedValue;
429 const auto baselineScale7To8 = [&] (uint8_t in)
431 return baselineScale (in, 7, 8);
434 const auto baselineScale7To16 = [&] (uint8_t in)
436 return baselineScale (in, 7, 16);
439 const auto baselineScale14To16 = [&] (uint16_t in)
441 return baselineScale (in, 14, 16);
444 const auto baselineScale7To32 = [&] (uint8_t in)
446 return baselineScale (in, 7, 32);
449 const auto baselineScale14To32 = [&] (uint16_t in)
451 return baselineScale (in, 14, 32);
454 for (
auto i = 0; i != 100; ++i)
456 const auto rand = (uint8_t) random.nextInt (0x80);
458 (int64_t) baselineScale7To8 (rand));
467 for (
auto i = 0; i != 100; ++i)
469 const auto rand = (uint8_t) random.nextInt (0x80);
471 (int64_t) baselineScale7To16 (rand));
474 for (
auto i = 0; i != 100; ++i)
476 const auto rand = (uint16_t) random.nextInt (0x4000);
478 (int64_t) baselineScale14To16 (rand));
481 for (
auto i = 0; i != 100; ++i)
483 const auto rand = (uint8_t) random.nextInt (0x80);
485 (int64_t) baselineScale7To32 (rand));
492 for (
auto i = 0; i != 100; ++i)
494 const auto rand = (uint16_t) random.nextInt (0x4000);
496 (int64_t) baselineScale14To32 (rand));
500 beginTest (
"Round-trip widening/narrowing conversions work");
502 for (
auto i = 0; i != 100; ++i)
505 const auto rand = (uint8_t) random.nextInt (0x80);
510 const auto rand = (uint8_t) random.nextInt (0x80);
515 const auto rand = (uint8_t) random.nextInt (0x80);
520 const auto rand = (uint16_t) random.nextInt (0x4000);
525 const auto rand = (uint16_t) random.nextInt (0x4000);
531 beginTest (
"MIDI 2 -> 1 note on conversions");
535 midi2.add (PacketX2 { 0x41946410, 0x12345678 });
538 midi1.add (PacketX1 { 0x21946409 });
540 checkMidi2ToMidi1Conversion (midi2, midi1);
546 midi2.add (PacketX2 { 0x4295327f, 0x00345678 });
549 midi1.add (PacketX1 { 0x22953201 });
551 checkMidi2ToMidi1Conversion (midi2, midi1);
555 beginTest (
"MIDI 2 -> 1 note off conversion");
558 midi2.add (PacketX2 { 0x448b0520, 0xfedcba98 });
561 midi1.add (PacketX1 { 0x248b057f });
563 checkMidi2ToMidi1Conversion (midi2, midi1);
566 beginTest (
"MIDI 2 -> 1 poly pressure conversion");
569 midi2.add (PacketX2 { 0x49af0520, 0x80dcba98 });
572 midi1.add (PacketX1 { 0x29af0540 });
574 checkMidi2ToMidi1Conversion (midi2, midi1);
577 beginTest (
"MIDI 2 -> 1 control change conversion");
580 midi2.add (PacketX2 { 0x49b00520, 0x80dcba98 });
583 midi1.add (PacketX1 { 0x29b00540 });
585 checkMidi2ToMidi1Conversion (midi2, midi1);
588 beginTest (
"MIDI 2 -> 1 channel pressure conversion");
591 midi2.add (PacketX2 { 0x40d20520, 0x80dcba98 });
594 midi1.add (PacketX1 { 0x20d24000 });
596 checkMidi2ToMidi1Conversion (midi2, midi1);
599 beginTest (
"MIDI 2 -> 1 nrpn rpn conversion");
603 midi2.add (PacketX2 { 0x44240123, 0x456789ab });
606 midi1.add (PacketX1 { 0x24b46501 });
607 midi1.add (PacketX1 { 0x24b46423 });
608 midi1.add (PacketX1 { 0x24b40622 });
609 midi1.add (PacketX1 { 0x24b42659 });
611 checkMidi2ToMidi1Conversion (midi2, midi1);
616 midi2.add (PacketX2 { 0x48347f7f, 0xffffffff });
619 midi1.add (PacketX1 { 0x28b4637f });
620 midi1.add (PacketX1 { 0x28b4627f });
621 midi1.add (PacketX1 { 0x28b4067f });
622 midi1.add (PacketX1 { 0x28b4267f });
624 checkMidi2ToMidi1Conversion (midi2, midi1);
628 beginTest (
"MIDI 2 -> 1 program change and bank select conversion");
633 midi2.add (PacketX2 { 0x4cc10000, 0x70004020 });
636 midi1.add (PacketX1 { 0x2cc17000 });
638 checkMidi2ToMidi1Conversion (midi2, midi1);
644 midi2.add (PacketX2 { 0x4bc20001, 0x70004020 });
647 midi1.add (PacketX1 { 0x2bb20040 });
648 midi1.add (PacketX1 { 0x2bb22020 });
649 midi1.add (PacketX1 { 0x2bc27000 });
651 checkMidi2ToMidi1Conversion (midi2, midi1);
655 beginTest (
"MIDI 2 -> 1 pitch bend conversion");
658 midi2.add (PacketX2 { 0x4eee0000, 0x12340000 });
661 midi1.add (PacketX1 { 0x2eee0d09 });
663 checkMidi2ToMidi1Conversion (midi2, midi1);
666 beginTest (
"MIDI 2 -> 1 messages which don't convert");
668 const std::byte opcodes[] { std::byte { 0x0 },
675 for (
const auto opcode : opcodes)
678 midi2.add (PacketX2 {
Utils::bytesToWord (std::byte { 0x40 }, std::byte { opcode << 0x4 }, std::byte { 0 }, std::byte { 0 }), 0x0 });
679 checkMidi2ToMidi1Conversion (midi2, {});
683 beginTest (
"MIDI 2 -> 1 messages which are passed through");
685 const uint8_t typecodesX1[] { 0x0, 0x1, 0x2 };
687 for (
const auto typecode : typecodesX1)
690 p.add (PacketX1 { (uint32_t) ((int64_t) typecode << 0x1c | (random.nextInt64() & 0xffffff)) });
692 checkMidi2ToMidi1Conversion (p, p);
697 p.add (PacketX2 { (uint32_t) (0x3 << 0x1c | (random.nextInt64() & 0xffffff)),
698 (uint32_t) (random.nextInt64() & 0xffffffff) });
700 checkMidi2ToMidi1Conversion (p, p);
705 p.add (PacketX4 { (uint32_t) (0x5 << 0x1c | (random.nextInt64() & 0xffffff)),
706 (uint32_t) (random.nextInt64() & 0xffffffff),
707 (uint32_t) (random.nextInt64() & 0xffffffff),
708 (uint32_t) (random.nextInt64() & 0xffffffff) });
710 checkMidi2ToMidi1Conversion (p, p);
714 beginTest (
"MIDI 2 -> 1 control changes which should be ignored");
716 const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 };
718 for (
const auto cc : CCs)
721 midi2.add (PacketX2 { (uint32_t) (0x40b00000 | (cc << 0x8)), 0x00000000 });
723 checkMidi2ToMidi1Conversion (midi2, {});
727 beginTest (
"MIDI 1 -> 2 note on conversions");
731 midi1.add (PacketX1 { 0x20904040 });
734 midi2.add (PacketX2 { 0x40904000,
static_cast<uint32_t
> (
Conversion::scaleTo16 (0x40_u8)) << 0x10 });
736 checkMidi1ToMidi2Conversion (midi1, midi2);
742 midi1.add (PacketX1 { 0x23935100 });
745 midi2.add (PacketX2 { 0x43835100, 0x0 });
747 checkMidi1ToMidi2Conversion (midi1, midi2);
751 beginTest (
"MIDI 1 -> 2 note off conversions");
754 midi1.add (PacketX1 { 0x21831020 });
757 midi2.add (PacketX2 { 0x41831000,
static_cast<uint32_t
> (
Conversion::scaleTo16 (0x20_u8)) << 0x10 });
759 checkMidi1ToMidi2Conversion (midi1, midi2);
762 beginTest (
"MIDI 1 -> 2 poly pressure conversions");
765 midi1.add (PacketX1 { 0x20af7330 });
770 checkMidi1ToMidi2Conversion (midi1, midi2);
773 beginTest (
"individual MIDI 1 -> 2 control changes which should be ignored");
775 const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 };
777 for (
const auto cc : CCs)
780 midi1.add (PacketX1 {
Utils::bytesToWord (std::byte { 0x20 }, std::byte { 0xb0 }, std::byte { cc }, std::byte { 0x00 }) });
782 checkMidi1ToMidi2Conversion (midi1, {});
786 beginTest (
"MIDI 1 -> 2 control change conversions");
791 midi1.add (PacketX1 { 0x29b1017f });
796 checkMidi1ToMidi2Conversion (midi1, midi2);
802 midi1.add (PacketX1 { 0x20b06301 });
803 midi1.add (PacketX1 { 0x20b06223 });
804 midi1.add (PacketX1 { 0x20b00645 });
805 midi1.add (PacketX1 { 0x20b02667 });
808 midi2.add (PacketX2 { 0x40300123,
Conversion::scaleTo32 (
static_cast<uint16_t
> ((0x45 << 7) | 0x67)) });
810 checkMidi1ToMidi2Conversion (midi1, midi2);
816 midi1.add (PacketX1 { 0x20b06543 });
817 midi1.add (PacketX1 { 0x20b06421 });
818 midi1.add (PacketX1 { 0x20b00601 });
819 midi1.add (PacketX1 { 0x20b02623 });
822 midi2.add (PacketX2 { 0x40204321,
Conversion::scaleTo32 (
static_cast<uint16_t
> ((0x01 << 7) | 0x23)) });
824 checkMidi1ToMidi2Conversion (midi1, midi2);
828 beginTest (
"MIDI 1 -> MIDI 2 program change and bank select");
832 midi1.add (PacketX1 { 0x2bb20030 });
833 midi1.add (PacketX1 { 0x2bb22010 });
834 midi1.add (PacketX1 { 0x2bc24000 });
836 midi1.add (PacketX1 { 0x20c01000 });
839 midi2.add (PacketX2 { 0x4bc20001, 0x40003010 });
840 midi2.add (PacketX2 { 0x40c00000, 0x10000000 });
842 checkMidi1ToMidi2Conversion (midi1, midi2);
845 beginTest (
"MIDI 1 -> MIDI 2 channel pressure conversions");
848 midi1.add (PacketX1 { 0x20df3000 });
853 checkMidi1ToMidi2Conversion (midi1, midi2);
856 beginTest (
"MIDI 1 -> MIDI 2 pitch bend conversions");
859 midi1.add (PacketX1 { 0x20e74567 });
862 midi2.add (PacketX2 { 0x40e70000,
Conversion::scaleTo32 (
static_cast<uint16_t
> ((0x67 << 7) | 0x45)) });
864 checkMidi1ToMidi2Conversion (midi1, midi2);
869 static Packets toMidi1 (
const MidiMessage& msg)
872 Conversion::toMidi1 (ump::BytestreamMidiView (&msg), [&] (
const auto p) { packets.add (p); });
876 static Packets convertMidi2ToMidi1 (
const Packets& midi2)
880 for (
const auto& packet : midi2)
881 Conversion::midi2ToMidi1DefaultTranslation (packet, [&r] (const View& v) { r.add (v); });
886 static Packets convertMidi1ToMidi2 (
const Packets& midi1)
889 Midi1ToMidi2DefaultTranslator translator;
891 for (
const auto& packet : midi1)
892 translator.dispatch (packet, [&r] (const View& v) { r.add (v); });
897 void checkBytestreamConversion (
const Packets& actual,
const Packets& expected)
899 expectEquals ((
int) actual.size(), (
int) expected.size());
901 if (actual.size() != expected.size())
904 auto actualPtr = actual.data();
906 std::for_each (expected.data(),
907 expected.data() + expected.size(),
908 [&] (
const uint32_t word) { expectEquals ((uint64_t) *actualPtr++, (uint64_t) word); });
911 void checkMidi2ToMidi1Conversion (
const Packets& midi2,
const Packets& expected)
913 checkBytestreamConversion (convertMidi2ToMidi1 (midi2), expected);
916 void checkMidi1ToMidi2Conversion (
const Packets& midi1,
const Packets& expected)
918 checkBytestreamConversion (convertMidi1ToMidi2 (midi1), expected);
921 MidiMessage createRandomSysEx (Random& random,
size_t sysExBytes)
923 std::vector<uint8_t> data;
924 data.reserve (sysExBytes);
926 for (
size_t i = 0; i != sysExBytes; ++i)
927 data.push_back (uint8_t (random.nextInt (0x80)));
932 PacketX1 createRandomUtilityUMP (Random& random)
934 const auto status = random.nextInt (3);
937 std::byte (status << 0x4),
938 std::byte (status == 0 ? 0 : random.nextInt (0x100)),
939 std::byte (status == 0 ? 0 : random.nextInt (0x100))) };
942 PacketX1 createRandomRealtimeUMP (Random& random)
944 const auto status = [&]
946 switch (random.nextInt (6))
948 case 0:
return std::byte { 0xf8 };
949 case 1:
return std::byte { 0xfa };
950 case 2:
return std::byte { 0xfb };
951 case 3:
return std::byte { 0xfc };
952 case 4:
return std::byte { 0xfe };
953 case 5:
return std::byte { 0xff };
957 return std::byte { 0x00 };
960 return PacketX1 {
Utils::bytesToWord (std::byte { 0x10 }, status, std::byte { 0x00 }, std::byte { 0x00 }) };
963 template <
typename Fn>
964 void forEachNonSysExTestMessage (Random& random, Fn&& fn)
966 for (uint16_t counter = 0x80; counter != 0x100; ++counter)
968 const auto firstByte = (uint8_t) counter;
970 if (firstByte == 0xf0 || firstByte == 0xf7)
974 const auto getDataByte = [&] {
return uint8_t (random.nextInt (256) & 0x7f); };
976 const auto message = [&]
980 case 1:
return MidiMessage (firstByte);
981 case 2:
return MidiMessage (firstByte, getDataByte());
982 case 3:
return MidiMessage (firstByte, getDataByte(), getDataByte());
985 return MidiMessage();
992 static bool equal (
const MidiMessage& a,
const MidiMessage& b)
noexcept
994 return a.getRawDataSize() == b.getRawDataSize()
995 && std::equal (a.getRawData(), a.getRawData() + a.getRawDataSize(), b.getRawData());
998 static bool equal (
const MidiBuffer& a,
const MidiBuffer& b)
noexcept
1000 return a.data == b.data;
1004static UniversalMidiPacketTests universalMidiPacketTests;
static MidiMessage createSysExMessage(const void *sysexData, int dataSize)
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
void expectEquals(ValueType actual, ValueType expected, String failureMessage=String())
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
static MidiMessage fromUmp(const PacketX1 &m, double time=0)
static uint16_t scaleTo14(uint16_t word16Bit)
static uint32_t scaleTo32(uint8_t word7Bit)
static uint16_t scaleTo16(uint8_t word7Bit)
static void toMidi1(const BytestreamMidiView &m, PacketCallbackFunction &&callback)
static uint8_t scaleTo8(uint8_t word7Bit)
static uint8_t scaleTo7(uint8_t word8Bit)
static constexpr uint32_t bytesToWord(std::byte a, std::byte b, std::byte c, std::byte d)