6#include "dsp/audio_port.h"
7#include "dsp/cv_port.h"
8#include "dsp/graph_node.h"
9#include "dsp/midi_port.h"
10#include "utils/math_utils.h"
11#include "utils/traits.h"
12#include "utils/units.h"
13#include "utils/uuid_identifiable_object.h"
15#include <QtQmlIntegration/qqmlintegration.h>
17#include <nlohmann/json_fwd.hpp>
25 QML_VALUE_TYPE (parameterRange)
28 enum class Type : std::uint8_t
72 enum class
Unit : std::uint8_t
94 : type_ (type),
minf_ (min), maxf_ (max),
95 zerof_ (std::clamp (zero, min, max)),
deff_ (std::clamp (def, min, max))
99 static ParameterRange make_toggle (
bool default_val)
101 return {
Type::Toggle, 0.f, 1.f, 0.f, default_val ? 1.f : 0.f };
103 static ParameterRange make_gain (
float max_val)
108 static ParameterRange make_enumeration (
109 std::vector<utils::Utf8String> labels,
110 size_t default_index = 0)
114 throw std::invalid_argument (
115 "Enumeration parameter requires at least one label");
117 if (default_index >= labels.size ())
119 throw std::invalid_argument (
120 "default_index out of range for enumeration labels");
122 const auto count =
static_cast<float> (labels.size ());
123 ParameterRange range{
125 static_cast<float> (default_index)
127 range.enum_labels_ = std::move (labels);
139 Q_INVOKABLE
size_t enumIndex (
float normalized_val)
const
141 const auto real = convertFrom0To1 (normalized_val);
143 const auto idx =
static_cast<size_t> (std::max (std::round (real), 0.f));
155 return convertTo0To1 (
static_cast<float> (index));
166 Q_INVOKABLE QString enumLabel (
int index)
const
168 if (index < 0 ||
static_cast<size_t> (index) >=
enum_labels_.size ())
170 return enum_label (
static_cast<size_t> (index)).to_qstring ();
173 template <EnumType E>
float normalized_from_enum (E value)
const
176 const auto index =
static_cast<size_t> (value);
181 template <EnumType E> E enum_value (
float normalized_val)
const
184 return static_cast<E
> (
enumIndex (normalized_val));
187 constexpr float clamp_to_range (
float val)
const
189 return std::clamp (val,
minf_, maxf_);
192 Q_INVOKABLE
float convertFrom0To1 (
float normalized_val)
const;
193 Q_INVOKABLE
float convertTo0To1 (
float real_val)
const;
195 Q_INVOKABLE
bool isToggled (
float normalized_val)
const
201 friend void to_json (nlohmann::json &j,
const ParameterRange &p);
202 friend void from_json (
const nlohmann::json &j, ParameterRange &p);
233 BOOST_DESCRIBE_CLASS (
248class ProcessorParameter
255 float baseValue READ baseValue WRITE setBaseValue NOTIFY baseValueChanged)
256 Q_PROPERTY (QString label READ label CONSTANT)
257 Q_PROPERTY (QString description READ description CONSTANT)
259 Q_PROPERTY (
bool automatable READ automatable CONSTANT)
264 struct UniqueId final
265 : type_safe::strong_typedef<UniqueId,
utils::Utf8String>,
266 type_safe::strong_typedef_op::equality_comparison<UniqueId>,
267 type_safe::strong_typedef_op::relational_comparison<UniqueId>
271 explicit UniqueId () =
default;
275 std::size_t hash ()
const {
return qHash (type_safe::get (*this).view ()); }
277 static_assert (std::regular<UniqueId>);
280 std::function<QPointer<ProcessorParameter> (
const UniqueId &unique_id)>;
283 PortRegistry &port_registry,
287 QObject * parent =
nullptr);
303 std::function<std::optional<float> (units::sample_t sample_position)>;
309 QString label ()
const {
return label_.to_qstring (); }
310 QString description ()
const {
return description_->to_qstring (); }
311 bool automatable ()
const {
return automatable_; }
313 const auto &range ()
const {
return range_; }
315 float baseValue ()
const {
return base_value_.load (); }
316 void setBaseValue (
float newValue) [[clang::blocking]]
318 newValue = std::clamp (newValue, 0.f, 1.f);
319 if (qFuzzyCompare (base_value_, newValue))
321 base_value_ = newValue;
322 Q_EMIT baseValueChanged (newValue);
324 Q_INVOKABLE
void resetBaseValueToDefault ()
326 setBaseValue (range_.convertTo0To1 (range_.deff_));
328 Q_SIGNAL
void baseValueChanged (
float value);
334 Q_INVOKABLE
float currentValue ()
const {
return last_modulated_value_; }
344 return last_automated_value_.load ();
347 Q_INVOKABLE
void beginUserGesture ()
349 during_gesture_.store (
true);
350 Q_EMIT userGestureStarted ();
352 Q_INVOKABLE
void endUserGesture ()
354 during_gesture_.store (
false);
355 Q_EMIT userGestureFinished ();
357 Q_SIGNAL
void userGestureStarted ();
358 Q_SIGNAL
void userGestureFinished ();
377 const dsp::TempoMap &tempo_map)
noexcept override;
381 units::sample_rate_t sample_rate,
382 units::sample_u32_t max_block_length)
override;
389 automation_value_provider_ = provider;
391 void unset_automation_provider () { automation_value_provider_.reset (); }
393 PortUuidReference get_modulation_input_port_ref ()
const
395 return modulation_input_uuid_;
398 void set_description (utils::Utf8String descr)
400 description_ = std::move (descr);
403 void set_automatable (
bool automatable) { automatable_ = automatable; }
405 bool hidden ()
const {
return hidden_; }
407 const auto &get_unique_id ()
const {
return unique_id_; }
411 static constexpr auto kUniqueIdKey =
"uniqueId"sv;
412 static constexpr auto kRangeKey =
"range"sv;
413 static constexpr auto kLabelKey =
"label"sv;
414 static constexpr auto kSymbolKey =
"symbol"sv;
415 static constexpr auto kDescriptionKey =
"description"sv;
416 static constexpr auto kAutomatableKey =
"automatable"sv;
417 static constexpr auto kHiddenKey =
"hidden"sv;
418 static constexpr auto kBaseValueKey =
"baseValue"sv;
419 static constexpr auto kModulationSourcePortIdKey =
"modulationSourcePortId"sv;
420 friend void to_json (nlohmann::json &j,
const ProcessorParameter &p);
421 friend void from_json (
const nlohmann::json &j, ProcessorParameter &p);
437 ParameterRange range_;
440 utils::Utf8String label_;
445 std::atomic<float> base_value_;
452 std::atomic_bool during_gesture_;
461 std::atomic<float> last_automated_value_;
472 std::atomic<float> last_modulated_value_;
480 PortUuidReference modulation_input_uuid_;
483 dsp::CVPort * modulation_input_{};
490 std::optional<AutomationValueProvider> automation_value_provider_;
493 std::optional<utils::Utf8String> symbol_;
496 std::optional<utils::Utf8String> description_;
499 bool automatable_{
true };
504 BOOST_DESCRIBE_CLASS (
506 (utils::UuidIdentifiableObject<ProcessorParameter>),
513 modulation_input_uuid_,
523 return type_safe::get (
id).view ();
526using ProcessorParameterPtrVariant = std::variant<ProcessorParameter *>;
529DEFINE_UUID_HASH_SPECIALIZATION (zrythm::dsp::ProcessorParameter::Uuid)
539class ProcessorParameterRegistry
541 OwningObjectRegistry<ProcessorParameterPtrVariant, ProcessorParameter>
544 ProcessorParameterRegistry (
545 dsp::PortRegistry &port_registry,
546 QObject * parent =
nullptr)
548 ProcessorParameterPtrVariant,
550 port_registry_ (port_registry)
557 const auto &map = get_hash_map ();
558 for (
const auto &kv : map)
560 if (std::get<ProcessorParameter *> (kv.second)->get_unique_id () ==
id)
562 return std::get<ProcessorParameter *> (kv.second);
571 auto * val = find_by_unique_id (
id);
572 if (val ==
nullptr) [[unlikely]]
574 throw std::runtime_error (
575 fmt::format (
"Processor Parameter with unique id {} not found",
id));
581 struct ProcessorParameterRegistryBuilder
583 ProcessorParameterRegistryBuilder (dsp::PortRegistry &port_registry)
584 : port_registry_ (port_registry)
588 template <
typename T> std::unique_ptr<T> build ()
const
590 return std::make_unique<T> (
595 dsp::PortRegistry &port_registry_;
599 from_json (
const nlohmann::json &j, ProcessorParameterRegistry ®)
601 from_json_with_builder (
602 j, reg, ProcessorParameterRegistryBuilder{ reg.port_registry_ });
606 dsp::PortRegistry &port_registry_;
616template <>
struct hash<zrythm::dsp::ProcessorParameter::UniqueId>
std::vector< utils::Utf8String > enum_labels_
Labels for Enumeration type parameters.
float minf_
Minimum, maximum and zero values for this parameter.
Q_INVOKABLE size_t enumCount() const
Returns the number of enum entries.
const auto & enum_label(size_t index) const
Returns the label for a given enum index.
Q_INVOKABLE float normalizedEnumValue(size_t index) const
Returns the normalized value for a given enum index.
float zerof_
The zero position of the port.
Unit unit_
Parameter unit.
Q_INVOKABLE size_t enumIndex(float normalized_val) const
Converts a normalized value to an enum index.
@ GainAmplitude
Parameter is a gain amplitude (0-2.0).
@ Enumeration
Port's only reasonable values are its scale points.
@ Logarithmic
Logarithmic-scaled float parameter.
@ Linear
Linearly-scaled float parameter.
@ Integer
Whether the port is an integer.
@ Toggle
Whether the port is a toggle (on/off).
@ Trigger
Trigger parameters are set to on to trigger a change during processing and then turned off at the end...
Unit
Unit to be displayed in the UI.
float deff_
Default value.
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
std::function< std::optional< float >(units::sample_t sample_position)> AutomationValueProvider
Provides the automation value for a given sample position.
void prepare_for_processing(const graph::GraphNode *node, units::sample_rate_t sample_rate, units::sample_u32_t max_block_length) override
Called to allocate resources required for processing.
void release_resources() override
Called to release resources allocated by prepare_for_processing().
void process_block(dsp::graph::ProcessBlockInfo time_nfo, const dsp::ITransport &transport, const dsp::TempoMap &tempo_map) noexcept override
Processes automation and modulation.
Q_INVOKABLE float currentValue() const
Returns the current (normalized) value after any automation and modulation has been applied.
utils::Utf8String get_node_name() const override
Returns a human friendly name of the node.
Q_INVOKABLE float valueAfterAutomationApplied() const
Returns the value after automation, but before modulation has been applied.
Represents a node in a DSP graph.
Interface for objects that can be processed in the DSP graph.
A registry that owns and manages objects identified by a UUID.
Lightweight UTF-8 string wrapper with safe conversions.
Base class for objects that need to be uniquely identified by UUID.
A reference-counted RAII wrapper for a UUID in a registry.
constexpr bool floats_equal(T a, T b)
Checks if 2 floating point numbers are equal.
Common struct to pass around during processing to avoid repeating the data in function arguments.