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:
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