diff --git a/clap-libs/clap b/clap-libs/clap index 41964fa..df8f16c 160000 --- a/clap-libs/clap +++ b/clap-libs/clap @@ -1 +1 @@ -Subproject commit 41964fa3f44fdbf6feb20df528a9cdf2cc3b05ba +Subproject commit df8f16c69ba1c1a15fb105f0c5a2e5b9ac6be742 diff --git a/clap-libs/clap-helpers b/clap-libs/clap-helpers index 41e1086..7b53a68 160000 --- a/clap-libs/clap-helpers +++ b/clap-libs/clap-helpers @@ -1 +1 @@ -Subproject commit 41e1086488f5cd27da871d07edb8eccea99e556d +Subproject commit 7b53a685e11465154b4ccba3065224dbcbf8a893 diff --git a/include/clap-juce-extensions/clap-juce-extensions.h b/include/clap-juce-extensions/clap-juce-extensions.h index 39b4b01..5cea719 100644 --- a/include/clap-juce-extensions/clap-juce-extensions.h +++ b/include/clap-juce-extensions/clap-juce-extensions.h @@ -24,7 +24,6 @@ const clap_plugin *clap_create_plugin(const struct clap_plugin_factory *, const const char *); } - /** Forward declarations for any JUCE classes we might need. */ namespace juce { @@ -216,13 +215,13 @@ struct clap_juce_audio_processor_capabilities * If your plugin supports custom note names, then this method should be overriden * to return how the number of note names that your plugin has. */ - virtual int noteNameCount() noexcept { return 0; } + virtual uint32_t noteNameCount() noexcept { return 0; } /** * The host will call this method to retrieve the note name for a given index * in the range [0, noteNameCount()). */ - virtual bool noteNameGet(int /*index*/, clap_note_name * /*noteName*/) noexcept + virtual bool noteNameGet(uint32_t /*index*/, clap_note_name * /*noteName*/) noexcept { return false; } @@ -267,6 +266,30 @@ struct clap_juce_audio_processor_capabilities suggestRemoteControlsPageSignal(pageID); } + /** If your plugin supports preset load, then override this method to return true. */ + virtual bool supportsPresetLoad() const noexcept { return false; } + + /** + * The plugin should override this method to attempt to load a preset from a location, + * and return true if the load occurred successfully. + */ + virtual bool presetLoadFromLocation(uint32_t /*location_kind*/, const char * /*location*/, + const char * /*load_key*/) noexcept + { + return false; + } + + /** + * The plugin should call this from within presetLoadFromLocation() to report an error when + * trying to load the preset, and then return false from presetLoadFromLocation(). + */ + void reportPresetLoadError(uint32_t location_kind, const char *location, const char *load_key, + int32_t os_error, const juce::String &message) + { + if (onPresetLoadError != nullptr) + onPresetLoadError(location_kind, location, load_key, os_error, message); + } + /* * If you are working with a host that chooses to not implement cookies you will * need to look up parameters by param_id. Use this method to do so. @@ -294,6 +317,9 @@ struct clap_juce_audio_processor_capabilities std::function noteNamesChangedSignal = nullptr; std::function remoteControlsChangedSignal = nullptr; std::function suggestRemoteControlsPageSignal = nullptr; + std::function + onPresetLoadError = nullptr; std::function extensionGet = nullptr; friend const clap_plugin *ClapAdapter::clap_create_plugin(const struct clap_plugin_factory *, diff --git a/src/wrapper/clap-juce-wrapper.cpp b/src/wrapper/clap-juce-wrapper.cpp index 65c8102..b9119aa 100644 --- a/src/wrapper/clap-juce-wrapper.cpp +++ b/src/wrapper/clap-juce-wrapper.cpp @@ -41,6 +41,11 @@ JUCE_BEGIN_IGNORE_WARNINGS_MSVC(4100 4127 4244) #include #include #include + +#if CLAP_VERSION_LT(1,2,0) +static_assert(false, "CLAP juce wrapper requires at least clap 1.2.0"); +#endif + JUCE_END_IGNORE_WARNINGS_MSVC JUCE_END_IGNORE_WARNINGS_GCC_LIKE @@ -68,7 +73,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE } #if CLAP_SUPPORTS_CUSTOM_FACTORY -extern void *clapJuceExtensionCustomFactory(const char *); +extern const void *JUCE_CALLTYPE clapJuceExtensionCustomFactory(const char *); #endif #if !JUCE_MAC @@ -173,7 +178,7 @@ class EditorContextMenu : public juce::HostProvidedContextMenu juce::PopupMenu getEquivalentPopupMenu() const override { - host.contextMenuPopulate(host.host(), &menuTarget, builder.builder()); + host.contextMenuPopulate(&menuTarget, builder.builder()); jassert(builder.menuStack.size() == 1); // one of the sub-menus has not been closed? return builder.menuStack.front(); @@ -181,11 +186,11 @@ class EditorContextMenu : public juce::HostProvidedContextMenu void showNativeMenu(Point pos) const override { - if (!host.contextMenuCanPopup(host.host())) + if (!host.contextMenuCanPopup()) return; // TODO: figure out screen index? - host.contextMenuPopup(host.host(), &menuTarget, 0, pos.x, pos.y); + host.contextMenuPopup(&menuTarget, 0, pos.x, pos.y); } clap_context_menu_target menuTarget{}; @@ -230,9 +235,7 @@ class EditorContextMenu : public juce::HostProvidedContextMenu item.text = juce::CharPointer_UTF8(entry->label); item.isEnabled = entry->is_enabled; item.action = [&host = this->host, target = *this->menuTarget, - id = entry->action_id] { - host.contextMenuPerform(host.host(), &target, id); - }; + id = entry->action_id] { host.contextMenuPerform(&target, id); }; currentMenu.addItem(item); } @@ -246,9 +249,7 @@ class EditorContextMenu : public juce::HostProvidedContextMenu item.isEnabled = entry->is_enabled; item.isTicked = entry->is_checked; item.action = [&host = this->host, target = *this->menuTarget, - id = entry->action_id] { - host.contextMenuPerform(host.host(), &target, id); - }; + id = entry->action_id] { host.contextMenuPerform(&target, id); }; currentMenu.addItem(item); } @@ -434,6 +435,13 @@ class ClapJuceWrapper : public clap::helpers::Plugin< _host.remoteControlsSuggestPage(pageID); }); }; + processorAsClapExtensions->onPresetLoadError = + [this](uint32_t location_kind, const char *location, const char *load_key, + int32_t os_error, const juce::String &msg) { + if (_host.canUsePresetLoad()) + _host.presetLoadOnError(location_kind, location, load_key, os_error, + msg.toRawUTF8()); + }; processorAsClapExtensions->extensionGet = [this](const char *name) { return _host.host()->get_extension(_host.host(), name); }; @@ -1018,14 +1026,14 @@ class ClapJuceWrapper : public clap::helpers::Plugin< return false; } - int noteNameCount() noexcept override + uint32_t noteNameCount() noexcept override { if (processorAsClapExtensions) return processorAsClapExtensions->noteNameCount(); return 0; } - bool noteNameGet(int index, clap_note_name *noteName) noexcept override + bool noteNameGet(uint32_t index, clap_note_name *noteName) noexcept override { if (processorAsClapExtensions) return processorAsClapExtensions->noteNameGet(index, noteName); @@ -1080,6 +1088,29 @@ class ClapJuceWrapper : public clap::helpers::Plugin< return false; } + bool implementsPresetLoad() const noexcept override + { + if (processorAsClapExtensions) + return processorAsClapExtensions->supportsPresetLoad(); + return false; + } + + bool presetLoadFromLocation(uint32_t location_kind, const char *location, + const char *load_key) noexcept override + { + if (processorAsClapExtensions) + { + if (processorAsClapExtensions->presetLoadFromLocation(location_kind, location, + load_key)) + { + if (_host.canUsePresetLoad()) + _host.presetLoadLoaded(location_kind, location, load_key); + return true; + } + } + return false; + } + public: bool implementsParams() const noexcept override { return true; } bool isValidParamId(clap_id paramId) const noexcept override