Zrythm v2.0.0-alpha.1
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/processor_base.h"
13#include "plugins/iplugin_host_window.h"
14#include "plugins/plugin_configuration.h"
15#include "plugins/plugin_descriptor.h"
16#include "utils/qt.h"
17#include "utils/registry_utils.h"
18#include "utils/variant_helpers.h"
19
20#include <QTimer>
21
22namespace zrythm::plugins
23{
24
44{
45 Q_OBJECT
46 Q_PROPERTY (
47 int programIndex READ programIndex WRITE setProgramIndex NOTIFY
49 Q_PROPERTY (
50 zrythm::plugins::PluginConfiguration * configuration READ configuration
52 Q_PROPERTY (
53 zrythm::dsp::ProcessorParameter * bypassParameter READ bypassParameter
54 CONSTANT)
55 Q_PROPERTY (
56 zrythm::dsp::ProcessorParameter * gainParameter READ gainParameter CONSTANT)
57 Q_PROPERTY (
58 bool uiVisible READ uiVisible WRITE setUiVisible NOTIFY uiVisibleChanged)
59 Q_PROPERTY (
60 InstantiationStatus instantiationStatus READ instantiationStatus NOTIFY
61 instantiationStatusChanged)
62 QML_ELEMENT
63 QML_UNCREATABLE ("")
64
65 Q_DISABLE_COPY_MOVE (Plugin)
66public:
67 enum class InstantiationStatus : std::uint8_t
68 {
69 Pending,
71 Failed
72 };
73 Q_ENUM (InstantiationStatus)
74
75 ~Plugin () override;
76
77 // ============================================================================
78 // QML Interface
79 // ============================================================================
80
84 int programIndex () const { return program_index_.value_or (-1); }
85 void setProgramIndex (int index)
86 {
87 if (program_index_.value_or (-1) == index)
88 return;
89
90 if (index >= 0)
91 {
92 program_index_.emplace (index);
93 }
94 else
95 {
96 program_index_.reset ();
97 }
98
99 Q_EMIT programIndexChanged (index);
100 }
101
105 Q_SIGNAL void programIndexChanged (int index);
106
107 PluginConfiguration * configuration () const { return configuration_.get (); }
122 Q_SIGNAL void configurationChanged (
123 PluginConfiguration * configuration,
124 bool generateNewPluginPortsAndParams);
125
126 dsp::ProcessorParameter * bypassParameter () const;
127 dsp::ProcessorParameter * gainParameter () const;
128
129 bool uiVisible () const { return visible_; }
130 void setUiVisible (bool visible)
131 {
132 if (visible == visible_)
133 return;
135 visible_ = visible;
136 Q_EMIT uiVisibleChanged (visible);
137 }
138
143 Q_SIGNAL void uiVisibleChanged (bool visible);
144
145 InstantiationStatus instantiationStatus () const
146 {
147 return instantiation_status_;
148 }
149 Q_SIGNAL void instantiationStatusChanged (InstantiationStatus status);
159 Q_SIGNAL void instantiationFinished (bool successful, const QString &error);
160
161 // ============================================================================
162
163 PluginDescriptor &get_descriptor () const
164 {
165 return *configuration ()->descr_;
166 }
167 utils::Utf8String get_name () const
168 {
169 return configuration ()->descr_->name_;
170 }
171 Protocol::ProtocolType get_protocol () const
172 {
173 return configuration ()->descr_->protocol_;
174 }
175
188 void set_configuration (const PluginConfiguration &setting);
189
190 // ============================================================================
191 // IProcessable Interface
192 // ============================================================================
193
194 void custom_prepare_for_processing (
195 const dsp::graph::GraphNode * node,
196 units::sample_rate_t sample_rate,
197 units::sample_u32_t max_block_length) final;
198
199 [[gnu::hot]] void custom_process_block (
201 const dsp::ITransport &transport,
202 const dsp::TempoMap &tempo_map) noexcept final;
203
204 void custom_release_resources () final;
205
206 // ============================================================================
207
211 bool currently_enabled () const
212 {
213 const auto * bypass = bypassParameter ();
214 return !bypass->range ().isToggled (bypass->currentValue ());
215 }
216
217 bool currently_enabled_rt () const noexcept [[clang::nonblocking]]
218 {
219 const auto * bypass = bypass_param_rt_;
220 return !bypass->range ().isToggled (bypass->currentValue ());
221 }
222
223 // ============================================================================
224 // Implementation Interface
225 // ============================================================================
226
227public:
233 std::string save_state () const;
234
240 void load_state (const std::string &base64_state);
241
248 void flush_plugin_values ();
249
250private:
251 virtual void prepare_for_processing_impl (
252 units::sample_rate_t sample_rate,
253 units::sample_u32_t max_block_length) { };
254
255 virtual void
256 process_impl (dsp::graph::ProcessBlockInfo time_info) noexcept = 0;
257
258 virtual void release_resources_impl () { }
259
268 [[gnu::hot]] virtual void process_passthrough_impl (
270 const dsp::ITransport &transport,
271 const dsp::TempoMap &tempo_map) noexcept;
272
273 virtual std::string save_state_impl () const = 0;
274 virtual void load_state_impl (const std::string &base64_state) = 0;
275
276 // ============================================================================
277
284 void init_param_caches ();
285
286protected:
293 Plugin (utils::IObjectRegistry &registry, QObject * parent);
294
299 dsp::ProcessorParameterUuidReference generate_default_bypass_param () const;
300
305 dsp::ProcessorParameterUuidReference generate_default_gain_param () const;
306
307private:
308 static constexpr auto kConfigurationKey = "configuration"sv;
309 static constexpr auto kProgramIndexKey = "programIndex"sv;
310 static constexpr auto kProtocolKey = "protocol"sv;
311 static constexpr auto kVisibleKey = "visible"sv;
312 friend void to_json (nlohmann::json &j, const Plugin &p);
313 friend void from_json (const nlohmann::json &j, Plugin &p);
314
315protected:
318 bool instantiation_failed_ = false;
319
320 // ============================================================================
321 // DSP Caches
322 // ============================================================================
323
330 std::optional<dsp::ProcessorParameter::Uuid> bypass_id_;
331
335 std::optional<dsp::ProcessorParameter::Uuid> gain_id_;
336
337 /* Realtime caches */
338 std::vector<dsp::AudioPort *> audio_in_ports_;
339 std::vector<dsp::AudioPort *> audio_out_ports_;
340 std::vector<dsp::CVPort *> cv_in_ports_;
341 dsp::MidiPort * midi_in_port_{};
342 dsp::MidiPort * midi_out_port_{};
343 dsp::ProcessorParameter * bypass_param_rt_{};
344
345 // ============================================================================
346 // Parameter Synchronization
347 // ============================================================================
348
352 struct ParamSync
354 struct Entry
355 {
362 float last_from_plugin = -1.f;
363
369 std::atomic<float> pending_value{ -1.f };
370
371 Entry () = default;
372 Entry (const Entry &) = delete;
373 Entry &operator= (const Entry &) = delete;
374 Entry (Entry &&other) noexcept
375 : last_from_plugin (other.last_from_plugin),
376 pending_value (other.pending_value.load (std::memory_order_relaxed))
377 {
378 }
379 Entry &operator= (Entry &&other) noexcept
380 {
381 if (this != &other)
382 {
383 last_from_plugin = other.last_from_plugin;
385 other.pending_value.load (std::memory_order_relaxed),
386 std::memory_order_relaxed);
387 }
388 return *this;
389 }
390 };
391
393 std::vector<Entry> entries;
394
395 void prepare (size_t count) { entries.resize (count); }
396 };
397
398 ParamSync param_sync_;
399
400 // ============================================================================
401
402private:
404 std::unique_ptr<PluginConfiguration> configuration_;
405
409 std::optional<int> program_index_;
410
411 InstantiationStatus instantiation_status_{ InstantiationStatus::Pending };
412
414 bool visible_ = false;
415
419 bool set_configuration_called_{};
420
426 utils::QObjectUniquePtr<QTimer> param_flush_timer_;
427};
428
430class JucePlugin;
431class ClapPlugin;
433
434using PluginVariant = std::variant<JucePlugin, ClapPlugin, InternalPluginBase>;
435using PluginPtrVariant = utils::to_pointer_variant<PluginVariant>;
436
437using PluginUuidReference = utils::TypedUuidReference<Plugin>;
438
439using PluginHostWindowFactory =
440 std::function<std::unique_ptr<plugins::IPluginHostWindow> (Plugin &)>;
441
442} // namespace zrythm::plugins
443
444DEFINE_UUID_HASH_SPECIALIZATION (zrythm::plugins::Plugin::Uuid)
Interface for transport.
Definition itransport.h:16
MIDI port specifics.
Definition midi_port.h:21
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:255
Represents a node in a DSP graph.
Definition graph_node.h:173
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:44
bool instantiation_failed_
Set to true if instantiation failed and the plugin will be treated as disabled.
Definition plugin.h:309
Plugin(utils::IObjectRegistry &registry, QObject *parent)
Creates/initializes a plugin and its internal plugin (LV2, etc.) using the given setting.
void custom_process_block(dsp::graph::ProcessBlockInfo time_nfo, const dsp::ITransport &transport, const dsp::TempoMap &tempo_map) noexcept final
Custom processor logic after processing all owned parameters.
std::optional< dsp::ProcessorParameter::Uuid > gain_id_
Zrythm-provided plugin gain parameter.
Definition plugin.h:326
int programIndex() const
Returns the current program index, or -1 if no program exists.
Definition plugin.h:75
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:202
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:60
@ Successful
Instantiation successful.
Definition plugin.h:61
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:321
dsp::ProcessorParameterUuidReference generate_default_bypass_param() const
To be called by implementations to generate the default bypass parameter if the plugin does not provi...
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.
Abstract interface for a UUID-keyed object registry.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37
CRTP base that adds a typed UUID strong-typedef to a class hierarchy.
typename to_pointer_variant_impl< Variant >::type to_pointer_variant
Converts a variant to a variant of pointers.
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:360
float last_from_plugin
One-shot feedback guard: set when the plugin reports a value.
Definition plugin.h:353
Per-parameter state for bidirectional plugin sync.
Definition plugin.h:344
std::vector< Entry > entries
Parallel to ProcessorBase's live_params_.
Definition plugin.h:384