Correctly implement LV2 event URI mapping (event URI context is restricted to uint16_t).
authorDavid Robillard <d@drobilla.net>
Tue, 30 Nov 2010 23:42:58 +0000 (23:42 +0000)
committerDavid Robillard <d@drobilla.net>
Tue, 30 Nov 2010 23:42:58 +0000 (23:42 +0000)
Implement LV2 URI Unmap extension.

git-svn-id: svn://localhost/ardour2/branches/3.0@8139 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/uri_map.h
libs/ardour/lv2ext/lv2_uri_unmap.h [new file with mode: 0644]
libs/ardour/uri_map.cc

index 59de9b3dfd74ecbad4d273f43228b43e753349a6..d75836e619e17cc1512ce5af9effe2e2c235f711 100644 (file)
 
 #include <map>
 #include <string>
+
 #include <boost/utility.hpp>
-#include <slv2/slv2.h>
+
+#include "lv2.h"
 #include "lv2ext/lv2_uri_map.h"
+#include "lv2ext/lv2_uri_unmap.h"
 
 namespace ARDOUR {
 
@@ -41,17 +44,28 @@ public:
        uint32_t uri_to_id(const char* map,
                           const char* uri);
 
-private:
-       typedef std::map<std::string, uint32_t> Map;
+       const char* id_to_uri(const char* map,
+                             uint32_t id);
 
+private:
        static uint32_t uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
                                          const char*               map,
                                          const char*               uri);
 
-       LV2_Feature         uri_map_feature;
-       LV2_URI_Map_Feature uri_map_feature_data;
-       Map                 uri_map;
-       uint32_t            next_uri_id;
+       static const char* uri_unmap_id_to_uri(LV2_URI_Map_Callback_Data callback_data,
+                                              const char*               map,
+                                              const uint32_t            id);
+
+       typedef std::map<uint16_t, uint32_t> EventToGlobal;
+       typedef std::map<uint32_t, uint16_t> GlobalToEvent;
+
+       EventToGlobal _event_to_global;
+       GlobalToEvent _global_to_event;
+
+       LV2_Feature           uri_map_feature;
+       LV2_URI_Map_Feature   uri_map_feature_data;
+       LV2_Feature           uri_unmap_feature;
+       LV2_URI_Unmap_Feature uri_unmap_feature_data;
 };
 
 
diff --git a/libs/ardour/lv2ext/lv2_uri_unmap.h b/libs/ardour/lv2ext/lv2_uri_unmap.h
new file mode 100644 (file)
index 0000000..d6cb900
--- /dev/null
@@ -0,0 +1,81 @@
+/* lv2_uri_unmap.h - C header file for the LV2 URI Unmap extension.
+ *
+ * Copyright (C) 2010 David Robillard <http://drobilla.net>
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This header is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this header; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA
+ */
+
+/** @file
+ * C header for the LV2 URI Map extension <http://lv2plug.in/ns/ext/uri-unmap>.
+ */
+
+#ifndef LV2_URI_UNMAP_H
+#define LV2_URI_UNMAP_H
+
+#define LV2_URI_UNMAP_URI "http://lv2plug.in/ns/ext/uri-unmap"
+
+#include <stdint.h>
+
+
+/** Opaque pointer to host data. */
+typedef void* LV2_URI_Unmap_Callback_Data;
+
+
+/** The data field of the LV2_Feature for the URI Unmap extension.
+ *
+ * To support this extension the host must pass an LV2_Feature struct to the
+ * plugin's instantiate method with URI "http://lv2plug.in/ns/ext/uri-unmap"
+ * and data pointed to an instance of this struct.
+ */
+typedef struct {
+
+       /** Opaque pointer to host data.
+        *
+        * The plugin MUST pass this to any call to functions in this struct.
+        * Otherwise, it must not be interpreted in any way.
+        */
+       LV2_URI_Unmap_Callback_Data callback_data;
+
+       /** Get the numeric ID of a URI from the host.
+        *
+        * @param callback_data Must be the callback_data member of this struct.
+        * @param map The 'context' used to map this URI.
+        * @param id The URI ID to unmap.
+        * @return The string form of @a id, or NULL on error.
+        *
+        * The @a id MUST be a value previously returned from
+        * LV2_Uri_Map_Feature.uri_to_id.
+        *
+        * The returned string is owned by the host and MUST NOT be freed by
+        * the plugin or stored for a long period of time (e.g. across run
+        * invocations) without copying.
+        *
+        * This function is referentially transparent - any number of calls with
+        * the same arguments is guaranteed to return the same value over the life
+        * of a plugin instance (though the same ID may return different values
+        * with a different map parameter).
+        *
+        * This function may be called from any non-realtime thread, possibly
+        * concurrently (hosts may simply use a mutex to meet these requirements).
+        */
+       const char* (*id_to_uri)(LV2_URI_Unmap_Callback_Data callback_data,
+                                const char*                 map,
+                                uint32_t                    id);
+
+} LV2_URI_Unmap_Feature;
+
+
+#endif /* LV2_URI_UNMAP_H */
+
index a551a5b5a451fbef5ee20af4a6a73d1a9a4bd414..116236a8b69f366faa60881544a2d416b96f8c49 100644 (file)
 
 #include <cassert>
 #include <iostream>
+
 #include <stdint.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "pbd/error.h"
+
 #include "ardour/uri_map.h"
 
 using namespace std;
@@ -29,12 +36,16 @@ namespace ARDOUR {
 
 
 URIMap::URIMap()
-       : next_uri_id(1)
 {
-       uri_map_feature_data.uri_to_id = &URIMap::uri_map_uri_to_id;
+       uri_map_feature_data.uri_to_id     = &URIMap::uri_map_uri_to_id;
        uri_map_feature_data.callback_data = this;
-       uri_map_feature.URI = LV2_URI_MAP_URI;
-       uri_map_feature.data = &uri_map_feature_data;
+       uri_map_feature.URI                = LV2_URI_MAP_URI;
+       uri_map_feature.data               = &uri_map_feature_data;
+
+       uri_unmap_feature_data.id_to_uri     = &URIMap::uri_unmap_id_to_uri;
+       uri_unmap_feature_data.callback_data = this;
+       uri_unmap_feature.URI                = LV2_URI_UNMAP_URI;
+       uri_unmap_feature.data               = &uri_unmap_feature_data;
 }
 
 
@@ -42,33 +53,64 @@ uint32_t
 URIMap::uri_to_id(const char* map,
                   const char* uri)
 {
-       return uri_map_uri_to_id(this, map, uri);
+       const uint32_t id = static_cast<uint32_t>(g_quark_from_string(uri));
+       if (map && !strcmp(map, "http://lv2plug.in/ns/ext/event")) {
+               GlobalToEvent::iterator i = _global_to_event.find(id);
+               if (i != _global_to_event.end()) {
+                       return i->second;
+               } else {
+                       if (_global_to_event.size() + 1 > UINT16_MAX) {
+                               PBD::error << "Event URI " << uri << " ID out of range." << endl;
+                               return NULL;
+                       }
+                       const uint16_t ev_id = _global_to_event.size() + 1;
+                       assert(_event_to_global.find(ev_id) == _event_to_global.end());
+                       _global_to_event.insert(make_pair(id, ev_id));
+                       _event_to_global.insert(make_pair(ev_id, id));
+                       return ev_id;
+               }
+       } else {
+               return id;
+       }
+}
+
+
+const char*
+URIMap::id_to_uri(const char*    map,
+                  const uint32_t id)
+{
+       if (map && !strcmp(map, "http://lv2plug.in/ns/ext/event")) {
+               EventToGlobal::iterator i = _event_to_global.find(id);
+               if (i == _event_to_global.end()) {
+                       PBD::error << "Failed to unmap event URI " << id << endl;
+                       return NULL;
+               }
+               return g_quark_to_string(i->second);
+       } else {
+               return g_quark_to_string(id);
+       }
+
 }
 
 
 uint32_t
 URIMap::uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
-                          const char*               /*map*/,
+                          const char*               map,
                           const char*               uri)
 {
-       // TODO: map ignored, < UINT16_MAX assumed
-
        URIMap* me = (URIMap*)callback_data;
-       uint32_t ret = 0;
+       return me->uri_to_id(map, uri);
 
-       Map::iterator i = me->uri_map.find(uri);
-       if (i != me->uri_map.end()) {
-               ret = i->second;
-       } else {
-               ret = me->next_uri_id++;
-               me->uri_map.insert(make_pair(string(uri), ret));
-       }
+}
 
-       /*cout << "URI MAP (" << (map ? (void*)map : NULL)
-               << "): " << uri << " -> " << ret << endl;*/
 
-       assert(ret <= UINT16_MAX);
-       return ret;
+const char*
+URIMap::uri_unmap_id_to_uri(LV2_URI_Map_Callback_Data callback_data,
+                            const char*               map,
+                            uint32_t                  id)
+{
+       URIMap* me = (URIMap*)callback_data;
+       return me->id_to_uri(map, id);
 }