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/midi_panic_processor.h"
10#include "dsp/midi_port.h"
11#include "dsp/transport.h"
12#include "utils/concurrency.h"
13#include "utils/types.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
36public:
43 dsp::Transport &transport,
44 std::shared_ptr<juce::AudioDeviceManager> device_mgr,
45 dsp::DspGraphDispatcher &graph_dispatcher,
46 QObject * parent = nullptr);
47
51 ~AudioEngine () override;
52
53 // =========================================================
54 // QML interface
55 // =========================================================
56
57 Q_INVOKABLE int xRunCount () const { return load_measurer_.getXRunCount (); }
58 Q_INVOKABLE double loadPercentage () const
59 {
60 return load_measurer_.getLoadAsPercentage ();
61 }
62
63 int sampleRate () const { return get_sample_rate ().in (units::sample_rate); }
64
65 Q_SIGNAL void sampleRateChanged (int sampleRate);
66
67 // =========================================================
68
74 void wait_for_pause (EngineState &state, bool force_pause, bool with_fadeout);
75
76 void resume (const EngineState &state);
77
78 void activate ();
79 void deactivate ();
80
91 [[gnu::hot]] bool process_prepare (
92 dsp::Transport::TransportSnapshot &transport_snapshot,
93 nframes_t nframes,
95 [[clang::nonblocking]];
96
97 enum class ProcessReturnStatus : std::uint8_t
98 {
99 // Process completed normally
100 ProcessCompleted,
101 // Process skipped (e.g., when recalculating the graph)
102 ProcessSkipped,
103 // Process failed for some reason
104 ProcessFailed,
105 };
106
112 [[gnu::hot]] auto process (
113 const dsp::PlayheadProcessingGuard &playhead_guard,
114 nframes_t total_frames_to_process) noexcept [[clang::nonblocking]]
115 -> ProcessReturnStatus;
116
125 dsp::Transport::TransportSnapshot &transport_snapshot,
126 const dsp::PlayheadProcessingGuard &playhead_guard,
127 nframes_t roll_nframes,
128 nframes_t nframes) noexcept [[clang::nonblocking]];
129
130 auto &get_monitor_out_port () { return monitor_out_; }
131
132 auto * midi_panic_processor () const { return midi_panic_processor_.get (); }
133
137 void panic_all ();
138
139 auto get_device_manager () const { return device_manager_; }
140
141 bool activated () const { return state_ == State::Active; }
142 bool running () const { return run_.load (); }
143 void set_running (bool run) { run_.store (run); }
144 auto &graph_dispatcher () { return graph_dispatcher_; }
145
146 bool exporting () const { return exporting_; }
147 void set_exporting (bool exporting) { exporting_.store (exporting); }
148
149 auto get_processing_lock () [[clang::blocking]]
150 {
151 return SemaphoreRAII (process_lock_, true);
152 }
153
154 nframes_t get_block_length () const
155 {
156 auto * dev = device_manager_->getCurrentAudioDevice ();
157 assert (dev != nullptr);
158 return dev->getCurrentBufferSizeSamples ();
159 }
160
161 units::sample_rate_t get_sample_rate () const
162 {
163 auto * dev = device_manager_->getCurrentAudioDevice ();
164 assert (dev != nullptr);
165 return units::sample_rate (static_cast<int> (dev->getCurrentSampleRate ()));
166 }
167
176 const std::function<void ()> &func,
177 bool recalculate_graph);
178
179private:
185 void activate_impl (bool activate);
186
187private:
188 dsp::PortRegistry port_registry_;
189 dsp::ProcessorParameterRegistry param_registry_{ port_registry_ };
190
191 dsp::Transport &transport_;
192
194 dsp::DspGraphDispatcher &graph_dispatcher_;
195
196 std::shared_ptr<juce::AudioDeviceManager> device_manager_;
197
203 std::atomic_uint64_t cycle_{ 0 };
204
217 dsp::AudioPort monitor_out_;
218
225 std::unique_ptr<dsp::MidiPort> midi_in_;
226
230 moodycamel::LightweightSemaphore process_lock_{ 1 };
231
233 std::atomic_bool run_{ false };
234
236 std::atomic_bool exporting_{ false };
237
238 juce::AudioProcessLoadMeasurer load_measurer_;
239
244 nframes_t remaining_latency_preroll_{};
245
247 std::atomic_bool capture_cc_{ false };
248
250 std::array<midi_byte_t, 3> last_cc_captured_{};
251
252 std::atomic<State> state_{ State::Uninitialized };
253 static_assert (decltype (state_)::is_always_lock_free);
254
255 utils::QObjectUniquePtr<dsp::MidiPanicProcessor> midi_panic_processor_;
256
257 std::unique_ptr<AudioCallback> audio_callback_;
258
263 bool callback_running_{};
264};
265}
RAII wrapper class for std::binary_semaphore.
Definition concurrency.h:62
AudioEngine(dsp::Transport &transport, std::shared_ptr< juce::AudioDeviceManager > device_mgr, dsp::DspGraphDispatcher &graph_dispatcher, QObject *parent=nullptr)
Create a new audio engine.
~AudioEngine() override
Closes any connections and free's data.
void advance_playhead_after_processing(dsp::Transport::TransportSnapshot &transport_snapshot, const dsp::PlayheadProcessingGuard &playhead_guard, nframes_t roll_nframes, nframes_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.
auto process(const dsp::PlayheadProcessingGuard &playhead_guard, nframes_t total_frames_to_process) noexcept -> ProcessReturnStatus
Processes current cycle.
void wait_for_pause(EngineState &state, bool force_pause, bool with_fadeout)
bool process_prepare(dsp::Transport::TransportSnapshot &transport_snapshot, nframes_t nframes, SemaphoreRAII< moodycamel::LightweightSemaphore > &sem) noexcept
To be called by each implementation to prepare the structures before processing.
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.
RAII helper for Playhead audio processing block.
Definition playhead.h:241
Wrapper over a Uuid registry that provides (slow) lookup by unique ID.
Definition parameter.h:523
The Transport class represents the transport controls and state for an audio engine.
Definition transport.h:45
uint32_t nframes_t
Frame count.
Definition types.h:58