6fac103715441d26be9e17bcdb99f5383d929c70
[ardour.git] / libs / ardour / uri_map.cc
1 /*
2     Copyright (C) 2008-2011 Paul Davis
3     Author: David Robillard
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <cassert>
21 #include <string>
22 #include <utility>
23
24 #include <stdint.h>
25 #include <string.h>
26
27 #include "pbd/error.h"
28
29 #include "ardour/uri_map.h"
30
31 namespace ARDOUR {
32
33 URIMap* URIMap::uri_map;
34
35 void
36 URIMap::URIDs::init(URIMap& uri_map)
37 {
38         // Use string literals here instead of LV2 defines to avoid LV2 dependency
39         atom_Chunk          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Chunk");
40         atom_Path           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Path");
41         atom_Sequence       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Sequence");
42         atom_eventTransfer  = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#eventTransfer");
43         atom_URID           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#URID");
44         atom_Blank          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Blank");
45         atom_Object         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Object");
46         atom_Float          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Float");
47         log_Error           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Error");
48         log_Note            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Note");
49         log_Warning         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Warning");
50         midi_MidiEvent      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/midi#MidiEvent");
51         time_Position       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#Position");
52         time_bar            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#bar");
53         time_barBeat        = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#barBeat");
54         time_beatUnit       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatUnit");
55         time_beatsPerBar    = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerBar");
56         time_beatsPerMinute = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerMinute");
57         time_frame          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#frame");
58         time_speed          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#speed");
59         patch_Get           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Get");
60         patch_Set           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Set");
61         patch_property      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#property");
62         patch_value         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#value");
63 }
64
65 URIMap&
66 URIMap::instance()
67 {
68         if (!URIMap::uri_map) {
69                 URIMap::uri_map = new URIMap();
70         }
71         return *URIMap::uri_map;
72 }
73
74 static uint32_t
75 c_uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
76                     const char*               map,
77                     const char*               uri)
78 {
79         URIMap* const me = (URIMap*)callback_data;
80         const uint32_t id = me->uri_to_id(uri);
81
82         /* The event context with the uri-map extension guarantees a value in the
83            range of uint16_t.  Ardour used to map to a separate range to achieve
84            this, but unfortunately some plugins are broken and use the incorrect
85            context.  To compensate, we simply use the same context for everything
86            and hope that anything in the event context gets mapped before
87            UINT16_MAX is reached (which will be fine unless something seriously
88            weird is going on).  If this fails there is nothing we can do, die.
89         */
90         assert(!map || strcmp(map, "http://lv2plug.in/ns/ext/event")
91                || id < UINT16_MAX);
92
93         return id;
94 }
95
96 static LV2_URID
97 c_urid_map(LV2_URID_Map_Handle handle,
98            const char*         uri)
99 {
100         URIMap* const me = (URIMap*)handle;
101         return me->uri_to_id(uri);
102 }
103
104 static const char*
105 c_urid_unmap(LV2_URID_Unmap_Handle handle,
106              LV2_URID              urid)
107 {
108         URIMap* const me = (URIMap*)handle;
109         return me->id_to_uri(urid);
110 }
111
112 URIMap::URIMap()
113 {
114         _uri_map_feature_data.uri_to_id     = c_uri_map_uri_to_id;
115         _uri_map_feature_data.callback_data = this;
116         _uri_map_feature.URI                = LV2_URI_MAP_URI;
117         _uri_map_feature.data               = &_uri_map_feature_data;
118
119         _urid_map_feature_data.map    = c_urid_map;
120         _urid_map_feature_data.handle = this;
121         _urid_map_feature.URI         = LV2_URID_MAP_URI;
122         _urid_map_feature.data        = &_urid_map_feature_data;
123
124         _urid_unmap_feature_data.unmap  = c_urid_unmap;
125         _urid_unmap_feature_data.handle = this;
126         _urid_unmap_feature.URI         = LV2_URID_UNMAP_URI;
127         _urid_unmap_feature.data        = &_urid_unmap_feature_data;
128
129         urids.init(*this);
130 }
131
132 uint32_t
133 URIMap::uri_to_id(const char* uri)
134 {
135         Glib::Threads::Mutex::Lock lm (_lock);
136
137         const std::string urimm(uri);
138         const Map::const_iterator i = _map.find(urimm);
139         if (i != _map.end()) {
140                 return i->second;
141         }
142         const uint32_t id = _map.size() + 1;
143         _map.insert(std::make_pair(urimm, id));
144         _unmap.insert(std::make_pair(id, urimm));
145         return id;
146 }
147
148 const char*
149 URIMap::id_to_uri(const uint32_t id) const
150 {
151         Glib::Threads::Mutex::Lock lm (_lock);
152
153         const Unmap::const_iterator i = _unmap.find(id);
154         return (i != _unmap.end()) ? i->second.c_str() : NULL;
155 }
156
157 } // namespace ARDOUR
158