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