aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-12-16 20:15:21 +0000
committerDavid Robillard <d@drobilla.net>2011-12-16 20:15:21 +0000
commit102ba23f77650bbeaceca98c3a6539f1e637b4f7 (patch)
tree88d7032347b31ab8e79e992e2b5ab0c002aa6ccd /src
parent1849c5d7f96db8f2dfed04208e0c49685c50d4a4 (diff)
downloadjalv-102ba23f77650bbeaceca98c3a6539f1e637b4f7.tar.gz
jalv-102ba23f77650bbeaceca98c3a6539f1e637b4f7.tar.bz2
jalv-102ba23f77650bbeaceca98c3a6539f1e637b4f7.zip
Support presets in Gtk UI.
git-svn-id: http://svn.drobilla.net/lad/trunk/jalv@3878 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/jalv.c24
-rw-r--r--src/jalv_gtk2.c54
-rw-r--r--src/jalv_internal.h23
-rw-r--r--src/presets.c94
4 files changed, 184 insertions, 11 deletions
diff --git a/src/jalv.c b/src/jalv.c
index f1fb6c2..de40077 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -46,6 +46,7 @@
#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
#define NS_MIDI "http://lv2plug.in/ns/ext/midi#"
+#define NS_PSET "http://lv2plug.in/ns/ext/presets#"
sem_t exit_sem; /**< Exit semaphore */
@@ -144,8 +145,9 @@ create_port(Jalv* host,
port->lilv_port = lilv_plugin_get_port_by_index(host->plugin, port_index);
port->jack_port = NULL;
- port->control = 0.0f;
port->evbuf = NULL;
+ port->index = port_index;
+ port->control = 0.0f;
port->flow = FLOW_UNKNOWN;
/* Get the port symbol for console printing */
@@ -446,12 +448,12 @@ jack_session_cb(jack_session_event_t* event, void* arg)
}
#endif /* JALV_JACK_SESSION */
-static void
-lv2_ui_write(SuilController controller,
- uint32_t port_index,
- uint32_t buffer_size,
- uint32_t protocol,
- const void* buffer)
+void
+jalv_ui_write(SuilController controller,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t protocol,
+ const void* buffer)
{
Jalv* host = (Jalv*)controller;
@@ -477,11 +479,13 @@ lv2_ui_write(SuilController controller,
ev->protocol = protocol;
ev->size = buffer_size;
memcpy(ev->body, buffer, buffer_size);
+ #if 0
printf("WRITE: ");
for (uint32_t i = 0; i < sizeof(buf); ++i) {
printf("%c", buf[i]);
}
printf("\n");
+ #endif
jack_ringbuffer_write(host->ui_events, buf, sizeof(buf));
}
@@ -558,6 +562,8 @@ main(int argc, char** argv)
host.event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
host.aevent_class = lilv_new_uri(world, NS_ATOM "EventPort");
host.midi_class = lilv_new_uri(world, LILV_URI_MIDI_EVENT);
+ host.preset_class = lilv_new_uri(world, NS_PSET "Preset");
+ host.label_pred = lilv_new_uri(world, LILV_NS_RDFS "label");
host.optional = lilv_new_uri(world, LILV_NS_LV2
"connectionOptional");
@@ -694,7 +700,7 @@ main(int argc, char** argv)
SuilHost* ui_host = NULL;
if (host.ui) {
/* Instantiate UI */
- ui_host = suil_host_new(lv2_ui_write, NULL, NULL, NULL);
+ ui_host = suil_host_new(jalv_ui_write, NULL, NULL, NULL);
host.ui_instance = suil_instance_new(
ui_host,
@@ -755,6 +761,8 @@ main(int argc, char** argv)
lilv_node_free(host.audio_class);
lilv_node_free(host.event_class);
lilv_node_free(host.midi_class);
+ lilv_node_free(host.preset_class);
+ lilv_node_free(host.label_pred);
lilv_node_free(host.optional);
symap_free(host.symap);
suil_instance_free(host.ui_instance);
diff --git a/src/jalv_gtk2.c b/src/jalv_gtk2.c
index fae3f6a..c56bab1 100644
--- a/src/jalv_gtk2.c
+++ b/src/jalv_gtk2.c
@@ -79,13 +79,55 @@ on_save_activate(GtkWidget* widget, void* ptr)
}
static void
-on_quit_activate(GtkWidget* widget,
- gpointer data)
+on_quit_activate(GtkWidget* widget, gpointer data)
{
GtkWidget* window = (GtkWidget*)data;
gtk_widget_destroy(window);
}
+typedef struct {
+ Jalv* jalv;
+ LilvNode* preset;
+} PresetRecord;
+
+static void
+on_preset_activate(GtkWidget* widget, gpointer data)
+{
+ PresetRecord* record = (PresetRecord*)data;
+ jalv_apply_preset(record->jalv, record->preset);
+}
+
+static void
+on_preset_destroy(gpointer data, GClosure* closure)
+{
+ PresetRecord* record = (PresetRecord*)data;
+ lilv_node_free(record->preset);
+ free(record);
+}
+
+static int
+add_preset_to_menu(Jalv* jalv,
+ const LilvNode* node,
+ const LilvNode* title,
+ void* data)
+{
+ GtkWidget* presets_menu = GTK_WIDGET(data);
+ const char* label = lilv_node_as_string(title);
+ GtkWidget* item = gtk_menu_item_new_with_label(label);
+
+ PresetRecord* record = (PresetRecord*)malloc(sizeof(PresetRecord));
+ record->jalv = jalv;
+ record->preset = lilv_node_duplicate(node);
+
+ g_signal_connect_data(G_OBJECT(item), "activate",
+ G_CALLBACK(on_preset_activate),
+ record, on_preset_destroy,
+ 0);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(presets_menu), item);
+ return 0;
+}
+
int
jalv_ui_resize(Jalv* jalv, int width, int height)
{
@@ -124,6 +166,14 @@ jalv_open_ui(Jalv* jalv,
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), save);
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), quit);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file);
+
+ GtkWidget* presets = gtk_menu_item_new_with_mnemonic("_Presets");
+ GtkWidget* presets_menu = gtk_menu_new();
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(presets), presets_menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), presets);
+
+ jalv_load_presets(jalv, add_preset_to_menu, presets_menu);
+
gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(quit), "activate",
diff --git a/src/jalv_internal.h b/src/jalv_internal.h
index 8ecb44c..d44b5c5 100644
--- a/src/jalv_internal.h
+++ b/src/jalv_internal.h
@@ -55,8 +55,9 @@ struct Port {
enum PortType type;
enum PortFlow flow;
jack_port_t* jack_port; /**< For audio/MIDI ports, otherwise NULL */
- float control; /**< For control ports, otherwise 0.0f */
LV2_Evbuf* evbuf; /**< For MIDI ports, otherwise NULL */
+ uint32_t index; /**< Port index */
+ float control; /**< For control ports, otherwise 0.0f */
bool old_api; /**< True for event, false for atom */
};
@@ -105,6 +106,8 @@ typedef struct {
LilvNode* event_class; /**< Event port class (URI) */
LilvNode* aevent_class; /**< Atom event port class (URI) */
LilvNode* midi_class; /**< MIDI event class (URI) */
+ LilvNode* preset_class; /**< Preset class (URI) */
+ LilvNode* label_pred; /**< rdfs:label */
LilvNode* optional; /**< lv2:connectionOptional port property */
uint32_t midi_event_id; /**< MIDI event class ID */
uint32_t atom_prot_id; /**< Atom protocol ID */
@@ -128,12 +131,30 @@ int
jalv_open_ui(Jalv* jalv,
SuilInstance* instance);
+void
+jalv_ui_write(SuilController controller,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t protocol,
+ const void* buffer);
+
bool
jalv_emit_ui_events(Jalv* jalv);
int
jalv_ui_resize(Jalv* jalv, int width, int height);
+typedef int (*PresetSink)(Jalv* jalv,
+ const LilvNode* node,
+ const LilvNode* title,
+ void* data);
+
+int
+jalv_load_presets(Jalv* jalv, PresetSink sink, void* data);
+
+int
+jalv_apply_preset(Jalv* jalv, LilvNode* preset);
+
void
jalv_save(Jalv* jalv, const char* dir);
diff --git a/src/presets.c b/src/presets.c
new file mode 100644
index 0000000..bf7fd78
--- /dev/null
+++ b/src/presets.c
@@ -0,0 +1,94 @@
+/*
+ Copyright 2007-2011 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.
+*/
+
+#include "jalv-config.h"
+#include "jalv_internal.h"
+
+#define NS_LV2 "http://lv2plug.in/ns/lv2core#"
+#define NS_PSET "http://lv2plug.in/ns/ext/presets#"
+
+#define USTR(s) ((const uint8_t*)s)
+
+int
+jalv_load_presets(Jalv* jalv, PresetSink sink, void* data)
+{
+ LilvNodes* presets = lilv_plugin_get_related(jalv->plugin,
+ jalv->preset_class);
+ LILV_FOREACH(nodes, i, presets) {
+ const LilvNode* preset = lilv_nodes_get(presets, i);
+ lilv_world_load_resource(jalv->world, preset);
+ LilvNodes* titles = lilv_world_find_nodes(
+ jalv->world, preset, jalv->label_pred, NULL);
+ if (titles) {
+ const LilvNode* title = lilv_nodes_get_first(titles);
+ sink(jalv, preset, title, data);
+ lilv_nodes_free(titles);
+ } else {
+ fprintf(stderr, "Preset <%s> has no rdfs:label\n",
+ lilv_node_as_string(lilv_nodes_get(presets, i)));
+ }
+ }
+ lilv_nodes_free(presets);
+
+ return 0;
+}
+
+static inline const LilvNode*
+get_value(LilvWorld* world, const LilvNode* subject, const LilvNode* predicate)
+{
+ LilvNodes* vs = lilv_world_find_nodes(world, subject, predicate, NULL);
+ return vs ? lilv_nodes_get_first(vs) : NULL;
+}
+
+int
+jalv_apply_preset(Jalv* jalv, LilvNode* preset)
+{
+ LilvNode* lv2_port = lilv_new_uri(jalv->world, NS_LV2 "port");
+ LilvNode* lv2_symbol = lilv_new_uri(jalv->world, NS_LV2 "symbol");
+ LilvNode* pset_value = lilv_new_uri(jalv->world, NS_PSET "value");
+
+ LilvNodes* ports = lilv_world_find_nodes(
+ jalv->world, preset, lv2_port, NULL);
+ LILV_FOREACH(nodes, i, ports) {
+ const LilvNode* port = lilv_nodes_get(ports, i);
+ const LilvNode* symbol = get_value(jalv->world, port, lv2_symbol);
+ const LilvNode* value = get_value(jalv->world, port, pset_value);
+ if (!symbol) {
+ fprintf(stderr, "error: Preset port missing symbol.\n");
+ } else if (!value) {
+ fprintf(stderr, "error: Preset port missing value.\n");
+ } else if (!lilv_node_is_float(value) && !lilv_node_is_int(value)) {
+ fprintf(stderr, "error: Preset port value is not a number.\n");
+ } else {
+ const char* sym = lilv_node_as_string(symbol);
+ struct Port* p = jalv_port_by_symbol(jalv, sym);
+ if (p) {
+ const float fvalue = lilv_node_as_float(value);
+ jalv_ui_write(jalv, p->index, sizeof(float), 0, &fvalue);
+ } else {
+ fprintf(stderr, "error: Preset port `%s' is missing\n", sym);
+ }
+ }
+ }
+ lilv_nodes_free(ports);
+
+ lilv_node_free(pset_value);
+ lilv_node_free(preset);
+ lilv_node_free(lv2_symbol);
+ lilv_node_free(lv2_port);
+
+ return 0;
+}