25namespace juce::universal_midi_packets
34 constexpr BytestreamMidiView (Span<const std::byte> bytesIn,
double timestampIn)
35 : bytes (bytesIn), timestamp (timestampIn) {}
42 explicit BytestreamMidiView (
const MidiMessage* msg)
44 static_cast<
size_t> (msg->getRawDataSize())),
45 timestamp (msg->getTimeStamp()) {}
47 explicit BytestreamMidiView (
const MidiMessageMetadata msg)
49 static_cast<
size_t> (msg.numBytes)),
50 timestamp (msg.samplePosition) {}
52 MidiMessage getMessage()
const
54 return MidiMessage (bytes.data(), (
int) bytes.size(), timestamp);
59 return ! bytes.empty() && bytes.front() ==
std::byte { 0xf0 };
62 Span<const std::byte> bytes;
63 double timestamp = 0.0;
78 template <
typename PacketCallbackFunction>
79 static void toMidi1 (
const BytestreamMidiView& m, PacketCallbackFunction&& callback)
81 const auto size = m.bytes.size();
86 const auto*
data = m.bytes.data();
87 const auto firstByte =
data[0];
91 const auto mask = [
size]() -> uint32_t
95 case 0:
return 0xff000000;
96 case 1:
return 0xffff0000;
97 case 2:
return 0xffffff00;
98 case 3:
return 0xffffffff;
105 const PacketX1 packet { mask & Utils::bytesToWord (extraByte, data[0], data[1], data[2]) };
106 callback (View (packet.data()));
110 const auto numSysExBytes = (
ssize_t) (size - 2);
111 const auto numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes);
112 auto* dataOffset =
data + 1;
114 if (numMessages <= 1)
116 const auto packet = Factory::makeSysExIn1Packet (0, (uint8_t) numSysExBytes, dataOffset);
117 callback (View (packet.data()));
121 constexpr ssize_t byteIncrement = 6;
123 for (
auto i =
static_cast<ssize_t> (numSysExBytes); i > 0; i -= byteIncrement, dataOffset += byteIncrement)
125 const auto func = [&]
127 if (i == numSysExBytes)
128 return Factory::makeSysExStart;
130 if (i <= byteIncrement)
131 return Factory::makeSysExEnd;
133 return Factory::makeSysExContinue;
136 const auto bytesNow =
std::min (byteIncrement, i);
137 const auto packet = func (0, (uint8_t) bytesNow, dataOffset);
138 callback (View (packet.data()));
143 static uint8_t scaleTo8 (uint8_t word7Bit)
145 const auto shifted = (
uint8_t) (word7Bit << 0x1);
146 const auto repeat = (
uint8_t) (word7Bit & 0x3f);
147 const auto mask = (
uint8_t) (word7Bit <= 0x40 ? 0x0 : 0xff);
148 return (uint8_t) (shifted | ((repeat >> 5) & mask));
152 static uint16_t scaleTo16 (uint8_t word7Bit)
154 const auto shifted = (
uint16_t) (word7Bit << 0x9);
155 const auto repeat = (
uint16_t) (word7Bit & 0x3f);
156 const auto mask = (
uint16_t) (word7Bit <= 0x40 ? 0x0 : 0xffff);
157 return (uint16_t) (shifted | (((repeat << 3) | (repeat >> 3)) & mask));
161 static uint16_t scaleTo16 (uint16_t word14Bit)
163 const auto shifted = (
uint16_t) (word14Bit << 0x2);
164 const auto repeat = (
uint16_t) (word14Bit & 0x1fff);
165 const auto mask = (
uint16_t) (word14Bit <= 0x2000 ? 0x0 : 0xffff);
166 return (uint16_t) (shifted | ((repeat >> 11) & mask));
170 static uint32_t scaleTo32 (uint8_t word7Bit)
172 const auto shifted = (
uint32_t) (word7Bit << 0x19);
173 const auto repeat = (
uint32_t) (word7Bit & 0x3f);
174 const auto mask = (
uint32_t) (word7Bit <= 0x40 ? 0x0 : 0xffffffff);
175 return (uint32_t) (shifted | (((repeat << 19)
179 | (repeat >> 5)) & mask));
183 static uint32_t scaleTo32 (uint16_t word14Bit)
185 const auto shifted = (
uint32_t) (word14Bit << 0x12);
186 const auto repeat = (
uint32_t) (word14Bit & 0x1fff);
187 const auto mask = (
uint32_t) (word14Bit <= 0x2000 ? 0x0 : 0xffffffff);
188 return (uint32_t) (shifted | (((repeat << 5) | (repeat >> 8)) & mask));
192 static uint8_t scaleTo7 (uint8_t word8Bit) {
return (uint8_t) (word8Bit >> 1); }
195 static uint8_t scaleTo7 (uint16_t word16Bit) {
return (uint8_t) (word16Bit >> 9); }
198 static uint8_t scaleTo7 (uint32_t word32Bit) {
return (uint8_t) (word32Bit >> 25); }
201 static uint16_t scaleTo14 (uint16_t word16Bit) {
return (uint16_t) (word16Bit >> 2); }
204 static uint16_t scaleTo14 (uint32_t word32Bit) {
return (uint16_t) (word32Bit >> 18); }
215 template <
typename Callback>
216 static void midi2ToMidi1DefaultTranslation (
const View& v, Callback&& callback)
218 const auto firstWord = v[0];
220 if (Utils::getMessageType (firstWord) != 0x4)
226 const auto status = Utils::getStatus (firstWord);
227 const auto typeAndGroup = ((
std::byte { 0x2 } << 0x4) |
std::byte { Utils::getGroup (firstWord) });
236 const auto statusAndChannel =
std::byte ((firstWord >> 0x10) & 0xff);
237 const auto byte2 =
std::byte ((firstWord >> 0x08) & 0xff);
238 const auto byte3 =
std::byte { scaleTo7 (v[1]) };
242 const auto needsCorrection =
status == 0x9 && byte3 ==
std::byte { 0 };
243 const auto correctedByte = needsCorrection ?
std::byte { 1 } : byte3;
245 const auto shouldIgnore =
status == 0xb && [&]
247 switch (uint8_t (byte2))
266 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
270 callback (View (packet.data()));
276 const auto statusAndChannel =
std::byte ((firstWord >> 0x10) & 0xff);
277 const auto byte2 =
std::byte { scaleTo7 (v[1]) };
279 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
283 callback (View (packet.data()));
292 const auto statusAndChannel =
std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
293 const auto data = scaleTo14 (v[1]);
295 const PacketX1 packets[]
297 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX,
std::byte ((firstWord >> 0x8) & 0x7f)) },
298 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY,
std::byte ((firstWord >> 0x0) & 0x7f)) },
299 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel,
std::byte { 6 },
std::byte ((data >> 0x7) & 0x7f)) },
300 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel,
std::byte { 38 },
std::byte ((data >> 0x0) & 0x7f)) },
303 for (
const auto& packet : packets)
304 callback (View (packet.
data()));
313 const auto statusAndChannel =
std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
314 const auto secondWord = v[1];
316 const PacketX1 packets[]
318 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel,
std::byte { 0 },
std::byte ((secondWord >> 0x8) & 0x7f)) },
319 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel,
std::byte { 32 },
std::byte ((secondWord >> 0x0) & 0x7f)) },
322 for (
const auto& packet : packets)
323 callback (View (packet.
data()));
326 const auto statusAndChannel =
std::byte ((0xc << 0x4) | Utils::getChannel (firstWord));
327 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
331 callback (View (packet.data()));
337 const auto data = scaleTo14 (v[1]);
338 const auto statusAndChannel =
std::byte ((firstWord >> 0x10) & 0xff);
339 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
343 callback (View (packet.data()));
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...