1 /*
2 Copyright 2007-2019 David Robillard <http://drobilla.net>
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted, provided that the above
6 copyright notice and this permission notice appear in all copies.
7
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "lilv_internal.h"
18
19 #include "lv2/atom/atom.h"
20 #include "lv2/core/lv2.h"
21 #include "lv2/event/event.h"
22
23 #include "lilv/lilv.h"
24 #include "sord/sord.h"
25 #include "zix/tree.h"
26
27 #include <assert.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 LilvPort*
lilv_port_new(LilvWorld * world,const SordNode * node,uint32_t index,const char * symbol)34 lilv_port_new(LilvWorld* world,
35 const SordNode* node,
36 uint32_t index,
37 const char* symbol)
38 {
39 LilvPort* port = (LilvPort*)malloc(sizeof(LilvPort));
40 port->node = lilv_node_new_from_node(world, node);
41 port->index = index;
42 port->symbol = lilv_node_new(world, LILV_VALUE_STRING, symbol);
43 port->classes = lilv_nodes_new();
44 return port;
45 }
46
47 void
lilv_port_free(const LilvPlugin * plugin,LilvPort * port)48 lilv_port_free(const LilvPlugin* plugin, LilvPort* port)
49 {
50 if (port) {
51 lilv_node_free(port->node);
52 lilv_nodes_free(port->classes);
53 lilv_node_free(port->symbol);
54 free(port);
55 }
56 }
57
58 LILV_API bool
lilv_port_is_a(const LilvPlugin * plugin,const LilvPort * port,const LilvNode * port_class)59 lilv_port_is_a(const LilvPlugin* plugin,
60 const LilvPort* port,
61 const LilvNode* port_class)
62 {
63 LILV_FOREACH(nodes, i, port->classes) {
64 if (lilv_node_equals(lilv_nodes_get(port->classes, i), port_class)) {
65 return true;
66 }
67 }
68
69 return false;
70 }
71
72 LILV_API bool
lilv_port_has_property(const LilvPlugin * plugin,const LilvPort * port,const LilvNode * property)73 lilv_port_has_property(const LilvPlugin* plugin,
74 const LilvPort* port,
75 const LilvNode* property)
76 {
77 return lilv_world_ask_internal(plugin->world,
78 port->node->node,
79 plugin->world->uris.lv2_portProperty,
80 property->node);
81 }
82
83 LILV_API bool
lilv_port_supports_event(const LilvPlugin * plugin,const LilvPort * port,const LilvNode * event_type)84 lilv_port_supports_event(const LilvPlugin* plugin,
85 const LilvPort* port,
86 const LilvNode* event_type)
87 {
88 const uint8_t* predicates[] = { (const uint8_t*)LV2_EVENT__supportsEvent,
89 (const uint8_t*)LV2_ATOM__supports,
90 NULL };
91
92 for (const uint8_t** pred = predicates; *pred; ++pred) {
93 if (lilv_world_ask_internal(plugin->world,
94 port->node->node,
95 sord_new_uri(plugin->world->world, *pred),
96 event_type->node)) {
97 return true;
98 }
99 }
100 return false;
101 }
102
103 static LilvNodes*
lilv_port_get_value_by_node(const LilvPlugin * plugin,const LilvPort * port,const SordNode * predicate)104 lilv_port_get_value_by_node(const LilvPlugin* plugin,
105 const LilvPort* port,
106 const SordNode* predicate)
107 {
108 return lilv_world_find_nodes_internal(plugin->world,
109 port->node->node,
110 predicate,
111 NULL);
112 }
113
114 LILV_API const LilvNode*
lilv_port_get_node(const LilvPlugin * plugin,const LilvPort * port)115 lilv_port_get_node(const LilvPlugin* plugin,
116 const LilvPort* port)
117 {
118 return port->node;
119 }
120
121 LILV_API LilvNodes*
lilv_port_get_value(const LilvPlugin * plugin,const LilvPort * port,const LilvNode * predicate)122 lilv_port_get_value(const LilvPlugin* plugin,
123 const LilvPort* port,
124 const LilvNode* predicate)
125 {
126 if (!lilv_node_is_uri(predicate)) {
127 LILV_ERRORF("Predicate `%s' is not a URI\n",
128 sord_node_get_string(predicate->node));
129 return NULL;
130 }
131
132 return lilv_port_get_value_by_node(plugin, port, predicate->node);
133 }
134
135 LILV_API LilvNode*
lilv_port_get(const LilvPlugin * plugin,const LilvPort * port,const LilvNode * predicate)136 lilv_port_get(const LilvPlugin* plugin,
137 const LilvPort* port,
138 const LilvNode* predicate)
139 {
140 LilvNodes* values = lilv_port_get_value(plugin, port, predicate);
141
142 LilvNode* value = lilv_node_duplicate(
143 values ? lilv_nodes_get_first(values) : NULL);
144
145 lilv_nodes_free(values);
146 return value;
147 }
148
149 LILV_API uint32_t
lilv_port_get_index(const LilvPlugin * plugin,const LilvPort * port)150 lilv_port_get_index(const LilvPlugin* plugin,
151 const LilvPort* port)
152 {
153 return port->index;
154 }
155
156 LILV_API const LilvNode*
lilv_port_get_symbol(const LilvPlugin * plugin,const LilvPort * port)157 lilv_port_get_symbol(const LilvPlugin* plugin,
158 const LilvPort* port)
159 {
160 return port->symbol;
161 }
162
163 LILV_API LilvNode*
lilv_port_get_name(const LilvPlugin * plugin,const LilvPort * port)164 lilv_port_get_name(const LilvPlugin* plugin,
165 const LilvPort* port)
166 {
167 LilvNodes* results = lilv_port_get_value_by_node(
168 plugin, port, plugin->world->uris.lv2_name);
169
170 LilvNode* ret = NULL;
171 if (results) {
172 LilvNode* val = lilv_nodes_get_first(results);
173 if (lilv_node_is_string(val)) {
174 ret = lilv_node_duplicate(val);
175 }
176 lilv_nodes_free(results);
177 }
178
179 if (!ret) {
180 LILV_WARNF("Plugin <%s> port has no (mandatory) doap:name\n",
181 lilv_node_as_string(lilv_plugin_get_uri(plugin)));
182 }
183
184 return ret;
185 }
186
187 LILV_API const LilvNodes*
lilv_port_get_classes(const LilvPlugin * plugin,const LilvPort * port)188 lilv_port_get_classes(const LilvPlugin* plugin,
189 const LilvPort* port)
190 {
191 return port->classes;
192 }
193
194 LILV_API void
lilv_port_get_range(const LilvPlugin * plugin,const LilvPort * port,LilvNode ** def,LilvNode ** min,LilvNode ** max)195 lilv_port_get_range(const LilvPlugin* plugin,
196 const LilvPort* port,
197 LilvNode** def,
198 LilvNode** min,
199 LilvNode** max)
200 {
201 if (def) {
202 LilvNodes* defaults = lilv_port_get_value_by_node(
203 plugin, port, plugin->world->uris.lv2_default);
204 *def = defaults
205 ? lilv_node_duplicate(lilv_nodes_get_first(defaults))
206 : NULL;
207 lilv_nodes_free(defaults);
208 }
209 if (min) {
210 LilvNodes* minimums = lilv_port_get_value_by_node(
211 plugin, port, plugin->world->uris.lv2_minimum);
212 *min = minimums
213 ? lilv_node_duplicate(lilv_nodes_get_first(minimums))
214 : NULL;
215 lilv_nodes_free(minimums);
216 }
217 if (max) {
218 LilvNodes* maximums = lilv_port_get_value_by_node(
219 plugin, port, plugin->world->uris.lv2_maximum);
220 *max = maximums
221 ? lilv_node_duplicate(lilv_nodes_get_first(maximums))
222 : NULL;
223 lilv_nodes_free(maximums);
224 }
225 }
226
227 LILV_API LilvScalePoints*
lilv_port_get_scale_points(const LilvPlugin * plugin,const LilvPort * port)228 lilv_port_get_scale_points(const LilvPlugin* plugin,
229 const LilvPort* port)
230 {
231 SordIter* points = lilv_world_query_internal(
232 plugin->world,
233 port->node->node,
234 sord_new_uri(plugin->world->world, (const uint8_t*)LV2_CORE__scalePoint),
235 NULL);
236
237 LilvScalePoints* ret = NULL;
238 if (!sord_iter_end(points)) {
239 ret = lilv_scale_points_new();
240 }
241
242 FOREACH_MATCH(points) {
243 const SordNode* point = sord_iter_get_node(points, SORD_OBJECT);
244
245 LilvNode* value = lilv_plugin_get_unique(plugin,
246 point,
247 plugin->world->uris.rdf_value);
248
249 LilvNode* label = lilv_plugin_get_unique(plugin,
250 point,
251 plugin->world->uris.rdfs_label);
252
253 if (value && label) {
254 zix_tree_insert(
255 (ZixTree*)ret, lilv_scale_point_new(value, label), NULL);
256 }
257 }
258 sord_iter_free(points);
259
260 assert(!ret || lilv_nodes_size(ret) > 0);
261 return ret;
262 }
263
264 LILV_API LilvNodes*
lilv_port_get_properties(const LilvPlugin * plugin,const LilvPort * port)265 lilv_port_get_properties(const LilvPlugin* plugin,
266 const LilvPort* port)
267 {
268 LilvNode* pred = lilv_node_new_from_node(
269 plugin->world, plugin->world->uris.lv2_portProperty);
270 LilvNodes* ret = lilv_port_get_value(plugin, port, pred);
271 lilv_node_free(pred);
272 return ret;
273 }
274