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 void set_monitor_out_source (dsp::AudioPort &port)
183 {
184 assert (!audio_callback_active_);
185 monitor_out_source_ = &port;
186 }
187
188 auto * midi_panic_processor () const { return midi_panic_processor_.get (); }
189
194 auto * audio_input_processor () const
195 {
196 return audio_input_processor_.get ();
197 }
198
199 const auto &midi_input_processors () const { return midi_input_processors_; }
200
204 void panic_all ();
205
206 bool activated () const { return state_ == State::Active; }
207 bool running () const { return run_.load (); }
208 void set_running (bool run) { run_.store (run); }
209 auto &graph_dispatcher () { return graph_dispatcher_; }
210
211 bool exporting () const { return exporting_; }
212 void set_exporting (bool exporting) { exporting_.store (exporting); }
213
214 auto get_processing_lock () [[clang::blocking]]
215 {
216 return SemaphoreRAII (process_lock_, true);
217 }
218
227 const std::function<void ()> &func,
228 bool recalculate_graph);
229
230private:
236 void activate_impl (bool activate);
237
246 void update_midi_processors (
247 const IHardwareMidiInterface::BufferMap &active_buffers);
248
249private:
250 utils::ObjectRegistry local_registry_;
251
252 dsp::Transport &transport_;
253
255 const dsp::TempoMap &tempo_map_;
256
258 dsp::DspGraphDispatcher &graph_dispatcher_;
259
260 IHardwareAudioInterface &hw_interface_;
261 IHardwareMidiInterface &midi_interface_;
262
268 std::atomic_uint64_t cycle_{ 0 };
269
283 dsp::AudioPort * monitor_out_source_ = nullptr;
284
291 std::unique_ptr<dsp::MidiPort> midi_in_;
292
296 moodycamel::LightweightSemaphore process_lock_{ 1 };
297
299 std::atomic_bool run_{ false };
300
302 std::atomic_bool exporting_{ false };
303
304 juce::AudioProcessLoadMeasurer load_measurer_;
305
310 units::sample_u32_t remaining_latency_preroll_;
311
313 std::atomic_bool capture_cc_{ false };
314
316 std::array<midi_byte_t, 3> last_cc_captured_{};
317
318 std::atomic<State> state_{ State::Uninitialized };
319 static_assert (decltype (state_)::is_always_lock_free);
320
321 std::optional<dsp::AudioDeviceInfo> cached_device_info_;
322
323 utils::QObjectUniquePtr<dsp::MidiPanicProcessor> midi_panic_processor_;
324
325 std::unique_ptr<AudioCallback> audio_callback_;
326
327 utils::QObjectUniquePtr<AudioInputProcessor> audio_input_processor_;
328
329 std::map<utils::Utf8String, utils::QObjectUniquePtr<MidiInputProcessor>>
330 midi_input_processors_;
331
339 std::span<const float * const> current_hw_input_;
340
345 bool audio_callback_active_{};
346
353 units::precise_second_t block_start_time_;
354};
355}
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:194
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.
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:241
The Transport class represents the transport controls and state for an audio engine.
Definition transport.h:48
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