diff options
author | David Robillard <d@drobilla.net> | 2024-11-15 18:45:56 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2024-11-24 19:00:56 -0500 |
commit | b56679c566dfd01a3b09958e98dcadbbd306bfcb (patch) | |
tree | a9cdee57620f629b87b9124e2102705ef329cafc /src | |
parent | 417f76f18194ab6edf7e77d771037cf3ff8059e1 (diff) | |
download | jalv-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.c | 25 | ||||
-rw-r--r-- | src/comm.h | 44 | ||||
-rw-r--r-- | src/control.h | 8 | ||||
-rw-r--r-- | src/jack.c | 7 | ||||
-rw-r--r-- | src/jalv.c | 111 | ||||
-rw-r--r-- | src/portaudio.c | 7 |
6 files changed, 127 insertions, 75 deletions
@@ -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; } @@ -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, @@ -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 && @@ -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 && |