commit 63d49ec3ba0ed9f94d0b6fb7b204f089a971e0ca
parent 1f428a898fca85585e4d5ee183d6c143f8a86099
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date: Mon, 24 May 2021 19:27:04 +0200
Work on audio ports management
Diffstat:
5 files changed, 597 insertions(+), 534 deletions(-)
diff --git a/examples/plugins/clap-entry.cc b/examples/plugins/clap-entry.cc
@@ -29,7 +29,7 @@ static void addPlugin() {
}
static bool clap_init(const char *plugin_path) {
- addPlugin<Gain>();
+ addPlugin<clap::Gain>();
return true;
}
diff --git a/examples/plugins/gain/gain.cc b/examples/plugins/gain/gain.cc
@@ -2,59 +2,61 @@
#include "gain.hh"
-const clap_plugin_descriptor *Gain::descriptor() {
- static const clap_plugin_descriptor desc = {
-
- CLAP_VERSION,
- "com.github.free-audio.clap.gain",
- "gain",
- "clap",
- "https://github.com/free-audio/clap",
- nullptr,
- nullptr,
- "0.1",
- "example gain plugin",
- "mix;gain",
- CLAP_PLUGIN_AUDIO_EFFECT
-
- };
- return &desc;
-}
-
-Gain::Gain(clap_host *host) : Plugin(descriptor(), host) {}
-
-bool Gain::activate(int sample_rate) {
- channelCount_ = trackChannelCount();
- return true;
-}
-
-void Gain::deactivate() { channelCount_ = 0; }
-
-clap_process_status Gain::process(const clap_process *process) {
- float **in = process->audio_inputs[0].data32;
- float **out = process->audio_outputs[0].data32;
-
- float k = 1;
- for (int i = 0; i < process->frames_count; ++i) {
- for (int c = 0; c < channelCount_; ++c)
- out[c][i] = k * in[c][i];
+namespace clap {
+ const clap_plugin_descriptor *Gain::descriptor() {
+ static const clap_plugin_descriptor desc = {
+
+ CLAP_VERSION,
+ "com.github.free-audio.clap.gain",
+ "gain",
+ "clap",
+ "https://github.com/free-audio/clap",
+ nullptr,
+ nullptr,
+ "0.1",
+ "example gain plugin",
+ "mix;gain",
+ CLAP_PLUGIN_AUDIO_EFFECT
+
+ };
+ return &desc;
}
- return CLAP_PROCESS_CONTINUE_IF_NOT_QUIET;
-}
-
-void Gain::defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
- std::vector<clap_audio_port_info> &outputPorts) {
- clap_audio_port_info info;
- info.id = 0;
- strncpy(info.name, "main", sizeof(info.name));
- info.is_main = true;
- info.is_cv = false;
- info.supports_64_bits = false;
- info.supports_in_place = true;
- info.channel_count = channelCount_;
- info.channel_map = CLAP_CHMAP_UNSPECIFIED;
-
- inputPorts.push_back(info);
- outputPorts.push_back(info);
-}
+ Gain::Gain(clap_host *host) : Plugin(descriptor(), host) {}
+
+ bool Gain::activate(int sample_rate) {
+ channelCount_ = trackChannelCount();
+ return true;
+ }
+
+ void Gain::deactivate() { channelCount_ = 0; }
+
+ clap_process_status Gain::process(const clap_process *process) {
+ float **in = process->audio_inputs[0].data32;
+ float **out = process->audio_outputs[0].data32;
+
+ float k = 1;
+ for (int i = 0; i < process->frames_count; ++i) {
+ for (int c = 0; c < channelCount_; ++c)
+ out[c][i] = k * in[c][i];
+ }
+
+ return CLAP_PROCESS_CONTINUE_IF_NOT_QUIET;
+ }
+
+ void Gain::defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
+ std::vector<clap_audio_port_info> &outputPorts) {
+ clap_audio_port_info info;
+ info.id = 0;
+ strncpy(info.name, "main", sizeof(info.name));
+ info.is_main = true;
+ info.is_cv = false;
+ info.supports_64_bits = false;
+ info.supports_in_place = true;
+ info.channel_count = channelCount_;
+ info.channel_map = CLAP_CHMAP_UNSPECIFIED;
+
+ inputPorts.push_back(info);
+ outputPorts.push_back(info);
+ }
+} // namespace clap
+\ No newline at end of file
diff --git a/examples/plugins/gain/gain.hh b/examples/plugins/gain/gain.hh
@@ -4,21 +4,25 @@
#include "../plugin.hh"
-class Gain final : public Plugin {
-public:
- Gain(clap_host *host);
+namespace clap {
+ class Gain final : public Plugin {
+ public:
+ Gain(clap_host *host);
- static const clap_plugin_descriptor *descriptor();
+ static const clap_plugin_descriptor *descriptor();
-protected:
- bool activate(int sample_rate) override;
- void deactivate() override;
- clap_process_status process(const clap_process *process) override;
+ protected:
+ bool activate(int sample_rate) override;
+ void deactivate() override;
+ clap_process_status process(const clap_process *process) override;
- void defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
- std::vector<clap_audio_port_info> &outputPorts) override;
- bool shouldInvalidateAudioPortsDefinitionOnTrackChannelChange() const override { return true; }
+ void defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
+ std::vector<clap_audio_port_info> &outputPorts) override;
+ bool shouldInvalidateAudioPortsDefinitionOnTrackChannelChange() const override {
+ return true;
+ }
-private:
- int channelCount_ = 0;
-};
-\ No newline at end of file
+ private:
+ int channelCount_ = 0;
+ };
+} // namespace clap
+\ No newline at end of file
diff --git a/examples/plugins/plugin.cc b/examples/plugins/plugin.cc
@@ -6,360 +6,402 @@
#include "plugin.hh"
-Plugin::Plugin(const clap_plugin_descriptor *desc, clap_host *host) : host_(host) {
- plugin_.plugin_data = this;
- plugin_.desc = desc;
- plugin_.init = Plugin::clapInit;
- plugin_.destroy = Plugin::clapDestroy;
- plugin_.extension = nullptr;
- plugin_.process = nullptr;
- plugin_.activate = nullptr;
- plugin_.deactivate = nullptr;
- plugin_.start_processing = nullptr;
- plugin_.stop_processing = nullptr;
-}
-
-/////////////////////
-// CLAP Interfaces //
-/////////////////////
-
-// clap_plugin interface
-bool Plugin::clapInit(clap_plugin *plugin) {
- auto &self = from(plugin);
-
- self.plugin_.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.initInterfaces();
- self.ensureMainThread("clap_plugin.init");
- self.initTrackInfo();
- self.defineAudioPorts(self.inputAudioPorts_, self.outputAudioPorts_);
- return self.init();
-}
-
-void Plugin::clapDestroy(clap_plugin *plugin) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin.destroy");
- delete &from(plugin);
-}
-
-bool Plugin::clapActivate(clap_plugin *plugin, int sample_rate) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin.activate");
-
- if (self.isActive_) {
- self.hostMisbehaving("Plugin was activated twice");
-
- if (sample_rate != self.sampleRate_) {
- std::ostringstream msg;
- msg << "The plugin was activated twice and with different sample rates: "
- << self.sampleRate_ << " and " << sample_rate
- << ". The host must deactivate the plugin first." << std::endl
- << "Simulating deactivation.";
- self.hostMisbehaving(msg.str());
- clapDeactivate(plugin);
- }
+namespace clap {
+
+ Plugin::Plugin(const clap_plugin_descriptor *desc, clap_host *host) : host_(host) {
+ plugin_.plugin_data = this;
+ plugin_.desc = desc;
+ plugin_.init = Plugin::clapInit;
+ plugin_.destroy = Plugin::clapDestroy;
+ plugin_.extension = nullptr;
+ plugin_.process = nullptr;
+ plugin_.activate = nullptr;
+ plugin_.deactivate = nullptr;
+ plugin_.start_processing = nullptr;
+ plugin_.stop_processing = nullptr;
}
- if (sample_rate <= 0) {
- std::ostringstream msg;
- msg << "The plugin was activated with an invalid sample rates: " << sample_rate;
- self.hostMisbehaving(msg.str());
- return false;
+ /////////////////////
+ // CLAP Interfaces //
+ /////////////////////
+
+ // clap_plugin interface
+ bool Plugin::clapInit(clap_plugin *plugin) {
+ auto &self = from(plugin);
+
+ self.plugin_.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.initInterfaces();
+ self.ensureMainThread("clap_plugin.init");
+ self.initTrackInfo();
+ self.defineAudioPorts(self.inputAudioPorts_, self.outputAudioPorts_);
+ return self.init();
+ }
+
+ void Plugin::clapDestroy(clap_plugin *plugin) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin.destroy");
+ delete &from(plugin);
}
- assert(!self.isActive_);
- assert(self.sampleRate_ == 0);
+ bool Plugin::clapActivate(clap_plugin *plugin, int sample_rate) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin.activate");
+
+ if (self.isActive_) {
+ self.hostMisbehaving("Plugin was activated twice");
+
+ if (sample_rate != self.sampleRate_) {
+ std::ostringstream msg;
+ msg << "The plugin was activated twice and with different sample rates: "
+ << self.sampleRate_ << " and " << sample_rate
+ << ". The host must deactivate the plugin first." << std::endl
+ << "Simulating deactivation.";
+ self.hostMisbehaving(msg.str());
+ clapDeactivate(plugin);
+ }
+ }
+
+ if (sample_rate <= 0) {
+ std::ostringstream msg;
+ msg << "The plugin was activated with an invalid sample rates: " << sample_rate;
+ self.hostMisbehaving(msg.str());
+ return false;
+ }
- if (!self.activate(sample_rate)) {
assert(!self.isActive_);
assert(self.sampleRate_ == 0);
- return false;
+
+ if (!self.activate(sample_rate)) {
+ assert(!self.isActive_);
+ assert(self.sampleRate_ == 0);
+ return false;
+ }
+
+ self.isActive_ = true;
+ self.sampleRate_ = sample_rate;
+ return true;
}
- self.isActive_ = true;
- self.sampleRate_ = sample_rate;
- return true;
-}
+ void Plugin::clapDeactivate(clap_plugin *plugin) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin.deactivate");
-void Plugin::clapDeactivate(clap_plugin *plugin) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin.deactivate");
+ if (!self.isActive_) {
+ self.hostMisbehaving("The plugin was deactivated twice.");
+ return;
+ }
+
+ if (self.scheduleAudioPortsUpdate_)
+ self.updateAudioPorts();
- if (!self.isActive_) {
- self.hostMisbehaving("The plugin was deactivated twice.");
- return;
+ self.deactivate();
}
- if (self.scheduleAudioPortsUpdate_)
- self.updateAudioPorts();
+ bool Plugin::clapStartProcessing(clap_plugin *plugin) {
+ auto &self = from(plugin);
+ self.ensureAudioThread("clap_plugin.start_processing");
- self.deactivate();
-}
+ if (!self.isActive_) {
+ self.hostMisbehaving("Host called clap_plugin.start_processing() on a deactivated plugin");
+ return false;
+ }
-bool Plugin::clapStartProcessing(clap_plugin *plugin) {
- auto &self = from(plugin);
- self.ensureAudioThread("clap_plugin.start_processing");
+ if (self.isProcessing_) {
+ self.hostMisbehaving("Host called clap_plugin.start_processing() twice");
+ return true;
+ }
- if (!self.isActive_) {
- self.hostMisbehaving("Host called clap_plugin.start_processing() on a deactivated plugin");
- return false;
+ self.isProcessing_ = self.startProcessing();
+ return self.isProcessing_;
}
- if (self.isProcessing_) {
- self.hostMisbehaving("Host called clap_plugin.start_processing() twice");
- return true;
- }
+ void Plugin::clapStopProcessing(clap_plugin *plugin) {
+ auto &self = from(plugin);
+ self.ensureAudioThread("clap_plugin.stop_processing");
- self.isProcessing_ = self.startProcessing();
- return self.isProcessing_;
-}
+ if (!self.isActive_) {
+ self.hostMisbehaving("Host called clap_plugin.stop_processing() on a deactivated plugin");
+ return;
+ }
-void Plugin::clapStopProcessing(clap_plugin *plugin) {
- auto &self = from(plugin);
- self.ensureAudioThread("clap_plugin.stop_processing");
+ if (!self.isProcessing_) {
+ self.hostMisbehaving("Host called clap_plugin.stop_processing() twice");
+ return;
+ }
- if (!self.isActive_) {
- self.hostMisbehaving("Host called clap_plugin.stop_processing() on a deactivated plugin");
- return;
+ self.stopProcessing();
+ self.isProcessing_ = false;
}
- if (!self.isProcessing_) {
- self.hostMisbehaving("Host called clap_plugin.stop_processing() twice");
- return;
+ clap_process_status Plugin::clapProcess(struct clap_plugin *plugin,
+ const clap_process *process) {
+ auto &self = from(plugin);
+ self.ensureAudioThread("clap_plugin.process");
+
+ if (!self.isActive_) {
+ self.hostMisbehaving("Host called clap_plugin.process() on a deactivated plugin");
+ return CLAP_PROCESS_ERROR;
+ }
+
+ if (!self.isProcessing_) {
+ self.hostMisbehaving(
+ "Host called clap_plugin.process() without calling clap_plugin.start_processing()");
+ return CLAP_PROCESS_ERROR;
+ }
+
+ return self.process(process);
}
- self.stopProcessing();
- self.isProcessing_ = false;
-}
+ const void *Plugin::clapExtension(struct clap_plugin *plugin, const char *id) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin.extension");
-clap_process_status Plugin::clapProcess(struct clap_plugin *plugin, const clap_process *process) {
- auto &self = from(plugin);
- self.ensureAudioThread("clap_plugin.process");
+ if (!strcmp(id, CLAP_EXT_RENDER))
+ return &self.pluginRender_;
+ if (!strcmp(id, CLAP_EXT_TRACK_INFO))
+ return &pluginTrackInfo_;
+ if (!strcmp(id, CLAP_EXT_AUDIO_PORTS))
+ return &pluginAudioPorts_;
- if (!self.isActive_) {
- self.hostMisbehaving("Host called clap_plugin.process() on a deactivated plugin");
- return CLAP_PROCESS_ERROR;
+ return from(plugin).extension(id);
}
- if (!self.isProcessing_) {
- self.hostMisbehaving(
- "Host called clap_plugin.process() without calling clap_plugin.start_processing()");
- return CLAP_PROCESS_ERROR;
+ void Plugin::clapTrackInfoChanged(clap_plugin *plugin) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin_track_info.changed");
+
+ if (!self.canUseTrackInfo()) {
+ self.hostMisbehaving("Host called clap_plugin_track_info.changed() but does not provide a "
+ "complete clap_host_track_info interface");
+ return;
+ }
+
+ clap_track_info info;
+ if (!self.hostTrackInfo_->get(self.host_, &info)) {
+ self.hasTrackInfo_ = false;
+ self.hostMisbehaving(
+ "clap_host_track_info.get() failed after calling clap_plugin_track_info.changed()");
+ return;
+ }
+
+ const bool didChannelChange = info.channel_count != self.trackInfo_.channel_count ||
+ info.channel_map != self.trackInfo_.channel_map;
+ self.trackInfo_ = info;
+ self.hasTrackInfo_ = true;
+
+ if (didChannelChange && self.canChangeAudioPorts() &&
+ self.shouldInvalidateAudioPortsDefinitionOnTrackChannelChange())
+ self.invalidateAudioPortsDefinition();
+
+ self.trackInfoChanged();
}
- return self.process(process);
-}
+ void Plugin::invalidateAudioPortsDefinition() {
+ checkMainThread();
+
+ if (isActive()) {
+ scheduleAudioPortsUpdate_ = true;
+ hostAudioPorts_->rescan(host_, CLAP_AUDIO_PORTS_RESCAN_ALL);
+ return;
+ }
+
+ updateAudioPorts();
+ }
-const void *Plugin::clapExtension(struct clap_plugin *plugin, const char *id) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin.extension");
+ void Plugin::initTrackInfo() {
+ checkMainThread();
- if (!strcmp(id, CLAP_EXT_RENDER))
- return &self.pluginRender_;
- if (!strcmp(id, CLAP_EXT_TRACK_INFO))
- return &pluginTrackInfo_;
- if (!strcmp(id, CLAP_EXT_AUDIO_PORTS))
- return &pluginAudioPorts_;
+ assert(!hasTrackInfo_);
+ if (!canUseTrackInfo())
+ return;
- return from(plugin).extension(id);
-}
+ hasTrackInfo_ = hostTrackInfo_->get(host_, &trackInfo_);
+ }
-void Plugin::clapTrackInfoChanged(clap_plugin *plugin) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin_track_info.changed");
+ uint32_t Plugin::clapAudioPortsCount(clap_plugin *plugin, bool is_input) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin_audio_ports.count");
- if (!self.canUseTrackInfo()) {
- self.hostMisbehaving("Host called clap_plugin_track_info.changed() but does not provide a "
- "complete clap_host_track_info interface");
- return;
+ return is_input ? self.inputAudioPorts_.size() : self.outputAudioPorts_.size();
}
- clap_track_info info;
- if (!self.hostTrackInfo_->get(self.host_, &info)) {
- self.hasTrackInfo_ = false;
- self.hostMisbehaving(
- "clap_host_track_info.get() failed after calling clap_plugin_track_info.changed()");
- return;
+ bool Plugin::clapAudioPortsInfo(clap_plugin * plugin,
+ uint32_t index,
+ bool is_input,
+ clap_audio_port_info *info) {
+ auto &self = from(plugin);
+ self.ensureMainThread("clap_plugin_audio_ports.info");
+ auto count = clapAudioPortsCount(plugin, is_input);
+ if (index >= count) {
+ std::ostringstream msg;
+ msg << "Host called clap_plugin_audio_ports.info() with an index out of bounds: " << index
+ << " >= " << count;
+ self.hostMisbehaving(msg.str());
+ return false;
+ }
+
+ *info = is_input ? self.inputAudioPorts_[index] : self.outputAudioPorts_[index];
+ return true;
}
- const bool didChannelChange = info.channel_count != self.trackInfo_.channel_count ||
- info.channel_map != self.trackInfo_.channel_map;
- self.trackInfo_ = info;
- self.hasTrackInfo_ = true;
+ void Plugin::updateAudioPorts() {
+ checkMainThread();
+ assert(!isActive());
- if (didChannelChange && self.canChangeAudioPorts() &&
- self.shouldInvalidateAudioPortsDefinitionOnTrackChannelChange())
- self.invalidateAudioPortsDefinition();
+ scheduleAudioPortsUpdate_ = false;
- self.trackInfoChanged();
-}
+ // Get the new list of ports
+ std::vector<clap_audio_port_info> inputs;
+ std::vector<clap_audio_port_info> outputs;
+ defineAudioPorts(inputAudioPorts_, outputAudioPorts_);
-void Plugin::invalidateAudioPortsDefinition() {
- checkMainThread();
+ uint32_t flags = 0;
+
+ if (inputs.size() != inputAudioPorts_.size() || outputs.size() != outputAudioPorts_.size())
+ flags = CLAP_AUDIO_PORTS_RESCAN_ALL;
+ else {
+ for (int i = 0; i < inputs.size() && !(flags & CLAP_AUDIO_PORTS_RESCAN_ALL); ++i)
+ flags |= compareAudioPortsInfo(inputs[i], inputAudioPorts_[i]);
+ for (int i = 0; i < outputs.size() && !(flags & CLAP_AUDIO_PORTS_RESCAN_ALL); ++i)
+ flags |= compareAudioPortsInfo(outputs[i], outputAudioPorts_[i]);
+ }
- if (isActive()) {
- scheduleAudioPortsUpdate_ = true;
- hostAudioPorts_->rescan(host_, CLAP_AUDIO_PORTS_RESCAN_ALL);
- return;
+ if (flags == 0)
+ return;
+
+ // compare the list of ports to the old one
+ inputAudioPorts_ = inputs;
+ outputAudioPorts_ = outputs;
+
+ hostAudioPorts_->rescan(host_, flags);
}
- updateAudioPorts();
- hostAudioPorts_->rescan(host_, CLAP_AUDIO_PORTS_RESCAN_ALL);
-}
+ /////////////
+ // Logging //
+ /////////////
+ void Plugin::log(clap_log_severity severity, const char *msg) const {
+ if (canUseHostLog())
+ hostLog_->log(host_, severity, msg);
+ else
+ std::clog << msg << std::endl;
+ }
-void Plugin::initTrackInfo() {
- checkMainThread();
+ void Plugin::hostMisbehaving(const char *msg) { log(CLAP_LOG_HOST_MISBEHAVING, msg); }
- assert(!hasTrackInfo_);
- if (!canUseTrackInfo())
- return;
+ /////////////////////////////////
+ // Interface consistency check //
+ /////////////////////////////////
- hasTrackInfo_ = hostTrackInfo_->get(host_, &trackInfo_);
-}
+ bool Plugin::canUseHostLog() const noexcept { return hostLog_ && hostLog_->log; }
-uint32_t Plugin::clapAudioPortsCount(clap_plugin *plugin, bool is_input) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin_audio_ports.count");
+ bool Plugin::canUseThreadCheck() const noexcept {
+ return hostThreadCheck_ && hostThreadCheck_->is_audio_thread &&
+ hostThreadCheck_->is_main_thread;
+ }
- return is_input ? self.inputAudioPorts_.size() : self.outputAudioPorts_.size();
-}
+ /////////////////////
+ // Thread Checking //
+ /////////////////////
-bool Plugin::clapAudioPortsInfo(clap_plugin * plugin,
- uint32_t index,
- bool is_input,
- clap_audio_port_info *info) {
- auto &self = from(plugin);
- self.ensureMainThread("clap_plugin_audio_ports.info");
- auto count = clapAudioPortsCount(plugin, is_input);
- if (index >= count) {
- std::ostringstream msg;
- msg << "Host called clap_plugin_audio_ports.info() with an index out of bounds: " << index
- << " >= " << count;
- self.hostMisbehaving(msg.str());
- return false;
+ void Plugin::checkMainThread() {
+ if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread ||
+ hostThreadCheck_->is_main_thread(host_))
+ return;
+
+ std::terminate();
}
- *info = is_input ? self.inputAudioPorts_[index] : self.outputAudioPorts_[index];
- return true;
-}
-
-void Plugin::updateAudioPorts() {
- scheduleAudioPortsUpdate_ = false;
- inputAudioPorts_.clear();
- outputAudioPorts_.clear();
- defineAudioPorts(inputAudioPorts_, outputAudioPorts_);
-}
-
-/////////////
-// Logging //
-/////////////
-void Plugin::log(clap_log_severity severity, const char *msg) const {
- if (canUseHostLog())
- hostLog_->log(host_, severity, msg);
- else
- std::clog << msg << std::endl;
-}
-
-void Plugin::hostMisbehaving(const char *msg) { log(CLAP_LOG_HOST_MISBEHAVING, msg); }
-
-/////////////////////////////////
-// Interface consistency check //
-/////////////////////////////////
-
-bool Plugin::canUseHostLog() const noexcept { return hostLog_ && hostLog_->log; }
-
-bool Plugin::canUseThreadCheck() const noexcept {
- return hostThreadCheck_ && hostThreadCheck_->is_audio_thread && hostThreadCheck_->is_main_thread;
-}
-
-/////////////////////
-// Thread Checking //
-/////////////////////
-
-void Plugin::checkMainThread() {
- if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread ||
- hostThreadCheck_->is_main_thread(host_))
- return;
-
- std::terminate();
-}
-
-void Plugin::ensureMainThread(const char *method) {
- if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread ||
- hostThreadCheck_->is_main_thread(host_))
- return;
-
- std::ostringstream msg;
- msg << "Host called the method " << method
- << "() on wrong thread! It must be called on main thread!";
- hostMisbehaving(msg.str());
- std::terminate();
-}
-
-void Plugin::ensureAudioThread(const char *method) {
- if (!hostThreadCheck_ || !hostThreadCheck_->is_audio_thread ||
- hostThreadCheck_->is_audio_thread(host_))
- return;
-
- std::ostringstream msg;
- msg << "Host called the method " << method
- << "() on wrong thread! It must be called on audio thread!";
- hostMisbehaving(msg.str());
- std::terminate();
-}
-
-///////////////
-// Utilities //
-///////////////
-Plugin &Plugin::from(clap_plugin *plugin) {
- if (!plugin) {
- std::cerr << "called with a null clap_plugin pointer!" << std::endl;
+ void Plugin::ensureMainThread(const char *method) {
+ if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread ||
+ hostThreadCheck_->is_main_thread(host_))
+ return;
+
+ std::ostringstream msg;
+ msg << "Host called the method " << method
+ << "() on wrong thread! It must be called on main thread!";
+ hostMisbehaving(msg.str());
std::terminate();
}
- if (!plugin->plugin_data) {
- std::cerr << "called with a null clap_plugin->plugin_data pointer! The host must never "
- "change this pointer!"
- << std::endl;
+ void Plugin::ensureAudioThread(const char *method) {
+ if (!hostThreadCheck_ || !hostThreadCheck_->is_audio_thread ||
+ hostThreadCheck_->is_audio_thread(host_))
+ return;
+
+ std::ostringstream msg;
+ msg << "Host called the method " << method
+ << "() on wrong thread! It must be called on audio thread!";
+ hostMisbehaving(msg.str());
std::terminate();
}
- return *static_cast<Plugin *>(plugin->plugin_data);
-}
-
-template <typename T>
-void Plugin::initInterface(const T *&ptr, const char *id) {
- assert(!ptr);
- assert(id);
-
- if (host_->extension)
- ptr = static_cast<const T *>(host_->extension(host_, id));
-}
-
-void Plugin::initInterfaces() {
- initInterface(hostLog_, CLAP_EXT_LOG);
- initInterface(hostThreadCheck_, CLAP_EXT_THREAD_CHECK);
- initInterface(hostThreadPool_, CLAP_EXT_THREAD_POOL);
- initInterface(hostAudioPorts_, CLAP_EXT_AUDIO_PORTS);
- initInterface(hostEventLoop_, CLAP_EXT_EVENT_LOOP);
- initInterface(hostEventFilter_, CLAP_EXT_EVENT_FILTER);
- initInterface(hostFileReference_, CLAP_EXT_FILE_REFERENCE);
- initInterface(hostLatency_, CLAP_EXT_LATENCY);
- initInterface(hostGui_, CLAP_EXT_GUI);
- initInterface(hostParams_, CLAP_EXT_PARAMS);
- initInterface(hostTrackInfo_, CLAP_EXT_TRACK_INFO);
- initInterface(hostState_, CLAP_EXT_STATE);
- initInterface(hostNoteName_, CLAP_EXT_NOTE_NAME);
-}
-
-int Plugin::sampleRate() const noexcept {
- assert(isActive_ &&
- "there is no point in querying the sample rate if the plugin isn't activated");
- assert(isActive_ ? sampleRate_ > 0 : sampleRate_ == 0);
- return sampleRate_;
-}
-\ No newline at end of file
+ ///////////////
+ // Utilities //
+ ///////////////
+ Plugin &Plugin::from(clap_plugin *plugin) {
+ if (!plugin) {
+ std::cerr << "called with a null clap_plugin pointer!" << std::endl;
+ std::terminate();
+ }
+
+ if (!plugin->plugin_data) {
+ std::cerr << "called with a null clap_plugin->plugin_data pointer! The host must never "
+ "change this pointer!"
+ << std::endl;
+ std::terminate();
+ }
+
+ return *static_cast<Plugin *>(plugin->plugin_data);
+ }
+
+ template <typename T>
+ void Plugin::initInterface(const T *&ptr, const char *id) {
+ assert(!ptr);
+ assert(id);
+
+ if (host_->extension)
+ ptr = static_cast<const T *>(host_->extension(host_, id));
+ }
+
+ void Plugin::initInterfaces() {
+ initInterface(hostLog_, CLAP_EXT_LOG);
+ initInterface(hostThreadCheck_, CLAP_EXT_THREAD_CHECK);
+ initInterface(hostThreadPool_, CLAP_EXT_THREAD_POOL);
+ initInterface(hostAudioPorts_, CLAP_EXT_AUDIO_PORTS);
+ initInterface(hostEventLoop_, CLAP_EXT_EVENT_LOOP);
+ initInterface(hostEventFilter_, CLAP_EXT_EVENT_FILTER);
+ initInterface(hostFileReference_, CLAP_EXT_FILE_REFERENCE);
+ initInterface(hostLatency_, CLAP_EXT_LATENCY);
+ initInterface(hostGui_, CLAP_EXT_GUI);
+ initInterface(hostParams_, CLAP_EXT_PARAMS);
+ initInterface(hostTrackInfo_, CLAP_EXT_TRACK_INFO);
+ initInterface(hostState_, CLAP_EXT_STATE);
+ initInterface(hostNoteName_, CLAP_EXT_NOTE_NAME);
+ }
+
+ uint32_t Plugin::compareAudioPortsInfo(const clap_audio_port_info &a,
+ const clap_audio_port_info &b) noexcept {
+ if (a.supports_64_bits != b.supports_64_bits || a.supports_in_place != b.supports_in_place ||
+ a.is_cv != b.is_cv || a.is_main != b.is_main || a.channel_count != b.channel_count ||
+ a.channel_map != b.channel_map || a.id != b.id)
+ return CLAP_AUDIO_PORTS_RESCAN_ALL;
+
+ if (strncmp(a.name, b.name, sizeof(a.name)))
+ return CLAP_AUDIO_PORTS_RESCAN_NAMES;
+
+ return 0;
+ }
+
+ int Plugin::sampleRate() const noexcept {
+ assert(isActive_ &&
+ "there is no point in querying the sample rate if the plugin isn't activated");
+ assert(isActive_ ? sampleRate_ > 0 : sampleRate_ == 0);
+ return sampleRate_;
+ }
+} // namespace clap
+\ No newline at end of file
diff --git a/examples/plugins/plugin.hh b/examples/plugins/plugin.hh
@@ -7,168 +7,182 @@
#include <clap/all.h>
-class Plugin {
-public:
- clap_plugin *clapPlugin() noexcept { return &plugin_; }
-
-protected:
- Plugin(const clap_plugin_descriptor *desc, clap_host *host);
- virtual ~Plugin() = default;
-
- // not copyable, not moveable
- Plugin(const Plugin &) = delete;
- Plugin(Plugin &&) = delete;
- Plugin &operator=(const Plugin &) = delete;
- Plugin &operator=(Plugin &&) = delete;
-
- /////////////////////////
- // Methods to override //
- /////////////////////////
-
- virtual bool init() { return true; }
- virtual bool activate(int sample_rate) { return true; }
- virtual void deactivate() {}
- virtual bool startProcessing() { return true; }
- virtual void stopProcessing() {}
- virtual clap_process_status process(const clap_process *process) { return CLAP_PROCESS_SLEEP; }
- virtual const void * extension(const char *id) { return nullptr; }
-
- virtual void defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
- std::vector<clap_audio_port_info> &outputPorts) {}
- void invalidateAudioPortsDefinition();
- virtual bool shouldInvalidateAudioPortsDefinitionOnTrackChannelChange() const { return false; }
-
- virtual void trackInfoChanged() {}
-
- /////////////
- // Logging //
- /////////////
- void log(clap_log_severity severity, const char *msg) const;
- void hostMisbehaving(const char *msg);
- void hostMisbehaving(const std::string &msg) { hostMisbehaving(msg.c_str()); }
-
- /////////////////////////////////
- // Interface consistency check //
- /////////////////////////////////
- bool canUseHostLog() const noexcept;
- bool canUseThreadCheck() const noexcept;
- bool canUseTrackInfo() const noexcept;
- bool canChangeAudioPorts() const noexcept;
-
- /////////////////////
- // Thread Checking //
- /////////////////////
- void checkMainThread();
- void ensureMainThread(const char *method);
- void ensureAudioThread(const char *method);
-
- ///////////////
- // Utilities //
- ///////////////
- static Plugin &from(clap_plugin *plugin);
-
- template <typename T>
- void initInterface(const T *&ptr, const char *id);
- void initInterfaces();
-
- //////////////////////
- // Processing State //
- //////////////////////
- bool isActive() const noexcept { return isActive_; }
- bool isProcessing() const noexcept { return isProcessing_; }
- int sampleRate() const noexcept;
-
- //////////////////////
- // Cached Host Info //
- //////////////////////
- bool hasTrackInfo() const noexcept { return hasTrackInfo_; }
- const clap_track_info &trackInfo() const noexcept {
- assert(hasTrackInfo_);
- return trackInfo_;
- }
- uint32_t trackChannelCount() const noexcept {
- return hasTrackInfo_ ? trackInfo_.channel_count : 2;
- }
- clap_chmap trackChannelMap() const noexcept {
- return hasTrackInfo_ ? trackInfo_.channel_map : CLAP_CHMAP_STEREO;
- }
-
-protected:
- clap_plugin_event_filter pluginEventFilter_;
- clap_plugin_latency pluginLatency_;
- clap_plugin_params pluginParams_;
- clap_plugin_render pluginRender_;
- clap_plugin_note_name pluginNoteName_;
- clap_plugin_thread_pool pluginThreadPool_;
-
- /* state related */
- clap_plugin_state pluginState_;
- clap_plugin_preset_load pluginPresetLoad_;
- clap_plugin_file_reference pluginFileReference_;
-
- /* GUI related */
- clap_plugin_gui pluginGui_;
- clap_plugin_gui_win32 pluginGuiWin32_;
- clap_plugin_gui_cocoa pluginGuiCocoa_;
- clap_plugin_gui_x11 pluginGuiX11_;
- clap_plugin_event_loop pluginEventLoop_;
-
- clap_host *const host_ = nullptr;
- const clap_host_log * hostLog_ = nullptr;
- const clap_host_thread_check * hostThreadCheck_ = nullptr;
- const clap_host_thread_pool * hostThreadPool_ = nullptr;
- const clap_host_audio_ports * hostAudioPorts_ = nullptr;
- const clap_host_event_filter * hostEventFilter_ = nullptr;
- const clap_host_file_reference *hostFileReference_ = nullptr;
- const clap_host_latency * hostLatency_ = nullptr;
- const clap_host_gui * hostGui_ = nullptr;
- const clap_host_event_loop * hostEventLoop_ = nullptr;
- const clap_host_params * hostParams_ = nullptr;
- const clap_host_track_info * hostTrackInfo_ = nullptr;
- const clap_host_state * hostState_ = nullptr;
- const clap_host_note_name * hostNoteName_ = nullptr;
-
-private:
- /////////////////////
- // CLAP Interfaces //
- /////////////////////
-
- clap_plugin plugin_;
- // clap_plugin
- static bool clapInit(clap_plugin *plugin);
- static void clapDestroy(clap_plugin *plugin);
- static bool clapActivate(clap_plugin *plugin, int sample_rate);
- static void clapDeactivate(clap_plugin *plugin);
- static bool clapStartProcessing(clap_plugin *plugin);
- static void clapStopProcessing(clap_plugin *plugin);
- static clap_process_status clapProcess(struct clap_plugin *plugin, const clap_process *process);
- static const void * clapExtension(struct clap_plugin *plugin, const char *id);
-
- // clap_plugin_track_info
- static void clapTrackInfoChanged(clap_plugin *plugin);
- void initTrackInfo();
-
- // clap_plugin_audio_ports
- static uint32_t clapAudioPortsCount(clap_plugin *plugin, bool is_input);
- static bool clapAudioPortsInfo(clap_plugin * plugin,
- uint32_t index,
- bool is_input,
- clap_audio_port_info *info);
- void updateAudioPorts();
-
- static const constexpr clap_plugin_track_info pluginTrackInfo_ = {clapTrackInfoChanged};
- static const constexpr clap_plugin_audio_ports pluginAudioPorts_ = {clapAudioPortsCount,
- clapAudioPortsInfo};
-
- // state
- bool isActive_ = false;
- bool isProcessing_ = false;
- int sampleRate_ = 0;
-
- bool hasTrackInfo_ = false;
- clap_track_info trackInfo_;
-
- bool scheduleAudioPortsUpdate_ = false;
- std::vector<clap_audio_port_info> inputAudioPorts_;
- std::vector<clap_audio_port_info> outputAudioPorts_;
-};
-\ No newline at end of file
+namespace clap {
+ class Plugin {
+ public:
+ clap_plugin *clapPlugin() noexcept { return &plugin_; }
+
+ protected:
+ Plugin(const clap_plugin_descriptor *desc, clap_host *host);
+ virtual ~Plugin() = default;
+
+ // not copyable, not moveable
+ Plugin(const Plugin &) = delete;
+ Plugin(Plugin &&) = delete;
+ Plugin &operator=(const Plugin &) = delete;
+ Plugin &operator=(Plugin &&) = delete;
+
+ /////////////////////////
+ // Methods to override //
+ /////////////////////////
+
+ virtual bool init() { return true; }
+ virtual bool activate(int sample_rate) { return true; }
+ virtual void deactivate() {}
+ virtual bool startProcessing() { return true; }
+ virtual void stopProcessing() {}
+ virtual clap_process_status process(const clap_process *process) {
+ return CLAP_PROCESS_SLEEP;
+ }
+ virtual const void *extension(const char *id) { return nullptr; }
+
+ virtual void defineAudioPorts(std::vector<clap_audio_port_info> &inputPorts,
+ std::vector<clap_audio_port_info> &outputPorts) {}
+ virtual bool shouldInvalidateAudioPortsDefinitionOnTrackChannelChange() const {
+ return false;
+ }
+
+ virtual void trackInfoChanged() {}
+
+ //////////////////
+ // Invalidation //
+ //////////////////
+ void invalidateAudioPortsDefinition();
+
+ /////////////
+ // Logging //
+ /////////////
+ void log(clap_log_severity severity, const char *msg) const;
+ void hostMisbehaving(const char *msg);
+ void hostMisbehaving(const std::string &msg) { hostMisbehaving(msg.c_str()); }
+
+ /////////////////////////////////
+ // Interface consistency check //
+ /////////////////////////////////
+ bool canUseHostLog() const noexcept;
+ bool canUseThreadCheck() const noexcept;
+ bool canUseTrackInfo() const noexcept;
+ bool canChangeAudioPorts() const noexcept;
+
+ /////////////////////
+ // Thread Checking //
+ /////////////////////
+ void checkMainThread();
+ void ensureMainThread(const char *method);
+ void ensureAudioThread(const char *method);
+
+ ///////////////
+ // Utilities //
+ ///////////////
+ static Plugin &from(clap_plugin *plugin);
+
+ template <typename T>
+ void initInterface(const T *&ptr, const char *id);
+ void initInterfaces();
+
+ static uint32_t compareAudioPortsInfo(const clap_audio_port_info &a,
+ const clap_audio_port_info &b) noexcept;
+
+ //////////////////////
+ // Processing State //
+ //////////////////////
+ bool isActive() const noexcept { return isActive_; }
+ bool isProcessing() const noexcept { return isProcessing_; }
+ int sampleRate() const noexcept;
+
+ //////////////////////
+ // Cached Host Info //
+ //////////////////////
+ bool hasTrackInfo() const noexcept { return hasTrackInfo_; }
+ const clap_track_info &trackInfo() const noexcept {
+ assert(hasTrackInfo_);
+ return trackInfo_;
+ }
+ uint32_t trackChannelCount() const noexcept {
+ return hasTrackInfo_ ? trackInfo_.channel_count : 2;
+ }
+ clap_chmap trackChannelMap() const noexcept {
+ return hasTrackInfo_ ? trackInfo_.channel_map : CLAP_CHMAP_STEREO;
+ }
+
+ protected:
+ clap_plugin_event_filter pluginEventFilter_;
+ clap_plugin_latency pluginLatency_;
+ clap_plugin_params pluginParams_;
+ clap_plugin_render pluginRender_;
+ clap_plugin_note_name pluginNoteName_;
+ clap_plugin_thread_pool pluginThreadPool_;
+
+ /* state related */
+ clap_plugin_state pluginState_;
+ clap_plugin_preset_load pluginPresetLoad_;
+ clap_plugin_file_reference pluginFileReference_;
+
+ /* GUI related */
+ clap_plugin_gui pluginGui_;
+ clap_plugin_gui_win32 pluginGuiWin32_;
+ clap_plugin_gui_cocoa pluginGuiCocoa_;
+ clap_plugin_gui_x11 pluginGuiX11_;
+ clap_plugin_event_loop pluginEventLoop_;
+
+ clap_host *const host_ = nullptr;
+ const clap_host_log * hostLog_ = nullptr;
+ const clap_host_thread_check * hostThreadCheck_ = nullptr;
+ const clap_host_thread_pool * hostThreadPool_ = nullptr;
+ const clap_host_audio_ports * hostAudioPorts_ = nullptr;
+ const clap_host_event_filter * hostEventFilter_ = nullptr;
+ const clap_host_file_reference *hostFileReference_ = nullptr;
+ const clap_host_latency * hostLatency_ = nullptr;
+ const clap_host_gui * hostGui_ = nullptr;
+ const clap_host_event_loop * hostEventLoop_ = nullptr;
+ const clap_host_params * hostParams_ = nullptr;
+ const clap_host_track_info * hostTrackInfo_ = nullptr;
+ const clap_host_state * hostState_ = nullptr;
+ const clap_host_note_name * hostNoteName_ = nullptr;
+
+ private:
+ /////////////////////
+ // CLAP Interfaces //
+ /////////////////////
+
+ clap_plugin plugin_;
+ // clap_plugin
+ static bool clapInit(clap_plugin *plugin);
+ static void clapDestroy(clap_plugin *plugin);
+ static bool clapActivate(clap_plugin *plugin, int sample_rate);
+ static void clapDeactivate(clap_plugin *plugin);
+ static bool clapStartProcessing(clap_plugin *plugin);
+ static void clapStopProcessing(clap_plugin *plugin);
+ static clap_process_status clapProcess(struct clap_plugin *plugin,
+ const clap_process *process);
+ static const void * clapExtension(struct clap_plugin *plugin, const char *id);
+
+ // clap_plugin_track_info
+ static void clapTrackInfoChanged(clap_plugin *plugin);
+ void initTrackInfo();
+
+ // clap_plugin_audio_ports
+ static uint32_t clapAudioPortsCount(clap_plugin *plugin, bool is_input);
+ static bool clapAudioPortsInfo(clap_plugin * plugin,
+ uint32_t index,
+ bool is_input,
+ clap_audio_port_info *info);
+ void updateAudioPorts();
+
+ static const constexpr clap_plugin_track_info pluginTrackInfo_ = {clapTrackInfoChanged};
+ static const constexpr clap_plugin_audio_ports pluginAudioPorts_ = {clapAudioPortsCount,
+ clapAudioPortsInfo};
+
+ // state
+ bool isActive_ = false;
+ bool isProcessing_ = false;
+ int sampleRate_ = 0;
+
+ bool hasTrackInfo_ = false;
+ clap_track_info trackInfo_;
+
+ bool scheduleAudioPortsUpdate_ = false;
+ std::vector<clap_audio_port_info> inputAudioPorts_;
+ std::vector<clap_audio_port_info> outputAudioPorts_;
+ };
+} // namespace clap
+\ No newline at end of file