/* ============================================================================== 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 { #define JUCE_SUBSCRIPTION_COMMANDS X(start) X(partial) X(full) X(notify) X(end) /** Kinds of command that may be sent as part of a subscription update. Check the Property Exchange specification to find the meaning of the different kinds. @tags{Audio} */ enum class PropertySubscriptionCommand { #define X(str) str, JUCE_SUBSCRIPTION_COMMANDS #undef X }; /** Functions to use with PropertySubscriptionCommand. @tags{Audio} */ struct PropertySubscriptionCommandUtils { PropertySubscriptionCommandUtils() = delete; /** Converts a command to a human-readable string. */ static const char* toString (PropertySubscriptionCommand x) { switch (x) { #define X(str) case PropertySubscriptionCommand::str: return #str; JUCE_SUBSCRIPTION_COMMANDS #undef X } return nullptr; } /** Converts a command string from a property exchange JSON header to an PropertySubscriptionCommand. */ static std::optional toCommand (const char* str) { #define X(name) if (std::string_view (str) == std::string_view (#name)) return PropertySubscriptionCommand::name; JUCE_SUBSCRIPTION_COMMANDS #undef X return {}; } }; #undef JUCE_SUBSCRIPTION_COMMANDS /** A struct containing data members that correspond to common fields in a property subscription header. Check the Property Exchange specification to find the meaning of the different fields. @tags{Audio} */ struct PropertySubscriptionHeader { String resource; String resId; Encoding mutualEncoding = Encoding::ascii; String mediaType = "application/json"; PropertySubscriptionCommand command { -1 }; String subscribeId; std::map extended; /** Converts a JSON object to a PropertyRequestHeader. Unspecified fields will use their default values. */ static PropertySubscriptionHeader parseCondensed (const var&); /** Converts a PropertySubscriptionHeader to a JSON object suitable for use as a MIDI-CI message header after conversion to 7-bit ASCII. */ var toVarCondensed() const; }; /** Contains information about the pagination of a request. Check the Property Exchange specification to find the meaning of the different fields. @tags{Audio} */ struct Pagination { int offset = 0; int limit = 1; }; /** A struct containing data members that correspond to common fields in a property request header. Check the Property Exchange specification to find the meaning of the different fields. @tags{Audio} */ struct PropertyRequestHeader { String resource; String resId; Encoding mutualEncoding = Encoding::ascii; String mediaType = "application/json"; bool setPartial = false; std::optional pagination; std::map extended; /** Converts a JSON object to a PropertyRequestHeader. Unspecified fields will use their default values. */ static PropertyRequestHeader parseCondensed (const var&); /** Converts a PropertyRequestHeader to a JSON object suitable for use as a MIDI-CI message header after conversion to 7-bit ASCII. */ var toVarCondensed() const; }; /** Bundles together a property request header and a data payload. @tags{Audio} */ struct PropertyRequestData { PropertyRequestHeader header; Span body; }; /** A struct containing data members that correspond to common fields in a reply to a property exchange request. Check the Property Exchange specification to find the meaning of the different fields. For extended attributes that don't correspond to any of the defined data members, use the 'extended' map. @tags{Audio} */ struct PropertyReplyHeader { int status = 200; String message; Encoding mutualEncoding = Encoding::ascii; int cacheTime = 0; String mediaType = "application/json"; std::map extended; /** Converts a JSON object to a PropertyReplyHeader. Unspecified fields will use their default values. */ static PropertyReplyHeader parseCondensed (const var&); /** Converts a PropertyReplyHeader to a JSON object suitable for use as a MIDI-CI message header after conversion to 7-bit ASCII. */ var toVarCondensed() const; }; /** Bundles together a property reply header and a data payload. @tags{Audio} */ struct PropertyReplyData { PropertyReplyHeader header; std::vector body; }; /** An interface with methods that can be overridden to customise how a Device implementing properties responds to property inquiries. @tags{Audio} */ struct PropertyDelegate { PropertyDelegate() = default; virtual ~PropertyDelegate() = default; PropertyDelegate (const PropertyDelegate&) = default; PropertyDelegate (PropertyDelegate&&) = default; PropertyDelegate& operator= (const PropertyDelegate&) = default; PropertyDelegate& operator= (PropertyDelegate&&) = default; /** Returns the max number of simultaneous property exchange messages that can be processed. */ virtual uint8_t getNumSimultaneousRequestsSupported() const { return 127; } /** Returns a header/body containing the requested data. To report an error, you can return a failure status code in the header and leave the body empty. */ virtual PropertyReplyData propertyGetDataRequested (MUID, const PropertyRequestHeader&) = 0; /** Returns a header that describes the result of the set operation. */ virtual PropertyReplyHeader propertySetDataRequested (MUID, const PropertyRequestData&) = 0; /** Returns true to allow the subscription, or false otherwise. */ virtual bool subscriptionStartRequested (MUID, const PropertySubscriptionHeader&) = 0; /** Called with the corresponding subscription token after a subscription has started. */ virtual void subscriptionDidStart (MUID, const String& subId, const PropertySubscriptionHeader&) = 0; /** Called when a device requests for an ongoing subscription to end. */ virtual void subscriptionWillEnd (MUID, const Subscription& sub) = 0; }; } // namespace juce::midi_ci #ifndef DOXYGEN namespace juce { template <> struct SerialisationTraits { static constexpr auto marshallingVersion = std::nullopt; template void load (Archive& archive, midi_ci::PropertySubscriptionCommand& t) { String command; archive (command); t = midi_ci::PropertySubscriptionCommandUtils::toCommand (command.toRawUTF8()).value_or (midi_ci::PropertySubscriptionCommand{}); } template void save (Archive& archive, const midi_ci::PropertySubscriptionCommand& t) { archive (midi_ci::PropertySubscriptionCommandUtils::toString (t)); } }; } // namespace juce #endif // ifndef DOXYGEN