From adf2092b3da83d837001711614570f6b9996f538 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 2 Jul 2016 10:24:51 +0200 Subject: [PATCH] lv2: add support for saving presets Plugns supporting the state interface can now save their presets under '.lv2'. --- ext/lv2/gstlv2filter.c | 8 +++- ext/lv2/gstlv2source.c | 8 +++- ext/lv2/gstlv2utils.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++-- ext/lv2/gstlv2utils.h | 3 ++ 4 files changed, 112 insertions(+), 8 deletions(-) diff --git a/ext/lv2/gstlv2filter.c b/ext/lv2/gstlv2filter.c index bbdd5f6..0ef6ade 100644 --- a/ext/lv2/gstlv2filter.c +++ b/ext/lv2/gstlv2filter.c @@ -91,7 +91,9 @@ gst_lv2_filter_load_preset (GstPreset * preset, const gchar * name) static gboolean gst_lv2_filter_save_preset (GstPreset * preset, const gchar * name) { - return FALSE; + GstLV2Filter *self = (GstLV2Filter *) preset; + + return gst_lv2_save_preset (&self->lv2, (GstObject *) self, name); } static gboolean @@ -104,7 +106,9 @@ gst_lv2_filter_rename_preset (GstPreset * preset, const gchar * old_name, static gboolean gst_lv2_filter_delete_preset (GstPreset * preset, const gchar * name) { - return FALSE; + GstLV2Filter *self = (GstLV2Filter *) preset; + + return gst_lv2_delete_preset (&self->lv2, (GstObject *) self, name); } static gboolean diff --git a/ext/lv2/gstlv2source.c b/ext/lv2/gstlv2source.c index 92d73e2..56f9911 100644 --- a/ext/lv2/gstlv2source.c +++ b/ext/lv2/gstlv2source.c @@ -108,7 +108,9 @@ gst_lv2_source_load_preset (GstPreset * preset, const gchar * name) static gboolean gst_lv2_source_save_preset (GstPreset * preset, const gchar * name) { - return FALSE; + GstLV2Source *self = (GstLV2Source *) preset; + + return gst_lv2_save_preset (&self->lv2, (GstObject *) self, name); } static gboolean @@ -121,7 +123,9 @@ gst_lv2_source_rename_preset (GstPreset * preset, const gchar * old_name, static gboolean gst_lv2_source_delete_preset (GstPreset * preset, const gchar * name) { - return FALSE; + GstLV2Source *self = (GstLV2Source *) preset; + + return gst_lv2_delete_preset (&self->lv2, (GstObject *) self, name); } static gboolean diff --git a/ext/lv2/gstlv2utils.c b/ext/lv2/gstlv2utils.c index e5b6e8e..017d449 100644 --- a/ext/lv2/gstlv2utils.c +++ b/ext/lv2/gstlv2utils.c @@ -225,7 +225,6 @@ set_port_value (const char *port_symbol, void *data, const void *value, g_object_set (obj, prop_name, fvalue, NULL); } - gboolean gst_lv2_load_preset (GstLV2 * lv2, GstObject * obj, const gchar * name) { @@ -242,26 +241,120 @@ gst_lv2_load_preset (GstLV2 * lv2, GstObject * obj, const gchar * name) return FALSE; } -#if 0 +static const void * +get_port_value (const char *port_symbol, void *data, uint32_t * size, + uint32_t * type) +{ + gpointer *user_data = (gpointer *) data; + GstLV2Class *klass = user_data[0]; + GstObject *obj = user_data[1]; + gchar *prop_name = g_hash_table_lookup (klass->sym_to_name, port_symbol); + static gfloat fvalue; + + if (!prop_name) { + GST_WARNING_OBJECT (obj, "Preset port '%s' is missing", port_symbol); + *size = *type = 0; + return NULL; + } + + *size = sizeof (float); + *type = forge.Float; + g_object_get (obj, prop_name, &fvalue, NULL); + /* FIXME: can we return &lv2->ports.{in,out}[x]; */ + return &fvalue; +} + gboolean gst_lv2_save_preset (GstLV2 * lv2, GstObject * obj, const gchar * name) { - return FALSE; + gchar *filename, *basename, *bundle, *dir, *tmp_dir, *s; + gpointer user_data[] = { lv2->klass, obj }; + GstElementFactory *factory; + LilvState *state; + LilvNode *bundle_dir; + LilvInstance *instance = lv2->instance; + gboolean res; + + factory = gst_element_get_factory ((GstElement *) obj); + basename = g_strdup (gst_element_factory_get_metadata (factory, + GST_ELEMENT_METADATA_LONGNAME)); + s = basename; + while ((s = strchr (s, ' '))) { + *s = '_'; + } + + filename = g_strjoin (NULL, name, ".ttl", NULL); + bundle = g_strjoin (NULL, basename, "_", name, ".preset.lv2", NULL); + /* dir needs to end on a dir separator for the lilv_new_file_uri() to work */ + dir = + g_build_filename (g_get_home_dir (), ".lv2", bundle, G_DIR_SEPARATOR_S, + NULL); + tmp_dir = g_dir_make_tmp ("gstlv2-XXXXXX", NULL); + g_mkdir_with_parents (dir, 0750); + + if (!instance) { + /* instance is NULL until we play!! */ + instance = lilv_plugin_instantiate (lv2->klass->plugin, GST_AUDIO_DEF_RATE, + lv2_features); + } + + state = lilv_state_new_from_instance (lv2->klass->plugin, instance, &lv2_map, + tmp_dir, dir, dir, dir, get_port_value, user_data, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE, NULL); + + lilv_state_set_label (state, name); + + res = lilv_state_save (world, &lv2_map, &lv2_unmap, state, /*uri */ NULL, dir, + filename) != 0; + + /* reload bundle into the world */ + bundle_dir = lilv_new_file_uri (world, NULL, dir); + lilv_world_unload_bundle (world, bundle_dir); + lilv_world_load_bundle (world, bundle_dir); + lilv_node_free (bundle_dir); + + lilv_world_load_resource (world, lilv_state_get_uri (state)); + g_hash_table_insert (lv2->presets, g_strdup (name), + lilv_node_duplicate (lilv_state_get_uri (state))); + + lilv_state_free (state); + if (!lv2->instance) { + lilv_instance_free (instance); + } + + g_free (tmp_dir); + g_free (dir); + g_free (bundle); + g_free (filename); + g_free (basename); + + return res; } +#if 0 gboolean gst_lv2_rename_preset (GstLV2 * lv2, GstObject * obj, const gchar * old_name, const gchar * new_name) { + /* need to relabel the preset */ return FALSE; } +#endif gboolean gst_lv2_delete_preset (GstLV2 * lv2, GstObject * obj, const gchar * name) { + LilvNode *preset = g_hash_table_lookup (lv2->presets, name); + LilvState *state = lilv_state_new_from_world (world, &lv2_map, preset); + + lilv_world_unload_resource (world, lilv_state_get_uri (state)); + lilv_state_delete (world, state); + lilv_state_free (state); + + g_hash_table_remove (lv2->presets, name); + return FALSE; } -#endif /* api helpers */ diff --git a/ext/lv2/gstlv2utils.h b/ext/lv2/gstlv2utils.h index 815bb11..b179e36 100644 --- a/ext/lv2/gstlv2utils.h +++ b/ext/lv2/gstlv2utils.h @@ -106,6 +106,9 @@ void gst_lv2_host_init (void); gchar **gst_lv2_get_preset_names (GstLV2 * lv2, GstObject * obj); gboolean gst_lv2_load_preset (GstLV2 * lv2, GstObject * obj, const gchar * name); +gboolean gst_lv2_save_preset (GstLV2 * lv2, GstObject * obj, const gchar * name); +gboolean gst_lv2_delete_preset (GstLV2 * lv2, GstObject * obj, const gchar * name); + void gst_lv2_init (GstLV2 * lv2, GstLV2Class * lv2_class); void gst_lv2_finalize (GstLV2 * lv2); -- 2.7.4