git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
43
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMP.h
vendored
Normal file
43
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMP.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../juce_MidiDataConcatenator.h"
|
||||
|
||||
#include "juce_UMPProtocols.h"
|
||||
#include "juce_UMPUtils.h"
|
||||
#include "juce_UMPacket.h"
|
||||
#include "juce_UMPSysEx7.h"
|
||||
#include "juce_UMPView.h"
|
||||
#include "juce_UMPIterator.h"
|
||||
#include "juce_UMPackets.h"
|
||||
#include "juce_UMPFactory.h"
|
||||
#include "juce_UMPConversion.h"
|
||||
#include "juce_UMPMidi1ToBytestreamTranslator.h"
|
||||
#include "juce_UMPMidi1ToMidi2DefaultTranslator.h"
|
||||
#include "juce_UMPConverters.h"
|
||||
#include "juce_UMPDispatcher.h"
|
||||
#include "juce_UMPReceiver.h"
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace ump = universal_midi_packets;
|
||||
}
|
326
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h
vendored
Normal file
326
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Functions to assist conversion of UMP messages to/from other formats,
|
||||
especially older 'bytestream' formatted MidiMessages.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct Conversion
|
||||
{
|
||||
/** Converts from a MIDI 1 bytestream to MIDI 1 on Universal MIDI Packets.
|
||||
|
||||
`callback` is a function which accepts a single View argument.
|
||||
*/
|
||||
template <typename PacketCallbackFunction>
|
||||
static void toMidi1 (const MidiMessage& m, PacketCallbackFunction&& callback)
|
||||
{
|
||||
const auto* data = m.getRawData();
|
||||
const auto firstByte = data[0];
|
||||
const auto size = m.getRawDataSize();
|
||||
|
||||
if (firstByte != 0xf0)
|
||||
{
|
||||
const auto mask = [size]() -> uint32_t
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: return 0xff000000;
|
||||
case 1: return 0xffff0000;
|
||||
case 2: return 0xffffff00;
|
||||
case 3: return 0xffffffff;
|
||||
}
|
||||
|
||||
return 0x00000000;
|
||||
}();
|
||||
|
||||
const auto extraByte = (uint8_t) ((((firstByte & 0xf0) == 0xf0) ? 0x1 : 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 numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes);
|
||||
auto* dataOffset = m.getSysExData();
|
||||
|
||||
if (numMessages <= 1)
|
||||
{
|
||||
const auto packet = Factory::makeSysExIn1Packet (0, (uint8_t) numSysExBytes, dataOffset);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr auto byteIncrement = 6;
|
||||
|
||||
for (auto i = numSysExBytes; i > 0; i -= byteIncrement, dataOffset += byteIncrement)
|
||||
{
|
||||
const auto func = [&]
|
||||
{
|
||||
if (i == numSysExBytes)
|
||||
return Factory::makeSysExStart;
|
||||
|
||||
if (i <= byteIncrement)
|
||||
return Factory::makeSysExEnd;
|
||||
|
||||
return Factory::makeSysExContinue;
|
||||
}();
|
||||
|
||||
const auto bytesNow = std::min (byteIncrement, i);
|
||||
const auto packet = func (0, (uint8_t) bytesNow, dataOffset);
|
||||
callback (View (packet.data()));
|
||||
}
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
const auto shifted = (uint8_t) (word7Bit << 0x1);
|
||||
const auto repeat = (uint8_t) (word7Bit & 0x3f);
|
||||
const auto mask = (uint8_t) (word7Bit <= 0x40 ? 0x0 : 0xff);
|
||||
return (uint8_t) (shifted | ((repeat >> 5) & mask));
|
||||
}
|
||||
|
||||
/** Widens a 7-bit MIDI 1.0 value to a 16-bit MIDI 2.0 value. */
|
||||
static uint16_t scaleTo16 (uint8_t word7Bit)
|
||||
{
|
||||
const auto shifted = (uint16_t) (word7Bit << 0x9);
|
||||
const auto repeat = (uint16_t) (word7Bit & 0x3f);
|
||||
const auto mask = (uint16_t) (word7Bit <= 0x40 ? 0x0 : 0xffff);
|
||||
return (uint16_t) (shifted | (((repeat << 3) | (repeat >> 3)) & mask));
|
||||
}
|
||||
|
||||
/** Widens a 14-bit MIDI 1.0 value to a 16-bit MIDI 2.0 value. */
|
||||
static uint16_t scaleTo16 (uint16_t word14Bit)
|
||||
{
|
||||
const auto shifted = (uint16_t) (word14Bit << 0x2);
|
||||
const auto repeat = (uint16_t) (word14Bit & 0x1fff);
|
||||
const auto mask = (uint16_t) (word14Bit <= 0x2000 ? 0x0 : 0xffff);
|
||||
return (uint16_t) (shifted | ((repeat >> 11) & mask));
|
||||
}
|
||||
|
||||
/** Widens a 7-bit MIDI 1.0 value to a 32-bit MIDI 2.0 value. */
|
||||
static uint32_t scaleTo32 (uint8_t word7Bit)
|
||||
{
|
||||
const auto shifted = (uint32_t) (word7Bit << 0x19);
|
||||
const auto repeat = (uint32_t) (word7Bit & 0x3f);
|
||||
const auto mask = (uint32_t) (word7Bit <= 0x40 ? 0x0 : 0xffffffff);
|
||||
return (uint32_t) (shifted | (((repeat << 19)
|
||||
| (repeat << 13)
|
||||
| (repeat << 7)
|
||||
| (repeat << 1)
|
||||
| (repeat >> 5)) & mask));
|
||||
}
|
||||
|
||||
/** Widens a 14-bit MIDI 1.0 value to a 32-bit MIDI 2.0 value. */
|
||||
static uint32_t scaleTo32 (uint16_t word14Bit)
|
||||
{
|
||||
const auto shifted = (uint32_t) (word14Bit << 0x12);
|
||||
const auto repeat = (uint32_t) (word14Bit & 0x1fff);
|
||||
const auto mask = (uint32_t) (word14Bit <= 0x2000 ? 0x0 : 0xffffffff);
|
||||
return (uint32_t) (shifted | (((repeat << 5) | (repeat >> 8)) & mask));
|
||||
}
|
||||
|
||||
/** Narrows a 16-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */
|
||||
static uint8_t scaleTo7 (uint8_t word8Bit) { return (uint8_t) (word8Bit >> 1); }
|
||||
|
||||
/** Narrows a 16-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */
|
||||
static uint8_t scaleTo7 (uint16_t word16Bit) { return (uint8_t) (word16Bit >> 9); }
|
||||
|
||||
/** Narrows a 32-bit MIDI 2.0 value to a 7-bit MIDI 1.0 value. */
|
||||
static uint8_t scaleTo7 (uint32_t word32Bit) { return (uint8_t) (word32Bit >> 25); }
|
||||
|
||||
/** Narrows a 32-bit MIDI 2.0 value to a 14-bit MIDI 1.0 value. */
|
||||
static uint16_t scaleTo14 (uint16_t word16Bit) { return (uint16_t) (word16Bit >> 2); }
|
||||
|
||||
/** Narrows a 32-bit MIDI 2.0 value to a 14-bit MIDI 1.0 value. */
|
||||
static uint16_t scaleTo14 (uint32_t word32Bit) { return (uint16_t) (word32Bit >> 18); }
|
||||
|
||||
/** Converts UMP messages which may include MIDI 2.0 channel voice messages into
|
||||
equivalent MIDI 1.0 messages (still in UMP format).
|
||||
|
||||
`callback` is a function that accepts a single View argument and will be
|
||||
called with each converted packet.
|
||||
|
||||
Note that not all MIDI 2.0 messages have MIDI 1.0 equivalents, so such
|
||||
messages will be ignored.
|
||||
*/
|
||||
template <typename Callback>
|
||||
static void midi2ToMidi1DefaultTranslation (const View& v, Callback&& callback)
|
||||
{
|
||||
const auto firstWord = v[0];
|
||||
|
||||
if (Utils::getMessageType (firstWord) != 0x4)
|
||||
{
|
||||
callback (v);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto status = Utils::getStatus (firstWord);
|
||||
const auto typeAndGroup = (uint8_t) ((0x2 << 0x4) | Utils::getGroup (firstWord));
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 0x8: // note off
|
||||
case 0x9: // note on
|
||||
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]);
|
||||
|
||||
// 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 shouldIgnore = status == 0xb && [&]
|
||||
{
|
||||
switch (byte2)
|
||||
{
|
||||
case 0:
|
||||
case 6:
|
||||
case 32:
|
||||
case 38:
|
||||
case 98:
|
||||
case 99:
|
||||
case 100:
|
||||
case 101:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (shouldIgnore)
|
||||
return;
|
||||
|
||||
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
|
||||
statusAndChannel,
|
||||
byte2,
|
||||
correctedByte) };
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xd: // channel pressure
|
||||
{
|
||||
const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff);
|
||||
const auto byte2 = scaleTo7 (v[1]);
|
||||
|
||||
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
|
||||
statusAndChannel,
|
||||
byte2,
|
||||
0) };
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
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 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)) },
|
||||
};
|
||||
|
||||
for (const auto& packet : packets)
|
||||
callback (View (packet.data()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xc: // program change / bank select
|
||||
{
|
||||
if (firstWord & 1)
|
||||
{
|
||||
const auto statusAndChannel = (uint8_t) ((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)) },
|
||||
};
|
||||
|
||||
for (const auto& packet : packets)
|
||||
callback (View (packet.data()));
|
||||
}
|
||||
|
||||
const auto statusAndChannel = (uint8_t) ((0xc << 0x4) | Utils::getChannel (firstWord));
|
||||
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
|
||||
statusAndChannel,
|
||||
(uint8_t) ((v[1] >> 0x18) & 0x7f),
|
||||
0) };
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xe: // pitch bend
|
||||
{
|
||||
const auto data = scaleTo14 (v[1]);
|
||||
const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff);
|
||||
const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
|
||||
statusAndChannel,
|
||||
(uint8_t) (data & 0x7f),
|
||||
(uint8_t) ((data >> 7) & 0x7f)) };
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
default: // other message types do not translate
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
165
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h
vendored
Normal file
165
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
/**
|
||||
Allows conversion from bytestream- or Universal MIDI Packet-formatted
|
||||
messages to MIDI 1.0 messages in UMP format.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct ToUMP1Converter
|
||||
{
|
||||
template <typename Fn>
|
||||
void convert (const MidiMessage& m, Fn&& fn)
|
||||
{
|
||||
Conversion::toMidi1 (m, std::forward<Fn> (fn));
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const View& v, Fn&& fn)
|
||||
{
|
||||
Conversion::midi2ToMidi1DefaultTranslation (v, std::forward<Fn> (fn));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Allows conversion from bytestream- or Universal MIDI Packet-formatted
|
||||
messages to MIDI 2.0 messages in UMP format.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct ToUMP2Converter
|
||||
{
|
||||
template <typename Fn>
|
||||
void convert (const MidiMessage& m, Fn&& fn)
|
||||
{
|
||||
Conversion::toMidi1 (m, [&] (const View& v)
|
||||
{
|
||||
translator.dispatch (v, fn);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const View& v, Fn&& fn)
|
||||
{
|
||||
translator.dispatch (v, std::forward<Fn> (fn));
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
translator.reset();
|
||||
}
|
||||
|
||||
Midi1ToMidi2DefaultTranslator translator;
|
||||
};
|
||||
|
||||
/**
|
||||
Allows conversion from bytestream- or Universal MIDI Packet-formatted
|
||||
messages to UMP format.
|
||||
|
||||
The packet protocol can be selected using the constructor parameter.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class GenericUMPConverter
|
||||
{
|
||||
public:
|
||||
explicit GenericUMPConverter (PacketProtocol m)
|
||||
: mode (m) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
std::get<1> (converters).reset();
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const MidiMessage& m, Fn&& fn)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (m, std::forward<Fn> (fn));
|
||||
case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (m, std::forward<Fn> (fn));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const View& v, Fn&& fn)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (v, std::forward<Fn> (fn));
|
||||
case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (v, std::forward<Fn> (fn));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (Iterator begin, Iterator end, Fn&& fn)
|
||||
{
|
||||
std::for_each (begin, end, [&] (const View& v)
|
||||
{
|
||||
convert (v, fn);
|
||||
});
|
||||
}
|
||||
|
||||
PacketProtocol getProtocol() const noexcept { return mode; }
|
||||
|
||||
private:
|
||||
std::tuple<ToUMP1Converter, ToUMP2Converter> converters;
|
||||
const PacketProtocol mode{};
|
||||
};
|
||||
|
||||
/**
|
||||
Allows conversion from bytestream- or Universal MIDI Packet-formatted
|
||||
messages to bytestream format.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct ToBytestreamConverter
|
||||
{
|
||||
explicit ToBytestreamConverter (int storageSize)
|
||||
: translator (storageSize) {}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const MidiMessage& m, Fn&& fn)
|
||||
{
|
||||
fn (m);
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void convert (const View& v, double time, Fn&& fn)
|
||||
{
|
||||
Conversion::midi2ToMidi1DefaultTranslation (v, [&] (const View& midi1)
|
||||
{
|
||||
translator.dispatch (midi1, time, fn);
|
||||
});
|
||||
}
|
||||
|
||||
void reset() { translator.reset(); }
|
||||
|
||||
Midi1ToBytestreamTranslator translator;
|
||||
};
|
||||
}
|
||||
}
|
198
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h
vendored
Normal file
198
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Parses a raw stream of uint32_t, and calls a user-provided callback every time
|
||||
a full Universal MIDI Packet is encountered.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class Dispatcher
|
||||
{
|
||||
public:
|
||||
/** Clears the dispatcher. */
|
||||
void reset() { currentPacketLen = 0; }
|
||||
|
||||
/** Calls `callback` with a View of each packet encountered in the range delimited
|
||||
by `begin` and `end`.
|
||||
|
||||
If the range ends part-way through a packet, the next call to `dispatch` will
|
||||
continue from that point in the packet (unless `reset` is called first).
|
||||
*/
|
||||
template <typename PacketCallbackFunction>
|
||||
void dispatch (const uint32_t* begin,
|
||||
const uint32_t* end,
|
||||
double timeStamp,
|
||||
PacketCallbackFunction&& callback)
|
||||
{
|
||||
std::for_each (begin, end, [&] (uint32_t word)
|
||||
{
|
||||
nextPacket[currentPacketLen++] = word;
|
||||
|
||||
if (currentPacketLen == Utils::getNumWordsForMessageType (nextPacket.front()))
|
||||
{
|
||||
callback (View (nextPacket.data()), timeStamp);
|
||||
currentPacketLen = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint32_t, 4> nextPacket;
|
||||
size_t currentPacketLen = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Parses a stream of bytes representing a sequence of bytestream-encoded MIDI 1.0 messages,
|
||||
converting the messages to UMP format and passing the packets to a user-provided callback
|
||||
as they become ready.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class BytestreamToUMPDispatcher
|
||||
{
|
||||
public:
|
||||
/** Initialises the dispatcher.
|
||||
|
||||
Channel messages will be converted to the requested protocol format `pp`.
|
||||
`storageSize` bytes will be allocated to store incomplete messages.
|
||||
*/
|
||||
explicit BytestreamToUMPDispatcher (PacketProtocol pp, int storageSize)
|
||||
: concatenator (storageSize),
|
||||
converter (pp)
|
||||
{}
|
||||
|
||||
void reset()
|
||||
{
|
||||
concatenator.reset();
|
||||
converter.reset();
|
||||
}
|
||||
|
||||
/** Calls `callback` with a View of each converted packet as it becomes ready.
|
||||
|
||||
@param begin the first byte in a range of bytes representing bytestream-encoded MIDI messages.
|
||||
@param end one-past the last byte in a range of bytes representing bytestream-encoded MIDI messages.
|
||||
@param timestamp a timestamp to apply to the created packets.
|
||||
@param callback a callback which will be passed a View pointing to each new packet as it becomes ready.
|
||||
*/
|
||||
template <typename PacketCallbackFunction>
|
||||
void dispatch (const uint8_t* begin,
|
||||
const uint8_t* end,
|
||||
double timestamp,
|
||||
PacketCallbackFunction&& callback)
|
||||
{
|
||||
using CallbackPtr = decltype (std::addressof (callback));
|
||||
|
||||
#if JUCE_MINGW
|
||||
#define JUCE_MINGW_HIDDEN_VISIBILITY __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define JUCE_MINGW_HIDDEN_VISIBILITY
|
||||
#endif
|
||||
|
||||
struct JUCE_MINGW_HIDDEN_VISIBILITY Callback
|
||||
{
|
||||
Callback (BytestreamToUMPDispatcher& d, CallbackPtr c)
|
||||
: dispatch (d), callbackPtr (c) {}
|
||||
|
||||
void handleIncomingMidiMessage (void*, const MidiMessage& msg) const
|
||||
{
|
||||
Conversion::toMidi1 (msg, [&] (const View& view)
|
||||
{
|
||||
dispatch.converter.convert (view, *callbackPtr);
|
||||
});
|
||||
}
|
||||
|
||||
void handlePartialSysexMessage (void*, const uint8_t*, int, double) const {}
|
||||
|
||||
BytestreamToUMPDispatcher& dispatch;
|
||||
CallbackPtr callbackPtr = nullptr;
|
||||
};
|
||||
|
||||
#undef JUCE_MINGW_HIDDEN_VISIBILITY
|
||||
|
||||
Callback inputCallback { *this, &callback };
|
||||
concatenator.pushMidiData (begin, int (end - begin), timestamp, (void*) nullptr, inputCallback);
|
||||
}
|
||||
|
||||
private:
|
||||
MidiDataConcatenator concatenator;
|
||||
GenericUMPConverter converter;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Parses a stream of 32-bit words representing a sequence of UMP-encoded MIDI messages,
|
||||
converting the messages to MIDI 1.0 bytestream format and passing them to a user-provided
|
||||
callback as they become ready.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class ToBytestreamDispatcher
|
||||
{
|
||||
public:
|
||||
/** Initialises the dispatcher.
|
||||
|
||||
`storageSize` bytes will be allocated to store incomplete messages.
|
||||
*/
|
||||
explicit ToBytestreamDispatcher (int storageSize)
|
||||
: converter (storageSize) {}
|
||||
|
||||
/** Clears the dispatcher. */
|
||||
void reset()
|
||||
{
|
||||
dispatcher.reset();
|
||||
converter.reset();
|
||||
}
|
||||
|
||||
/** Calls `callback` with converted bytestream-formatted MidiMessage whenever
|
||||
a new message becomes available.
|
||||
|
||||
@param begin the first word in a stream of words representing UMP-encoded MIDI packets.
|
||||
@param end one-past the last word in a stream of words representing UMP-encoded MIDI packets.
|
||||
@param timestamp a timestamp to apply to converted messages.
|
||||
@param callback a callback which will be passed a MidiMessage each time a new message becomes ready.
|
||||
*/
|
||||
template <typename BytestreamMessageCallback>
|
||||
void dispatch (const uint32_t* begin,
|
||||
const uint32_t* end,
|
||||
double timestamp,
|
||||
BytestreamMessageCallback&& callback)
|
||||
{
|
||||
dispatcher.dispatch (begin, end, timestamp, [&] (const View& view, double time)
|
||||
{
|
||||
converter.convert (view, time, callback);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
Dispatcher dispatcher;
|
||||
ToBytestreamConverter converter;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
534
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h
vendored
Normal file
534
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h
vendored
Normal file
@ -0,0 +1,534 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
This struct holds functions that can be used to create different kinds
|
||||
of Universal MIDI Packet.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct Factory
|
||||
{
|
||||
/** @internal */
|
||||
struct Detail
|
||||
{
|
||||
static PacketX1 makeSystem() { return PacketX1{}.withMessageType (1); }
|
||||
static PacketX1 makeV1() { return PacketX1{}.withMessageType (2); }
|
||||
static PacketX2 makeV2() { return PacketX2{}.withMessageType (4); }
|
||||
|
||||
static PacketX2 makeSysEx (uint8_t group,
|
||||
uint8_t status,
|
||||
uint8_t numBytes,
|
||||
const uint8_t* data)
|
||||
{
|
||||
jassert (numBytes <= 6);
|
||||
|
||||
std::array<uint8_t, 8> bytes{{}};
|
||||
bytes[0] = (0x3 << 0x4) | group;
|
||||
bytes[1] = (uint8_t) (status << 0x4) | numBytes;
|
||||
|
||||
std::memcpy (bytes.data() + 2, data, numBytes);
|
||||
|
||||
std::array<uint32_t, 2> words;
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
for (auto& word : words)
|
||||
word = ByteOrder::bigEndianInt (bytes.data() + 4 * index++);
|
||||
|
||||
return PacketX2 { words };
|
||||
}
|
||||
|
||||
static PacketX4 makeSysEx8 (uint8_t group,
|
||||
uint8_t status,
|
||||
uint8_t numBytes,
|
||||
uint8_t dataStart,
|
||||
const uint8_t* data)
|
||||
{
|
||||
jassert (numBytes <= 16 - dataStart);
|
||||
|
||||
std::array<uint8_t, 16> bytes{{}};
|
||||
bytes[0] = (0x5 << 0x4) | group;
|
||||
bytes[1] = (uint8_t) (status << 0x4) | numBytes;
|
||||
|
||||
std::memcpy (bytes.data() + dataStart, data, numBytes);
|
||||
|
||||
std::array<uint32_t, 4> words;
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
for (auto& word : words)
|
||||
word = ByteOrder::bigEndianInt (bytes.data() + 4 * index++);
|
||||
|
||||
return PacketX4 { words };
|
||||
}
|
||||
};
|
||||
|
||||
static PacketX1 makeNoop (uint8_t group)
|
||||
{
|
||||
return PacketX1{}.withGroup (group);
|
||||
}
|
||||
|
||||
static PacketX1 makeJRClock (uint8_t group, uint16_t time)
|
||||
{
|
||||
return PacketX1 { time }.withStatus (1).withGroup (group);
|
||||
}
|
||||
|
||||
static PacketX1 makeJRTimestamp (uint8_t group, uint16_t time)
|
||||
{
|
||||
return PacketX1 { time }.withStatus (2).withGroup (group);
|
||||
}
|
||||
|
||||
static PacketX1 makeTimeCode (uint8_t group, uint8_t code)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xf1)
|
||||
.withU8<2> (code & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeSongPositionPointer (uint8_t group, uint16_t pos)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xf2)
|
||||
.withU8<2> (pos & 0x7f)
|
||||
.withU8<3> ((pos >> 7) & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeSongSelect (uint8_t group, uint8_t song)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xf3)
|
||||
.withU8<2> (song & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeTuneRequest (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xf6);
|
||||
}
|
||||
|
||||
static PacketX1 makeTimingClock (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xf8);
|
||||
}
|
||||
|
||||
static PacketX1 makeStart (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xfa);
|
||||
}
|
||||
|
||||
static PacketX1 makeContinue (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xfb);
|
||||
}
|
||||
|
||||
static PacketX1 makeStop (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xfc);
|
||||
}
|
||||
|
||||
static PacketX1 makeActiveSensing (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xfe);
|
||||
}
|
||||
|
||||
static PacketX1 makeReset (uint8_t group)
|
||||
{
|
||||
return Detail::makeSystem().withGroup (group)
|
||||
.withU8<1> (0xff);
|
||||
}
|
||||
|
||||
static PacketX1 makeNoteOffV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t velocity)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0x8)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> (velocity & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeNoteOnV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t velocity)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0x9)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> (velocity & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makePolyPressureV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t pressure)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0xa)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> (pressure & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeControlChangeV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t controller,
|
||||
uint8_t value)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0xb)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (controller & 0x7f)
|
||||
.withU8<3> (value & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeProgramChangeV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t program)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0xc)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (program & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makeChannelPressureV1 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t pressure)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0xd)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (pressure & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX1 makePitchBend (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint16_t pitchbend)
|
||||
{
|
||||
return Detail::makeV1().withGroup (group)
|
||||
.withStatus (0xe)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (pitchbend & 0x7f)
|
||||
.withU8<3> ((pitchbend >> 7) & 0x7f);
|
||||
}
|
||||
|
||||
static PacketX2 makeSysExIn1Packet (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx (group, 0x0, numBytes, data);
|
||||
}
|
||||
|
||||
static PacketX2 makeSysExStart (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx (group, 0x1, numBytes, data);
|
||||
}
|
||||
|
||||
static PacketX2 makeSysExContinue (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx (group, 0x2, numBytes, data);
|
||||
}
|
||||
|
||||
static PacketX2 makeSysExEnd (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx (group, 0x3, numBytes, data);
|
||||
}
|
||||
|
||||
static PacketX2 makeRegisteredPerNoteControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t controller,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x0)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> (controller & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeAssignablePerNoteControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t controller,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x1)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> (controller & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeRegisteredControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t bank,
|
||||
uint8_t index,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x2)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (bank & 0x7f)
|
||||
.withU8<3> (index & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeAssignableControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t bank,
|
||||
uint8_t index,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x3)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (bank & 0x7f)
|
||||
.withU8<3> (index & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeRelativeRegisteredControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t bank,
|
||||
uint8_t index,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x4)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (bank & 0x7f)
|
||||
.withU8<3> (index & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeRelativeAssignableControllerV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t bank,
|
||||
uint8_t index,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x5)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (bank & 0x7f)
|
||||
.withU8<3> (index & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makePerNotePitchBendV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x6)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
enum class NoteAttributeKind : uint8_t
|
||||
{
|
||||
none = 0x00,
|
||||
manufacturer = 0x01,
|
||||
profile = 0x02,
|
||||
pitch7_9 = 0x03
|
||||
};
|
||||
|
||||
static PacketX2 makeNoteOffV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
NoteAttributeKind attribute,
|
||||
uint16_t velocity,
|
||||
uint16_t attributeValue)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x8)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> ((uint8_t) attribute)
|
||||
.withU16<2> (velocity)
|
||||
.withU16<3> (attributeValue);
|
||||
}
|
||||
|
||||
static PacketX2 makeNoteOnV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
NoteAttributeKind attribute,
|
||||
uint16_t velocity,
|
||||
uint16_t attributeValue)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0x9)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU8<3> ((uint8_t) attribute)
|
||||
.withU16<2> (velocity)
|
||||
.withU16<3> (attributeValue);
|
||||
}
|
||||
|
||||
static PacketX2 makePolyPressureV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xa)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeControlChangeV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t controller,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xb)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (controller & 0x7f)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makeProgramChangeV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t optionFlags,
|
||||
uint8_t program,
|
||||
uint8_t bankMsb,
|
||||
uint8_t bankLsb)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xc)
|
||||
.withChannel (channel)
|
||||
.withU8<3> (optionFlags)
|
||||
.withU8<4> (program)
|
||||
.withU8<6> (bankMsb)
|
||||
.withU8<7> (bankLsb);
|
||||
}
|
||||
|
||||
static PacketX2 makeChannelPressureV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xd)
|
||||
.withChannel (channel)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makePitchBendV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint32_t data)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xe)
|
||||
.withChannel (channel)
|
||||
.withU32<1> (data);
|
||||
}
|
||||
|
||||
static PacketX2 makePerNoteManagementV2 (uint8_t group,
|
||||
uint8_t channel,
|
||||
uint8_t note,
|
||||
uint8_t optionFlags)
|
||||
{
|
||||
return Detail::makeV2().withGroup (group)
|
||||
.withStatus (0xf)
|
||||
.withChannel (channel)
|
||||
.withU8<2> (note)
|
||||
.withU8<3> (optionFlags);
|
||||
}
|
||||
|
||||
|
||||
static PacketX4 makeSysEx8in1Packet (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
uint8_t streamId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x0, numBytes, 3, data).withU8<2> (streamId);
|
||||
}
|
||||
|
||||
static PacketX4 makeSysEx8Start (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
uint8_t streamId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x1, numBytes, 3, data).withU8<2> (streamId);
|
||||
}
|
||||
|
||||
static PacketX4 makeSysEx8Continue (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
uint8_t streamId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x2, numBytes, 3, data).withU8<2> (streamId);
|
||||
}
|
||||
|
||||
static PacketX4 makeSysEx8End (uint8_t group,
|
||||
uint8_t numBytes,
|
||||
uint8_t streamId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x3, numBytes, 3, data).withU8<2> (streamId);
|
||||
}
|
||||
|
||||
static PacketX4 makeMixedDataSetHeader (uint8_t group,
|
||||
uint8_t dataSetId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x8, 14, 2, data).withChannel (dataSetId);
|
||||
}
|
||||
|
||||
static PacketX4 makeDataSetPayload (uint8_t group,
|
||||
uint8_t dataSetId,
|
||||
const uint8_t* data)
|
||||
{
|
||||
return Detail::makeSysEx8 (group, 0x9, 14, 2, data).withChannel (dataSetId);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
126
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h
vendored
Normal file
126
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPIterator.h
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Enables iteration over a collection of Universal MIDI Packets stored as
|
||||
a contiguous range of 32-bit words.
|
||||
|
||||
This iterator is used by Packets to allow access to the messages
|
||||
that it contains.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
/** Creates an invalid (singular) iterator. */
|
||||
Iterator() noexcept = default;
|
||||
|
||||
/** Creates an iterator pointing at `ptr`. */
|
||||
explicit Iterator (const uint32_t* ptr, size_t bytes) noexcept
|
||||
: view (ptr)
|
||||
#if JUCE_DEBUG
|
||||
, bytesRemaining (bytes)
|
||||
#endif
|
||||
{
|
||||
ignoreUnused (bytes);
|
||||
}
|
||||
|
||||
using difference_type = std::iterator_traits<const uint32_t*>::difference_type;
|
||||
using value_type = View;
|
||||
using reference = const View&;
|
||||
using pointer = const View*;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
/** Moves this iterator to the next packet in the range. */
|
||||
Iterator& operator++() noexcept
|
||||
{
|
||||
const auto increment = view.size();
|
||||
|
||||
#if JUCE_DEBUG
|
||||
// If you hit this, the memory region contained a truncated or otherwise
|
||||
// malformed Universal MIDI Packet.
|
||||
// The Iterator can only be used on regions containing complete packets!
|
||||
jassert (increment <= bytesRemaining);
|
||||
bytesRemaining -= increment;
|
||||
#endif
|
||||
|
||||
view = View (view.data() + increment);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Moves this iterator to the next packet in the range,
|
||||
returning the value of the iterator before it was
|
||||
incremented.
|
||||
*/
|
||||
Iterator operator++ (int) noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
++(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Returns true if this iterator points to the same address
|
||||
as another iterator.
|
||||
*/
|
||||
bool operator== (const Iterator& other) const noexcept
|
||||
{
|
||||
return view == other.view;
|
||||
}
|
||||
|
||||
/** Returns false if this iterator points to the same address
|
||||
as another iterator.
|
||||
*/
|
||||
bool operator!= (const Iterator& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
/** Returns a reference to a View of the packet currently
|
||||
pointed-to by this iterator.
|
||||
|
||||
The View can be queried for its size and content.
|
||||
*/
|
||||
reference operator*() noexcept { return view; }
|
||||
|
||||
/** Returns a pointer to a View of the packet currently
|
||||
pointed-to by this iterator.
|
||||
|
||||
The View can be queried for its size and content.
|
||||
*/
|
||||
pointer operator->() noexcept { return &view; }
|
||||
|
||||
private:
|
||||
View view;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
size_t bytesRemaining = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
}
|
213
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h
vendored
Normal file
213
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Parses a raw stream of uint32_t holding a series of Universal MIDI Packets using
|
||||
the MIDI 1.0 Protocol, converting to plain (non-UMP) MidiMessages.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class Midi1ToBytestreamTranslator
|
||||
{
|
||||
public:
|
||||
/** Ensures that there is room in the internal buffer for a sysex message of at least
|
||||
`initialBufferSize` bytes.
|
||||
*/
|
||||
explicit Midi1ToBytestreamTranslator (int initialBufferSize)
|
||||
{
|
||||
pendingSysExData.reserve (size_t (initialBufferSize));
|
||||
}
|
||||
|
||||
/** Clears the concatenator. */
|
||||
void reset()
|
||||
{
|
||||
pendingSysExData.clear();
|
||||
pendingSysExTime = 0.0;
|
||||
}
|
||||
|
||||
/** Converts a Universal MIDI Packet using the MIDI 1.0 Protocol to
|
||||
an equivalent MidiMessage. Accumulates SysEx packets into a single
|
||||
MidiMessage, as appropriate.
|
||||
|
||||
@param packet a packet which is using the MIDI 1.0 Protocol.
|
||||
@param time the timestamp to be applied to these messages.
|
||||
@param callback a callback which will be called with each converted MidiMessage.
|
||||
*/
|
||||
template <typename MessageCallback>
|
||||
void dispatch (const View& packet, double time, MessageCallback&& callback)
|
||||
{
|
||||
const auto firstWord = *packet.data();
|
||||
|
||||
if (! pendingSysExData.empty() && shouldPacketTerminateSysExEarly (firstWord))
|
||||
pendingSysExData.clear();
|
||||
|
||||
switch (packet.size())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
// Utility messages don't translate to bytestream format
|
||||
if (Utils::getMessageType (firstWord) != 0x00)
|
||||
callback (fromUmp (PacketX1 { firstWord }, time));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (Utils::getMessageType (firstWord) == 0x3)
|
||||
processSysEx (PacketX2 { packet[0], packet[1] }, time, callback);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // no 3-word packets in the current spec
|
||||
case 4: // no 4-word packets translate to bytestream format
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts from a Universal MIDI Packet to MIDI 1 bytestream format.
|
||||
|
||||
This is only capable of converting a single Universal MIDI Packet to
|
||||
an equivalent bytestream MIDI message. This function cannot understand
|
||||
multi-packet messages, like SysEx7 messages.
|
||||
|
||||
To convert multi-packet messages, use `Midi1ToBytestreamTranslator`
|
||||
to convert from a UMP MIDI 1.0 stream, or `ToBytestreamDispatcher`
|
||||
to convert from both MIDI 2.0 and MIDI 1.0.
|
||||
*/
|
||||
static MidiMessage fromUmp (const PacketX1& m, double time = 0)
|
||||
{
|
||||
const auto word = m.front();
|
||||
jassert (Utils::getNumWordsForMessageType (word) == 1);
|
||||
|
||||
const std::array<uint8_t, 3> bytes { { uint8_t ((word >> 0x10) & 0xff),
|
||||
uint8_t ((word >> 0x08) & 0xff),
|
||||
uint8_t ((word >> 0x00) & 0xff) } };
|
||||
const auto numBytes = MidiMessage::getMessageLengthFromFirstByte (bytes.front());
|
||||
return MidiMessage (bytes.data(), numBytes, time);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename MessageCallback>
|
||||
void processSysEx (const PacketX2& packet,
|
||||
double time,
|
||||
MessageCallback&& callback)
|
||||
{
|
||||
switch (getSysEx7Kind (packet[0]))
|
||||
{
|
||||
case SysEx7::Kind::complete:
|
||||
startSysExMessage (time);
|
||||
pushBytes (packet);
|
||||
terminateSysExMessage (callback);
|
||||
break;
|
||||
|
||||
case SysEx7::Kind::begin:
|
||||
startSysExMessage (time);
|
||||
pushBytes (packet);
|
||||
break;
|
||||
|
||||
case SysEx7::Kind::continuation:
|
||||
if (pendingSysExData.empty())
|
||||
break;
|
||||
|
||||
pushBytes (packet);
|
||||
break;
|
||||
|
||||
case SysEx7::Kind::end:
|
||||
if (pendingSysExData.empty())
|
||||
break;
|
||||
|
||||
pushBytes (packet);
|
||||
terminateSysExMessage (callback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pushBytes (const PacketX2& packet)
|
||||
{
|
||||
const auto bytes = SysEx7::getDataBytes (packet);
|
||||
pendingSysExData.insert (pendingSysExData.end(),
|
||||
bytes.data.begin(),
|
||||
bytes.data.begin() + bytes.size);
|
||||
}
|
||||
|
||||
void startSysExMessage (double time)
|
||||
{
|
||||
pendingSysExTime = time;
|
||||
pendingSysExData.push_back (0xf0);
|
||||
}
|
||||
|
||||
template <typename MessageCallback>
|
||||
void terminateSysExMessage (MessageCallback&& callback)
|
||||
{
|
||||
pendingSysExData.push_back (0xf7);
|
||||
callback (MidiMessage (pendingSysExData.data(),
|
||||
int (pendingSysExData.size()),
|
||||
pendingSysExTime));
|
||||
pendingSysExData.clear();
|
||||
}
|
||||
|
||||
static bool shouldPacketTerminateSysExEarly (uint32_t firstWord)
|
||||
{
|
||||
return ! (isSysExContinuation (firstWord)
|
||||
|| isSystemRealTime (firstWord)
|
||||
|| isJROrNOP (firstWord));
|
||||
}
|
||||
|
||||
static SysEx7::Kind getSysEx7Kind (uint32_t word)
|
||||
{
|
||||
return SysEx7::Kind ((word >> 0x14) & 0xf);
|
||||
}
|
||||
|
||||
static bool isJROrNOP (uint32_t word)
|
||||
{
|
||||
return Utils::getMessageType (word) == 0x0;
|
||||
}
|
||||
|
||||
static bool isSysExContinuation (uint32_t word)
|
||||
{
|
||||
if (Utils::getMessageType (word) != 0x3)
|
||||
return false;
|
||||
|
||||
const auto kind = getSysEx7Kind (word);
|
||||
return kind == SysEx7::Kind::continuation || kind == SysEx7::Kind::end;
|
||||
}
|
||||
|
||||
static bool isSystemRealTime (uint32_t word)
|
||||
{
|
||||
return Utils::getMessageType (word) == 0x1 && ((word >> 0x10) & 0xff) >= 0xf8;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> pendingSysExData;
|
||||
|
||||
double pendingSysExTime = 0.0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
195
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp
vendored
Normal file
195
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
PacketX2 Midi1ToMidi2DefaultTranslator::processNoteOnOrOff (const HelperValues helpers)
|
||||
{
|
||||
const auto velocity = helpers.byte2;
|
||||
const auto needsConversion = (helpers.byte0 >> 0x4) == 0x9 && velocity == 0;
|
||||
const auto firstByte = needsConversion ? (uint8_t) ((0x8 << 0x4) | (helpers.byte0 & 0xf))
|
||||
: helpers.byte0;
|
||||
|
||||
return PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, firstByte, helpers.byte1, 0),
|
||||
(uint32_t) (Conversion::scaleTo16 (velocity) << 0x10)
|
||||
};
|
||||
}
|
||||
|
||||
PacketX2 Midi1ToMidi2DefaultTranslator::processPolyPressure (const HelperValues helpers)
|
||||
{
|
||||
return PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, helpers.byte1, 0),
|
||||
Conversion::scaleTo32 (helpers.byte2)
|
||||
};
|
||||
}
|
||||
|
||||
bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues helpers,
|
||||
PacketX2& packet)
|
||||
{
|
||||
const auto statusAndChannel = helpers.byte0;
|
||||
const auto cc = helpers.byte1;
|
||||
|
||||
const auto shouldAccumulate = [&]
|
||||
{
|
||||
switch (cc)
|
||||
{
|
||||
case 6:
|
||||
case 38:
|
||||
case 98:
|
||||
case 99:
|
||||
case 100:
|
||||
case 101:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
const auto group = (uint8_t) (helpers.typeAndGroup & 0xf);
|
||||
const auto channel = (uint8_t) (statusAndChannel & 0xf);
|
||||
const auto byte = helpers.byte2;
|
||||
|
||||
if (shouldAccumulate)
|
||||
{
|
||||
auto& accumulator = groupAccumulators[group][channel];
|
||||
|
||||
if (accumulator.addByte (cc, byte))
|
||||
{
|
||||
const auto& bytes = accumulator.getBytes();
|
||||
const auto bank = bytes[0];
|
||||
const auto index = bytes[1];
|
||||
const auto msb = bytes[2];
|
||||
const auto lsb = bytes[3];
|
||||
|
||||
const auto value = (uint16_t) (((msb & 0x7f) << 7) | (lsb & 0x7f));
|
||||
|
||||
const auto newStatus = (uint8_t) (accumulator.getKind() == PnKind::nrpn ? 0x3 : 0x2);
|
||||
|
||||
packet = PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, (uint8_t) ((newStatus << 0x4) | channel), bank, index),
|
||||
Conversion::scaleTo32 (value)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cc == 0)
|
||||
{
|
||||
groupBanks[group][channel].setMsb (byte);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cc == 32)
|
||||
{
|
||||
groupBanks[group][channel].setLsb (byte);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet = PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, statusAndChannel, cc, 0),
|
||||
Conversion::scaleTo32 (helpers.byte2)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
PacketX2 Midi1ToMidi2DefaultTranslator::processProgramChange (const HelperValues helpers) const
|
||||
{
|
||||
const auto group = (uint8_t) (helpers.typeAndGroup & 0xf);
|
||||
const auto channel = (uint8_t) (helpers.byte0 & 0xf);
|
||||
const auto bank = groupBanks[group][channel];
|
||||
const auto valid = bank.isValid();
|
||||
|
||||
return PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, valid ? 1 : 0),
|
||||
Utils::bytesToWord (helpers.byte1, 0, valid ? bank.getMsb() : 0, valid ? bank.getLsb() : 0)
|
||||
};
|
||||
}
|
||||
|
||||
PacketX2 Midi1ToMidi2DefaultTranslator::processChannelPressure (const HelperValues helpers)
|
||||
{
|
||||
return PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0),
|
||||
Conversion::scaleTo32 (helpers.byte1)
|
||||
};
|
||||
}
|
||||
|
||||
PacketX2 Midi1ToMidi2DefaultTranslator::processPitchBend (const HelperValues helpers)
|
||||
{
|
||||
const auto lsb = helpers.byte1;
|
||||
const auto msb = helpers.byte2;
|
||||
const auto value = (uint16_t) (msb << 7 | lsb);
|
||||
|
||||
return PacketX2
|
||||
{
|
||||
Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0),
|
||||
Conversion::scaleTo32 (value)
|
||||
};
|
||||
}
|
||||
|
||||
bool Midi1ToMidi2DefaultTranslator::PnAccumulator::addByte (uint8_t cc, uint8_t byte)
|
||||
{
|
||||
const auto isStart = cc == 99 || cc == 101;
|
||||
|
||||
if (isStart)
|
||||
{
|
||||
kind = cc == 99 ? PnKind::nrpn : PnKind::rpn;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
bytes[index] = byte;
|
||||
|
||||
const auto shouldContinue = [&]
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return isStart;
|
||||
case 1: return kind == PnKind::nrpn ? cc == 98 : cc == 100;
|
||||
case 2: return cc == 6;
|
||||
case 3: return cc == 38;
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
index = shouldContinue ? index + 1 : 0;
|
||||
|
||||
if (index != bytes.size())
|
||||
return false;
|
||||
|
||||
index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
187
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h
vendored
Normal file
187
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Translates a series of MIDI 1 Universal MIDI Packets to corresponding MIDI 2
|
||||
packets.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class Midi1ToMidi2DefaultTranslator
|
||||
{
|
||||
public:
|
||||
Midi1ToMidi2DefaultTranslator() = default;
|
||||
|
||||
/** Converts MIDI 1 Universal MIDI Packets to corresponding MIDI 2 packets,
|
||||
calling `callback` with each converted packet.
|
||||
|
||||
In some cases (such as RPN/NRPN messages) multiple MIDI 1 packets will
|
||||
convert to a single MIDI 2 packet. In these cases, the translator will
|
||||
accumulate the full message internally, and send a single callback with
|
||||
the completed message, once all the individual MIDI 1 packets have been
|
||||
processed.
|
||||
*/
|
||||
template <typename PacketCallback>
|
||||
void dispatch (const View& v, PacketCallback&& callback)
|
||||
{
|
||||
const auto firstWord = v[0];
|
||||
const auto messageType = Utils::getMessageType (firstWord);
|
||||
|
||||
if (messageType != 0x2)
|
||||
{
|
||||
callback (v);
|
||||
return;
|
||||
}
|
||||
|
||||
const HelperValues helperValues
|
||||
{
|
||||
(uint8_t) ((0x4 << 0x4) | Utils::getGroup (firstWord)),
|
||||
(uint8_t) ((firstWord >> 0x10) & 0xff),
|
||||
(uint8_t) ((firstWord >> 0x08) & 0x7f),
|
||||
(uint8_t) ((firstWord >> 0x00) & 0x7f),
|
||||
};
|
||||
|
||||
switch (Utils::getStatus (firstWord))
|
||||
{
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
{
|
||||
const auto packet = processNoteOnOrOff (helperValues);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xa:
|
||||
{
|
||||
const auto packet = processPolyPressure (helperValues);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xb:
|
||||
{
|
||||
PacketX2 packet;
|
||||
|
||||
if (processControlChange (helperValues, packet))
|
||||
callback (View (packet.data()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xc:
|
||||
{
|
||||
const auto packet = processProgramChange (helperValues);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xd:
|
||||
{
|
||||
const auto packet = processChannelPressure (helperValues);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
case 0xe:
|
||||
{
|
||||
const auto packet = processPitchBend (helperValues);
|
||||
callback (View (packet.data()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
groupAccumulators = {};
|
||||
groupBanks = {};
|
||||
}
|
||||
|
||||
private:
|
||||
enum class PnKind { nrpn, rpn };
|
||||
|
||||
struct HelperValues
|
||||
{
|
||||
uint8_t typeAndGroup;
|
||||
uint8_t byte0;
|
||||
uint8_t byte1;
|
||||
uint8_t byte2;
|
||||
};
|
||||
|
||||
static PacketX2 processNoteOnOrOff (const HelperValues helpers);
|
||||
static PacketX2 processPolyPressure (const HelperValues helpers);
|
||||
|
||||
bool processControlChange (const HelperValues helpers, PacketX2& packet);
|
||||
|
||||
PacketX2 processProgramChange (const HelperValues helpers) const;
|
||||
|
||||
static PacketX2 processChannelPressure (const HelperValues helpers);
|
||||
static PacketX2 processPitchBend (const HelperValues helpers);
|
||||
|
||||
class PnAccumulator
|
||||
{
|
||||
public:
|
||||
bool addByte (uint8_t cc, uint8_t byte);
|
||||
|
||||
const std::array<uint8_t, 4>& getBytes() const noexcept { return bytes; }
|
||||
PnKind getKind() const noexcept { return kind; }
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 4> bytes;
|
||||
uint8_t index = 0;
|
||||
PnKind kind = PnKind::nrpn;
|
||||
};
|
||||
|
||||
class Bank
|
||||
{
|
||||
public:
|
||||
bool isValid() const noexcept { return ! (msb & 0x80); }
|
||||
|
||||
uint8_t getMsb() const noexcept { return msb & 0x7f; }
|
||||
uint8_t getLsb() const noexcept { return lsb & 0x7f; }
|
||||
|
||||
void setMsb (uint8_t i) noexcept { msb = i & 0x7f; }
|
||||
void setLsb (uint8_t i) noexcept { msb &= 0x7f; lsb = i & 0x7f; }
|
||||
|
||||
private:
|
||||
// We use the top bit to indicate whether this bank is valid.
|
||||
// After reading the spec, it's not clear how we should determine whether
|
||||
// there are valid values, so we'll just assume that the bank is valid
|
||||
// once either the lsb or msb have been written.
|
||||
uint8_t msb = 0x80;
|
||||
uint8_t lsb = 0x00;
|
||||
};
|
||||
|
||||
using ChannelAccumulators = std::array<PnAccumulator, 16>;
|
||||
std::array<ChannelAccumulators, 16> groupAccumulators;
|
||||
|
||||
using ChannelBanks = std::array<Bank, 16>;
|
||||
std::array<ChannelBanks, 16> groupBanks;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
44
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h
vendored
Normal file
44
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPProtocols.h
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/** The kinds of MIDI protocol that can be formatted into Universal MIDI Packets. */
|
||||
enum class PacketProtocol
|
||||
{
|
||||
MIDI_1_0,
|
||||
MIDI_2_0,
|
||||
};
|
||||
|
||||
/** All kinds of MIDI protocol understood by JUCE. */
|
||||
enum class MidiProtocol
|
||||
{
|
||||
bytestream,
|
||||
UMP_MIDI_1_0,
|
||||
UMP_MIDI_2_0,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
42
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPReceiver.h
vendored
Normal file
42
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPReceiver.h
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
A base class for classes which receive Universal MIDI Packets from an input.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct Receiver
|
||||
{
|
||||
virtual ~Receiver() noexcept = default;
|
||||
|
||||
/** This will be called each time a new packet is ready for processing. */
|
||||
virtual void packetReceived (const View& packet, double time) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
53
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp
vendored
Normal file
53
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
uint32_t SysEx7::getNumPacketsRequiredForDataSize (uint32_t size)
|
||||
{
|
||||
constexpr auto denom = 6;
|
||||
return (size / denom) + ((size % denom) != 0);
|
||||
}
|
||||
|
||||
SysEx7::PacketBytes SysEx7::getDataBytes (const PacketX2& packet)
|
||||
{
|
||||
const auto numBytes = Utils::getChannel (packet[0]);
|
||||
constexpr uint8_t maxBytes = 6;
|
||||
jassert (numBytes <= maxBytes);
|
||||
|
||||
return
|
||||
{
|
||||
{ { packet.getU8<2>(),
|
||||
packet.getU8<3>(),
|
||||
packet.getU8<4>(),
|
||||
packet.getU8<5>(),
|
||||
packet.getU8<6>(),
|
||||
packet.getU8<7>() } },
|
||||
jmin (numBytes, maxBytes)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
73
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h
vendored
Normal file
73
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
This struct acts as a single-file namespace for Univeral MIDI Packet
|
||||
functionality related to 7-bit SysEx.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct SysEx7
|
||||
{
|
||||
/** Returns the number of 64-bit packets required to hold a series of
|
||||
SysEx bytes.
|
||||
|
||||
The number passed to this function should exclude the leading/trailing
|
||||
SysEx bytes used in an old midi bytestream, as these are not required
|
||||
when using Universal MIDI Packets.
|
||||
*/
|
||||
static uint32_t getNumPacketsRequiredForDataSize (uint32_t);
|
||||
|
||||
/** The different kinds of UMP SysEx-7 message. */
|
||||
enum class Kind : uint8_t
|
||||
{
|
||||
/** The whole message fits in a single 2-word packet. */
|
||||
complete = 0,
|
||||
|
||||
/** The packet begins a SysEx message that will continue in subsequent packets. */
|
||||
begin = 1,
|
||||
|
||||
/** The packet is a continuation of an ongoing SysEx message. */
|
||||
continuation = 2,
|
||||
|
||||
/** The packet terminates an ongoing SysEx message. */
|
||||
end = 3
|
||||
};
|
||||
|
||||
/** Holds the bytes from a single SysEx-7 packet. */
|
||||
struct PacketBytes
|
||||
{
|
||||
std::array<uint8_t, 6> data;
|
||||
uint8_t size;
|
||||
};
|
||||
|
||||
/** Extracts the data bytes from a 64-bit data message. */
|
||||
static PacketBytes getDataBytes (const PacketX2& packet);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
1018
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPTests.cpp
vendored
Normal file
1018
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPTests.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
59
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPUtils.cpp
vendored
Normal file
59
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPUtils.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
uint32_t Utils::getNumWordsForMessageType (uint32_t mt)
|
||||
{
|
||||
switch (Utils::getMessageType (mt))
|
||||
{
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
return 1;
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
return 2;
|
||||
case 0xb:
|
||||
case 0xc:
|
||||
return 3;
|
||||
case 0x5:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
case 0xf:
|
||||
return 4;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
113
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h
vendored
Normal file
113
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Helpful types and functions for interacting with Universal MIDI Packets.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct Utils
|
||||
{
|
||||
/** Joins 4 bytes into a single 32-bit word. */
|
||||
static constexpr uint32_t bytesToWord (uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
return uint32_t (a << 0x18 | b << 0x10 | c << 0x08 | d << 0x00);
|
||||
}
|
||||
|
||||
/** Returns the expected number of 32-bit words in a Universal MIDI Packet, given
|
||||
the first word of the packet.
|
||||
|
||||
The result will be between 1 and 4 inclusive.
|
||||
A result of 1 means that the word is itself a complete packet.
|
||||
*/
|
||||
static uint32_t getNumWordsForMessageType (uint32_t);
|
||||
|
||||
/**
|
||||
Helper functions for setting/getting 4-bit ranges inside a 32-bit word.
|
||||
*/
|
||||
template <size_t Index>
|
||||
struct U4
|
||||
{
|
||||
static constexpr uint32_t shift = (uint32_t) 0x1c - Index * 4;
|
||||
|
||||
static constexpr uint32_t set (uint32_t word, uint8_t value)
|
||||
{
|
||||
return (word & ~((uint32_t) 0xf << shift)) | (uint32_t) ((value & 0xf) << shift);
|
||||
}
|
||||
|
||||
static constexpr uint8_t get (uint32_t word)
|
||||
{
|
||||
return (uint8_t) ((word >> shift) & 0xf);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Helper functions for setting/getting 8-bit ranges inside a 32-bit word.
|
||||
*/
|
||||
template <size_t Index>
|
||||
struct U8
|
||||
{
|
||||
static constexpr uint32_t shift = (uint32_t) 0x18 - Index * 8;
|
||||
|
||||
static constexpr uint32_t set (uint32_t word, uint8_t value)
|
||||
{
|
||||
return (word & ~((uint32_t) 0xff << shift)) | (uint32_t) (value << shift);
|
||||
}
|
||||
|
||||
static constexpr uint8_t get (uint32_t word)
|
||||
{
|
||||
return (uint8_t) ((word >> shift) & 0xff);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Helper functions for setting/getting 16-bit ranges inside a 32-bit word.
|
||||
*/
|
||||
template <size_t Index>
|
||||
struct U16
|
||||
{
|
||||
static constexpr uint32_t shift = (uint32_t) 0x10 - Index * 16;
|
||||
|
||||
static constexpr uint32_t set (uint32_t word, uint16_t value)
|
||||
{
|
||||
return (word & ~((uint32_t) 0xffff << shift)) | (uint32_t) (value << shift);
|
||||
}
|
||||
|
||||
static constexpr uint16_t get (uint32_t word)
|
||||
{
|
||||
return (uint16_t) ((word >> shift) & 0xffff);
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr uint8_t getMessageType (uint32_t w) noexcept { return U4<0>::get (w); }
|
||||
static constexpr uint8_t getGroup (uint32_t w) noexcept { return U4<1>::get (w); }
|
||||
static constexpr uint8_t getStatus (uint32_t w) noexcept { return U4<2>::get (w); }
|
||||
static constexpr uint8_t getChannel (uint32_t w) noexcept { return U4<3>::get (w); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
35
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPView.cpp
vendored
Normal file
35
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPView.cpp
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
uint32_t View::size() const noexcept
|
||||
{
|
||||
jassert (ptr != nullptr);
|
||||
return Utils::getNumWordsForMessageType (*ptr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
88
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPView.h
vendored
Normal file
88
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPView.h
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Points to a single Universal MIDI Packet.
|
||||
|
||||
The packet must be well-formed for member functions to work correctly.
|
||||
|
||||
Specifically, the constructor argument must be the beginning of a region of
|
||||
uint32_t that contains at least `getNumWordsForMessageType(*ddata)` items,
|
||||
where `data` is the constructor argument.
|
||||
|
||||
NOTE: Instances of this class do not own the memory that they point to!
|
||||
If you need to store a packet pointed-to by a View for later use, copy
|
||||
the view contents to a Packets collection, or use the Utils::PacketX types.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class View
|
||||
{
|
||||
public:
|
||||
/** Create an invalid view. */
|
||||
View() noexcept = default;
|
||||
|
||||
/** Create a view of the packet starting at address `d`. */
|
||||
explicit View (const uint32_t* data) noexcept : ptr (data) {}
|
||||
|
||||
/** Get a pointer to the first word in the Universal MIDI Packet currently
|
||||
pointed-to by this view.
|
||||
*/
|
||||
const uint32_t* data() const noexcept { return ptr; }
|
||||
|
||||
/** Get the number of 32-words (between 1 and 4 inclusive) in the Universal
|
||||
MIDI Packet currently pointed-to by this view.
|
||||
*/
|
||||
uint32_t size() const noexcept;
|
||||
|
||||
/** Get a specific word from this packet.
|
||||
|
||||
Passing an `index` that is greater than or equal to the result of `size`
|
||||
will cause undefined behaviour.
|
||||
*/
|
||||
const uint32_t& operator[] (size_t index) const noexcept { return ptr[index]; }
|
||||
|
||||
/** Get an iterator pointing to the first word in the packet. */
|
||||
const uint32_t* begin() const noexcept { return ptr; }
|
||||
const uint32_t* cbegin() const noexcept { return ptr; }
|
||||
|
||||
/** Get an iterator pointing one-past the last word in the packet. */
|
||||
const uint32_t* end() const noexcept { return ptr + size(); }
|
||||
const uint32_t* cend() const noexcept { return ptr + size(); }
|
||||
|
||||
/** Return true if this view is pointing to the same address as another view. */
|
||||
bool operator== (const View& other) const noexcept { return ptr == other.ptr; }
|
||||
|
||||
/** Return false if this view is pointing to the same address as another view. */
|
||||
bool operator!= (const View& other) const noexcept { return ! operator== (other); }
|
||||
|
||||
private:
|
||||
const uint32_t* ptr = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
189
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPacket.h
vendored
Normal file
189
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPacket.h
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Holds a single Universal MIDI Packet.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
template <size_t numWords>
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
Packet() = default;
|
||||
|
||||
template <size_t w = numWords, typename std::enable_if<w == 1, int>::type = 0>
|
||||
Packet (uint32_t a)
|
||||
: contents { { a } }
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (a) == 1);
|
||||
}
|
||||
|
||||
template <size_t w = numWords, typename std::enable_if<w == 2, int>::type = 0>
|
||||
Packet (uint32_t a, uint32_t b)
|
||||
: contents { { a, b } }
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (a) == 2);
|
||||
}
|
||||
|
||||
template <size_t w = numWords, typename std::enable_if<w == 3, int>::type = 0>
|
||||
Packet (uint32_t a, uint32_t b, uint32_t c)
|
||||
: contents { { a, b, c } }
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (a) == 3);
|
||||
}
|
||||
|
||||
template <size_t w = numWords, typename std::enable_if<w == 4, int>::type = 0>
|
||||
Packet (uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
||||
: contents { { a, b, c, d } }
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (a) == 4);
|
||||
}
|
||||
|
||||
template <size_t w, typename std::enable_if<w == numWords, int>::type = 0>
|
||||
explicit Packet (const std::array<uint32_t, w>& fullPacket)
|
||||
: contents (fullPacket)
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (fullPacket.front()) == numWords);
|
||||
}
|
||||
|
||||
Packet withMessageType (uint8_t type) const noexcept
|
||||
{
|
||||
return withU4<0> (type);
|
||||
}
|
||||
|
||||
Packet withGroup (uint8_t group) const noexcept
|
||||
{
|
||||
return withU4<1> (group);
|
||||
}
|
||||
|
||||
Packet withStatus (uint8_t status) const noexcept
|
||||
{
|
||||
return withU4<2> (status);
|
||||
}
|
||||
|
||||
Packet withChannel (uint8_t channel) const noexcept
|
||||
{
|
||||
return withU4<3> (channel);
|
||||
}
|
||||
|
||||
uint8_t getMessageType() const noexcept { return getU4<0>(); }
|
||||
|
||||
uint8_t getGroup() const noexcept { return getU4<1>(); }
|
||||
|
||||
uint8_t getStatus() const noexcept { return getU4<2>(); }
|
||||
|
||||
uint8_t getChannel() const noexcept { return getU4<3>(); }
|
||||
|
||||
template <size_t index>
|
||||
Packet withU4 (uint8_t value) const noexcept
|
||||
{
|
||||
constexpr auto word = index / 8;
|
||||
auto copy = *this;
|
||||
std::get<word> (copy.contents) = Utils::U4<index % 8>::set (copy.template getU32<word>(), value);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
Packet withU8 (uint8_t value) const noexcept
|
||||
{
|
||||
constexpr auto word = index / 4;
|
||||
auto copy = *this;
|
||||
std::get<word> (copy.contents) = Utils::U8<index % 4>::set (copy.template getU32<word>(), value);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
Packet withU16 (uint16_t value) const noexcept
|
||||
{
|
||||
constexpr auto word = index / 2;
|
||||
auto copy = *this;
|
||||
std::get<word> (copy.contents) = Utils::U16<index % 2>::set (copy.template getU32<word>(), value);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
Packet withU32 (uint32_t value) const noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
std::get<index> (copy.contents) = value;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
uint8_t getU4() const noexcept
|
||||
{
|
||||
return Utils::U4<index % 8>::get (this->template getU32<index / 8>());
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
uint8_t getU8() const noexcept
|
||||
{
|
||||
return Utils::U8<index % 4>::get (this->template getU32<index / 4>());
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
uint16_t getU16() const noexcept
|
||||
{
|
||||
return Utils::U16<index % 2>::get (this->template getU32<index / 2>());
|
||||
}
|
||||
|
||||
template <size_t index>
|
||||
uint32_t getU32() const noexcept
|
||||
{
|
||||
return std::get<index> (contents);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
using Contents = std::array<uint32_t, numWords>;
|
||||
|
||||
using const_iterator = typename Contents::const_iterator;
|
||||
|
||||
const_iterator begin() const noexcept { return contents.begin(); }
|
||||
const_iterator cbegin() const noexcept { return contents.begin(); }
|
||||
|
||||
const_iterator end() const noexcept { return contents.end(); }
|
||||
const_iterator cend() const noexcept { return contents.end(); }
|
||||
|
||||
const uint32_t* data() const noexcept { return contents.data(); }
|
||||
|
||||
const uint32_t& front() const noexcept { return contents.front(); }
|
||||
const uint32_t& back() const noexcept { return contents.back(); }
|
||||
|
||||
const uint32_t& operator[] (size_t index) const noexcept { return contents[index]; }
|
||||
|
||||
private:
|
||||
Contents contents { {} };
|
||||
};
|
||||
|
||||
using PacketX1 = Packet<1>;
|
||||
using PacketX2 = Packet<2>;
|
||||
using PacketX3 = Packet<3>;
|
||||
using PacketX4 = Packet<4>;
|
||||
|
||||
}
|
||||
}
|
92
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPackets.h
vendored
Normal file
92
deps/juce/modules/juce_audio_basics/midi/ump/juce_UMPackets.h
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - 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
|
||||
{
|
||||
|
||||
/**
|
||||
Holds a collection of Universal MIDI Packets.
|
||||
|
||||
Unlike MidiBuffer, this collection does not store any additional information
|
||||
(e.g. timestamps) alongside the raw messages.
|
||||
|
||||
If timestamps are required, these can be added to the container in UMP format,
|
||||
as Jitter Reduction Utility messages.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class Packets
|
||||
{
|
||||
public:
|
||||
/** Adds a single packet to the collection.
|
||||
|
||||
The View must be valid for this to work. If the view
|
||||
points to a malformed message, or if the view points to a region
|
||||
too short for the contained message, this call will result in
|
||||
undefined behaviour.
|
||||
*/
|
||||
void add (const View& v) { storage.insert (storage.end(), v.cbegin(), v.cend()); }
|
||||
|
||||
void add (const PacketX1& p) { addImpl (p); }
|
||||
void add (const PacketX2& p) { addImpl (p); }
|
||||
void add (const PacketX3& p) { addImpl (p); }
|
||||
void add (const PacketX4& p) { addImpl (p); }
|
||||
|
||||
/** Pre-allocates space for at least `numWords` 32-bit words in this collection. */
|
||||
void reserve (size_t numWords) { storage.reserve (numWords); }
|
||||
|
||||
/** Removes all previously-added packets from this collection. */
|
||||
void clear() { storage.clear(); }
|
||||
|
||||
/** Gets an iterator pointing to the first packet in this collection. */
|
||||
Iterator cbegin() const noexcept { return Iterator (data(), size()); }
|
||||
Iterator begin() const noexcept { return cbegin(); }
|
||||
|
||||
/** Gets an iterator pointing one-past the last packet in this collection. */
|
||||
Iterator cend() const noexcept { return Iterator (data() + size(), 0); }
|
||||
Iterator end() const noexcept { return cend(); }
|
||||
|
||||
/** Gets a pointer to the contents of the collection as a range of raw 32-bit words. */
|
||||
const uint32_t* data() const noexcept { return storage.data(); }
|
||||
|
||||
/** Returns the number of uint32_t words in storage.
|
||||
|
||||
Note that this is likely to be larger than the number of packets
|
||||
currently being stored, as some packets span multiple words.
|
||||
*/
|
||||
size_t size() const noexcept { return storage.size(); }
|
||||
|
||||
private:
|
||||
template <size_t numWords>
|
||||
void addImpl (const Packet<numWords>& p)
|
||||
{
|
||||
jassert (Utils::getNumWordsForMessageType (p[0]) == numWords);
|
||||
add (View (p.data()));
|
||||
}
|
||||
|
||||
std::vector<uint32_t> storage;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user