Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
track_processor.h
1// SPDX-FileCopyrightText: © 2019-2026 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include "dsp/port.h"
7#include "dsp/processor_base.h"
8#include "structure/arrangement/arranger_object_all.h"
9#include "structure/arrangement/timeline_data_provider.h"
10#include "structure/tracks/clip_playback_data_provider.h"
11#include "utils/icloneable.h"
12#include "utils/mpmc_queue.h"
13#include "utils/types.h"
14
15#include <farbot/RealtimeObject.hpp>
16
17namespace zrythm::structure::tracks
18{
25class TrackProcessor final : public QObject, public dsp::ProcessorBase
26{
27 Q_OBJECT
28 QML_ELEMENT
29 QML_UNCREATABLE ("")
30
31 using PortType = dsp::PortType;
32 using PortFlow = dsp::PortFlow;
33
34 struct TrackProcessorProcessingCaches
35 {
36 std::vector<dsp::AudioPort *> audio_ins_rt_;
37 std::vector<dsp::AudioPort *> audio_outs_rt_;
38 dsp::MidiPort * midi_in_rt_{};
39 dsp::MidiPort * midi_out_rt_{};
40 dsp::MidiPort * piano_roll_rt_{};
41 dsp::ProcessorParameter * mono_param_{};
42 dsp::ProcessorParameter * input_gain_{};
43 dsp::ProcessorParameter * output_gain_{};
44 dsp::ProcessorParameter * monitor_audio_{};
45 };
46
47public:
48 using StereoPortPair = std::pair<std::span<float>, std::span<float>>;
49 using ConstStereoPortPair =
50 std::pair<std::span<const float>, std::span<const float>>;
51
59 using FillEventsCallback = std::function<void (
60 const dsp::ITransport &transport,
61 const EngineProcessTimeInfo &time_nfo,
62 dsp::MidiEventVector * midi_events,
63 std::optional<StereoPortPair> stereo_ports)>;
64
71 using HandleRecordingCallback = std::function<void (
72 const EngineProcessTimeInfo &time_nfo,
73 const dsp::MidiEventVector * midi_events,
74 std::optional<ConstStereoPortPair> stereo_ports)>;
75
85 using AppendMidiInputsToOutputsFunc = std::function<void (
86 dsp::MidiEventVector &out_events,
87 const dsp::MidiEventVector &in_events,
88 const EngineProcessTimeInfo &time_nfo)>;
89
95 using TransformMidiInputsFunc = std::function<void (dsp::MidiEventVector &)>;
96
102 using EnabledProvider = std::function<bool ()>;
103
104 using TrackNameProvider = std::function<utils::Utf8String ()>;
105
106 using MidiEventProviderProcessFunc = std::function<void (
107 const EngineProcessTimeInfo &time_nfo,
108 dsp::MidiEventVector &output_buffer)>;
109
110 enum class ActiveMidiEventProviders : uint8_t
111 {
112 Timeline = 1 << 0,
113 ClipLauncher = 1 << 1,
114 PianoRoll = 1 << 2,
115 Recording = 1 << 3,
116 Custom = 1 << 4,
117 };
118
119 enum class ActiveAudioProviders : uint8_t
120 {
121 Timeline = 1 << 0,
122 ClipLauncher = 1 << 1,
123 Recording = 1 << 2,
124 Custom = 1 << 3,
125 };
126
135 const dsp::TempoMap &tempo_map,
136 PortType signal_type,
137 TrackNameProvider track_name_provider,
138 EnabledProvider enabled_provider,
139 bool generates_midi_events,
140 bool has_midi_cc,
141 bool is_audio_track,
142 ProcessorBaseDependencies dependencies,
143 std::optional<FillEventsCallback> fill_events_cb = std::nullopt,
144 std::optional<TransformMidiInputsFunc> transform_midi_inputs_func =
145 std::nullopt,
146 std::optional<AppendMidiInputsToOutputsFunc>
147 append_midi_inputs_to_outputs_func = std::nullopt,
148 QObject * parent = nullptr);
149
150 // note: this should eventually be passed from the constructor
151 void set_handle_recording_callback (HandleRecordingCallback handle_rec_cb)
152 {
153 handle_recording_cb_ = std::move (handle_rec_cb);
154 }
155
156 bool is_audio () const { return is_audio_; }
157
158 constexpr bool is_midi () const { return is_midi_; }
159
160 utils::Utf8String get_full_designation_for_port (const dsp::Port &port) const;
161
162 // ============================================================================
163 // ProcessorBase Interface
164 // ============================================================================
165
180 EngineProcessTimeInfo time_nfo,
181 const dsp::ITransport &transport,
182 const dsp::TempoMap &tempo_map) noexcept override;
183
184 void custom_prepare_for_processing (
185 const dsp::graph::GraphNode * node,
186 units::sample_rate_t sample_rate,
187 nframes_t max_block_length) override;
188
189 void custom_release_resources () override;
190
191 // ============================================================================
192
193 dsp::AudioPort &get_stereo_in_port () const
194 {
195 assert (is_audio ());
196 return *get_input_ports ().front ().get_object_as<dsp::AudioPort> ();
197 }
198 dsp::AudioPort &get_stereo_out_port () const
199 {
200 assert (is_audio ());
201 return *get_output_ports ().front ().get_object_as<dsp::AudioPort> ();
202 }
203
204 dsp::ProcessorParameter &get_mono_param () const
205 {
206 return *std::get<dsp::ProcessorParameter *> (
207 dependencies ().param_registry_.find_by_id_or_throw (*mono_id_));
208 }
209 dsp::ProcessorParameter &get_input_gain_param () const
210 {
211 return *std::get<dsp::ProcessorParameter *> (
212 dependencies ().param_registry_.find_by_id_or_throw (*input_gain_id_));
213 }
214 dsp::ProcessorParameter &get_output_gain_param () const
215 {
216 return *std::get<dsp::ProcessorParameter *> (
217 dependencies ().param_registry_.find_by_id_or_throw (*output_gain_id_));
218 }
219 dsp::ProcessorParameter &get_monitor_audio_param () const
220 {
221 return *std::get<dsp::ProcessorParameter *> (
222 dependencies ().param_registry_.find_by_id_or_throw (*monitor_audio_id_));
223 }
224
231 dsp::ProcessorParameter &
233 {
234 assert (has_midi_cc_);
235 return *std::get<dsp::ProcessorParameter *> (
236 dependencies ().param_registry_.find_by_id_or_throw (
237 midi_cc_caches_->midi_cc_ids_.at ((channel * 128) + control_no)));
238 }
239
249 {
250 assert (is_midi ());
251 return *get_input_ports ().front ().get_object_as<dsp::MidiPort> ();
252 }
253
258 {
259 assert (is_midi ());
260 return *get_output_ports ().front ().get_object_as<dsp::MidiPort> ();
261 }
262
270 {
271 return *get_input_ports ().at (1).get_object_as<dsp::MidiPort> ();
272 }
273
274 auto &timeline_audio_data_provider ()
275 {
276 return *timeline_audio_data_provider_;
277 }
278 auto &timeline_midi_data_provider () { return *timeline_midi_data_provider_; }
279
280 auto &clip_playback_data_provider () { return *clip_playback_data_provider_; }
281
291 ActiveMidiEventProviders event_providers,
292 bool active);
293
302 void
303 set_audio_providers_active (ActiveAudioProviders audio_providers, bool active);
304
308 void
309 set_custom_midi_event_provider (MidiEventProviderProcessFunc process_func);
310
321 const EngineProcessTimeInfo &time_nfo,
322 const dsp::ITransport &transport,
323 dsp::MidiEventVector &midi_events);
324
334 const EngineProcessTimeInfo &time_nfo,
335 const dsp::ITransport &transport,
336 StereoPortPair stereo_ports);
337
338private:
339 friend void to_json (nlohmann::json &j, const TrackProcessor &tp);
340 friend void from_json (const nlohmann::json &j, TrackProcessor &tp);
341
342 friend void init_from (
343 TrackProcessor &obj,
344 const TrackProcessor &other,
345 utils::ObjectCloneType clone_type);
346
351 void handle_recording (
352 const EngineProcessTimeInfo &time_nfo,
353 const dsp::ITransport &transport);
354
358 [[gnu::hot]] void add_events_from_midi_cc_control_ports (
359 dsp::MidiEventVector &events,
360 nframes_t local_offset);
361
365 void set_param_id_caches ();
366
367// TODO
368#if 0
369 void set_midi_mappings ();
370#endif
371
372private:
373 const bool is_midi_;
374 const bool is_audio_;
375 const bool has_piano_roll_port_;
376 const bool has_midi_cc_;
377
378 const EnabledProvider enabled_provider_;
379 const TrackNameProvider track_name_provider_;
380
381 std::optional<FillEventsCallback> fill_events_cb_;
382 std::optional<HandleRecordingCallback> handle_recording_cb_;
383 AppendMidiInputsToOutputsFunc append_midi_inputs_to_outputs_func_;
384 std::optional<TransformMidiInputsFunc> transform_midi_inputs_func_;
385
387 std::optional<dsp::ProcessorParameter::Uuid> mono_id_;
388
390 std::optional<dsp::ProcessorParameter::Uuid> input_gain_id_;
391
397 std::optional<dsp::ProcessorParameter::Uuid> output_gain_id_;
398
408 std::optional<dsp::ProcessorParameter::Uuid> monitor_audio_id_;
409
410#if 0
412 std::unique_ptr<engine::session::MidiMappings> cc_mappings_;
413#endif
414
418 struct MidiCcCaches
419 {
421 std::array<dsp::ProcessorParameter::Uuid, 16_zu * 128> midi_cc_ids_;
422
423 using SixteenPortUuidArray = std::array<dsp::ProcessorParameter::Uuid, 16>;
424
426 SixteenPortUuidArray pitch_bend_ids_;
427
437 SixteenPortUuidArray poly_key_pressure_ids_;
438
445 SixteenPortUuidArray channel_pressure_ids_;
446
453 MPMCQueue<dsp::ProcessorParameter *> updated_midi_automatable_ports_;
454 };
455
456 std::unique_ptr<MidiCcCaches> midi_cc_caches_;
457
458 // Processing caches
459 std::unique_ptr<TrackProcessorProcessingCaches> processing_caches_;
460
464 std::unique_ptr<arrangement::MidiTimelineDataProvider>
465 timeline_midi_data_provider_;
466
470 std::unique_ptr<arrangement::AudioTimelineDataProvider>
471 timeline_audio_data_provider_;
472
473 std::unique_ptr<ClipPlaybackDataProvider> clip_playback_data_provider_;
474
475 // TODO: piano roll, recording data providers
476
477 farbot::RealtimeObject<
478 std::optional<MidiEventProviderProcessFunc>,
479 farbot::RealtimeObjectOptions::nonRealtimeMutatable>
480 custom_midi_event_provider_;
481
482 std::atomic<ActiveMidiEventProviders> active_midi_event_providers_;
483 std::atomic<ActiveAudioProviders> active_audio_providers_;
484
485 static_assert (decltype (active_midi_event_providers_)::is_always_lock_free);
486};
487}
488
489ENUM_ENABLE_BITSET (
490 zrythm::structure::tracks::TrackProcessor::ActiveMidiEventProviders);
Multiple Producer Multiple Consumer lock-free queue.
Definition mpmc_queue.h:65
Audio port specifics.
Definition audio_port.h:25
Interface for transport.
Definition itransport.h:17
A lock-free thread-safe vector of MidiEvents.
Definition midi_event.h:78
MIDI port specifics.
Definition midi_port.h:22
A base class for ports used for connecting processors in the DSP graph.
Definition port.h:30
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:220
Represents a node in a DSP graph.
Definition graph_node.h:131
void fill_midi_events(const EngineProcessTimeInfo &time_nfo, const dsp::ITransport &transport, dsp::MidiEventVector &midi_events)
Wrapper for MIDI/instrument/chord tracks to fill in MidiEvents from the timeline data.
std::function< void( const EngineProcessTimeInfo &time_nfo, const dsp::MidiEventVector * midi_events, std::optional< ConstStereoPortPair > stereo_ports)> HandleRecordingCallback
Callback to record the given audio or MIDI data.
void fill_audio_events(const EngineProcessTimeInfo &time_nfo, const dsp::ITransport &transport, StereoPortPair stereo_ports)
Wrapper for audio tracks to fill in StereoPorts from the timeline data.
dsp::MidiPort & get_piano_roll_port() const
MIDI input for receiving MIDI signals from the piano roll (i.e., MIDI notes inside regions) or other ...
std::function< void( dsp::MidiEventVector &out_events, const dsp::MidiEventVector &in_events, const EngineProcessTimeInfo &time_nfo)> AppendMidiInputsToOutputsFunc
Custom logic to use when appending the MIDI input events to the output events.
dsp::MidiPort & get_midi_out_port() const
MIDI out port, if MIDI.
std::function< void( const dsp::ITransport &transport, const EngineProcessTimeInfo &time_nfo, dsp::MidiEventVector * midi_events, std::optional< StereoPortPair > stereo_ports)> FillEventsCallback
Function called during processing to fill events.
TrackProcessor(const dsp::TempoMap &tempo_map, PortType signal_type, TrackNameProvider track_name_provider, EnabledProvider enabled_provider, bool generates_midi_events, bool has_midi_cc, bool is_audio_track, ProcessorBaseDependencies dependencies, std::optional< FillEventsCallback > fill_events_cb=std::nullopt, std::optional< TransformMidiInputsFunc > transform_midi_inputs_func=std::nullopt, std::optional< AppendMidiInputsToOutputsFunc > append_midi_inputs_to_outputs_func=std::nullopt, QObject *parent=nullptr)
Creates a new track processor for the given track.
void set_audio_providers_active(ActiveAudioProviders audio_providers, bool active)
Used to enable or disable audio providers.
void custom_process_block(EngineProcessTimeInfo time_nfo, const dsp::ITransport &transport, const dsp::TempoMap &tempo_map) noexcept override
Process the TrackProcessor.
dsp::ProcessorParameter & get_midi_cc_param(midi_byte_t channel, midi_byte_t control_no)
std::function< void(dsp::MidiEventVector &)> TransformMidiInputsFunc
Function to transform the given MIDI inputs.
void set_midi_providers_active(ActiveMidiEventProviders event_providers, bool active)
Used to enable or disable MIDI event providers.
void set_custom_midi_event_provider(MidiEventProviderProcessFunc process_func)
Replaces the "Custom" MIDI event provider.
std::function< bool()> EnabledProvider
Function that returns if the track for this processor is enabled.
dsp::MidiPort & get_midi_in_port() const
MIDI in Port.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:38
uint32_t nframes_t
Frame count.
Definition types.h:58
uint8_t midi_byte_t
MIDI byte.
Definition types.h:55
Common struct to pass around during processing to avoid repeating the data in function arguments.
Definition types.h:133