From 9336043540fd2d36f138163a6d7f63d32dd25074 Mon Sep 17 00:00:00 2001 From: jatin Date: Sat, 30 Dec 2023 14:32:18 -0800 Subject: [PATCH] Setting up CLAP preset discovery --- CMakeLists.txt | 3 + modules/chowdsp_utils | 2 +- modules/clap-juce-extensions | 2 +- src/CMakeLists.txt | 4 +- src/ChowMultiTool.cpp | 27 ++++- src/gui/Toolbar/Toolbar.cpp | 2 +- src/pch.h | 3 + src/state/presets/PresetDiscovery.cpp | 130 ++++++++++++++++++++++ src/state/presets/PresetDiscovery.h | 17 +++ src/state/{ => presets}/PresetManager.cpp | 42 ++++--- src/state/{ => presets}/PresetManager.h | 2 + 11 files changed, 212 insertions(+), 22 deletions(-) create mode 100644 src/state/presets/PresetDiscovery.cpp create mode 100644 src/state/presets/PresetDiscovery.h rename src/state/{ => presets}/PresetManager.cpp (88%) rename src/state/{ => presets}/PresetManager.h (90%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ad78f3..31619a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ juce_add_plugin(ChowMultiTool IPAD_SCREEN_ORIENTATIONS UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ) +set(CHOWMULTITOOL_CLAP_ID "org.chowdsp.ChowMultiTool") if(CHOWMULTITOOL_BUILD_CLAP) clap_juce_extensions_plugin( TARGET ChowMultiTool @@ -73,6 +74,7 @@ if(CHOWMULTITOOL_BUILD_CLAP) CLAP_FEATURES audio-effect win32-dpi-aware CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 64 CLAP_USE_JUCE_PARAMETER_RANGES DISCRETE + CLAP_SUPPORTS_CUSTOM_FACTORY 1 ) endif() @@ -82,6 +84,7 @@ add_subdirectory(res) target_compile_definitions(ChowMultiTool PUBLIC JUCE_VST3_CAN_REPLACE_VST2=0 + CHOWMULTITOOL_CLAP_ID="${CHOWMULTITOOL_CLAP_ID}" ) target_link_libraries(ChowMultiTool diff --git a/modules/chowdsp_utils b/modules/chowdsp_utils index 4482306..4a53a3d 160000 --- a/modules/chowdsp_utils +++ b/modules/chowdsp_utils @@ -1 +1 @@ -Subproject commit 448230662beaaa5ef9a460e4ba6e6740a3f85bc7 +Subproject commit 4a53a3de9823f987e568691b507f40a493152e25 diff --git a/modules/clap-juce-extensions b/modules/clap-juce-extensions index 76a9c20..f417137 160000 --- a/modules/clap-juce-extensions +++ b/modules/clap-juce-extensions @@ -1 +1 @@ -Subproject commit 76a9c20ff4de5dc4519ed2dcd4b2831f826d4058 +Subproject commit f417137a5132dfe9274a926a4f21dfc56e363d5d diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a88d9e7..e88306f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,9 +2,11 @@ target_sources(ChowMultiTool PRIVATE ChowMultiTool.cpp state/PluginState.cpp - state/PresetManager.cpp state/PluginRemoteControls.cpp + state/presets/PresetManager.cpp + state/presets/PresetDiscovery.cpp + dsp/MultiToolProcessor.cpp dsp/AnalogEQ/PultecEQWDF.cpp diff --git a/src/ChowMultiTool.cpp b/src/ChowMultiTool.cpp index 819adc9..6d8c45f 100644 --- a/src/ChowMultiTool.cpp +++ b/src/ChowMultiTool.cpp @@ -1,10 +1,9 @@ #include "ChowMultiTool.h" #include "gui/PluginEditor.h" -#include "state/PresetManager.h" +#include "state/presets/PresetManager.h" namespace { -const juce::String settingsFilePath = "ChowdhuryDSP/ChowMultiTool/.plugin_settings.json"; const juce::String logFileSubDir = "ChowdhuryDSP/ChowMultiTool/Logs"; const juce::String logFileNameRoot = "ChowMultiTool_Log_"; } // namespace @@ -82,3 +81,27 @@ juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() { return new ChowMultiTool(); } + +#if HAS_CLAP_JUCE_EXTENSIONS +#include "state/presets/PresetDiscovery.h" + +// bool BYOD::presetLoadFromLocation (uint32_t location_kind, const char* location, const char* load_key) noexcept +// { +// return preset_discovery::presetLoadFromLocation (*presetManager, location_kind, location, load_key); +// } + +static const clap_preset_discovery_factory chowmultitool_preset_discovery_factory { + .count = state::presets::discovery::count, + .get_descriptor = state::presets::discovery::get_descriptor, + .create = state::presets::discovery::create, +}; + +const void* JUCE_CALLTYPE clapJuceExtensionCustomFactory (const char* factory_id) +{ + if (strcmp (factory_id, CLAP_PRESET_DISCOVERY_FACTORY_ID) == 0) + { + return &chowmultitool_preset_discovery_factory; + } + return nullptr; +} +#endif diff --git a/src/gui/Toolbar/Toolbar.cpp b/src/gui/Toolbar/Toolbar.cpp index 9141410..2cb3366 100644 --- a/src/gui/Toolbar/Toolbar.cpp +++ b/src/gui/Toolbar/Toolbar.cpp @@ -2,7 +2,7 @@ #include "ChowMultiTool.h" #include "gui/Shared/Colours.h" #include "gui/Shared/LookAndFeels.h" -#include "state/PresetManager.h" +#include "state/presets/PresetManager.h" namespace gui { diff --git a/src/pch.h b/src/pch.h index f2dc335..8eeac1c 100644 --- a/src/pch.h +++ b/src/pch.h @@ -48,3 +48,6 @@ CMRC_DECLARE (presets); // Any other widely used headers that don't change... #include "state/ParameterVersionHints.h" + +// constants +const juce::String settingsFilePath = "ChowdhuryDSP/ChowMultiTool/.plugin_settings.json"; diff --git a/src/state/presets/PresetDiscovery.cpp b/src/state/presets/PresetDiscovery.cpp new file mode 100644 index 0000000..8976ab7 --- /dev/null +++ b/src/state/presets/PresetDiscovery.cpp @@ -0,0 +1,130 @@ +#if HAS_CLAP_JUCE_EXTENSIONS + +#include "PresetDiscovery.h" +#include "PresetManager.h" + +namespace state::presets::discovery +{ +static constexpr clap_plugin_id plugin_id { + .abi = "clap", + .id = CHOWMULTITOOL_CLAP_ID, +}; + +static auto getUserPresetsFolder() +{ + chowdsp::SharedPluginSettings pluginSettings; + pluginSettings->initialise (settingsFilePath, 0); + + static constexpr auto propertyID = chowdsp::presets::frontend::SettingsInterface::userPresetsDirID; + if (! pluginSettings->hasProperty (propertyID)) + return juce::File {}; + + const auto userPresetsPath = pluginSettings->getProperty (propertyID); + return juce::File { userPresetsPath }; +} + +//============================================================================== +struct FactoryPresetsProvider : chowdsp::presets::discovery::EmbeddedPresetsProvider +{ + static constexpr clap_preset_discovery_provider_descriptor descriptor { + .clap_version = CLAP_VERSION_INIT, + .id = "org.chowdsp.ChowMultiTool.factory-presets", + .name = "ChowMultiTool Factory Presets Provider", + .vendor = "ChowDSP" + }; + + static constexpr clap_preset_discovery_location factoryPresetsLocation { + .flags = CLAP_PRESET_DISCOVERY_IS_FACTORY_CONTENT, + .name = "ChowMultiTool Factory Presets Location", + .kind = CLAP_PRESET_DISCOVERY_LOCATION_PLUGIN, + .location = nullptr, + }; + + explicit FactoryPresetsProvider (const clap_preset_discovery_indexer* indexer) + : EmbeddedPresetsProvider (plugin_id, descriptor, factoryPresetsLocation, indexer) + { + } + + std::vector getPresets() override + { + return PresetManager::getFactoryPresets(); + } +}; + +//============================================================================== +struct UserPresetsProvider : chowdsp::presets::discovery::FilePresetsProvider +{ + static constexpr clap_preset_discovery_provider_descriptor descriptor { + .clap_version = CLAP_VERSION_INIT, + .id = "org.chowdsp.ChowMultiTool.user-presets", + .name = "ChowMultiTool User Presets Provider", + .vendor = "User" + }; + + + static constexpr clap_preset_discovery_filetype filetype { + .name = "User Preset Filetype", + .description = "User preset filetype for ChowMultiTool", + .file_extension = "chowpreset", + }; + + explicit UserPresetsProvider (const clap_preset_discovery_indexer* indexer) + : FilePresetsProvider (plugin_id, descriptor, filetype, indexer) + { + } + + bool fillInLocation(clap_preset_discovery_location& location) override + { + const auto userPresetsFolder = getUserPresetsFolder(); + if (userPresetsFolder == juce::File {} || ! userPresetsFolder.isDirectory()) + return false; + + location.name = "ChowMultiTool User Presets Location"; + location.location = userPresetsFolder.getFullPathName().toRawUTF8(); + return true; + } +}; + +//============================================================================== +uint32_t count (const clap_preset_discovery_factory*) +{ + const auto userPresetsFolder = getUserPresetsFolder(); + if (userPresetsFolder == juce::File {} || ! userPresetsFolder.isDirectory()) + return 1; + return 2; +} + +const clap_preset_discovery_provider_descriptor_t* get_descriptor ( + const clap_preset_discovery_factory*, + uint32_t index) +{ + if (index == 0) + return &FactoryPresetsProvider::descriptor; + + if (index == 1) + return &UserPresetsProvider::descriptor; + + return nullptr; +} + +const clap_preset_discovery_provider_t* create ( + const clap_preset_discovery_factory*, + const clap_preset_discovery_indexer_t* indexer, + const char* provider_id) +{ + if (strcmp (provider_id, FactoryPresetsProvider::descriptor.id) == 0) + { + auto* provider = new FactoryPresetsProvider { indexer }; + return provider->provider(); + } + + if (strcmp (provider_id, UserPresetsProvider::descriptor.id) == 0) + { + auto* provider = new UserPresetsProvider { indexer }; + return provider->provider(); + } + + return nullptr; +} +} // namespace state::presets::discovery +#endif diff --git a/src/state/presets/PresetDiscovery.h b/src/state/presets/PresetDiscovery.h new file mode 100644 index 0000000..0a13217 --- /dev/null +++ b/src/state/presets/PresetDiscovery.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace state::presets::discovery +{ +uint32_t count (const clap_preset_discovery_factory* factory); + +const clap_preset_discovery_provider_descriptor_t* get_descriptor ( + const clap_preset_discovery_factory* factory, + uint32_t index); + +const clap_preset_discovery_provider_t* create ( + const clap_preset_discovery_factory* factory, + const clap_preset_discovery_indexer_t* indexer, + const char* provider_id); +} // namespace state::presets::discovery diff --git a/src/state/PresetManager.cpp b/src/state/presets/PresetManager.cpp similarity index 88% rename from src/state/PresetManager.cpp rename to src/state/presets/PresetManager.cpp index dc29cc4..f538642 100644 --- a/src/state/PresetManager.cpp +++ b/src/state/presets/PresetManager.cpp @@ -8,6 +8,29 @@ using namespace chowdsp::presets; constexpr std::string_view presetParamsTag { "preset_params" }; constexpr std::string_view presetWaveshaperStateTag { "ws_state" }; +const auto createPresetFromEmbeddedFile = [] (const cmrc::embedded_filesystem& fs, + const std::string& path) -> Preset +{ + const auto presetFile = fs.open (path); + return { presetFile.begin(), presetFile.size() }; +}; + +std::vector PresetManager::getFactoryPresets() +{ + const auto fs = cmrc::presets::get_filesystem(); + + std::vector factoryPresets; + factoryPresets.reserve (32); + for (auto&& entry : fs.iterate_directory ("")) + { + jassert (entry.is_file()); + jassert (fs.exists (entry.filename())); + factoryPresets.emplace_back (createPresetFromEmbeddedFile (fs, entry.filename())); + } + + return factoryPresets; +} + PresetManager::PresetManager (ChowMultiTool& plugin) : chowdsp::presets::PresetManager (plugin.getState(), &plugin, ".chowpreset"), toolParam (*plugin.getState().params.toolParam) @@ -70,22 +93,9 @@ PresetManager::PresetManager (ChowMultiTool& plugin) } }; - const auto fs = cmrc::presets::get_filesystem(); - const auto createPresetFromEmbeddedFile = [&fs] (const std::string& path) -> Preset - { - const auto presetFile = fs.open (path); - return { presetFile.begin(), presetFile.size() }; - }; - - std::vector factoryPresets; - for (auto&& entry : fs.iterate_directory ("")) - { - jassert (entry.is_file()); - jassert (fs.exists (entry.filename())); - factoryPresets.emplace_back (createPresetFromEmbeddedFile (entry.filename())); - } + auto factoryPresets = getFactoryPresets(); addPresets (std::move (factoryPresets)); - setDefaultPreset (createPresetFromEmbeddedFile ("Init.chowpreset")); + setDefaultPreset (createPresetFromEmbeddedFile (cmrc::presets::get_filesystem(), "Init.chowpreset")); presetsSettings.emplace (*this, *pluginSettings, @@ -97,7 +107,7 @@ PresetManager::PresetManager (ChowMultiTool& plugin) Preset PresetManager::getUserPresetForState (const juce::String& presetName, nlohmann::json&& presetState) const { - std::cout << presetState << std::endl; + DBG (presetState.dump()); const auto toolParamIndex = presetState[presetParamsTag][toolParam.paramID.toStdString()].get(); if (toolParamIndex == 0) return chowdsp::presets::PresetManager::getUserPresetForState (presetName, std::move (presetState)); diff --git a/src/state/PresetManager.h b/src/state/presets/PresetManager.h similarity index 90% rename from src/state/PresetManager.h rename to src/state/presets/PresetManager.h index db29d6b..29b4ca8 100644 --- a/src/state/PresetManager.h +++ b/src/state/presets/PresetManager.h @@ -14,6 +14,8 @@ class PresetManager : public chowdsp::presets::PresetManager [[nodiscard]] chowdsp::presets::Preset getUserPresetForState (const juce::String& presetName, nlohmann::json&& presetState) const override; auto* getPresetSettings() { return &(*presetsSettings); } + static std::vector getFactoryPresets(); + private: chowdsp::SharedPluginSettings pluginSettings; std::optional presetsSettings;