Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
plugin_factory.h
1// SPDX-FileCopyrightText: © 2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <utility>
7
8#include "plugins/plugin_all.h"
9
10namespace zrythm::plugins
11{
12
21class PluginFactory : public QObject
22{
23 Q_OBJECT
24 QML_ELEMENT
25 QML_UNCREATABLE ("")
26
27public:
28 using PluginConfiguration = zrythm::plugins::PluginConfiguration;
29
30 // A handler that will be called on the main thread either asynchronously or
31 // synchronously (depending on the plugin format) when the plugin has finished
32 // instantiation
33 using InstantiationFinishedHandler =
34 std::function<void (plugins::PluginUuidReference)>;
35
37 {
38 InstantiationFinishedHandler handler_;
39 QObject * handler_context_{};
40 };
41
45 using AudioThreadChecker = std::function<bool ()>;
46
48 {
49 plugins::PluginRegistry &plugin_registry_;
50 dsp::ProcessorBase::ProcessorBaseDependencies processor_base_dependencies_;
52 plugins::JucePlugin::CreatePluginInstanceAsyncFunc
53 create_plugin_instance_async_func_;
54 std::function<units::sample_rate_t ()> sample_rate_provider_;
55 std::function<nframes_t ()> buffer_size_provider_;
56 plugins::PluginHostWindowFactory top_level_window_provider_;
57 AudioThreadChecker audio_thread_checker_;
58 };
59
60 PluginFactory () = delete;
61 PluginFactory (
62 CommonFactoryDependencies dependencies,
63 QObject * parent = nullptr)
64 : QObject (parent), dependencies_ (std::move (dependencies))
65 {
66 }
67
68private:
69 template <typename PluginT> class Builder
70 {
71 friend class PluginFactory;
72
73 private:
74 explicit Builder (CommonFactoryDependencies dependencies)
75 : dependencies_ (std::move (dependencies))
76 {
77 }
78
79 Builder &with_setting (const PluginConfiguration &setting)
80 {
81 setting_ = setting;
82 return *this;
83 }
84
85 Builder &with_instantiation_finished_options (
86 InstantiationFinishOptions instantiation_finish_options)
87 {
88 instantiation_finish_options_.emplace (instantiation_finish_options);
89 return *this;
90 }
91
92 public:
93 auto build ()
94 {
95 auto obj_ref = [&] () {
96 if constexpr (std::is_same_v<PluginT, plugins::ClapPlugin>)
97 {
98 return dependencies_.plugin_registry_.create_object<PluginT> (
99 dependencies_.processor_base_dependencies_,
100 dependencies_.state_dir_path_provider_,
101 dependencies_.audio_thread_checker_,
102 dependencies_.top_level_window_provider_);
103 }
104 else if constexpr (
105 std::derived_from<PluginT, plugins::InternalPluginBase>)
106 {
107 return dependencies_.plugin_registry_.create_object<PluginT> (
108 dependencies_.processor_base_dependencies_,
109 dependencies_.state_dir_path_provider_);
110 }
111 else
112 {
113 return dependencies_.plugin_registry_.create_object<PluginT> (
114 dependencies_.processor_base_dependencies_,
115 dependencies_.state_dir_path_provider_,
116 dependencies_.create_plugin_instance_async_func_,
117 dependencies_.sample_rate_provider_,
118 dependencies_.buffer_size_provider_,
119 dependencies_.top_level_window_provider_);
120 }
121 }();
122
123 if (instantiation_finish_options_.has_value ())
124 {
125 // set instantiation finished handler and apply configuration, which
126 // will either fire the instantiation finished handler immediately or
127 // later (depending on the plugin format)
128 std::visit (
129 [&] (auto &&pl) {
130 const auto instantiation_finish_opts =
131 instantiation_finish_options_.value ();
132 QObject::connect (
134 instantiation_finish_opts.handler_context_,
135 [obj_ref, instantiation_finish_opts] () {
136 instantiation_finish_opts.handler_ (obj_ref);
137 });
138 },
139 obj_ref.get_object ());
140 }
141
142 if (setting_.has_value ())
143 {
144 obj_ref.template get_object_as<PluginT> ()->set_configuration (
145 *setting_);
146 }
147 else
148 {
149 throw std::logic_error ("PluginConfiguration required");
150 }
151
152 return obj_ref;
153 }
154
155 private:
156 CommonFactoryDependencies dependencies_;
157 OptionalRef<const PluginConfiguration> setting_;
158 std::optional<InstantiationFinishOptions> instantiation_finish_options_;
159 };
160
161 template <typename PluginT> auto get_builder () const
162 {
163 auto builder = Builder<PluginT> (dependencies_);
164 return builder;
165 }
166
167public:
168 plugins::PluginUuidReference create_plugin_from_setting (
169 const PluginConfiguration &setting,
170 InstantiationFinishOptions instantiation_finish_options) const
171 {
172 const auto * descriptor = setting.descriptor ();
173 if (descriptor == nullptr)
174 {
175 throw std::invalid_argument ("Setting with valid descriptor required");
176 }
177
178 const auto protocol = descriptor->protocol_;
179 if (protocol == plugins::Protocol::ProtocolType::CLAP)
180 {
181 return get_builder<plugins::ClapPlugin> ()
182 .with_setting (setting)
183 .with_instantiation_finished_options (instantiation_finish_options)
184 .build ();
185 }
187 {
188 return get_builder<plugins::InternalPluginBase> ()
189 .with_setting (setting)
190 .with_instantiation_finished_options (instantiation_finish_options)
191 .build ();
192 }
193
194 return get_builder<plugins::JucePlugin> ()
195 .with_setting (setting)
196 .with_instantiation_finished_options (instantiation_finish_options)
197 .build ();
198 }
199
200// TODO
201#if 0
202 template <typename PluginT>
203 auto clone_new_object_identity (const PluginT &other) const
204 {
205 return plugin_registry_.clone_object (other, plugin_registry_);
206 }
207
208 template <typename PluginT>
209 auto clone_object_snapshot (const PluginT &other, QObject &owner) const
210 {
211 PluginT * new_obj{};
212
213 new_obj = utils::clone_qobject (
214 other, &owner, utils::ObjectCloneType::Snapshot, plugin_registry_);
215 return new_obj;
216 }
217#endif
218
219private:
220 CommonFactoryDependencies dependencies_;
221};
222}
Configuration for instantiating a plugin descriptor.
std::function< bool()> AudioThreadChecker
Function that returns whether the caller is an audio DSP thread.
std::function< fs::path()> StateDirectoryParentPathProvider
Returns the parent path where the plugin should save its state directory in (or load it).
Definition plugin.h:48
Q_SIGNAL void instantiationFinished(bool successful, const QString &error)
To be emitted by implementations when instantiation finished.
@ Internal
Dummy protocol for tests.
uint32_t nframes_t
Frame count.
Definition types.h:58
@ Snapshot
Creates a snapshot of the object with the same identity.
Definition icloneable.h:23