more work on the suprisingly ongoing filename/path/origin issue
[ardour.git] / libs / ardour / lv2_plugin.cc
index 3c557b7d2fa016d95a94eea9dd6e2eabd7b4a606..29af02c696221e5b2150ba0a1f2658549d792bc2 100644 (file)
 
 #include "libardour-config.h"
 
-#include "ardour/types.h"
 #include "ardour/audio_buffer.h"
 #include "ardour/audioengine.h"
 #include "ardour/debug.h"
 #include "ardour/lv2_plugin.h"
 #include "ardour/session.h"
 #include "ardour/tempo.h"
+#include "ardour/types.h"
+#include "ardour/utils.h"
 #include "ardour/worker.h"
 
 #include "i18n.h"
@@ -175,7 +176,7 @@ work_respond(LV2_Worker_Respond_Handle handle,
 /* log extension */
 
 static int
-log_vprintf(LV2_Log_Handle handle,
+log_vprintf(LV2_Log_Handle /*handle*/,
             LV2_URID       type,
             const char*    fmt,
             va_list        args)
@@ -214,7 +215,7 @@ struct LV2Plugin::Impl {
        /** Find the LV2 input port with the given designation.
         * If found, bufptrs[port_index] will be set to bufptr.
         */
-       LilvPort* designated_input (const char* uri, void** bufptrs[], void** bufptr);
+       const LilvPort* designated_input (const char* uri, void** bufptrs[], void** bufptr);
 
        const LilvPlugin*           plugin;
        const LilvUI*               ui;
@@ -288,6 +289,8 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _log_feature.URI             = LV2_LOG__log;
        _work_schedule_feature.URI   = LV2_WORKER__schedule;
        _work_schedule_feature.data  = NULL;
+       _def_state_feature.URI       = LV2_STATE_PREFIX "loadDefaultState";  // Post LV2-1.2.0
+       _def_state_feature.data      = NULL;
 
        const LilvPlugin* plugin = _impl->plugin;
 
@@ -301,7 +304,7 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        lilv_node_free(state_uri);
        lilv_node_free(state_iface_uri);
 
-       _features    = (LV2_Feature**)calloc(10, sizeof(LV2_Feature*));
+       _features    = (LV2_Feature**)calloc(11, sizeof(LV2_Feature*));
        _features[0] = &_instance_access_feature;
        _features[1] = &_data_access_feature;
        _features[2] = &_make_path_feature;
@@ -310,9 +313,13 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
        _features[5] = _uri_map.urid_unmap_feature();
        _features[6] = &_log_feature;
 
+       unsigned n_features = 7;
+#ifdef HAVE_NEW_LV2
+       _features[n_features++] = &_def_state_feature;
+#endif
+
        lv2_atom_forge_init(&_impl->forge, _uri_map.urid_map());
 
-       unsigned n_features = 7;
 #ifdef HAVE_NEW_LV2
        LV2_URID atom_Int = _uri_map.uri_to_id(LV2_ATOM__Int);
        LV2_Options_Option options[] = {
@@ -384,6 +391,15 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
                throw failed_constructor();
        }
 
+#ifdef HAVE_NEW_LILV
+       // Load default state
+       LilvState* state = lilv_state_new_from_world(
+               _world.world, _uri_map.urid_map(), lilv_plugin_get_uri(_impl->plugin));
+       if (state && _has_state_interface) {
+               lilv_state_restore(state, _impl->instance, NULL, NULL, 0, NULL);
+       }
+#endif
+
        _sample_rate = rate;
 
        const uint32_t num_ports = this->num_ports();
@@ -946,38 +962,38 @@ LV2Plugin::find_presets()
        lilv_node_free(lv2_appliesTo);
 }
 
-bool
-LV2Plugin::load_preset(PresetRecord r)
+static void
+set_port_value(const char* port_symbol,
+               void*       user_data,
+               const void* value,
+               uint32_t    /*size*/,
+               uint32_t    type)
 {
-       std::map<std::string,uint32_t>::iterator it;
-
-       LilvNode* lv2_port   = lilv_new_uri(_world.world, LILV_NS_LV2 "port");
-       LilvNode* lv2_symbol = lilv_new_uri(_world.world, LILV_NS_LV2 "symbol");
-       LilvNode* preset     = lilv_new_uri(_world.world, r.uri.c_str());
-       LilvNode* pset_value = lilv_new_uri(_world.world, LV2_PRESETS__value);
-
-       LilvNodes* ports = lilv_world_find_nodes(_world.world, preset, lv2_port, NULL);
-       LILV_FOREACH(nodes, i, ports) {
-               const LilvNode* port   = lilv_nodes_get(ports, i);
-               const LilvNode* symbol = get_value(_world.world, port, lv2_symbol);
-               const LilvNode* value  = get_value(_world.world, port, pset_value);
-               if (value && lilv_node_is_float(value)) {
-                       it = _port_indices.find(lilv_node_as_string(symbol));
-                       if (it != _port_indices.end()) {
-                               set_parameter(it->second,lilv_node_as_float(value));
-                       }
-               }
+       LV2Plugin* self = (LV2Plugin*)user_data;
+       if (type != 0 && type != self->_uri_map.uri_to_id(LV2_ATOM__Float)) {
+               return;  // TODO: Support non-float ports
        }
-       lilv_nodes_free(ports);
 
-       lilv_node_free(pset_value);
-       lilv_node_free(preset);
-       lilv_node_free(lv2_symbol);
-       lilv_node_free(lv2_port);
+       const uint32_t port_index = self->port_index(port_symbol);
+       if (port_index != (uint32_t)-1) {
+               self->set_parameter(port_index, *(const float*)value);
+       }
+}
 
-       Plugin::load_preset(r);
+bool
+LV2Plugin::load_preset(PresetRecord r)
+{
+       LilvWorld* world = _world.world;
+       LilvNode*  pset  = lilv_new_uri(world, r.uri.c_str());
+       LilvState* state = lilv_state_new_from_world(world, _uri_map.urid_map(), pset);
 
-       return true;
+       if (state) {
+               lilv_state_restore(state, _impl->instance, set_port_value, this, 0, NULL);
+               lilv_state_free(state);
+       }
+
+       lilv_node_free(pset);
+       return state;
 }
 
 const void*
@@ -1008,42 +1024,40 @@ ARDOUR::lv2plugin_get_port_value(const char* port_symbol,
 std::string
 LV2Plugin::do_save_preset(string name)
 {
-       string pset_uri = uri();
-       pset_uri += "#";
-       pset_uri += name;
-
-       string save_dir = Glib::build_filename(
+       const string base_name = legalize_for_uri(name);
+       const string file_name = base_name + ".ttl";
+       const string bundle    = Glib::build_filename(
                Glib::get_home_dir(),
-               Glib::build_filename(".lv2", "presets")
-       );
+               Glib::build_filename(".lv2", base_name + ".lv2"));
 
        LilvState* state = lilv_state_new_from_instance(
                _impl->plugin,
                _impl->instance,
                _uri_map.urid_map(),
-               scratch_dir().c_str(),                  // file_dir
-               NULL,                                   // copy_dir
-               NULL,                                   // link_dir
-               save_dir.c_str(),                       // save_dir
-               lv2plugin_get_port_value,               // get_value
-               (void*) this,                           // user_data
-               LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, // flags
-               _features                               // features
+               scratch_dir().c_str(),                   // file_dir
+               bundle.c_str(),                          // copy_dir
+               bundle.c_str(),                          // link_dir
+               bundle.c_str(),                          // save_dir
+               lv2plugin_get_port_value,                // get_value
+               (void*)this,                             // user_data
+               LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE,  // flags
+               _features                                // features
        );
 
        lilv_state_set_label(state, name.c_str());
        lilv_state_save(
                _world.world,           // world
-               _uri_map.urid_map(),    // map
-               _uri_map.urid_unmap(),  // unmap
+               _uri_map.urid_map(),    // map
+               _uri_map.urid_unmap(),  // unmap
                state,                  // state
-               pset_uri.c_str(),       // uri
-               save_dir.c_str(),       // dir
-               (name + ".ttl").c_str() // filename
+               NULL,                   // uri (NULL = use file URI)
+               bundle.c_str(),         // dir
+               file_name.c_str()       // filename
        );
 
        lilv_state_free(state);
-       return pset_uri;
+
+       return Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
 }
 
 void
@@ -1797,10 +1811,10 @@ LV2Plugin::latency_compute_run()
        deactivate();
 }
 
-LilvPort*
+const LilvPort*
 LV2Plugin::Impl::designated_input (const char* uri, void** bufptrs[], void** bufptr)
 {
-       LilvPort* port        = NULL;
+       const LilvPort* port = NULL;
        LilvNode* designation = lilv_new_uri(_world.world, uri);
        port = lilv_plugin_get_port_by_designation(
                plugin, _world.lv2_InputPort, designation);