diff options
author | David Robillard <d@drobilla.net> | 2024-11-22 19:12:59 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2024-11-24 19:12:22 -0500 |
commit | 10f1ed7218d4480cd9b1e43e0eb1af4541dab59f (patch) | |
tree | 7ce9b72aac4b25253e0bfc60678d62f14f983ac4 | |
parent | 57006d3bf443f2ade18abe7021f8aa8a11b08bcb (diff) | |
download | jalv-10f1ed7218d4480cd9b1e43e0eb1af4541dab59f.tar.gz jalv-10f1ed7218d4480cd9b1e43e0eb1af4541dab59f.tar.bz2 jalv-10f1ed7218d4480cd9b1e43e0eb1af4541dab59f.zip |
Cleanly separate backends from the rest of the application
Finally hitting some concrete refactoring paydirt, with this, backend code
doesn't have access to the application as a whole whatsoever.
If some day the backends become loadable modules that need a more stable API,
something will need to be done about jalv_backend_open(), probably move the
parameters into some struct to make the interface extensible. For now though,
being explicit and fine-grained is fine (good, even), if a bit verbose.
-rw-r--r-- | src/backend.h | 26 | ||||
-rw-r--r-- | src/jack.c | 104 | ||||
-rw-r--r-- | src/jack_impl.h | 10 | ||||
-rw-r--r-- | src/jalv.c | 23 | ||||
-rw-r--r-- | src/portaudio.c | 54 |
5 files changed, 124 insertions, 93 deletions
diff --git a/src/backend.h b/src/backend.h index 9cb6508..1794455 100644 --- a/src/backend.h +++ b/src/backend.h @@ -1,12 +1,16 @@ -// Copyright 2007-2022 David Robillard <d@drobilla.net> +// Copyright 2007-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #ifndef JALV_BACKEND_H #define JALV_BACKEND_H #include "attributes.h" +#include "process.h" +#include "settings.h" #include "types.h" +#include "urids.h" +#include <stdbool.h> #include <stdint.h> // Interface that must be implemented by audio/MIDI backends @@ -22,27 +26,35 @@ jalv_backend_free(JalvBackend* backend); /// Open the audio/MIDI system int -jalv_backend_open(Jalv* jalv); +jalv_backend_open(JalvBackend* backend, + const JalvURIDs* urids, + JalvSettings* settings, + JalvProcess* process, + ZixSem* done, + const char* name, + bool exact_name); /// Close the audio/MIDI system void -jalv_backend_close(Jalv* jalv); +jalv_backend_close(JalvBackend* backend); /// Activate the backend and start processing audio void -jalv_backend_activate(Jalv* jalv); +jalv_backend_activate(JalvBackend* backend); /// Deactivate the backend and stop processing audio void -jalv_backend_deactivate(Jalv* jalv); +jalv_backend_deactivate(JalvBackend* backend); /// Expose a port to the system (if applicable) and connect it to its buffer void -jalv_backend_activate_port(Jalv* jalv, uint32_t port_index); +jalv_backend_activate_port(JalvBackend* backend, + JalvProcess* process, + uint32_t port_index); /// Recompute latencies based on plugin port latencies if necessary void -jalv_backend_recompute_latencies(Jalv* jalv); +jalv_backend_recompute_latencies(JalvBackend* backend); JALV_END_DECLS @@ -4,9 +4,7 @@ #include "backend.h" #include "comm.h" -#include "frontend.h" #include "jack_impl.h" -#include "jalv.h" #include "jalv_config.h" #include "log.h" #include "lv2_evbuf.h" @@ -51,17 +49,17 @@ static const float max_latency = 16777216.0f; static int buffer_size_cb(jack_nframes_t nframes, void* data) { - Jalv* const jalv = (Jalv*)data; - JalvSettings* const settings = &jalv->settings; - JalvProcess* const proc = &jalv->process; + JalvBackend* const backend = (JalvBackend*)data; + JalvSettings* const settings = backend->settings; + JalvProcess* const proc = backend->process; settings->block_length = nframes; #if USE_JACK_PORT_TYPE_GET_BUFFER_SIZE - settings->midi_buf_size = jack_port_type_get_buffer_size( - jalv->backend->client, JACK_DEFAULT_MIDI_TYPE); + settings->midi_buf_size = + jack_port_type_get_buffer_size(backend->client, JACK_DEFAULT_MIDI_TYPE); #endif if (proc->run_state == JALV_RUNNING) { - jalv_process_activate(proc, &jalv->urids, proc->instance, &jalv->settings); + jalv_process_activate(proc, backend->urids, proc->instance, settings); } return 0; } @@ -70,9 +68,8 @@ buffer_size_cb(jack_nframes_t nframes, void* data) static void shutdown_cb(void* data) { - Jalv* const jalv = (Jalv*)data; - jalv_frontend_close(jalv); - zix_sem_post(&jalv->done); + JalvBackend* const backend = (JalvBackend*)data; + zix_sem_post(backend->done); } static void @@ -145,10 +142,10 @@ process_transport(JalvProcess* const proc, static REALTIME int process_cb(jack_nframes_t nframes, void* data) { - Jalv* const jalv = (Jalv*)data; - const JalvURIDs* const urids = &jalv->urids; - JalvProcess* const proc = &jalv->process; - jack_client_t* const client = jalv->backend->client; + JalvBackend* const backend = (JalvBackend*)data; + const JalvURIDs* const urids = backend->urids; + JalvProcess* const proc = backend->process; + jack_client_t* const client = backend->client; uint64_t pos_buf[64] = {0U}; LV2_Atom* const lv2_pos = (LV2_Atom*)pos_buf; @@ -267,8 +264,8 @@ latency_cb(const jack_latency_callback_mode_t mode, void* const data) { // Calculate latency assuming all ports depend on each other - const Jalv* const jalv = (const Jalv*)data; - const JalvProcess* const proc = &jalv->process; + JalvBackend* const backend = (JalvBackend*)data; + const JalvProcess* const proc = backend->process; const PortFlow flow = ((mode == JackCaptureLatency) ? FLOW_INPUT : FLOW_OUTPUT); @@ -308,19 +305,9 @@ latency_cb(const jack_latency_callback_mode_t mode, void* const data) } static jack_client_t* -create_client(Jalv* jalv) +create_client(const char* const name, const bool exact_name) { - // Determine the name of the JACK client - char* jack_name = NULL; - if (jalv->opts.name) { - // Name given on command line - jack_name = jalv_strdup(jalv->opts.name); - } else { - // Use plugin name - LilvNode* name = lilv_plugin_get_name(jalv->plugin); - jack_name = jalv_strdup(lilv_node_as_string(name)); - lilv_node_free(name); - } + char* const jack_name = jalv_strdup(name); // Truncate client name to suit JACK if necessary if (strlen(jack_name) >= (unsigned)jack_client_name_size() - 1) { @@ -329,9 +316,7 @@ create_client(Jalv* jalv) // Connect to JACK jack_client_t* const client = jack_client_open( - jack_name, - (jalv->opts.name_exact ? JackUseExactName : JackNullOption), - NULL); + jack_name, (exact_name ? JackUseExactName : JackNullOption), NULL); free(jack_name); @@ -351,10 +336,16 @@ jalv_backend_free(JalvBackend* const backend) } int -jalv_backend_open(Jalv* jalv) +jalv_backend_open(JalvBackend* const backend, + const JalvURIDs* const urids, + JalvSettings* const settings, + JalvProcess* const process, + ZixSem* const done, + const char* const name, + const bool exact_name) { jack_client_t* const client = - jalv->backend->client ? jalv->backend->client : create_client(jalv); + backend->client ? backend->client : create_client(name, exact_name); if (!client) { return 1; @@ -363,55 +354,58 @@ jalv_backend_open(Jalv* jalv) jalv_log(JALV_LOG_INFO, "JACK name: %s\n", jack_get_client_name(client)); // Set audio engine properties - JalvSettings* const settings = &jalv->settings; - settings->sample_rate = (float)jack_get_sample_rate(client); - settings->block_length = jack_get_buffer_size(client); - settings->midi_buf_size = 4096; + settings->sample_rate = (float)jack_get_sample_rate(client); + settings->block_length = jack_get_buffer_size(client); + settings->midi_buf_size = 4096; #if USE_JACK_PORT_TYPE_GET_BUFFER_SIZE settings->midi_buf_size = jack_port_type_get_buffer_size(client, JACK_DEFAULT_MIDI_TYPE); #endif // Set JACK callbacks - void* const arg = (void*)jalv; + void* const arg = (void*)backend; jack_set_process_callback(client, &process_cb, arg); jack_set_buffer_size_callback(client, &buffer_size_cb, arg); jack_on_shutdown(client, &shutdown_cb, arg); jack_set_latency_callback(client, &latency_cb, arg); - jalv->backend->client = client; - jalv->backend->is_internal_client = false; + backend->urids = urids; + backend->settings = settings; + backend->process = process; + backend->done = done; + backend->client = client; + backend->is_internal_client = false; return 0; } void -jalv_backend_close(Jalv* jalv) +jalv_backend_close(JalvBackend* const backend) { - if (jalv->backend && jalv->backend->client && - !jalv->backend->is_internal_client) { - jack_client_close(jalv->backend->client); + if (backend && backend->client && !backend->is_internal_client) { + jack_client_close(backend->client); } } void -jalv_backend_activate(Jalv* jalv) +jalv_backend_activate(JalvBackend* const backend) { - jack_activate(jalv->backend->client); + jack_activate(backend->client); } void -jalv_backend_deactivate(Jalv* jalv) +jalv_backend_deactivate(JalvBackend* const backend) { - if (!jalv->backend->is_internal_client && jalv->backend->client) { - jack_deactivate(jalv->backend->client); + if (!backend->is_internal_client && backend->client) { + jack_deactivate(backend->client); } } void -jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) +jalv_backend_activate_port(JalvBackend* const backend, + JalvProcess* const proc, + const uint32_t port_index) { - jack_client_t* const client = jalv->backend->client; - JalvProcess* const proc = &jalv->process; + jack_client_t* const client = backend->client; JalvProcessPort* const port = &proc->ports[port_index]; // Connect unsupported ports to NULL (known to be optional by this point) @@ -481,7 +475,7 @@ jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) } void -jalv_backend_recompute_latencies(Jalv* const jalv) +jalv_backend_recompute_latencies(JalvBackend* const backend) { - jack_recompute_total_latencies(jalv->backend->client); + jack_recompute_total_latencies(backend->client); } diff --git a/src/jack_impl.h b/src/jack_impl.h index 0ecd3eb..cc922a9 100644 --- a/src/jack_impl.h +++ b/src/jack_impl.h @@ -5,6 +5,8 @@ #define JALV_JACK_IMPL_H #include "attributes.h" +#include "settings.h" +#include "urids.h" #include <jack/jack.h> @@ -14,8 +16,12 @@ JALV_BEGIN_DECLS struct JalvBackendImpl { - jack_client_t* client; ///< Jack client - bool is_internal_client; ///< Running inside jackd + const JalvURIDs* urids; ///< Application vocabulary + JalvSettings* settings; ///< Run settings + JalvProcess* process; ///< Process thread state + ZixSem* done; ///< Shutdown semaphore + jack_client_t* client; ///< Jack client + bool is_internal_client; ///< Running inside jackd }; JALV_END_DECLS @@ -485,7 +485,7 @@ jalv_update(Jalv* jalv) jalv->urids.atom_eventTransfer, &msg->atom); } else if (header.type == LATENCY_CHANGE) { - jalv_backend_recompute_latencies(jalv); + jalv_backend_recompute_latencies(jalv->backend); } else { return ring_error("Unknown message type received from process ring\n"); } @@ -767,6 +767,11 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) return -4; } + if (!jalv->opts.name) { + jalv->opts.name = + jalv_strdup(lilv_node_as_string(lilv_plugin_get_name(jalv->plugin))); + } + // Create workers if necessary if (lilv_plugin_has_extension_data(jalv->plugin, jalv->nodes.work_interface)) { @@ -840,7 +845,13 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) jalv_create_controls(jalv, true); jalv_create_controls(jalv, false); - if (jalv_backend_open(jalv)) { + if (jalv_backend_open(jalv->backend, + &jalv->urids, + &jalv->settings, + &jalv->process, + &jalv->done, + jalv->opts.name, + jalv->opts.name_exact)) { jalv_log(JALV_LOG_ERR, "Failed to connect to audio system\n"); return -6; } @@ -928,7 +939,7 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) // Create Jack ports and connect plugin ports to buffers for (uint32_t i = 0; i < jalv->num_ports; ++i) { - jalv_backend_activate_port(jalv, i); + jalv_backend_activate_port(jalv->backend, &jalv->process, i); } // Discover UI @@ -946,7 +957,7 @@ jalv_activate(Jalv* const jalv) jalv_worker_launch(jalv->process.worker); } lilv_instance_activate(jalv->process.instance); - jalv_backend_activate(jalv); + jalv_backend_activate(jalv->backend); } return 0; @@ -956,7 +967,7 @@ int jalv_deactivate(Jalv* const jalv) { if (jalv->backend) { - jalv_backend_deactivate(jalv); + jalv_backend_deactivate(jalv->backend); } if (jalv->process.instance) { lilv_instance_deactivate(jalv->process.instance); @@ -976,7 +987,7 @@ jalv_close(Jalv* const jalv) jalv_deactivate(jalv); jalv_process_deactivate(&jalv->process); if (jalv->backend) { - jalv_backend_close(jalv); + jalv_backend_close(jalv->backend); } // Free UI and plugin instances diff --git a/src/portaudio.c b/src/portaudio.c index d39b7e8..8ce1945 100644 --- a/src/portaudio.c +++ b/src/portaudio.c @@ -3,14 +3,16 @@ #include "backend.h" #include "comm.h" -#include "jalv.h" #include "log.h" #include "lv2_evbuf.h" #include "process.h" +#include "settings.h" #include "types.h" +#include "urids.h" #include <lilv/lilv.h> #include <zix/attributes.h> +#include <zix/sem.h> #include <portaudio.h> #include <stdbool.h> @@ -46,8 +48,7 @@ process_cb(const void* inputs, (void)time; (void)flags; - Jalv* const jalv = (Jalv*)handle; - JalvProcess* const proc = &jalv->process; + JalvProcess* const proc = (JalvProcess*)handle; // If execution is paused, emit silence and return if (proc->run_state == JALV_PAUSED) { @@ -125,7 +126,13 @@ jalv_backend_free(JalvBackend* const backend) } int -jalv_backend_open(Jalv* jalv) +jalv_backend_open(JalvBackend* const backend, + const JalvURIDs* const ZIX_UNUSED(urids), + JalvSettings* const settings, + JalvProcess* const proc, + ZixSem* const ZIX_UNUSED(done), + const char* const ZIX_UNUSED(name), + const bool ZIX_UNUSED(exact_name)) { PaStreamParameters inputParameters; PaStreamParameters outputParameters; @@ -153,11 +160,11 @@ jalv_backend_open(Jalv* jalv) // Count number of input and output audio ports/channels inputParameters.channelCount = 0; outputParameters.channelCount = 0; - for (uint32_t i = 0; i < jalv->num_ports; ++i) { - if (jalv->ports[i].type == TYPE_AUDIO) { - if (jalv->ports[i].flow == FLOW_INPUT) { + for (uint32_t i = 0; i < proc->num_ports; ++i) { + if (proc->ports[i].type == TYPE_AUDIO) { + if (proc->ports[i].flow == FLOW_INPUT) { ++inputParameters.channelCount; - } else if (jalv->ports[i].flow == FLOW_OUTPUT) { + } else if (proc->ports[i].flow == FLOW_OUTPUT) { ++outputParameters.channelCount; } } @@ -180,25 +187,25 @@ jalv_backend_open(Jalv* jalv) paFramesPerBufferUnspecified, 0, process_cb, - jalv))) { + proc))) { return setup_error("Failed to open audio stream", st); } // Set audio parameters - jalv->settings.sample_rate = in_dev->defaultSampleRate; - // jalv->settings.block_length = FIXME - jalv->settings.midi_buf_size = 4096; + settings->sample_rate = in_dev->defaultSampleRate; + // settings->block_length = FIXME + settings->midi_buf_size = 4096; - jalv->backend->stream = stream; + backend->stream = stream; return 0; } void -jalv_backend_close(Jalv* jalv) +jalv_backend_close(JalvBackend* const backend) { - if (jalv->backend) { + if (backend) { PaError st = paNoError; - if (jalv->backend->stream && (st = Pa_CloseStream(jalv->backend->stream))) { + if (backend->stream && (st = Pa_CloseStream(backend->stream))) { jalv_log(JALV_LOG_ERR, "Error closing audio (%s)\n", Pa_GetErrorText(st)); } @@ -210,27 +217,28 @@ jalv_backend_close(Jalv* jalv) } void -jalv_backend_activate(Jalv* jalv) +jalv_backend_activate(JalvBackend* const backend) { - const PaError st = Pa_StartStream(jalv->backend->stream); + const PaError st = Pa_StartStream(backend->stream); if (st != paNoError) { jalv_log(JALV_LOG_ERR, "Error starting audio (%s)\n", Pa_GetErrorText(st)); } } void -jalv_backend_deactivate(Jalv* jalv) +jalv_backend_deactivate(JalvBackend* const backend) { - const PaError st = Pa_StopStream(jalv->backend->stream); + const PaError st = Pa_StopStream(backend->stream); if (st != paNoError) { jalv_log(JALV_LOG_ERR, "Error stopping audio (%s)\n", Pa_GetErrorText(st)); } } void -jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) +jalv_backend_activate_port(JalvBackend* const ZIX_UNUSED(backend), + JalvProcess* const proc, + const uint32_t port_index) { - JalvProcess* const proc = &jalv->process; JalvProcessPort* const port = &proc->ports[port_index]; if (port->type == TYPE_CONTROL) { @@ -240,5 +248,5 @@ jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) } void -jalv_backend_recompute_latencies(Jalv* const ZIX_UNUSED(jalv)) +jalv_backend_recompute_latencies(JalvBackend* const ZIX_UNUSED(backend)) {} |