Zrythm v2.0.0-DEV
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
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
43 {
44 plugins::PluginRegistry &plugin_registry_;
45 dsp::ProcessorBase::ProcessorBaseDependencies processor_base_dependencies_;
46 plugins::JucePlugin::CreatePluginInstanceAsyncFunc
47 create_plugin_instance_async_func_;
48 std::function<units::sample_rate_t ()> sample_rate_provider_;
49 std::function<units::sample_u32_t ()> buffer_size_provider_;
50 plugins::PluginHostWindowFactory top_level_window_provider_;
51 };
52
53 PluginFactory () = delete;
54 PluginFactory (
55 CommonFactoryDependencies dependencies,
56 QObject * parent = nullptr)
57 : QObject (parent), dependencies_ (std::move (dependencies))
58 {
59 }
60
61private:
62 template <typename PluginT> class Builder
63 {
64 friend class PluginFactory;
65
66 private:
67 explicit Builder (CommonFactoryDependencies dependencies)
68 : dependencies_ (std::move (dependencies))
69 {
70 }
71
72 Builder &with_setting (const PluginConfiguration &setting)
73 {
74 setting_ = setting;
75 return *this;
76 }
77
78 Builder &with_instantiation_finished_options (
79 InstantiationFinishOptions instantiation_finish_options)
80 {
81 instantiation_finish_options_.emplace (instantiation_finish_options);
82 return *this;
83 }
84
85 public:
86 auto build ()
87 {
88 auto obj_ref = [&] () {
89 if constexpr (std::is_same_v<PluginT, plugins::ClapPlugin>)
90 {
91 return dependencies_.plugin_registry_.create_object<PluginT> (
92 dependencies_.processor_base_dependencies_,
93 dependencies_.top_level_window_provider_);
94 }
95 else if constexpr (
96 std::derived_from<PluginT, plugins::InternalPluginBase>)
97 {
98 return dependencies_.plugin_registry_.create_object<PluginT> (
99 dependencies_.processor_base_dependencies_);
100 }
101 else
102 {
103 return dependencies_.plugin_registry_.create_object<PluginT> (
104 dependencies_.processor_base_dependencies_,
105 dependencies_.create_plugin_instance_async_func_,
106 dependencies_.sample_rate_provider_,
107 dependencies_.buffer_size_provider_,
108 dependencies_.top_level_window_provider_);
109 }
110 }();
111
112 if (instantiation_finish_options_.has_value ())
113 {
114 // set instantiation finished handler and apply configuration, which
115 // will either fire the instantiation finished handler immediately or
116 // later (depending on the plugin format)
117 std::visit (
118 [&] (auto &&pl) {
119 const auto instantiation_finish_opts =
120 instantiation_finish_options_.value ();
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 obj_ref.get_object ());
129 }
130
131 if (setting_.has_value ())
132 {
133 obj_ref.template get_object_as<PluginT> ()->set_configuration (
134 *setting_);
135 }
136 else
137 {
138 throw std::logic_error ("PluginConfiguration required");
139 }
140
141 return obj_ref;
142 }
143
144 private:
145 CommonFactoryDependencies dependencies_;
146 utils::OptionalRef<const PluginConfiguration> setting_;
147 std::optional<InstantiationFinishOptions> instantiation_finish_options_;
148 };
149
150 template <typename PluginT> auto get_builder () const
151 {
152 auto builder = Builder<PluginT> (dependencies_);
153 return builder;
154 }
155
156public:
157 plugins::PluginUuidReference create_plugin_from_setting (
158 const PluginConfiguration &setting,
159 InstantiationFinishOptions instantiation_finish_options) const
160 {
161 const auto * descriptor = setting.descriptor ();
162 if (descriptor == nullptr)
163 {
164 throw std::invalid_argument ("Setting with valid descriptor required");
165 }
166
167 const auto protocol = descriptor->protocol_;
168 if (protocol == plugins::Protocol::ProtocolType::CLAP)
169 {
170 return get_builder<plugins::ClapPlugin> ()
171 .with_setting (setting)
172 .with_instantiation_finished_options (instantiation_finish_options)
173 .build ();
174 }
176 {
177 return get_builder<plugins::InternalPluginBase> ()
178 .with_setting (setting)
179 .with_instantiation_finished_options (instantiation_finish_options)
180 .build ();
181 }
182
183 return get_builder<plugins::JucePlugin> ()
184 .with_setting (setting)
185 .with_instantiation_finished_options (instantiation_finish_options)
186 .build ();
187 }
188
189// TODO
190#if 0
191 template <typename PluginT>
192 auto clone_new_object_identity (const PluginT &other) const
193 {
194 return plugin_registry_.clone_object (other, plugin_registry_);
195 }
196
197 template <typename PluginT>
198 auto clone_object_snapshot (const PluginT &other, QObject &owner) const
199 {
200 PluginT * new_obj{};
201
202 new_obj = utils::clone_qobject (
203 other, &owner, utils::ObjectCloneType::Snapshot, plugin_registry_);
204 return new_obj;
205 }
206#endif
207
208private:
209 CommonFactoryDependencies dependencies_;
210};
211}
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.
@ Snapshot
Creates a snapshot of the object with the same identity.
Definition icloneable.h:23