7#include "zrythm-config.h"
9#include "dsp/panning.h"
10#include "gui/backend/channel.h"
11#include "gui/dsp/audio_port.h"
12#include "gui/dsp/control_room.h"
14#include "gui/dsp/hardware_processor.h"
15#include "gui/dsp/midi_port.h"
16#include "gui/dsp/pool.h"
17#include "gui/dsp/sample_processor.h"
18#include "gui/dsp/transport.h"
19#include "utils/audio.h"
20#include "utils/backtrace.h"
21#include "utils/concurrency.h"
22#include "utils/object_pool.h"
26# include "weakjack/weak_libjack.h"
30# include <pulse/pulseaudio.h>
34# include <portaudio.h>
38# include <rtaudio_c.h>
41namespace zrythm::gui::old_dsp::plugins
60constexpr int BLOCK_LENGTH = 4096;
63constexpr int MIDI_BUF_SIZE = 1024;
65#define AUDIO_ENGINE (AudioEngine::get_active_instance ())
66#define AUDIO_POOL (AUDIO_ENGINE->pool_)
68#define DENORMAL_PREVENTION_VAL(engine_) ((engine_)->denormal_prevention_val_)
70constexpr int ENGINE_MAX_EVENTS = 128;
75#define ENGINE_EVENTS_PUSH(et, _arg, _uint_arg, _float_arg) \
77 auto _ev = AUDIO_ENGINE->ev_pool_.acquire (); \
78 _ev->file_ = __FILE__; \
79 _ev->func_ = __func__; \
80 _ev->lineno_ = __LINE__; \
82 _ev->arg_ = (void *) _arg; \
83 _ev->uint_arg_ = _uint_arg; \
84 _ev->float_arg_ = _float_arg; \
85 AUDIO_ENGINE->ev_queue_.push_back (_ev); \
88enum class AudioBackend
91 AUDIO_BACKEND_DUMMY_LIBSOUNDIO,
93 AUDIO_BACKEND_ALSA_LIBSOUNDIO,
94 AUDIO_BACKEND_ALSA_RTAUDIO,
96 AUDIO_BACKEND_JACK_LIBSOUNDIO,
97 AUDIO_BACKEND_JACK_RTAUDIO,
98 AUDIO_BACKEND_PULSEAUDIO,
99 AUDIO_BACKEND_PULSEAUDIO_LIBSOUNDIO,
100 AUDIO_BACKEND_PULSEAUDIO_RTAUDIO,
101 AUDIO_BACKEND_COREAUDIO_LIBSOUNDIO,
102 AUDIO_BACKEND_COREAUDIO_RTAUDIO,
104 AUDIO_BACKEND_WASAPI_LIBSOUNDIO,
105 AUDIO_BACKEND_WASAPI_RTAUDIO,
106 AUDIO_BACKEND_ASIO_RTAUDIO,
110audio_backend_is_rtaudio (AudioBackend backend)
112 return backend == AudioBackend::AUDIO_BACKEND_ALSA_RTAUDIO
113 || backend == AudioBackend::AUDIO_BACKEND_JACK_RTAUDIO
114 || backend == AudioBackend::AUDIO_BACKEND_PULSEAUDIO_RTAUDIO
115 || backend == AudioBackend::AUDIO_BACKEND_COREAUDIO_RTAUDIO
116 || backend == AudioBackend::AUDIO_BACKEND_WASAPI_RTAUDIO
117 || backend == AudioBackend::AUDIO_BACKEND_ASIO_RTAUDIO;
141enum class MidiBackend
145 MIDI_BACKEND_ALSA_RTMIDI,
147 MIDI_BACKEND_JACK_RTMIDI,
148 MIDI_BACKEND_WINDOWS_MME,
149 MIDI_BACKEND_WINDOWS_MME_RTMIDI,
150 MIDI_BACKEND_COREMIDI_RTMIDI,
151 MIDI_BACKEND_WINDOWS_UWP_RTMIDI,
155midi_backend_is_rtmidi (MidiBackend backend)
157 return backend == MidiBackend::MIDI_BACKEND_ALSA_RTMIDI
158 || backend == MidiBackend::MIDI_BACKEND_JACK_RTMIDI
159 || backend == MidiBackend::MIDI_BACKEND_WINDOWS_MME_RTMIDI
160 || backend == MidiBackend::MIDI_BACKEND_COREMIDI_RTMIDI
161 || backend == MidiBackend::MIDI_BACKEND_WINDOWS_UWP_RTMIDI;
170 enum class JackTransportType
196 AUDIO_ENGINE_EVENT_BUFFER_SIZE_CHANGE,
197 AUDIO_ENGINE_EVENT_SAMPLE_RATE_CHANGE,
206 Event () : file_ (
nullptr), func_ (
nullptr) { }
210 AudioEngineEventType::AUDIO_ENGINE_EVENT_BUFFER_SIZE_CHANGE;
211 void * arg_ =
nullptr;
212 uint32_t uint_arg_ = 0;
213 float float_arg_ = 0.0f;
214 const char * file_ =
nullptr;
215 const char * func_ =
nullptr;
299 auto &get_port_registry () {
return *port_registry_; }
300 auto &get_port_registry ()
const {
return *port_registry_; }
301 TrackRegistry &get_track_registry ();
302 TrackRegistry &get_track_registry ()
const;
304 bool has_handled_buffer_size_change ()
const
310 bool is_in_active_project ()
const override;
325 void realloc_port_buffers (
nframes_t buf_size);
335 void resume (
State &state);
344 void append_ports (std::vector<Port *> &ports);
379 bool update_from_ticks,
457 std::pair<AudioPort &, AudioPort &> get_monitor_out_ports ();
458 std::pair<AudioPort &, AudioPort &> get_dummy_input_ports ();
461 static constexpr auto kTransportTypeKey =
"transportType"sv;
462 static constexpr auto kSampleRateKey =
"sampleRate"sv;
463 static constexpr auto kFramesPerTickKey =
"framesPerTick"sv;
464 static constexpr auto kMonitorOutLKey =
"monitorOutL"sv;
465 static constexpr auto kMonitorOutRKey =
"monitorOutR"sv;
466 static constexpr auto kMidiEditorManualPressKey =
"midiEditorManualPress"sv;
467 static constexpr auto kMidiInKey =
"midiIn"sv;
468 static constexpr auto kPoolKey =
"pool"sv;
469 static constexpr auto kControlRoomKey =
"controlRoom"sv;
470 static constexpr auto kSampleProcessorKey =
"sampleProcessor"sv;
471 static constexpr auto kHwInProcessorKey =
"hwInProcessor"sv;
472 static constexpr auto kHwOutProcessorKey =
"hwOutProcessor"sv;
473 friend void to_json (nlohmann::json &j,
const AudioEngine &engine)
476 { kTransportTypeKey, engine.transport_type_ },
477 { kSampleRateKey, engine.sample_rate_ },
480 { kMonitorOutRKey, engine.monitor_out_right_ },
483 { kPoolKey, engine.
pool_ },
485 { kSampleProcessorKey, engine.sample_processor_ },
490 friend void from_json (
const nlohmann::json &j,
AudioEngine &engine);
495 int clean_duplicate_events_and_copy (std::array<Event *, 100> &ret);
497 [[gnu::cold]]
void init_common ();
506 void clear_output_buffers (
nframes_t nframes);
508 void receive_midi_events (uint32_t nframes);
517 OptionalRef<PortRegistry> port_registry_;
532 jack_client_t * client_ =
nullptr;
534 void * client_ =
nullptr;
611 std::optional<PortUuidReference> dummy_right_input_;
620 std::optional<PortUuidReference> monitor_out_right_;
663 std::atomic_bool
run_{
false };
674#ifdef HAVE_PORT_AUDIO
675 PaStream * port_audio_stream_ =
nullptr;
677 void * port_audio_stream_ =
nullptr;
690 rtaudio_t rtaudio_ =
nullptr;
692 void * rtaudio_ =
nullptr;
696 pa_threaded_mainloop * pulse_mainloop_ =
nullptr;
697 pa_context * pulse_context_ =
nullptr;
698 pa_stream * pulse_stream_ =
nullptr;
700 void * pulse_mainloop_ =
nullptr;
701 void * pulse_context_ =
nullptr;
702 void * pulse_stream_ =
nullptr;
704 std::atomic_bool pulse_notified_underflow_{
false };
754 std::unique_ptr<SampleProcessor> sample_processor_;
780 float denormal_prevention_val_ = 1e-12f;
870DEFINE_ENUM_FORMATTER (
874 QT_TR_NOOP_UTF8 (
"Dummy"),
875 QT_TR_NOOP_UTF8 (
"Dummy (libsoundio)"),
876 "ALSA (not working)",
883 "PulseAudio (libsoundio)",
884 "PulseAudio (rtaudio)",
885 "CoreAudio (libsoundio)",
886 "CoreAudio (rtaudio)",
888 "WASAPI (libsoundio)",
892DEFINE_ENUM_FORMATTER (
896 QT_TR_NOOP_UTF8 (
"Dummy"),
897 QT_TR_NOOP_UTF8 (
"ALSA Sequencer (not working)"),
898 QT_TR_NOOP_UTF8 (
"ALSA Sequencer (rtmidi)"),
900 "JACK MIDI (rtmidi)",
902 "Windows MME (rtmidi)",
904 "Windows UWP (rtmidi)")
906DEFINE_ENUM_FORMATTER (
908 AudioEngine_SampleRate,
909 QT_TR_NOOP_UTF8 (
"22,050"),
910 QT_TR_NOOP_UTF8 (
"32,000"),
911 QT_TR_NOOP_UTF8 (
"44,100"),
912 QT_TR_NOOP_UTF8 (
"48,000"),
913 QT_TR_NOOP_UTF8 (
"88,200"),
914 QT_TR_NOOP_UTF8 (
"96,000"),
915 QT_TR_NOOP_UTF8 (
"192,000"))
917DEFINE_ENUM_FORMATTER (
919 AudioEngine_BufferSize,
926 QT_TR_NOOP_UTF8 (
"1,024"),
927 QT_TR_NOOP_UTF8 (
"2,048"),
928 QT_TR_NOOP_UTF8 (
"4,096"))
std::unique_ptr< MidiPort > midi_in_
Port used for receiving MIDI in messages for binding CC and other non-recording purposes.
AudioEngineEventType
Audio engine event type.
sample_rate_t sample_rate_
Sample rate.
RtTimePoint timestamp_start_
Timestamp at the start of the current cycle.
nframes_t remaining_latency_preroll_
Timestamp at end of previous cycle.
bool destroying_
Whether the engine is currently undergoing destruction.
void activate(bool activate)
Activates the audio engine to start processing and receiving events.
BounceMode bounce_mode_
If this is on, only tracks/regions marked as "for bounce" will be allowed to make sound.
nframes_t block_length_
Audio buffer size (block length), per channel.
RtDuration max_time_taken_
Time taken to process in the last cycle.
void wait_n_cycles(int n)
Waits for n processing cycles to finish.
void setup()
Sets up the audio engine after the project is initialized/loaded.
std::atomic_bool panic_
Send note off MIDI everywhere.
BufferSize
Buffer sizes to be used in combo boxes.
std::atomic_bool handled_jack_buffer_size_change_
Whether pending jack buffer change was handled (buffers reallocated).
RtTimePoint last_timestamp_start_
Expected timestamp at the end of the current cycle.
std::atomic_bool capture_cc_
To be set to 1 when the CC from the Midi in port should be captured.
SteadyTimePoint last_xrun_notification_
Last time an XRUN notification was shown.
SteadyTimePoint last_events_process_started_
Time last event processing started.
bool denormal_prevention_val_positive_
Whether the denormal prevention value (1e-12 ~ 1e-20) is positive.
SampleRate
Samplerates to be used in comboboxes.
std::optional< PortUuidReference > dummy_left_input_
Used during tests to pass input data for recording.
float * port_audio_out_buf_
Port Audio output buffer.
int process(nframes_t total_frames_to_process)
Processes current cycle.
PositionInfo pos_nfo_before_
Position info at the end of the previous cycle before moving the transport.
bool processing_events_
ID of the event processing source func.
std::unique_ptr< MidiPort > midi_clock_out_
MIDI Clock output.
size_t midi_buf_size_
Size of MIDI port buffers in bytes.
static int samplerate_enum_to_int(SampleRate samplerate)
Returns the int value corresponding to the given AudioEngineSamplerate.
moodycamel::LightweightSemaphore port_operation_lock_
Semaphore for blocking DSP while a plugin and its ports are deleted.
MidiBackend midi_backend_
Current MIDI backend.
ObjectPool< Event > ev_pool_
Object pool of event structs to avoid allocation.
AudioBackend audio_backend_
Current audio backend.
std::atomic_bool run_
Ok to process or not.
static void set_default_backends(bool reset_to_dummy)
Detects the best backends on the system and sets them to GSettings.
std::atomic_bool cycle_running_
Whether the cycle is currently running.
int buf_size_set_
True iff buffer size callback fired.
utils::audio::BounceStep bounce_step_
Bounce step cache.
void pre_setup()
Sets up the audio engine before the project is initialized/loaded.
std::array< midi_byte_t, 3 > last_cc_captured_
Last MIDI CC captured.
bool preparing_to_export_
To be set to true when preparing to export.
void update_frames_per_tick(int beats_per_bar, bpm_t bpm, sample_rate_t sample_rate, bool thread_check, bool update_from_ticks, bool bpm_change)
Updates frames per tick based on the time sig, the BPM, and the sample rate.
std::unique_ptr< HardwareProcessor > hw_out_processor_
Output device processor.
dsp::PanLaw pan_law_
Pan law.
void init_loaded(Project *project)
JackTransportType transport_type_
Whether transport master/client or no connection with jack transport.
void fill_out_bufs(nframes_t nframes)
Called to fill in the external buffers at the end of the processing cycle.
MPMCQueue< Event * > ev_queue_
Event queue.
bool process_prepare(nframes_t nframes, SemaphoreRAII< moodycamel::LightweightSemaphore > *sem=nullptr)
To be called by each implementation to prepare the structures before processing.
std::unique_ptr< HardwareProcessor > hw_in_processor_
Input device processor.
void reset_bounce_mode()
Reset the bounce mode on the engine, all tracks and regions to OFF.
PositionInfo pos_nfo_current_
Position info at the start of the current cycle.
std::unique_ptr< juce::Thread > dummy_audio_thread_
Dummy audio DSP processing thread.
void init_after_cloning(const AudioEngine &other, ObjectCloneType clone_type) override
Initializes the cloned object.
void post_process(nframes_t roll_nframes, nframes_t nframes)
To be called after processing for common logic.
PositionInfo pos_nfo_at_end_
Expected position info at the end of the current cycle.
static int buffer_size_enum_to_int(BufferSize buffer_size)
Returns the int value corresponding to the given AudioEngineBufferSize.
void set_port_metadata_from_owner(dsp::PortIdentifier &id, PortRange &range) const override
Function that will be called by the Port to update the identifier's relevant members based on this po...
SteadyTimePoint last_events_processed_
Time last event processing completed.
void wait_for_pause(State &state, bool force_pause, bool with_fadeout)
bool activated_
Whether the engine is currently activated.
Project * project_
Pointer to owner project, if any.
std::atomic_bool exporting_
Whether currently exporting.
dsp::TicksPerFrame ticks_per_frame_
Reciprocal of frames_per_tick_.
std::unique_ptr< Metronome > metronome_
The metronome.
bool process_events()
Timeout function to be called periodically by Glib.
nframes_t nframes_
Number of frames/samples in the current cycle, per channel.
AudioEngine(Project *project=nullptr)
Create a new audio engine.
dsp::FramesPerTick frames_per_tick_
Number of frames/samples per tick.
std::unique_ptr< ControlRoom > control_room_
The ControlRoom.
bool pre_setup_
Whether the engine is already pre-set up.
bool updating_frames_per_tick_
True while updating frames per tick.
std::unique_ptr< MidiPort > midi_clock_in_
MIDI Clock input TODO.
dsp::PanAlgorithm pan_algo_
Pan algorithm.
std::unique_ptr< AudioPool > pool_
Audio file pool.
std::atomic_bool trigger_midi_activity_
Flag to tell the UI that this channel had MIDI activity.
std::unique_ptr< Router > router_
The processing graph router.
~AudioEngine() override
Closes any connections and free's data.
std::optional< PortUuidReference > monitor_out_left_
Monitor - these should be the last ports in the signal chain.
bool setup_
Whether the engine is already set up.
bool bounce_with_parents_
Whether currently bouncing with parents (cache).
void set_buffer_size(uint32_t buf_size)
Request the backend to set the buffer size.
std::atomic_uint64_t cycle_
Cycle count to know which cycle we are in.
std::unique_ptr< MidiPort > midi_editor_manual_press_
Manual note press events from the piano roll.
Multiple Producer Multiple Consumer lock-free queue.
All MIDI mappings in Zrythm.
Thread-safe, realtime-safe object pool.
Contains all of the info that will be serialized into a project file.
The Router class manages the processing graph for the audio engine.
RAII wrapper class for std::binary_semaphore.
The Tracklist contains all the tracks in the Project.
Struct used to identify Ports in the project.
This class provides the core functionality for managing a plugin, including creating/initializing the...
Lightweight UTF-8 string wrapper with safe conversions.
BounceMode
Mode used when bouncing, either during exporting or when bouncing tracks or regions to audio.
@ BOUNCE_INHERIT
Bounce if parent is bouncing.
@ BOUNCE_OFF
Don't bounce.
uint32_t sample_rate_t
Sample rate.
uint32_t nframes_t
Frame count.
int32_t sixteenth_within_song_
Current sixteenth (within song, ie, total sixteenths).
double tick_within_bar_
Current tick (within bar).
int32_t sixteenth_
Current sixteenth (within beat).
int32_t ninetysixth_notes_
Total 1/96th notes completed up to current pos.
int32_t beat_
Current beat (within bar).
double playhead_ticks_
Exact playhead position (in ticks).
bool is_rolling_
Transport is rolling.
int32_t sixteenth_within_bar_
Current sixteenth (within bar).
double tick_within_beat_
Current tick-within-beat.
bool running_
Engine running.
bool looping_
Transport loop.