commit cea197fb2bc9b9e07a0a79ba9829fecd032a7d8a
parent 87ebfa05273ef685130abb690a6a289b8ac410f5
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date: Sat, 29 May 2021 15:23:52 +0200
More work on parameters
Diffstat:
4 files changed, 130 insertions(+), 10 deletions(-)
diff --git a/examples/plugins/parameters.cc b/examples/plugins/parameters.cc
@@ -0,0 +1,28 @@
+#include <cassert>
+
+#include "parameters.hh"
+
+namespace clap {
+ void clap::Parameters::addParameter(const Parameter ¶m) {
+ assert(id2param_.find(param.info.id) == id2param_.end());
+
+ auto p = std::make_unique<Parameter>(param);
+ id2param_.emplace(param.info.id, p.get());
+ params_.emplace_back(std::move(p));
+ }
+
+ size_t Parameters::count() const noexcept { return params_.size(); }
+
+ Parameter *Parameters::getByIndex(size_t index) const noexcept {
+ if (index > params_.size())
+ return nullptr;
+ return params_[index].get();
+ }
+
+ Parameter *Parameters::getById(clap_id id) const noexcept {
+ auto it = id2param_.find(id);
+ if (it == id2param_.end())
+ return nullptr;
+ return it->second;
+ }
+} // namespace clap
diff --git a/examples/plugins/parameters.hh b/examples/plugins/parameters.hh
@@ -0,0 +1,44 @@
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <clap/all.h>
+
+namespace clap {
+ struct EnumEntry {
+ std::string name;
+ int64_t value;
+ };
+
+ struct EnumDefinition {
+ std::vector<EnumEntry> entries;
+ };
+
+ struct Parameter {
+ clap_param_info info;
+ EnumDefinition enumDefinition;
+ clap_param_value value;
+ clap_param_value modulation;
+ double valueRamp = 0;
+ double modulationRamp = 0;
+ };
+
+ class Parameters {
+ public:
+ Parameters() = default;
+ Parameters(const Parameters ¶meters);
+
+ void addParameter(const Parameter ¶m);
+
+ size_t count() const noexcept;
+
+ Parameter *getByIndex(size_t index) const noexcept;
+
+ Parameter *getById(clap_id id) const noexcept;
+
+ private:
+ 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/include/clap/events.h b/include/clap/events.h
@@ -66,13 +66,28 @@ typedef union clap_param_value {
} clap_param_value;
typedef struct clap_event_param {
- int32_t key;
- int32_t channel;
- clap_id param_id; // parameter index
+ // selects if the events targets a specific key or channel, -1 for global;
+ int32_t key;
+ int32_t channel;
+
+ // target parameter
+ clap_id param_id;
+
+ // The value that we hear is value + modulation
+ // If the plugin receives MIDI CC or overrides the automation playback because of a
+ // GUI takeover, it should add the modulation and preserve the modulation playback
clap_param_value value;
- double ramp; // valid until the end of the block or the next event
- clap_param_value modulated_value;
- double modulation_ramp;
+ clap_param_value modulation;
+
+ // the ramps are constant value that are added to value every samples
+ // they are valid until the end of the block or the next event
+ // If this event happens at time T, the value at time K is value + (K - T) * ramp.
+ double value_ramp;
+ double modulation_ramp;
+
+ // only used by the plugin for output events
+ bool begin_adjust;
+ bool end_adjust;
} clap_event_param;
typedef struct clap_event_transport {
diff --git a/include/clap/ext/params.h b/include/clap/ext/params.h
@@ -9,6 +9,34 @@ extern "C" {
/// @page Parameters
/// @brief parameters management
///
+/// Main idea:
+///
+/// The host sees the plugin as an atomic entity; and acts as a controler on top of its parameters.
+///
+/// The host can read at any time the parameter value on the [main-thread] using
+/// @ref clap_plugin_params.value().
+///
+/// There is a single way at a time for the host to set parameters value.
+/// - if the plugin is active, send @ref CLAP_PARAM_SET event during the process call [audio-thread]
+/// - if the plugin is not active, call @ref clap_plugin_params.set_value [main-thread]
+///
+/// Rationale: sending @ref CLAP_PARAM_SET event during the process call is the natural way to play parameter automation.
+/// But, the process call is only possible if the plugin is active. If it is not, then everything happens on the
+/// [main-thread] using the clap_plugin_params and clap_host_params interfaces.
+///
+/// When the plugin receives a parameter set, it is responsible to keep in sync its GUI and audio processor.
+///
+/// When the plugin changes a parameter value because a knob is being adjusted on its GUI or a MIDI CC is mapped to a parameter,
+/// the plugin must inform the host. The host can then update its GUI, interrupt automation playback and record new automation points.
+/// If the plugin is active, it will send @ref CLAP_PARAM_SET events, it must set the fields begin_adjust on the first parameter set and end_adjust on the last one.
+/// If the plugin is inactive, it will use:
+/// - @ref clap_host_params.adjust_begin() - marks the begining of automation recording
+/// - @ref clap_host_params.adjust() - adds a new point in the automation recording
+/// - @ref clap_host_params.adjust_end() - marks the end of automation recording
+///
+/// @note it may be convenient for the plugin to let the host knows about the midi mapping table,
+/// and translate MIDI CCs to parameter events for the plugin, yet it is not necessary.
+///
/// Scenarios:
///
/// I. Loading a preset
@@ -24,17 +52,21 @@ extern "C" {
/// - if the plugin is not active, the host will call plugin_params->set_value(...)
///
/// III. Turning a knob on the Plugin interface
-/// - host_params->begin_adjust(...)
-/// - host_params->adjust(...) many times -> updates host's knob and record automation
-/// - host_params->end_adjust(...)
+/// - if the plugin is not active
+/// - host_params->begin_adjust(...)
+/// - host_params->adjust(...) many times -> updates host's knob and record automation
+/// - host_params->end_adjust(...)
+/// - if the plugin is active
+/// - send CLAP_PARAM_SET event and don't forget to set begin_adjust and end_adjust attributes
/// - the plugin is responsible to send the parameter value to its audio processor
///
/// IV. Turning a knob via automation
/// - host sends a CLAP_PARAM_SET event
/// - the plugin is responsible to update its GUI
///
-/// V. Turning a knob via MIDI mapping
+/// V. Turning a knob via internal MIDI mapping
/// - the plugin sends a CLAP_PARAM_SET output event
+/// - the plugin is responsible to update its GUI
///
/// VI. Adding or removing parameters
/// - call host_params->rescan(CLAP_PARAM_RESCAN_ALL)