clap

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

commit a09bd8329bfe0fa2edf041a5489bdccb00fea838
parent 8978b707c9a04d1b32065ce443ba3109b85389ef
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Tue, 22 Jun 2021 17:54:56 +0200

Big refactoring after the param change

Diffstat:
Mexamples/glue/clap-plugin.cc | 62++++++++------------------------------------------------------
Mexamples/glue/clap-plugin.hh | 45+++++++++++----------------------------------
Mexamples/host/param-queue.cc | 4++--
Mexamples/host/param-queue.hh | 8++++----
Mexamples/host/plugin-host.cc | 114+++++++++++--------------------------------------------------------------------
Mexamples/host/plugin-host.hh | 10++++------
Mexamples/host/plugin-param.cc | 108++++++++++++-------------------------------------------------------------------
Mexamples/host/plugin-param.hh | 32++++++++++++++------------------
Mexamples/host/plugin-parameters-widget.cc | 90+++++++++++++++++++------------------------------------------------------------
Mexamples/host/plugin-parameters-widget.hh | 5++---
Mexamples/host/plugin-quick-control-widget.cc | 24+++---------------------
Mexamples/plugins/CMakeLists.txt | 3+++
Aexamples/plugins/dc-offset/dc-offset.cc | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/plugins/dc-offset/dc-offset.hh | 28++++++++++++++++++++++++++++
Mexamples/plugins/gain/gain.cc | 31++++++++-----------------------
Mexamples/plugins/gain/gain.hh | 2--
Aexamples/plugins/parameter-interpolator.hh | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/plugins/parameters.cc | 4++--
Mexamples/plugins/parameters.hh | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mexamples/plugins/plugin-helper.hh | 26+++++---------------------
20 files changed, 385 insertions(+), 465 deletions(-)

diff --git a/examples/glue/clap-plugin.cc b/examples/glue/clap-plugin.cc @@ -397,9 +397,9 @@ namespace clap { //--------------------// // clap_plugin_params // //--------------------// - bool Plugin::clapParamsIinfo(const clap_plugin *plugin, - int32_t param_index, - clap_param_info *param_info) noexcept { + bool Plugin::clapParamsInfo(const clap_plugin *plugin, + int32_t param_index, + clap_param_info *param_info) noexcept { auto &self = from(plugin); self.ensureMainThread("clap_plugin_params.info"); @@ -415,28 +415,8 @@ namespace clap { return self.paramsInfo(param_index, param_info); } - bool Plugin::clapParamsEnumValue(const clap_plugin *plugin, - clap_id param_id, - int32_t value_index, - clap_param_value *value) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.enum_value"); - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.enum_value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: check the value index? - - return self.paramsEnumValue(param_id, value_index, value); - } - - bool Plugin::clapParamsValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value *value) noexcept { + bool + Plugin::clapParamsValue(const clap_plugin *plugin, clap_id param_id, double *value) noexcept { auto &self = from(plugin); self.ensureMainThread("clap_plugin_params.value"); @@ -452,34 +432,9 @@ namespace clap { return self.paramsValue(param_id, value); } - bool Plugin::clapParamsSetValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - clap_param_value modulation) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.set_value"); - - if (self.isActive_) { - self.hostMisbehaving( - "it is forbidden to call clap_plugin_params.set_value() if the plugin is activated"); - return false; - } - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.set_value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: extra checks - - return self.paramsSetValue(param_id, value, modulation); - } - bool Plugin::clapParamsValueToText(const clap_plugin *plugin, clap_id param_id, - clap_param_value value, + double value, char *display, uint32_t size) noexcept { auto &self = from(plugin); @@ -499,7 +454,7 @@ namespace clap { bool Plugin::clapParamsTextToValue(const clap_plugin *plugin, clap_id param_id, const char *display, - clap_param_value *value) noexcept { + double *value) noexcept { auto &self = from(plugin); self.ensureMainThread("clap_plugin_params.text_to_value"); @@ -745,8 +700,7 @@ namespace clap { if (!hostParams_) return false; - if (hostParams_->adjust && hostParams_->adjust_begin && hostParams_->adjust_end && - hostParams_->rescan) + if (hostParams_->rescan && hostParams_->clear) return true; hostMisbehaving("clap_host_params is partially implemented"); diff --git a/examples/glue/clap-plugin.hh b/examples/glue/clap-plugin.hh @@ -108,24 +108,12 @@ namespace clap { virtual bool paramsInfo(int32_t paramIndex, clap_param_info *info) const noexcept { return false; } + virtual bool paramsValue(clap_id paramId, double *value) noexcept { return false; } virtual bool - paramsEnumValue(clap_id paramId, int32_t valueIndex, clap_param_value *value) noexcept { + paramsValueToText(clap_id paramId, double value, char *display, uint32_t size) noexcept { return false; } - virtual bool paramsValue(clap_id paramId, clap_param_value *value) noexcept { return false; } - virtual bool paramsSetValue(clap_id paramId, - clap_param_value value, - clap_param_value modulation) noexcept { - return false; - } - virtual bool paramsValueToText(clap_id paramId, - clap_param_value value, - char *display, - uint32_t size) noexcept { - return false; - } - virtual bool - paramsTextToValue(clap_id paramId, const char *display, clap_param_value *value) noexcept { + virtual bool paramsTextToValue(clap_id paramId, const char *display, double *value) noexcept { return false; } virtual bool isValidParamId(clap_id paramId) const noexcept; @@ -308,29 +296,20 @@ namespace clap { // clap_plugin_params static uint32_t clapParamsCount(const clap_plugin *plugin) noexcept; - static bool clapParamsIinfo(const clap_plugin *plugin, - int32_t param_index, - clap_param_info *param_info) noexcept; - static bool clapParamsEnumValue(const clap_plugin *plugin, - clap_id param_id, - int32_t value_index, - clap_param_value *value) noexcept; - static bool clapParamsValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value *value) noexcept; - static bool clapParamsSetValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - clap_param_value modulation) noexcept; + static bool clapParamsInfo(const clap_plugin *plugin, + int32_t param_index, + clap_param_info *param_info) noexcept; + static bool + clapParamsValue(const clap_plugin *plugin, clap_id param_id, double *value) noexcept; static bool clapParamsValueToText(const clap_plugin *plugin, clap_id param_id, - clap_param_value value, + double value, char *display, uint32_t size) noexcept; static bool clapParamsTextToValue(const clap_plugin *plugin, clap_id param_id, const char *display, - clap_param_value *value) noexcept; + double *value) noexcept; // clap_plugin_quick_controls static uint32_t clapQuickControlsPageCount(const clap_plugin *plugin) noexcept; @@ -404,10 +383,8 @@ namespace clap { static const constexpr clap_plugin_params pluginParams_ = { clapParamsCount, - clapParamsIinfo, - clapParamsEnumValue, + clapParamsInfo, clapParamsValue, - clapParamsSetValue, clapParamsValueToText, clapParamsTextToValue, }; diff --git a/examples/host/param-queue.cc b/examples/host/param-queue.cc @@ -18,7 +18,7 @@ void ParamQueue::setCapacity(size_t capacity) { q.reserve(2 * capacity); } -void ParamQueue::set(clap_id id, clap_param_value value) { producer_.load()->emplace(id, value); } +void ParamQueue::set(clap_id id, double value) { producer_.load()->emplace(id, value); } void ParamQueue::producerDone() { if (consumer_) @@ -31,7 +31,7 @@ void ParamQueue::producerDone() { Q_ASSERT(producer_); } -void ParamQueue::consume(const std::function<void(clap_id, clap_param_value)> consumer) { +void ParamQueue::consume(const std::function<void(clap_id, double)> consumer) { Q_ASSERT(consumer); if (!consumer_) diff --git a/examples/host/param-queue.hh b/examples/host/param-queue.hh @@ -8,21 +8,21 @@ class ParamQueue { public: - using queue_type = std::unordered_map<clap_id, clap_param_value>; + using queue_type = std::unordered_map<clap_id, double>; ParamQueue(); void setCapacity(size_t capacity); - void set(clap_id id, clap_param_value value); + void set(clap_id id, double value); void producerDone(); - void consume(const std::function<void(clap_id id, clap_param_value value)> consumer); + void consume(const std::function<void(clap_id id, double value)> consumer); void reset(); private: - queue_type queues_[2]; + queue_type queues_[2]; std::atomic<queue_type *> free_ = nullptr; std::atomic<queue_type *> producer_ = nullptr; std::atomic<queue_type *> consumer_ = nullptr; diff --git a/examples/host/plugin-host.cc b/examples/host/plugin-host.cc @@ -48,9 +48,6 @@ PluginHost::PluginHost(Engine &engine) : QObject(&engine), engine_(engine) { hostEventLoop_.modify_fd = PluginHost::clapEventLoopModifyFd; hostEventLoop_.unregister_fd = PluginHost::clapEventLoopUnregisterFd; - hostParams_.adjust_begin = PluginHost::clapParamsAdjustBegin; - hostParams_.adjust_end = PluginHost::clapParamsAdjustEnd; - hostParams_.adjust = PluginHost::clapParamsAdjust; hostParams_.rescan = PluginHost::clapParamsRescan; hostQuickControls_.pages_changed = PluginHost::clapQuickControlsPagesChanged; @@ -607,7 +604,7 @@ void PluginHost::process() { process_.audio_outputs_count = 1; evOut_.clear(); - appToEngineQueue_.consume([this](clap_id param_id, clap_param_value value) { + appToEngineQueue_.consume([this](clap_id param_id, double value) { clap_event ev; ev.time = 0; ev.type = CLAP_EVENT_PARAM_SET; @@ -616,9 +613,9 @@ void PluginHost::process() { ev.param.channel = -1; ev.param.val0 = value; ev.param.val1 = value; - ev.param.mod0.d = 0; - ev.param.mod1.d = 0; - ev.param.duration = process_.frames_count; + ev.param.mod0 = 0; + ev.param.mod1 = 0; + ev.param.distance = process_.frames_count; evIn_.push_back(ev); }); @@ -657,7 +654,7 @@ void PluginHost::idle() { // Try to send events to the audio engine appToEngineQueue_.producerDone(); - engineToAppQueue_.consume([this](clap_id param_id, clap_param_value value) { + engineToAppQueue_.consume([this](clap_id param_id, double value) { auto it = params_.find(param_id); if (it == params_.end()) { std::ostringstream msg; @@ -666,8 +663,6 @@ void PluginHost::idle() { } it->second->setValue(value); - if (pluginParams_ && pluginParams_->set_value) - pluginParams_->set_value(plugin_, param_id, value, value); }); } @@ -695,104 +690,25 @@ PluginParam &PluginHost::checkValidParamId(const std::string_view &function, return *it->second; } -void PluginHost::checkValidParamValue(const PluginParam &param, clap_param_value value) { +void PluginHost::checkValidParamValue(const PluginParam &param, double value) { checkForMainThread(); if (!param.isValueValid(value)) { std::ostringstream msg; msg << "Invalid value for param. "; param.printInfo(msg); - msg << "; value: "; - param.printValue(value, msg); + msg << "; value: " << value; // std::cerr << msg.str() << std::endl; throw std::invalid_argument(msg.str()); } } -void PluginHost::clapParamsAdjustBegin(const clap_host *host, clap_id param_id) { +void PluginHost::setParamValueByHost(PluginParam &param, double value) { checkForMainThread(); - auto h = fromHost(host); - - if (h->isPluginActive()) - throw std::logic_error("Plugin called clap_host_params.begin_adjust() but the plugin is " - "active, it should transmit the event via output param event"); - - auto &param = h->checkValidParamId("clap_host_params.touch_begin()", "param_id", param_id); - - if (param.isBeingAdjusted()) { - std::ostringstream msg; - msg << "Plugin called clap_host_params.adjust_end() on "; - param.printShortInfo(msg); - msg << ", but this parameter is already marked as being adjusted"; - throw std::logic_error(msg.str()); - } - - param.beginAdjust(); -} - -void PluginHost::clapParamsAdjustEnd(const clap_host *host, clap_id param_id) { - checkForMainThread(); - - auto h = fromHost(host); - - if (h->isPluginActive()) - throw std::logic_error( - "Plugin called clap_host_params.end_adjust() but the plugin is active, it should " - "transmit the event via output param event"); - - auto &param = h->checkValidParamId("clap_host_params.touch_begin()", "param_id", param_id); - - if (!param.isBeingAdjusted()) { - std::ostringstream msg; - msg << "Plugin called clap_host_params.adjust_end() on "; - param.printShortInfo(msg); - msg << ", but this parameter is not marked as being adjusted"; - throw std::logic_error(msg.str()); - } - - param.endAdjust(); -} - -void PluginHost::clapParamsAdjust(const clap_host *host, clap_id param_id, clap_param_value value) { - checkForMainThread(); - - auto h = fromHost(host); - - if (h->isPluginActive()) - throw std::logic_error( - "Plugin called clap_host_params.adjust() but the plugin is active, it should transmit " - "the event via output param event"); - - auto &param = h->checkValidParamId("clap_host_params.touch_begin()", "param_id", param_id); - - if (!param.isBeingAdjusted()) { - std::ostringstream msg; - msg << "Plugin called clap_host_params.adjust() on "; - param.printShortInfo(msg); - msg << ", but this parameter is not marked as being adjusted"; - throw std::logic_error(msg.str()); - } - - h->checkValidParamValue(param, value); - - if (param.isValueEqualTo(value)) - return; - param.setValue(value); - h->pluginParams_->set_value(h->plugin_, param.info().id, value, value); -} - -void PluginHost::setParamValueByHost(PluginParam &param, clap_param_value value) { - checkForMainThread(); - param.setValue(value); - - if (isPluginActive()) { - appToEngineQueue_.set(param.info().id, value); - appToEngineQueue_.producerDone(); - } else { - pluginParams_->set_value(plugin_, param.info().id, value, value); - } + appToEngineQueue_.set(param.info().id, value); + appToEngineQueue_.producerDone(); } void PluginHost::scanParams() { clapParamsRescan(&host_, CLAP_PARAM_RESCAN_ALL); } @@ -849,7 +765,7 @@ void PluginHost::clapParamsRescan(const clap_host *host, uint32_t flags) { throw std::logic_error(msg.str()); } - clap_param_value value = h->getParamValue(info); + double value = h->getParamValue(info); auto param = std::make_unique<PluginParam>(*h, info, value); h->checkValidParamValue(*param, value); h->params_.emplace(info.id, std::move(param)); @@ -878,8 +794,8 @@ void PluginHost::clapParamsRescan(const clap_host *host, uint32_t flags) { it->second->setInfo(info); } - clap_param_value value = h->getParamValue(info); - if (!it->second->isValueEqualTo(value)) { + double value = h->getParamValue(info); + if (it->second->value() != value) { if (!clapParamsRescanMayValueChange(flags)) { std::ostringstream msg; msg << "a parameter's value did change but, but the flag CLAP_PARAM_RESCAN_VALUES " @@ -925,8 +841,8 @@ void PluginHost::clapParamsRescan(const clap_host *host, uint32_t flags) { } } -clap_param_value PluginHost::getParamValue(const clap_param_info &info) { - clap_param_value value; +double PluginHost::getParamValue(const clap_param_info &info) { + double value; if (pluginParams_->value(plugin_, info.id, &value)) return value; diff --git a/examples/host/plugin-host.hh b/examples/host/plugin-host.hh @@ -52,7 +52,7 @@ public: void terminateThreadPool(); void threadPoolEntry(); - void setParamValueByHost(PluginParam &param, clap_param_value value); + void setParamValueByHost(PluginParam &param, double value); auto &params() const { return params_; } auto &quickControlsPages() const { return quickControlsPages_; } @@ -82,17 +82,15 @@ private: static bool clapIsMainThread(const clap_host *host); static bool clapIsAudioThread(const clap_host *host); - static void clapParamsAdjustBegin(const clap_host *host, clap_id param_id); - static void clapParamsAdjustEnd(const clap_host *host, clap_id param_id); - static void clapParamsAdjust(const clap_host *host, clap_id param_id, clap_param_value plain_value); static void clapParamsRescan(const clap_host *host, uint32_t flags); + static void clapParamsClear(const clap_host *host, uint32_t flags); void scanParams(); void scanParam(int32_t index); PluginParam &checkValidParamId(const std::string_view &function, const std::string_view &param_name, clap_id param_id); - void checkValidParamValue(const PluginParam &param, clap_param_value value); - clap_param_value getParamValue(const clap_param_info &info); + void checkValidParamValue(const PluginParam &param, double value); + double getParamValue(const clap_param_info &info); static bool clapParamsRescanMayValueChange(uint32_t flags) { return flags & (CLAP_PARAM_RESCAN_ALL | CLAP_PARAM_RESCAN_VALUES); } diff --git a/examples/host/plugin-param.cc b/examples/host/plugin-param.cc @@ -1,66 +1,27 @@ #include "plugin-param.hh" #include "plugin-host.hh" -PluginParam::PluginParam(PluginHost & pluginHost, - const clap_param_info &info, - clap_param_value value) +PluginParam::PluginParam(PluginHost &pluginHost, const clap_param_info &info, double value) : QObject(&pluginHost), info_(info), value_(value), modulated_value_(value) {} -void PluginParam::setValue(clap_param_value v) { - if (isValueEqualTo(v)) +void PluginParam::setValue(double v) { + if (value_ == v) return; + value_ = v; valueChanged(); } -void PluginParam::setModulatedValue(clap_param_value v) { - if (areValuesEqual(info_.type, modulated_value_, v)) +void PluginParam::setModulatedValue(double v) { + if (modulated_value_ == v) return; + modulated_value_ = v; modulatedValueChanged(); } -bool PluginParam::hasRange() const { - switch (info_.type) { - case CLAP_PARAM_INT: - case CLAP_PARAM_FLOAT: - return true; - default: - return false; - } -} - -bool PluginParam::areValuesEqual(clap_param_type type, clap_param_value v1, clap_param_value v2) { - switch (type) { - case CLAP_PARAM_BOOL: - return v1.b == v2.b; - case CLAP_PARAM_ENUM: - case CLAP_PARAM_INT: - return v1.i == v2.i; - case CLAP_PARAM_FLOAT: - return v1.d == v2.d; - default: - std::terminate(); - } -} - -bool PluginParam::isValueEqualTo(const clap_param_value v) const { - return areValuesEqual(info_.type, value_, v); -} - -bool PluginParam::isValueValid(const clap_param_value v) const { - switch (info_.type) { - case CLAP_PARAM_BOOL: - return true; - case CLAP_PARAM_ENUM: - return enum_entries_.find(v.i) != enum_entries_.end(); - case CLAP_PARAM_INT: - return info_.min_value.i <= v.i && v.i <= info_.max_value.i; - case CLAP_PARAM_FLOAT: - return info_.min_value.d <= v.d && v.d <= info_.max_value.d; - default: - std::terminate(); - } +bool PluginParam::isValueValid(const double v) const { + return info_.min_value <= v && v <= info_.max_value; } void PluginParam::printShortInfo(std::ostream &os) const { @@ -69,54 +30,17 @@ void PluginParam::printShortInfo(std::ostream &os) const { void PluginParam::printInfo(std::ostream &os) const { printShortInfo(os); - - if (hasRange()) { - os << ", min: "; - printValue(info_.min_value, os); - os << ", max: "; - printValue(info_.max_value, os); - } -} - -void PluginParam::printValue(const clap_param_value v, std::ostream &os) const { - switch (info_.type) { - case CLAP_PARAM_BOOL: - os << (v.b ? "true" : "false"); - return; - case CLAP_PARAM_ENUM: { - auto it = enum_entries_.find(v.i); - if (it != enum_entries_.end()) - os << it->second << "=" << v.i; - else - os << "(unknown enum entry)=" << v.i; - } - return; - case CLAP_PARAM_INT: - os << v.i; - return; - case CLAP_PARAM_FLOAT: - os << v.d; - return; - default: - std::terminate(); - } + os << ", min: " << info_.min_value << ", max: " << info_.max_value; } bool PluginParam::isInfoEqualTo(const clap_param_info &info) const { - return !isInfoCriticallyDifferentTo(info) && - !strncmp(info_.name, info.name, sizeof(info.name)) && - !strncmp(info_.module, info.module, sizeof(info.module)) && - info_.is_used == info.is_used && info_.is_periodic == info.is_periodic && - info_.is_hidden == info.is_hidden && info_.is_bypass == info.is_bypass && - areValuesEqual(info.type, info_.default_value, info_.default_value); + return !std::memcmp(&info, &info_, sizeof(clap_param_info)); } bool PluginParam::isInfoCriticallyDifferentTo(const clap_param_info &info) const { - return info_.id != info.id || info_.is_per_note != info.is_per_note || - info_.is_per_channel != info.is_per_channel || info_.is_locked != info.is_locked || - info_.is_automatable != info.is_automatable || info_.type != info.type || - ((info.type == CLAP_PARAM_INT || info.type == CLAP_PARAM_FLOAT) && - !areValuesEqual(info.type, info_.min_value, info_.min_value) || - !areValuesEqual(info.type, info_.max_value, info_.max_value)) || - (info.type == CLAP_PARAM_ENUM && info.enum_entry_count != info_.enum_entry_count); + assert(info_.id == info.id); + return (info_.flags & CLAP_PARAM_IS_PER_NOTE) == (info.flags & CLAP_PARAM_IS_PER_NOTE) || + (info_.flags & CLAP_PARAM_IS_PER_CHANNEL) == (info.flags & CLAP_PARAM_IS_PER_CHANNEL) || + (info_.flags & CLAP_PARAM_IS_READONLY) == (info.flags & CLAP_PARAM_IS_READONLY) || + info_.min_value != info_.min_value || info_.max_value != info_.max_value; } \ No newline at end of file diff --git a/examples/host/plugin-param.hh b/examples/host/plugin-param.hh @@ -12,27 +12,23 @@ class PluginParam : public QObject { Q_OBJECT; public: - PluginParam(PluginHost &pluginHost, const clap_param_info &info, clap_param_value value); + PluginParam(PluginHost &pluginHost, const clap_param_info &info, double value); - clap_param_value value() const { return value_; } - void setValue(clap_param_value v); + double value() const { return value_; } + void setValue(double v); - clap_param_value modulatedValue() const { return modulated_value_; } - void setModulatedValue(clap_param_value v); + double modulatedValue() const { return modulated_value_; } + void setModulatedValue(double v); - bool hasRange() const; - bool isValueEqualTo(const clap_param_value v) const; - bool isValueValid(const clap_param_value v) const; - static bool areValuesEqual(clap_param_type type, clap_param_value v1, clap_param_value v2); + bool isValueValid(const double v) const; void printShortInfo(std::ostream &os) const; void printInfo(std::ostream &os) const; - void printValue(const clap_param_value v, std::ostream &os) const; - void setInfo(const clap_param_info &info) noexcept { info_ = info; } - bool isInfoEqualTo(const clap_param_info &info) const; - bool isInfoCriticallyDifferentTo(const clap_param_info &info) const; - clap_param_info & info() noexcept { return info_; } + void setInfo(const clap_param_info &info) noexcept { info_ = info; } + bool isInfoEqualTo(const clap_param_info &info) const; + bool isInfoCriticallyDifferentTo(const clap_param_info &info) const; + clap_param_info &info() noexcept { return info_; } const clap_param_info &info() const noexcept { return info_; } bool isBeingAdjusted() const noexcept { return is_being_adjusted_; } @@ -54,9 +50,9 @@ signals: void modulatedValueChanged(); private: - bool is_being_adjusted_ = false; - clap_param_info info_; - clap_param_value value_; - clap_param_value modulated_value_; + bool is_being_adjusted_ = false; + clap_param_info info_; + double value_; + double modulated_value_; std::unordered_map<int64_t, std::string> enum_entries_; }; \ No newline at end of file diff --git a/examples/host/plugin-parameters-widget.cc b/examples/host/plugin-parameters-widget.cc @@ -104,11 +104,10 @@ PluginParametersWidget::PluginParametersWidget(QWidget *parent, PluginHost &plug isPerNoteLabel_ = new QLabel; isPerChannelLabel_ = new QLabel; isPeriodicLabel_ = new QLabel; - isLockedLabel_ = new QLabel; - isAutomatableLabel_ = new QLabel; + isReadOnlyLabel_ = new QLabel; isHiddenLabel_ = new QLabel; isBypassLabel_ = new QLabel; - typeLabel_ = new QLabel; + isSteppedLabel_ = new QLabel; minValueLabel_ = new QLabel; maxValueLabel_ = new QLabel; defaultValueLabel_ = new QLabel; @@ -126,11 +125,10 @@ PluginParametersWidget::PluginParametersWidget(QWidget *parent, PluginHost &plug formLayout->addRow(tr("is_per_note"), isPerNoteLabel_); formLayout->addRow(tr("is_per_channel"), isPerChannelLabel_); formLayout->addRow(tr("is_periodic"), isPeriodicLabel_); - formLayout->addRow(tr("is_locked"), isLockedLabel_); - formLayout->addRow(tr("is_automatable"), isAutomatableLabel_); + formLayout->addRow(tr("is_read_only"), isReadOnlyLabel_); formLayout->addRow(tr("is_hidden"), isHiddenLabel_); formLayout->addRow(tr("is_bypass"), isBypassLabel_); - formLayout->addRow(tr("type"), typeLabel_); + formLayout->addRow(tr("is_stepped"), isSteppedLabel_); formLayout->addRow(tr("min_value"), minValueLabel_); formLayout->addRow(tr("max_value"), maxValueLabel_); formLayout->addRow(tr("default_value"), defaultValueLabel_); @@ -160,8 +158,8 @@ void PluginParametersWidget::computeDataModel() { auto &param = *it.second; QString path(param.info().module); - auto modules = path.split("/", Qt::SkipEmptyParts); - auto module = rootModuleItem_; + auto modules = path.split("/", Qt::SkipEmptyParts); + auto module = rootModuleItem_; for (auto &m : modules) module = &module->subModule(m); @@ -235,11 +233,10 @@ void PluginParametersWidget::updateParamInfo() { isPerNoteLabel_->setText("-"); isPerChannelLabel_->setText("-"); isPeriodicLabel_->setText("-"); - isLockedLabel_->setText("-"); - isAutomatableLabel_->setText("-"); + isReadOnlyLabel_->setText("-"); isHiddenLabel_->setText("-"); isBypassLabel_->setText("-"); - typeLabel_->setText("-"); + isSteppedLabel_->setText("-"); minValueLabel_->setText("-"); maxValueLabel_->setText("-"); defaultValueLabel_->setText("-"); @@ -250,44 +247,18 @@ void PluginParametersWidget::updateParamInfo() { idLabel_->setText(QString::number(i.id)); nameLabel_->setText(i.name); moduleLabel_->setText(i.module); - isPerNoteLabel_->setText(i.is_per_note ? "true" : "false"); - isPerChannelLabel_->setText(i.is_per_channel ? "true" : "false"); - isPeriodicLabel_->setText(i.is_periodic ? "true" : "false"); - isLockedLabel_->setText(i.is_locked ? "true" : "false"); - isAutomatableLabel_->setText(i.is_automatable ? "true" : "false"); - isHiddenLabel_->setText(i.is_hidden ? "true" : "false"); - isBypassLabel_->setText(i.is_bypass ? "true" : "false"); + isPerNoteLabel_->setText(i.flags & CLAP_PARAM_IS_PER_NOTE ? "true" : "false"); + isPerChannelLabel_->setText(i.flags & CLAP_PARAM_IS_PER_CHANNEL ? "true" : "false"); + isPeriodicLabel_->setText(i.flags & CLAP_PARAM_IS_PERIODIC ? "true" : "false"); + isReadOnlyLabel_->setText(i.flags & CLAP_PARAM_IS_READONLY ? "true" : "false"); + isHiddenLabel_->setText(i.flags & CLAP_PARAM_IS_HIDDEN ? "true" : "false"); + isBypassLabel_->setText(i.flags & CLAP_PARAM_IS_BYPASS ? "true" : "false"); isBeingAdjusted_->setText(p.isBeingAdjusted() ? "true" : "false"); - switch (i.type) { - case CLAP_PARAM_BOOL: - typeLabel_->setText("bool"); - minValueLabel_->setText("-"); - maxValueLabel_->setText("-"); - defaultValueLabel_->setText(i.default_value.b ? "true" : "false"); - break; - - case CLAP_PARAM_INT: - typeLabel_->setText("int"); - minValueLabel_->setText(QString::number(i.min_value.i)); - maxValueLabel_->setText(QString::number(i.max_value.i)); - defaultValueLabel_->setText(QString::number(i.default_value.i)); - break; - - case CLAP_PARAM_ENUM: - typeLabel_->setText("enum"); - minValueLabel_->setText("-"); - maxValueLabel_->setText("-"); - defaultValueLabel_->setText(QString::number(i.default_value.i)); - break; - - case CLAP_PARAM_FLOAT: - typeLabel_->setText("float"); - minValueLabel_->setText(QString::number(i.min_value.d)); - maxValueLabel_->setText(QString::number(i.max_value.d)); - defaultValueLabel_->setText(QString::number(i.default_value.d)); - break; - } + isSteppedLabel_->setText("float"); + minValueLabel_->setText(QString::number(i.min_value)); + maxValueLabel_->setText(QString::number(i.max_value)); + defaultValueLabel_->setText(QString::number(i.default_value)); } } @@ -309,16 +280,7 @@ void PluginParametersWidget::updateParamValue() { auto info = currentParam_->info(); auto v = currentParam_->value(); - switch (info.type) { - case CLAP_PARAM_FLOAT: - valueSlider_->setValue(SLIDER_RANGE * (v.d - info.min_value.d) / - (info.max_value.d - info.min_value.d)); - break; - case CLAP_PARAM_INT: - valueSlider_->setValue((SLIDER_RANGE * (v.i - info.min_value.i)) / - (info.max_value.i - info.min_value.i)); - break; - } + valueSlider_->setValue(SLIDER_RANGE * (v - info.min_value) / (info.max_value - info.min_value)); } void PluginParametersWidget::paramInfoChanged() { updateParamInfo(); } @@ -334,16 +296,6 @@ void PluginParametersWidget::sliderValueChanged(int newValue) { auto &info = currentParam_->info(); - clap_param_value value; - switch (info.type) { - case CLAP_PARAM_FLOAT: - value.d = newValue * (info.max_value.d - info.min_value.d) / SLIDER_RANGE + info.min_value.d; - pluginHost_.setParamValueByHost(*currentParam_, value); - break; - case CLAP_PARAM_INT: - value.i = - (newValue * (info.max_value.i - info.min_value.i)) / SLIDER_RANGE + info.min_value.i; - pluginHost_.setParamValueByHost(*currentParam_, value); - break; - } + double value = newValue * (info.max_value - info.min_value) / SLIDER_RANGE + info.min_value; + pluginHost_.setParamValueByHost(*currentParam_, value); } \ No newline at end of file diff --git a/examples/host/plugin-parameters-widget.hh b/examples/host/plugin-parameters-widget.hh @@ -84,11 +84,10 @@ private: QLabel * isPerNoteLabel_ = nullptr; QLabel * isPerChannelLabel_ = nullptr; QLabel * isPeriodicLabel_ = nullptr; - QLabel * isLockedLabel_ = nullptr; - QLabel * isAutomatableLabel_ = nullptr; + QLabel * isReadOnlyLabel_ = nullptr; QLabel * isHiddenLabel_ = nullptr; QLabel * isBypassLabel_ = nullptr; - QLabel * typeLabel_ = nullptr; + QLabel * isSteppedLabel_ = nullptr; QLabel * minValueLabel_ = nullptr; QLabel * maxValueLabel_ = nullptr; QLabel * defaultValueLabel_ = nullptr; diff --git a/examples/host/plugin-quick-control-widget.cc b/examples/host/plugin-quick-control-widget.cc @@ -63,17 +63,8 @@ void PluginQuickControlWidget::dialValueChanged(int newValue) { auto &info = param_->info(); - clap_param_value value; - switch (info.type) { - case CLAP_PARAM_FLOAT: - value.d = newValue * (info.max_value.d - info.min_value.d) / DIAL_RANGE + info.min_value.d; - pluginHost_.setParamValueByHost(*param_, value); - break; - case CLAP_PARAM_INT: - value.i = (newValue * (info.max_value.i - info.min_value.i)) / DIAL_RANGE + info.min_value.i; - pluginHost_.setParamValueByHost(*param_, value); - break; - } + double value = newValue * (info.max_value - info.min_value) / DIAL_RANGE + info.min_value; + pluginHost_.setParamValueByHost(*param_, value); } void PluginQuickControlWidget::updateParamValue() { if (!param_) @@ -84,16 +75,7 @@ void PluginQuickControlWidget::updateParamValue() { auto info = param_->info(); auto v = param_->value(); - switch (info.type) { - case CLAP_PARAM_FLOAT: - dial_->setValue(DIAL_RANGE * (v.d - info.min_value.d) / - (info.max_value.d - info.min_value.d)); - break; - case CLAP_PARAM_INT: - dial_->setValue((DIAL_RANGE * (v.i - info.min_value.i)) / - (info.max_value.i - info.min_value.i)); - break; - } + dial_->setValue(DIAL_RANGE * (v - info.min_value) / (info.max_value - info.min_value)); } void PluginQuickControlWidget::updateParamInfo() { diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt @@ -3,8 +3,11 @@ add_library( clap-entry.cc parameters.cc parameters.hh + parameter-interpolator.hh plugin-helper.cc plugin-helper.hh + dc-offset/dc-offset.hh + dc-offset/dc-offset.cc gain/gain.hh gain/gain.cc) target_link_libraries(clap-plugins clap-plugin-glue) diff --git a/examples/plugins/dc-offset/dc-offset.cc b/examples/plugins/dc-offset/dc-offset.cc @@ -0,0 +1,109 @@ +#include <cstring> + +#include "../parameter-interpolator.hh" +#include "dc-offset.hh" + +namespace clap { + const clap_plugin_descriptor *DcOffset::descriptor() { + static const clap_plugin_descriptor desc = { + + CLAP_VERSION, + "com.github.free-audio.clap.dc-offset", + "dc offset", + "clap", + "https://github.com/free-audio/clap", + nullptr, + nullptr, + "0.1", + "example DC offset plugin", + "utility", + CLAP_PLUGIN_AUDIO_EFFECT + + }; + return &desc; + } + + enum { + kParamIdOffset = 0, + }; + + DcOffset::DcOffset(const clap_host *host) : PluginHelper(descriptor(), host) { + parameters_.addParameter(clap_param_info{ + .id = kParamIdOffset, + .name = "offset", + .module = "/", + .flags = 0, + .min_value = -1, + .max_value = 1, + .default_value = 0, + }); + } + + bool DcOffset::init() noexcept { + if (!super::init()) + return false; + + defineAudioPorts(); + return true; + } + + void DcOffset::defineAudioPorts() noexcept { + assert(!isActive()); + + channelCount_ = trackChannelCount(); + + clap_audio_port_info info; + info.id = 0; + strncpy(info.name, "main", sizeof(info.name)); + info.is_main = true; + info.is_cv = false; + info.sample_size = 32; + info.in_place = true; + info.channel_count = channelCount_; + info.channel_map = CLAP_CHMAP_UNSPECIFIED; + + audioInputs_.clear(); + audioInputs_.push_back(info); + audioOutputs_.clear(); + audioOutputs_.push_back(info); + } + + bool DcOffset::activate(int sample_rate) noexcept { return true; } + + void DcOffset::deactivate() noexcept { channelCount_ = 0; } + + clap_process_status DcOffset::process(const clap_process *process) noexcept { + float **in = process->audio_inputs[0].data32; + float **out = process->audio_outputs[0].data32; + uint32_t evCount = process->in_events->size(process->in_events); + uint32_t nextEvIndex = 0; + const clap_event *ev = nullptr; + + for (int i = 0; i < process->frames_count; ++i) { + if (nextEvIndex < evCount) { + ev = process->in_events->get(process->in_events, nextEvIndex); + if (ev->time != i) + break; + + switch (ev->type) { + case CLAP_EVENT_PARAM_SET: + auto p = parameters_.getById(ev->param.param_id); + if (p) + p->setInterpolationData(ev->param.val0, + ev->param.val1, + ev->param.mod0, + ev->param.mod1, + ev->param.distance); + break; + } + } + + float offset = offsetParam_->value(); + for (int c = 0; c < channelCount_; ++c) + out[c][i] = in[c][i] + offset; + offsetParam_->step(1); + } + + return CLAP_PROCESS_CONTINUE_IF_NOT_QUIET; + } +} // namespace clap +\ No newline at end of file diff --git a/examples/plugins/dc-offset/dc-offset.hh b/examples/plugins/dc-offset/dc-offset.hh @@ -0,0 +1,27 @@ +#pragma once + +#include "../plugin-helper.hh" + +namespace clap { + class DcOffset final : public PluginHelper { + private: + using super = PluginHelper; + + public: + DcOffset(const clap_host *host); + + static const clap_plugin_descriptor *descriptor(); + + protected: + // clap_plugin + bool init() noexcept override; + void defineAudioPorts() noexcept; + bool activate(int sample_rate) noexcept override; + void deactivate() noexcept override; + clap_process_status process(const clap_process *process) noexcept override; + + private: + int channelCount_ = 1; + Parameter *offsetParam_ = nullptr; + }; +} // namespace clap +\ No newline at end of file diff --git a/examples/plugins/gain/gain.cc b/examples/plugins/gain/gain.cc @@ -27,29 +27,14 @@ namespace clap { }; Gain::Gain(const clap_host *host) : PluginHelper(descriptor(), host) { - parameters_.addParameter({ - .info = - { - .id = kParamIdGain, - .name = "gain", - .module = "/", - .is_per_note = false, - .is_per_channel = false, - .is_used = true, - .is_periodic = false, - .is_locked = false, - .is_automatable = true, - .is_hidden = false, - .is_bypass = false, - .type = CLAP_PARAM_FLOAT, - .min_value = {.d = -120}, - .max_value = {.d = 20}, - .default_value = {.d = 0}, - .enum_entry_count = 0, - }, - .enumDefinition = {}, - .value = {.d = 0}, - .modulation = {.d = 0}, + parameters_.addParameter(clap_param_info{ + .id = kParamIdGain, + .name = "gain", + .module = "/", + .flags = 0, + .min_value = -1, + .max_value = 1, + .default_value = 0, }); } diff --git a/examples/plugins/gain/gain.hh b/examples/plugins/gain/gain.hh @@ -1,7 +1,5 @@ #pragma once -#include <clap/all.h> - #include "../plugin-helper.hh" namespace clap { diff --git a/examples/plugins/parameter-interpolator.hh b/examples/plugins/parameter-interpolator.hh @@ -0,0 +1,68 @@ +#pragma once + +#include <cstdint> +#include <algorithm> + +namespace clap { + class ParameterInterpolator { + public: + ParameterInterpolator() = default; + ParameterInterpolator(double val, double mod) + { + setValue(val, mod); + } + + void setValue(double val, double mod) + { + val0_ = val; + val1_ = val; + mod0_ = mod; + mod1_ = mod; + duration_ = 0; + offset_ = 0; + } + + void setInterpolationData(double val0, double val1, double mod0, double mod1, uint32_t duration) noexcept + { + val0_ = val0; + val1_ = val1; + mod0_ = mod0; + mod1_ = mod1; + duration_ = duration; + offset_ = 0; + } + + double value() noexcept + { + if (offset_ >= duration_) + return val1_ + mod1_; + + const double x = static_cast<double>(offset_) / static_cast<double>(duration_); + const double value = (val1_ + mod1_) * x + (val0_ + mod0_) * (1 - x); + return value; + } + + double mod() noexcept + { + if (offset_ >= duration_) + return mod1_; + + const double x = static_cast<double>(offset_) / static_cast<double>(duration_); + const double value = (mod1_) * x + (mod0_) * (1 - x); + return value; + } + + void step(uint32_t n) noexcept + { + offset_ += n; + } + + private: + double val0_ = 0; + double val1_ = 0; + double mod0_ = 0; + double mod1_ = 0; + uint32_t duration_ = 0; + uint32_t offset_ = 0; + }; +} // namespace clap +\ No newline at end of file diff --git a/examples/plugins/parameters.cc b/examples/plugins/parameters.cc @@ -4,10 +4,10 @@ namespace clap { void clap::Parameters::addParameter(const Parameter &param) { - assert(id2param_.find(param.info.id) == id2param_.end()); + assert(id2param_.find(param.info().id) == id2param_.end()); auto p = std::make_unique<Parameter>(param); - id2param_.emplace(param.info.id, p.get()); + id2param_.emplace(param.info().id, p.get()); params_.emplace_back(std::move(p)); } diff --git a/examples/plugins/parameters.hh b/examples/plugins/parameters.hh @@ -5,23 +5,68 @@ #include <clap/all.h> +#include "parameter-interpolator.hh" + namespace clap { - struct EnumEntry { - std::string name; - int64_t value; - }; + class Parameter { + public: + Parameter(const clap_param_info &info) : info_(info) {} - struct EnumDefinition { - std::vector<EnumEntry> entries; - }; + const double value() const noexcept { return value_; } + const double modulation() const noexcept { return modulation_; } + const double modulatedValue() const noexcept { return value_ + modulation_; } + const clap_param_info &info() const noexcept { return info_; } + + void setValue(double val, double mod) { + value_ = val; + modulation_ = mod; + + val0_ = val; + val1_ = val; + mod0_ = mod; + mod1_ = mod; + distance_ = 0; + offset_ = 0; + } + + void setInterpolationData( + double val0, double val1, double mod0, double mod1, uint32_t distance) noexcept { + val0_ = val0; + val1_ = val1; + mod0_ = mod0; + mod1_ = mod1; + distance_ = distance; + offset_ = 0; + + value_ = val0; + modulation_ = mod0; + } + + void step(uint32_t n) noexcept { + offset_ += n; + if (offset_ >= n) { + offset_ = n; + value_ = val1_; + modulation_ = mod1_; + } else { + const double x = static_cast<double>(offset_) / static_cast<double>(distance_); + value_ = (val1_ + mod1_) * x + (val0_ + mod0_) * (1 - x); + mod1_ = (mod1_)*x + (mod0_) * (1 - x); + } + } + + private: + clap_param_info info_; + + double value_; + double modulation_; - struct Parameter { - clap_param_info info; - EnumDefinition enumDefinition; - clap_param_value value; - clap_param_value modulation; - double valueRamp = 0; - double modulationRamp = 0; + double val0_ = 0; + double val1_ = 0; + double mod0_ = 0; + double mod1_ = 0; + uint32_t distance_ = 0; + uint32_t offset_ = 0; }; class Parameters { @@ -38,7 +83,7 @@ namespace clap { Parameter *getById(clap_id id) const noexcept; private: - std::vector<std::unique_ptr<Parameter>> params_; + std::vector<std::unique_ptr<Parameter>> params_; std::unordered_map<clap_id, Parameter *> id2param_; }; } // namespace clap \ No newline at end of file diff --git a/examples/plugins/plugin-helper.hh b/examples/plugins/plugin-helper.hh @@ -35,33 +35,17 @@ namespace clap { uint32_t paramsCount() const noexcept override { return parameters_.count(); } bool paramsInfo(int32_t paramIndex, clap_param_info *info) const noexcept override { - *info = parameters_.getByIndex(paramIndex)->info; + *info = parameters_.getByIndex(paramIndex)->info(); return true; } - bool paramsEnumValue(clap_id paramId, - int32_t valueIndex, - clap_param_value *value) noexcept override { - value->i = parameters_.getById(paramId)->enumDefinition.entries[valueIndex].value; + virtual bool paramsValue(clap_id paramId, double *value) noexcept override { + *value = parameters_.getById(paramId)->value(); return true; } - virtual bool paramsValue(clap_id paramId, clap_param_value *value) noexcept override { - *value = parameters_.getById(paramId)->value; - return true; - } - - virtual bool paramsSetValue(clap_id paramId, - clap_param_value value, - clap_param_value modulation) noexcept override { - auto p = parameters_.getById(paramId); - p->value = value; - p->modulation = modulation; - return false; - } - virtual bool paramsValueToText(clap_id paramId, - clap_param_value value, + double value, char *display, uint32_t size) noexcept override { // TODO @@ -70,7 +54,7 @@ namespace clap { virtual bool paramsTextToValue(clap_id param_id, const char *display, - clap_param_value *value) noexcept override { + double *value) noexcept override { // TODO return false; }