Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
juce_plugin.h
1// SPDX-FileCopyrightText: © 2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include "plugins/plugin.h"
7
8#include <juce_wrapper.h>
9
10namespace zrythm::plugins
11{
12
19class JucePlugin : public Plugin
20{
21 Q_OBJECT
22 QML_ELEMENT
23 QML_UNCREATABLE ("")
24
25public:
26 using CreatePluginInstanceAsyncFunc = std::function<void (
27 const juce::PluginDescription &,
28 double,
29 int,
30 juce::AudioPluginFormat::AudioPluginFormat::PluginCreationCallback)>;
31
44 StateDirectoryParentPathProvider state_path_provider,
45 CreatePluginInstanceAsyncFunc create_plugin_instance_async_func,
46 std::function<sample_rate_t ()> sample_rate_provider,
47 std::function<nframes_t ()> buffer_size_provider,
48 PluginHostWindowFactory top_level_window_provider,
49 QObject * parent = nullptr);
50
51 ~JucePlugin () override;
52
53 // ============================================================================
54 // Plugin Interface Implementation
55 // ============================================================================
56
57 void save_state (std::optional<fs::path> abs_state_dir) override;
58 void load_state (std::optional<fs::path> abs_state_dir) override;
59
61
62protected:
63 void prepare_for_processing_impl (
64 sample_rate_t sample_rate,
65 nframes_t max_block_length) override;
66
67 void process_impl (EngineProcessTimeInfo time_info) noexcept override;
68
69private Q_SLOTS:
73 void on_configuration_changed ();
74
78 void on_ui_visibility_changed ();
79
80private:
86 void initialize_juce_plugin_async ();
87
91 void create_ports_from_juce_plugin ();
92
96 void create_parameters_from_juce_plugin ();
97
101 void update_parameter_values ();
102
106 void sync_parameters_to_juce ();
107
111 void show_editor ();
112
116 void hide_editor ();
117
118 static constexpr auto kStateKey = "state"sv;
119 friend void to_json (nlohmann::json &j, const JucePlugin &p)
120 {
121 to_json (j, static_cast<const Plugin &> (p));
122 if (p.juce_plugin_)
123 {
124 juce::MemoryBlock state_data;
125 p.juce_plugin_->getStateInformation (state_data);
126 auto encoded = state_data.toBase64Encoding ();
127 j[kStateKey] = encoded.toStdString ();
128 }
129 }
130 friend void from_json (const nlohmann::json &j, JucePlugin &p)
131 {
132 // Note that state must be deserialized first, because the Plugin
133 // deserialization may cause an instantiation
134 std::string state_str;
135 j[kStateKey].get_to (state_str);
136 p.state_to_apply_.emplace ();
137 p.state_to_apply_->fromBase64Encoding (state_str);
138
139 // Now that we have the state, continue deserializing base Plugin...
140 from_json (j, static_cast<Plugin &> (p));
141 }
142
143private:
144 // ============================================================================
145 // JUCE-specific members
146 // ============================================================================
147
148 CreatePluginInstanceAsyncFunc create_plugin_instance_async_func_;
149
150 std::unique_ptr<juce::AudioPluginInstance> juce_plugin_;
151 std::unique_ptr<juce::AudioProcessorEditor> editor_;
152 std::unique_ptr<plugins::IPluginHostWindow> top_level_window_;
153
154 std::function<sample_rate_t ()> sample_rate_provider_;
155 std::function<nframes_t ()> buffer_size_provider_;
156
157 juce::AudioBuffer<float> juce_audio_buffer_;
158 juce::MidiBuffer juce_midi_buffer_;
159
160 class JuceParamListener : public juce::AudioProcessorParameter::Listener
161 {
162 public:
163 JuceParamListener (dsp::ProcessorParameter &zrythm_param)
164 : zrythm_param_ (zrythm_param)
165 {
166 }
167
168 void parameterValueChanged (int parameterIndex, float newValue)
169 [[clang::blocking]] override
170 {
171 // FIXME: this may get called from the audio thread, according to the
172 // docs
173 // The logic here is not realtime-safe, and currently no test hits this
174 z_debug (
175 "{}: Parameter on JUCE side changed to {}",
176 zrythm_param_.get_node_name (), newValue);
177 zrythm_param_.setBaseValue (newValue);
178 }
179 void parameterGestureChanged (int parameterIndex, bool gestureIsStarting)
180 [[clang::blocking]] override
181 {
182 // FIXME: this may get called from the audio thread, according to the
183 // docs
184 // The logic here is not realtime-safe, and currently no test hits this
185 }
186
187 private:
188 dsp::ProcessorParameter &zrythm_param_;
189 };
190
191 // Parameter mapping between JUCE and Zrythm
192 struct ParameterMapping
193 {
194 juce::AudioProcessorParameter * juce_param;
195 dsp::ProcessorParameter * zrythm_param;
196 int juce_param_index;
197 std::unique_ptr<JuceParamListener> juce_param_listener;
198 };
199
200 std::vector<ParameterMapping> parameter_mappings_;
201
202 // Audio/MIDI buffer management
203 std::vector<float *> input_channels_;
204 std::vector<float *> output_channels_;
205
206 bool juce_initialized_ = false;
207 bool editor_visible_ = false;
208 bool plugin_loading_ = false;
209
210 // Optional state to apply on instantiation (this is mainly used as a
211 // temporary space to store the restored state temporarily until the plugin is
212 // instantiated).
213 std::optional<juce::MemoryBlock> state_to_apply_;
214
215 PluginHostWindowFactory top_level_window_provider_;
216};
217
218} // namespace zrythm::plugins
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
Definition parameter.h:225
void save_state(std::optional< fs::path > abs_state_dir) override
Saves the state inside the standard state directory.
JucePlugin(dsp::ProcessorBase::ProcessorBaseDependencies dependencies, StateDirectoryParentPathProvider state_path_provider, CreatePluginInstanceAsyncFunc create_plugin_instance_async_func, std::function< sample_rate_t()> sample_rate_provider, std::function< nframes_t()> buffer_size_provider, PluginHostWindowFactory top_level_window_provider, QObject *parent=nullptr)
Constructor for JucePlugin.
void load_state(std::optional< fs::path > abs_state_dir) override
Load the state from the default directory or from abs_state_dir if given.
nframes_t get_single_playback_latency() const override
Returns the latency of only the given processable, without adding the previous/next latencies.
Plugin(ProcessorBaseDependencies dependencies, StateDirectoryParentPathProvider state_path_provider, QObject *parent)
Creates/initializes a plugin and its internal plugin (LV2, etc.) using the given setting.
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
uint32_t sample_rate_t
Sample rate.
Definition types.h:61
uint32_t nframes_t
Frame count.
Definition types.h:58
Common struct to pass around during processing to avoid repeating the data in function arguments.
Definition types.h:136