diff options
author | David Robillard <d@drobilla.net> | 2024-11-17 08:20:17 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2024-11-24 19:04:07 -0500 |
commit | 660d0e3591e6a972f5d4adfd7d0d3bf6cef566f9 (patch) | |
tree | 046c2c571efb23cc24fbe90dd885c44dd0b52743 | |
parent | 06bd42a00bd86f5d487727ff8f08797f9286b27f (diff) | |
download | jalv-660d0e3591e6a972f5d4adfd7d0d3bf6cef566f9.tar.gz jalv-660d0e3591e6a972f5d4adfd7d0d3bf6cef566f9.tar.bz2 jalv-660d0e3591e6a972f5d4adfd7d0d3bf6cef566f9.zip |
Use message mechanism to pause plugin execution
-rw-r--r-- | src/comm.h | 12 | ||||
-rw-r--r-- | src/jack.c | 19 | ||||
-rw-r--r-- | src/jalv.c | 4 | ||||
-rw-r--r-- | src/jalv_internal.h | 2 | ||||
-rw-r--r-- | src/portaudio.c | 20 | ||||
-rw-r--r-- | src/process.c | 21 | ||||
-rw-r--r-- | src/process.h | 13 | ||||
-rw-r--r-- | src/state.c | 25 | ||||
-rw-r--r-- | src/types.h | 9 |
9 files changed, 98 insertions, 27 deletions
@@ -5,6 +5,7 @@ #define JALV_COMM_H #include "attributes.h" +#include "types.h" #include "lv2/atom/atom.h" #include "lv2/urid/urid.h" @@ -24,6 +25,7 @@ typedef enum { EVENT_TRANSFER, ///< Event transfer for a sequence port (atom) LATENCY_CHANGE, ///< Change to plugin latency STATE_REQUEST, ///< Request for a plugin state update (no payload) + RUN_STATE_CHANGE, ///< Request to pause or resume running } JalvMessageType; /** @@ -71,6 +73,16 @@ typedef struct { } JalvLatencyChange; /** + The payload of a RUN_STATE_CHANGE message. + + This message has a fixed sized, and is described in its entirety by this + struct. +*/ +typedef struct { + JalvRunState state; ///< Run state to change to +} JalvRunStateChange; + +/** Write a message in two parts to a ring. This is used to conveniently write a message with a fixed-size header and @@ -125,7 +125,7 @@ process_silent(Jalv* const jalv, const jack_nframes_t nframes) } } - return 0; + return jalv_bypass(jalv, nframes); } static bool @@ -158,6 +158,11 @@ jack_process_cb(jack_nframes_t nframes, void* data) uint64_t pos_buf[64] = {0U}; LV2_Atom* const lv2_pos = (LV2_Atom*)pos_buf; + // If execution is paused, emit silence and return + if (jalv->run_state == JALV_PAUSED) { + return process_silent(jalv, nframes); + } + // Get transport state and position jack_position_t pos = {0U}; const jack_transport_state_t state = jack_transport_query(client, &pos); @@ -170,18 +175,6 @@ jack_process_cb(jack_nframes_t nframes, void* data) forge_position(&jalv->forge, &jalv->urids, state, pos); } - // Update play state and signal UI if necessary - switch (jalv->play_state) { - case JALV_RUNNING: - break; - case JALV_PAUSE_REQUESTED: - jalv->play_state = JALV_PAUSED; - zix_sem_post(&jalv->paused); - break; - case JALV_PAUSED: - return process_silent(jalv, nframes); - } - // Prepare port buffers for (uint32_t p = 0; p < jalv->num_ports; ++p) { JalvPort* const port = &jalv->ports[p]; @@ -924,7 +924,7 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) jalv->block_length = 4096U; jalv->midi_buf_size = 1024U; jalv->msg_buf_size = 1024U; - jalv->play_state = JALV_PAUSED; + jalv->run_state = JALV_PAUSED; jalv->bpm = 120.0f; jalv->control_in = UINT32_MAX; jalv->log.urids = &jalv->urids; @@ -1187,8 +1187,8 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) jalv->has_ui = jalv_frontend_discover(jalv); // Activate audio backend + jalv->run_state = JALV_RUNNING; jalv_backend_activate(jalv); - jalv->play_state = JALV_RUNNING; return 0; } diff --git a/src/jalv_internal.h b/src/jalv_internal.h index db9ec68..4b76162 100644 --- a/src/jalv_internal.h +++ b/src/jalv_internal.h @@ -85,7 +85,7 @@ struct JalvImpl { ZixSem work_lock; ///< Lock for plugin work() method ZixSem done; ///< Exit semaphore ZixSem paused; ///< Paused signal from process thread - JalvPlayState play_state; ///< Current play state + JalvRunState run_state; ///< Current process thread run state char* temp_dir; ///< Temporary plugin state directory char* save_dir; ///< Plugin save directory const LilvPlugin* plugin; ///< Plugin class (RDF data) diff --git a/src/portaudio.c b/src/portaudio.c index d0c4aa3..516b1a8 100644 --- a/src/portaudio.c +++ b/src/portaudio.c @@ -1,4 +1,4 @@ -// Copyright 2007-2022 David Robillard <d@drobilla.net> +// Copyright 2007-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "backend.h" @@ -18,12 +18,25 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> struct JalvBackendImpl { PaStream* stream; }; static int +process_silent(Jalv* const jalv, + void* const outputs, + const unsigned long nframes) +{ + for (uint32_t i = 0; i < jalv->num_ports; ++i) { + memset(((float**)outputs)[i], '\0', nframes * sizeof(float)); + } + + return jalv_bypass(jalv, nframes); +} + +static int pa_process_cb(const void* inputs, void* outputs, unsigned long nframes, @@ -36,6 +49,11 @@ pa_process_cb(const void* inputs, Jalv* jalv = (Jalv*)handle; + // If execution is paused, emit silence and return + if (jalv->run_state == JALV_PAUSED) { + return process_silent(jalv, outputs, nframes); + } + // Prepare port buffers uint32_t in_index = 0; uint32_t out_index = 0; diff --git a/src/process.c b/src/process.c index 49e5a1f..fd2aa31 100644 --- a/src/process.c +++ b/src/process.c @@ -14,6 +14,7 @@ #include "lv2/atom/atom.h" #include "lv2/core/lv2.h" #include "zix/ring.h" +#include "zix/sem.h" #include <assert.h> #include <stddef.h> @@ -81,6 +82,18 @@ apply_ui_events(Jalv* const jalv, const uint32_t nframes) lv2_evbuf_write( &iter, nframes, 0U, get.atom.type, get.atom.size, &get.body); + } else if (header.type == RUN_STATE_CHANGE) { + assert(header.size == sizeof(JalvRunStateChange)); + JalvRunStateChange msg = {JALV_RUNNING}; + if (zix_ring_read(ring, &msg, sizeof(msg)) != sizeof(msg)) { + return ring_error("Failed to read run state change from UI ring\n"); + } + + jalv->run_state = msg.state; + if (msg.state == JALV_PAUSED) { + zix_sem_post(&jalv->paused); + } + } else { return ring_error("Unknown message type received from UI ring\n"); } @@ -115,3 +128,11 @@ jalv_run(Jalv* const jalv, const uint32_t nframes) return send_ui_updates; } + +int +jalv_bypass(Jalv* const jalv, const uint32_t nframes) +{ + // Read and apply control change events from UI + apply_ui_events(jalv, nframes); + return 0; +} diff --git a/src/process.h b/src/process.h index 366d30e..da7470b 100644 --- a/src/process.h +++ b/src/process.h @@ -27,6 +27,19 @@ JALV_BEGIN_DECLS bool jalv_run(Jalv* jalv, uint32_t nframes); +/** + Bypass the plugin for a block of frames. + + This is like jalv_run(), but doesn't actually run the plugin and only does + the minimum necessary internal work for the cycle. + + @param jalv Application state. + @param nframes Number of frames to bypass. + @return Zero. +*/ +int +jalv_bypass(Jalv* jalv, uint32_t nframes); + JALV_END_DECLS #endif // JALV_PROCESS_H diff --git a/src/state.c b/src/state.c index 1bfe6ce..767db0a 100644 --- a/src/state.c +++ b/src/state.c @@ -1,4 +1,4 @@ -// Copyright 2007-2016 David Robillard <d@drobilla.net> +// Copyright 2007-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "state.h" @@ -150,7 +150,7 @@ set_port_value(const char* port_symbol, } ZixStatus st = ZIX_STATUS_SUCCESS; - if (jalv->play_state != JALV_RUNNING) { + if (jalv->run_state != JALV_RUNNING) { // Set value on port struct directly port->control = fvalue; } else { @@ -172,10 +172,18 @@ set_port_value(const char* port_symbol, void jalv_apply_state(Jalv* jalv, const LilvState* state) { + typedef struct { + JalvMessageHeader head; + JalvRunStateChange body; + } PauseMessage; + const bool must_pause = - !jalv->safe_restore && jalv->play_state == JALV_RUNNING; + !jalv->safe_restore && jalv->run_state == JALV_RUNNING; if (must_pause) { - jalv->play_state = JALV_PAUSE_REQUESTED; + const PauseMessage pause_msg = { + {RUN_STATE_CHANGE, sizeof(JalvRunStateChange)}, {JALV_PAUSED}}; + zix_ring_write(jalv->ui_to_plugin, &pause_msg, sizeof(pause_msg)); + zix_sem_wait(&jalv->paused); } @@ -194,9 +202,12 @@ jalv_apply_state(Jalv* jalv, const LilvState* state) state, jalv->instance, set_port_value, jalv, 0, state_features); if (must_pause) { - const JalvMessageHeader msg = {STATE_REQUEST, 0U}; - zix_ring_write(jalv->ui_to_plugin, &msg, sizeof(msg)); - jalv->play_state = JALV_RUNNING; + const JalvMessageHeader state_msg = {STATE_REQUEST, 0U}; + zix_ring_write(jalv->ui_to_plugin, &state_msg, sizeof(state_msg)); + + const PauseMessage run_msg = { + {RUN_STATE_CHANGE, sizeof(JalvRunStateChange)}, {JALV_RUNNING}}; + zix_ring_write(jalv->ui_to_plugin, &run_msg, sizeof(run_msg)); } } diff --git a/src/types.h b/src/types.h index ed577f6..f56ee14 100644 --- a/src/types.h +++ b/src/types.h @@ -1,4 +1,4 @@ -// Copyright 2007-2022 David Robillard <d@drobilla.net> +// Copyright 2007-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #ifndef JALV_TYPES_H @@ -8,8 +8,11 @@ JALV_BEGIN_DECLS -/// Backend playing state -typedef enum { JALV_RUNNING, JALV_PAUSE_REQUESTED, JALV_PAUSED } JalvPlayState; +/// Process thread running state +typedef enum { + JALV_RUNNING, ///< Active and running the plugin + JALV_PAUSED, ///< Active but bypassing the plugin (silent) +} JalvRunState; /// "Global" application state typedef struct JalvImpl Jalv; |