aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2024-11-15 18:45:56 -0500
committerDavid Robillard <d@drobilla.net>2024-11-24 19:00:56 -0500
commitb56679c566dfd01a3b09958e98dcadbbd306bfcb (patch)
treea9cdee57620f629b87b9124e2102705ef329cafc /src
parent417f76f18194ab6edf7e77d771037cf3ff8059e1 (diff)
downloadjalv-b56679c566dfd01a3b09958e98dcadbbd306bfcb.tar.gz
jalv-b56679c566dfd01a3b09958e98dcadbbd306bfcb.tar.bz2
jalv-b56679c566dfd01a3b09958e98dcadbbd306bfcb.zip
Generalize audio/main thread communication
Defines a more general message structure that can also accommodate internal use (not just as a channel for plugin/UI message), and cleans up the ring reading/writing code to prepare for such use.
Diffstat (limited to 'src')
-rw-r--r--src/comm.c25
-rw-r--r--src/comm.h44
-rw-r--r--src/control.h8
-rw-r--r--src/jack.c7
-rw-r--r--src/jalv.c111
-rw-r--r--src/portaudio.c7
6 files changed, 127 insertions, 75 deletions
diff --git a/src/comm.c b/src/comm.c
index ef83c8e..c7ed49b 100644
--- a/src/comm.c
+++ b/src/comm.c
@@ -3,9 +3,6 @@
#include "comm.h"
-#include "control.h"
-
-#include "lv2/atom/atom.h"
#include "lv2/urid/urid.h"
ZixStatus
@@ -29,7 +26,6 @@ jalv_write_split_message(ZixRing* const target,
ZixStatus
jalv_write_event(ZixRing* const target,
const uint32_t port_index,
- const uint32_t protocol,
const uint32_t size,
const LV2_URID type,
const void* const body)
@@ -37,12 +33,12 @@ jalv_write_event(ZixRing* const target,
// TODO: Be more discriminate about what to send
typedef struct {
- ControlChange change;
- LV2_Atom atom;
+ JalvMessageHeader message;
+ JalvEventTransfer event;
} Header;
- const Header header = {{port_index, protocol, sizeof(LV2_Atom) + size},
- {size, type}};
+ const Header header = {{EVENT_TRANSFER, sizeof(JalvEventTransfer) + size},
+ {port_index, {size, type}}};
return jalv_write_split_message(target, &header, sizeof(header), body, size);
}
@@ -52,8 +48,15 @@ jalv_write_control(ZixRing* const target,
const uint32_t port_index,
const float value)
{
- const ControlChange header = {port_index, 0, sizeof(value)};
+ typedef struct {
+ JalvMessageHeader message;
+ JalvControlChange control;
+ } Message;
+
+ const Message msg = {{CONTROL_PORT_CHANGE, sizeof(JalvControlChange)},
+ {port_index, value}};
- return jalv_write_split_message(
- target, &header, sizeof(header), &value, sizeof(value));
+ return zix_ring_write(target, &msg, sizeof(msg)) == sizeof(msg)
+ ? ZIX_STATUS_SUCCESS
+ : ZIX_STATUS_ERROR;
}
diff --git a/src/comm.h b/src/comm.h
index 75f098b..e4579eb 100644
--- a/src/comm.h
+++ b/src/comm.h
@@ -6,6 +6,7 @@
#include "attributes.h"
+#include "lv2/atom/atom.h"
#include "lv2/urid/urid.h"
#include "zix/ring.h"
#include "zix/status.h"
@@ -16,6 +17,47 @@ JALV_BEGIN_DECLS
// Communication between the audio and main threads via rings
+/// Type of an internal message in a communication ring
+typedef enum {
+ NO_MESSAGE, ///< Sentinel type for uninitialized messages
+ CONTROL_PORT_CHANGE, ///< Value change for a control port (float)
+ EVENT_TRANSFER, ///< Event transfer for a sequence port (atom)
+} JalvMessageType;
+
+/**
+ Message between the audio thread and the main thread.
+
+ This is the general header for any type of message in a communication ring.
+ The type determines how the message must be handled by the receiver. This
+ header is followed immediately by `size` bytes of data in the ring.
+*/
+typedef struct {
+ JalvMessageType type; ///< Type of this message
+ uint32_t size; ///< Size of payload following this header in bytes
+} JalvMessageHeader;
+
+/**
+ The payload of a CONTROL_PORT_CHANGE message.
+
+ This message has a fixed sized, and is described in its entirety by this
+ struct.
+*/
+typedef struct {
+ uint32_t port_index; ///< Control port index
+ float value; ///< Control value
+} JalvControlChange;
+
+/**
+ The start of the payload of an EVENT_TRANSFER message.
+
+ This message has a variable size, the start described by this struct is
+ followed immediately by `atom.size` bytes of data (the atom body).
+*/
+typedef struct {
+ uint32_t port_index; ///< Sequence port index
+ LV2_Atom atom; ///< Event payload header
+} JalvEventTransfer;
+
/**
Write a message in two parts to a ring.
@@ -43,7 +85,6 @@ jalv_write_split_message(ZixRing* target,
@param target Communication ring (jalv->plugin_to_ui or jalv->ui_to_plugin).
@param port_index Index of the port this change is for.
- @param protocol Port protocol (0 for float control, or atom:eventTransfer).o
@param size Size of body in bytes.
@param type Atom type URID.
@param body Atom body.
@@ -52,7 +93,6 @@ jalv_write_split_message(ZixRing* target,
ZixStatus
jalv_write_event(ZixRing* target,
uint32_t port_index,
- uint32_t protocol,
uint32_t size,
LV2_URID type,
const void* body);
diff --git a/src/control.h b/src/control.h
index 46bc158..858f933 100644
--- a/src/control.h
+++ b/src/control.h
@@ -62,14 +62,6 @@ typedef struct {
ControlID** controls;
} Controls;
-/// Control change event, sent through ring buffers for UI updates
-typedef struct {
- uint32_t index;
- uint32_t protocol;
- uint32_t size;
- // Followed immediately by size bytes of data
-} ControlChange;
-
/// Create a new ID for a control port
ControlID*
new_port_control(LilvWorld* world,
diff --git a/src/jack.c b/src/jack.c
index 3a92ff4..115029e 100644
--- a/src/jack.c
+++ b/src/jack.c
@@ -230,12 +230,7 @@ jack_process_cb(jack_nframes_t nframes, void* data)
if (jalv->has_ui) {
// Forward event to UI
- jalv_write_event(jalv->plugin_to_ui,
- p,
- jalv->urids.atom_eventTransfer,
- size,
- type,
- body);
+ jalv_write_event(jalv->plugin_to_ui, p, size, type, body);
}
}
} else if (send_ui_updates && port->flow == FLOW_OUTPUT &&
diff --git a/src/jalv.c b/src/jalv.c
index f12db19..ea0e13b 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -424,12 +424,8 @@ jalv_send_to_plugin(void* const jalv_handle,
st = ZIX_STATUS_BAD_ARG;
} else {
jalv_dump_atom(jalv, stdout, "UI => Plugin", atom, 36);
- st = jalv_write_event(jalv->ui_to_plugin,
- port_index,
- jalv->urids.atom_eventTransfer,
- atom->size,
- atom->type,
- atom + 1U);
+ st = jalv_write_event(
+ jalv->ui_to_plugin, port_index, atom->size, atom->type, atom + 1U);
}
} else {
@@ -566,42 +562,60 @@ jalv_ui_is_resizable(Jalv* jalv)
return !fs_matches && !nrs_matches;
}
-static void
+static int
+ring_error(const char* const message)
+{
+ jalv_log(JALV_LOG_ERR, "%s", message);
+ return 1;
+}
+
+static int
jalv_apply_ui_events(Jalv* jalv, uint32_t nframes)
{
if (!jalv->has_ui) {
- return;
+ return 0;
}
- ControlChange ev = {0U, 0U, 0U};
- const size_t space = zix_ring_read_space(jalv->ui_to_plugin);
- for (size_t i = 0; i < space; i += sizeof(ev) + ev.size) {
- if (zix_ring_read(jalv->ui_to_plugin, &ev, sizeof(ev)) != sizeof(ev)) {
- jalv_log(JALV_LOG_ERR, "Failed to read header from UI ring buffer\n");
- break;
+ ZixRing* const ring = jalv->ui_to_plugin;
+ JalvMessageHeader header = {NO_MESSAGE, 0U};
+ const size_t space = zix_ring_read_space(ring);
+ for (size_t i = 0; i < space; i += sizeof(header) + header.size) {
+ // Read message header (which includes the body size)
+ if (zix_ring_read(ring, &header, sizeof(header)) != sizeof(header)) {
+ return ring_error("Failed to read header from UI ring\n");
}
- void* const body = jalv->audio_msg;
- if (zix_ring_read(jalv->ui_to_plugin, body, ev.size) != ev.size) {
- jalv_log(JALV_LOG_ERR, "Failed to read from UI ring buffer\n");
- break;
- }
+ if (header.type == CONTROL_PORT_CHANGE) {
+ assert(header.size == sizeof(JalvControlChange));
+ JalvControlChange msg = {0U, 0.0f};
+ if (zix_ring_read(ring, &msg, sizeof(msg)) != sizeof(msg)) {
+ return ring_error("Failed to read control value from UI ring\n");
+ }
+
+ assert(msg.port_index < jalv->num_ports);
+ jalv->ports[msg.port_index].control = msg.value;
- assert(ev.index < jalv->num_ports);
- struct Port* const port = &jalv->ports[ev.index];
- if (ev.protocol == 0) {
- assert(ev.size == sizeof(float));
- port->control = *(const float*)body;
- } else if (ev.protocol == jalv->urids.atom_eventTransfer) {
+ } else if (header.type == EVENT_TRANSFER) {
+ assert(header.size <= jalv->msg_buf_size);
+ void* const body = jalv->audio_msg;
+ if (zix_ring_read(ring, body, header.size) != header.size) {
+ return ring_error("Failed to read event from UI ring\n");
+ }
+
+ const JalvEventTransfer* const msg = (const JalvEventTransfer*)body;
+ assert(msg->port_index < jalv->num_ports);
+ struct Port* const port = &jalv->ports[msg->port_index];
LV2_Evbuf_Iterator e = lv2_evbuf_end(port->evbuf);
- const LV2_Atom* const atom = (const LV2_Atom*)body;
+ const LV2_Atom* const atom = &msg->atom;
lv2_evbuf_write(
&e, nframes, 0, atom->type, atom->size, LV2_ATOM_BODY_CONST(atom));
+
} else {
- jalv_log(
- JALV_LOG_ERR, "Unknown control change protocol %u\n", ev.protocol);
+ return ring_error("Unknown message type received from UI ring\n");
}
}
+
+ return 0;
}
void
@@ -694,24 +708,37 @@ jalv_update(Jalv* jalv)
}
// Emit UI events
- ControlChange ev;
- const size_t space = zix_ring_read_space(jalv->plugin_to_ui);
- for (size_t i = 0; i + sizeof(ev) < space; i += sizeof(ev) + ev.size) {
- // Read event header to get the size
- zix_ring_read(jalv->plugin_to_ui, &ev, sizeof(ev));
+ ZixRing* const ring = jalv->plugin_to_ui;
+ JalvMessageHeader header = {NO_MESSAGE, 0U};
+ const size_t space = zix_ring_read_space(ring);
+ for (size_t i = 0; i < space; i += sizeof(header) + header.size) {
+ // Read message header (which includes the body size)
+ if (zix_ring_read(ring, &header, sizeof(header)) != sizeof(header)) {
+ return ring_error("Failed to read header from process ring\n");
+ }
- // Read event body
+ // Read message body
void* const body = jalv->ui_msg;
- zix_ring_read(jalv->plugin_to_ui, body, ev.size);
-
- if (ev.protocol == jalv->urids.atom_eventTransfer) {
- jalv_dump_atom(jalv, stdout, "Plugin => UI", (const LV2_Atom*)body, 35);
+ if (zix_ring_read(ring, body, header.size) != header.size) {
+ return ring_error("Failed to read message from process ring\n");
}
- jalv_frontend_port_event(jalv, ev.index, ev.size, ev.protocol, body);
-
- if (ev.protocol == 0 && jalv->opts.print_controls) {
- jalv_print_control(jalv, &jalv->ports[ev.index], *(float*)body);
+ if (header.type == CONTROL_PORT_CHANGE) {
+ const JalvControlChange* const msg = (const JalvControlChange*)body;
+ jalv_frontend_port_event(jalv, msg->port_index, sizeof(float), 0, body);
+ if (jalv->opts.print_controls) {
+ jalv_print_control(jalv, &jalv->ports[msg->port_index], *(float*)body);
+ }
+ } else if (header.type == EVENT_TRANSFER) {
+ const JalvEventTransfer* const msg = (const JalvEventTransfer*)body;
+ jalv_dump_atom(jalv, stdout, "Plugin => UI", &msg->atom, 35);
+ jalv_frontend_port_event(jalv,
+ msg->port_index,
+ sizeof(LV2_Atom) + msg->atom.size,
+ jalv->urids.atom_eventTransfer,
+ &msg->atom);
+ } else {
+ return ring_error("Unknown message type received from process ring\n");
}
}
diff --git a/src/portaudio.c b/src/portaudio.c
index 0c73ceb..9e37d29 100644
--- a/src/portaudio.c
+++ b/src/portaudio.c
@@ -87,12 +87,7 @@ pa_process_cb(const void* inputs,
if (jalv->has_ui) {
// Forward event to UI
- jalv_write_event(jalv->plugin_to_ui,
- p,
- jalv->urids.atom_eventTransfer,
- size,
- type,
- body);
+ jalv_write_event(jalv->plugin_to_ui, p, size, type, body);
}
}
} else if (send_ui_updates && port->flow == FLOW_OUTPUT &&