From 5ed1257408da33ac6b4cfbc15bf8034d47558976 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 14 Feb 2012 00:10:57 +0000 Subject: Add lv2_object_getv. --- lv2/lv2plug.in/ns/ext/atom/atom-helpers.h | 55 +++++++++++++ lv2/lv2plug.in/ns/ext/atom/atom-test.c | 125 ++++++++++++++++++------------ plugins/eg-sampler.lv2/sampler.c | 40 ++++++---- 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 #include #include #include @@ -303,6 +304,60 @@ lv2_object_get(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query) return matches; } +/** + 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 @@ -250,6 +250,13 @@ cleanup(LV2_Handle instance) free(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; } -- cgit v1.2.1