Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
plugin.h
1// SPDX-FileCopyrightText: © 2018-2022, 2024-2026 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <atomic>
7#include <memory>
8#include <vector>
9
10#include "dsp/parameter.h"
11#include "dsp/port_all.h"
12#include "dsp/port_span.h"
13#include "dsp/processor_base.h"
14#include "plugins/iplugin_host_window.h"
15#include "plugins/plugin_configuration.h"
16#include "plugins/plugin_descriptor.h"
17#include "utils/qt.h"
18
19#include <QTimer>
20
21namespace zrythm::plugins
22{
23
42class Plugin
43 : public QObject,
44 public dsp::ProcessorBase,
46{
47 Q_OBJECT
48 Q_PROPERTY (
49 int programIndex READ programIndex WRITE setProgramIndex NOTIFY
51 Q_PROPERTY (
52 zrythm::plugins::PluginConfiguration * configuration READ configuration
54 Q_PROPERTY (
55 zrythm::dsp::ProcessorParameter * bypassParameter READ bypassParameter
56 CONSTANT)
57 Q_PROPERTY (
58 zrythm::dsp::ProcessorParameter * gainParameter READ gainParameter CONSTANT)
59 Q_PROPERTY (
60 bool uiVisible READ uiVisible WRITE setUiVisible NOTIFY uiVisibleChanged)
61 Q_PROPERTY (
62 InstantiationStatus instantiationStatus READ instantiationStatus NOTIFY
63 instantiationStatusChanged)
64 QML_ELEMENT
65 QML_UNCREATABLE ("")
66
67 Q_DISABLE_COPY_MOVE (Plugin)
68public:
69 enum class InstantiationStatus : std::uint8_t
70 {
71 Pending,
73 Failed
74 };
75 Q_ENUM (InstantiationStatus)
76
77 ~Plugin () override;
78
79 // ============================================================================
80 // QML Interface
81 // ============================================================================
82
86 int programIndex () const { return program_index_.value_or (-1); }
87 void setProgramIndex (int index)
88 {
89 if (program_index_.value_or (-1) == index)
90 return;
91
92 if (index >= 0)
93 {
94 program_index_.emplace (index);
95 }
96 else
97 {
98 program_index_.reset ();
99 }
100
101 Q_EMIT programIndexChanged (index);
102 }
103
107 Q_SIGNAL void programIndexChanged (int index);
108
109 PluginConfiguration * configuration () const { return configuration_.get (); }
124 Q_SIGNAL void configurationChanged (
125 PluginConfiguration * configuration,
126 bool generateNewPluginPortsAndParams);
127
128 dsp::ProcessorParameter * bypassParameter () const
129 {
130 return std::get<dsp::ProcessorParameter *> (
131 dependencies ().param_registry_.find_by_id_or_throw (bypass_id_.value ()));
132 }
133 dsp::ProcessorParameter * gainParameter () const
134 {
135 return std::get<dsp::ProcessorParameter *> (
136 dependencies ().param_registry_.find_by_id_or_throw (gain_id_.value ()));
137 }
138
139 bool uiVisible () const { return visible_; }
140 void setUiVisible (bool visible)
141 {
142 if (visible == visible_)
143 return;
145 visible_ = visible;
146 Q_EMIT uiVisibleChanged (visible);
147 }
148
153 Q_SIGNAL void uiVisibleChanged (bool visible);
154
155 InstantiationStatus instantiationStatus () const
156 {
157 return instantiation_status_;
158 }
159 Q_SIGNAL void instantiationStatusChanged (InstantiationStatus status);
169 Q_SIGNAL void instantiationFinished (bool successful, const QString &error);
170
171 // ============================================================================
172
173 PluginDescriptor &get_descriptor () const
174 {
175 return *configuration ()->descr_;
176 }
177 utils::Utf8String get_name () const
178 {
179 return configuration ()->descr_->name_;
180 }
181 Protocol::ProtocolType get_protocol () const
182 {
183 return configuration ()->descr_->protocol_;
184 }
185
198 void set_configuration (const PluginConfiguration &setting);
199
200 // ============================================================================
201 // IProcessable Interface
202 // ============================================================================
203
204 void custom_prepare_for_processing (
205 const dsp::graph::GraphNode * node,
206 units::sample_rate_t sample_rate,
207 units::sample_u32_t max_block_length) final;
208
209 [[gnu::hot]] void custom_process_block (
211 const dsp::ITransport &transport,
212 const dsp::TempoMap &tempo_map) noexcept final;
213
214 void custom_release_resources () final;
215
216 // ============================================================================
217
221 bool currently_enabled () const
222 {
223 const auto * bypass = bypassParameter ();
224 return !bypass->range ().is_toggled (bypass->currentValue ());
225 }
226
227 bool currently_enabled_rt () const noexcept [[clang::nonblocking]]
228 {
229 const auto * bypass = bypass_param_rt_;
230 return !bypass->range ().is_toggled (bypass->currentValue ());
231 }
232
233 // ============================================================================
234 // Implementation Interface
235 // ============================================================================
236
237public:
243 std::string save_state () const;
244
250 void load_state (const std::string &base64_state);
251
258 void flush_plugin_values ();
259
260private:
261 virtual void prepare_for_processing_impl (
262 units::sample_rate_t sample_rate,
263 units::sample_u32_t max_block_length) { };
264
265 virtual void
266 process_impl (dsp::graph::EngineProcessTimeInfo time_info) noexcept = 0;
267
268 virtual void release_resources_impl () { }
269
278 [[gnu::hot]] virtual void process_passthrough_impl (
280 const dsp::ITransport &transport,
281 const dsp::TempoMap &tempo_map) noexcept;
282
283 virtual std::string save_state_impl () const = 0;
284 virtual void load_state_impl (const std::string &base64_state) = 0;
285
286 // ============================================================================
287
294 void init_param_caches ();
295
296protected:
303 Plugin (ProcessorBaseDependencies dependencies, QObject * parent);
304
309 dsp::ProcessorParameterUuidReference generate_default_bypass_param () const;
310
315 dsp::ProcessorParameterUuidReference generate_default_gain_param () const;
316
317private:
318 static constexpr auto kConfigurationKey = "configuration"sv;
319 static constexpr auto kProgramIndexKey = "programIndex"sv;
320 static constexpr auto kProtocolKey = "protocol"sv;
321 static constexpr auto kVisibleKey = "visible"sv;
322 friend void to_json (nlohmann::json &j, const Plugin &p);
323 friend void from_json (const nlohmann::json &j, Plugin &p);
324
325protected:
328 bool instantiation_failed_ = false;
329
330 // ============================================================================
331 // DSP Caches
332 // ============================================================================
333
340 std::optional<dsp::ProcessorParameter::Uuid> bypass_id_;
341
345 std::optional<dsp::ProcessorParameter::Uuid> gain_id_;
346
347 /* Realtime caches */
348 std::vector<dsp::AudioPort *> audio_in_ports_;
349 std::vector<dsp::AudioPort *> audio_out_ports_;
350 std::vector<dsp::CVPort *> cv_in_ports_;
351 dsp::MidiPort * midi_in_port_{};
352 dsp::MidiPort * midi_out_port_{};
353 dsp::ProcessorParameter * bypass_param_rt_{};
354
355 // ============================================================================
356 // Parameter Synchronization
357 // ============================================================================
358
362 struct ParamSync
364 struct Entry
365 {
372 float last_from_plugin = -1.f;
373
379 std::atomic<float> pending_value{ -1.f };
380
381 Entry () = default;
382 Entry (const Entry &) = delete;
383 Entry &operator= (const Entry &) = delete;
384 Entry (Entry &&other) noexcept
385 : last_from_plugin (other.last_from_plugin),
386 pending_value (other.pending_value.load (std::memory_order_relaxed))
387 {
388 }
389 Entry &operator= (Entry &&other) noexcept
390 {
391 if (this != &other)
392 {
393 last_from_plugin = other.last_from_plugin;
395 other.pending_value.load (std::memory_order_relaxed),
396 std::memory_order_relaxed);
397 }
398 return *this;
399 }
400 };
401
403 std::vector<Entry> entries;
404
405 void prepare (size_t count) { entries.resize (count); }
406 };
407
408 ParamSync param_sync_;
409
410 // ============================================================================
411
412private:
414 std::unique_ptr<PluginConfiguration> configuration_;
415
419 std::optional<int> program_index_;
420
421 InstantiationStatus instantiation_status_{ InstantiationStatus::Pending };
422
424 bool visible_ = false;
425
429 bool set_configuration_called_{};
430
436 utils::QObjectUniquePtr<QTimer> param_flush_timer_;
437};
438
440class JucePlugin;
441class ClapPlugin;
443
444using PluginVariant = std::variant<JucePlugin, ClapPlugin, InternalPluginBase>;
445using PluginPtrVariant = to_pointer_variant<PluginVariant>;
446
447// TODO: consider having a ProcessorRegistry instead for all
448// ProcessorBase-derived classes
449using PluginRegistry = utils::OwningObjectRegistry<PluginPtrVariant, Plugin>;
450using PluginUuidReference = utils::UuidReference<PluginRegistry>;
451
452using PluginHostWindowFactory =
453 std::function<std::unique_ptr<plugins::IPluginHostWindow> (Plugin &)>;
454
455} // namespace zrythm::plugins
456
457DEFINE_UUID_HASH_SPECIALIZATION (zrythm::plugins::Plugin::Uuid)
458
459void
460from_json (const nlohmann::json &j, zrythm::plugins::PluginRegistry &registry);
Interface for transport.
Definition itransport.h:16
MIDI port specifics.
Definition midi_port.h:22
A base class for processors in the DSP graph.
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
Definition parameter.h:167
Represents a node in a DSP graph.
Definition graph_node.h:160
CLAP-based plugin host implementation.
Definition clap_plugin.h:26
A base class for internal plugins.
JUCE-based plugin host implementation.
Definition juce_plugin.h:20
Configuration for instantiating a plugin descriptor.
std::unique_ptr< zrythm::plugins::PluginDescriptor > descr_
The descriptor of the plugin this setting is for.
The PluginDescriptor class provides a set of static utility functions and member functions to work wi...
DSP processing plugin.
Definition plugin.h:46
bool instantiation_failed_
Set to true if instantiation failed and the plugin will be treated as disabled.
Definition plugin.h:319
Plugin(ProcessorBaseDependencies dependencies, QObject *parent)
Creates/initializes a plugin and its internal plugin (LV2, etc.) using the given setting.
std::optional< dsp::ProcessorParameter::Uuid > gain_id_
Zrythm-provided plugin gain parameter.
Definition plugin.h:336
int programIndex() const
Returns the current program index, or -1 if no program exists.
Definition plugin.h:77
std::string save_state() const
Serializes the plugin's internal state to a base64-encoded string.
bool currently_enabled() const
Returns whether the plugin is enabled (not bypassed).
Definition plugin.h:212
dsp::ProcessorParameterUuidReference generate_default_gain_param() const
To be called by implementations to generate the default gain parameter if the plugin does not provide...
void load_state(const std::string &base64_state)
Queues a previously saved state to be applied to the plugin.
Q_SIGNAL void uiVisibleChanged(bool visible)
Implementations should listen to this and show/hide the plugin UI accordingly.
@ Pending
Instantiation underway.
Definition plugin.h:62
@ Successful
Instantiation successful.
Definition plugin.h:63
Q_SIGNAL void configurationChanged(PluginConfiguration *configuration, bool generateNewPluginPortsAndParams)
Emitted when the configuration is set on the plugin.
std::optional< dsp::ProcessorParameter::Uuid > bypass_id_
Bypass toggle parameter,.
Definition plugin.h:331
dsp::ProcessorParameterUuidReference generate_default_bypass_param() const
To be called by implementations to generate the default bypass parameter if the plugin does not provi...
void custom_process_block(dsp::graph::EngineProcessTimeInfo time_nfo, const dsp::ITransport &transport, const dsp::TempoMap &tempo_map) noexcept final
Custom processor logic after processing all owned parameters.
Q_SIGNAL void instantiationFinished(bool successful, const QString &error)
To be emitted by implementations when instantiation finished.
Q_SIGNAL void programIndexChanged(int index)
Implementations should attach to this and set the program.
void flush_plugin_values()
Flushes plugin-reported parameter values to Zrythm params.
void set_configuration(const PluginConfiguration &setting)
Sets the plugin configuration to use.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37
Base class for objects that need to be uniquely identified by UUID.
Common struct to pass around during processing to avoid repeating the data in function arguments.
Definition graph_node.h:51
std::atomic< float > pending_value
Cross-thread bridge: audio thread stores normalized value with release ordering; main thread exchange...
Definition plugin.h:370
float last_from_plugin
One-shot feedback guard: set when the plugin reports a value.
Definition plugin.h:363
Per-parameter state for bidirectional plugin sync.
Definition plugin.h:354
std::vector< Entry > entries
Parallel to ProcessorBase's live_params_.
Definition plugin.h:394