aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2024-11-22 19:12:59 -0500
committerDavid Robillard <d@drobilla.net>2024-11-24 19:12:22 -0500
commit10f1ed7218d4480cd9b1e43e0eb1af4541dab59f (patch)
tree7ce9b72aac4b25253e0bfc60678d62f14f983ac4
parent57006d3bf443f2ade18abe7021f8aa8a11b08bcb (diff)
downloadjalv-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.h26
-rw-r--r--src/jack.c104
-rw-r--r--src/jack_impl.h10
-rw-r--r--src/jalv.c23
-rw-r--r--src/portaudio.c54
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
diff --git a/src/jack.c b/src/jack.c
index 758e39a..e08b861 100644
--- a/src/jack.c
+++ b/src/jack.c
@@ -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
diff --git a/src/jalv.c b/src/jalv.c
index a4c9931..0cced8f 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -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))
{}