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 AUDIO_ENGINE->midi_in->midi_events->num_events
80#define AUDIO_ENGINE (PROJECT->audio_engine)
81#define MANUAL_PRESS_EVENTS \
82 (AUDIO_ENGINE->midi_editor_manual_press->midi_events)
84#define DENORMAL_PREVENTION_VAL (AUDIO_ENGINE->denormal_prevention_val)
86#define engine_is_in_active_project(self) (self->project == PROJECT)
90#define engine_set_run(engine, _run) g_atomic_int_set (&(engine)->run, _run)
91#define engine_get_run(engine) g_atomic_int_get (&(engine)->run)
93#define engine_has_handled_buffer_size_change(engine) \
94 ((engine)->audio_backend != AUDIO_BACKEND_JACK || \
95 ((engine)->audio_backend == AUDIO_BACKEND_JACK && \
96 g_atomic_int_get (&(engine)->handled_jack_buffer_size_change) == 1))
98#define ENGINE_MAX_EVENTS 100
100#define engine_queue_push_back_event(q, x) mpmc_queue_push_back (q, (void *) x)
102#define engine_queue_dequeue_event(q, x) mpmc_queue_dequeue (q, (void *) x)
107#define ENGINE_EVENTS_PUSH(et, _arg, _uint_arg, _float_arg) \
110 AudioEngineEvent * _ev = \
111 (AudioEngineEvent *) object_pool_get (AUDIO_ENGINE->ev_pool); \
112 _ev->file = __FILE__; \
113 _ev->func = __func__; \
114 _ev->lineno = __LINE__; \
116 _ev->arg = (void *) _arg; \
117 _ev->uint_arg = _uint_arg; \
118 _ev->float_arg = _float_arg; \
119 if (zrythm_app->gtk_thread == g_thread_self ()) \
121 _ev->backtrace = backtrace_get ("", 40, false); \
123 "pushing engine event " #et " (%s:%d) uint: %u | float: %f", \
124 __func__, __LINE__, _uint_arg, _float_arg); \
126 engine_queue_push_back_event (AUDIO_ENGINE->ev_queue, _ev); \
134 AUDIO_ENGINE_EVENT_BUFFER_SIZE_CHANGE,
135 AUDIO_ENGINE_EVENT_SAMPLE_RATE_CHANGE,
158 AUDIO_ENGINE_BUFFER_SIZE_16,
159 AUDIO_ENGINE_BUFFER_SIZE_32,
160 AUDIO_ENGINE_BUFFER_SIZE_64,
161 AUDIO_ENGINE_BUFFER_SIZE_128,
162 AUDIO_ENGINE_BUFFER_SIZE_256,
163 AUDIO_ENGINE_BUFFER_SIZE_512,
164 AUDIO_ENGINE_BUFFER_SIZE_1024,
165 AUDIO_ENGINE_BUFFER_SIZE_2048,
166 AUDIO_ENGINE_BUFFER_SIZE_4096,
167 NUM_AUDIO_ENGINE_BUFFER_SIZES,
170static const char * buffer_size_str[] = {
171 "16",
"32",
"64",
"128",
"256",
172 "512", N_ (
"1,024"), N_ (
"2,048"), N_ (
"4,096"),
175static inline const char *
178 return buffer_size_str[buf_size];
186 AUDIO_ENGINE_SAMPLERATE_22050,
187 AUDIO_ENGINE_SAMPLERATE_32000,
188 AUDIO_ENGINE_SAMPLERATE_44100,
189 AUDIO_ENGINE_SAMPLERATE_48000,
190 AUDIO_ENGINE_SAMPLERATE_88200,
191 AUDIO_ENGINE_SAMPLERATE_96000,
192 AUDIO_ENGINE_SAMPLERATE_192000,
193 NUM_AUDIO_ENGINE_SAMPLERATES,
196static const char * sample_rate_str[] = {
197 N_ (
"22,050"), N_ (
"32,000"), N_ (
"44,100"), N_ (
"48,000"),
198 N_ (
"88,200"), N_ (
"96,000"), N_ (
"192,000"),
201static inline const char *
204 return sample_rate_str[sample_rate];
207typedef enum AudioBackend
210 AUDIO_BACKEND_DUMMY_LIBSOUNDIO,
212 AUDIO_BACKEND_ALSA_LIBSOUNDIO,
213 AUDIO_BACKEND_ALSA_RTAUDIO,
215 AUDIO_BACKEND_JACK_LIBSOUNDIO,
216 AUDIO_BACKEND_JACK_RTAUDIO,
217 AUDIO_BACKEND_PULSEAUDIO,
218 AUDIO_BACKEND_PULSEAUDIO_LIBSOUNDIO,
219 AUDIO_BACKEND_PULSEAUDIO_RTAUDIO,
220 AUDIO_BACKEND_COREAUDIO_LIBSOUNDIO,
221 AUDIO_BACKEND_COREAUDIO_RTAUDIO,
223 AUDIO_BACKEND_WASAPI_LIBSOUNDIO,
224 AUDIO_BACKEND_WASAPI_RTAUDIO,
225 AUDIO_BACKEND_ASIO_RTAUDIO,
230audio_backend_is_rtaudio (AudioBackend backend)
232 return backend == AUDIO_BACKEND_ALSA_RTAUDIO
233 || backend == AUDIO_BACKEND_JACK_RTAUDIO
234 || backend == AUDIO_BACKEND_PULSEAUDIO_RTAUDIO
235 || backend == AUDIO_BACKEND_COREAUDIO_RTAUDIO
236 || backend == AUDIO_BACKEND_WASAPI_RTAUDIO
237 || backend == AUDIO_BACKEND_ASIO_RTAUDIO;
240__attribute__ ((unused))
static const char * audio_backend_str[] = {
242 N_ (
"Dummy"), N_ (
"Dummy (libsoundio)"),
243 "ALSA (not working)",
"ALSA (libsoundio)",
244 "ALSA (rtaudio)",
"JACK",
245 "JACK (libsoundio)",
"JACK (rtaudio)",
246 "PulseAudio",
"PulseAudio (libsoundio)",
247 "PulseAudio (rtaudio)",
"CoreAudio (libsoundio)",
248 "CoreAudio (rtaudio)",
"SDL",
249 "WASAPI (libsoundio)",
"WASAPI (rtaudio)",
274typedef enum MidiBackend
278 MIDI_BACKEND_ALSA_RTMIDI,
280 MIDI_BACKEND_JACK_RTMIDI,
281 MIDI_BACKEND_WINDOWS_MME,
282 MIDI_BACKEND_WINDOWS_MME_RTMIDI,
283 MIDI_BACKEND_COREMIDI_RTMIDI,
288midi_backend_is_rtmidi (MidiBackend backend)
290 return backend == MIDI_BACKEND_ALSA_RTMIDI || backend == MIDI_BACKEND_JACK_RTMIDI
291 || backend == MIDI_BACKEND_WINDOWS_MME_RTMIDI
292 || backend == MIDI_BACKEND_COREMIDI_RTMIDI;
295static const char * midi_backend_str[] = {
298 N_ (
"ALSA Sequencer (not working)"),
299 N_ (
"ALSA Sequencer (rtmidi)"),
301 "JACK MIDI (rtmidi)",
303 "Windows MME (rtmidi)",
307typedef enum AudioEngineJackTransportType
309 AUDIO_ENGINE_JACK_TIMEBASE_MASTER,
310 AUDIO_ENGINE_JACK_TRANSPORT_CLIENT,
311 AUDIO_ENGINE_NO_JACK_TRANSPORT,
312} AudioEngineJackTransportType;
314static const cyaml_strval_t jack_transport_type_strings[] = {
315 {
"Timebase master", AUDIO_ENGINE_JACK_TIMEBASE_MASTER },
316 {
"Transport client", AUDIO_ENGINE_JACK_TRANSPORT_CLIENT},
317 {
"No JACK transport", AUDIO_ENGINE_NO_JACK_TRANSPORT },
375 jack_client_t * client;
481 gint64 last_midi_activity;
536 snd_pcm_t * playback_handle;
537 snd_seq_t * seq_handle;
538 snd_pcm_hw_params_t * hw_params;
539 snd_pcm_sw_params_t * sw_params;
555 void * playback_handle;
573#ifdef HAVE_PORT_AUDIO
574 PaStream * pa_stream;
590 WindowsMmeDevice * mme_in_devs[1024];
592 WindowsMmeDevice * mme_out_devs[1024];
593 int num_mme_out_devs;
595 void * mme_in_devs[1024];
597 void * mme_out_devs[1024];
598 int num_mme_out_devs;
602 SDL_AudioDeviceID dev;
613#ifdef HAVE_PULSEAUDIO
614 pa_threaded_mainloop * pulse_mainloop;
615 pa_context * pulse_context;
616 pa_stream * pulse_stream;
618 void * pulse_mainloop;
619 void * pulse_context;
622 gboolean pulse_notified_underflow;
697 float denormal_prevention_val;
805static const cyaml_schema_field_t engine_fields_schema[] = {
807 YAML_FIELD_ENUM (
AudioEngine, transport_type, jack_transport_type_strings),
819 sample_processor_fields_schema),
823 hardware_processor_fields_schema),
827 hardware_processor_fields_schema),
832static const cyaml_schema_value_t engine_schema = {
885engine_append_ports (
AudioEngine * self, GPtrArray * ports);
924 const int beats_per_bar,
928 bool update_from_ticks,
1009#define engine_is_port_own(self, port) \
1010 (port == MONITOR_FADER->stereo_in->l || port == MONITOR_FADER->stereo_in->r \
1011 || port == MONITOR_FADER->stereo_out->l \
1012 || port == MONITOR_FADER->stereo_out->r)
1021engine_audio_backend_from_string (
const char * str);
1026static inline const char *
1027engine_midi_backend_to_string (MidiBackend backend)
1029 return midi_backend_str[backend];
1033engine_midi_backend_from_string (
const char * str);
The control room backend.
NONNULL_ARGS(1) int undo_manager_undo(UndoManager *self
Undo last action.
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.
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.