11#ifndef __AUDIO_ENGINE_H__
12#define __AUDIO_ENGINE_H__
14#include "zrythm-config.h"
17#include "dsp/exporter.h"
29# include "weak_libjack.h"
33# include <pulse/pulseaudio.h>
37# include <portaudio.h>
41# include <alsa/asoundlib.h>
45# include <SDL2/SDL_audio.h>
49# include <rtaudio_c.h>
59typedef struct WindowsMmeDevice WindowsMmeDevice;
73#define AUDIO_ENGINE_SCHEMA_VERSION 2
75#define BLOCK_LENGTH 4096
76#define MIDI_BUF_SIZE 1024
78#define MIDI_IN_NUM_EVENTS \
79 AUDIO_ENGINE->midi_in->midi_events->num_events
81#define AUDIO_ENGINE (PROJECT->audio_engine)
82#define MANUAL_PRESS_EVENTS \
83 (AUDIO_ENGINE->midi_editor_manual_press->midi_events)
85#define DENORMAL_PREVENTION_VAL \
86 (AUDIO_ENGINE->denormal_prevention_val)
88#define engine_is_in_active_project(self) \
89 (self->project == PROJECT)
93#define engine_set_run(engine, _run) \
94 g_atomic_int_set (&(engine)->run, _run)
95#define engine_get_run(engine) \
96 g_atomic_int_get (&(engine)->run)
98#define engine_has_handled_buffer_size_change(engine) \
99 ((engine)->audio_backend != AUDIO_BACKEND_JACK || \
100 ((engine)->audio_backend == AUDIO_BACKEND_JACK && \
101 g_atomic_int_get (&(engine)->handled_jack_buffer_size_change) == 1))
103#define ENGINE_MAX_EVENTS 100
105#define engine_queue_push_back_event(q, x) \
106 mpmc_queue_push_back (q, (void *) x)
108#define engine_queue_dequeue_event(q, x) \
109 mpmc_queue_dequeue (q, (void *) x)
114#define ENGINE_EVENTS_PUSH(et, _arg, _uint_arg, _float_arg) \
117 AudioEngineEvent * _ev = (AudioEngineEvent *) \
118 object_pool_get (AUDIO_ENGINE->ev_pool); \
119 _ev->file = __FILE__; \
120 _ev->func = __func__; \
121 _ev->lineno = __LINE__; \
123 _ev->arg = (void *) _arg; \
124 _ev->uint_arg = _uint_arg; \
125 _ev->float_arg = _float_arg; \
126 if (zrythm_app->gtk_thread == g_thread_self ()) \
128 _ev->backtrace = backtrace_get ("", 40, false); \
130 "pushing engine event " #et \
131 " (%s:%d) uint: %u | float: %f", \
132 __func__, __LINE__, _uint_arg, _float_arg); \
134 engine_queue_push_back_event ( \
135 AUDIO_ENGINE->ev_queue, _ev); \
143 AUDIO_ENGINE_EVENT_BUFFER_SIZE_CHANGE,
144 AUDIO_ENGINE_EVENT_SAMPLE_RATE_CHANGE,
167 AUDIO_ENGINE_BUFFER_SIZE_16,
168 AUDIO_ENGINE_BUFFER_SIZE_32,
169 AUDIO_ENGINE_BUFFER_SIZE_64,
170 AUDIO_ENGINE_BUFFER_SIZE_128,
171 AUDIO_ENGINE_BUFFER_SIZE_256,
172 AUDIO_ENGINE_BUFFER_SIZE_512,
173 AUDIO_ENGINE_BUFFER_SIZE_1024,
174 AUDIO_ENGINE_BUFFER_SIZE_2048,
175 AUDIO_ENGINE_BUFFER_SIZE_4096,
176 NUM_AUDIO_ENGINE_BUFFER_SIZES,
179static const char * buffer_size_str[] = {
180 "16",
"32",
"64",
"128",
"256",
181 "512", N_ (
"1,024"), N_ (
"2,048"), N_ (
"4,096"),
184static inline const char *
187 return buffer_size_str[buf_size];
195 AUDIO_ENGINE_SAMPLERATE_22050,
196 AUDIO_ENGINE_SAMPLERATE_32000,
197 AUDIO_ENGINE_SAMPLERATE_44100,
198 AUDIO_ENGINE_SAMPLERATE_48000,
199 AUDIO_ENGINE_SAMPLERATE_88200,
200 AUDIO_ENGINE_SAMPLERATE_96000,
201 AUDIO_ENGINE_SAMPLERATE_192000,
202 NUM_AUDIO_ENGINE_SAMPLERATES,
205static const char * sample_rate_str[] = {
206 N_ (
"22,050"), N_ (
"32,000"), N_ (
"44,100"), N_ (
"48,000"),
207 N_ (
"88,200"), N_ (
"96,000"), N_ (
"192,000"),
210static inline const char *
211engine_sample_rate_to_string (
214 return sample_rate_str[sample_rate];
217typedef enum AudioBackend
220 AUDIO_BACKEND_DUMMY_LIBSOUNDIO,
222 AUDIO_BACKEND_ALSA_LIBSOUNDIO,
223 AUDIO_BACKEND_ALSA_RTAUDIO,
225 AUDIO_BACKEND_JACK_LIBSOUNDIO,
226 AUDIO_BACKEND_JACK_RTAUDIO,
227 AUDIO_BACKEND_PULSEAUDIO,
228 AUDIO_BACKEND_PULSEAUDIO_LIBSOUNDIO,
229 AUDIO_BACKEND_PULSEAUDIO_RTAUDIO,
230 AUDIO_BACKEND_COREAUDIO_LIBSOUNDIO,
231 AUDIO_BACKEND_COREAUDIO_RTAUDIO,
233 AUDIO_BACKEND_WASAPI_LIBSOUNDIO,
234 AUDIO_BACKEND_WASAPI_RTAUDIO,
235 AUDIO_BACKEND_ASIO_RTAUDIO,
240audio_backend_is_rtaudio (AudioBackend backend)
242 return backend == AUDIO_BACKEND_ALSA_RTAUDIO
243 || backend == AUDIO_BACKEND_JACK_RTAUDIO
244 || backend == AUDIO_BACKEND_PULSEAUDIO_RTAUDIO
245 || backend == AUDIO_BACKEND_COREAUDIO_RTAUDIO
246 || backend == AUDIO_BACKEND_WASAPI_RTAUDIO
247 || backend == AUDIO_BACKEND_ASIO_RTAUDIO;
251 unused))
static const char * audio_backend_str[] = {
253 N_ (
"Dummy"), N_ (
"Dummy (libsoundio)"),
254 "ALSA (not working)",
"ALSA (libsoundio)",
255 "ALSA (rtaudio)",
"JACK",
256 "JACK (libsoundio)",
"JACK (rtaudio)",
257 "PulseAudio",
"PulseAudio (libsoundio)",
258 "PulseAudio (rtaudio)",
"CoreAudio (libsoundio)",
259 "CoreAudio (rtaudio)",
"SDL",
260 "WASAPI (libsoundio)",
"WASAPI (rtaudio)",
285typedef enum MidiBackend
289 MIDI_BACKEND_ALSA_RTMIDI,
291 MIDI_BACKEND_JACK_RTMIDI,
292 MIDI_BACKEND_WINDOWS_MME,
293 MIDI_BACKEND_WINDOWS_MME_RTMIDI,
294 MIDI_BACKEND_COREMIDI_RTMIDI,
299midi_backend_is_rtmidi (MidiBackend backend)
301 return backend == MIDI_BACKEND_ALSA_RTMIDI
302 || backend == MIDI_BACKEND_JACK_RTMIDI
303 || backend == MIDI_BACKEND_WINDOWS_MME_RTMIDI
304 || backend == MIDI_BACKEND_COREMIDI_RTMIDI;
307static const char * midi_backend_str[] = {
310 N_ (
"ALSA Sequencer (not working)"),
311 N_ (
"ALSA Sequencer (rtmidi)"),
313 "JACK MIDI (rtmidi)",
315 "Windows MME (rtmidi)",
319typedef enum AudioEngineJackTransportType
321 AUDIO_ENGINE_JACK_TIMEBASE_MASTER,
322 AUDIO_ENGINE_JACK_TRANSPORT_CLIENT,
323 AUDIO_ENGINE_NO_JACK_TRANSPORT,
324} AudioEngineJackTransportType;
326static const cyaml_strval_t jack_transport_type_strings[] = {
327 {
"Timebase master", AUDIO_ENGINE_JACK_TIMEBASE_MASTER },
328 {
"Transport client", AUDIO_ENGINE_JACK_TRANSPORT_CLIENT},
329 {
"No JACK transport", AUDIO_ENGINE_NO_JACK_TRANSPORT },
387 jack_client_t * client;
493 gint64 last_midi_activity;
548 snd_pcm_t * playback_handle;
549 snd_seq_t * seq_handle;
550 snd_pcm_hw_params_t * hw_params;
551 snd_pcm_sw_params_t * sw_params;
567 void * playback_handle;
585#ifdef HAVE_PORT_AUDIO
586 PaStream * pa_stream;
602 WindowsMmeDevice * mme_in_devs[1024];
604 WindowsMmeDevice * mme_out_devs[1024];
605 int num_mme_out_devs;
607 void * mme_in_devs[1024];
609 void * mme_out_devs[1024];
610 int num_mme_out_devs;
614 SDL_AudioDeviceID dev;
625#ifdef HAVE_PULSEAUDIO
626 pa_threaded_mainloop * pulse_mainloop;
627 pa_context * pulse_context;
628 pa_stream * pulse_stream;
630 void * pulse_mainloop;
631 void * pulse_context;
634 gboolean pulse_notified_underflow;
709 float denormal_prevention_val;
817static const cyaml_schema_field_t engine_fields_schema[] = {
822 jack_transport_type_strings),
828 stereo_ports_fields_schema),
831 midi_editor_manual_press,
840 transport_fields_schema),
844 audio_pool_fields_schema),
848 control_room_fields_schema),
852 sample_processor_fields_schema),
856 hardware_processor_fields_schema),
860 hardware_processor_fields_schema),
865static const cyaml_schema_value_t engine_schema = {
870engine_realloc_port_buffers (
921engine_append_ports (
AudioEngine * self, GPtrArray * ports);
960 const int beats_per_bar,
964 bool update_from_ticks,
995 const nframes_t total_frames_to_process);
1051#define engine_is_port_own(self, port) \
1052 (port == MONITOR_FADER->stereo_in->l \
1053 || port == MONITOR_FADER->stereo_in->r \
1054 || port == MONITOR_FADER->stereo_out->l \
1055 || port == MONITOR_FADER->stereo_out->r)
1064engine_audio_backend_from_string (
const char * str);
1069static inline const char *
1070engine_midi_backend_to_string (MidiBackend backend)
1072 return midi_backend_str[backend];
1076engine_midi_backend_from_string (
const char * str);
The control room backend.
AudioEngineSamplerate
Samplerates to be used in comboboxes.
AudioEngineEventType
Audio engine event type.
void engine_set_default_backends(bool reset_to_dummy)
Detects the best backends on the system and sets them to GSettings.
void engine_setup(AudioEngine *self)
Sets up the audio engine after the project is initialized/loaded.
void engine_wait_for_pause(AudioEngine *self, EngineState *state, bool force_pause, bool with_fadeout)
AudioEngineBufferSize
Buffer sizes to be used in combo boxes.
const char * engine_audio_backend_to_string(AudioBackend backend)
Returns the audio backend as a string.
COLD WARN_UNUSED_RESULT AudioEngine * engine_new(Project *project)
Create a new audio engine.
int engine_samplerate_enum_to_int(AudioEngineSamplerate samplerate)
Returns the int value corresponding to the given AudioEngineSamplerate.
void engine_pre_setup(AudioEngine *self)
Sets up the audio engine before the project is initialized/loaded.
void engine_wait_n_cycles(AudioEngine *self, int n)
Waits for n processing cycles to finish.
NONNULL HOT void engine_post_process(AudioEngine *self, const nframes_t roll_nframes, const nframes_t nframes)
To be called after processing for common logic.
NONNULL HOT bool engine_process_prepare(AudioEngine *self, nframes_t nframes)
To be called by each implementation to prepare the structures before processing.
COLD NONNULL void engine_free(AudioEngine *self)
Closes any connections and free's data.
void engine_reset_bounce_mode(AudioEngine *self)
Reset the bounce mode on the engine, all tracks and regions to OFF.
NONNULL void engine_fill_out_bufs(AudioEngine *self, const nframes_t nframes)
Called to fill in the external buffers at the end of the processing cycle.
BounceMode
Mode used when bouncing, either during exporting or when bouncing tracks or regions to audio.
COLD void engine_activate(AudioEngine *self, bool activate)
Activates the audio engine to start processing and receiving events.
void engine_update_frames_per_tick(AudioEngine *self, const int beats_per_bar, const bpm_t bpm, const 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.
COLD NONNULL AudioEngine * engine_clone(const AudioEngine *src)
Clones the audio engine.
void engine_set_buffer_size(AudioEngine *self, uint32_t buf_size)
Request the backend to set the buffer size.
int engine_process_events(AudioEngine *self)
GSourceFunc to be added using idle add.
COLD NONNULL_ARGS(1) void automation_track_init_loaded(AutomationTrack *self
Inits a loaded AutomationTracklist.
NONNULL HOT int engine_process(AudioEngine *self, const nframes_t total_frames_to_process)
Processes current cycle.
int engine_buffer_size_enum_to_int(AudioEngineBufferSize buffer_size)
Returns the int value corresponding to the given AudioEngineBufferSize.
@ BOUNCE_OFF
Don't bounce.
@ BOUNCE_INHERIT
Bounce if parent is bouncing.
uint32_t sample_rate_t
Sample rate.
uint32_t nframes_t
Frame count.
uint8_t midi_byte_t
MIDI byte.
#define YAML_FIELD_MAPPING_PTR(owner, member, schema)
Mapping pointer to a struct.
#define YAML_VALUE_PTR(cc, fields_schema)
Schema to be used as a pointer.
Hardware processor for the routing graph.
PanAlgorithm
See https://www.harmonycentral.com/articles/the-truth-about-panning-laws.
PanLaw
These are only useful when changing mono to stereo.
int32_t beat
Current beat (within bar).
double tick_within_beat
Current tick-within-beat.
int32_t sixteenth_within_bar
Current sixteenth (within bar).
double tick_within_bar
Current tick (within bar).
int32_t ninetysixth_notes
Total 1/96th notes completed up to current pos.
int32_t sixteenth_within_song
Current sixteenth (within song, ie, total sixteenths).
bool is_rolling
Transport is rolling.
double playhead_ticks
Exact playhead position (in ticks).
int32_t sixteenth
Current sixteenth (within beat).
HardwareProcessor * hw_in_processor
Input device processor.
AudioEnginePositionInfo pos_nfo_at_end
Expected position info at the end of the current cycle.
double ticks_per_frame
Reciprocal of AudioEngine::frames_per_tick.
double frames_per_tick
Number of frames/samples per tick.
bool bounce_with_parents
Whether currently bouncing with parents (cache).
nframes_t remaining_latency_preroll
When first set, it is equal to the max playback latency of all initial trigger nodes.
nframes_t nframes
Number of frames/samples in the current cycle, per channel.
size_t midi_buf_size
Size of MIDI port buffers in bytes.
volatile gint cycle_running
Whether the cycle is currently running.
ControlRoom * control_room
The ControlRoom.
Port * midi_editor_manual_press
Manual note press events from the piano roll.
gint64 last_timestamp_start
Timestamp at start of previous cycle.
int capture_cc
To be set to 1 when the CC from the Midi in port should be captured.
bool setup
Whether the engine is already set up.
volatile gint run
Ok to process or not.
gint64 last_events_process_started
Time last event processing started.
gint64 zrythm_start_time
Time at start to keep track if trial limit is reached.
volatile gint filled_stereo_out_bufs
Flag used when processing in some backends.
gint handled_jack_buffer_size_change
Whether pending jack buffer change was handled (buffers reallocated).
gint64 timestamp_start
Timestamp at the start of the current cycle.
AudioEnginePositionInfo pos_nfo_before
Position info at the end of the previous cycle before moving the transport.
int processing_events
Whether currently processing events.
StereoPorts * dummy_input
Used during tests to pass input data for recording.
Port * midi_in
Port used for receiving MIDI in messages for binding CC and other non-recording purposes.
AudioBackend audio_backend
Current audio backend.
sample_rate_t sample_rate
Sample rate.
nframes_t block_length
Audio buffer size (block length), per channel.
AudioPool * pool
Audio file pool.
AudioEngineJackTransportType transport_type
Whether transport master/client or no connection with jack transport.
Metronome * metronome
The metronome.
int limit_reached
Flag to keep track of the first time the limit is reached.
MPMCQueue * ev_queue
Event queue.
bool updating_frames_per_tick
True while updating frames per tick.
gint exporting
1 if currently exporting.
MidiBackend midi_backend
Current MIDI backend.
bool preparing_to_export
To be set to true when preparing to export.
gint64 last_xrun_notification
Last time an XRUN notification was shown.
StereoPorts * monitor_out
Monitor - these should be the last ports in the signal chain.
Router * router
The processing graph router.
gint preparing_for_process
Flag used to check if we are inside engine_process_prepare().
gint64 last_events_processed
Time last event processing completed.
BounceMode bounce_mode
If this is on, only tracks/regions marked as "for bounce" will be allowed to make sound.
guint process_source_id
ID of the event processing source func.
BounceStep bounce_step
Bounce step cache.
ObjectPool * ev_pool
Object pool of event structs to avoid allocation.
ZixSem port_operation_lock
Semaphore for blocking DSP while a plugin and its ports are deleted.
AudioEnginePositionInfo pos_nfo_current
Position info at the start of the current cycle.
Project * project
Pointer to owner project, if any.
float * pa_out_buf
Port Audio output buffer.
gint64 max_time_taken
Max time taken to process in the last few cycles.
float * alsa_out_buf
ALSA audio buffer.
Transport * transport
Timeline metadata like BPM, time signature, etc.
gint64 last_timestamp_end
Timestamp at end of previous cycle.
bool denormal_prevention_val_positive
Whether the denormal prevention value (1e-12 ~ 1e-20) is positive.
Port * midi_clock_out
MIDI Clock output.
GThread * dummy_audio_thread
Dummy audio DSP processing thread.
uint_fast64_t cycle
Cycle count to know which cycle we are in.
gint64 last_time_taken
Time taken to process in the last cycle.
PanAlgorithm pan_algo
Pan algorithm.
bool pre_setup
Whether the engine is already pre-set up.
Port * midi_clock_in
MIDI Clock input TODO.
midi_byte_t last_cc[3]
Last MIDI CC captured.
volatile gint panic
Send note off MIDI everywhere.
gint64 timestamp_end
Expected timestamp at the end of the current cycle.
int stop_dummy_audio_thread
Set to 1 to stop the dummy audio thread.
HardwareProcessor * hw_out_processor
Output device processor.
int trigger_midi_activity
Flag to tell the UI that this channel had MIDI activity.
int buf_size_set
True iff buffer size callback fired.
bool activated
Whether the engine is currently activated.
An audio pool is a pool of audio files and their corresponding float arrays in memory that are refere...
A Channel is part of a Track (excluding Tracks that don't have Channels) and contains information rel...
The control room allows to specify how Listen will work on each Channel and to set overall volume aft...
bool looping
Transport loop.
int running
Engine running.
Multiple Producer Multiple Consumer lock-free queue.
All MIDI mappings in Zrythm.
The base plugin Inheriting plugins must have this as a child.
Must ONLY be created via port_new()
Contains all of the info that will be serialized into a project file.
A processor to be used in the routing graph for playing samples independent of the timeline.
L & R port, for convenience.
The Tracklist contains all the tracks in the Project.