aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/atom-helpers.h55
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/atom-test.c125
-rw-r--r--plugins/eg-sampler.lv2/sampler.c40
3 files changed, 154 insertions, 66 deletions
diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h b/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h
index 6fff74b..ae2eb43 100644
--- a/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h
+++ b/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h
@@ -25,6 +25,7 @@
#ifndef LV2_ATOM_HELPERS_H
#define LV2_ATOM_HELPERS_H
+#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -304,6 +305,60 @@ lv2_object_get(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query)
}
/**
+ Variable argument version of lv2_object_get().
+
+ This is nicer-looking in code, but a bit more error-prone since it is not
+ type safe and the argument list must be terminated.
+
+ The arguments should be a series of uint32_t key and const LV2_Atom** value
+ pairs, terminated by a zero key. The value pointers MUST be initialized to
+ NULL. For example:
+
+ @code
+ const LV2_Atom* name = NULL;
+ const LV2_Atom* age = NULL;
+ lv2_object_getv(obj,
+ uris.name_key, &name,
+ uris.age_key, &age,
+ 0);
+ @endcode
+*/
+static inline int
+lv2_object_getv(const LV2_Atom_Object* object, ...)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of query keys so we can short-circuit when done */
+ va_list args;
+ va_start(args, object);
+ for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
+ if (!va_arg(args, const LV2_Atom**)) {
+ return -1;
+ }
+ }
+ va_end(args);
+
+ LV2_OBJECT_FOREACH(object, o) {
+ const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o);
+ va_start(args, object);
+ for (int i = 0; i < n_queries; ++i) {
+ uint32_t qkey = va_arg(args, uint32_t);
+ const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
+ if (qkey == prop->key && !*qval) {
+ *qval = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ va_end(args);
+ }
+ return matches;
+}
+
+/**
@}
*/
diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-test.c b/lv2/lv2plug.in/ns/ext/atom/atom-test.c
index 1850660..563e574 100644
--- a/lv2/lv2plug.in/ns/ext/atom/atom-test.c
+++ b/lv2/lv2plug.in/ns/ext/atom/atom-test.c
@@ -242,61 +242,84 @@ main()
n_props, NUM_PROPS);
}
- const LV2_Atom* one_match = NULL;
- const LV2_Atom* two_match = NULL;
- const LV2_Atom* three_match = NULL;
- const LV2_Atom* four_match = NULL;
- const LV2_Atom* true_match = NULL;
- const LV2_Atom* false_match = NULL;
- const LV2_Atom* uri_match = NULL;
- const LV2_Atom* string_match = NULL;
- const LV2_Atom* literal_match = NULL;
- const LV2_Atom* tuple_match = NULL;
- const LV2_Atom* vector_match = NULL;
- const LV2_Atom* seq_match = NULL;
+ struct {
+ const LV2_Atom* one;
+ const LV2_Atom* two;
+ const LV2_Atom* three;
+ const LV2_Atom* four;
+ const LV2_Atom* affirmative;
+ const LV2_Atom* negative;
+ const LV2_Atom* uri;
+ const LV2_Atom* string;
+ const LV2_Atom* literal;
+ const LV2_Atom* tuple;
+ const LV2_Atom* vector;
+ const LV2_Atom* seq;
+ } matches;
+
+ memset(&matches, 0, sizeof(matches));
+
LV2_Atom_Object_Query q[] = {
- { eg_one, &one_match },
- { eg_two, &two_match },
- { eg_three, &three_match },
- { eg_four, &four_match },
- { eg_true, &true_match },
- { eg_false, &false_match },
- { eg_uri, &uri_match },
- { eg_string, &string_match },
- { eg_literal, &literal_match },
- { eg_tuple, &tuple_match },
- { eg_vector, &vector_match },
- { eg_seq, &seq_match },
+ { eg_one, &matches.one },
+ { eg_two, &matches.two },
+ { eg_three, &matches.three },
+ { eg_four, &matches.four },
+ { eg_true, &matches.affirmative },
+ { eg_false, &matches.negative },
+ { eg_uri, &matches.uri },
+ { eg_string, &matches.string },
+ { eg_literal, &matches.literal },
+ { eg_tuple, &matches.tuple },
+ { eg_vector, &matches.vector },
+ { eg_seq, &matches.seq },
LV2_OBJECT_QUERY_END
};
- unsigned matches = lv2_object_get((LV2_Atom_Object*)obj, q);
- if (matches != n_props) {
- return test_fail("Query failed, %u matches != %u\n", matches, n_props);
- } else if (!lv2_atom_equals((LV2_Atom*)one, one_match)) {
- return test_fail("Bad match one\n");
- } else if (!lv2_atom_equals((LV2_Atom*)two, two_match)) {
- return test_fail("Bad match two\n");
- } else if (!lv2_atom_equals((LV2_Atom*)three, three_match)) {
- return test_fail("Bad match three\n");
- } else if (!lv2_atom_equals((LV2_Atom*)four, four_match)) {
- return test_fail("Bad match four\n");
- } else if (!lv2_atom_equals((LV2_Atom*)t, true_match)) {
- return test_fail("Bad match true\n");
- } else if (!lv2_atom_equals((LV2_Atom*)f, false_match)) {
- return test_fail("Bad match false\n");
- } else if (!lv2_atom_equals((LV2_Atom*)uri, uri_match)) {
- return test_fail("Bad match URI\n");
- } else if (!lv2_atom_equals((LV2_Atom*)string, string_match)) {
- return test_fail("Bad match string\n");
- } else if (!lv2_atom_equals((LV2_Atom*)literal, literal_match)) {
- return test_fail("Bad match literal\n");
- } else if (!lv2_atom_equals((LV2_Atom*)tuple, tuple_match)) {
- return test_fail("Bad match tuple\n");
- } else if (!lv2_atom_equals((LV2_Atom*)vector, vector_match)) {
- return test_fail("Bad match vector\n");
- } else if (!lv2_atom_equals((LV2_Atom*)seq, seq_match)) {
- return test_fail("Bad match sequence\n");
+ unsigned n_matches = lv2_object_get((LV2_Atom_Object*)obj, q);
+ for (int i = 0; i < 2; ++i) {
+ if (n_matches != n_props) {
+ return test_fail("Query failed, %u matches != %u\n",
+ n_matches, n_props);
+ } else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) {
+ return test_fail("Bad match one\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) {
+ return test_fail("Bad match two\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) {
+ return test_fail("Bad match three\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) {
+ return test_fail("Bad match four\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) {
+ return test_fail("Bad match true\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) {
+ return test_fail("Bad match false\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) {
+ return test_fail("Bad match URI\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) {
+ return test_fail("Bad match string\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) {
+ return test_fail("Bad match literal\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) {
+ return test_fail("Bad match tuple\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) {
+ return test_fail("Bad match vector\n");
+ } else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) {
+ return test_fail("Bad match sequence\n");
+ }
+ memset(&matches, 0, sizeof(matches));
+ n_matches = lv2_object_getv((LV2_Atom_Object*)obj,
+ eg_one, &matches.one,
+ eg_two, &matches.two,
+ eg_three, &matches.three,
+ eg_four, &matches.four,
+ eg_true, &matches.affirmative,
+ eg_false, &matches.negative,
+ eg_uri, &matches.uri,
+ eg_string, &matches.string,
+ eg_literal, &matches.literal,
+ eg_tuple, &matches.tuple,
+ eg_vector, &matches.vector,
+ eg_seq, &matches.seq,
+ 0);
}
printf("All tests passed.\n");
diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c
index 90d5cbe..960a391 100644
--- a/plugins/eg-sampler.lv2/sampler.c
+++ b/plugins/eg-sampler.lv2/sampler.c
@@ -251,6 +251,13 @@ cleanup(LV2_Handle instance)
}
static bool
+is_object_type(Sampler* plugin, LV2_URID type)
+{
+ return type == plugin->uris.atom_Resource
+ || type == plugin->uris.atom_Blank;
+}
+
+static bool
handle_message(Sampler* plugin,
const LV2_Atom_Object* obj)
{
@@ -259,29 +266,32 @@ handle_message(Sampler* plugin,
return false;
}
+ /* Message should look like this:
+ * [
+ * a msg:SetMessage ;
+ * msg:body [
+ * eg:filename "/some/value.wav" ;
+ * ] ;
+ * ]
+ */
+
/* Get body of message */
const LV2_Atom_Object* body = NULL;
- LV2_Atom_Object_Query q1[] = {
- { plugin->uris.msg_body, (const LV2_Atom**)&body },
- LV2_OBJECT_QUERY_END
- };
- lv2_object_get(obj, q1);
-
- if (!body) { // TODO: check type
- fprintf(stderr, "Malformed set message with no body.\n");
+ lv2_object_getv(obj, plugin->uris.msg_body, &body, 0);
+ if (!body) {
+ fprintf(stderr, "Malformed set message has no body.\n");
+ return false;
+ }
+ if (!is_object_type(plugin, body->atom.type)) {
+ fprintf(stderr, "Malformed set message has non-object body.\n");
return false;
}
/* Get filename from body */
const LV2_Atom* filename = NULL;
- LV2_Atom_Object_Query q2[] = {
- { plugin->uris.eg_filename, &filename },
- LV2_OBJECT_QUERY_END
- };
- lv2_object_get((LV2_Atom_Object*)body, q2);
-
+ lv2_object_getv(body, plugin->uris.eg_filename, &filename, 0);
if (!filename) {
- fprintf(stderr, "Ignored set message with no filename\n");
+ fprintf(stderr, "Ignored set message with no filename.\n");
return false;
}