25namespace juce::universal_midi_packets
40 explicit Midi1ToBytestreamTranslator (
int initialBufferSize)
42 pendingSysExData.reserve (
size_t (initialBufferSize));
48 pendingSysExData.clear();
49 pendingSysExTime = 0.0;
60 template <
typename MessageCallback>
61 void dispatch (
const View& packet,
double time, MessageCallback&& callback)
63 const auto firstWord = *packet.data();
65 if (! pendingSysExData.empty() && shouldPacketTerminateSysExEarly (firstWord))
66 pendingSysExData.clear();
68 switch (packet.size())
73 if (Utils::getMessageType (firstWord) != 0x00)
75 const auto message = fromUmp (PacketX1 { firstWord },
time);
76 callback (BytestreamMidiView (&message));
84 if (Utils::getMessageType (firstWord) == 0x3)
85 processSysEx (PacketX2 { packet[0], packet[1] },
time, callback);
107 static MidiMessage fromUmp (
const PacketX1& m,
double time = 0)
109 const auto word = m.front();
110 jassert (Utils::getNumWordsForMessageType (word) == 1);
113 uint8_t ((word >> 0x08) & 0xff),
114 uint8_t ((word >> 0x00) & 0xff) } };
115 const auto numBytes = MidiMessage::getMessageLengthFromFirstByte (bytes.front());
116 return MidiMessage (bytes.data(), numBytes, time);
120 template <
typename MessageCallback>
121 void processSysEx (
const PacketX2& packet,
123 MessageCallback&& callback)
125 switch (getSysEx7Kind (packet[0]))
127 case SysEx7::Kind::complete:
128 startSysExMessage (time);
130 terminateSysExMessage (callback);
133 case SysEx7::Kind::begin:
134 startSysExMessage (time);
138 case SysEx7::Kind::continuation:
139 if (pendingSysExData.empty())
145 case SysEx7::Kind::end:
146 if (pendingSysExData.empty())
150 terminateSysExMessage (callback);
155 void pushBytes (
const PacketX2& packet)
157 const auto bytes = SysEx7::getDataBytes (packet);
158 pendingSysExData.insert (pendingSysExData.end(),
160 bytes.data.begin() + bytes.size);
163 void startSysExMessage (
double time)
165 pendingSysExTime =
time;
166 pendingSysExData.push_back (
std::byte { 0xf0 });
169 template <
typename MessageCallback>
170 void terminateSysExMessage (MessageCallback&& callback)
172 pendingSysExData.push_back (
std::byte { 0xf7 });
173 callback (BytestreamMidiView (pendingSysExData, pendingSysExTime));
174 pendingSysExData.clear();
177 static bool shouldPacketTerminateSysExEarly (uint32_t firstWord)
179 return ! (isSysExContinuation (firstWord)
180 || isSystemRealTime (firstWord)
181 || isJROrNOP (firstWord));
184 static SysEx7::Kind getSysEx7Kind (uint32_t word)
186 return SysEx7::Kind ((word >> 0x14) & 0xf);
189 static bool isJROrNOP (uint32_t word)
191 return Utils::getMessageType (word) == 0x0;
194 static bool isSysExContinuation (uint32_t word)
196 if (Utils::getMessageType (word) != 0x3)
199 const auto kind = getSysEx7Kind (word);
200 return kind == SysEx7::Kind::continuation || kind == SysEx7::Kind::end;
203 static bool isSystemRealTime (uint32_t word)
205 return Utils::getMessageType (word) == 0x1 && ((word >> 0x10) & 0xff) >= 0xf8;
210 double pendingSysExTime = 0.0;
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...