aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jalv.c16
-rw-r--r--src/jalv_gtk.c118
-rw-r--r--src/jalv_internal.h5
3 files changed, 116 insertions, 23 deletions
diff --git a/src/jalv.c b/src/jalv.c
index dcc1425..7d29777 100644
--- a/src/jalv.c
+++ b/src/jalv.c
@@ -50,6 +50,7 @@
#include "lv2/lv2plug.in/ns/ext/event/event.h"
#include "lv2/lv2plug.in/ns/ext/options/options.h"
#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
#include "lv2/lv2plug.in/ns/ext/time/time.h"
#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
@@ -194,9 +195,8 @@ create_port(Jalv* jalv,
const LilvNode* symbol = lilv_port_get_symbol(jalv->plugin,
port->lilv_port);
- const bool optional = lilv_port_has_property(jalv->plugin,
- port->lilv_port,
- jalv->nodes.lv2_connectionOptional);
+ const bool optional = lilv_port_has_property(
+ jalv->plugin, port->lilv_port, jalv->nodes.lv2_connectionOptional);
/* Set the port flow (input or output) */
if (lilv_port_is_a(jalv->plugin, port->lilv_port, jalv->nodes.lv2_InputPort)) {
@@ -249,6 +249,12 @@ jalv_create_ports(Jalv* jalv)
create_port(jalv, i, default_values[i]);
}
+ const LilvPort* control_input = lilv_plugin_get_port_by_designation(
+ jalv->plugin, jalv->nodes.lv2_InputPort, jalv->nodes.lv2_control);
+ if (control_input) {
+ jalv->control_in = lilv_port_get_index(jalv->plugin, control_input);
+ }
+
free(default_values);
}
@@ -805,6 +811,9 @@ main(int argc, char** argv)
jalv.urids.log_Trace = symap_map(jalv.symap, LV2_LOG__Trace);
jalv.urids.midi_MidiEvent = symap_map(jalv.symap, LV2_MIDI__MidiEvent);
jalv.urids.param_sampleRate = symap_map(jalv.symap, LV2_PARAMETERS__sampleRate);
+ jalv.urids.patch_Set = symap_map(jalv.symap, LV2_PATCH__Set);
+ jalv.urids.patch_property = symap_map(jalv.symap, LV2_PATCH__property);
+ jalv.urids.patch_value = symap_map(jalv.symap, LV2_PATCH__value);
jalv.urids.time_Position = symap_map(jalv.symap, LV2_TIME__Position);
jalv.urids.time_bar = symap_map(jalv.symap, LV2_TIME__bar);
jalv.urids.time_barBeat = symap_map(jalv.symap, LV2_TIME__barBeat);
@@ -857,6 +866,7 @@ main(int argc, char** argv)
jalv.nodes.lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
jalv.nodes.lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
jalv.nodes.lv2_connectionOptional = lilv_new_uri(world, LV2_CORE__connectionOptional);
+ jalv.nodes.lv2_control = lilv_new_uri(world, LV2_CORE__control);
jalv.nodes.midi_MidiEvent = lilv_new_uri(world, LV2_MIDI__MidiEvent);
jalv.nodes.pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
jalv.nodes.rdfs_label = lilv_new_uri(world, LILV_NS_RDFS "label");
diff --git a/src/jalv_gtk.c b/src/jalv_gtk.c
index 25de946..5c126cc 100644
--- a/src/jalv_gtk.c
+++ b/src/jalv_gtk.c
@@ -18,10 +18,16 @@
#include <gtk/gtk.h>
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
#include "lv2/lv2plug.in/ns/ext/port-props/port-props.h"
#include "jalv_internal.h"
+typedef struct {
+ Jalv* jalv;
+ LilvNode* property;
+} PropertyRecord;
+
static GtkWidget*
new_box(gboolean horizontal, gint spacing)
{
@@ -322,6 +328,36 @@ toggle_changed(GtkToggleButton* button, gpointer data)
return FALSE;
}
+static void
+file_changed(GtkFileChooserButton* widget,
+ gpointer data)
+{
+ PropertyRecord* record = (PropertyRecord*)data;
+ Jalv* jalv = record->jalv;
+ const char* property = lilv_node_as_uri(record->property);
+ const char* filename = gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(widget));
+
+ // Copy forge since it is used by process thread
+ LV2_Atom_Forge forge = jalv->forge;
+ LV2_Atom_Forge_Frame frame;
+ uint8_t buf[1024];
+ lv2_atom_forge_set_buffer(&forge, buf, sizeof(buf));
+
+ lv2_atom_forge_blank(&forge, &frame, 1, jalv->urids.patch_Set);
+ lv2_atom_forge_property_head(&forge, jalv->urids.patch_property, 0);
+ lv2_atom_forge_urid(&forge, jalv->map.map(jalv, property));
+ lv2_atom_forge_property_head(&forge, jalv->urids.patch_value, 0);
+ lv2_atom_forge_path(&forge, filename, strlen(filename));
+
+ const LV2_Atom* atom = lv2_atom_forge_deref(&forge, frame.ref);
+ jalv_ui_write(jalv,
+ jalv->control_in,
+ lv2_atom_total_size(atom),
+ jalv->urids.atom_eventTransfer,
+ atom);
+}
+
static gchar*
scale_format(GtkScale* scale, gdouble value, gpointer user_data)
{
@@ -422,13 +458,48 @@ make_toggle(struct Port* port)
}
static GtkWidget*
+make_file_chooser(Jalv* jalv, const LilvNode* property)
+{
+ GtkWidget* button = gtk_file_chooser_button_new(
+ lilv_node_as_uri(property), GTK_FILE_CHOOSER_ACTION_OPEN);
+ PropertyRecord* record = (PropertyRecord*)malloc(sizeof(PropertyRecord));
+ record->jalv = jalv;
+ record->property = lilv_node_duplicate(property);
+ g_signal_connect(
+ G_OBJECT(button), "file-set", G_CALLBACK(file_changed), record);
+ return button;
+}
+
+static void
+add_control_row(GtkWidget* table,
+ int row,
+ const char* name,
+ GtkWidget* control)
+{
+ GtkWidget* label = gtk_label_new(NULL);
+ gchar* markup = g_markup_printf_escaped(
+ "<span font_weight=\"bold\">%s:</span>", name);
+ gtk_label_set_markup(GTK_LABEL(label), markup);
+ g_free(markup);
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(table),
+ label,
+ 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL | GTK_EXPAND, 15, 15);
+ gtk_table_attach(GTK_TABLE(table), control,
+ 1, 2, row, row + 1,
+ GTK_FILL | GTK_EXPAND, 0, 0, 0);
+}
+
+static GtkWidget*
build_control_widget(Jalv* jalv, GtkWidget* window)
{
- LilvNode* lv2_sampleRate = lilv_new_uri(jalv->world, LV2_CORE__sampleRate);
- LilvNode* lv2_integer = lilv_new_uri(jalv->world, LV2_CORE__integer);
- LilvNode* lv2_toggled = lilv_new_uri(jalv->world, LV2_CORE__toggled);
LilvNode* lv2_enum = lilv_new_uri(jalv->world, LV2_CORE__enumeration);
+ LilvNode* lv2_integer = lilv_new_uri(jalv->world, LV2_CORE__integer);
LilvNode* lv2_log = lilv_new_uri(jalv->world, LV2_PORT_PROPS__logarithmic);
+ LilvNode* lv2_sampleRate = lilv_new_uri(jalv->world, LV2_CORE__sampleRate);
+ LilvNode* lv2_toggled = lilv_new_uri(jalv->world, LV2_CORE__toggled);
+ LilvNode* patch_writable = lilv_new_uri(jalv->world, LV2_PATCH__writable);
LilvNode* rdfs_comment = lilv_new_uri(jalv->world, LILV_NS_RDFS "comment");
GtkWidget* port_table = gtk_table_new(jalv->num_ports, 2, false);
float* mins = (float*)calloc(jalv->num_ports, sizeof(float));
@@ -497,31 +568,38 @@ build_control_widget(Jalv* jalv, GtkWidget* window)
}
lilv_nodes_free(comments);
- /* Add control table row */
- GtkWidget* label = gtk_label_new(NULL);
- gchar* markup = g_markup_printf_escaped(
- "<span font_weight=\"bold\">%s:</span>",
- lilv_node_as_string(name));
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_table_attach(GTK_TABLE(port_table),
- label,
- 0, 1, i, i + 1,
- GTK_FILL, GTK_FILL | GTK_EXPAND, 15, 15);
- gtk_table_attach(GTK_TABLE(port_table), control,
- 1, 2, i, i + 1,
- GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ add_control_row(port_table, i, lilv_node_as_string(name), control);
+
lilv_node_free(name);
}
+ LilvNodes* properties = lilv_world_find_nodes(
+ jalv->world,
+ lilv_plugin_get_uri(jalv->plugin),
+ patch_writable,
+ NULL);
+ LILV_FOREACH(nodes, p, properties) {
+ const LilvNode* property = lilv_nodes_get(properties, p);
+ LilvNode* label = lilv_nodes_get_first(
+ lilv_world_find_nodes(
+ jalv->world, property, jalv->nodes.rdfs_label, NULL));
+
+ GtkWidget* control = make_file_chooser(jalv, property);
+ add_control_row(
+ port_table, num_controls++,
+ label ? lilv_node_as_string(label) : lilv_node_as_uri(property),
+ control);
+ }
+ lilv_nodes_free(properties);
+
free(mins);
free(maxs);
+ lilv_node_free(rdfs_comment);
+ lilv_node_free(patch_writable);
+ lilv_node_free(lv2_toggled);
lilv_node_free(lv2_sampleRate);
lilv_node_free(lv2_integer);
- lilv_node_free(lv2_toggled);
lilv_node_free(lv2_enum);
- lilv_node_free(rdfs_comment);
if (num_controls > 0) {
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
diff --git a/src/jalv_internal.h b/src/jalv_internal.h
index 76de642..64c4373 100644
--- a/src/jalv_internal.h
+++ b/src/jalv_internal.h
@@ -100,6 +100,9 @@ typedef struct {
LV2_URID log_Trace;
LV2_URID midi_MidiEvent;
LV2_URID param_sampleRate;
+ LV2_URID patch_Set;
+ LV2_URID patch_property;
+ LV2_URID patch_value;
LV2_URID time_Position;
LV2_URID time_bar;
LV2_URID time_barBeat;
@@ -120,6 +123,7 @@ typedef struct {
LilvNode* lv2_InputPort;
LilvNode* lv2_OutputPort;
LilvNode* lv2_connectionOptional;
+ LilvNode* lv2_control;
LilvNode* midi_MidiEvent;
LilvNode* pset_Preset;
LilvNode* rdfs_label;
@@ -175,6 +179,7 @@ typedef struct {
struct Port* ports; ///< Port array of size num_ports
uint32_t block_length; ///< Jack buffer size (block length)
size_t midi_buf_size; ///< Size of MIDI port buffers
+ uint32_t control_in; ///< Index of control input port
uint32_t num_ports; ///< Size of the two following arrays:
uint32_t longest_sym; ///< Longest port symbol
uint32_t ui_update_hz; ///< Frequency of UI updates