Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
plugin_factory.h
1// SPDX-FileCopyrightText: © 2025-2026 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#include "utils/optional_ref.h"
10#include "utils/registry_utils.h"
11
12namespace zrythm::plugins
13{
14
23class PluginFactory : public QObject
24{
25 Q_OBJECT
26 QML_ELEMENT
27 QML_UNCREATABLE ("")
28
29public:
30 using PluginConfiguration = zrythm::plugins::PluginConfiguration;
31
32 // A handler that will be called on the main thread either asynchronously or
33 // synchronously (depending on the plugin format) when the plugin has finished
34 // instantiation
35 using InstantiationFinishedHandler =
36 std::function<void (plugins::PluginUuidReference)>;
37
39 {
40 InstantiationFinishedHandler handler_;
41 QObject * handler_context_{};
42 };
43
45 {
46 utils::IObjectRegistry &registry;
47 plugins::JucePlugin::CreatePluginInstanceAsyncFunc
48 create_plugin_instance_async_func_;
49 std::function<units::sample_rate_t ()> sample_rate_provider_;
50 std::function<units::sample_u32_t ()> buffer_size_provider_;
51 plugins::PluginHostWindowFactory top_level_window_provider_;
52 };
53
54 PluginFactory () = delete;
55 PluginFactory (
56 CommonFactoryDependencies dependencies,
57 QObject * parent = nullptr)
58 : QObject (parent), dependencies_ (std::move (dependencies))
59 {
60 }
61
62private:
63 template <typename PluginT> class Builder
64 {
65 friend class PluginFactory;
66
67 private:
68 explicit Builder (CommonFactoryDependencies dependencies)
69 : dependencies_ (std::move (dependencies))
70 {
71 }
72
73 Builder &with_setting (const PluginConfiguration &setting)
74 {
75 setting_ = setting;
76 return *this;
77 }
78
79 Builder &with_instantiation_finished_options (
80 InstantiationFinishOptions instantiation_finish_options)
81 {
82 instantiation_finish_options_.emplace (instantiation_finish_options);
83 return *this;
84 }
85
86 public:
87 auto build ()
88 {
89 auto obj_ref = [&] () {
90 if constexpr (std::is_same_v<PluginT, plugins::ClapPlugin>)
91 {
92 return utils::create_object<PluginT> (
93 dependencies_.registry, dependencies_.registry,
94 dependencies_.top_level_window_provider_);
95 }
96 else if constexpr (
97 std::derived_from<PluginT, plugins::InternalPluginBase>)
98 {
99 return utils::create_object<PluginT> (
100 dependencies_.registry, dependencies_.registry);
101 }
102 else
103 {
104 return utils::create_object<PluginT> (
105 dependencies_.registry, dependencies_.registry,
106 dependencies_.create_plugin_instance_async_func_,
107 dependencies_.sample_rate_provider_,
108 dependencies_.buffer_size_provider_,
109 dependencies_.top_level_window_provider_);
110 }
111 }();
112
113 if (instantiation_finish_options_.has_value ())
114 {
115 // set instantiation finished handler and apply configuration, which
116 // will either fire the instantiation finished handler immediately or
117 // later (depending on the plugin format)
118 const auto instantiation_finish_opts =
119 instantiation_finish_options_.value ();
120 auto * plugin = obj_ref.get ();
121 QObject::connect (
123 instantiation_finish_opts.handler_context_,
124 [obj_ref, instantiation_finish_opts] () {
125 instantiation_finish_opts.handler_ (obj_ref);
126 });
127 }
128
129 if (setting_.has_value ())
130 {
131 obj_ref.template get_object_as<PluginT> ()->set_configuration (
132 *setting_);
133 }
134 else
135 {
136 throw std::logic_error ("PluginConfiguration required");
137 }
138
139 return obj_ref;
140 }
141
142 private:
143 CommonFactoryDependencies dependencies_;
144 utils::OptionalRef<const PluginConfiguration> setting_;
145 std::optional<InstantiationFinishOptions> instantiation_finish_options_;
146 };
147
148 template <typename PluginT> auto get_builder () const
149 {
150 auto builder = Builder<PluginT> (dependencies_);
151 return builder;
152 }
153
154public:
155 template <typename PluginT>
156 std::unique_ptr<PluginT> build_for_deserialization () const
157 {
158 if constexpr (std::is_same_v<PluginT, plugins::ClapPlugin>)
159 {
160 return std::make_unique<PluginT> (
161 dependencies_.registry, dependencies_.top_level_window_provider_);
162 }
163 else if constexpr (std::derived_from<PluginT, plugins::InternalPluginBase>)
164 {
165 return std::make_unique<PluginT> (dependencies_.registry);
166 }
167 else
168 {
169 return std::make_unique<PluginT> (
170 dependencies_.registry,
171 dependencies_.create_plugin_instance_async_func_,
172 dependencies_.sample_rate_provider_,
173 dependencies_.buffer_size_provider_,
174 dependencies_.top_level_window_provider_);
175 }
176 }
177
178public:
179 plugins::PluginUuidReference create_plugin_from_setting (
180 const PluginConfiguration &setting,
181 InstantiationFinishOptions instantiation_finish_options) const
182 {
183 const auto * descriptor = setting.descriptor ();
184 if (descriptor == nullptr)
185 {
186 throw std::invalid_argument ("Setting with valid descriptor required");
187 }
188
189 const auto protocol = descriptor->protocol_;
190 if (protocol == plugins::Protocol::ProtocolType::CLAP)
191 {
192 return get_builder<plugins::ClapPlugin> ()
193 .with_setting (setting)
194 .with_instantiation_finished_options (instantiation_finish_options)
195 .build ();
196 }
198 {
199 return get_builder<plugins::InternalPluginBase> ()
200 .with_setting (setting)
201 .with_instantiation_finished_options (instantiation_finish_options)
202 .build ();
203 }
204
205 return get_builder<plugins::JucePlugin> ()
206 .with_setting (setting)
207 .with_instantiation_finished_options (instantiation_finish_options)
208 .build ();
209 }
210
211// TODO
212#if 0
213 template <typename PluginT>
214 auto clone_new_object_identity (const PluginT &other) const
215 {
216 return plugin_registry_.clone_object (other, plugin_registry_);
217 }
218
219 template <typename PluginT>
220 auto clone_object_snapshot (const PluginT &other, QObject &owner) const
221 {
222 PluginT * new_obj{};
223
224 new_obj = utils::clone_qobject (
225 other, &owner, utils::ObjectCloneType::Snapshot, plugin_registry_);
226 return new_obj;
227 }
228#endif
229
230private:
231 CommonFactoryDependencies dependencies_;
232};
233}
Configuration for instantiating a plugin descriptor.
Q_SIGNAL void instantiationFinished(bool successful, const QString &error)
To be emitted by implementations when instantiation finished.
@ Internal
Dummy protocol for tests.
Abstract interface for a UUID-keyed object registry.
@ Snapshot
Creates a snapshot of the object with the same identity.
Definition icloneable.h:23