handle no audio-output AUs
[ardour.git] / libs / ardour / uri_map.cc
index a702ee3862d8b685694a1755edb157e791cdb1a0..0bf67965476ce951821af5d9853487653c2fbf94 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2008-2010 Paul Davis
+    Copyright (C) 2008-2011 Paul Davis
     Author: David Robillard
 
     This program is free software; you can redistribute it and/or modify
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
 */
 
 #include <cassert>
-#include <iostream>
+#include <string>
+#include <utility>
 
 #include <stdint.h>
 #include <string.h>
 
-#include <glib.h>
-
 #include "pbd/error.h"
 
 #include "ardour/uri_map.h"
-
-using namespace std;
+#include "ardour/lv2_extensions.h"
 
 namespace ARDOUR {
 
+URIMap* URIMap::uri_map;
 
-URIMap::URIMap()
+void
+URIMap::URIDs::init(URIMap& uri_map)
 {
-       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_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;
+       // Use string literals here instead of LV2 defines to avoid LV2 dependency
+       atom_Chunk          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Chunk");
+       atom_Path           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Path");
+       atom_Sequence       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Sequence");
+       atom_eventTransfer  = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#eventTransfer");
+       atom_URID           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#URID");
+       atom_Blank          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Blank");
+       atom_Object         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Object");
+       atom_Float          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Float");
+       log_Error           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Error");
+       log_Note            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Note");
+       log_Warning         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Warning");
+       midi_MidiEvent      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/midi#MidiEvent");
+       time_Position       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#Position");
+       time_bar            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#bar");
+       time_barBeat        = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#barBeat");
+       time_beatUnit       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatUnit");
+       time_beatsPerBar    = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerBar");
+       time_beatsPerMinute = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerMinute");
+       time_frame          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#frame");
+       time_speed          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#speed");
+       patch_Get           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Get");
+       patch_Set           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Set");
+       patch_property      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#property");
+       patch_value         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#value");
+#ifdef LV2_EXTENDED
+       auto_event         = uri_map.uri_to_id(LV2_AUTOMATE_URI__event);
+       auto_setup         = uri_map.uri_to_id(LV2_AUTOMATE_URI__setup);
+       auto_finalize      = uri_map.uri_to_id(LV2_AUTOMATE_URI__finalize);
+       auto_start         = uri_map.uri_to_id(LV2_AUTOMATE_URI__start);
+       auto_end           = uri_map.uri_to_id(LV2_AUTOMATE_URI__end);
+       auto_parameter     = uri_map.uri_to_id(LV2_AUTOMATE_URI__parameter);
+       auto_value         = uri_map.uri_to_id(LV2_AUTOMATE_URI__value);
+#endif
 }
 
-
-uint32_t
-URIMap::uri_to_id(const char* map,
-                  const char* uri)
+URIMap&
+URIMap::instance()
 {
-       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 0;
-                       }
-                       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;
+       if (!URIMap::uri_map) {
+               URIMap::uri_map = new URIMap();
        }
+       return *URIMap::uri_map;
 }
 
+static uint32_t
+c_uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
+                    const char*               map,
+                    const char*               uri)
+{
+       URIMap* const me = (URIMap*)callback_data;
+       const uint32_t id = me->uri_to_id(uri);
+
+       /* The event context with the uri-map extension guarantees a value in the
+          range of uint16_t.  Ardour used to map to a separate range to achieve
+          this, but unfortunately some plugins are broken and use the incorrect
+          context.  To compensate, we simply use the same context for everything
+          and hope that anything in the event context gets mapped before
+          UINT16_MAX is reached (which will be fine unless something seriously
+          weird is going on).  If this fails there is nothing we can do, die.
+       */
+       assert(!map || strcmp(map, "http://lv2plug.in/ns/ext/event")
+              || id < UINT16_MAX);
+
+       return id;
+}
 
-const char*
-URIMap::id_to_uri(const char*    map,
-                  const uint32_t id)
+static LV2_URID
+c_urid_map(LV2_URID_Map_Handle handle,
+           const char*         uri)
 {
-       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);
-       }
+       URIMap* const me = (URIMap*)handle;
+       return me->uri_to_id(uri);
+}
 
+static const char*
+c_urid_unmap(LV2_URID_Unmap_Handle handle,
+             LV2_URID              urid)
+{
+       URIMap* const me = (URIMap*)handle;
+       return me->id_to_uri(urid);
 }
 
+URIMap::URIMap()
+{
+       _uri_map_feature_data.uri_to_id     = c_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;
+
+       _urid_map_feature_data.map    = c_urid_map;
+       _urid_map_feature_data.handle = this;
+       _urid_map_feature.URI         = LV2_URID_MAP_URI;
+       _urid_map_feature.data        = &_urid_map_feature_data;
+
+       _urid_unmap_feature_data.unmap  = c_urid_unmap;
+       _urid_unmap_feature_data.handle = this;
+       _urid_unmap_feature.URI         = LV2_URID_UNMAP_URI;
+       _urid_unmap_feature.data        = &_urid_unmap_feature_data;
+
+       urids.init(*this);
+}
 
 uint32_t
-URIMap::uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
-                          const char*               map,
-                          const char*               uri)
+URIMap::uri_to_id(const char* uri)
 {
-       URIMap* me = (URIMap*)callback_data;
-       return me->uri_to_id(map, uri);
+       Glib::Threads::Mutex::Lock lm (_lock);
 
+       const std::string urimm(uri);
+       const Map::const_iterator i = _map.find(urimm);
+       if (i != _map.end()) {
+               return i->second;
+       }
+       const uint32_t id = _map.size() + 1;
+       _map.insert(std::make_pair(urimm, id));
+       _unmap.insert(std::make_pair(id, urimm));
+       return id;
 }
 
-
 const char*
-URIMap::uri_unmap_id_to_uri(LV2_URI_Map_Callback_Data callback_data,
-                            const char*               map,
-                            uint32_t                  id)
+URIMap::id_to_uri(const uint32_t id) const
 {
-       URIMap* me = (URIMap*)callback_data;
-       return me->id_to_uri(map, id);
-}
+       Glib::Threads::Mutex::Lock lm (_lock);
 
+       const Unmap::const_iterator i = _unmap.find(id);
+       return (i != _unmap.end()) ? i->second.c_str() : NULL;
+}
 
 } // namespace ARDOUR