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:
parent
f1f68007c6
commit
78a12d2f57
13 changed files with 230 additions and 191 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue