prototype online self-automating LV2 plugin interface
[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 #include "ardour/lv2_extensions.h"
31
32 namespace ARDOUR {
33
34 URIMap* URIMap::uri_map;
35
36 void
37 URIMap::URIDs::init(URIMap& uri_map)
38 {
39         // Use string literals here instead of LV2 defines to avoid LV2 dependency
40         atom_Chunk          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Chunk");
41         atom_Path           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Path");
42         atom_Sequence       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Sequence");
43         atom_eventTransfer  = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#eventTransfer");
44         atom_URID           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#URID");
45         atom_Blank          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Blank");
46         atom_Object         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Object");
47         atom_Float          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/atom#Float");
48         log_Error           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Error");
49         log_Note            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Note");
50         log_Warning         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/log#Warning");
51         midi_MidiEvent      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/midi#MidiEvent");
52         time_Position       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#Position");
53         time_bar            = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#bar");
54         time_barBeat        = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#barBeat");
55         time_beatUnit       = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatUnit");
56         time_beatsPerBar    = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerBar");
57         time_beatsPerMinute = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#beatsPerMinute");
58         time_frame          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#frame");
59         time_speed          = uri_map.uri_to_id("http://lv2plug.in/ns/ext/time#speed");
60         patch_Get           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Get");
61         patch_Set           = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#Set");
62         patch_property      = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#property");
63         patch_value         = uri_map.uri_to_id("http://lv2plug.in/ns/ext/patch#value");
64 #ifdef LV2_EXTENDED
65         auto_event         = uri_map.uri_to_id(LV2_AUTOMATE_URI__event);
66         auto_setup         = uri_map.uri_to_id(LV2_AUTOMATE_URI__setup);
67         auto_finalize      = uri_map.uri_to_id(LV2_AUTOMATE_URI__finalize);
68         auto_start         = uri_map.uri_to_id(LV2_AUTOMATE_URI__start);
69         auto_end           = uri_map.uri_to_id(LV2_AUTOMATE_URI__end);
70         auto_parameter     = uri_map.uri_to_id(LV2_AUTOMATE_URI__parameter);
71         auto_value         = uri_map.uri_to_id(LV2_AUTOMATE_URI__value);
72 #endif
73 }
74
75 URIMap&
76 URIMap::instance()
77 {
78         if (!URIMap::uri_map) {
79                 URIMap::uri_map = new URIMap();
80         }
81         return *URIMap::uri_map;
82 }
83
84 static uint32_t
85 c_uri_map_uri_to_id(LV2_URI_Map_Callback_Data callback_data,
86                     const char*               map,
87                     const char*               uri)
88 {
89         URIMap* const me = (URIMap*)callback_data;
90         const uint32_t id = me->uri_to_id(uri);
91
92         /* The event context with the uri-map extension guarantees a value in the
93            range of uint16_t.  Ardour used to map to a separate range to achieve
94            this, but unfortunately some plugins are broken and use the incorrect
95            context.  To compensate, we simply use the same context for everything
96            and hope that anything in the event context gets mapped before
97            UINT16_MAX is reached (which will be fine unless something seriously
98            weird is going on).  If this fails there is nothing we can do, die.
99         */
100         assert(!map || strcmp(map, "http://lv2plug.in/ns/ext/event")
101                || id < UINT16_MAX);
102
103         return id;
104 }
105
106 static LV2_URID
107 c_urid_map(LV2_URID_Map_Handle handle,
108            const char*         uri)
109 {
110         URIMap* const me = (URIMap*)handle;
111         return me->uri_to_id(uri);
112 }
113
114 static const char*
115 c_urid_unmap(LV2_URID_Unmap_Handle handle,
116              LV2_URID              urid)
117 {
118         URIMap* const me = (URIMap*)handle;
119         return me->id_to_uri(urid);
120 }
121
122 URIMap::URIMap()
123 {
124         _uri_map_feature_data.uri_to_id     = c_uri_map_uri_to_id;
125         _uri_map_feature_data.callback_data = this;
126         _uri_map_feature.URI                = LV2_URI_MAP_URI;
127         _uri_map_feature.data               = &_uri_map_feature_data;
128
129         _urid_map_feature_data.map    = c_urid_map;
130         _urid_map_feature_data.handle = this;
131         _urid_map_feature.URI         = LV2_URID_MAP_URI;
132         _urid_map_feature.data        = &_urid_map_feature_data;
133
134         _urid_unmap_feature_data.unmap  = c_urid_unmap;
135         _urid_unmap_feature_data.handle = this;
136         _urid_unmap_feature.URI         = LV2_URID_UNMAP_URI;
137         _urid_unmap_feature.data        = &_urid_unmap_feature_data;
138
139         urids.init(*this);
140 }
141
142 uint32_t
143 URIMap::uri_to_id(const char* uri)
144 {
145         Glib::Threads::Mutex::Lock lm (_lock);
146
147         const std::string urimm(uri);
148         const Map::const_iterator i = _map.find(urimm);
149         if (i != _map.end()) {
150                 return i->second;
151         }
152         const uint32_t id = _map.size() + 1;
153         _map.insert(std::make_pair(urimm, id));
154         _unmap.insert(std::make_pair(id, urimm));
155         return id;
156 }
157
158 const char*
159 URIMap::id_to_uri(const uint32_t id) const
160 {
161         Glib::Threads::Mutex::Lock lm (_lock);
162
163         const Unmap::const_iterator i = _unmap.find(id);
164         return (i != _unmap.end()) ? i->second.c_str() : NULL;
165 }
166
167 } // namespace ARDOUR
168