diff --git a/.github/workflows/pullreq.yml b/.github/workflows/pullreq.yml index a9d916b..ac0c521 100644 --- a/.github/workflows/pullreq.yml +++ b/.github/workflows/pullreq.yml @@ -31,11 +31,11 @@ jobs: # name: Windows gcc/minGW # exe: .exe - - os: windows-latest - cmakeargs: -GNinja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang - install_ninja: true - name: Windows clang - exe: .exe +# - os: windows-latest +# cmakeargs: -GNinja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang +# install_ninja: true +# name: Windows clang +# exe: .exe - os: ubuntu-latest cmakeargs: -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_C_COMPILER=gcc-12 -DCLAP_HELPERS_TESTS_CXX_STANDARD=11 diff --git a/.gitignore b/.gitignore index 4ee5684..96a5983 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ ignore/ build/ out/ .DS_Store + +# Meson +.meson-subproject* diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc47a0..cfe65ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.17) cmake_policy(SET CMP0100 NEW) # handle .hh files project(clap-helpers C CXX) +include(GNUInstallDirs) option(CLAP_HELPERS_BUILD_TESTS "Build tests for the CLAP Helper" FALSE) option(CLAP_HELPERS_DOWNLOAD_DEPENDENCIES "Resolve CLAP Targets with CPM if not defined" FALSE) @@ -97,5 +98,5 @@ if (${CLAP_HELPERS_BUILD_TESTS}) ) endif() -install(DIRECTORY include DESTINATION ".") -install(FILES "cmake/clap-helpers-config.cmake" DESTINATION "lib/cmake/clap-helpers") +install(DIRECTORY "include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +install(FILES "cmake/clap-helpers-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/clap-helpers") diff --git a/cmake/external/CPM.cmake b/cmake/external/CPM.cmake index ad6b74a..b5c0ffa 100644 --- a/cmake/external/CPM.cmake +++ b/cmake/external/CPM.cmake @@ -2,8 +2,8 @@ # # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors -set(CPM_DOWNLOAD_VERSION 0.38.6) -set(CPM_HASH_SUM "11c3fa5f1ba14f15d31c2fb63dbc8628ee133d81c8d764caad9a8db9e0bacb07") +set(CPM_DOWNLOAD_VERSION 0.42.0) +set(CPM_HASH_SUM "2020B4FC42DBA44817983E06342E682ECFC3D2F484A581F11CC5731FBE4DCE8A") if(CPM_SOURCE_CACHE) set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") diff --git a/include/clap/helpers/host-proxy.hh b/include/clap/helpers/host-proxy.hh index a0b3a2f..383d184 100644 --- a/include/clap/helpers/host-proxy.hh +++ b/include/clap/helpers/host-proxy.hh @@ -216,6 +216,12 @@ namespace clap { namespace helpers { bool miniCurveDisplayGetHints(uint32_t kind, clap_mini_curve_display_curve_hints_t *hints) const noexcept; + //////////////////////////// + // nl_clap_plugin_webview // + //////////////////////////// + bool canUseWebview() const noexcept; + bool webviewSend(const void *buffer, uint32_t size) const noexcept; + protected: void ensureMainThread(const char *method) const noexcept; void ensureAudioThread(const char *method) const noexcept; @@ -245,5 +251,6 @@ namespace clap { namespace helpers { const clap_host_undo *_hostUndo = nullptr; const clap_host_scratch_memory *_hostScratchMemory = nullptr; const clap_host_mini_curve_display *_hostMiniCurveDisplay = nullptr; + const clap_host_webview *_hostWebview = nullptr; }; }} // namespace clap::helpers diff --git a/include/clap/helpers/host-proxy.hxx b/include/clap/helpers/host-proxy.hxx index ac9f640..16e29e5 100644 --- a/include/clap/helpers/host-proxy.hxx +++ b/include/clap/helpers/host-proxy.hxx @@ -43,6 +43,7 @@ namespace clap { namespace helpers { getExtension(_hostUndo, CLAP_EXT_UNDO); getExtension(_hostScratchMemory, CLAP_EXT_SCRATCH_MEMORY); getExtension(_hostMiniCurveDisplay, CLAP_EXT_MINI_CURVE_DISPLAY); + getExtension(_hostWebview, CLAP_EXT_WEBVIEW); } template @@ -810,14 +811,28 @@ namespace clap { namespace helpers { bool HostProxy::miniCurveDisplayGetHints( uint32_t kind, clap_mini_curve_display_curve_hints_t *hints) const noexcept { assert(canUseMiniCurveDisplay()); - ensureMainThread("mini_curve_display_get_hints"); + ensureMainThread("mini_curve_display.get_hints"); if (!hints) { - pluginMisbehaving("mini_curve_display_get_hints() called with a null hints pointer"); + pluginMisbehaving("mini_curve_display.get_hints() called with a null hints pointer"); return false; } return _hostMiniCurveDisplay->get_hints(_host, kind, hints); } + //////////////////////// + // clap_host_web_view // + //////////////////////// + template + bool HostProxy::canUseWebview() const noexcept { + return _hostWebview && _hostWebview->send; + } + + template + bool HostProxy::webviewSend(const void *buffer, uint32_t size) const noexcept { + assert(canUseWebview()); + this->ensureMainThread("webview.send"); + return _hostWebview->send(this->_host, buffer, size); + } }} // namespace clap::helpers diff --git a/include/clap/helpers/host.hh b/include/clap/helpers/host.hh index 71f3b74..5d11332 100644 --- a/include/clap/helpers/host.hh +++ b/include/clap/helpers/host.hh @@ -51,6 +51,7 @@ namespace clap { namespace helpers { virtual void requestCallback() noexcept = 0; virtual bool enableDraftExtensions() const noexcept { return false; } + virtual const void* getExtension(const char* extensionId) const noexcept { return nullptr; } // clap_host_audio_ports virtual bool implementsAudioPorts() const noexcept { return false; } @@ -107,6 +108,14 @@ namespace clap { namespace helpers { virtual bool implementsThreadPool() const noexcept { return false; } virtual bool threadPoolRequestExec(uint32_t numTasks) noexcept { return false; } + // clap_host_surround + virtual bool implementsSurround() const noexcept { return false; } + virtual void surroundChanged() noexcept {} + + // clap_host_webview + virtual bool implementsWebview() const noexcept { return false; } + virtual bool webviewSend(const void *buffer, uint32_t size) const noexcept { return false; } + ///////////////////// // Thread Checking // ///////////////////// @@ -173,7 +182,9 @@ namespace clap { namespace helpers { static void clapStateMarkDirty(const clap_host *host) noexcept; // clap_host_timer_support - static bool clapTimerSupportRegisterTimer(const clap_host *host, uint32_t period_ms, clap_id *timer_id) noexcept; + static bool clapTimerSupportRegisterTimer(const clap_host *host, + uint32_t period_ms, + clap_id *timer_id) noexcept; static bool clapTimerSupportUnregisterTimer(const clap_host *host, clap_id timer_id) noexcept; // clap_host_tail @@ -186,6 +197,12 @@ namespace clap { namespace helpers { // clap_host_thread_pool static bool clapThreadPoolRequestExec(const clap_host *host, uint32_t num_tasks) noexcept; + // clap_host_surround + static void clapSurroundChanged(const clap_host_t *host) noexcept; + + // clap_host_webview + static bool clapWebviewSend(const clap_host_t *host, const void *buffer, uint32_t size); + // interfaces static const clap_host_audio_ports _hostAudioPorts; static const clap_host_gui _hostGui; @@ -199,5 +216,7 @@ namespace clap { namespace helpers { static const clap_host_tail _hostTail; static const clap_host_thread_check _hostThreadCheck; static const clap_host_thread_pool _hostThreadPool; + static const clap_host_surround _hostSurround; + static const clap_host_webview _hostWebview; }; }} // namespace clap::helpers diff --git a/include/clap/helpers/host.hxx b/include/clap/helpers/host.hxx index 428ebce..e1bd0fa 100644 --- a/include/clap/helpers/host.hxx +++ b/include/clap/helpers/host.hxx @@ -81,6 +81,16 @@ namespace clap { namespace helpers { clapThreadPoolRequestExec, }; + template + const clap_host_surround Host::_hostSurround = { + clapSurroundChanged, + }; + + template + const clap_host_webview Host::_hostWebview = { + clapWebviewSend, + }; + template Host::Host(const char *name, const char *vendor, const char *url, const char *version) : _host{ @@ -132,6 +142,8 @@ namespace clap { namespace helpers { const void *Host::clapGetExtension(const clap_host_t *host, const char *extension_id) noexcept { auto &self = from(host); + if (auto ext = self.getExtension(extension_id)) + return ext; if (!std::strcmp(extension_id, CLAP_EXT_AUDIO_PORTS) && self.implementsAudioPorts()) return &_hostAudioPorts; if (!std::strcmp(extension_id, CLAP_EXT_GUI) && self.implementsGui()) @@ -158,10 +170,15 @@ namespace clap { namespace helpers { return &_hostThreadCheck; if (!strcmp(extension_id, CLAP_EXT_THREAD_POOL) && self.implementsThreadPool()) return &_hostThreadPool; + if (!std::strcmp(extension_id, CLAP_EXT_SURROUND) && self.implementsSurround()) + return &_hostSurround; if (self.enableDraftExtensions()) { + if (!strcmp(extension_id, CLAP_EXT_WEBVIEW) && self.implementsWebview()) + return &_hostWebview; // put draft ext here } + return nullptr; } @@ -394,6 +411,26 @@ namespace clap { namespace helpers { return self.threadPoolRequestExec(num_tasks); } + //--------------------// + // clap_host_surround // + //--------------------// + template + void Host::clapSurroundChanged(const clap_host *host) noexcept { + auto &self = from(host); + self.ensureMainThread("surround.changed"); + self.surroundChanged(); + } + + //-------------------// + // clap_host_webview // + //-------------------// + template + bool Host::clapWebviewSend(const clap_host_t *host, const void *buffer, uint32_t size) { + auto &self = from(host); + self.ensureMainThread("webview.send"); + return self.webviewSend(buffer, size); + } + ///////////////////// // Thread Checking // ///////////////////// diff --git a/include/clap/helpers/plugin-proxy.hh b/include/clap/helpers/plugin-proxy.hh index ff56860..26dd99a 100644 --- a/include/clap/helpers/plugin-proxy.hh +++ b/include/clap/helpers/plugin-proxy.hh @@ -152,6 +152,13 @@ namespace clap { namespace helpers { bool canUseGainAdjustmentMetering() const noexcept; double gainAdjustmentMeteringGet() const noexcept; + ///////////////////////// + // clap_plugin_webview // + ///////////////////////// + bool canUseWebview() const noexcept; + int32_t webviewGetUri(char *uri, uint32_t uriCapacity) const noexcept; + bool webviewReceive(const void *buffer, uint32_t size) const noexcept; + protected: ///////////////////// // Thread Checking // @@ -181,6 +188,7 @@ namespace clap { namespace helpers { const clap_plugin_project_location *_pluginProjectLocation = nullptr; const clap_plugin_gain_adjustment_metering *_pluginGainAdjustmentMetering = nullptr; const clap_plugin_mini_curve_display *_pluginMiniCurveDisplay = nullptr; + const clap_plugin_webview* _pluginWebview = nullptr; // state bool _isActive = false; diff --git a/include/clap/helpers/plugin-proxy.hxx b/include/clap/helpers/plugin-proxy.hxx index 0f3a867..c6a28ef 100644 --- a/include/clap/helpers/plugin-proxy.hxx +++ b/include/clap/helpers/plugin-proxy.hxx @@ -35,6 +35,7 @@ namespace clap { namespace helpers { getExtension(_pluginProjectLocation, CLAP_EXT_PROJECT_LOCATION); getExtension(_pluginGainAdjustmentMetering, CLAP_EXT_GAIN_ADJUSTMENT_METERING); getExtension(_pluginMiniCurveDisplay, CLAP_EXT_MINI_CURVE_DISPLAY); + getExtension(_pluginWebview, CLAP_EXT_WEBVIEW); return true; } @@ -644,6 +645,28 @@ namespace clap { namespace helpers { return gain; } + ///////////////////////// + // clap_plugin_webview // + ///////////////////////// + template + bool PluginProxy::canUseWebview() const noexcept { + return _pluginWebview && _pluginWebview->get_uri && _pluginWebview->receive; + } + + template + int32_t PluginProxy::webviewGetUri(char *uri, uint32_t uriCapacity) const noexcept { + assert(canUseWebview()); + ensureMainThread("webview.get_uri"); + return _pluginWebview->get_uri(&this->_plugin, uri, uriCapacity); + } + + template + bool PluginProxy::webviewReceive(const void *buffer, uint32_t size) const noexcept { + assert(canUseWebview()); + ensureMainThread("webview.receive"); + return _pluginWebview->receive(&this->_plugin, buffer, size); + } + ///////////////////// // Thread Checking // ///////////////////// diff --git a/include/clap/helpers/plugin.hh b/include/clap/helpers/plugin.hh index 84dc9da..472cb54 100644 --- a/include/clap/helpers/plugin.hh +++ b/include/clap/helpers/plugin.hh @@ -163,6 +163,18 @@ namespace clap { namespace helpers { return false; } + //----------------------// + // clap_plugin_surround // + //----------------------// + virtual bool implementsSurround() const noexcept { return false; } + virtual bool isChannelMaskSupported(uint64_t channel_mask) const noexcept { return false; } + virtual uint32_t getChannelMap(bool is_input, + uint32_t port_index, + uint8_t *channel_map, + uint32_t channel_map_capacity) const noexcept { + return 0; + } + //--------------------// // clap_plugin_params // //--------------------// @@ -352,6 +364,21 @@ namespace clap { namespace helpers { return false; } + //---------------------// + // clap_plugin_webview // + //---------------------// + virtual bool implementsWebview() const noexcept { return false; } + virtual int32_t webviewGetUri(char *uri, uint32_t uriCapacity) const noexcept { return 0; } + virtual bool webviewGetResource(const char *path, + char *mime, + uint32_t mime_capacity, + const clap_ostream_t *data_stream) { + return false; + } + virtual bool webviewReceive(const void *buffer, uint32_t size) const noexcept { + return false; + } + ///////////// // Logging // ///////////// @@ -505,6 +532,15 @@ namespace clap { namespace helpers { const clap_audio_port_configuration_request *requests, uint32_t request_count) noexcept; + // clap_plugin_surround + static bool clapSurroundIsChannelMaskSupported(const clap_plugin_t *plugin, + uint64_t channel_mask) noexcept; + static uint32_t clapSurroundGetChannelMap(const clap_plugin_t *plugin, + bool is_input, + uint32_t port_index, + uint8_t *channel_map, + uint32_t channel_map_capacity) noexcept; + // clap_plugin_params static uint32_t clapParamsCount(const clap_plugin *plugin) noexcept; static bool clapParamsInfo(const clap_plugin *plugin, @@ -656,11 +692,23 @@ namespace clap { namespace helpers { char *y_name, uint32_t name_capacity) noexcept; + // clap_plugin_webview + static int32_t + clapWebviewGetUri(const clap_plugin_t *plugin, char *uri, uint32_t uri_capacity); + static bool clapWebviewGetResource(const clap_plugin_t *plugin, + const char *path, + char *mime, + uint32_t mime_capacity, + const clap_ostream_t *data_stream); + static bool + clapWebviewReceive(const clap_plugin_t *plugin, const void *buffer, uint32_t size); + // interfaces static const clap_plugin_audio_ports _pluginAudioPorts; static const clap_plugin_audio_ports_config _pluginAudioPortsConfig; static const clap_plugin_audio_ports_activation _pluginAudioPortsActivation; static const clap_plugin_configurable_audio_ports _pluginConfigurableAudioPorts; + static const clap_plugin_surround_t _pluginSurroundConfig; static const clap_plugin_gui _pluginGui; static const clap_plugin_latency _pluginLatency; static const clap_plugin_note_name _pluginNoteName; @@ -685,6 +733,7 @@ namespace clap { namespace helpers { static const clap_plugin_project_location _pluginProjectLocation; static const clap_plugin_gain_adjustment_metering _pluginGainAdjustmentMetering; static const clap_plugin_mini_curve_display _pluginMiniCurveDisplay; + static const clap_plugin_webview _pluginWebview; // state bool _wasInitialized = false; diff --git a/include/clap/helpers/plugin.hxx b/include/clap/helpers/plugin.hxx index d366fdf..200e432 100644 --- a/include/clap/helpers/plugin.hxx +++ b/include/clap/helpers/plugin.hxx @@ -69,6 +69,12 @@ namespace clap { namespace helpers { clapConfigurableAudioPortsApplyConfiguration, }; + template + const clap_plugin_surround_t Plugin::_pluginSurroundConfig = { + clapSurroundIsChannelMaskSupported, + clapSurroundGetChannelMap, + }; + template const clap_plugin_params Plugin::_pluginParams = { clapParamsCount, @@ -189,6 +195,13 @@ namespace clap { namespace helpers { clapMiniCurveDisplayGetAxisName, }; + template + const clap_plugin_webview Plugin::_pluginWebview = { + clapWebviewGetUri, + clapWebviewGetResource, + clapWebviewReceive, + }; + template Plugin::Plugin(const clap_plugin_descriptor *desc, const clap_host *host) : _host(host) { _plugin.plugin_data = this; @@ -484,6 +497,8 @@ namespace clap { namespace helpers { auto &self = from(plugin); self.ensureInitialized("extension"); + if (auto ext = self.extension(id)) + return ext; if (!strcmp(id, CLAP_EXT_STATE) && self.implementsState()) return &_pluginState; if (!strcmp(id, CLAP_EXT_STATE_CONTEXT) && self.implementsStateContext() && @@ -507,6 +522,8 @@ namespace clap { namespace helpers { return &_pluginAudioPortsActivation; if (!strcmp(id, CLAP_EXT_AUDIO_PORTS_CONFIG) && self.implementsAudioPortsConfig()) return &_pluginAudioPortsConfig; + if (!strcmp(id, CLAP_EXT_SURROUND) && self.implementsSurround()) + return &_pluginSurroundConfig; if (!strcmp(id, CLAP_EXT_CONFIGURABLE_AUDIO_PORTS) && self.implementsConfigurableAudioPorts()) return &_pluginConfigurableAudioPorts; if (!strcmp(id, CLAP_EXT_PARAMS) && self.implementsParams()) @@ -552,9 +569,11 @@ namespace clap { namespace helpers { return &_pluginGainAdjustmentMetering; if (!strcmp(id, CLAP_EXT_MINI_CURVE_DISPLAY) && self.implementsMiniCurveDisplay()) return &_pluginMiniCurveDisplay; + if (!strcmp(id, CLAP_EXT_WEBVIEW) && self.implementsWebview()) + return &_pluginWebview; } - return self.extension(id); + return nullptr; } //-------------------// @@ -886,6 +905,42 @@ namespace clap { namespace helpers { return applyConfigurationSuccess; } + //----------------------// + // clap_plugin_surround // + //----------------------// + template + bool Plugin::clapSurroundIsChannelMaskSupported(const clap_plugin_t *plugin, + uint64_t channel_mask) noexcept { + auto &self = from(plugin); + auto methodName = "clap_plugin_surround.is_channel_mask_supported"; + self.ensureMainThread(methodName); + + return self.isChannelMaskSupported(channel_mask); + } + + template + uint32_t Plugin::clapSurroundGetChannelMap(const clap_plugin_t *plugin, + bool is_input, + uint32_t port_index, + uint8_t *channel_map, + uint32_t channel_map_capacity) noexcept { + auto &self = from(plugin); + auto methodName = "clap_plugin_surround.get_channel_map"; + self.ensureMainThread(methodName); + + const uint32_t channel_count = + self.getChannelMap(is_input, port_index, channel_map, channel_map_capacity); + + if (l >= CheckingLevel::Minimal && channel_count > channel_map_capacity) { + self._host.pluginMisbehaving( + "Plugin's functions clap_plugin_surround.get_channel_map cannot return a channel " + "count greater than channel_map_capacity."); + return channel_map_capacity; + } + + return channel_count; + } + //--------------------// // clap_plugin_params // //--------------------// @@ -1940,6 +1995,37 @@ namespace clap { namespace helpers { return self.miniCurveDisplayGetAxisName(curve_index, x_name, y_name, name_capacity); } + //--------------------------------// + // clap_plugin_mini_curve_display // + //--------------------------------// + template + int32_t + Plugin::clapWebviewGetUri(const clap_plugin_t *plugin, char *uri, uint32_t uri_capacity) { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_webview.get_uri"); + return self.webviewGetUri(uri, uri_capacity); + } + + template + bool Plugin::clapWebviewGetResource(const clap_plugin_t *plugin, + const char *path, + char *mime, + uint32_t mime_capacity, + const clap_ostream_t *data_stream) { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_webview.get_resource"); + return self.webviewGetResource(path, mime, mime_capacity, data_stream); + } + + template + bool Plugin::clapWebviewReceive(const clap_plugin_t *plugin, + const void *buffer, + uint32_t size) { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_webview.receive"); + return self.webviewReceive(buffer, size); + } + ///////////// // Logging // /////////////