aboutsummaryrefslogtreecommitdiffstats
path: root/src/jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jack.c')
-rw-r--r--src/jack.c959
1 files changed, 460 insertions, 499 deletions
diff --git a/src/jack.c b/src/jack.c
index 7a3d6dc..de8517a 100644
--- a/src/jack.c
+++ b/src/jack.c
@@ -1,577 +1,538 @@
-/*
- Copyright 2007-2016 David Robillard <http://drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
+// Copyright 2007-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+#include "backend.h"
+
+#include "frontend.h"
+#include "jalv_config.h"
#include "jalv_internal.h"
-#include "worker.h"
+#include "log.h"
+#include "lv2_evbuf.h"
+#include "port.h"
+#include "types.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>
-#ifdef JALV_JACK_SESSION
-# include <jack/session.h>
-#endif
-#ifdef HAVE_JACK_METADATA
-# include <jack/metadata.h>
+#include <jack/transport.h>
+#include <jack/types.h>
+
+#if USE_JACK_METADATA
+# include <jack/metadata.h>
#endif
#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __clang__
+# define REALTIME __attribute__((annotate("realtime")))
+#else
+# define REALTIME
+#endif
-struct JalvBackend {
- jack_client_t* client; ///< Jack client
- bool is_internal_client; ///< Running inside jackd
+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 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);
+/// Internal Jack client finalization entry point
+void
+jack_finish(void* arg);
-/** Jack buffer size callback. */
+/// Jack buffer size callback
static int
jack_buffer_size_cb(jack_nframes_t nframes, void* data)
{
- Jalv* const jalv = (Jalv*)data;
- jalv->block_length = nframes;
- jalv->buf_size_set = true;
-#ifdef HAVE_JACK_PORT_TYPE_GET_BUFFER_SIZE
- jalv->midi_buf_size = jack_port_type_get_buffer_size(
- jalv->backend->client, JACK_DEFAULT_MIDI_TYPE);
+ Jalv* const jalv = (Jalv*)data;
+ jalv->block_length = nframes;
+ jalv->buf_size_set = true;
+#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);
#endif
- jalv_allocate_port_buffers(jalv);
- return 0;
+ jalv_allocate_port_buffers(jalv);
+ return 0;
}
-/** Jack shutdown callback. */
+/// Jack shutdown callback
static void
jack_shutdown_cb(void* data)
{
- Jalv* const jalv = (Jalv*)data;
- jalv_close_ui(jalv);
- zix_sem_post(&jalv->done);
+ Jalv* const jalv = (Jalv*)data;
+ jalv_frontend_close(jalv);
+ zix_sem_post(&jalv->done);
}
-/** Jack process callback. */
+/// Jack process callback
static REALTIME int
jack_process_cb(jack_nframes_t nframes, void* data)
{
- Jalv* const jalv = (Jalv*)data;
- jack_client_t* client = jalv->backend->client;
-
- /* Get Jack transport position */
- jack_position_t pos;
- const bool rolling = (jack_transport_query(client, &pos)
- == JackTransportRolling);
-
- /* If transport state is not as expected, then something has changed */
- const bool xport_changed = (rolling != jalv->rolling ||
- pos.frame != jalv->position ||
- pos.beats_per_minute != jalv->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 (pos.valid & JackPositionBBT) {
- 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);
- }
-
- if (jalv->opts.dump) {
- char* str = sratom_to_turtle(
- jalv->sratom, &jalv->unmap, "time:", NULL, NULL,
- lv2_pos->type, lv2_pos->size, LV2_ATOM_BODY(lv2_pos));
- jalv_ansi_start(stdout, 36);
- printf("\n## Position ##\n%s\n", str);
- jalv_ansi_reset(stdout);
- free(str);
- }
- }
-
- /* Update transport state to expected values for next cycle */
- jalv->position = rolling ? pos.frame + nframes : pos.frame;
- jalv->bpm = pos.beats_per_minute;
- 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;
- }
-
- /* 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));
-#ifdef HAVE_JACK_METADATA
- } else if (port->type == TYPE_CV && 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));
+ Jalv* const jalv = (Jalv*)data;
+ jack_client_t* client = jalv->backend->client;
+
+ // Get Jack transport position
+ jack_position_t pos;
+ const bool rolling =
+ (jack_transport_query(client, &pos) == JackTransportRolling);
+
+ // If transport state is not as expected, then something has changed
+ 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));
+
+ 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);
+ }
+
+ jalv_dump_atom(jalv, stdout, "Position", lv2_pos, 32);
+ }
+
+ // 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;
+ }
+
+ // 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) {
+ // Connect plugin port directly to Jack port buffer
+ lilv_instance_connect_port(
+ jalv->instance, p, jack_port_get_buffer(port->sys_port, nframes));
#endif
- } 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,
- (const uint8_t*)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 } };
- lv2_evbuf_write(&iter, 0, 0,
- get.atom.type, get.atom.size,
- (const uint8_t*)LV2_ATOM_BODY(&get));
- }
-
- if (port->sys_port) {
- /* Write Jack MIDI input */
- void* buf = jack_port_get_buffer(port->sys_port, nframes);
- for (uint32_t i = 0; i < jack_midi_get_event_count(buf); ++i) {
- 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);
- }
- }
- } else if (port->type == TYPE_EVENT) {
- /* Clear event output for plugin to write to */
- lv2_evbuf_reset(port->evbuf, false);
- }
- }
- jalv->request_update = false;
-
- /* Run plugin for this cycle */
- const bool send_ui_updates = jalv_run(jalv, nframes);
-
- /* Deliver MIDI output and UI events */
- for (uint32_t p = 0; p < jalv->num_ports; ++p) {
- struct Port* const port = &jalv->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);
- }
- } else if (port->flow == FLOW_OUTPUT && port->type == TYPE_EVENT) {
- void* buf = NULL;
- if (port->sys_port) {
- buf = jack_port_get_buffer(port->sys_port, nframes);
- jack_midi_clear_buffer(buf);
- }
-
- for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(port->evbuf);
- lv2_evbuf_is_valid(i);
- i = lv2_evbuf_next(i)) {
- // Get event from LV2 buffer
- uint32_t frames, subframes, type, size;
- uint8_t* body;
- lv2_evbuf_get(i, &frames, &subframes, &type, &size, &body);
-
- if (buf && type == jalv->urids.midi_MidiEvent) {
- // Write MIDI event to Jack output
- jack_midi_event_write(buf, frames, body, size);
- }
-
- if (jalv->has_ui) {
- // Forward event to UI
- jalv_send_to_ui(jalv, p, type, size, body);
- }
- }
- } else if (send_ui_updates &&
- port->flow == FLOW_OUTPUT && port->type == TYPE_CONTROL) {
- char buf[sizeof(ControlChange) + sizeof(float)];
- ControlChange* ev = (ControlChange*)buf;
- ev->index = p;
- ev->protocol = 0;
- ev->size = sizeof(float);
- *(float*)ev->body = port->control;
- if (zix_ring_write(jalv->plugin_events, buf, sizeof(buf))
- < sizeof(buf)) {
- fprintf(stderr, "Plugin => UI buffer overflow!\n");
- }
- }
- }
-
- return 0;
+ } 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}};
+ lv2_evbuf_write(
+ &iter, 0, 0, get.atom.type, get.atom.size, LV2_ATOM_BODY_CONST(&get));
+ }
+
+ if (port->sys_port) {
+ // Write Jack MIDI input
+ void* buf = jack_port_get_buffer(port->sys_port, nframes);
+ for (uint32_t i = 0; i < jack_midi_get_event_count(buf); ++i) {
+ 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);
+ }
+ }
+ } else if (port->type == TYPE_EVENT) {
+ // Clear event output for plugin to write to
+ lv2_evbuf_reset(port->evbuf, false);
+ }
+ }
+ jalv->request_update = false;
+
+ // Run plugin for this cycle
+ const bool send_ui_updates = jalv_run(jalv, nframes);
+
+ // Deliver MIDI output and UI events
+ for (uint32_t p = 0; p < jalv->num_ports; ++p) {
+ struct Port* const port = &jalv->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);
+ }
+ } else if (port->flow == FLOW_OUTPUT && port->type == TYPE_EVENT) {
+ void* buf = NULL;
+ if (port->sys_port) {
+ buf = jack_port_get_buffer(port->sys_port, nframes);
+ jack_midi_clear_buffer(buf);
+ }
+
+ for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(port->evbuf);
+ lv2_evbuf_is_valid(i);
+ i = lv2_evbuf_next(i)) {
+ // Get event from LV2 buffer
+ uint32_t frames = 0;
+ uint32_t subframes = 0;
+ LV2_URID type = 0;
+ uint32_t size = 0;
+ void* body = NULL;
+ lv2_evbuf_get(i, &frames, &subframes, &type, &size, &body);
+
+ if (buf && type == jalv->urids.midi_MidiEvent) {
+ // Write MIDI event to Jack output
+ jack_midi_event_write(buf, frames, body, size);
+ }
+
+ if (jalv->has_ui) {
+ // Forward event to UI
+ jalv_write_event(jalv, jalv->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);
+ }
+ }
+
+ return 0;
}
-/** Calculate latency assuming all ports depend on each other. */
+/// Calculate latency assuming all ports depend on each other
static void
jack_latency_cb(jack_latency_callback_mode_t mode, void* data)
{
- Jalv* const jalv = (Jalv*)data;
- const enum 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];
- if (port->sys_port && port->flow == flow) {
- jack_latency_range_t r;
- jack_port_get_latency_range(port->sys_port, mode, &r);
- if (r.min < range.min) { range.min = r.min; }
- if (r.max > range.max) { range.max = r.max; }
- ++ports_found;
- }
- }
-
- if (ports_found == 0) {
- range.min = 0;
- }
-
- /* Add the plugin's own latency */
- range.min += jalv->plugin_latency;
- range.max += jalv->plugin_latency;
-
- /* Tell Jack about it */
- for (uint32_t p = 0; p < jalv->num_ports; ++p) {
- struct Port* port = &jalv->ports[p];
- if (port->sys_port && port->flow == flow) {
- jack_port_set_latency_range(port->sys_port, mode, &range);
- }
- }
+ Jalv* const jalv = (Jalv*)data;
+ const enum 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];
+ if (port->sys_port && port->flow == flow) {
+ jack_latency_range_t r;
+ jack_port_get_latency_range(port->sys_port, mode, &r);
+ if (r.min < range.min) {
+ range.min = r.min;
+ }
+ if (r.max > range.max) {
+ range.max = r.max;
+ }
+ ++ports_found;
+ }
+ }
+
+ if (ports_found == 0) {
+ range.min = 0;
+ }
+
+ // Add the plugin's own latency
+ range.min += jalv->plugin_latency;
+ range.max += jalv->plugin_latency;
+
+ // Tell Jack about it
+ for (uint32_t p = 0; p < jalv->num_ports; ++p) {
+ struct Port* port = &jalv->ports[p];
+ if (port->sys_port && port->flow == flow) {
+ jack_port_set_latency_range(port->sys_port, mode, &range);
+ }
+ }
}
-#ifdef JALV_JACK_SESSION
-static void
-jack_session_cb(jack_session_event_t* event, void* arg)
-{
- Jalv* const jalv = (Jalv*)arg;
-
- #define MAX_CMD_LEN 256
- event->command_line = (char*)malloc(MAX_CMD_LEN);
- snprintf(event->command_line, MAX_CMD_LEN, "%s -u %s -l \"${SESSION_DIR}\"",
- jalv->prog_name,
- event->client_uuid);
-
- switch (event->type) {
- case JackSessionSave:
- case JackSessionSaveTemplate:
- jalv_save(jalv, event->session_dir);
- break;
- case JackSessionSaveAndQuit:
- jalv_save(jalv, event->session_dir);
- jalv_close_ui(jalv);
- break;
- }
-
- jack_session_reply(jalv->backend->client, event);
- jack_session_event_free(event);
-}
-#endif /* JALV_JACK_SESSION */
-
static jack_client_t*
jack_create_client(Jalv* jalv)
{
- 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);
- }
-
- /* Truncate client name to suit JACK if necessary */
- if (strlen(jack_name) >= (unsigned)jack_client_name_size() - 1) {
- jack_name[jack_client_name_size() - 1] = '\0';
- }
-
- /* Connect to JACK */
-#ifdef JALV_JACK_SESSION
- if (jalv->opts.uuid) {
- client = jack_client_open(
- jack_name,
- (jack_options_t)(JackSessionID |
- (jalv->opts.name_exact ? JackUseExactName : 0)),
- NULL,
- jalv->opts.uuid);
- }
-#endif
-
- if (!client) {
- client = jack_client_open(
- jack_name,
- (jalv->opts.name_exact ? JackUseExactName : JackNullOption),
- NULL);
- }
-
- free(jack_name);
-
- return client;
+ 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);
+ }
+
+ // Truncate client name to suit JACK if necessary
+ if (strlen(jack_name) >= (unsigned)jack_client_name_size() - 1) {
+ jack_name[jack_client_name_size() - 1] = '\0';
+ }
+
+ // Connect to JACK
+ if (!client) {
+ client = jack_client_open(
+ jack_name,
+ (jalv->opts.name_exact ? JackUseExactName : JackNullOption),
+ NULL);
+ }
+
+ free(jack_name);
+
+ return client;
}
JalvBackend*
jalv_backend_init(Jalv* jalv)
{
- jack_client_t* const client =
- jalv->backend ? jalv->backend->client : jack_create_client(jalv);
-
- if (!client) {
- return NULL;
- }
-
- printf("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;
-#ifdef HAVE_JACK_PORT_TYPE_GET_BUFFER_SIZE
- jalv->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);
-#ifdef JALV_JACK_SESSION
- jack_set_session_callback(client, &jack_session_cb, arg);
+ jack_client_t* const client =
+ jalv->backend ? jalv->backend->client : jack_create_client(jalv);
+
+ if (!client) {
+ return NULL;
+ }
+
+ 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;
+#if USE_JACK_PORT_TYPE_GET_BUFFER_SIZE
+ jalv->midi_buf_size =
+ jack_port_type_get_buffer_size(client, JACK_DEFAULT_MIDI_TYPE);
#endif
- 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));
- backend->client = client;
- backend->is_internal_client = false;
- return backend;
+ // 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));
+ backend->client = client;
+ backend->is_internal_client = false;
+ return backend;
}
void
jalv_backend_close(Jalv* jalv)
{
- if (jalv->backend) {
- if (!jalv->backend->is_internal_client) {
- jack_client_close(jalv->backend->client);
- }
-
- free(jalv->backend);
- jalv->backend = NULL;
- }
+ if (jalv->backend) {
+ if (!jalv->backend->is_internal_client) {
+ jack_client_close(jalv->backend->client);
+ }
+
+ free(jalv->backend);
+ jalv->backend = NULL;
+ }
}
void
jalv_backend_activate(Jalv* jalv)
{
- jack_activate(jalv->backend->client);
+ jack_activate(jalv->backend->client);
}
void
jalv_backend_deactivate(Jalv* jalv)
{
- if (jalv->backend && !jalv->backend->is_internal_client) {
- jack_deactivate(jalv->backend->client);
- }
+ if (jalv->backend && !jalv->backend->is_internal_client) {
+ jack_deactivate(jalv->backend->client);
+ }
}
void
jalv_backend_activate_port(Jalv* jalv, 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);
-
- /* 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);
- return;
- }
-
- /* Build Jack flags for port */
- enum JackPortFlags jack_flags = (port->flow == FLOW_INPUT)
- ? JackPortIsInput
- : JackPortIsOutput;
-
- /* Connect the port based on its type */
- switch (port->type) {
- case TYPE_CONTROL:
- lilv_instance_connect_port(jalv->instance, port_index, &port->control);
- break;
- case TYPE_AUDIO:
- port->sys_port = jack_port_register(
- client, lilv_node_as_string(sym),
- JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0);
- break;
-#ifdef HAVE_JACK_METADATA
- case TYPE_CV:
- port->sys_port = jack_port_register(
- client, lilv_node_as_string(sym),
- JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0);
- if (port->sys_port) {
- jack_set_property(client, jack_port_uuid(port->sys_port),
- "http://jackaudio.org/metadata/signal-type", "CV",
- "text/plain");
- }
- break;
+ 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);
+
+ // 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);
+ return;
+ }
+
+ // Build Jack flags for port
+ enum JackPortFlags jack_flags =
+ (port->flow == FLOW_INPUT) ? JackPortIsInput : JackPortIsOutput;
+
+ // Connect the port based on its type
+ switch (port->type) {
+ case TYPE_CONTROL:
+ lilv_instance_connect_port(jalv->instance, port_index, &port->control);
+ break;
+ case TYPE_AUDIO:
+ port->sys_port = jack_port_register(
+ client, lilv_node_as_string(sym), 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);
+ if (port->sys_port) {
+ jack_set_property(client,
+ jack_port_uuid(port->sys_port),
+ "http://jackaudio.org/metadata/signal-type",
+ "CV",
+ "text/plain");
+ }
+ 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);
- }
- break;
- default:
- break;
- }
-
-#ifdef HAVE_JACK_METADATA
- if (port->sys_port) {
- // Set port order to index
- char index_str[16];
- snprintf(index_str, sizeof(index_str), "%d", port_index);
- jack_set_property(client, jack_port_uuid(port->sys_port),
- "http://jackaudio.org/metadata/order", index_str,
- "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);
- }
+ 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);
+ }
+ break;
+ default:
+ break;
+ }
+
+#if USE_JACK_METADATA
+ if (port->sys_port) {
+ // Set port order to index
+ char index_str[16];
+ snprintf(index_str, sizeof(index_str), "%u", port_index);
+ jack_set_property(client,
+ jack_port_uuid(port->sys_port),
+ "http://jackaudio.org/metadata/order",
+ index_str,
+ "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) {
- fprintf(stderr, "error: 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);
- strcat(cmd, "jalv ");
- strcat(cmd, load_init);
-
- /* 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;
- }
- }
-
- const int err = jalv_open(jalv, &argc, &argv);
- if (err) {
- jalv_backend_close(jalv);
- free(jalv);
- }
-
- free(argv);
- free(cmd);
- return err;
+ 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;
+ }
+ }
+
+ const int err = jalv_open(jalv, &argc, &argv);
+ if (err) {
+ jalv_backend_close(jalv);
+ free(jalv);
+ }
+
+ free(argv);
+ free(cmd);
+ return err;
}
void
jack_finish(void* const arg)
{
- Jalv* const jalv = (Jalv*)arg;
- if (jalv) {
- if (jalv_close(jalv)) {
- fprintf(stderr, "Failed to close Jalv\n");
- }
-
- free(jalv);
- }
+ Jalv* const jalv = (Jalv*)arg;
+ if (jalv) {
+ if (jalv_close(jalv)) {
+ jalv_log(JALV_LOG_ERR, "Failed to close Jalv\n");
+ }
+
+ free(jalv);
+ }
}