Zrythm v2.0.0-alpha.0+26.6dd8d70b0368
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
fader.h
1// SPDX-FileCopyrightText: © 2019-2022, 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <cstdint>
7
8#include "dsp/audio_port.h"
9#include "dsp/midi_port.h"
10#include "dsp/parameter.h"
11#include "dsp/processor_base.h"
12#include "utils/icloneable.h"
13#include "utils/types.h"
14
15namespace zrythm::structure::tracks
16{
20class Fader : public QObject, public dsp::ProcessorBase
21{
22 Q_OBJECT
23 Q_PROPERTY (
24 MidiFaderMode midiMode READ midiMode WRITE setMidiMode NOTIFY midiModeChanged)
25 Q_PROPERTY (zrythm::dsp::ProcessorParameter * gain READ gain CONSTANT)
26 Q_PROPERTY (zrythm::dsp::ProcessorParameter * balance READ balance CONSTANT)
27 Q_PROPERTY (zrythm::dsp::ProcessorParameter * mute READ mute CONSTANT)
28 Q_PROPERTY (zrythm::dsp::ProcessorParameter * solo READ solo CONSTANT)
29 Q_PROPERTY (zrythm::dsp::ProcessorParameter * listen READ listen CONSTANT)
30 Q_PROPERTY (
31 zrythm::dsp::ProcessorParameter * monoToggle READ monoToggle CONSTANT)
32 Q_PROPERTY (
33 zrythm::dsp::ProcessorParameter * swapPhaseToggle READ swapPhaseToggle
34 CONSTANT)
35 QML_ELEMENT
36 QML_UNCREATABLE ("")
37
38 struct FaderProcessingCaches
39 {
40 dsp::ProcessorParameter * amp_param_{};
41 dsp::ProcessorParameter * balance_param_{};
42 dsp::ProcessorParameter * mute_param_{};
43 dsp::ProcessorParameter * solo_param_{};
44 dsp::ProcessorParameter * listen_param_{};
45 dsp::ProcessorParameter * mono_compat_enabled_param_{};
46 dsp::ProcessorParameter * swap_phase_param_{};
47 std::vector<dsp::AudioPort *> audio_ins_rt_;
48 std::vector<dsp::AudioPort *> audio_outs_rt_;
49 dsp::MidiPort * midi_in_rt_{};
50 dsp::MidiPort * midi_out_rt_{};
51 };
52
53public:
54 enum class MidiFaderMode : basic_enum_base_type_t
55 {
58
61 };
62 Q_ENUM (MidiFaderMode)
63
64public:
74 using ShouldBeMutedCallback = std::function<bool (bool fader_solo_status)>;
75
80 using MuteGainCallback = std::function<float ()>;
81
88 using PreProcessAudioCallback = std::function<void (
89 std::pair<std::span<float>, std::span<float>> stereo_bufs,
90 const EngineProcessTimeInfo &time_nfo)>;
91
103 dsp::PortType signal_type,
104 bool hard_limit_output,
105 bool make_params_automatable,
106 std::optional<std::function<utils::Utf8String ()>> owner_name_provider,
107 ShouldBeMutedCallback should_be_muted_cb,
108 QObject * parent = nullptr);
109
110 // ============================================================================
111 // QML Interface
112 // ============================================================================
113
114 MidiFaderMode midiMode () const { return midi_mode_; }
115 void setMidiMode (MidiFaderMode mode)
116 {
117 if (midi_mode_ == mode)
118 return;
119
120 midi_mode_ = mode;
121 Q_EMIT midiModeChanged (mode);
122 }
123 Q_SIGNAL void midiModeChanged (MidiFaderMode mode);
124
125 zrythm::dsp::ProcessorParameter * gain () const
126 {
127 if (amp_id_.has_value ())
128 {
129 return &get_amp_param ();
130 }
131 return nullptr;
132 }
133 zrythm::dsp::ProcessorParameter * balance () const
134 {
135 if (balance_id_.has_value ())
136 {
137 return &get_balance_param ();
138 }
139 return nullptr;
140 }
141 zrythm::dsp::ProcessorParameter * mute () const
142 {
143 if (mute_id_.has_value ())
144 {
145 return &get_mute_param ();
146 }
147 return nullptr;
148 }
149 zrythm::dsp::ProcessorParameter * solo () const
150 {
151 if (solo_id_.has_value ())
152 {
153 return &get_solo_param ();
154 }
155 return nullptr;
156 }
157 zrythm::dsp::ProcessorParameter * listen () const
158 {
159 if (listen_id_.has_value ())
160 {
161 return &get_listen_param ();
162 }
163 return nullptr;
164 }
165 zrythm::dsp::ProcessorParameter * monoToggle () const
166 {
167 if (mono_compat_enabled_id_.has_value ())
168 {
169 return &get_mono_compat_enabled_param ();
170 }
171 return nullptr;
172 }
173 zrythm::dsp::ProcessorParameter * swapPhaseToggle () const
174 {
175 if (swap_phase_id_.has_value ())
176 {
177 return &get_swap_phase_param ();
178 }
179 return nullptr;
180 }
181
182 // ============================================================================
183
187 bool currently_muted () const
188 {
189 const auto &mute_param = get_mute_param ();
190 return mute_param.range ().is_toggled (mute_param.currentValue ());
191 }
192
196 [[gnu::hot]] bool currently_soloed () const
197 {
198 const auto &solo_param = get_solo_param ();
199 return solo_param.range ().is_toggled (solo_param.currentValue ());
200 }
201
205 bool currently_listened () const
206 {
207 const auto &listened_param = get_listen_param ();
208 return listened_param.range ().is_toggled (listened_param.currentValue ());
209 }
210
214 float get_current_amp () const
215 {
216 const auto &amp_param = get_amp_param ();
217 return amp_param.range ().convertFrom0To1 (amp_param.currentValue ());
218 }
219
220 std::string db_string_getter () const;
221
222 void set_mute_gain_callback (MuteGainCallback cb)
223 {
224 mute_gain_cb_ = std::move (cb);
225 }
226
227 void set_preprocess_audio_callback (PreProcessAudioCallback cb)
228 {
229 preprocess_audio_cb_ = std::move (cb);
230 }
231
232 // ============================================================================
233 // ProcessorBase Interface
234 // ============================================================================
235
236 void custom_prepare_for_processing (
237 sample_rate_t sample_rate,
238 nframes_t max_block_length) override;
239
240 void custom_release_resources () override;
241
242 [[gnu::hot]] void
243 custom_process_block (EngineProcessTimeInfo time_nfo) noexcept override;
244
245 // ============================================================================
246
247 bool is_audio () const { return signal_type_ == dsp::PortType::Audio; }
248 bool is_midi () const { return signal_type_ == dsp::PortType::Midi; }
249
250 bool hard_limiting_enabled () const { return hard_limit_output_; }
251
252 friend void
253 init_from (Fader &obj, const Fader &other, utils::ObjectCloneType clone_type);
254
255 dsp::ProcessorParameter &get_amp_param () const
256 {
257 return *std::get<dsp::ProcessorParameter *> (
258 dependencies ().param_registry_.find_by_id_or_throw (*amp_id_));
259 }
260 dsp::ProcessorParameter &get_balance_param () const
261 {
262 return *std::get<dsp::ProcessorParameter *> (
263 dependencies ().param_registry_.find_by_id_or_throw (*balance_id_));
264 }
265 dsp::ProcessorParameter &get_mute_param () const
266 {
267 return *std::get<dsp::ProcessorParameter *> (
268 dependencies ().param_registry_.find_by_id_or_throw (*mute_id_));
269 }
270 dsp::ProcessorParameter &get_solo_param () const
271 {
272 return *std::get<dsp::ProcessorParameter *> (
273 dependencies ().param_registry_.find_by_id_or_throw (*solo_id_));
274 }
275 dsp::ProcessorParameter &get_listen_param () const
276 {
277 return *std::get<dsp::ProcessorParameter *> (
278 dependencies ().param_registry_.find_by_id_or_throw (*listen_id_));
279 }
280 dsp::ProcessorParameter &get_mono_compat_enabled_param () const
281 {
282 return *std::get<dsp::ProcessorParameter *> (
283 dependencies ().param_registry_.find_by_id_or_throw (
284 *mono_compat_enabled_id_));
285 }
286 dsp::ProcessorParameter &get_swap_phase_param () const
287 {
288 return *std::get<dsp::ProcessorParameter *> (
289 dependencies ().param_registry_.find_by_id_or_throw (*swap_phase_id_));
290 }
291 dsp::AudioPort &get_stereo_in_port () const
292 {
293 if (!is_audio ())
294 {
295 throw std::runtime_error ("Not an audio fader");
296 }
297 return *get_input_ports ().at (0).get_object_as<dsp::AudioPort> ();
298 }
299 dsp::AudioPort &get_stereo_out_port () const
300 {
301 if (!is_audio ())
302 {
303 throw std::runtime_error ("Not an audio fader");
304 }
305 return *get_output_ports ().at (0).get_object_as<dsp::AudioPort> ();
306 }
307 dsp::MidiPort &get_midi_in_port () const
308 {
309 return *get_input_ports ().front ().get_object_as<dsp::MidiPort> ();
310 }
311 dsp::MidiPort &get_midi_out_port () const
312 {
313 return *get_output_ports ().front ().get_object_as<dsp::MidiPort> ();
314 }
315
316private:
317 static constexpr auto kMidiModeKey = "midiMode"sv;
318 friend void to_json (nlohmann::json &j, const Fader &fader)
319 {
320 to_json (j, static_cast<const dsp::ProcessorBase &> (fader));
321 j[kMidiModeKey] = fader.midi_mode_;
322 }
323 friend void from_json (const nlohmann::json &j, Fader &fader);
324
331 void init_param_caches ();
332
337 float calculate_target_gain_rt () const;
338
339 bool effectively_muted () const
340 {
341 return currently_muted () || should_be_muted_cb_ (currently_soloed ());
342 }
343
344 bool effectively_muted_rt () const
345 {
346 const auto currently_muted_rt = [this] () {
347 return processing_caches_->mute_param_->range ().is_toggled (
348 processing_caches_->mute_param_->currentValue ());
349 };
350 const auto currently_soloed_rt = [this] () {
351 return processing_caches_->solo_param_->range ().is_toggled (
352 processing_caches_->solo_param_->currentValue ());
353 };
354
355 return currently_muted_rt () || should_be_muted_cb_ (currently_soloed_rt ());
356 }
357
358private:
359 dsp::PortType signal_type_;
360
361 bool hard_limit_output_{};
362
370 float last_cc_volume_ = 0.f;
371
375 std::optional<dsp::ProcessorParameter::Uuid> amp_id_;
376
378 std::optional<dsp::ProcessorParameter::Uuid> balance_id_;
379
383 std::optional<dsp::ProcessorParameter::Uuid> mute_id_;
384
386 std::optional<dsp::ProcessorParameter::Uuid> solo_id_;
387
389 std::optional<dsp::ProcessorParameter::Uuid> listen_id_;
390
392 std::optional<dsp::ProcessorParameter::Uuid> mono_compat_enabled_id_;
393
395 std::optional<dsp::ProcessorParameter::Uuid> swap_phase_id_;
396
399
407 juce::SmoothedValue<float> current_gain_{ 0.f };
408
409 ShouldBeMutedCallback should_be_muted_cb_;
410
411 std::optional<PreProcessAudioCallback> preprocess_audio_cb_;
412
413 MuteGainCallback mute_gain_cb_ = [] () { return 0.f; };
414
415 // Processor caches
416 std::unique_ptr<FaderProcessingCaches> processing_caches_;
417};
418}
MIDI port specifics.
Definition midi_port.h:22
A base class for processors in the DSP graph.
Processor parameter that accepts automation and modulation sources and integrates with QML and the DS...
Definition parameter.h:225
bool currently_muted() const
Returns if the fader is muted.
Definition fader.h:187
bool currently_listened() const
Returns whether the fader is listened.
Definition fader.h:205
@ MIDI_FADER_MODE_CC_VOLUME
Send CC volume event on change TODO.
Definition fader.h:60
@ MIDI_FADER_MODE_VEL_MULTIPLIER
Multiply velocity of all MIDI note ons.
Definition fader.h:57
std::function< void( std::pair< std::span< float >, std::span< float > > stereo_bufs, const EngineProcessTimeInfo &time_nfo)> PreProcessAudioCallback
Callback to pre-process the incoming audio before applying gain, pan, etc.
Definition fader.h:88
std::function< bool(bool fader_solo_status)> ShouldBeMutedCallback
A callback to check if the fader should be muted based on various external factors (such as solo stat...
Definition fader.h:74
std::function< float()> MuteGainCallback
Callback to get the gain that should be used if the fader is effectively muted.
Definition fader.h:80
float get_current_amp() const
Gets the fader amplitude (not db)
Definition fader.h:214
bool currently_soloed() const
Returns if the track is soloed.
Definition fader.h:196
void custom_process_block(EngineProcessTimeInfo time_nfo) noexcept override
Custom processor logic after processing all owned parameters.
Fader(dsp::ProcessorBase::ProcessorBaseDependencies dependencies, dsp::PortType signal_type, bool hard_limit_output, bool make_params_automatable, std::optional< std::function< utils::Utf8String()> > owner_name_provider, ShouldBeMutedCallback should_be_muted_cb, QObject *parent=nullptr)
Creates a new fader.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:38
uint32_t sample_rate_t
Sample rate.
Definition types.h:61
uint32_t nframes_t
Frame count.
Definition types.h:58
@ Fader
0 to 1, suitable for drawing.
Definition types.h:128
Common struct to pass around during processing to avoid repeating the data in function arguments.
Definition types.h:136