diff options
| author | David Robillard <d@drobilla.net> | 2012-02-08 04:56:24 +0000 | 
|---|---|---|
| committer | David Robillard <d@drobilla.net> | 2012-02-08 04:56:24 +0000 | 
| commit | ed78bbe5ba12be1f9bcc736f14c51da6b4f639f3 (patch) | |
| tree | 653a2dfe33f3923da45a38fc04ed2106f93528f3 /lv2/lv2plug.in/ns/ext/atom | |
| parent | b617875c6f3ad439d25ae166da79df839ebfdc71 (diff) | |
| download | lv2-ed78bbe5ba12be1f9bcc736f14c51da6b4f639f3.tar.xz | |
Rearrange tree so top level can be used as an include path for standard style LV2 includes.
Diffstat (limited to 'lv2/lv2plug.in/ns/ext/atom')
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom-helpers.h | 310 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom-test.c | 304 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom.h | 203 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom.ttl | 462 | ||||
| l--------- | lv2/lv2plug.in/ns/ext/atom/ext.pc.in | 1 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/forge.h | 445 | ||||
| -rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/manifest.ttl | 9 | ||||
| l--------- | lv2/lv2plug.in/ns/ext/atom/waf | 1 | ||||
| l--------- | lv2/lv2plug.in/ns/ext/atom/wscript | 1 | 
9 files changed, 1736 insertions, 0 deletions
| diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h b/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h new file mode 100644 index 0000000..6fff74b --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/atom-helpers.h @@ -0,0 +1,310 @@ +/* +  Copyright 2008-2012 David Robillard <http://drobilla.net> + +  Permission to use, copy, modify, and/or distribute this software for any +  purpose with or without fee is hereby granted, provided that the above +  copyright notice and this permission notice appear in all copies. + +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** +   @file atom-helpers.h Helper functions for the LV2 Atom extension. + +   Note these functions are all static inline, do not take their address. + +   This header is non-normative, it is provided for convenience. +*/ + +#ifndef LV2_ATOM_HELPERS_H +#define LV2_ATOM_HELPERS_H + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" + +#ifdef __cplusplus +extern "C" { +#else +#    include <stdbool.h> +#endif + +/** Pad a size to 64 bits. */ +static inline uint32_t +lv2_atom_pad_size(uint32_t size) +{ +	return (size + 7) & (~7); +} + +/** Return true iff @p atom is null. */ +static inline bool +lv2_atom_is_null(const LV2_Atom* atom) +{ +	return !atom || (atom->type == 0 && atom->size == 0); +} + +/** Return true iff @p a is equal to @p b. */ +static inline bool +lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) +{ +	return (a == b) || ( +		(a->type == b->type) && +		(a->size == b->size) && +		!memcmp(LV2_ATOM_CONTENTS(LV2_Atom, a), +		        LV2_ATOM_CONTENTS(LV2_Atom, b), +		        a->size)); +} + +/** +   @name Sequence Iterator +   @{ +*/ + +/** An iterator over the elements of an LV2_Atom_Sequence. */ +typedef LV2_Atom_Event* LV2_Atom_Sequence_Iter; + +/** Get an iterator pointing to the first element in @p tup. */ +static inline LV2_Atom_Sequence_Iter +lv2_sequence_begin(const LV2_Atom_Sequence* seq) +{ +	return (LV2_Atom_Sequence_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq)); +} + +/** Return true iff @p i has reached the end of @p tup. */ +static inline bool +lv2_sequence_is_end(const LV2_Atom_Sequence* seq, LV2_Atom_Sequence_Iter i) +{ +	return (uint8_t*)i >= ((uint8_t*)seq + sizeof(LV2_Atom) + seq->atom.size); +} + +/** Return an iterator to the element following @p i. */ +static inline LV2_Atom_Sequence_Iter +lv2_sequence_iter_next(const LV2_Atom_Sequence_Iter i) +{ +	return (LV2_Atom_Sequence_Iter)((uint8_t*)i +	                                + sizeof(LV2_Atom_Event) +	                                + lv2_atom_pad_size(i->body.size)); +} + +/** Return the element pointed to by @p i. */ +static inline LV2_Atom_Event* +lv2_sequence_iter_get(LV2_Atom_Sequence_Iter i) +{ +	return (LV2_Atom_Event*)i; +} + +/** +   A macro for iterating over all events in a Sequence. +   @param sequence The sequence to iterate over +   @param iter The name of the iterator + +   This macro is used similarly to a for loop (which it expands to), e.g.: +   @code +   LV2_SEQUENCE_FOREACH(sequence, i) { +       LV2_Atom_Event* ev = lv2_sequence_iter_get(i); +       // Do something with ev here... +   } +   @endcode +*/ +#define LV2_SEQUENCE_FOREACH(sequence, iter) \ +	for (LV2_Atom_Sequence_Iter (iter) = lv2_sequence_begin(sequence); \ +	     !lv2_sequence_is_end(sequence, (iter)); \ +	     (iter) = lv2_sequence_iter_next(iter)) + +/** +   @} +   @name Tuple Iterator +   @{ +*/ + +/** An iterator over the elements of an LV2_Atom_Tuple. */ +typedef LV2_Atom* LV2_Atom_Tuple_Iter; + +/** Get an iterator pointing to the first element in @p tup. */ +static inline LV2_Atom_Tuple_Iter +lv2_tuple_begin(const LV2_Atom_Tuple* tup) +{ +	return (LV2_Atom_Tuple_Iter)(LV2_ATOM_BODY(tup)); +} + +/** Return true iff @p i has reached the end of @p tup. */ +static inline bool +lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i) +{ +	return (uint8_t*)i >= ((uint8_t*)tup + sizeof(LV2_Atom) + tup->atom.size); +} + +/** Return an iterator to the element following @p i. */ +static inline LV2_Atom_Tuple_Iter +lv2_tuple_iter_next(const LV2_Atom_Tuple_Iter i) +{ +	return (LV2_Atom_Tuple_Iter)( +		(uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size)); +} + +/** Return the element pointed to by @p i. */ +static inline LV2_Atom* +lv2_tuple_iter_get(LV2_Atom_Tuple_Iter i) +{ +	return (LV2_Atom*)i; +} + +/** +   A macro for iterating over all properties of a Tuple. +   @param tuple The tuple to iterate over +   @param iter The name of the iterator + +   This macro is used similarly to a for loop (which it expands to), e.g.: +   @code +   LV2_TUPLE_FOREACH(tuple, i) { +       LV2_Atom_Property* prop = lv2_tuple_iter_get(i); +       // Do something with prop here... +   } +   @endcode +*/ +#define LV2_TUPLE_FOREACH(tuple, iter) \ +	for (LV2_Atom_Tuple_Iter (iter) = lv2_tuple_begin(tuple); \ +	     !lv2_tuple_is_end(tuple, (iter)); \ +	     (iter) = lv2_tuple_iter_next(iter)) + +/** +   @} +   @name Object Iterator +   @{ +*/ + +/** An iterator over the properties of an LV2_Atom_Object. */ +typedef LV2_Atom_Property_Body* LV2_Atom_Object_Iter; + +/** Get an iterator pointing to the first property in @p obj. */ +static inline LV2_Atom_Object_Iter +lv2_object_begin(const LV2_Atom_Object* obj) +{ +	return (LV2_Atom_Object_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Object, obj)); +} + +/** Return true iff @p i has reached the end of @p obj. */ +static inline bool +lv2_object_is_end(const LV2_Atom_Object* obj, LV2_Atom_Object_Iter i) +{ +	return (uint8_t*)i >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->atom.size); +} + +/** Return true iff @p l points to the same property as @p r. */ +static inline bool +lv2_object_iter_equals(const LV2_Atom_Object_Iter l, +                       const LV2_Atom_Object_Iter r) +{ +	return l == r; +} + +/** Return an iterator to the property following @p i. */ +static inline LV2_Atom_Object_Iter +lv2_object_iter_next(const LV2_Atom_Object_Iter i) +{ +	const LV2_Atom* const value = (LV2_Atom*)((uint8_t*)i + sizeof(i)); +	return (LV2_Atom_Object_Iter)((uint8_t*)i +	                              + sizeof(LV2_Atom_Property_Body) +	                              + lv2_atom_pad_size(value->size)); +} + +/** Return the property pointed to by @p i. */ +static inline LV2_Atom_Property_Body* +lv2_object_iter_get(LV2_Atom_Object_Iter i) +{ +	return (LV2_Atom_Property_Body*)i; +} + +/** +   A macro for iterating over all properties of an Object. +   @param object The object to iterate over +   @param iter The name of the iterator + +   This macro is used similarly to a for loop (which it expands to), e.g.: +   @code +   LV2_OBJECT_FOREACH(object, i) { +       LV2_Atom_Property* prop = lv2_object_iter_get(i); +       // Do something with prop here... +   } +   @endcode +*/ +#define LV2_OBJECT_FOREACH(object, iter) \ +	for (LV2_Atom_Object_Iter (iter) = lv2_object_begin(object); \ +	     !lv2_object_is_end(object, (iter)); \ +	     (iter) = lv2_object_iter_next(iter)) + +/** +   @} +   @name Object Query +   @{ +*/ + +/** A single entry in an Object query. */ +typedef struct { +	uint32_t         key;    /**< Key to query (input set by user) */ +	const LV2_Atom** value;  /**< Found value (output set by query function) */ +} LV2_Atom_Object_Query; + +static const LV2_Atom_Object_Query LV2_OBJECT_QUERY_END = { 0, NULL }; + +/** +   Get an object's values for various keys. + +   The value pointer of each item in @p query will be set to the location of +   the corresponding value in @p object.  Every value pointer in @p query MUST +   be initialised to NULL.  This function reads @p object in a single linear +   sweep.  By allocating @p query on the stack, objects can be "queried" +   quickly without allocating any memory.  This function is realtime safe. + +   For example: +   @code +   const LV2_Atom* name = NULL; +   const LV2_Atom* age  = NULL; +   LV2_Atom_Object_Query q[] = { +       { urids.eg_name, &name }, +       { urids.eg_age,  &age }, +       LV2_OBJECT_QUERY_END +   }; +   lv2_object_get(obj, q); +   // name and age are now set to the appropriate values in obj, or NULL. +   @endcode +*/ +static inline int +lv2_object_get(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query) +{ +	int matches   = 0; +	int n_queries = 0; + +	/* Count number of query keys so we can short-circuit when done */ +	for (LV2_Atom_Object_Query* q = query; q->key; ++q) { +		++n_queries; +	} + +	LV2_OBJECT_FOREACH(object, o) { +		const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o); +		for (LV2_Atom_Object_Query* q = query; q->key; ++q) { +			if (q->key == prop->key && !*q->value) { +				*q->value = &prop->value; +				if (++matches == n_queries) { +					return matches; +				} +				break; +			} +		} +	} +	return matches; +} + +/** +   @} +*/ + +#endif /* LV2_ATOM_HELPERS_H */ diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-test.c b/lv2/lv2plug.in/ns/ext/atom/atom-test.c new file mode 100644 index 0000000..1a88d7d --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/atom-test.c @@ -0,0 +1,304 @@ +/* +  Copyright 2012 David Robillard <http://drobilla.net> + +  Permission to use, copy, modify, and/or distribute this software for any +  purpose with or without fee is hereby granted, provided that the above +  copyright notice and this permission notice appear in all copies. + +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "lv2/lv2plug.in/ns/ext/atom/atom-helpers.h" +#include "lv2/lv2plug.in/ns/ext/atom/forge.h" + +char** uris   = NULL; +size_t n_uris = 0; + +char* +copy_string(const char* str) +{ +	const size_t len = strlen(str); +	char*        dup = (char*)malloc(len + 1); +	memcpy(dup, str, len + 1); +	return dup; +} + +LV2_URID +urid_map(LV2_URID_Map_Handle handle, const char* uri) +{ +	for (size_t i = 0; i < n_uris; ++i) { +		if (!strcmp(uris[i], uri)) { +			return i + 1; +		} +	} + +	uris = (char**)realloc(uris, ++n_uris * sizeof(char*)); +	uris[n_uris - 1] = copy_string(uri); +	return n_uris; +} + +int +test_fail(const char* fmt, ...) +{ +	va_list args; +	va_start(args, fmt); +	fprintf(stderr, "error: "); +	vfprintf(stderr, fmt, args); +	va_end(args); +	return 1; +} + +int +main() +{ +	LV2_URID_Map   map = { NULL, urid_map }; +	LV2_Atom_Forge forge; +	lv2_atom_forge_init(&forge, &map); + +	LV2_URID eg_Object  = urid_map(NULL, "http://example.org/Object"); +	LV2_URID eg_one     = urid_map(NULL, "http://example.org/one"); +	LV2_URID eg_two     = urid_map(NULL, "http://example.org/two"); +	LV2_URID eg_three   = urid_map(NULL, "http://example.org/three"); +	LV2_URID eg_four    = urid_map(NULL, "http://example.org/four"); +	LV2_URID eg_true    = urid_map(NULL, "http://example.org/true"); +	LV2_URID eg_false   = urid_map(NULL, "http://example.org/false"); +	LV2_URID eg_uri     = urid_map(NULL, "http://example.org/uri"); +	LV2_URID eg_string  = urid_map(NULL, "http://example.org/string"); +	LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal"); +	LV2_URID eg_tuple   = urid_map(NULL, "http://example.org/tuple"); +	LV2_URID eg_vector  = urid_map(NULL, "http://example.org/vector"); +	LV2_URID eg_seq     = urid_map(NULL, "http://example.org/seq"); + +#define BUF_SIZE  1024 +#define NUM_PROPS 12 + +	uint8_t buf[BUF_SIZE]; +	lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE); + +	LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_object( +		&forge, NULL, 0, eg_Object); + +	// eg_one = (Int32)1 +	lv2_atom_forge_property_head(&forge, obj, eg_one, 0); +	LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, obj, 1); +	if (one->value != 1) { +		return test_fail("%d != 1\n", one->value); +	} + +	// eg_two = (Int64)2 +	lv2_atom_forge_property_head(&forge, obj, eg_two, 0); +	LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, obj, 2); +	if (two->value != 2) { +		return test_fail("%ld != 2\n", two->value); +	} + +	// eg_three = (Float)3.0 +	lv2_atom_forge_property_head(&forge, obj, eg_three, 0); +	LV2_Atom_Float* three = lv2_atom_forge_float(&forge, obj, 3.0f); +	if (three->value != 3) { +		return test_fail("%f != 3\n", three->value); +	} + +	// eg_four = (Double)4.0 +	lv2_atom_forge_property_head(&forge, obj, eg_four, 0); +	LV2_Atom_Double* four = lv2_atom_forge_double(&forge, obj, 4.0); +	if (four->value != 4) { +		return test_fail("%ld != 4\n", four->value); +	} + +	// eg_true = (Bool)1 +	lv2_atom_forge_property_head(&forge, obj, eg_true, 0); +	LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, obj, true); +	if (t->value != 1) { +		return test_fail("%ld != 1 (true)\n", t->value); +	} + +	// eg_false = (Bool)0 +	lv2_atom_forge_property_head(&forge, obj, eg_false, 0); +	LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, obj, false); +	if (f->value != 0) { +		return test_fail("%ld != 0 (false)\n", f->value); +	} + +	// eg_uri = (URID)"http://example.org/value" +	LV2_URID eg_value = urid_map(NULL, "http://example.org/value"); +	lv2_atom_forge_property_head(&forge, obj, eg_uri, 0); +	LV2_Atom_URID* uri = lv2_atom_forge_urid(&forge, obj, eg_value); +	if (uri->id != eg_value) { +		return test_fail("%u != %u\n", uri->id, eg_value); +	} + +	// eg_string = (String)"hello" +	lv2_atom_forge_property_head(&forge, obj, eg_string, 0); +	LV2_Atom_String* string = lv2_atom_forge_string( +		&forge, obj, (const uint8_t*)"hello", strlen("hello")); +	uint8_t* body = (uint8_t*)LV2_ATOM_BODY(string); +	if (strcmp((const char*)body, "hello")) { +		return test_fail("%s != \"hello\"\n", (const char*)body); +	} + +	// eg_literal = (Literal)"hello"@fr +	lv2_atom_forge_property_head(&forge, obj, eg_literal, 0); +	LV2_Atom_Literal* literal = lv2_atom_forge_literal( +		&forge, obj, (const uint8_t*)"bonjour", strlen("bonjour"), +		0, urid_map(NULL, "http://lexvo.org/id/term/fr")); +	body = (uint8_t*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal); +	if (strcmp((const char*)body, "bonjour")) { +		return test_fail("%s != \"bonjour\"\n", (const char*)body); +	} + +	// eg_tuple = "foo",true +	lv2_atom_forge_property_head(&forge, obj, eg_tuple, 0); +	LV2_Atom_Tuple*  tuple = lv2_atom_forge_tuple(&forge, obj); +	LV2_Atom_String* tup0  = lv2_atom_forge_string( +		&forge, (LV2_Atom*)tuple, (const uint8_t*)"foo", strlen("foo")); +	LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, (LV2_Atom*)tuple, true); +	obj->size += ((LV2_Atom*)tuple)->size; +	LV2_Atom_Tuple_Iter i = lv2_tuple_begin(tuple); +	if (lv2_tuple_is_end(tuple, i)) { +		return test_fail("Tuple iterator is empty\n"); +	} +	LV2_Atom* tup0i = (LV2_Atom*)lv2_tuple_iter_get(i); +	if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) { +		return test_fail("Corrupt tuple element 0\n"); +	} +	i = lv2_tuple_iter_next(i); +	if (lv2_tuple_is_end(tuple, i)) { +		return test_fail("Premature end of tuple iterator\n"); +	} +	LV2_Atom* tup1i = lv2_tuple_iter_get(i); +	if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) { +		return test_fail("Corrupt tuple element 1\n"); +	} +	i = lv2_tuple_iter_next(i); +	if (!lv2_tuple_is_end(tuple, i)) { +		return test_fail("Tuple iter is not at end\n"); +	} + +	// eg_vector = (Vector<Int32>)1,2,3,4 +	lv2_atom_forge_property_head(&forge, obj, eg_vector, 0); +	int32_t elems[] = { 1, 2, 3, 4 }; +	LV2_Atom_Vector* vector = lv2_atom_forge_vector( +		&forge, obj, 4, forge.Int32, sizeof(int32_t), elems); +	void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector); +	if (memcmp(elems, vec_body, sizeof(elems))) { +		return test_fail("Corrupt vector\n"); +	} + +	// eg_seq = (Sequence)1, 2 +	lv2_atom_forge_property_head(&forge, obj, eg_seq, 0); +	LV2_Atom_Sequence* seq = lv2_atom_forge_sequence_head(&forge, obj, 0); +	lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 0, 0); +	lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 1); +	lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 1, 0); +	lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 2); +	obj->size += seq->atom.size - sizeof(LV2_Atom); + +	// Test equality +	LV2_Atom_Int32 itwo = { { forge.Int32, sizeof(int32_t) }, 2 }; +	if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) { +		return test_fail("1 == 2.0\n"); +	} else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) { +		return test_fail("1 == 2\n"); +	} + +	unsigned n_events = 0; +	LV2_SEQUENCE_FOREACH(seq, i) { +		LV2_Atom_Event* ev = lv2_sequence_iter_get(i); +		if (ev->time.audio.frames != n_events +		    || ev->time.audio.subframes != 0) { +			return test_fail("Corrupt event %u has bad time\n", n_events); +		} else if (ev->body.type != forge.Int32) { +			return test_fail("Corrupt event %u has bad type\n", n_events); +		} else if (((LV2_Atom_Int32*)&ev->body)->value != (int)n_events + 1) { +			return test_fail("Event %u != %d\n", n_events, n_events + 1); +		} +		++n_events; +	} +	 +	unsigned n_props = 0; +	LV2_OBJECT_FOREACH((LV2_Atom_Object*)obj, i) { +		LV2_Atom_Property_Body* prop = lv2_object_iter_get(i); +		if (!prop->key) { +			return test_fail("Corrupt property %u has no key\n", n_props); +		} else if (prop->context) { +			return test_fail("Corrupt property %u has context\n", n_props); +		} +		++n_props; +	} + +	if (n_props != NUM_PROPS) { +		return test_fail("Corrupt object has %u properties != %u\n", +		                 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; +	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 }, +		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"); +	} + +	printf("All tests passed.\n"); +	return 0; +} diff --git a/lv2/lv2plug.in/ns/ext/atom/atom.h b/lv2/lv2plug.in/ns/ext/atom/atom.h new file mode 100644 index 0000000..bea9197 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/atom.h @@ -0,0 +1,203 @@ +/* +  Copyright 2008-2012 David Robillard <http://drobilla.net> + +  Permission to use, copy, modify, and/or distribute this software for any +  purpose with or without fee is hereby granted, provided that the above +  copyright notice and this permission notice appear in all copies. + +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** +   @file atom.h C header for the LV2 Atom extension +   <http://lv2plug.in/ns/ext/atom>. + +   This header describes the binary layout of various types defined in the +   atom extension. +*/ + +#ifndef LV2_ATOM_H +#define LV2_ATOM_H + +#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" + +#define LV2_ATOM_REFERENCE_TYPE 0 + +#include <stdint.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** This expression will fail to compile if double does not fit in 64 bits. */ +typedef char lv2_atom_assert_double_fits_in_64_bits[ +	((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; + +/** +   Return a pointer to the contents of a variable-sized atom. +   @param type The type of the atom, e.g. LV2_Atom_String. +   @param atom A variable-sized atom. +*/ +#define LV2_ATOM_CONTENTS(type, atom) \ +	((void*)((uint8_t*)(atom) + sizeof(type))) + +/** Return a pointer to the body of @p atom (just past the LV2_Atom head). */ +#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom) + +/** The header of an atom:Atom. */ +typedef struct { +	uint32_t type;  /**< Type of this atom (mapped URI). */ +	uint32_t size;  /**< Size in bytes, not including type and size. */ +} LV2_Atom; + +/** An atom:Int32 or atom:Bool.  May be cast to LV2_Atom. */ +typedef struct { +	LV2_Atom atom; +	int32_t  value; +} LV2_Atom_Int32; + +/** An atom:Int64.  May be cast to LV2_Atom. */ +typedef struct { +	LV2_Atom atom; +	int64_t  value; +} LV2_Atom_Int64; + +/** An atom:Float.  May be cast to LV2_Atom. */ +typedef struct { +	LV2_Atom atom; +	float    value; +} LV2_Atom_Float; + +/** An atom:Double.  May be cast to LV2_Atom. */ +typedef struct { +	LV2_Atom atom; +	double   value; +} LV2_Atom_Double; + +/** An atom:Bool.  May be cast to LV2_Atom. */ +typedef LV2_Atom_Int32 LV2_Atom_Bool; + +/** An atom:URID.  May be cast to LV2_Atom. */ +typedef struct { +	LV2_Atom atom;  /**< Atom header. */ +	uint32_t id;    /**< URID. */ +} LV2_Atom_URID; + +/** The complete header of an atom:String. */ +typedef struct { +	LV2_Atom atom;  /**< Atom header. */ +	/* Contents (a null-terminated UTF-8 string) follow here. */ +} LV2_Atom_String; + +/** The header of an atom:Literal body. */ +typedef struct { +	uint32_t datatype;  /**< The ID of the datatype of this literal. */ +	uint32_t lang;      /**< The ID of the language of this literal. */ +} LV2_Atom_Literal_Head; + +/** The complete header of an atom:Literal. */ +typedef struct { +	LV2_Atom              atom;     /**< Atom header. */ +	LV2_Atom_Literal_Head literal;  /**< Literal body header. */ +	/* Contents (a null-terminated UTF-8 string) follow here. */ +} LV2_Atom_Literal; + +/** The complete header of an atom:Tuple. */ +typedef struct { +	LV2_Atom atom;  /**< Atom header. */ +	/* Contents (a series of complete atoms) follow here. */ +} LV2_Atom_Tuple; + +/** The complete header of an atom:Vector. */ +typedef struct { +	LV2_Atom atom;        /**< Atom header. */ +	uint32_t elem_count;  /**< The number of elements in the vector */ +	uint32_t elem_type;   /**< The type of each element in the vector */ +	/* Contents (a series of packed atom bodies) follow here. */ +} LV2_Atom_Vector; + +/** The header of an atom:Property body (e.g. in an atom:Object). */ +typedef struct { +	uint32_t key;      /**< Key (predicate) (mapped URI). */ +	uint32_t context;  /**< Context URID (may be, and generally is, 0). */ +	LV2_Atom value;    /**< Value atom header. */ +} LV2_Atom_Property_Body; + +/** The complete header of an atom:Property. */ +typedef struct { +	LV2_Atom atom;     /**< Atom header. */ +	uint32_t key;      /**< Key (predicate) (mapped URI). */ +	uint32_t context;  /**< Context URID (may be, and generally is, 0). */ +	LV2_Atom value;    /**< Value atom header. */ +	/* Value atom body follows here. */ +} LV2_Atom_Property; + +/** The complete header of an atom:Object. */ +typedef struct { +	LV2_Atom atom;  /**< Atom header. */ +	uint32_t id;    /**< URID for atom:Resource, or blank ID for atom:Blank. */ +	uint32_t type;  /**< Type URID (same as rdf:type, for fast dispatch). */ +	/* Contents (a series of property bodies) follow here. */ +} LV2_Atom_Object; + +/** The complete header of an atom:Response. */ +typedef struct { +	LV2_Atom atom;    /**< Atom header. */ +	uint32_t source;  /**< ID of message this is a response to (may be 0). */ +	uint32_t type;    /**< Specific response type URID (may be 0). */ +	uint32_t seq;     /**< Response sequence number, 0 for end. */ +	LV2_Atom body;    /**< Body atom header (may be empty). */ +	/* Body optionally follows here. */ +} LV2_Atom_Response; + +/** A time stamp in frames.  Note this type is NOT an LV2_Atom. */ +typedef struct { +	uint32_t frames;     /**< Time in frames relative to this block. */ +	uint32_t subframes;  /**< Fractional time in 1/(2^32)ths of a frame. */ +} LV2_Atom_Audio_Time; + +/** The header of an atom:Event.  Note this type is NOT an LV2_Atom. */ +typedef struct { +	/** Time stamp.  Which type is valid is determined by context. */ +	union { +		LV2_Atom_Audio_Time audio;  /**< Time in audio frames. */ +		double              beats;  /**< Time in beats. */ +	} time; +	LV2_Atom body;  /**< Event body atom header. */ +	/* Body atom contents follow here. */ +} LV2_Atom_Event; + +/** +   A sequence of events (time-stamped atoms). + +   This is used as the contents of an atom:EventPort, but is a generic Atom +   type which can be used anywhere. + +   The contents of a sequence is a series of LV2_Atom_Event, each aligned +   to 64-bits, e.g.: +   <pre> +   | Event 1 (size 6)                              | Event 2 +   |       |       |       |       |       |       |       |       | +   | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +   |FRAMES |SUBFRMS|TYPE   |SIZE   |DATADATADATAPAD|FRAMES |SUBFRMS|... +   </pre> +*/ +typedef struct { +	LV2_Atom atom;       /**< Atom header. */ +	uint32_t capacity;   /**< Maximum size of contents. */ +	uint32_t time_type;  /**< URID type of event time stamps. */ +	/* Contents (a series of events) follow here. */ +} LV2_Atom_Sequence; + +#ifdef __cplusplus +}  /* extern "C" */ +#endif + +#endif  /* LV2_ATOM_H */ diff --git a/lv2/lv2plug.in/ns/ext/atom/atom.ttl b/lv2/lv2plug.in/ns/ext/atom/atom.ttl new file mode 100644 index 0000000..7d534d0 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/atom.ttl @@ -0,0 +1,462 @@ +# LV2 Atom Extension +# Copyright 2007-2012 David Robillard <d@drobilla.net> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +@prefix atom: <http://lv2plug.in/ns/ext/atom#> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix lv2:  <http://lv2plug.in/ns/lv2core#> . +@prefix owl:  <http://www.w3.org/2002/07/owl#> . +@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> . + +<http://lv2plug.in/ns/ext/atom> +	a lv2:Specification ; +	doap:name "LV2 Atom" ; +	doap:shortdesc "A generic value container and several data types." ; +	doap:license <http://opensource.org/licenses/isc> ; +	rdfs:seeAlso <atom-helpers.h> , +		<forge.h> ; +	doap:release [ +		doap:revision "0.4" ; +		doap:created "2012-02-07" +	] ; +	doap:maintainer [ +		a foaf:Person ; +		foaf:name "David Robillard" ; +		foaf:homepage <http://drobilla.net/> ; +		rdfs:seeAlso <http://drobilla.net/drobilla.rdf> +	] ; +	lv2:documentation """ +<p>This extension defines a generic container for data, called an <q>Atom</q>, +and several basic Atom types which can be used to express structured data. +Atoms allow LV2 plugins and hosts to communicate, process, serialise, and store +values of any type via a generic mechanism (e.g. ports, files, networks, +ringbuffers, etc.).  Atoms are, with one exception, Plain Old Data (POD) which +may safely be copied (e.g. with a simple call to <code>memcpy</code>).</p> + +<p>Since Atom communication can be implemented generically, plugins that +understand some type can be used together in a host that does not understand +that type, and plugins (e.g. routers, delays) can process atoms of unknown +type.</p> + +<p>Atoms can and should be used anywhere values of various types must be stored +or transmitted.  This extension defines port types, atom:ValuePort and +atom:MessagePort, which are connected to an Atom.  The atom:Sequence type in +conjunction with atom:MessagePort is intended to replace the <a +href="http://lv2plug.in/ns/ext/event">LV2 event</a> extension.</p> + +<p>The types defined in this extension should be powerful enough to express +almost any structure.  Implementers SHOULD build structures out of the types +provided here, rather than define new binary formats (e.g. use atom:Object +rather than a new C <code>struct</code> type).  New binary formats are an +implementation burden which harms interoperabilty, and should only be defined +where absolutely necessary.</p> + +<p>Implementing this extension requires a facility for mapping URIs to +integers, such as the <a href="http://lv2plug.in/ns/ext/urid">LV2 URID</a> +extension.</p> +""" . + +atom:cType +	a rdf:Property , +		owl:DatatypeProperty ; +	rdfs:label "C type" ; +	rdfs:domain rdfs:Class ; +	rdfs:range xsd:string ; +	rdfs:comment """ +The identifier for a C type describing the in-memory representation of +an instance of this class. +""" . + +atom:Atom +	a rdfs:Class ; +	rdfs:label "Atom" ; +	atom:cType "LV2_Atom" ; +	lv2:documentation """ +<p>Abstract base class for all atoms.  An LV2_Atom has a 32-bit +<code>type</code> and <code>size</code> followed by a body of <code>size</code> +bytes.  Atoms MUST be 64-bit aligned.</p> + +<p>All concrete Atom types (subclasses of this class) MUST define a precise +binary layout for their body.</p> + +<p>The <code>type</code> field is the URI of an Atom type mapped to an integer. +Implementations SHOULD gracefully ignore, or pass through, atoms with unknown +types.</p> + +<p>All atoms are POD by definition except references, which as a special case +have <code>type = 0</code>.  An Atom MUST NOT contain a Reference.  It is safe +to copy any non-reference Atom with a simple <code>memcpy</code>, even if the +implementation does not understand <code>type</code>.  Though this extension +reserves the type 0 for references, the details of reference handling are +currently unspecified.  A future revision of this extension, or a different +extension, may define how to use non-POD data and references.  Implementations +MUST NOT send references to another implementation unless the receiver is +explicitly known to support references (e.g. by supporting a feature).  The +atom with both <code>type</code> <em>and</em> <code>size</code> 0 is +<q>null</q>, which is not considered a Reference.</p> +""" . + +atom:Bang +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Bang" ; +    rdfs:comment "Generic activity or trigger, with no body." . + +atom:Number +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Number" . + +atom:Int32 +	a rdfs:Class ; +	rdfs:subClassOf atom:Number ; +	rdfs:label "Signed 32-bit integer" ; +	atom:cType "LV2_Atom_Int32" . + +atom:Int64 +	a rdfs:Class ; +	rdfs:subClassOf atom:Number ; +	rdfs:label "Signed 64-bit integer" ; +	atom:cType "LV2_Atom_Int64" . + +atom:Float +	a rdfs:Class ; +	rdfs:subClassOf atom:Number ; +	rdfs:label "32-bit IEEE-754 floating point number" ; +	atom:cType "LV2_Atom_Float" . + +atom:Double +	a rdfs:Class ; +	rdfs:subClassOf atom:Number ; +	rdfs:label "64-bit IEEE-754 floating point number" ; +	atom:cType "LV2_Atom_Double" . + +atom:Bool +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Boolean" ; +	atom:cType "LV2_Atom_Bool" ; +	rdfs:comment "An Int32 where 0 is false and any other value is true." . + +atom:String +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "String" ; +	atom:cType "LV2_Atom_String" ; +	lv2:documentation """ +<p>A UTF-8 encoded string.</p> + +<p>The body of an LV2_Atom_String is a C string in UTF-8 encoding, i.e. an +array of bytes (<code>uint8_t</code>) terminated with a NULL byte +(<code>'\\0'</code>).</p> + +<p>This type can be used for free-form strings, but in most cases it is better to +use atom:Literal since this supports a language tag or datatype.  Implementations +SHOULD NOT use atom:String unless translating the string does not make sense and +the string has no meaningful datatype.</p> +""" . + +atom:Literal +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "String Literal" ; +	atom:cType "LV2_Atom_Literal" ; +	lv2:documentation """ +<p>A UTF-8 encoded string literal, with an optional datatype or language.</p> + +<p>This type is compatible with rdf:Literal and is capable of expressing a +string in any language or a value of any type.  A Literal has a +<code>datatype</code> and <code>lang</code> followed by string data in UTF-8 +encoding.  The length of the string data in bytes is <code>size - +sizeof(LV2_Atom_Literal)</code>, including the terminating NULL character.  The +<code>lang</code> field SHOULD be a URI of the form +<http://lexvo.org/id/term/LANG> where LANG is an <a +href="http://www.loc.gov/standards/iso639-2/">ISO 693-2</a> or <a +href="http://www.loc.gov/standards/iso639-2/">ISO 693-3</a> language code.</p> + +<p>A Literal may have a <code>datatype</code> OR a <code>lang</code>, but never +both.</p> + +<p>For example, a Literal can be "Hello" in English:</p> +<pre class="c-code"> +void set_to_hello_in_english(LV2_Atom_Literal* lit) { +     lit->atom.type = map(expand("atom:Literal")); +     lit->atom.size = 14; +     lit->datatype  = 0; +     lit->lang      = map("http://lexvo.org/id/term/en"); +     memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit), +            "Hello", +            sizeof("Hello"));  // Assumes enough space +} +</pre> + +<p>or a Turtle string:</p> +<pre class="c-code"> +void set_to_turtle_string(LV2_Atom_Literal* lit, const char* ttl) { +     lit->atom.type = map(expand("atom:Literal")); +     lit->atom.size = 64; +     lit->datatype  = map("http://www.w3.org/2008/turtle#turtle"); +     lit->lang      = 0; +     memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit), +            ttl, +            strlen(ttl) + 1);  // Assumes enough space +} +</pre> +""" . + +atom:URID +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Integer ID mapped from a URI" ; +	atom:cType "LV2_Atom_ID" ; +	lv2:documentation """ +<p>An unsigned 32-bit integer mapped from a URI (e.g. with LV2_URID_Map).</p> +""" . + +atom:Vector +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Vector" ; +	atom:cType "LV2_Atom_Vector" ; +	lv2:documentation """ +<p>A homogeneous series of atom bodies with equivalent type and size.</p> + +<p>An LV2_Atom_Vector is a 32-bit <code>elem_count</code> and +<code>elem_type</code> followed by <code>elem_count</code> atom bodies of type +<code>elem_type</code>.  The element type must be a fixed size atom:Atom type, +i.e. the size of each element is the vector's <code>size / +elem_count</code>.</p> + +<p>For example, an atom:Vector containing 42 elements of type atom:Float:</p> +<pre class="c-code"> +struct VectorOf42Floats { +    uint32_t type;        // map(expand("atom:Vector")) +    uint32_t size;        // sizeof(LV2_Atom_Vector) + (42 * sizeof(float); +    uint32_t elem_count;  // 42 +    uint32_t elem_type;   // map(expand("atom:Float")) +    float    elems[32]; +}; +</pre> + +<p>Note that it is possible to construct a valid Atom for each element +of the vector, even by an implementation which does not understand +<code>elem_type</code>.</p> +""" . + +atom:Tuple +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Tuple" ; +	lv2:documentation """ +<p>A series of Atoms with varying <code>type</code> and <code>size</code>.</p> + +<p>The body of a Tuple is simply a series of complete atoms, each aligned to +64 bits.</p> +""" . + +atom:Property +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Property" ; +	atom:cType "LV2_Atom_Property" ; +	lv2:documentation """ +<p>A property of an atom:Object.  An LV2_Atom_Property has a URID +<code>key</code> and <code>context</code>, and an Atom <code>value</code>. +This corresponds to an RDF Property, where the <q>key</q> is the <q>predicate</q> +and the <q>value</q> is the object.</p> + +<p>The <code>context</code> field can be used to specify a different context +for each property, where this is useful.  Otherwise, it may be 0.</p> +""" . + +atom:Object +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Object" ; +	atom:cType "LV2_Atom_Object" ; +	lv2:documentation """ +<p>An <q>Object</q> is an atom with a set of properties.  This corresponds to +an RDF Resource, and can be thought of as a dictionary with URID keys.</p> + +<p>An LV2_Atom_Object has a uint32_t <code>id</code> and uint32_t +<code>type</code>, followed by a series of atom:Property bodies (without +headers, i.e. LV2_Atom_Property_Body).  The LV2_Atom_Object::type field is +semantically equivalent to a property with key rdf:type, but is included in the +structure to allow for fast dispatch.</p> + +<p>This is an abstract Atom type, an Object is always either a atom:Resource +or a atom:Blank.</p> +""" . + +atom:Resource +	a rdfs:Class ; +	rdfs:subClassOf atom:Object ; +	rdfs:label "Resource" ; +	atom:cType "LV2_Atom_Object" ; +	lv2:documentation """ +<p>An atom:Object where the <code>id</code> field is a URID, i.e. an Object +with a URI.</p> +""" . + +atom:Blank +	a rdfs:Class ; +	rdfs:subClassOf atom:Object ; +	rdfs:label "Blank" ; +	atom:cType "LV2_Atom_Object" ; +	lv2:documentation """ +<p>An atom:Object where the LV2_Atom_Object::id is a blank node ID (NOT a URI). +The ID of a Blank is valid only within the context the Blank appears in.  For +ports this is the context of the associated run() call, i.e. all ports share +the same context so outputs can contain IDs that correspond to IDs of blanks in +the input.</p> """ . + +atom:Event +	a rdfs:Class ; +	rdfs:label "Event" ; +	atom:cType "LV2_Atom_Event" ; +	lv2:documentation """ +<p>An atom with a time stamp header prepended, typically an element of an +atom:Sequence.  Note this is not an Atom type.</p> +""" . + +atom:Sequence +	a rdfs:Class ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Sequence" ; +	atom:cType "LV2_Atom_Sequence" ; +	lv2:documentation """ +<p>A sequence of atom:Event, i.e. a series of time-stamped Atoms.</p> +""" . + +atom:AtomPort +	a rdfs:Class ; +	rdfs:subClassOf lv2:Port ; +	rdfs:label "Atom Port" ; +	lv2:documentation """ +<p>A port which contains an lv2:Atom.  Ports of this type will be connected to +a 64-bit aligned LV2_Atom immediately followed by <code>size</code> bytes of +data.</p> + +<p>This is an abstract port type with incomplete semantics which can not be +used directly as a port type.  Atom ports should be either a atom:ValuePort or +a atom:MessagePort.</p> + +<p>Before calling a method on a plugin that writes to an AtomPort output, the +host MUST set the size of the Atom in that output to the amount of available +memory immediately following the Atom header.  The plugin MUST write a valid +Atom to that port; leaving it untouched is illegal.  If there is no reasonable +value to write to the port, the plugin MUST write null (the Atom with both +<code>type</code> and <code>size</code> 0).</p> +""" . + +atom:ValuePort +	a rdfs:Class ; +	rdfs:subClassOf atom:AtomPort ; +	rdfs:label "Value Port" ; +	lv2:documentation """ + +<p>An AtomPort that contains a persistent <em>value</em>.  A <q>value</q> is +time-independent and may be used numerous times.  A ValuePort is <q>pure</q> in +the sense that it may affect output but MUST NOT affect persistent plugin state +in any externally visible way.</p> + +<ul> +<li>If a plugin has fixed values for all inputs, all ValuePort outputs are also +fixed regardless of the number of times the plugin is run.</li> + +<li>If a plugin has fixed input values for all ports except a ValuePort, each +value of that port corresponds to a single set of values for all +ValuePort outputs.</li> + +<li>If the plugin saves state other than port values (e.g. using the <a +href="http://lv2plug.in/ns/ext/state">LV2 State</a> extension), changing only +the value of a ValuePort input MUST NOT change that state.  In other words, +value port changes MUST NOT trigger a state change that requires a save.</li> +</ul> + +<p>Value ports are essentially purely functional ports: if a plugin has only +value ports, that plugin is purely functional.  Hosts may elect to cache output +and avoid calling run() if the output is already known according to these +rules.</p> +""" . + +atom:MessagePort +	a rdfs:Class ; +	rdfs:subClassOf atom:AtomPort ; +	rdfs:label "Message Port" ; +	lv2:documentation """ +<p>An AtomPort that contains transient data which is <em>consumed</em> or +<em>sent</em>.  The Atom contained in a MessagePort is time-dependent and only +valid for a single run invocation.  Unlike a ValuePort, a MessagePort may be +used to manipulate internal plugin state.</p> + +<p>Intuitively, a MessagePort contains a <q>message</q> or <q>event</q> which +is reacted to <em>once</em> (not a <q>value</q> which is computed with any +number of times).</p> +""" . + +atom:bufferType +	a rdf:Property ; +	rdfs:domain atom:AtomPort ; +	rdfs:label "buffer type" ; +	lv2:documentation """ +<p>Indicates that an AtomPort may be connected to a certain Atom type.  A port +MAY support several buffer types.  The host MUST NOT connect a port to an Atom +with a type not explicitly listed with this property.  The value of this +property MUST be a sub-class of atom:Atom.  For example, an input port that is +connected directly to an LV2_Atom_Double value is described like so:</p> + +<pre class="turtle-code"> +<plugin> +    lv2:port [ +        a lv2:InputPort , atom:ValuePort ; +        atom:bufferType atom:Double ; +    ] . +</pre> + +<p>Note this property only indicates the atom types a port may be directly +connected to, it is not <q>recursive</q>.  If a port can be connected to a +collection, use atom:supports to indicate which element types are understood. +If a port supports heterogeneous collections (collections that can contain +several types of elements at once), implementations MUST gracefully handle any +types that are present in the collection, even if those types are not +explicitly supported.</p> +""" . + +atom:supports +	a rdf:Property ; +	rdfs:label "supports" ; +	lv2:documentation """ +<p>Indicates that a particular Atom type is supported.</p> + +<p>This property is defined loosely, it may be used to indicate that anything +<q>supports</q> an Atom type, wherever that may be useful.  It applies +<q>recursively</q> where collections are involved.</p> + +<p>In particular, this property can be used to describe which event types are +supported by a port.  For example, a port that receives MIDI events is +described like so:</p> + +<pre class="turtle-code"> +<plugin> +    lv2:port [ +        a lv2:InputPort , atom:MessagePort ; +        atom:bufferType atom:Sequence ; +        atom:supports midi:MidiEvent ; +    ] . +</pre> +""" . diff --git a/lv2/lv2plug.in/ns/ext/atom/ext.pc.in b/lv2/lv2plug.in/ns/ext/atom/ext.pc.in new file mode 120000 index 0000000..03dd044 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/ext.pc.in @@ -0,0 +1 @@ +../../../../../ext.pc.in
\ No newline at end of file diff --git a/lv2/lv2plug.in/ns/ext/atom/forge.h b/lv2/lv2plug.in/ns/ext/atom/forge.h new file mode 100644 index 0000000..2790778 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/forge.h @@ -0,0 +1,445 @@ +/* +  Copyright 2008-2012 David Robillard <http://drobilla.net> + +  Permission to use, copy, modify, and/or distribute this software for any +  purpose with or without fee is hereby granted, provided that the above +  copyright notice and this permission notice appear in all copies. + +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** +   @file forge.h An API for constructing LV2 atoms. + +   This file provides a simple API which can be used to create complex nested +   atoms by calling the provided functions to append atoms (or atom headers) in +   the correct order.  The size of the parent atom is automatically updated, +   but the caller must handle this situation if atoms are more deeply nested. + +   All output is written to a user-provided buffer.  This entire API is +   realtime safe and suitable for writing to output port buffers in the run +   method. + +   Note these functions are all static inline, do not take their address. + +   This header is non-normative, it is provided for convenience. +*/ + +#ifndef LV2_ATOM_FORGE_H +#define LV2_ATOM_FORGE_H + +#include <assert.h> +#include <string.h> + +#include "lv2/lv2plug.in/ns/ext/atom/atom-helpers.h" +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" + +#ifdef __cplusplus +extern "C" { +#else +#    include <stdbool.h> +#endif + +/** +   A "forge" for creating atoms by appending to a buffer. +*/ +typedef struct { +	uint8_t* buf; +	size_t   offset; +	size_t   size; + +	LV2_URID Bool; +	LV2_URID Double; +	LV2_URID Float; +	LV2_URID Int32; +	LV2_URID Int64; +	LV2_URID Literal; +	LV2_URID Object; +	LV2_URID Property; +	LV2_URID Sequence; +	LV2_URID String; +	LV2_URID Tuple; +	LV2_URID URID; +	LV2_URID Vector; +} LV2_Atom_Forge; + +/** Set the output buffer where @c forge will write atoms. */ +static inline void +lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) +{ +	forge->buf    = buf; +	forge->size   = size; +	forge->offset = 0; +} + +/** +   Initialise @c forge. + +   URIs will be mapped using @c map and stored, a reference to @c map itself is +   not held. +*/ +static inline void +lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) +{ +	lv2_atom_forge_set_buffer(forge, NULL, 0); +	forge->Bool     = map->map(map->handle, LV2_ATOM_URI "#Bool"); +	forge->Double   = map->map(map->handle, LV2_ATOM_URI "#Double"); +	forge->Float    = map->map(map->handle, LV2_ATOM_URI "#Float"); +	forge->Int32    = map->map(map->handle, LV2_ATOM_URI "#Int32"); +	forge->Int64    = map->map(map->handle, LV2_ATOM_URI "#Int64"); +	forge->Literal  = map->map(map->handle, LV2_ATOM_URI "#Literal"); +	forge->Object   = map->map(map->handle, LV2_ATOM_URI "#Object"); +	forge->Property = map->map(map->handle, LV2_ATOM_URI "#Property"); +	forge->Sequence = map->map(map->handle, LV2_ATOM_URI "#Sequence"); +	forge->String   = map->map(map->handle, LV2_ATOM_URI "#String"); +	forge->Tuple    = map->map(map->handle, LV2_ATOM_URI "#Tuple"); +	forge->URID     = map->map(map->handle, LV2_ATOM_URI "#URID"); +	forge->Vector   = map->map(map->handle, LV2_ATOM_URI "#Vector"); +} + +/** +   Reserve @c size bytes in the output buffer (used internally). +   @return The start of the reserved memory, or NULL if out of space. +*/ +static inline uint8_t* +lv2_atom_forge_reserve(LV2_Atom_Forge* forge, +                       LV2_Atom*       parent, +                       uint32_t        size) +{ +	uint8_t* const out         = forge->buf + forge->offset; +	const uint32_t padded_size = lv2_atom_pad_size(size); +	if (forge->offset + padded_size > forge->size) { +		return NULL; +	} +	if (parent) { +		parent->size += padded_size; +	} +	forge->offset += padded_size; +	return out; +} + +/** +   Write the header of an atom:Atom. + +   Space for the complete atom will be reserved, but uninitialised. +*/ +static inline LV2_Atom* +lv2_atom_forge_atom_head(LV2_Atom_Forge* forge, +                         LV2_Atom*       parent, +                         uint32_t        type, +                         uint32_t        size) +{ +	LV2_Atom* const out = (LV2_Atom*)lv2_atom_forge_reserve( +		forge, parent, size); +	if (out) { +		out->type = type; +		out->size = size - sizeof(LV2_Atom); +	} +	return out; +} + +/** Write an atom:Int32. */ +static inline LV2_Atom_Int32* +lv2_atom_forge_int32(LV2_Atom_Forge* forge, LV2_Atom* parent, int32_t val) +{ +	LV2_Atom_Int32* out = (LV2_Atom_Int32*)lv2_atom_forge_atom_head( +		forge, parent, forge->Int32, sizeof(LV2_Atom_Int32)); +	if (out) { +		out->value = val; +	} +	return out; +} + +/** Write an atom:Int64. */ +static inline LV2_Atom_Int64* +lv2_atom_forge_int64(LV2_Atom_Forge* forge, LV2_Atom* parent, int64_t val) +{ +	LV2_Atom_Int64* out = (LV2_Atom_Int64*)lv2_atom_forge_atom_head( +		forge, parent, forge->Int64, sizeof(LV2_Atom_Int64)); +	if (out) { +		out->value = val; +	} +	return out; +} + +/** Write an atom:Float. */ +static inline LV2_Atom_Float* +lv2_atom_forge_float(LV2_Atom_Forge* forge, LV2_Atom* parent, float val) +{ +	LV2_Atom_Float* out = (LV2_Atom_Float*)lv2_atom_forge_atom_head( +		forge, parent, forge->Float, sizeof(LV2_Atom_Float)); +	if (out) { +		out->value = val; +	} +	return out; +} + +/** Write an atom:Double. */ +static inline LV2_Atom_Double* +lv2_atom_forge_double(LV2_Atom_Forge* forge, LV2_Atom* parent, double val) +{ +	LV2_Atom_Double* out = (LV2_Atom_Double*)lv2_atom_forge_atom_head( +		forge, parent, forge->Double, sizeof(LV2_Atom_Double)); +	if (out) { +		out->value = val; +	} +	return out; +} + +/** Write an atom:Bool. */ +static inline LV2_Atom_Bool* +lv2_atom_forge_bool(LV2_Atom_Forge* forge, LV2_Atom* parent, bool val) +{ +	LV2_Atom_Bool* out = (LV2_Atom_Bool*)lv2_atom_forge_atom_head( +		forge, parent, forge->Bool, sizeof(LV2_Atom_Bool)); +	if (out) { +		out->value = val ? 1 : 0; +	} +	return out; +} + +/** Write an atom:URID. */ +static inline LV2_Atom_URID* +lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_Atom* parent, LV2_URID id) +{ +	LV2_Atom_URID* out = (LV2_Atom_URID*)lv2_atom_forge_reserve( +		forge, parent, sizeof(LV2_Atom_URID)); +	if (out) { +		out->atom.type = forge->URID; +		out->atom.size = sizeof(uint32_t); +		out->id        = id; +	} +	return out; +} + +/** Write an atom:String. */ +static inline LV2_Atom_String* +lv2_atom_forge_string(LV2_Atom_Forge* forge, +                      LV2_Atom*       parent, +                      const uint8_t*  str, +                      size_t          len) +{ +	LV2_Atom_String* out = (LV2_Atom_String*)lv2_atom_forge_reserve( +		forge, parent, sizeof(LV2_Atom_String) + len + 1); +	if (out) { +		out->atom.type = forge->String; +		out->atom.size = len + 1; +		assert(LV2_ATOM_CONTENTS(LV2_Atom_String, out) == LV2_ATOM_BODY(out)); +		uint8_t* buf = LV2_ATOM_CONTENTS(LV2_Atom_String, out); +		memcpy(buf, str, len); +		buf[len] = '\0'; +	} +	return out; +} + +/** Write an atom:Literal. */ +static inline LV2_Atom_Literal* +lv2_atom_forge_literal(LV2_Atom_Forge* forge, +                       LV2_Atom*       parent, +                       const uint8_t*  str, +                       size_t          len, +                       uint32_t        datatype, +                       uint32_t        lang) +{ +	LV2_Atom_Literal* out = (LV2_Atom_Literal*)lv2_atom_forge_reserve( +		forge, parent, sizeof(LV2_Atom_Literal) + len + 1); +	if (out) { +		out->atom.type        = forge->Literal; +		out->atom.size        = sizeof(LV2_Atom_Literal_Head) + len + 1; +		out->literal.datatype = datatype; +		out->literal.lang     = lang; +		uint8_t* buf = LV2_ATOM_CONTENTS(LV2_Atom_Literal, out); +		memcpy(buf, str, len); +		buf[len] = '\0'; +	} +	return out; +} + +/** Write an atom:Vector header and reserve space for the body. */ +static inline LV2_Atom_Vector* +lv2_atom_forge_reserve_vector(LV2_Atom_Forge* forge, +                              LV2_Atom*       parent, +                              uint32_t        elem_count, +                              uint32_t        elem_type, +                              uint32_t        elem_size) +{ +	const size_t     size = sizeof(LV2_Atom_Vector) + (elem_size * elem_count); +	LV2_Atom_Vector* out  = (LV2_Atom_Vector*)lv2_atom_forge_reserve( +		forge, parent, size); +	if (out) { +		out->atom.type  = forge->Vector; +		out->atom.size  = size - sizeof(LV2_Atom); +		out->elem_count = elem_count; +		out->elem_type  = elem_type; +	} +	return out; +} + +/** Write an atom:Vector. */ +static inline LV2_Atom_Vector* +lv2_atom_forge_vector(LV2_Atom_Forge* forge, +                      LV2_Atom*       parent, +                      uint32_t        elem_count, +                      uint32_t        elem_type, +                      uint32_t        elem_size, +                      void*           elems) +{ +	LV2_Atom_Vector* out = lv2_atom_forge_reserve_vector( +		forge, parent, elem_count, elem_type, elem_size); +	if (out) { +		uint8_t* buf = LV2_ATOM_CONTENTS(LV2_Atom_Vector, out); +		memcpy(buf, elems, elem_size * elem_count); +	} +	return out; +} + +/** +   Write the header of an atom:Tuple. + +   To complete the tuple, write a sequence of atoms, always passing the +   returned tuple as the @c parent parameter (or otherwise ensuring the size is +   updated correctly). + +   For example: +   @code +   // Write tuple (1, 2.0) +   LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, NULL); +   lv2_atom_forge_int32(forge, tup, 1); +   lv2_atom_forge_float(forge, tup, 2.0); +   @endcode +*/ +static inline LV2_Atom_Tuple* +lv2_atom_forge_tuple(LV2_Atom_Forge* forge, +                     LV2_Atom*       parent) +{ +	return (LV2_Atom_Tuple*)lv2_atom_forge_atom_head( +		forge, parent, forge->Tuple, sizeof(LV2_Atom)); +} + +/** +   Write the header of an atom:Object. + +   To complete the object, write a sequence of properties, always passing the +   object as the @c parent parameter (or otherwise ensuring the size is updated +   correctly). + +   For example: +   @code +   LV2_URID eg_Cat  = map("http://example.org/Cat"); +   LV2_URID eg_name = map("http://example.org/name"); + +   // Write object header +   LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_object(forge, NULL, 0, eg_Cat); + +   // Write property: eg:name = "Hobbes" +   lv2_atom_forge_property_head(forge, obj, eg_name, 0); +   lv2_atom_forge_string(forge, obj, "Hobbes", strlen("Hobbes")); +   @endcode +*/ +static inline LV2_Atom_Object* +lv2_atom_forge_object(LV2_Atom_Forge* forge, +                      LV2_Atom*       parent, +                      LV2_URID        id, +                      LV2_URID        type) +{ +	LV2_Atom_Object* out = (LV2_Atom_Object*)lv2_atom_forge_reserve( +		forge, parent, sizeof(LV2_Atom_Object)); +	if (out) { +		out->atom.type = forge->Object; +		out->atom.size = sizeof(LV2_Atom_Object) - sizeof(LV2_Atom); +		out->id        = id; +		out->type      = type; +	} +	return out; +} + +/** +   Write the header for a property body (likely in an Object). +   See lv2_atom_forge_object() documentation for an example. +*/ +static inline LV2_Atom_Property_Body* +lv2_atom_forge_property_head(LV2_Atom_Forge* forge, +                             LV2_Atom*       parent, +                             LV2_URID        key, +                             LV2_URID        context) +{ +	LV2_Atom_Property_Body* out = (LV2_Atom_Property_Body*) +		lv2_atom_forge_reserve(forge, parent, 2 * sizeof(uint32_t)); +	if (out) { +		out->key     = key; +		out->context = context; +	} +	return out; +} + +/** +   Write the header for a Sequence. +   The size of the returned sequence will be 0, so passing it as the parent +   parameter to other forge methods will do the right thing. +*/ +static inline LV2_Atom_Sequence* +lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, +                             LV2_Atom*       parent, +                             uint32_t        capacity) +{ +	LV2_Atom_Sequence* out = (LV2_Atom_Sequence*) +		lv2_atom_forge_reserve(forge, parent, sizeof(LV2_Atom_Sequence)); +	if (out) { +		out->atom.type = forge->Sequence; +		out->atom.size = sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom); +		out->capacity  = capacity; +		out->pad       = 0; +	} +	return out; +} + +/** +   Write the time stamp header of an Event (in a Sequence) in audio frames. +   After this, call the appropriate forge method(s) to write the body, passing +   the same @c parent parameter.  Note the returned LV2_Event is NOT an Atom. +*/ +static inline LV2_Atom_Event* +lv2_atom_forge_audio_time(LV2_Atom_Forge* forge, +                          LV2_Atom*       parent, +                          uint32_t        frames, +                          uint32_t        subframes) +{ +	LV2_Atom_Event* out = (LV2_Atom_Event*) +		lv2_atom_forge_reserve(forge, parent, 2 * sizeof(uint32_t)); +	if (out) { +		out->time.audio.frames    = frames; +		out->time.audio.subframes = subframes; +	} +	return out; +} + +/** +   Write the time stamp header of an Event (in a Sequence) in beats. +   After this, call the appropriate forge method(s) to write the body, passing +   the same @c parent parameter.  Note the returned LV2_Event is NOT an Atom. +*/ +static inline LV2_Atom_Event* +lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, +                         LV2_Atom*       parent, +                         double          beats) +{ +	LV2_Atom_Event* out = (LV2_Atom_Event*) +		lv2_atom_forge_reserve(forge, parent, sizeof(double)); +	if (out) { +		out->time.beats = beats; +	} +	return out; +} + +#ifdef __cplusplus +}  /* extern "C" */ +#endif + +#endif  /* LV2_ATOM_FORGE_H */ diff --git a/lv2/lv2plug.in/ns/ext/atom/manifest.ttl b/lv2/lv2plug.in/ns/ext/atom/manifest.ttl new file mode 100644 index 0000000..37f0f58 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/manifest.ttl @@ -0,0 +1,9 @@ +@prefix lv2:  <http://lv2plug.in/ns/lv2core#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://lv2plug.in/ns/ext/atom> +	a lv2:Specification ; +	lv2:minorVersion 0 ; +	lv2:microVersion 4 ; +	rdfs:seeAlso <atom.ttl> . + diff --git a/lv2/lv2plug.in/ns/ext/atom/waf b/lv2/lv2plug.in/ns/ext/atom/waf new file mode 120000 index 0000000..5235032 --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/waf @@ -0,0 +1 @@ +../../../../../waf
\ No newline at end of file diff --git a/lv2/lv2plug.in/ns/ext/atom/wscript b/lv2/lv2plug.in/ns/ext/atom/wscript new file mode 120000 index 0000000..7e2c01b --- /dev/null +++ b/lv2/lv2plug.in/ns/ext/atom/wscript @@ -0,0 +1 @@ +../../../../../ext.wscript
\ No newline at end of file |