1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

UMP: Migrate to std::byte

This commit is contained in:
reuk 2023-02-08 20:25:36 +00:00
parent f1f68007c6
commit 78a12d2f57
13 changed files with 230 additions and 191 deletions

View file

@ -27,6 +27,44 @@ namespace juce
namespace universal_midi_packets
{
/** Represents a MIDI message that happened at a particular time.
Unlike MidiMessage, BytestreamMidiView is non-owning.
*/
struct BytestreamMidiView
{
constexpr BytestreamMidiView (Span<const std::byte> bytesIn, double timestampIn)
: bytes (bytesIn), timestamp (timestampIn) {}
/** Creates a view over the provided message.
Note that the argument is a pointer, not a reference, in order to avoid taking a reference
to a temporary.
*/
explicit BytestreamMidiView (const MidiMessage* msg)
: bytes (unalignedPointerCast<const std::byte*> (msg->getRawData()),
static_cast<size_t> (msg->getRawDataSize())),
timestamp (msg->getTimeStamp()) {}
explicit BytestreamMidiView (const MidiMessageMetadata msg)
: bytes (unalignedPointerCast<const std::byte*> (msg.data),
static_cast<size_t> (msg.numBytes)),
timestamp (msg.samplePosition) {}
MidiMessage getMessage() const
{
return MidiMessage (bytes.data(), (int) bytes.size(), timestamp);
}
bool isSysEx() const
{
return ! bytes.empty() && bytes.front() == std::byte { 0xf0 };
}
Span<const std::byte> bytes;
double timestamp = 0.0;
};
/**
Functions to assist conversion of UMP messages to/from other formats,
especially older 'bytestream' formatted MidiMessages.
@ -40,13 +78,17 @@ struct Conversion
`callback` is a function which accepts a single View argument.
*/
template <typename PacketCallbackFunction>
static void toMidi1 (const MidiMessage& m, PacketCallbackFunction&& callback)
static void toMidi1 (const BytestreamMidiView& m, PacketCallbackFunction&& callback)
{
const auto* data = m.getRawData();
const auto firstByte = data[0];
const auto size = m.getRawDataSize();
const auto size = m.bytes.size();
if (firstByte != 0xf0)
if (size <= 0)
return;
const auto* data = m.bytes.data();
const auto firstByte = data[0];
if (firstByte != std::byte { 0xf0 })
{
const auto mask = [size]() -> uint32_t
{
@ -61,15 +103,15 @@ struct Conversion
return 0x00000000;
}();
const auto extraByte = (uint8_t) ((((firstByte & 0xf0) == 0xf0) ? 0x1 : 0x2) << 0x4);
const auto extraByte = ((((firstByte & std::byte { 0xf0 }) == std::byte { 0xf0 }) ? std::byte { 0x1 } : std::byte { 0x2 }) << 0x4);
const PacketX1 packet { mask & Utils::bytesToWord (extraByte, data[0], data[1], data[2]) };
callback (View (packet.data()));
return;
}
const auto numSysExBytes = m.getSysExDataSize();
const auto numSysExBytes = (ssize_t) (size - 2);
const auto numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes);
auto* dataOffset = m.getSysExData();
auto* dataOffset = data + 1;
if (numMessages <= 1)
{
@ -78,9 +120,9 @@ struct Conversion
return;
}
constexpr auto byteIncrement = 6;
constexpr ssize_t byteIncrement = 6;
for (auto i = numSysExBytes; i > 0; i -= byteIncrement, dataOffset += byteIncrement)
for (auto i = static_cast<ssize_t> (numSysExBytes); i > 0; i -= byteIncrement, dataOffset += byteIncrement)
{
const auto func = [&]
{
@ -99,20 +141,6 @@ struct Conversion
}
}
/** Converts a MidiMessage to one or more messages in UMP format, using
the MIDI 1.0 Protocol.
`packets` is an out-param to allow the caller to control
allocation/deallocation. Returning a new Packets object would
require every call to toMidi1 to allocate. With this version, no
allocations will occur, provided that `packets` has adequate reserved
space.
*/
static void toMidi1 (const MidiMessage& m, Packets& packets)
{
toMidi1 (m, [&] (const View& view) { packets.add (view); });
}
/** Widens a 7-bit MIDI 1.0 value to a 8-bit MIDI 2.0 value. */
static uint8_t scaleTo8 (uint8_t word7Bit)
{
@ -198,7 +226,7 @@ struct Conversion
}
const auto status = Utils::getStatus (firstWord);
const auto typeAndGroup = (uint8_t) ((0x2 << 0x4) | Utils::getGroup (firstWord));
const auto typeAndGroup = ((std::byte { 0x2 } << 0x4) | std::byte { Utils::getGroup (firstWord) });
switch (status)
{
@ -207,18 +235,18 @@ struct Conversion
case 0xa: // poly pressure
case 0xb: // control change
{
const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff);
const auto byte2 = (uint8_t) ((firstWord >> 0x08) & 0xff);
const auto byte3 = scaleTo7 (v[1]);
const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
const auto byte2 = std::byte ((firstWord >> 0x08) & 0xff);
const auto byte3 = std::byte { scaleTo7 (v[1]) };
// If this is a note-on, and the scaled byte is 0,
// the scaled velocity should be 1 instead of 0
const auto needsCorrection = status == 0x9 && byte3 == 0;
const auto correctedByte = (uint8_t) (needsCorrection ? 1 : byte3);
const auto needsCorrection = status == 0x9 && byte3 == std::byte { 0 };
const auto correctedByte = needsCorrection ? std::byte { 1 } : byte3;
const auto shouldIgnore = status == 0xb && [&]
{
switch (byte2)
switch (uint8_t (byte2))
{
case 0:
case 6:
@ -247,13 +275,13 @@ struct Conversion
case 0xd: // channel pressure
{
const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff);
const auto byte2 = scaleTo7 (v[1]);
const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
const auto byte2 = std::byte { scaleTo7 (v[1]) };
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
statusAndChannel,
byte2,
0) };
std::byte { 0 }) };
callback (View (packet.data()));
return;
}
@ -261,17 +289,17 @@ struct Conversion
case 0x2: // rpn
case 0x3: // nrpn
{
const auto ccX = (uint8_t) (status == 0x2 ? 101 : 99);
const auto ccY = (uint8_t) (status == 0x2 ? 100 : 98);
const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord));
const auto ccX = status == 0x2 ? std::byte { 101 } : std::byte { 99 };
const auto ccY = status == 0x2 ? std::byte { 100 } : std::byte { 98 };
const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
const auto data = scaleTo14 (v[1]);
const PacketX1 packets[]
{
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, (uint8_t) ((firstWord >> 0x8) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, (uint8_t) ((firstWord >> 0x0) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 6, (uint8_t) ((data >> 0x7) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 38, (uint8_t) ((data >> 0x0) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, std::byte ((firstWord >> 0x8) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, std::byte ((firstWord >> 0x0) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 6 }, std::byte ((data >> 0x7) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 38 }, std::byte ((data >> 0x0) & 0x7f)) },
};
for (const auto& packet : packets)
@ -284,24 +312,24 @@ struct Conversion
{
if (firstWord & 1)
{
const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord));
const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
const auto secondWord = v[1];
const PacketX1 packets[]
{
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 0, (uint8_t) ((secondWord >> 0x8) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 32, (uint8_t) ((secondWord >> 0x0) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 0 }, std::byte ((secondWord >> 0x8) & 0x7f)) },
PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 32 }, std::byte ((secondWord >> 0x0) & 0x7f)) },
};
for (const auto& packet : packets)
callback (View (packet.data()));
}
const auto statusAndChannel = (uint8_t) ((0xc << 0x4) | Utils::getChannel (firstWord));
const auto statusAndChannel = std::byte ((0xc << 0x4) | Utils::getChannel (firstWord));
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
statusAndChannel,
(uint8_t) ((v[1] >> 0x18) & 0x7f),
0) };
std::byte ((v[1] >> 0x18) & 0x7f),
std::byte { 0 }) };
callback (View (packet.data()));
return;
}
@ -309,11 +337,11 @@ struct Conversion
case 0xe: // pitch bend
{
const auto data = scaleTo14 (v[1]);
const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff);
const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
statusAndChannel,
(uint8_t) (data & 0x7f),
(uint8_t) ((data >> 7) & 0x7f)) };
std::byte (data & 0x7f),
std::byte ((data >> 7) & 0x7f)) };
callback (View (packet.data()));
return;
}