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