clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit 6b01b60ca09524e75675ed2684798d7d0735da0b
parent 4dca98722de3ff5f58e29b6ee7d4b75e70010f3e
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Mon, 20 Sep 2021 18:42:38 +0200

Add a way for the plugin to request a callback on the main thread

Diffstat:
Mexamples/glue/clap-plugin.cc | 39+++++++++++++++++++++++----------------
Mexamples/glue/clap-plugin.hh | 16+++++++---------
Mexamples/host/plugin-host.cc | 32+++++++++++++++++++++++++-------
Mexamples/host/plugin-host.hh | 18++++++++++++------
Minclude/clap/host.h | 4++++
Minclude/clap/plugin.h | 5+++++
Minclude/clap/version.h | 2+-
7 files changed, 77 insertions(+), 39 deletions(-)

diff --git a/examples/glue/clap-plugin.cc b/examples/glue/clap-plugin.cc @@ -11,16 +11,16 @@ namespace clap { Plugin::Plugin(const clap_plugin_descriptor *desc, const clap_host *host) : _host(host) { - plugin_.plugin_data = this; - plugin_.desc = desc; - plugin_.init = Plugin::clapInit; - plugin_.destroy = Plugin::clapDestroy; - plugin_.get_extension = nullptr; - plugin_.process = nullptr; - plugin_.activate = nullptr; - plugin_.deactivate = nullptr; - plugin_.start_processing = nullptr; - plugin_.stop_processing = nullptr; + _plugin.plugin_data = this; + _plugin.desc = desc; + _plugin.init = Plugin::clapInit; + _plugin.destroy = Plugin::clapDestroy; + _plugin.get_extension = nullptr; + _plugin.process = nullptr; + _plugin.activate = nullptr; + _plugin.deactivate = nullptr; + _plugin.start_processing = nullptr; + _plugin.stop_processing = nullptr; } Plugin::~Plugin() = default; @@ -35,12 +35,13 @@ namespace clap { bool Plugin::clapInit(const clap_plugin *plugin) noexcept { auto &self = from(plugin); - self.plugin_.get_extension = Plugin::clapExtension; - self.plugin_.process = Plugin::clapProcess; - self.plugin_.activate = Plugin::clapActivate; - self.plugin_.deactivate = Plugin::clapDeactivate; - self.plugin_.start_processing = Plugin::clapStartProcessing; - self.plugin_.stop_processing = Plugin::clapStopProcessing; + self._plugin.get_extension = Plugin::clapExtension; + self._plugin.process = Plugin::clapProcess; + self._plugin.activate = Plugin::clapActivate; + self._plugin.deactivate = Plugin::clapDeactivate; + self._plugin.start_processing = Plugin::clapStartProcessing; + self._plugin.stop_processing = Plugin::clapStopProcessing; + self._plugin.on_main_thread = Plugin::clapOnMainThread; self.initInterfaces(); self.ensureMainThread("clap_plugin.init"); @@ -53,6 +54,12 @@ namespace clap { delete &from(plugin); } + void Plugin::clapOnMainThread(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin.on_main_thread"); + self.onMainThread(); + } + bool Plugin::clapActivate(const clap_plugin *plugin, double sample_rate) noexcept { auto &self = from(plugin); self.ensureMainThread("clap_plugin.activate"); diff --git a/examples/glue/clap-plugin.hh b/examples/glue/clap-plugin.hh @@ -13,7 +13,7 @@ namespace clap { /// @note for an higher level implementation, see @ref PluginHelper class Plugin { public: - const clap_plugin *clapPlugin() noexcept { return &plugin_; } + const clap_plugin *clapPlugin() noexcept { return &_plugin; } protected: Plugin(const clap_plugin_descriptor *desc, const clap_host *host); @@ -40,6 +40,7 @@ namespace clap { virtual clap_process_status process(const clap_process *process) noexcept { return CLAP_PROCESS_SLEEP; } + virtual void onMainThread() noexcept {} virtual const void *extension(const char *id) noexcept { return nullptr; } //---------------------// @@ -261,7 +262,7 @@ namespace clap { // CLAP Interfaces // ///////////////////// - clap_plugin plugin_; + clap_plugin _plugin; // clap_plugin static bool clapInit(const clap_plugin *plugin) noexcept; static void clapDestroy(const clap_plugin *plugin) noexcept; @@ -271,6 +272,7 @@ namespace clap { static void clapStopProcessing(const clap_plugin *plugin) noexcept; static clap_process_status clapProcess(const clap_plugin *plugin, const clap_process *process) noexcept; + static void clapOnMainThread(const clap_plugin *plugin) noexcept; static const void *clapExtension(const clap_plugin *plugin, const char *id) noexcept; // latency @@ -392,10 +394,8 @@ namespace clap { clapTrackInfoChanged, }; - static const constexpr clap_plugin_audio_ports _pluginAudioPorts = { - clapAudioPortsCount, - clapAudioPortsInfo - }; + static const constexpr clap_plugin_audio_ports _pluginAudioPorts = {clapAudioPortsCount, + clapAudioPortsInfo}; static const constexpr clap_plugin_audio_ports_config _pluginAudioPortsConfig = { clapAudioPortsConfigCount, @@ -427,9 +427,7 @@ namespace clap { clapNoteNameGet, }; - static const constexpr clap_plugin_timer_support _pluginTimerSupport = { - clapOnTimer - }; + static const constexpr clap_plugin_timer_support _pluginTimerSupport = {clapOnTimer}; static const constexpr clap_plugin_fd_support _pluginFdSupport = { clapOnFd, diff --git a/examples/host/plugin-host.cc b/examples/host/plugin-host.cc @@ -29,11 +29,14 @@ PluginHost::PluginHost(Engine &engine) : QObject(&engine), _engine(engine) { host_.host_data = this; host_.clap_version = CLAP_VERSION; - host_.get_extension = PluginHost::clapExtension; host_.name = "Clap Test Host"; host_.version = "0.1.0"; host_.vendor = "clap"; host_.url = "https://github.com/free-audio/clap"; + host_.get_extension = PluginHost::clapExtension; + host_.request_callback = PluginHost::clapRequestCallback; + host_.request_process = PluginHost::clapRequestProcess; + host_.request_restart = PluginHost::clapRequestRestart; initThreadPool(); } @@ -318,6 +321,19 @@ void PluginHost::setPluginWindowVisibility(bool isVisible) { } } +void PluginHost::clapRequestCallback(const clap_host *host) { + h->_scheduleMainThreadCallback = true; +} + +void PluginHost::clapRequestProcess(const clap_host *host) { + // nothing to do we always process for now +} + +void PluginHost::clapRequestRestart(const clap_host *host) { + auto h = fromHost(host); + h->_scheduleRestart = true; +} + void PluginHost::clapLog(const clap_host *host, clap_log_severity severity, const char *msg) { switch (severity) { case CLAP_LOG_DEBUG: @@ -348,10 +364,7 @@ void PluginHost::initPluginExtension(const T *&ext, const char *id) { const void *PluginHost::clapExtension(const clap_host *host, const char *extension) { checkForMainThread(); - PluginHost *h = static_cast<PluginHost *>(host->host_data); - if (!h->_plugin) - throw std::logic_error("The plugin can't query for extensions during the create method. Wait " - "for clap_plugin.init() call."); + auto h = fromHost(host); if (!strcmp(extension, CLAP_EXT_GUI)) return &h->_hostGui; @@ -381,8 +394,8 @@ PluginHost *PluginHost::fromHost(const clap_host *host) { throw std::invalid_argument("Passed an invalid host pointer because the host_data is null"); if (!h->_plugin) - throw std::logic_error( - "Called into host interfaces befores the host knows the plugin pointer"); + throw std::logic_error("The plugin can't query for extensions during the create method. Wait " + "for clap_plugin.init() call."); return h; } @@ -769,6 +782,11 @@ void PluginHost::idle() { it->second->setValue(value.value); it->second->setIsAdjusting(value.isAdjusting); }); + + if (_scheduleMainThreadCallback) { + _scheduleMainThreadCallback = false; + _plugin->on_main_thread(_plugin); + } } PluginParam &PluginHost::checkValidParamId(const std::string_view &function, diff --git a/examples/host/plugin-host.hh b/examples/host/plugin-host.hh @@ -86,6 +86,10 @@ private: /* clap host callbacks */ static void clapLog(const clap_host *host, clap_log_severity severity, const char *msg); + static void clapRequestCallback(const clap_host *host); + static void clapRequestRestart(const clap_host *host); + static void clapRequestProcess(const clap_host *host); + static bool clapIsMainThread(const clap_host *host); static bool clapIsAudioThread(const clap_host *host); @@ -107,10 +111,10 @@ private: void scanQuickControls(); void quickControlsSetSelectedPage(clap_id pageId); - static void clapQuickControlsChanged(const clap_host *host, clap_quick_controls_changed_flags flags); + static void clapQuickControlsChanged(const clap_host *host, + clap_quick_controls_changed_flags flags); - static bool - clapRegisterTimer(const clap_host *host, uint32_t period_ms, clap_id *timer_id); + static bool clapRegisterTimer(const clap_host *host, uint32_t period_ms, clap_id *timer_id); static bool clapUnregisterTimer(const clap_host *host, clap_id timer_id); static bool clapRegisterFd(const clap_host *host, clap_fd fd, uint32_t flags); static bool clapModifyFd(const clap_host *host, clap_fd fd, uint32_t flags); @@ -140,10 +144,10 @@ private: static const constexpr clap_host_gui _hostGui = { PluginHost::clapGuiResize, }; - //static const constexpr clap_host_audio_ports hostAudioPorts_; - //static const constexpr clap_host_audio_ports_config hostAudioPortsConfig_; + // static const constexpr clap_host_audio_ports hostAudioPorts_; + // static const constexpr clap_host_audio_ports_config hostAudioPortsConfig_; static const constexpr clap_host_params _hostParams = { -PluginHost::clapParamsRescan, + PluginHost::clapParamsRescan, }; static const constexpr clap_host_quick_controls _hostQuickControls = { PluginHost::clapQuickControlsChanged, @@ -269,4 +273,6 @@ PluginHost::clapParamsRescan, bool _isGuiCreated = false; bool _isGuiVisible = false; + + bool _scheduleMainThreadCallback = false; }; diff --git a/include/clap/host.h b/include/clap/host.h @@ -30,6 +30,10 @@ typedef struct clap_host { // This is useful if you have external IO and need to wake up the plugin from "sleep". // [thread-safe] void (*request_process)(const struct clap_host *host); + + // Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread. + // [thread-safe] + void (*request_callback)(const struct clap_host *host); } clap_host; #ifdef __cplusplus diff --git a/include/clap/plugin.h b/include/clap/plugin.h @@ -86,6 +86,11 @@ typedef struct clap_plugin { * The returned pointer is owned by the plugin. * [thread-safe] */ const void *(*get_extension)(const struct clap_plugin *plugin, const char *id); + + // Called by the host on the main thread in response to a previous call to: + // host->request_callback(host); + // [main-thread] + void (*on_main_thread)(const struct clap_plugin *plugin); } clap_plugin; ///////////////// diff --git a/include/clap/version.h b/include/clap/version.h @@ -22,7 +22,7 @@ typedef struct clap_version { } #endif -static CLAP_CONSTEXPR const clap_version CLAP_VERSION = {0, 13, 0}; +static CLAP_CONSTEXPR const clap_version CLAP_VERSION = {0, 14, 0}; static CLAP_CONSTEXPR inline bool clap_version_is_compatible(const clap_version &v) { // For version 0, we require the same minor version because