diff options
Diffstat (limited to 'src/jack.c')
-rw-r--r-- | src/jack.c | 509 |
1 files changed, 226 insertions, 283 deletions
@@ -1,21 +1,25 @@ -// Copyright 2007-2022 David Robillard <d@drobilla.net> +// Copyright 2007-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "backend.h" -#include "frontend.h" +#include "comm.h" +#include "jack_impl.h" #include "jalv_config.h" -#include "jalv_internal.h" #include "log.h" #include "lv2_evbuf.h" -#include "port.h" +#include "process.h" +#include "process_setup.h" +#include "settings.h" +#include "string_utils.h" #include "types.h" +#include "urids.h" -#include "lilv/lilv.h" -#include "lv2/atom/atom.h" -#include "lv2/atom/forge.h" -#include "lv2/urid/urid.h" -#include "zix/sem.h" +#include <lilv/lilv.h> +#include <lv2/atom/atom.h> +#include <lv2/atom/forge.h> +#include <lv2/urid/urid.h> +#include <zix/sem.h> #include <jack/jack.h> #include <jack/midiport.h> @@ -26,7 +30,6 @@ # include <jack/metadata.h> #endif -#include <ctype.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> @@ -39,147 +42,145 @@ # define REALTIME #endif -struct JalvBackendImpl { - jack_client_t* client; ///< Jack client - bool is_internal_client; ///< Running inside jackd -}; - -/// Internal Jack client initialization entry point -int -jack_initialize(jack_client_t* client, const char* load_init); - -/// Internal Jack client finalization entry point -void -jack_finish(void* arg); +/// Maximum supported latency in frames (at most 2^24 so all integers work) +static const float max_latency = 16777216.0f; /// Jack buffer size callback static int -jack_buffer_size_cb(jack_nframes_t nframes, void* data) +buffer_size_cb(jack_nframes_t nframes, void* data) { - Jalv* const jalv = (Jalv*)data; - jalv->block_length = nframes; - jalv->buf_size_set = true; + 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 - jalv->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 - jalv_allocate_port_buffers(jalv); + if (proc->run_state == JALV_RUNNING) { + jalv_process_activate(proc, backend->urids, proc->instance, settings); + } return 0; } /// Jack shutdown callback static void -jack_shutdown_cb(void* data) +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); } -/// Jack process callback -static REALTIME int -jack_process_cb(jack_nframes_t nframes, void* data) +static void +forge_position(LV2_Atom_Forge* const forge, + const JalvURIDs* const urids, + const jack_transport_state_t state, + const jack_position_t pos) { - Jalv* const jalv = (Jalv*)data; - jack_client_t* client = jalv->backend->client; + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_object(forge, &frame, 0, urids->time_Position); + lv2_atom_forge_key(forge, urids->time_frame); + lv2_atom_forge_long(forge, pos.frame); + lv2_atom_forge_key(forge, urids->time_speed); + lv2_atom_forge_float(forge, (state == JackTransportRolling) ? 1.0 : 0.0); + if ((pos.valid & JackPositionBBT)) { + lv2_atom_forge_key(forge, urids->time_barBeat); + lv2_atom_forge_float(forge, pos.beat - 1 + (pos.tick / pos.ticks_per_beat)); + lv2_atom_forge_key(forge, urids->time_bar); + lv2_atom_forge_long(forge, pos.bar - 1); + lv2_atom_forge_key(forge, urids->time_beatUnit); + lv2_atom_forge_int(forge, pos.beat_type); + lv2_atom_forge_key(forge, urids->time_beatsPerBar); + lv2_atom_forge_float(forge, pos.beats_per_bar); + lv2_atom_forge_key(forge, urids->time_beatsPerMinute); + lv2_atom_forge_float(forge, pos.beats_per_minute); + } +} - // Get Jack transport position - jack_position_t pos; - const bool rolling = - (jack_transport_query(client, &pos) == JackTransportRolling); +static int +process_silent(JalvProcess* const proc, const jack_nframes_t nframes) +{ + for (uint32_t p = 0U; p < proc->num_ports; ++p) { + const JalvProcessPort* const port = &proc->ports[p]; + jack_port_t* const jport = (jack_port_t*)proc->ports[p].sys_port; + if (jport && port->flow == FLOW_OUTPUT) { + void* const buf = jack_port_get_buffer(jport, nframes); + if (port->type == TYPE_EVENT) { + jack_midi_clear_buffer(buf); + } else { + memset(buf, '\0', nframes * sizeof(float)); + } + } + } + return jalv_bypass(proc, nframes); +} + +static bool +process_transport(JalvProcess* const proc, + const jack_transport_state_t state, + const jack_position_t pos, + const jack_nframes_t nframes) +{ // If transport state is not as expected, then something has changed + const bool rolling = state == JackTransportRolling; const bool has_bbt = (pos.valid & JackPositionBBT); const bool xport_changed = - (rolling != jalv->rolling || pos.frame != jalv->position || - (has_bbt && pos.beats_per_minute != jalv->bpm)); + (rolling != proc->rolling || pos.frame != proc->position || + (has_bbt && pos.beats_per_minute != proc->bpm)); - uint8_t pos_buf[256]; - LV2_Atom* lv2_pos = (LV2_Atom*)pos_buf; - if (xport_changed) { - // Build an LV2 position object to report change to plugin - lv2_atom_forge_set_buffer(&jalv->forge, pos_buf, sizeof(pos_buf)); - LV2_Atom_Forge* forge = &jalv->forge; - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, jalv->urids.time_Position); - lv2_atom_forge_key(forge, jalv->urids.time_frame); - lv2_atom_forge_long(forge, pos.frame); - lv2_atom_forge_key(forge, jalv->urids.time_speed); - lv2_atom_forge_float(forge, rolling ? 1.0 : 0.0); - if (has_bbt) { - lv2_atom_forge_key(forge, jalv->urids.time_barBeat); - lv2_atom_forge_float(forge, - pos.beat - 1 + (pos.tick / pos.ticks_per_beat)); - lv2_atom_forge_key(forge, jalv->urids.time_bar); - lv2_atom_forge_long(forge, pos.bar - 1); - lv2_atom_forge_key(forge, jalv->urids.time_beatUnit); - lv2_atom_forge_int(forge, pos.beat_type); - lv2_atom_forge_key(forge, jalv->urids.time_beatsPerBar); - lv2_atom_forge_float(forge, pos.beats_per_bar); - lv2_atom_forge_key(forge, jalv->urids.time_beatsPerMinute); - lv2_atom_forge_float(forge, pos.beats_per_minute); - } + // Update transport state to expected values for next cycle + proc->position = rolling ? pos.frame + nframes : pos.frame; + proc->bpm = has_bbt ? pos.beats_per_minute : proc->bpm; + proc->rolling = rolling; + + return xport_changed; +} - jalv_dump_atom(jalv, stdout, "Position", lv2_pos, 32); +/// Jack process callback +static REALTIME int +process_cb(jack_nframes_t nframes, void* data) +{ + 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; + + // If execution is paused, emit silence and return + if (proc->run_state == JALV_PAUSED) { + return process_silent(proc, nframes); } - // Update transport state to expected values for next cycle - jalv->position = rolling ? pos.frame + nframes : pos.frame; - jalv->bpm = has_bbt ? pos.beats_per_minute : jalv->bpm; - jalv->rolling = rolling; - - switch (jalv->play_state) { - case JALV_PAUSE_REQUESTED: - jalv->play_state = JALV_PAUSED; - zix_sem_post(&jalv->paused); - break; - case JALV_PAUSED: - for (uint32_t p = 0; p < jalv->num_ports; ++p) { - jack_port_t* jport = jalv->ports[p].sys_port; - if (jport && jalv->ports[p].flow == FLOW_OUTPUT) { - void* buf = jack_port_get_buffer(jport, nframes); - if (jalv->ports[p].type == TYPE_EVENT) { - jack_midi_clear_buffer(buf); - } else { - memset(buf, '\0', nframes * sizeof(float)); - } - } - } - return 0; - default: - break; + // Get transport state and position + jack_position_t pos = {0U}; + const jack_transport_state_t state = jack_transport_query(client, &pos); + + // Check if transport is discontinuous from last time and update state + const bool xport_changed = process_transport(proc, state, pos, nframes); + if (xport_changed) { + // Build an LV2 position object to report change to plugin + lv2_atom_forge_set_buffer(&proc->forge, (uint8_t*)pos_buf, sizeof(pos_buf)); + forge_position(&proc->forge, urids, state, pos); } // Prepare port buffers - for (uint32_t p = 0; p < jalv->num_ports; ++p) { - struct Port* port = &jalv->ports[p]; - if (port->type == TYPE_AUDIO && port->sys_port) { - // Connect plugin port directly to Jack port buffer - lilv_instance_connect_port( - jalv->instance, p, jack_port_get_buffer(port->sys_port, nframes)); -#if USE_JACK_METADATA - } else if (port->type == TYPE_CV && port->sys_port) { + for (uint32_t p = 0; p < proc->num_ports; ++p) { + JalvProcessPort* const port = &proc->ports[p]; + if (port->sys_port && (port->type == TYPE_AUDIO || port->type == TYPE_CV)) { // Connect plugin port directly to Jack port buffer lilv_instance_connect_port( - jalv->instance, p, jack_port_get_buffer(port->sys_port, nframes)); -#endif + proc->instance, p, jack_port_get_buffer(port->sys_port, nframes)); } else if (port->type == TYPE_EVENT && port->flow == FLOW_INPUT) { lv2_evbuf_reset(port->evbuf, true); - - // Write transport change event if applicable LV2_Evbuf_Iterator iter = lv2_evbuf_begin(port->evbuf); - if (xport_changed) { - lv2_evbuf_write( - &iter, 0, 0, lv2_pos->type, lv2_pos->size, LV2_ATOM_BODY(lv2_pos)); - } - if (jalv->request_update) { - // Plugin state has changed, request an update - const LV2_Atom_Object get = { - {sizeof(LV2_Atom_Object_Body), jalv->urids.atom_Object}, - {0, jalv->urids.patch_Get}}; + if (port->is_primary && xport_changed) { + // Write new transport position lv2_evbuf_write( - &iter, 0, 0, get.atom.type, get.atom.size, LV2_ATOM_BODY_CONST(&get)); + &iter, 0, 0, lv2_pos->type, lv2_pos->size, LV2_ATOM_BODY(lv2_pos)); } if (port->sys_port) { @@ -189,7 +190,7 @@ jack_process_cb(jack_nframes_t nframes, void* data) jack_midi_event_t ev; jack_midi_event_get(&ev, buf, i); lv2_evbuf_write( - &iter, ev.time, 0, jalv->urids.midi_MidiEvent, ev.size, ev.buffer); + &iter, ev.time, 0, urids->midi_MidiEvent, ev.size, ev.buffer); } } } else if (port->type == TYPE_EVENT) { @@ -197,20 +198,28 @@ jack_process_cb(jack_nframes_t nframes, void* data) lv2_evbuf_reset(port->evbuf, false); } } - jalv->request_update = false; // Run plugin for this cycle - const bool send_ui_updates = jalv_run(jalv, nframes); + const bool send_ui_updates = jalv_run(proc, nframes); // Deliver MIDI output and UI events - for (uint32_t p = 0; p < jalv->num_ports; ++p) { - struct Port* const port = &jalv->ports[p]; + for (uint32_t p = 0; p < proc->num_ports; ++p) { + JalvProcessPort* const port = &proc->ports[p]; if (port->flow == FLOW_OUTPUT && port->type == TYPE_CONTROL && - lilv_port_has_property( - jalv->plugin, port->lilv_port, jalv->nodes.lv2_reportsLatency)) { - if (jalv->plugin_latency != port->control) { - jalv->plugin_latency = port->control; - jack_recompute_total_latencies(client); + port->reports_latency) { + // Get the latency in frames from the control output truncated to integer + const float value = proc->controls_buf[p]; + const uint32_t frames = + (value >= 0.0f && value <= max_latency) ? (uint32_t)value : 0U; + + if (proc->plugin_latency != frames) { + // Update the cached value and notify the UI if the latency changed + proc->plugin_latency = frames; + + const JalvLatencyChange body = {frames}; + const JalvMessageHeader header = {LATENCY_CHANGE, sizeof(body)}; + jalv_write_split_message( + proc->plugin_to_ui, &header, sizeof(header), &body, sizeof(body)); } } else if (port->flow == FLOW_OUTPUT && port->type == TYPE_EVENT) { void* buf = NULL; @@ -230,38 +239,41 @@ jack_process_cb(jack_nframes_t nframes, void* data) void* body = NULL; lv2_evbuf_get(i, &frames, &subframes, &type, &size, &body); - if (buf && type == jalv->urids.midi_MidiEvent) { + if (buf && type == urids->midi_MidiEvent) { // Write MIDI event to Jack output jack_midi_event_write(buf, frames, body, size); } - if (jalv->has_ui) { + if (proc->has_ui) { // Forward event to UI - jalv_write_event(jalv, jalv->plugin_to_ui, p, size, type, body); + jalv_write_event(proc->plugin_to_ui, p, size, type, body); } } } else if (send_ui_updates && port->flow == FLOW_OUTPUT && port->type == TYPE_CONTROL) { - jalv_write_control(jalv, jalv->plugin_to_ui, p, port->control); + jalv_write_control(proc->plugin_to_ui, p, proc->controls_buf[p]); } } return 0; } -/// Calculate latency assuming all ports depend on each other +/// Jack latency callback static void -jack_latency_cb(jack_latency_callback_mode_t mode, void* data) +latency_cb(const jack_latency_callback_mode_t mode, void* const data) { - Jalv* const jalv = (Jalv*)data; - const enum PortFlow flow = + // Calculate latency assuming all ports depend on each other + + const JalvBackend* const backend = (JalvBackend*)data; + const JalvProcess* const proc = backend->process; + const PortFlow flow = ((mode == JackCaptureLatency) ? FLOW_INPUT : FLOW_OUTPUT); // First calculate the min/max latency of all feeding ports uint32_t ports_found = 0; jack_latency_range_t range = {UINT32_MAX, 0}; - for (uint32_t p = 0; p < jalv->num_ports; ++p) { - struct Port* port = &jalv->ports[p]; + for (uint32_t p = 0; p < proc->num_ports; ++p) { + JalvProcessPort* const port = &proc->ports[p]; if (port->sys_port && port->flow == flow) { jack_latency_range_t r; jack_port_get_latency_range(port->sys_port, mode, &r); @@ -280,12 +292,12 @@ jack_latency_cb(jack_latency_callback_mode_t mode, void* data) } // Add the plugin's own latency - range.min += jalv->plugin_latency; - range.max += jalv->plugin_latency; + range.min += proc->plugin_latency; + range.max += proc->plugin_latency; // Tell Jack about it - for (uint32_t p = 0; p < jalv->num_ports; ++p) { - struct Port* port = &jalv->ports[p]; + for (uint32_t p = 0; p < proc->num_ports; ++p) { + const JalvProcessPort* const port = &proc->ports[p]; if (port->sys_port && port->flow == flow) { jack_port_set_latency_range(port->sys_port, mode, &range); } @@ -293,21 +305,9 @@ jack_latency_cb(jack_latency_callback_mode_t mode, void* data) } static jack_client_t* -jack_create_client(Jalv* jalv) +create_client(const char* const name, const bool exact_name) { - jack_client_t* client = NULL; - - // 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) { @@ -315,12 +315,8 @@ jack_create_client(Jalv* jalv) } // Connect to JACK - if (!client) { - client = jack_client_open( - jack_name, - (jalv->opts.name_exact ? JackUseExactName : JackNullOption), - NULL); - } + jack_client_t* const client = jack_client_open( + jack_name, (exact_name ? JackUseExactName : JackNullOption), NULL); free(jack_name); @@ -328,84 +324,93 @@ jack_create_client(Jalv* jalv) } JalvBackend* -jalv_backend_init(Jalv* jalv) +jalv_backend_allocate(void) +{ + return (JalvBackend*)calloc(1, sizeof(JalvBackend)); +} + +void +jalv_backend_free(JalvBackend* const backend) +{ + free(backend); +} + +int +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 ? jalv->backend->client : jack_create_client(jalv); + backend->client ? backend->client : create_client(name, exact_name); if (!client) { - return NULL; + return 1; } - jalv_log(JALV_LOG_INFO, "JACK Name: %s\n", jack_get_client_name(client)); + jalv_log(JALV_LOG_INFO, "JACK name: %s\n", jack_get_client_name(client)); // Set audio engine properties - jalv->sample_rate = (float)jack_get_sample_rate(client); - jalv->block_length = jack_get_buffer_size(client); - jalv->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 - jalv->midi_buf_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; - jack_set_process_callback(client, &jack_process_cb, arg); - jack_set_buffer_size_callback(client, &jack_buffer_size_cb, arg); - jack_on_shutdown(client, &jack_shutdown_cb, arg); - jack_set_latency_callback(client, &jack_latency_cb, arg); - - if (jalv->backend) { - /* Internal JACK client, jalv->backend->is_internal_client was already set - in jack_initialize() when allocating the backend. */ - return jalv->backend; - } - - // External JACK client, allocate and return opaque backend - JalvBackend* backend = (JalvBackend*)calloc(1, sizeof(JalvBackend)); + 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); + + backend->urids = urids; + backend->settings = settings; + backend->process = process; + backend->done = done; backend->client = client; backend->is_internal_client = false; - return backend; + return 0; } void -jalv_backend_close(Jalv* jalv) +jalv_backend_close(JalvBackend* const backend) { - if (jalv->backend) { - if (!jalv->backend->is_internal_client) { - jack_client_close(jalv->backend->client); - } - - free(jalv->backend); - jalv->backend = NULL; + 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 && !jalv->backend->is_internal_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* client = jalv->backend->client; - struct Port* const port = &jalv->ports[port_index]; - - const LilvNode* sym = lilv_port_get_symbol(jalv->plugin, port->lilv_port); + 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) if (port->flow == FLOW_UNKNOWN || port->type == TYPE_UNKNOWN) { - lilv_instance_connect_port(jalv->instance, port_index, NULL); + lilv_instance_connect_port(proc->instance, port_index, NULL); return; } @@ -415,17 +420,20 @@ jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) // Connect the port based on its type switch (port->type) { + case TYPE_UNKNOWN: + break; case TYPE_CONTROL: - lilv_instance_connect_port(jalv->instance, port_index, &port->control); + lilv_instance_connect_port( + proc->instance, port_index, &proc->controls_buf[port_index]); break; case TYPE_AUDIO: port->sys_port = jack_port_register( - client, lilv_node_as_string(sym), JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0); + client, port->symbol, JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0); break; #if USE_JACK_METADATA case TYPE_CV: port->sys_port = jack_port_register( - client, lilv_node_as_string(sym), JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0); + client, port->symbol, JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0); if (port->sys_port) { jack_set_property(client, jack_port_uuid(port->sys_port), @@ -436,17 +444,11 @@ jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) break; #endif case TYPE_EVENT: - if (lilv_port_supports_event( - jalv->plugin, port->lilv_port, jalv->nodes.midi_MidiEvent)) { - port->sys_port = jack_port_register(client, - lilv_node_as_string(sym), - JACK_DEFAULT_MIDI_TYPE, - jack_flags, - 0); + if (port->supports_midi) { + port->sys_port = jack_port_register( + client, port->symbol, JACK_DEFAULT_MIDI_TYPE, jack_flags, 0); } break; - default: - break; } #if USE_JACK_METADATA @@ -461,78 +463,19 @@ jalv_backend_activate_port(Jalv* jalv, uint32_t port_index) "http://www.w3.org/2001/XMLSchema#integer"); // Set port pretty name to label - LilvNode* name = lilv_port_get_name(jalv->plugin, port->lilv_port); - jack_set_property(client, - jack_port_uuid(port->sys_port), - JACK_METADATA_PRETTY_NAME, - lilv_node_as_string(name), - "text/plain"); - lilv_node_free(name); - } -#endif -} - -int -jack_initialize(jack_client_t* const client, const char* const load_init) -{ - const size_t args_len = strlen(load_init); - if (args_len > JACK_LOAD_INIT_LIMIT) { - jalv_log(JALV_LOG_ERR, "Too many arguments given\n"); - return -1; - } - - Jalv* const jalv = (Jalv*)calloc(1, sizeof(Jalv)); - if (!jalv) { - return -1; - } - - if (!(jalv->backend = (JalvBackend*)calloc(1, sizeof(JalvBackend)))) { - free(jalv); - return -1; - } - - jalv->backend->client = client; - jalv->backend->is_internal_client = true; - - // Build full command line with "program" name for building argv - const size_t cmd_len = strlen("jalv ") + args_len; - char* const cmd = (char*)calloc(cmd_len + 1, 1); - memcpy(cmd, "jalv ", strlen("jalv ") + 1); - memcpy(cmd + 5, load_init, args_len + 1); - - // Build argv - int argc = 0; - char** argv = NULL; - char* tok = cmd; - for (size_t i = 0; i <= cmd_len; ++i) { - if (isspace(cmd[i]) || !cmd[i]) { - argv = (char**)realloc(argv, sizeof(char*) * ++argc); - cmd[i] = '\0'; - argv[argc - 1] = tok; - tok = cmd + i + 1; + if (port->label) { + jack_set_property(client, + jack_port_uuid(port->sys_port), + JACK_METADATA_PRETTY_NAME, + port->label, + "text/plain"); } } - - const int err = jalv_open(jalv, &argc, &argv); - if (err) { - jalv_backend_close(jalv); - free(jalv); - } - - free(argv); - free(cmd); - return err; +#endif } void -jack_finish(void* const arg) +jalv_backend_recompute_latencies(JalvBackend* const backend) { - Jalv* const jalv = (Jalv*)arg; - if (jalv) { - if (jalv_close(jalv)) { - jalv_log(JALV_LOG_ERR, "Failed to close Jalv\n"); - } - - free(jalv); - } + jack_recompute_total_latencies(backend->client); } |