| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - namespace universal_midi_packets
 - {
 - 
 - constexpr uint8_t  operator""_u8  (unsigned long long int i) { return static_cast<uint8_t>  (i); }
 - constexpr uint16_t operator""_u16 (unsigned long long int i) { return static_cast<uint16_t> (i); }
 - constexpr uint32_t operator""_u32 (unsigned long long int i) { return static_cast<uint32_t> (i); }
 - constexpr uint64_t operator""_u64 (unsigned long long int i) { return static_cast<uint64_t> (i); }
 - 
 - class UniversalMidiPacketTests : public UnitTest
 - {
 - public:
 -     UniversalMidiPacketTests()
 -         : UnitTest ("Universal MIDI Packet", UnitTestCategories::midi)
 -     {
 -     }
 - 
 -     void runTest() override
 -     {
 -         auto random = getRandom();
 - 
 -         beginTest ("Short bytestream midi messages can be round-tripped through the UMP converter");
 -         {
 -             Midi1ToBytestreamTranslator translator (0);
 - 
 -             forEachNonSysExTestMessage (random, [&] (const MidiMessage& m)
 -             {
 -                 const auto packets = toMidi1 (m);
 -                 expect (packets.size() == 1);
 - 
 -                 // Make sure that the message type is correct
 -                 const auto msgType = Utils::getMessageType (packets.data()[0]);
 -                 expect (msgType == ((m.getRawData()[0] >> 0x4) == 0xf ? 0x1 : 0x2));
 - 
 -                 translator.dispatch (View {packets.data() },
 -                                      0,
 -                                      [&] (const BytestreamMidiView& roundTripped)
 -                                      {
 -                                          expect (equal (m, roundTripped.getMessage()));
 -                                      });
 -             });
 -         }
 - 
 -         beginTest ("Bytestream SysEx converts to universal packets");
 -         {
 -             {
 -                 // Zero length message
 -                 const auto packets = toMidi1 (createRandomSysEx (random, 0));
 -                 expect (packets.size() == 2);
 - 
 -                 expect (packets.data()[0] == 0x30000000);
 -                 expect (packets.data()[1] == 0x00000000);
 -             }
 - 
 -             {
 -                 const auto message = createRandomSysEx (random, 1);
 -                 const auto packets = toMidi1 (message);
 -                 expect (packets.size() == 2);
 - 
 -                 const auto* sysEx = message.getSysExData();
 -                 expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 },
 -                                                                  std::byte { 0x01 },
 -                                                                  std::byte { sysEx[0] },
 -                                                                  std::byte { 0 }));
 -                 expect (packets.data()[1] == 0x00000000);
 -             }
 - 
 -             {
 -                 const auto message = createRandomSysEx (random, 6);
 -                 const auto packets = toMidi1 (message);
 -                 expect (packets.size() == 2);
 - 
 -                 const auto* sysEx = message.getSysExData();
 -                 expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x06 },     std::byte { sysEx[0] }, std::byte { sysEx[1] }));
 -                 expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] }));
 -             }
 - 
 -             {
 -                 const auto message = createRandomSysEx (random, 12);
 -                 const auto packets = toMidi1 (message);
 -                 expect (packets.size() == 4);
 - 
 -                 const auto* sysEx = message.getSysExData();
 -                 expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x16 },     std::byte { sysEx[0] },  std::byte { sysEx[1] }));
 -                 expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] },  std::byte { sysEx[5] }));
 -                 expect (packets.data()[2] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x36 },     std::byte { sysEx[6] },  std::byte { sysEx[7] }));
 -                 expect (packets.data()[3] == Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] }));
 -             }
 - 
 -             {
 -                 const auto message = createRandomSysEx (random, 13);
 -                 const auto packets = toMidi1 (message);
 -                 expect (packets.size() == 6);
 - 
 -                 const auto* sysEx = message.getSysExData();
 -                 expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x16 },     std::byte { sysEx[0] },  std::byte { sysEx[1] }));
 -                 expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] },  std::byte { sysEx[5] }));
 -                 expect (packets.data()[2] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x26 },     std::byte { sysEx[6] },  std::byte { sysEx[7] }));
 -                 expect (packets.data()[3] == Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] }));
 -                 expect (packets.data()[4] == Utils::bytesToWord (std::byte { 0x30 },     std::byte { 0x31 },     std::byte { sysEx[12] }, std::byte { 0 }));
 -                 expect (packets.data()[5] == 0x00000000);
 -             }
 -         }
 - 
 -         ToBytestreamDispatcher converter (0);
 -         Packets packets;
 - 
 -         const auto checkRoundTrip = [&] (const MidiBuffer& expected)
 -         {
 -             for (const auto meta : expected)
 -                 Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto p) { packets.add (p); });
 - 
 -             MidiBuffer output;
 -             converter.dispatch (packets.data(),
 -                                 packets.data() + packets.size(),
 -                                 0,
 -                                 [&] (const BytestreamMidiView& roundTripped)
 -                                 {
 -                                     output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
 -                                 });
 -             packets.clear();
 - 
 -             expect (equal (expected, output));
 -         };
 - 
 -         beginTest ("Long SysEx bytestream midi messages can be round-tripped through the UMP converter");
 -         {
 -             for (auto length : { 0, 1, 2, 3, 4, 5, 6, 7, 13, 20, 100, 1000 })
 -             {
 -                 MidiBuffer expected;
 -                 expected.addEvent (createRandomSysEx (random, size_t (length)), 0);
 -                 checkRoundTrip (expected);
 -             }
 -         }
 - 
 -         beginTest ("UMP SysEx7 messages interspersed with utility messages convert to bytestream");
 -         {
 -             const auto sysEx = createRandomSysEx (random, 100);
 -             const auto originalPackets = toMidi1 (sysEx);
 - 
 -             Packets modifiedPackets;
 - 
 -             const auto addRandomUtilityUMP = [&]
 -             {
 -                 const auto newPacket = createRandomUtilityUMP (random);
 -                 modifiedPackets.add (View (newPacket.data()));
 -             };
 - 
 -             for (const auto& packet : originalPackets)
 -             {
 -                 addRandomUtilityUMP();
 -                 modifiedPackets.add (packet);
 -                 addRandomUtilityUMP();
 -             }
 - 
 -             MidiBuffer output;
 -             converter.dispatch (modifiedPackets.data(),
 -                                 modifiedPackets.data() + modifiedPackets.size(),
 -                                 0,
 -                                 [&] (const BytestreamMidiView& roundTripped)
 -                                 {
 -                                     output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
 -                                 });
 - 
 -             // All Utility messages should have been ignored
 -             expect (output.getNumEvents() == 1);
 - 
 -             for (const auto meta : output)
 -                 expect (equal (meta.getMessage(), sysEx));
 -         }
 - 
 -         beginTest ("UMP SysEx7 messages interspersed with System Realtime messages convert to bytestream");
 -         {
 -             const auto sysEx = createRandomSysEx (random, 200);
 -             const auto originalPackets = toMidi1 (sysEx);
 - 
 -             Packets modifiedPackets;
 -             MidiBuffer realtimeMessages;
 - 
 -             const auto addRandomRealtimeUMP = [&]
 -             {
 -                 const auto newPacket = createRandomRealtimeUMP (random);
 -                 modifiedPackets.add (View (newPacket.data()));
 -                 realtimeMessages.addEvent (Midi1ToBytestreamTranslator::fromUmp (newPacket), 0);
 -             };
 - 
 -             for (const auto& packet : originalPackets)
 -             {
 -                 addRandomRealtimeUMP();
 -                 modifiedPackets.add (packet);
 -                 addRandomRealtimeUMP();
 -             }
 - 
 -             MidiBuffer output;
 -             converter.dispatch (modifiedPackets.data(),
 -                                 modifiedPackets.data() + modifiedPackets.size(),
 -                                 0,
 -                                 [&] (const BytestreamMidiView& roundTripped)
 -                                 {
 -                                     output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
 -                                 });
 - 
 -             const auto numOutputs = output.getNumEvents();
 -             const auto numInputs = realtimeMessages.getNumEvents();
 -             expect (numOutputs == numInputs + 1);
 - 
 -             if (numOutputs == numInputs + 1)
 -             {
 -                 const auto isMetadataEquivalent = [] (const MidiMessageMetadata& a,
 -                                                       const MidiMessageMetadata& b)
 -                 {
 -                     return equal (a.getMessage(), b.getMessage());
 -                 };
 - 
 -                 auto it = output.begin();
 - 
 -                 for (const auto meta : realtimeMessages)
 -                 {
 -                     if (! isMetadataEquivalent (*it, meta))
 -                     {
 -                         expect (equal ((*it).getMessage(), sysEx));
 -                         ++it;
 -                     }
 - 
 -                     expect (isMetadataEquivalent (*it, meta));
 -                     ++it;
 -                 }
 -             }
 -         }
 - 
 -         beginTest ("UMP SysEx7 messages interspersed with System Realtime and Utility messages convert to bytestream");
 -         {
 -             const auto sysEx = createRandomSysEx (random, 300);
 -             const auto originalPackets = toMidi1 (sysEx);
 - 
 -             Packets modifiedPackets;
 -             MidiBuffer realtimeMessages;
 - 
 -             const auto addRandomRealtimeUMP = [&]
 -             {
 -                 const auto newPacket = createRandomRealtimeUMP (random);
 -                 modifiedPackets.add (View (newPacket.data()));
 -                 realtimeMessages.addEvent (Midi1ToBytestreamTranslator::fromUmp (newPacket), 0);
 -             };
 - 
 -             const auto addRandomUtilityUMP = [&]
 -             {
 -                 const auto newPacket = createRandomUtilityUMP (random);
 -                 modifiedPackets.add (View (newPacket.data()));
 -             };
 - 
 -             for (const auto& packet : originalPackets)
 -             {
 -                 addRandomRealtimeUMP();
 -                 addRandomUtilityUMP();
 -                 modifiedPackets.add (packet);
 -                 addRandomRealtimeUMP();
 -                 addRandomUtilityUMP();
 -             }
 - 
 -             MidiBuffer output;
 -             converter.dispatch (modifiedPackets.data(),
 -                                 modifiedPackets.data() + modifiedPackets.size(),
 -                                 0,
 -                                 [&] (const BytestreamMidiView& roundTripped)
 -                                 {
 -                                     output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
 -                                 });
 - 
 -             const auto numOutputs = output.getNumEvents();
 -             const auto numInputs = realtimeMessages.getNumEvents();
 -             expect (numOutputs == numInputs + 1);
 - 
 -             if (numOutputs == numInputs + 1)
 -             {
 -                 const auto isMetadataEquivalent = [] (const MidiMessageMetadata& a, const MidiMessageMetadata& b)
 -                 {
 -                     return equal (a.getMessage(), b.getMessage());
 -                 };
 - 
 -                 auto it = output.begin();
 - 
 -                 for (const auto meta : realtimeMessages)
 -                 {
 -                     if (! isMetadataEquivalent (*it, meta))
 -                     {
 -                         expect (equal ((*it).getMessage(), sysEx));
 -                         ++it;
 -                     }
 - 
 -                     expect (isMetadataEquivalent (*it, meta));
 -                     ++it;
 -                 }
 -             }
 -         }
 - 
 -         beginTest ("SysEx messages are terminated by non-Utility, non-Realtime messages");
 -         {
 -             const auto noteOn = [&]
 -             {
 -                 MidiBuffer b;
 -                 b.addEvent (MidiMessage::noteOn (1, uint8_t (64), uint8_t (64)), 0);
 -                 return b;
 -             }();
 - 
 -             const auto noteOnPackets = [&]
 -             {
 -                 Packets p;
 - 
 -                 for (const auto meta : noteOn)
 -                     Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto packet) { p.add (packet); });
 - 
 -                 return p;
 -             }();
 - 
 -             const auto sysEx = createRandomSysEx (random, 300);
 - 
 -             const auto originalPackets = toMidi1 (sysEx);
 - 
 -             const auto modifiedPackets = [&]
 -             {
 -                 Packets p;
 - 
 -                 const auto insertionPoint = std::next (originalPackets.begin(), 10);
 -                 std::for_each (originalPackets.begin(),
 -                                insertionPoint,
 -                                [&] (const View& view) { p.add (view); });
 - 
 -                 for (const auto& view : noteOnPackets)
 -                     p.add (view);
 - 
 -                 std::for_each (insertionPoint,
 -                                originalPackets.end(),
 -                                [&] (const View& view) { p.add (view); });
 - 
 -                 return p;
 -             }();
 - 
 -             // modifiedPackets now contains some SysEx packets interrupted by a MIDI 1 noteOn
 - 
 -             MidiBuffer output;
 - 
 -             const auto pushToOutput = [&] (const Packets& p)
 -             {
 -                 converter.dispatch (p.data(),
 -                                     p.data() + p.size(),
 -                                     0,
 -                                     [&] (const BytestreamMidiView& roundTripped)
 -                                     {
 -                                         output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp));
 -                                     });
 -             };
 - 
 -             pushToOutput (modifiedPackets);
 - 
 -             // Interrupted sysEx shouldn't be present
 -             expect (equal (output, noteOn));
 - 
 -             const auto newSysEx = createRandomSysEx (random, 300);
 -             const auto newSysExPackets = toMidi1 (newSysEx);
 - 
 -             // If we push another midi event without interrupting it,
 -             // it should get through without being modified,
 -             // and it shouldn't be affected by the previous (interrupted) sysex.
 - 
 -             output.clear();
 -             pushToOutput (newSysExPackets);
 - 
 -             expect (output.getNumEvents() == 1);
 - 
 -             for (const auto meta : output)
 -                 expect (equal (meta.getMessage(), newSysEx));
 -         }
 - 
 -         beginTest ("Widening conversions work");
 -         {
 -             // This is similar to the 'slow' example code from the MIDI 2.0 spec
 -             const auto baselineScale = [] (uint32_t srcVal, uint32_t srcBits, uint32_t dstBits)
 -             {
 -                 const auto scaleBits = (uint32_t) (dstBits - srcBits);
 - 
 -                 auto bitShiftedValue = (uint32_t) (srcVal << scaleBits);
 - 
 -                 const auto srcCenter = (uint32_t) (1 << (srcBits - 1));
 - 
 -                 if (srcVal <= srcCenter)
 -                     return bitShiftedValue;
 - 
 -                 const auto repeatBits = (uint32_t) (srcBits - 1);
 -                 const auto repeatMask = (uint32_t) ((1 << repeatBits) - 1);
 - 
 -                 auto repeatValue = (uint32_t) (srcVal & repeatMask);
 - 
 -                 if (scaleBits > repeatBits)
 -                     repeatValue <<= scaleBits - repeatBits;
 -                 else
 -                     repeatValue >>= repeatBits - scaleBits;
 - 
 -                 while (repeatValue != 0)
 -                 {
 -                     bitShiftedValue |= repeatValue;
 -                     repeatValue >>= repeatBits;
 -                 }
 - 
 -                 return bitShiftedValue;
 -             };
 - 
 -             const auto baselineScale7To8 = [&] (uint8_t in)
 -             {
 -                 return baselineScale (in, 7, 8);
 -             };
 - 
 -             const auto baselineScale7To16 = [&] (uint8_t in)
 -             {
 -                 return baselineScale (in, 7, 16);
 -             };
 - 
 -             const auto baselineScale14To16 = [&] (uint16_t in)
 -             {
 -                 return baselineScale (in, 14, 16);
 -             };
 - 
 -             const auto baselineScale7To32 = [&] (uint8_t in)
 -             {
 -                 return baselineScale (in, 7, 32);
 -             };
 - 
 -             const auto baselineScale14To32 = [&] (uint16_t in)
 -             {
 -                 return baselineScale (in, 14, 32);
 -             };
 - 
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 const auto rand = (uint8_t) random.nextInt (0x80);
 -                 expectEquals ((int64_t) Conversion::scaleTo8 (rand),
 -                               (int64_t) baselineScale7To8 (rand));
 -             }
 - 
 -             expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x00), (int64_t) 0x0000);
 -             expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x0a), (int64_t) 0x1400);
 -             expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x40), (int64_t) 0x8000);
 -             expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x57), (int64_t) 0xaeba);
 -             expectEquals ((int64_t) Conversion::scaleTo16 ((uint8_t) 0x7f), (int64_t) 0xffff);
 - 
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 const auto rand = (uint8_t) random.nextInt (0x80);
 -                 expectEquals ((int64_t) Conversion::scaleTo16 (rand),
 -                               (int64_t) baselineScale7To16 (rand));
 -             }
 - 
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 const auto rand = (uint16_t) random.nextInt (0x4000);
 -                 expectEquals ((int64_t) Conversion::scaleTo16 (rand),
 -                               (int64_t) baselineScale14To16 (rand));
 -             }
 - 
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 const auto rand = (uint8_t) random.nextInt (0x80);
 -                 expectEquals ((int64_t) Conversion::scaleTo32 (rand),
 -                               (int64_t) baselineScale7To32 (rand));
 -             }
 - 
 -             expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x0000), (int64_t) 0x00000000);
 -             expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x2000), (int64_t) 0x80000000);
 -             expectEquals ((int64_t) Conversion::scaleTo32 ((uint16_t) 0x3fff), (int64_t) 0xffffffff);
 - 
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 const auto rand = (uint16_t) random.nextInt (0x4000);
 -                 expectEquals ((int64_t) Conversion::scaleTo32 (rand),
 -                               (int64_t) baselineScale14To32 (rand));
 -             }
 -         }
 - 
 -         beginTest ("Round-trip widening/narrowing conversions work");
 -         {
 -             for (auto i = 0; i != 100; ++i)
 -             {
 -                 {
 -                     const auto rand = (uint8_t) random.nextInt (0x80);
 -                     expectEquals (Conversion::scaleTo7 (Conversion::scaleTo8 (rand)), rand);
 -                 }
 - 
 -                 {
 -                     const auto rand = (uint8_t) random.nextInt (0x80);
 -                     expectEquals (Conversion::scaleTo7 (Conversion::scaleTo16 (rand)), rand);
 -                 }
 - 
 -                 {
 -                     const auto rand = (uint8_t) random.nextInt (0x80);
 -                     expectEquals (Conversion::scaleTo7 (Conversion::scaleTo32 (rand)), rand);
 -                 }
 - 
 -                 {
 -                     const auto rand = (uint16_t) random.nextInt (0x4000);
 -                     expectEquals ((uint64_t) Conversion::scaleTo14 (Conversion::scaleTo16 (rand)), (uint64_t) rand);
 -                 }
 - 
 -                 {
 -                     const auto rand = (uint16_t) random.nextInt (0x4000);
 -                     expectEquals ((uint64_t) Conversion::scaleTo14 (Conversion::scaleTo32 (rand)), (uint64_t) rand);
 -                 }
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 note on conversions");
 -         {
 -             {
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x41946410, 0x12345678 });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x21946409 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 - 
 -             {
 -                 // If the velocity is close to 0, the output velocity should still be 1
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x4295327f, 0x00345678 });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x22953201 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 note off conversion");
 -         {
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x448b0520, 0xfedcba98 });
 - 
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x248b057f });
 - 
 -             checkMidi2ToMidi1Conversion (midi2, midi1);
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 poly pressure conversion");
 -         {
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x49af0520, 0x80dcba98 });
 - 
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x29af0540 });
 - 
 -             checkMidi2ToMidi1Conversion (midi2, midi1);
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 control change conversion");
 -         {
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x49b00520, 0x80dcba98 });
 - 
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x29b00540 });
 - 
 -             checkMidi2ToMidi1Conversion (midi2, midi1);
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 channel pressure conversion");
 -         {
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x40d20520, 0x80dcba98 });
 - 
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x20d24000 });
 - 
 -             checkMidi2ToMidi1Conversion (midi2, midi1);
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 nrpn rpn conversion");
 -         {
 -             {
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x44240123, 0x456789ab });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x24b46501 });
 -                 midi1.add (PacketX1 { 0x24b46423 });
 -                 midi1.add (PacketX1 { 0x24b40622 });
 -                 midi1.add (PacketX1 { 0x24b42659 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 - 
 -             {
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x48347f7f, 0xffffffff });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x28b4637f });
 -                 midi1.add (PacketX1 { 0x28b4627f });
 -                 midi1.add (PacketX1 { 0x28b4067f });
 -                 midi1.add (PacketX1 { 0x28b4267f });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 program change and bank select conversion");
 -         {
 -             {
 -                 // If the bank valid bit is 0, just emit a program change
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x4cc10000, 0x70004020 });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x2cc17000 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 - 
 -             {
 -                 // If the bank valid bit is 1, emit bank select control changes and a program change
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x4bc20001, 0x70004020 });
 - 
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x2bb20040 });
 -                 midi1.add (PacketX1 { 0x2bb22020 });
 -                 midi1.add (PacketX1 { 0x2bc27000 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, midi1);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 pitch bend conversion");
 -         {
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x4eee0000, 0x12340000 });
 - 
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x2eee0d09 });
 - 
 -             checkMidi2ToMidi1Conversion (midi2, midi1);
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 messages which don't convert");
 -         {
 -             const std::byte opcodes[] { std::byte { 0x0 },
 -                                         std::byte { 0x1 },
 -                                         std::byte { 0x4 },
 -                                         std::byte { 0x5 },
 -                                         std::byte { 0x6 },
 -                                         std::byte { 0xf } };
 - 
 -             for (const auto opcode : opcodes)
 -             {
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { Utils::bytesToWord (std::byte { 0x40 }, std::byte { opcode << 0x4 }, std::byte { 0 }, std::byte { 0 }), 0x0 });
 -                 checkMidi2ToMidi1Conversion (midi2, {});
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 messages which are passed through");
 -         {
 -             const uint8_t typecodesX1[] { 0x0, 0x1, 0x2 };
 - 
 -             for (const auto typecode : typecodesX1)
 -             {
 -                 Packets p;
 -                 p.add (PacketX1 { (uint32_t) ((int64_t) typecode << 0x1c | (random.nextInt64() & 0xffffff)) });
 - 
 -                 checkMidi2ToMidi1Conversion (p, p);
 -             }
 - 
 -             {
 -                 Packets p;
 -                 p.add (PacketX2 { (uint32_t) (0x3 << 0x1c | (random.nextInt64() & 0xffffff)),
 -                                   (uint32_t) (random.nextInt64() & 0xffffffff) });
 - 
 -                 checkMidi2ToMidi1Conversion (p, p);
 -             }
 - 
 -             {
 -                 Packets p;
 -                 p.add (PacketX4 { (uint32_t) (0x5 << 0x1c | (random.nextInt64() & 0xffffff)),
 -                                   (uint32_t) (random.nextInt64() & 0xffffffff),
 -                                   (uint32_t) (random.nextInt64() & 0xffffffff),
 -                                   (uint32_t) (random.nextInt64() & 0xffffffff) });
 - 
 -                 checkMidi2ToMidi1Conversion (p, p);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 2 -> 1 control changes which should be ignored");
 -         {
 -             const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 };
 - 
 -             for (const auto cc : CCs)
 -             {
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { (uint32_t) (0x40b00000 | (cc << 0x8)), 0x00000000 });
 - 
 -                 checkMidi2ToMidi1Conversion (midi2, {});
 -             }
 -         }
 - 
 -         beginTest ("MIDI 1 -> 2 note on conversions");
 -         {
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x20904040 });
 - 
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x40904000, static_cast<uint32_t> (Conversion::scaleTo16 (0x40_u8)) << 0x10 });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, midi2);
 -             }
 - 
 -             // If velocity is 0, convert to a note-off
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x23935100 });
 - 
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x43835100, 0x0 });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, midi2);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 1 -> 2 note off conversions");
 -         {
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x21831020 });
 - 
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x41831000, static_cast<uint32_t> (Conversion::scaleTo16 (0x20_u8)) << 0x10 });
 - 
 -             checkMidi1ToMidi2Conversion (midi1, midi2);
 -         }
 - 
 -         beginTest ("MIDI 1 -> 2 poly pressure conversions");
 -         {
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x20af7330 });
 - 
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x40af7300, Conversion::scaleTo32 (0x30_u8) });
 - 
 -             checkMidi1ToMidi2Conversion (midi1, midi2);
 -         }
 - 
 -         beginTest ("individual MIDI 1 -> 2 control changes which should be ignored");
 -         {
 -             const uint8_t CCs[] { 6, 38, 98, 99, 100, 101, 0, 32 };
 - 
 -             for (const auto cc : CCs)
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { Utils::bytesToWord (std::byte { 0x20 }, std::byte { 0xb0 }, std::byte { cc }, std::byte { 0x00 }) });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, {});
 -             }
 -         }
 - 
 -         beginTest ("MIDI 1 -> 2 control change conversions");
 -         {
 -             // normal control change
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x29b1017f });
 - 
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x49b10100, Conversion::scaleTo32 (0x7f_u8) });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, midi2);
 -             }
 - 
 -             // nrpn
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x20b06301 });
 -                 midi1.add (PacketX1 { 0x20b06223 });
 -                 midi1.add (PacketX1 { 0x20b00645 });
 -                 midi1.add (PacketX1 { 0x20b02667 });
 - 
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x40300123, Conversion::scaleTo32 (static_cast<uint16_t> ((0x45 << 7) | 0x67)) });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, midi2);
 -             }
 - 
 -             // rpn
 -             {
 -                 Packets midi1;
 -                 midi1.add (PacketX1 { 0x20b06543 });
 -                 midi1.add (PacketX1 { 0x20b06421 });
 -                 midi1.add (PacketX1 { 0x20b00601 });
 -                 midi1.add (PacketX1 { 0x20b02623 });
 - 
 -                 Packets midi2;
 -                 midi2.add (PacketX2 { 0x40204321, Conversion::scaleTo32 (static_cast<uint16_t> ((0x01 << 7) | 0x23)) });
 - 
 -                 checkMidi1ToMidi2Conversion (midi1, midi2);
 -             }
 -         }
 - 
 -         beginTest ("MIDI 1 -> MIDI 2 program change and bank select");
 -         {
 -             Packets midi1;
 -             // program change with bank
 -             midi1.add (PacketX1 { 0x2bb20030 });
 -             midi1.add (PacketX1 { 0x2bb22010 });
 -             midi1.add (PacketX1 { 0x2bc24000 });
 -             // program change without bank (different group and channel)
 -             midi1.add (PacketX1 { 0x20c01000 });
 - 
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x4bc20001, 0x40003010 });
 -             midi2.add (PacketX2 { 0x40c00000, 0x10000000 });
 - 
 -             checkMidi1ToMidi2Conversion (midi1, midi2);
 -         }
 - 
 -         beginTest ("MIDI 1 -> MIDI 2 channel pressure conversions");
 -         {
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x20df3000 });
 - 
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x40df0000, Conversion::scaleTo32 (0x30_u8) });
 - 
 -             checkMidi1ToMidi2Conversion (midi1, midi2);
 -         }
 - 
 -         beginTest ("MIDI 1 -> MIDI 2 pitch bend conversions");
 -         {
 -             Packets midi1;
 -             midi1.add (PacketX1 { 0x20e74567 });
 - 
 -             Packets midi2;
 -             midi2.add (PacketX2 { 0x40e70000, Conversion::scaleTo32 (static_cast<uint16_t> ((0x67 << 7) | 0x45)) });
 - 
 -             checkMidi1ToMidi2Conversion (midi1, midi2);
 -         }
 -     }
 - 
 - private:
 -     static Packets toMidi1 (const MidiMessage& msg)
 -     {
 -         Packets packets;
 -         Conversion::toMidi1 (ump::BytestreamMidiView (&msg), [&] (const auto p) { packets.add (p); });
 -         return packets;
 -     }
 - 
 -     static Packets convertMidi2ToMidi1 (const Packets& midi2)
 -     {
 -         Packets r;
 - 
 -         for (const auto& packet : midi2)
 -             Conversion::midi2ToMidi1DefaultTranslation (packet, [&r] (const View& v) { r.add (v); });
 - 
 -         return r;
 -     }
 - 
 -     static Packets convertMidi1ToMidi2 (const Packets& midi1)
 -     {
 -         Packets r;
 -         Midi1ToMidi2DefaultTranslator translator;
 - 
 -         for (const auto& packet : midi1)
 -             translator.dispatch (packet, [&r] (const View& v) { r.add (v); });
 - 
 -         return r;
 -     }
 - 
 -     void checkBytestreamConversion (const Packets& actual, const Packets& expected)
 -     {
 -         expectEquals ((int) actual.size(), (int) expected.size());
 - 
 -         if (actual.size() != expected.size())
 -             return;
 - 
 -         auto actualPtr = actual.data();
 - 
 -         std::for_each (expected.data(),
 -                        expected.data() + expected.size(),
 -                        [&] (const uint32_t word) { expectEquals ((uint64_t) *actualPtr++, (uint64_t) word); });
 -     }
 - 
 -     void checkMidi2ToMidi1Conversion (const Packets& midi2, const Packets& expected)
 -     {
 -         checkBytestreamConversion (convertMidi2ToMidi1 (midi2), expected);
 -     }
 - 
 -     void checkMidi1ToMidi2Conversion (const Packets& midi1, const Packets& expected)
 -     {
 -         checkBytestreamConversion (convertMidi1ToMidi2 (midi1), expected);
 -     }
 - 
 -     MidiMessage createRandomSysEx (Random& random, size_t sysExBytes)
 -     {
 -         std::vector<uint8_t> data;
 -         data.reserve (sysExBytes);
 - 
 -         for (size_t i = 0; i != sysExBytes; ++i)
 -             data.push_back (uint8_t (random.nextInt (0x80)));
 - 
 -         return MidiMessage::createSysExMessage (data.data(), int (data.size()));
 -     }
 - 
 -     PacketX1 createRandomUtilityUMP (Random& random)
 -     {
 -         const auto status = random.nextInt (3);
 - 
 -         return PacketX1 { Utils::bytesToWord (std::byte { 0 },
 -                                               std::byte (status << 0x4),
 -                                               std::byte (status == 0 ? 0 : random.nextInt (0x100)),
 -                                               std::byte (status == 0 ? 0 : random.nextInt (0x100))) };
 -     }
 - 
 -     PacketX1 createRandomRealtimeUMP (Random& random)
 -     {
 -         const auto status = [&]
 -         {
 -             switch (random.nextInt (6))
 -             {
 -                 case 0: return std::byte { 0xf8 };
 -                 case 1: return std::byte { 0xfa };
 -                 case 2: return std::byte { 0xfb };
 -                 case 3: return std::byte { 0xfc };
 -                 case 4: return std::byte { 0xfe };
 -                 case 5: return std::byte { 0xff };
 -             }
 - 
 -             jassertfalse;
 -             return std::byte { 0x00 };
 -         }();
 - 
 -         return PacketX1 { Utils::bytesToWord (std::byte { 0x10 }, status, std::byte { 0x00 }, std::byte { 0x00 }) };
 -     }
 - 
 -     template <typename Fn>
 -     void forEachNonSysExTestMessage (Random& random, Fn&& fn)
 -     {
 -         for (uint16_t counter = 0x80; counter != 0x100; ++counter)
 -         {
 -             const auto firstByte = (uint8_t) counter;
 - 
 -             if (firstByte == 0xf0 || firstByte == 0xf7)
 -                 continue; // sysEx is tested separately
 - 
 -             const auto length = MidiMessage::getMessageLengthFromFirstByte (firstByte);
 -             const auto getDataByte = [&] { return uint8_t (random.nextInt (256) & 0x7f); };
 - 
 -             const auto message = [&]
 -             {
 -                 switch (length)
 -                 {
 -                     case 1: return MidiMessage (firstByte);
 -                     case 2: return MidiMessage (firstByte, getDataByte());
 -                     case 3: return MidiMessage (firstByte, getDataByte(), getDataByte());
 -                 }
 - 
 -                 return MidiMessage();
 -             }();
 - 
 -             fn (message);
 -         }
 -     }
 - 
 -    #if JUCE_WINDOWS && ! JUCE_MINGW
 -     #define JUCE_CHECKED_ITERATOR(msg, size) \
 -         stdext::checked_array_iterator<std::remove_reference_t<decltype (msg)>> ((msg), (size_t) (size))
 -    #else
 -     #define JUCE_CHECKED_ITERATOR(msg, size) (msg)
 -    #endif
 - 
 -     static bool equal (const MidiMessage& a, const MidiMessage& b) noexcept
 -     {
 -         return a.getRawDataSize() == b.getRawDataSize()
 -                && std::equal (a.getRawData(), a.getRawData() + a.getRawDataSize(),
 -                               JUCE_CHECKED_ITERATOR (b.getRawData(), b.getRawDataSize()));
 -     }
 - 
 -     #undef JUCE_CHECKED_ITERATOR
 - 
 -     static bool equal (const MidiBuffer& a, const MidiBuffer& b) noexcept
 -     {
 -         return a.data == b.data;
 -     }
 - };
 - 
 - static UniversalMidiPacketTests universalMidiPacketTests;
 - 
 - }
 - }
 
 
  |