aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-06-19 23:43:48 +0000
committerDavid Robillard <d@drobilla.net>2011-06-19 23:43:48 +0000
commitbe2a8ef955c2091a2639d4fc93dbc978615733a6 (patch)
tree21a9056c9f7ab0ffff6f551abd6a2aa833b9aa5d
parent3e6c580c197929c126613fcfc546308abdc18c09 (diff)
downloadjalv-be2a8ef955c2091a2639d4fc93dbc978615733a6.tar.gz
jalv-be2a8ef955c2091a2639d4fc93dbc978615733a6.tar.bz2
jalv-be2a8ef955c2091a2639d4fc93dbc978615733a6.zip
Send control output port updates to UIs (commonly used for metering).
git-svn-id: http://svn.drobilla.net/lad/trunk/jalv@3407 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/jalv.c93
-rw-r--r--src/jalv_gtk2.c13
-rw-r--r--src/jalv_internal.h14
-rw-r--r--src/jalv_qt4.cpp16
4 files changed, 101 insertions, 35 deletions
diff --git a/src/jalv.c b/src/jalv.c
index e13a858..b1724b9 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -216,17 +216,27 @@ jack_process_cb(jack_nframes_t nframes, void* data)
}
/* Read and apply control change events from UI */
- ControlChange ev;
- size_t ev_read_size = jack_ringbuffer_read_space(host->events);
- for (size_t i = 0; i < ev_read_size; i += sizeof(ev)) {
- jack_ringbuffer_read(host->events, (char*)&ev, sizeof(ev));
- host->ports[ev.index].control = ev.value;
+ if (host->ui) {
+ ControlChange ev;
+ size_t ev_read_size = jack_ringbuffer_read_space(host->ui_events);
+ for (size_t i = 0; i < ev_read_size; i += sizeof(ev)) {
+ jack_ringbuffer_read(host->ui_events, (char*)&ev, sizeof(ev));
+ host->ports[ev.index].control = ev.value;
+ }
}
/* Run plugin for this cycle */
lilv_instance_run(host->instance, nframes);
- /* Deliver MIDI output */
+ /* Check if it's time to send updates to the UI */
+ host->event_delta_t += nframes;
+ bool send_ui_updates = false;
+ if (host->ui && (host->event_delta_t > host->sample_rate / JALV_UI_UPDATE_HZ)) {
+ send_ui_updates = true;
+ host->event_delta_t = 0;
+ }
+
+ /* Deliver MIDI output and UI events */
for (uint32_t p = 0; p < host->num_ports; ++p) {
if (host->ports[p].jack_port
&& !host->ports[p].is_input
@@ -246,6 +256,11 @@ jack_process_cb(jack_nframes_t nframes, void* data)
jack_midi_event_write(buf, ev->frames, data, ev->size);
lv2_event_increment(&iter);
}
+ } else if (send_ui_updates
+ && !host->ports[p].is_input
+ && host->ports[p].type == CONTROL) {
+ const ControlChange ev = { p, host->ports[p].control };
+ jack_ringbuffer_write(host->plugin_events, (const char*)&ev, sizeof(ev));
}
}
@@ -287,12 +302,28 @@ lv2_ui_write(SuilController controller,
uint32_t format,
const void* buffer)
{
+ if (format != 0) {
+ return;
+ }
Jalv* host = (Jalv*)controller;
- // FIXME: not guaranteed to be a float change...
const ControlChange ev = { port_index, *(float*)buffer };
- jack_ringbuffer_write(host->events, (const char*)&ev, sizeof(ev));
+ jack_ringbuffer_write(host->ui_events, (const char*)&ev, sizeof(ev));
+}
+
+bool
+jalv_emit_ui_events(Jalv* host)
+{
+ ControlChange ev;
+ size_t ev_read_size = jack_ringbuffer_read_space(host->plugin_events);
+ for (size_t i = 0; i < ev_read_size; i += sizeof(ev)) {
+ jack_ringbuffer_read(host->plugin_events, (char*)&ev, sizeof(ev));
+ suil_instance_port_event(host->ui_instance, ev.index,
+ sizeof(float), 0, &ev.value);
+ }
+
+ return true;
}
static void
@@ -307,9 +338,12 @@ main(int argc, char** argv)
jalv_init(&argc, &argv);
Jalv host;
- host.jack_client = NULL;
- host.num_ports = 0;
- host.ports = NULL;
+ host.jack_client = NULL;
+ host.num_ports = 0;
+ host.ports = NULL;
+ host.ui_events = NULL;
+ host.plugin_events = NULL;
+ host.event_delta_t = 0;
host.symap = symap_new();
uri_map.callback_data = &host;
@@ -317,9 +351,6 @@ main(int argc, char** argv)
"http://lv2plug.in/ns/ext/event",
"http://lv2plug.in/ns/ext/midi#MidiEvent");
- host.events = jack_ringbuffer_create(4096);
- jack_ringbuffer_mlock(host.events);
-
sem_init(&exit_sem, 0, 0);
host.done = &exit_sem;
@@ -369,8 +400,8 @@ main(int argc, char** argv)
/* Get a plugin UI */
LilvNode* native_ui_type = jalv_native_ui_type(&host);
- const LilvUI* ui = NULL;
const LilvNode* ui_type = NULL;
+ host.ui = NULL;
if (native_ui_type) {
LilvUIs* uis = lilv_plugin_get_uis(host.plugin); // FIXME: leak
LILV_FOREACH(uis, u, uis) {
@@ -380,15 +411,20 @@ main(int argc, char** argv)
native_ui_type,
&ui_type)) {
// TODO: Multiple UI support
- ui = this_ui;
+ host.ui = this_ui;
break;
}
}
}
- if (ui) {
+ if (host.ui) {
fprintf(stderr, "UI: %s\n",
- lilv_node_as_uri(lilv_ui_get_uri(ui)));
+ lilv_node_as_uri(lilv_ui_get_uri(host.ui)));
+
+ host.ui_events = jack_ringbuffer_create(4096);
+ host.plugin_events = jack_ringbuffer_create(4096);
+ jack_ringbuffer_mlock(host.ui_events);
+ jack_ringbuffer_mlock(host.plugin_events);
} else {
fprintf(stderr, "No appropriate UI found\n");
}
@@ -456,27 +492,27 @@ main(int argc, char** argv)
/* Activate plugin and JACK */
lilv_instance_activate(host.instance);
jack_activate(host.jack_client);
+ host.sample_rate = jack_get_sample_rate(host.jack_client);
- SuilHost* ui_host = NULL;
- SuilInstance* ui_instance = NULL;
- if (ui) {
+ SuilHost* ui_host = NULL;
+ if (host.ui) {
/* Instantiate UI */
ui_host = suil_host_new(lv2_ui_write, NULL, NULL, NULL);
- ui_instance = suil_instance_new(
+ host.ui_instance = suil_instance_new(
ui_host,
&host,
lilv_node_as_uri(native_ui_type),
lilv_node_as_uri(lilv_plugin_get_uri(host.plugin)),
- lilv_node_as_uri(lilv_ui_get_uri(ui)),
+ lilv_node_as_uri(lilv_ui_get_uri(host.ui)),
lilv_node_as_uri(ui_type),
- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui))),
- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(ui))),
+ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(host.ui))),
+ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(host.ui))),
features);
}
/* Run UI (or prompt at console) */
- jalv_open_ui(&host, ui_instance);
+ jalv_open_ui(&host, host.ui_instance);
/* Wait for finish signal from UI or signal handler */
sem_wait(&exit_sem);
@@ -498,7 +534,8 @@ main(int argc, char** argv)
/* Clean up */
free(host.ports);
- jack_ringbuffer_free(host.events);
+ jack_ringbuffer_free(host.ui_events);
+ jack_ringbuffer_free(host.plugin_events);
lilv_node_free(native_ui_type);
lilv_node_free(host.input_class);
lilv_node_free(host.output_class);
@@ -508,7 +545,7 @@ main(int argc, char** argv)
lilv_node_free(host.midi_class);
lilv_node_free(host.optional);
symap_free(host.symap);
- suil_instance_free(ui_instance);
+ suil_instance_free(host.ui_instance);
suil_host_free(ui_host);
lilv_world_free(world);
diff --git a/src/jalv_gtk2.c b/src/jalv_gtk2.c
index 72c8a1a..59e9772 100644
--- a/src/jalv_gtk2.c
+++ b/src/jalv_gtk2.c
@@ -46,10 +46,10 @@ jalv_open_ui(Jalv* jalv,
SuilInstance* instance)
{
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
+
g_signal_connect(window, "destroy",
G_CALLBACK(destroy), NULL);
-
+
gtk_container_set_border_width(GTK_CONTAINER(window), 8);
if (instance) {
@@ -57,11 +57,11 @@ jalv_open_ui(Jalv* jalv,
gtk_container_add(GTK_CONTAINER(window), widget);
} else {
GtkWidget* button = gtk_button_new_with_label("Close");
-
+
g_signal_connect_swapped(button, "clicked",
G_CALLBACK(gtk_widget_destroy),
window);
-
+
gtk_container_add(GTK_CONTAINER(window), button);
}
@@ -69,7 +69,10 @@ jalv_open_ui(Jalv* jalv,
gtk_window_set_resizable(GTK_WINDOW(window), false);
gtk_widget_show_all(window);
-
+
+ g_timeout_add(1000 / JALV_UI_UPDATE_HZ,
+ (GSourceFunc)jalv_emit_ui_events, jalv);
+
gtk_main();
sem_post(jalv->done);
return 0;
diff --git a/src/jalv_internal.h b/src/jalv_internal.h
index 5ee7755..950d1b7 100644
--- a/src/jalv_internal.h
+++ b/src/jalv_internal.h
@@ -32,16 +32,23 @@
extern "C" {
#endif
+#define JALV_UI_UPDATE_HZ 15
+
typedef struct {
LilvWorld* world; /**< Lilv World */
Symap* symap; /**< Symbol (URI) map */
jack_client_t* jack_client; /**< Jack client */
- jack_ringbuffer_t* events; /**< Control change events */
+ jack_ringbuffer_t* ui_events; /**< Port events from UI */
+ jack_ringbuffer_t* plugin_events; /**< Port events from plugin */
sem_t* done; /**< Exit semaphore */
const LilvPlugin* plugin; /**< Plugin class (RDF data) */
+ const LilvUI* ui; /**< Plugin UI (RDF data) */
LilvInstance* instance; /**< Plugin instance (shared library) */
- uint32_t num_ports; /**< Size of the two following arrays: */
+ SuilInstance* ui_instance; /**< Plugin UI instance (shared library) */
struct Port* ports; /**< Port array of size num_ports */
+ uint32_t num_ports; /**< Size of the two following arrays: */
+ jack_nframes_t sample_rate; /**< Sample rate */
+ jack_nframes_t event_delta_t; /**< Frames since last update sent to UI */
LilvNode* input_class; /**< Input port class (URI) */
LilvNode* output_class; /**< Output port class (URI) */
LilvNode* control_class; /**< Control port class (URI) */
@@ -62,6 +69,9 @@ int
jalv_open_ui(Jalv* jalv,
SuilInstance* instance);
+bool
+jalv_emit_ui_events(Jalv* jalv);
+
#ifdef __cplusplus
} // extern "C"
diff --git a/src/jalv_qt4.cpp b/src/jalv_qt4.cpp
index 79cf985..eac67ec 100644
--- a/src/jalv_qt4.cpp
+++ b/src/jalv_qt4.cpp
@@ -19,6 +19,7 @@
#include <QApplication>
#include <QPushButton>
#include <QMainWindow>
+#include <QTimer>
static QApplication* app = NULL;
@@ -37,6 +38,18 @@ jalv_native_ui_type(Jalv* jalv)
"http://lv2plug.in/ns/extensions/ui#Qt4UI");
}
+class Timer : public QTimer {
+public:
+ Timer(Jalv* j) : jalv(j) {}
+
+ void timerEvent(QTimerEvent* e) {
+ jalv_emit_ui_events(jalv);
+ }
+
+private:
+ Jalv* jalv;
+};
+
int
jalv_open_ui(Jalv* jalv,
SuilInstance* instance)
@@ -51,6 +64,9 @@ jalv_open_ui(Jalv* jalv,
}
app->connect(app, SIGNAL(lastWindowClosed()), app, SLOT(quit()));
+ Timer* timer = new Timer(jalv);
+ timer->start(1000 / JALV_UI_UPDATE_HZ);
+
int ret = app->exec();
sem_post(jalv->done);
return ret;