Zrythm v2.0.0-alpha.1
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/hardware_midi_interface.h"
14#include "dsp/midi_input_processor.h"
15#include "dsp/midi_panic_processor.h"
16#include "dsp/midi_port.h"
17#include "dsp/transport.h"
18#include "utils/concurrency.h"
19#include "utils/object_registry.h"
20
21namespace zrythm::dsp
22{
23
27class AudioEngine : public QObject
28{
29 Q_OBJECT
30 Q_PROPERTY (int sampleRate READ sampleRate NOTIFY sampleRateChanged)
31 Q_PROPERTY (int blockLength READ blockLength NOTIFY blockLengthChanged)
32 QML_ELEMENT
33 QML_UNCREATABLE ("")
34
35public:
36 enum class State : std::uint8_t
37 {
38 Uninitialized,
39 Initialized,
40 Active,
41 };
42
43 // TODO: check if pausing/resuming can be done with RAII
45 {
52 };
53
54public:
61 dsp::Transport &transport,
62 IHardwareAudioInterface &hw_interface,
63 IHardwareMidiInterface &midi_interface,
64 dsp::DspGraphDispatcher &graph_dispatcher,
65 const dsp::TempoMap &tempo_map,
66 QObject * parent = nullptr);
67
71 ~AudioEngine () override;
72
73 // =========================================================
74 // QML interface
75 // =========================================================
76
77 Q_INVOKABLE int xRunCount () const { return load_measurer_.getXRunCount (); }
78 Q_INVOKABLE double loadPercentage () const
79 {
80 return load_measurer_.getLoadAsPercentage ();
81 }
82
86 int sampleRate () const;
90 int blockLength () const;
91
92 Q_SIGNAL void sampleRateChanged (int sampleRate);
93 Q_SIGNAL void blockLengthChanged (int blockLength);
94
95 // =========================================================
96
100 units::sample_rate_t sample_rate () const;
104 units::sample_u32_t block_length () const;
109
115 void wait_for_pause (EngineState &state, bool force_pause, bool with_fadeout);
116
117 void resume (const EngineState &state);
118
124 Q_INVOKABLE void activate ();
125
131 Q_INVOKABLE void deactivate ();
132
143 [[gnu::hot]] bool process_prepare (
144 dsp::Transport::TransportSnapshot &transport_snapshot,
145 units::sample_u32_t nframes,
147 [[clang::nonblocking]];
148
149 enum class ProcessReturnStatus : std::uint8_t
150 {
151 // Process completed normally
152 ProcessCompleted,
153 // Process skipped (e.g., when recalculating the graph)
154 ProcessSkipped,
155 // Process failed for some reason
156 ProcessFailed,
157 };
158
164 [[gnu::hot]] auto process (
165 const dsp::PlayheadProcessingGuard &playhead_guard,
166 units::sample_u32_t total_frames_to_process) noexcept [[clang::nonblocking]]
167 -> ProcessReturnStatus;
168
177 dsp::Transport::TransportSnapshot &transport_snapshot,
178 const dsp::PlayheadProcessingGuard &playhead_guard,
179 units::sample_u32_t roll_nframes,
180 units::sample_u32_t nframes) noexcept [[clang::nonblocking]];
181
182 auto &get_monitor_out_port () { return monitor_out_; }
183
184 auto * midi_panic_processor () const { return midi_panic_processor_.get (); }
185
190 auto * audio_input_processor () const
191 {
192 return audio_input_processor_.get ();
193 }
194
195 const auto &midi_input_processors () const { return midi_input_processors_; }
196
200 void panic_all ();
201
202 bool activated () const { return state_ == State::Active; }
203 bool running () const { return run_.load (); }
204 void set_running (bool run) { run_.store (run); }
205 auto &graph_dispatcher () { return graph_dispatcher_; }
206
207 bool exporting () const { return exporting_; }
208 void set_exporting (bool exporting) { exporting_.store (exporting); }
209
210 auto get_processing_lock () [[clang::blocking]]
211 {
212 return SemaphoreRAII (process_lock_, true);
213 }
214
223 const std::function<void ()> &func,
224 bool recalculate_graph);
225
226private:
232 void activate_impl (bool activate);
233
242 void update_midi_processors (
243 const IHardwareMidiInterface::BufferMap &active_buffers);
244
245private:
246 utils::ObjectRegistry local_registry_;
247
248 dsp::Transport &transport_;
249
251 const dsp::TempoMap &tempo_map_;
252
254 dsp::DspGraphDispatcher &graph_dispatcher_;
255
256 IHardwareAudioInterface &hw_interface_;
257 IHardwareMidiInterface &midi_interface_;
258
264 std::atomic_uint64_t cycle_{ 0 };
265
278 dsp::AudioPort monitor_out_;
279
286 std::unique_ptr<dsp::MidiPort> midi_in_;
287
291 moodycamel::LightweightSemaphore process_lock_{ 1 };
292
294 std::atomic_bool run_{ false };
295
297 std::atomic_bool exporting_{ false };
298
299 juce::AudioProcessLoadMeasurer load_measurer_;
300
305 units::sample_u32_t remaining_latency_preroll_;
306
308 std::atomic_bool capture_cc_{ false };
309
311 std::array<midi_byte_t, 3> last_cc_captured_{};
312
313 std::atomic<State> state_{ State::Uninitialized };
314 static_assert (decltype (state_)::is_always_lock_free);
315
316 std::optional<dsp::AudioDeviceInfo> cached_device_info_;
317
318 utils::QObjectUniquePtr<dsp::MidiPanicProcessor> midi_panic_processor_;
319
320 std::unique_ptr<AudioCallback> audio_callback_;
321
322 utils::QObjectUniquePtr<AudioInputProcessor> audio_input_processor_;
323
324 std::map<utils::Utf8String, utils::QObjectUniquePtr<MidiInputProcessor>>
325 midi_input_processors_;
326
334 std::span<const float * const> current_hw_input_;
335
340 bool audio_callback_active_{};
341
348 units::precise_second_t block_start_time_;
349};
350}
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:190
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)
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).
AudioEngine(dsp::Transport &transport, IHardwareAudioInterface &hw_interface, IHardwareMidiInterface &midi_interface, dsp::DspGraphDispatcher &graph_dispatcher, const dsp::TempoMap &tempo_map, QObject *parent=nullptr)
Create a new audio engine.
void panic_all()
Queues MIDI note off to event queues.
Audio port specifics.
Definition audio_port.h:25
The DspGraphDispatcher class manages the processing graph for the audio engine.
Abstraction for hardware audio interface.
Abstraction for hardware MIDI interface.
RAII helper for Playhead audio processing block.
Definition playhead.h:238
The Transport class represents the transport controls and state for an audio engine.
Definition transport.h:45
Concrete IObjectRegistry with QObject parent-child ownership and reference counting.
Lightweight UTF-8 string wrapper with safe conversions.
Definition utf8_string.h:37
bool looping_
Transport loop.
Definition engine.h:51
bool running_
Engine running.
Definition engine.h:47