|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 7 End-User License
- Agreement and JUCE Privacy Policy.
-
- End User License Agreement: www.juce.com/juce-7-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- 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::midi_ci
- {
-
- //==============================================================================
- /**
- Byte values representing different addresses within a group.
-
- @tags{Audio}
- */
- enum class ChannelInGroup : uint8_t
- {
- channel0 = 0x0,
- channel1 = 0x1,
- channel2 = 0x2,
- channel3 = 0x3,
- channel4 = 0x4,
- channel5 = 0x5,
- channel6 = 0x6,
- channel7 = 0x7,
- channel8 = 0x8,
- channel9 = 0x9,
- channelA = 0xA,
- channelB = 0xB,
- channelC = 0xC,
- channelD = 0xD,
- channelE = 0xE,
- channelF = 0xF,
- wholeGroup = 0x7e, ///< Refers to all channels in the UMP group
- wholeBlock = 0x7f, ///< Refers to all channels in the function block that contains the UMP group
- };
-
- /**
- Utility functions for working with the ChannelInGroup enum.
-
- @tags{Audio}
- */
- struct ChannelInGroupUtils
- {
- ChannelInGroupUtils() = delete;
-
- /** Converts a ChannelInGroup to a descriptive string. */
- static String toString (ChannelInGroup c)
- {
- if (c == ChannelInGroup::wholeGroup)
- return "Group";
-
- if (c == ChannelInGroup::wholeBlock)
- return "Function Block";
-
- const auto underlying = (std::underlying_type_t<ChannelInGroup>) c;
- return "Channel " + String (underlying + 1);
- }
- };
-
- using Profile = std::array<std::byte, 5>;
-
- //==============================================================================
- /**
- Namespace containing structs representing different kinds of MIDI-CI message.
-
- @tags{Audio}
- */
- namespace Message
- {
- /** Wraps a span, providing equality operators that compare the span
- contents elementwise.
-
- @tags{Audio}
- */
- template <typename T>
- struct ComparableRange
- {
- T& data;
-
- bool operator== (const ComparableRange& other) const
- {
- return std::equal (data.begin(), data.end(), other.data.begin(), other.data.end());
- }
-
- bool operator!= (const ComparableRange& other) const { return ! operator== (other); }
- };
-
- template <typename T> static constexpr auto makeComparableRange ( T& t) { return ComparableRange< T> { t }; }
- template <typename T> static constexpr auto makeComparableRange (const T& t) { return ComparableRange<const T> { t }; }
-
- //==============================================================================
- /**
- Holds fields that can be found at the beginning of every MIDI CI message.
-
- @tags{Audio}
- */
- struct Header
- {
- ChannelInGroup deviceID{};
- std::byte category{};
- std::byte version{};
- MUID source = MUID::makeUnchecked (0);
- MUID destination = MUID::makeUnchecked (0);
-
- auto tie() const
- {
- return std::tuple (deviceID, category, version, source, destination);
- }
-
- bool operator== (const Header& x) const { return tie() == x.tie(); }
- bool operator!= (const Header& x) const { return ! operator== (x); }
- };
-
- /**
- Groups together a CI message header, and some number of trailing bytes.
-
- @tags{Audio}
- */
- struct Generic
- {
- Header header;
- Span<const std::byte> data;
- };
-
- //==============================================================================
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct DiscoveryResponse
- {
- ump::DeviceInfo device;
- std::byte capabilities{};
- uint32_t maximumSysexSize{};
- std::byte outputPathID{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::byte functionBlock{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (device, capabilities, maximumSysexSize, outputPathID, functionBlock);
- }
-
- bool operator== (const DiscoveryResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const DiscoveryResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct Discovery
- {
- ump::DeviceInfo device;
- std::byte capabilities{};
- uint32_t maximumSysexSize{};
- std::byte outputPathID{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (device, capabilities, maximumSysexSize, outputPathID);
- }
-
- bool operator== (const Discovery& x) const { return tie() == x.tie(); }
- bool operator!= (const Discovery& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct EndpointInquiryResponse
- {
- std::byte status;
- Span<const std::byte> data;
-
- auto tie() const
- {
- return std::tuple (status, makeComparableRange (data));
- }
-
- bool operator== (const EndpointInquiryResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const EndpointInquiryResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct EndpointInquiry
- {
- std::byte status;
-
- auto tie() const
- {
- return std::tuple (status);
- }
-
- bool operator== (const EndpointInquiry& x) const { return tie() == x.tie(); }
- bool operator!= (const EndpointInquiry& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct InvalidateMUID
- {
- MUID target = MUID::makeUnchecked (0);
-
- auto tie() const
- {
- return std::tuple (target);
- }
-
- bool operator== (const InvalidateMUID& x) const { return tie() == x.tie(); }
- bool operator!= (const InvalidateMUID& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ACK
- {
- std::byte originalCategory{};
- std::byte statusCode{};
- std::byte statusData{};
- std::array<std::byte, 5> details{};
- Span<const std::byte> messageText{};
-
- /** Convenience function that returns the message's text as a String. */
- String getMessageTextAsString() const
- {
- return Encodings::stringFrom7BitText (messageText);
- }
-
- auto tie() const
- {
- return std::tuple (originalCategory, statusCode, statusData, details, makeComparableRange (messageText));
- }
-
- bool operator== (const ACK& x) const { return tie() == x.tie(); }
- bool operator!= (const ACK& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct NAK
- {
- std::byte originalCategory{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::byte statusCode{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::byte statusData{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::array<std::byte, 5> details{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- Span<const std::byte> messageText{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- /** Convenience function that returns the message's text as a String. */
- String getMessageTextAsString() const
- {
- return Encodings::stringFrom7BitText (messageText);
- }
-
- auto tie() const
- {
- return std::tuple (originalCategory, statusCode, statusData, details, makeComparableRange (messageText));
- }
-
- bool operator== (const NAK& x) const { return tie() == x.tie(); }
- bool operator!= (const NAK& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileInquiryResponse
- {
- Span<const Profile> enabledProfiles;
- Span<const Profile> disabledProfiles;
-
- auto tie() const
- {
- return std::tuple (makeComparableRange (enabledProfiles), makeComparableRange (disabledProfiles));
- }
-
- bool operator== (const ProfileInquiryResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileInquiryResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileInquiry
- {
- auto tie() const
- {
- return std::tuple<>();
- }
-
- bool operator== (const ProfileInquiry& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileInquiry& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileAdded
- {
- Profile profile{};
-
- auto tie() const
- {
- return std::tuple (profile);
- }
-
- bool operator== (const ProfileAdded& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileAdded& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileRemoved
- {
- Profile profile{};
-
- auto tie() const
- {
- return std::tuple (profile);
- }
-
- bool operator== (const ProfileRemoved& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileRemoved& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileDetailsResponse
- {
- Profile profile{};
- std::byte target{};
- Span<const std::byte> data;
-
- auto tie() const
- {
- return std::tuple (profile, target, makeComparableRange (data));
- }
-
- bool operator== (const ProfileDetailsResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileDetailsResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileDetails
- {
- Profile profile{};
- std::byte target{};
-
- auto tie() const
- {
- return std::tuple (profile, target);
- }
-
- bool operator== (const ProfileDetails& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileDetails& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileOn
- {
- Profile profile{};
- uint16_t numChannels{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (profile, numChannels);
- }
-
- bool operator== (const ProfileOn& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileOn& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileOff
- {
- Profile profile{};
-
- auto tie() const
- {
- return std::tuple (profile);
- }
-
- bool operator== (const ProfileOff& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileOff& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileEnabledReport
- {
- Profile profile{};
- uint16_t numChannels{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (profile, numChannels);
- }
-
- bool operator== (const ProfileEnabledReport& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileEnabledReport& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileDisabledReport
- {
- Profile profile{};
- uint16_t numChannels{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (profile, numChannels);
- }
-
- bool operator== (const ProfileDisabledReport& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileDisabledReport& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProfileSpecificData
- {
- Profile profile{};
- Span<const std::byte> data;
-
- auto tie() const
- {
- return std::tuple (profile, makeComparableRange (data));
- }
-
- bool operator== (const ProfileSpecificData& x) const { return tie() == x.tie(); }
- bool operator!= (const ProfileSpecificData& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertyExchangeCapabilitiesResponse
- {
- std::byte numSimultaneousRequestsSupported{};
- std::byte majorVersion{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::byte minorVersion{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (numSimultaneousRequestsSupported, majorVersion, minorVersion);
- }
-
- bool operator== (const PropertyExchangeCapabilitiesResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertyExchangeCapabilitiesResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertyExchangeCapabilities
- {
- std::byte numSimultaneousRequestsSupported{};
- std::byte majorVersion{}; /**< Only valid if the message header specifies version 0x02 or greater. */
- std::byte minorVersion{}; /**< Only valid if the message header specifies version 0x02 or greater. */
-
- auto tie() const
- {
- return std::tuple (numSimultaneousRequestsSupported, majorVersion, minorVersion);
- }
-
- bool operator== (const PropertyExchangeCapabilities& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertyExchangeCapabilities& x) const { return ! operator== (x); }
- };
-
- /** A property-exchange message that has no payload, and must therefore
- be contained in a single chunk.
-
- @tags{Audio}
- */
- struct StaticSizePropertyExchange
- {
- std::byte requestID{};
- Span<const std::byte> header;
-
- auto tie() const
- {
- return std::tuple (requestID, makeComparableRange (header));
- }
- };
-
- /** A property-exchange message that may form part of a multi-chunk
- message sequence.
-
- @tags{Audio}
- */
- struct DynamicSizePropertyExchange
- {
- std::byte requestID{};
- Span<const std::byte> header;
- uint16_t totalNumChunks{};
- uint16_t thisChunkNum{};
- Span<const std::byte> data;
-
- auto tie() const
- {
- return std::tuple (requestID,
- makeComparableRange (header),
- totalNumChunks,
- thisChunkNum,
- makeComparableRange (data));
- }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertyGetDataResponse : public DynamicSizePropertyExchange
- {
- bool operator== (const PropertyGetDataResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertyGetDataResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertyGetData : public StaticSizePropertyExchange
- {
- bool operator== (const PropertyGetData& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertyGetData& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertySetDataResponse : public StaticSizePropertyExchange
- {
- bool operator== (const PropertySetDataResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertySetDataResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertySetData : public DynamicSizePropertyExchange
- {
- bool operator== (const PropertySetData& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertySetData& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertySubscribeResponse : public DynamicSizePropertyExchange
- {
- bool operator== (const PropertySubscribeResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertySubscribeResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertySubscribe : public DynamicSizePropertyExchange
- {
- bool operator== (const PropertySubscribe& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertySubscribe& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct PropertyNotify : public DynamicSizePropertyExchange
- {
- bool operator== (const PropertyNotify& x) const { return tie() == x.tie(); }
- bool operator!= (const PropertyNotify& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProcessInquiryResponse
- {
- std::byte supportedFeatures{};
-
- auto tie() const
- {
- return std::tuple (supportedFeatures);
- }
-
- bool operator== (const ProcessInquiryResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const ProcessInquiryResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProcessInquiry
- {
- auto tie() const
- {
- return std::tuple<>();
- }
-
- bool operator== (const ProcessInquiry& x) const { return tie() == x.tie(); }
- bool operator!= (const ProcessInquiry& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProcessMidiMessageReportResponse
- {
- std::byte messageDataControl{};
- std::byte requestedMessages{};
- std::byte channelControllerMessages{};
- std::byte noteDataMessages{};
-
- auto tie() const
- {
- return std::tuple (messageDataControl, requestedMessages, channelControllerMessages, noteDataMessages);
- }
-
- bool operator== (const ProcessMidiMessageReportResponse& x) const { return tie() == x.tie(); }
- bool operator!= (const ProcessMidiMessageReportResponse& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProcessMidiMessageReport
- {
- std::byte messageDataControl{};
- std::byte requestedMessages{};
- std::byte channelControllerMessages{};
- std::byte noteDataMessages{};
-
- auto tie() const
- {
- return std::tuple (messageDataControl, requestedMessages, channelControllerMessages, noteDataMessages);
- }
-
- bool operator== (const ProcessMidiMessageReport& x) const { return tie() == x.tie(); }
- bool operator!= (const ProcessMidiMessageReport& x) const { return ! operator== (x); }
- };
-
- /** See the MIDI-CI specification.
-
- @tags{Audio}
- */
- struct ProcessEndMidiMessageReport
- {
- auto tie() const
- {
- return std::tuple<>();
- }
-
- bool operator== (const ProcessEndMidiMessageReport& x) const { return tie() == x.tie(); }
- bool operator!= (const ProcessEndMidiMessageReport& x) const { return ! operator== (x); }
- };
-
- /**
- A message with a header and optional body.
-
- The body may be set to std::monostate to indicate some kind of failure, such as a malformed
- incoming message.
-
- @tags{Audio}
- */
- struct Parsed
- {
- using Body = std::variant<std::monostate,
- Discovery,
- DiscoveryResponse,
- InvalidateMUID,
- EndpointInquiry,
- EndpointInquiryResponse,
- ACK,
- NAK,
- ProfileInquiry,
- ProfileInquiryResponse,
- ProfileAdded,
- ProfileRemoved,
- ProfileDetails,
- ProfileDetailsResponse,
- ProfileOn,
- ProfileOff,
- ProfileEnabledReport,
- ProfileDisabledReport,
- ProfileSpecificData,
- PropertyExchangeCapabilities,
- PropertyExchangeCapabilitiesResponse,
- PropertyGetData,
- PropertyGetDataResponse,
- PropertySetData,
- PropertySetDataResponse,
- PropertySubscribe,
- PropertySubscribeResponse,
- PropertyNotify,
- ProcessInquiry,
- ProcessInquiryResponse,
- ProcessMidiMessageReport,
- ProcessMidiMessageReportResponse,
- ProcessEndMidiMessageReport>;
-
- Header header;
- Body body;
-
- bool operator== (const Parsed& other) const
- {
- const auto tie = [] (const auto& x) { return std::tie (x.header, x.body); };
- return tie (*this) == tie (other);
- }
-
- bool operator!= (const Parsed& other) const { return ! operator== (other); }
- };
- }
-
- } // namespace juce::midi_ci
|