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 "dsp/audio_callback.h"
7#include "dsp/audio_port.h"
8#include "dsp/graph_dispatcher.h"
9#include "dsp/hardware_audio_interface.h"
10#include "dsp/midi_panic_processor.h"
11#include "dsp/midi_port.h"
12#include "dsp/transport.h"
13#include "utils/concurrency.h"
14
15namespace zrythm::dsp
16{
17
21class AudioEngine : public QObject
22{
23 Q_OBJECT
24 Q_PROPERTY (int sampleRate READ sampleRate NOTIFY sampleRateChanged)
25 QML_ELEMENT
26 QML_UNCREATABLE ("")
27
28public:
29 enum class State : std::uint8_t
30 {
31 Uninitialized,
32 Initialized,
33 Active,
34 };
35
36 // TODO: check if pausing/resuming can be done with RAII
38 {
45 };
46
47public:
54 dsp::Transport &transport,
55 IHardwareAudioInterface &hw_interface,
56 dsp::DspGraphDispatcher &graph_dispatcher,
57 const dsp::TempoMap &tempo_map,
58 QObject * parent = nullptr);
59
63 ~AudioEngine () override;
64
65 // =========================================================
66 // QML interface
67 // =========================================================
68
69 Q_INVOKABLE int xRunCount () const { return load_measurer_.getXRunCount (); }
70 Q_INVOKABLE double loadPercentage () const
71 {
72 return load_measurer_.getLoadAsPercentage ();
73 }
74
75 int sampleRate () const { return get_sample_rate ().in (units::sample_rate); }
76
77 Q_SIGNAL void sampleRateChanged (int sampleRate);
78
79 // =========================================================
80
86 void wait_for_pause (EngineState &state, bool force_pause, bool with_fadeout);
87
88 void resume (const EngineState &state);
89
90 Q_INVOKABLE void activate ();
91 Q_INVOKABLE void deactivate ();
92
103 [[gnu::hot]] bool process_prepare (
104 dsp::Transport::TransportSnapshot &transport_snapshot,
105 units::sample_u32_t nframes,
107 [[clang::nonblocking]];
108
109 enum class ProcessReturnStatus : std::uint8_t
110 {
111 // Process completed normally
112 ProcessCompleted,
113 // Process skipped (e.g., when recalculating the graph)
114 ProcessSkipped,
115 // Process failed for some reason
116 ProcessFailed,
117 };
118
124 [[gnu::hot]] auto process (
125 const dsp::PlayheadProcessingGuard &playhead_guard,
126 units::sample_u32_t total_frames_to_process) noexcept [[clang::nonblocking]]
127 -> ProcessReturnStatus;
128
137 dsp::Transport::TransportSnapshot &transport_snapshot,
138 const dsp::PlayheadProcessingGuard &playhead_guard,
139 units::sample_u32_t roll_nframes,
140 units::sample_u32_t nframes) noexcept [[clang::nonblocking]];
141
142 auto &get_monitor_out_port () { return monitor_out_; }
143
144 auto * midi_panic_processor () const { return midi_panic_processor_.get (); }
145
149 void panic_all ();
150
151 bool activated () const { return state_ == State::Active; }
152 bool running () const { return run_.load (); }
153 void set_running (bool run) { run_.store (run); }
154 auto &graph_dispatcher () { return graph_dispatcher_; }
155
156 bool exporting () const { return exporting_; }
157 void set_exporting (bool exporting) { exporting_.store (exporting); }
158
159 auto get_processing_lock () [[clang::blocking]]
160 {
161 return SemaphoreRAII (process_lock_, true);
162 }
163
164 units::sample_u32_t get_block_length () const
165 {
166 return hw_interface_.get_block_length ();
167 }
168
169 units::sample_rate_t get_sample_rate () const
170 {
171 return hw_interface_.get_sample_rate ();
172 }
173
182 const std::function<void ()> &func,
183 bool recalculate_graph);
184
185private:
191 void activate_impl (bool activate);
192
193private:
194 dsp::PortRegistry port_registry_;
195 dsp::ProcessorParameterRegistry param_registry_{ port_registry_ };
196
197 dsp::Transport &transport_;
198
200 const dsp::TempoMap &tempo_map_;
201
203 dsp::DspGraphDispatcher &graph_dispatcher_;
204
205 IHardwareAudioInterface &hw_interface_;
206
212 std::atomic_uint64_t cycle_{ 0 };
213
226 dsp::AudioPort monitor_out_;
227
234 std::unique_ptr<dsp::MidiPort> midi_in_;
235
239 moodycamel::LightweightSemaphore process_lock_{ 1 };
240
242 std::atomic_bool run_{ false };
243
245 std::atomic_bool exporting_{ false };
246
247 juce::AudioProcessLoadMeasurer load_measurer_;
248
253 units::sample_u32_t remaining_latency_preroll_;
254
256 std::atomic_bool capture_cc_{ false };
257
259 std::array<midi_byte_t, 3> last_cc_captured_{};
260
261 std::atomic<State> state_{ State::Uninitialized };
262 static_assert (decltype (state_)::is_always_lock_free);
263
264 utils::QObjectUniquePtr<dsp::MidiPanicProcessor> midi_panic_processor_;
265
266 std::unique_ptr<AudioCallback> audio_callback_;
267
272 bool callback_running_{};
273};
274}
RAII wrapper class for std::binary_semaphore.
Definition concurrency.h:62
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.
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.
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.
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.
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:449
The Transport class represents the transport controls and state for an audio engine.
Definition transport.h:45
bool looping_
Transport loop.
Definition engine.h:44
bool running_
Engine running.
Definition engine.h:40