diff options
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom-helpers.h | 55 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom-test.c | 125 | ||||
| -rw-r--r-- | 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 <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;  	} |