Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
engine.h
1// SPDX-FileCopyrightText: © 2018-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <optional>
7
8#include "dsp/audio_callback.h"
9#include "dsp/audio_input_processor.h"
10#include "dsp/audio_port.h"
11#include "dsp/graph_dispatcher.h"
12#include "dsp/hardware_audio_interface.h"
13#include "dsp/midi_panic_processor.h"
14#include "dsp/midi_port.h"
15#include "dsp/transport.h"
16#include "utils/concurrency.h"
17
18namespace zrythm::dsp
19{
20
24class AudioEngine : public QObject
25{
26 Q_OBJECT
27 Q_PROPERTY (int sampleRate READ sampleRate NOTIFY sampleRateChanged)
28 Q_PROPERTY (int blockLength READ blockLength NOTIFY blockLengthChanged)
29 QML_ELEMENT
30 QML_UNCREATABLE ("")
31
32public:
33 enum class State : std::uint8_t
34 {
35 Uninitialized,
36 Initialized,
37 Active,
38 };
39
40 // TODO: check if pausing/resuming can be done with RAII
42 {
49 };
50
51public:
58 dsp::Transport &transport,
59 IHardwareAudioInterface &hw_interface,
60 dsp::DspGraphDispatcher &graph_dispatcher,
61 const dsp::TempoMap &tempo_map,
62 QObject * parent = nullptr);
63
67 ~AudioEngine () override;
68
69 // =========================================================
70 // QML interface
71 // =========================================================
72
73 Q_INVOKABLE int xRunCount () const { return load_measurer_.getXRunCount (); }
74 Q_INVOKABLE double loadPercentage () const
75 {
76 return load_measurer_.getLoadAsPercentage ();
77 }
78
82 int sampleRate () const;
86 int blockLength () const;
87
88 Q_SIGNAL void sampleRateChanged (int sampleRate);
89 Q_SIGNAL void blockLengthChanged (int blockLength);
90
91 // =========================================================
92
96 units::sample_rate_t sample_rate () const;
100 units::sample_u32_t block_length () const;
105
111 void wait_for_pause (EngineState &state, bool force_pause, bool with_fadeout);
112
113 void resume (const EngineState &state);
114
120 Q_INVOKABLE void activate ();
121
127 Q_INVOKABLE void deactivate ();
128
139 [[gnu::hot]] bool process_prepare (
140 dsp::Transport::TransportSnapshot &transport_snapshot,
141 units::sample_u32_t nframes,
143 [[clang::nonblocking]];
144
145 enum class ProcessReturnStatus : std::uint8_t
146 {
147 // Process completed normally
148 ProcessCompleted,
149 // Process skipped (e.g., when recalculating the graph)
150 ProcessSkipped,
151 // Process failed for some reason
152 ProcessFailed,
153 };
154
160 [[gnu::hot]] auto process (
161 const dsp::PlayheadProcessingGuard &playhead_guard,
162 units::sample_u32_t total_frames_to_process) noexcept [[clang::nonblocking]]
163 -> ProcessReturnStatus;
164
173 dsp::Transport::TransportSnapshot &transport_snapshot,
174 const dsp::PlayheadProcessingGuard &playhead_guard,
175 units::sample_u32_t roll_nframes,
176 units::sample_u32_t nframes) noexcept [[clang::nonblocking]];
177
178 auto &get_monitor_out_port () { return monitor_out_; }
179
180 auto * midi_panic_processor () const { return midi_panic_processor_.get (); }
181
186 auto * audio_input_processor () const
187 {
188 return audio_input_processor_.get ();
189 }
190
194 void panic_all ();
195
196 bool activated () const { return state_ == State::Active; }
197 bool running () const { return run_.load (); }
198 void set_running (bool run) { run_.store (run); }
199 auto &graph_dispatcher () { return graph_dispatcher_; }
200
201 bool exporting () const { return exporting_; }
202 void set_exporting (bool exporting) { exporting_.store (exporting); }
203
204 auto get_processing_lock () [[clang::blocking]]
205 {
206 return SemaphoreRAII (process_lock_, true);
207 }
208
217 const std::function<void ()> &func,
218 bool recalculate_graph);
219
220private:
226 void activate_impl (bool activate);
227
228private:
229 dsp::PortRegistry port_registry_;
230 dsp::ProcessorParameterRegistry param_registry_{ port_registry_ };
231
232 dsp::Transport &transport_;
233
235 const dsp::TempoMap &tempo_map_;
236
238 dsp::DspGraphDispatcher &graph_dispatcher_;
239
240 IHardwareAudioInterface &hw_interface_;
241
247 std::atomic_uint64_t cycle_{ 0 };
248
261 dsp::AudioPort monitor_out_;
262
269 std::unique_ptr<dsp::MidiPort> midi_in_;
270
274 moodycamel::LightweightSemaphore process_lock_{ 1 };
275
277 std::atomic_bool run_{ false };
278
280 std::atomic_bool exporting_{ false };
281
282 juce::AudioProcessLoadMeasurer load_measurer_;
283
288 units::sample_u32_t remaining_latency_preroll_;
289
291 std::atomic_bool capture_cc_{ false };
292
294 std::array<midi_byte_t, 3> last_cc_captured_{};
295
296 std::atomic<State> state_{ State::Uninitialized };
297 static_assert (decltype (state_)::is_always_lock_free);
298
299 std::optional<dsp::AudioDeviceInfo> cached_device_info_;
300
301 utils::QObjectUniquePtr<dsp::MidiPanicProcessor> midi_panic_processor_;
302
303 std::unique_ptr<AudioCallback> audio_callback_;
304
305 utils::QObjectUniquePtr<AudioInputProcessor> audio_input_processor_;
306
314 std::span<const float * const> current_hw_input_;
315
320 bool callback_running_{};
321};
322}
RAII wrapper class for std::binary_semaphore.
Definition concurrency.h:62
Q_INVOKABLE void deactivate()
Deactivates the engine if active.
auto process(const dsp::PlayheadProcessingGuard &playhead_guard, units::sample_u32_t total_frames_to_process) noexcept -> ProcessReturnStatus
Processes current cycle.
~AudioEngine() override
Closes any connections and free's data.
void advance_playhead_after_processing(dsp::Transport::TransportSnapshot &transport_snapshot, const dsp::PlayheadProcessingGuard &playhead_guard, units::sample_u32_t roll_nframes, units::sample_u32_t nframes) noexcept
Advances the playhead if transport is rolling.
auto * audio_input_processor() const
Returns the audio input processor, or nullptr if no audio device has started.
Definition engine.h:186
void execute_function_with_paused_processing_synchronously(const std::function< void()> &func, bool recalculate_graph)
Executes the given function after pausing processing and then resumes processing.
int sampleRate() const
Current sample rate from the hardware interface (QML-friendly).
units::sample_u32_t block_length() const
Current block length as a unit type.
utils::Utf8String device_name() const
Current audio device name from the hardware interface.
bool process_prepare(dsp::Transport::TransportSnapshot &transport_snapshot, units::sample_u32_t nframes, SemaphoreRAII< moodycamel::LightweightSemaphore > &sem) noexcept
To be called by each implementation to prepare the structures before processing.
Q_INVOKABLE void activate()
Activate the engine if not already active.
void wait_for_pause(EngineState &state, bool force_pause, bool with_fadeout)
AudioEngine(dsp::Transport &transport, IHardwareAudioInterface &hw_interface, dsp::DspGraphDispatcher &graph_dispatcher, const dsp::TempoMap &tempo_map, QObject *parent=nullptr)
Create a new audio engine.
units::sample_rate_t sample_rate() const
Current sample rate as a unit type.
int blockLength() const
Current block length from the hardware interface (QML-friendly).
void panic_all()
Queues MIDI note off to event queues.
Audio port specifics.
Definition audio_port.h:26
The DspGraphDispatcher class manages the processing graph for the audio engine.
Abstraction for hardware audio interface.
RAII helper for Playhead audio processing block.
Definition playhead.h:238
Wrapper over a Uuid registry that provides (slow) lookup by unique ID.
Definition parameter.h:542
The Transport class represents the transport controls and state for an audio engine.
Definition transport.h:45
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37
bool looping_
Transport loop.
Definition engine.h:48
bool running_
Engine running.
Definition engine.h:44