diff options
Diffstat (limited to 'lv2/ns/ext')
| -rw-r--r-- | lv2/ns/ext/atom/atom-buffer.h | 163 | ||||
| -rw-r--r-- | lv2/ns/ext/atom/atom-helpers.h | 306 | ||||
| -rw-r--r-- | lv2/ns/ext/atom/atom.h | 279 | ||||
| -rw-r--r-- | lv2/ns/ext/atom/atom.ttl | 455 | ||||
| -rw-r--r-- | lv2/ns/ext/atom/forge.h | 424 | ||||
| -rw-r--r-- | lv2/ns/ext/atom/manifest.ttl | 2 | ||||
| -rw-r--r-- | lv2/ns/ext/state/state.ttl | 13 | 
7 files changed, 988 insertions, 654 deletions
| diff --git a/lv2/ns/ext/atom/atom-buffer.h b/lv2/ns/ext/atom/atom-buffer.h deleted file mode 100644 index f4b90dd..0000000 --- a/lv2/ns/ext/atom/atom-buffer.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -  Copyright 2008-2011 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-event-buffer.h Helper functions for atom:EventBuffer. - -   Note that these functions are all static inline which basically means: -   do not take the address of these functions. -*/ - -#ifndef LV2_ATOM_EVENT_BUFFER_H -#define LV2_ATOM_EVENT_BUFFER_H - -#include <stdint.h> -#include <stdbool.h> -#include <string.h> -#include <stdlib.h> - -#include "lv2/lv2plug.in/ns/ext/atom/atom.h" - -/** -   Initialize an existing atom buffer. -   All fields of @c buf are reset, except capacity which is unmodified. -*/ -static inline void -lv2_atom_buffer_reset(LV2_Atom_Buffer* buf) -{ -	buf->event_count = 0; -	buf->size        = 0; -} - -/** -   Allocate a new, empty atom buffer. -*/ -static inline LV2_Atom_Buffer* -lv2_atom_buffer_new(uint32_t capacity) -{ -	const uint32_t   size = sizeof(LV2_Atom_Buffer) + capacity; -	LV2_Atom_Buffer* buf  = (LV2_Atom_Buffer*)malloc(size); -	if (buf) { -		buf->data     = (uint8_t*)(buf + 1); -		buf->capacity = capacity; -		lv2_atom_buffer_reset(buf); -	} -	return buf; -} - -/** -   Free an atom buffer allocated with lv2_atom_buffer_new(). -*/ -static inline void -lv2_atom_buffer_free(LV2_Atom_Buffer* buf) -{ -	free(buf); -} - -/** -   An iterator over an LV2_Atom_Buffer. -*/ -typedef struct { -	LV2_Atom_Buffer* buf; -	uint32_t         offset; -} LV2_Atom_Buffer_Iterator; - -/** -   Return an iterator to the beginning of @c buf. -*/ -static inline LV2_Atom_Buffer_Iterator -lv2_atom_buffer_begin(LV2_Atom_Buffer* buf) -{ -	const LV2_Atom_Buffer_Iterator i = { buf, 0 }; -	return i; -} - -/** -   Return true iff @c i points to a valid atom. -*/ -static inline bool -lv2_atom_buffer_is_valid(LV2_Atom_Buffer_Iterator i) -{ -	return i.offset < i.buf->size; -} - -/** -   Return the iterator to the next element after @c i. -   @param i A valid iterator to an atom in a buffer. -*/ -static inline LV2_Atom_Buffer_Iterator -lv2_atom_buffer_next(LV2_Atom_Buffer_Iterator i) -{ -	if (!lv2_atom_buffer_is_valid(i)) { -		return i; -	} -	const LV2_Atom_Event* const ev = (LV2_Atom_Event*)(i.buf->data + i.offset); -	i.offset += lv2_atom_pad_size(sizeof(LV2_Atom_Event) + ev->body.size); -	return i; -} - -/** -   Return a pointer to the atom currently pointed to by @c i. -*/ -static inline LV2_Atom_Event* -lv2_atom_buffer_get(LV2_Atom_Buffer_Iterator i) -{ -	if (!lv2_atom_buffer_is_valid(i)) { -		return NULL; -	} -	return (LV2_Atom_Event*)(i.buf->data + i.offset); -} - -/** -   Write an atom to a buffer. - -   The atom will be written at the location pointed to by @c i, which will be -   incremented to point to the location where the next atom should be written -   (which is likely now garbage).  Thus, this function can be called repeatedly -   with a single @c i to write a sequence of atoms to the buffer. - -   @return True if atom was written, otherwise false (buffer is full). -*/ -static inline bool -lv2_atom_buffer_write(LV2_Atom_Buffer_Iterator* i, -                      uint32_t                  frames, -                      uint32_t                  subframes, -                      uint32_t                  type, -                      uint32_t                  size, -                      const uint8_t*            data) -{ -	const uint32_t free_space = i->buf->capacity - i->buf->size; -	if (free_space < sizeof(LV2_Atom_Event) + size) { -		return false; -	} - -	LV2_Atom_Event* const ev = (LV2_Atom_Event*)(i->buf->data + i->offset); - -	ev->frames    = frames; -	ev->subframes = subframes; -	ev->body.type = type; -	ev->body.size = size; -	memcpy((uint8_t*)ev + sizeof(LV2_Atom_Event), data, size); -	++i->buf->event_count; - -	size          = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + size); -	i->buf->size += size; -	i->offset    += size; - -	return true; -} - -#endif /* LV2_ATOM_EVENT_BUFFER_H */ diff --git a/lv2/ns/ext/atom/atom-helpers.h b/lv2/ns/ext/atom/atom-helpers.h index 4e51c89..6fff74b 100644 --- a/lv2/ns/ext/atom/atom-helpers.h +++ b/lv2/ns/ext/atom/atom-helpers.h @@ -1,5 +1,5 @@  /* -  Copyright 2008-2011 David Robillard <http://drobilla.net> +  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 @@ -17,153 +17,285 @@  /**     @file atom-helpers.h Helper functions for the LV2 Atom extension. -   These functions are provided for convenience only, use of them is not -   required for supporting atoms. +   Note these functions are all static inline, do not take their address. -   Note that these functions are all static inline which basically means: -   do not take the address of these functions. +   This header is non-normative, it is provided for convenience.  */  #ifndef LV2_ATOM_HELPERS_H  #define LV2_ATOM_HELPERS_H -#include <stdbool.h>  #include <stdint.h>  #include <stdio.h>  #include <string.h>  #include "lv2/lv2plug.in/ns/ext/atom/atom.h" -typedef LV2_Atom_Property* LV2_Thing_Iter; +#ifdef __cplusplus +extern "C" { +#else +#    include <stdbool.h> +#endif -/** Get an iterator pointing to @c prop in some LV2_Thing */ -static inline LV2_Thing_Iter -lv2_thing_begin(const LV2_Thing* obj) +/** Pad a size to 64 bits. */ +static inline uint32_t +lv2_atom_pad_size(uint32_t size)  { -	return (LV2_Thing_Iter)(obj->properties); +	return (size + 7) & (~7);  } -/** Return true iff @c iter has reached the end of @c thing */ +/** Return true iff @p atom is null. */  static inline bool -lv2_thing_iter_is_end(const LV2_Thing* obj, LV2_Thing_Iter iter) +lv2_atom_is_null(const LV2_Atom* atom)  { -	return (uint8_t*)iter >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->size); +	return !atom || (atom->type == 0 && atom->size == 0);  } -/** Return true iff @c l points to the same property as @c r */ +/** Return true iff @p a is equal to @p b. */  static inline bool -lv2_thing_iter_equals(const LV2_Thing_Iter l, const LV2_Thing_Iter r) +lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)  { -	return l == r; +	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 an iterator to the property following @c iter */ -static inline LV2_Thing_Iter -lv2_thing_iter_next(const LV2_Thing_Iter iter) +/** 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 (LV2_Thing_Iter)((uint8_t*)iter -	                        + sizeof(LV2_Atom_Property) -	                        + lv2_atom_pad_size(iter->value.size)); +	return (uint8_t*)i >= ((uint8_t*)seq + sizeof(LV2_Atom) + seq->atom.size);  } -/** Return the property pointed to by @c iter */ -static inline LV2_Atom_Property* -lv2_thing_iter_get(LV2_Thing_Iter iter) +/** 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_Property*)iter; +	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 properties of an Thing. -   @param thing The thing to iterate over +   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.: -   <pre> -   LV2_THING_FOREACH(thing, i) { -   LV2_Atom_Property* prop = lv2_thing_iter_get(i); -   // Do things with prop here... +   @code +   LV2_SEQUENCE_FOREACH(sequence, i) { +       LV2_Atom_Event* ev = lv2_sequence_iter_get(i); +       // Do something with ev here...     } -   </pre> +   @endcode  */ -#define LV2_THING_FOREACH(thing, iter)                                  \ -	for (LV2_Thing_Iter (iter) = lv2_thing_begin(thing); \ -	     !lv2_thing_iter_is_end(thing, (iter)); \ -	     (iter) = lv2_thing_iter_next(iter)) +#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))  /** -   Append a Property body to an Atom that contains properties (e.g. atom:Thing). -   @param thing Pointer to the atom that contains the property to add.  thing.size -   must be valid, but thing.type is ignored. -   @param key The key of the new property -   @param value_type The type of the new value -   @param value_size The size of the new value -   @param value_body Pointer to the new value's data -   @return a pointer to the new LV2_Atom_Property in @c body. - -   This function will write the property body (not including an LV2_Thing -   header) at lv2_atom_pad_size(body + size).  Thus, it can be used with any -   Atom type that contains headerless 32-bit aligned properties. +   @} +   @name Tuple Iterator +   @{  */ -static inline LV2_Atom_Property* -lv2_thing_append(LV2_Thing* thing, -                 uint32_t    key, -                 uint32_t    value_type, -                 uint32_t    value_size, -                 const void* value_body) -{ -	thing->size = lv2_atom_pad_size(thing->size); -	LV2_Atom_Property* prop = (LV2_Atom_Property*)( -		(uint8_t*)thing + sizeof(LV2_Atom) + thing->size); -	prop->key = key; -	prop->value.type = value_type; -	prop->value.size = value_size; -	memcpy(prop->value.body, value_body, value_size); -	thing->size += sizeof(LV2_Atom_Property) + value_size; -	return prop; -} - -/** Return true iff @c atom is NULL */ + +/** 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_atom_is_null(LV2_Atom* atom) +lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i)  { -	return !atom || (atom->type == 0 && atom->size == 0); +	return (uint8_t*)i >= ((uint8_t*)tup + sizeof(LV2_Atom) + tup->atom.size);  } -/** A single entry in an Thing query. */ +/** 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_Thing_Query; +} LV2_Atom_Object_Query; -static const LV2_Thing_Query LV2_THING_QUERY_END = { 0, NULL }; +static const LV2_Atom_Object_Query LV2_OBJECT_QUERY_END = { 0, NULL };  /** -   "Query" an thing, getting a pointer to the values for various keys. +   Get an object's values for various keys. -   The value pointer of each item in @c query will be set to the location of -   the corresponding value in @c thing.  Every value pointer in @c query MUST -   be initialised to NULL.  This function reads @c thing in a single linear -   sweep.  By allocating @c query on the stack, things can be "queried" +   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_thing_query(const LV2_Thing* thing, LV2_Thing_Query* query) +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_Thing_Query* q = query; q->key; ++q) +	for (LV2_Atom_Object_Query* q = query; q->key; ++q) {  		++n_queries; +	} -	LV2_THING_FOREACH(thing, o) { -		const LV2_Atom_Property* prop = lv2_thing_iter_get(o); -		for (LV2_Thing_Query* q = query; q->key; ++q) { +	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) +				if (++matches == n_queries) {  					return matches; +				}  				break;  			}  		} @@ -171,4 +303,8 @@ lv2_thing_query(const LV2_Thing* thing, LV2_Thing_Query* query)  	return matches;  } +/** +   @} +*/ +  #endif /* LV2_ATOM_HELPERS_H */ diff --git a/lv2/ns/ext/atom/atom.h b/lv2/ns/ext/atom/atom.h index 569ab49..7a29dae 100644 --- a/lv2/ns/ext/atom/atom.h +++ b/lv2/ns/ext/atom/atom.h @@ -1,5 +1,5 @@  /* -  Copyright 2008-2011 David Robillard <http://drobilla.net> +  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 @@ -36,148 +36,152 @@  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]; +  /** -   An LV2 Atom. +   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))) -   An "Atom" is a generic chunk of memory with a given type and size. -   The type field defines how to interpret an atom. +/** 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) -   All atoms are by definition Plain Old Data (POD) and may be safely copied -   (e.g. with memcpy) using the size field, except atoms with type 0.  An atom -   with type 0 is a reference, and may only be used via the functions provided -   in LV2_Blob_Support (e.g. it MUST NOT be manually copied). -*/ +/** 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. */ -	uint8_t  body[];  /**< Body of length @ref size bytes. */ +	uint32_t type;  /**< Type of this atom (mapped URI). */ +	uint32_t size;  /**< Size in bytes, not including type and size. */  } LV2_Atom; -/** -   An atom:String. -   May be cast to 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 { -	uint32_t type;   /**< Type of this atom (mapped URI). */ -	uint32_t size;   /**< Size in bytes, not including type and size. */ -	uint8_t  str[];  /**< Null-terminated string data in UTF-8 encoding. */ +	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; -/** -   An atom:Literal. -   May be cast to LV2_Atom. -*/ +/** The header of an atom:Literal body. */  typedef struct { -	uint32_t type;      /**< Type of this atom (mapped URI). */ -	uint32_t size;      /**< Size in bytes, not including type and size. */  	uint32_t datatype;  /**< The ID of the datatype of this literal. */  	uint32_t lang;      /**< The ID of the language of this literal. */ -	uint8_t  str[];     /**< Null-terminated string data in UTF-8 encoding. */ +} 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; -/** -   An atom:URID or atom:BlankID. -   May be cast to LV2_Atom. -*/ +/** The complete header of an atom:Tuple. */  typedef struct { -	uint32_t type;  /**< Type of this atom (mapped URI). */ -	uint32_t size;  /**< Size in bytes, not including type and size. */ -	uint32_t id;    /**< URID (integer mapped URI) or blank node ID. */ -} LV2_Atom_URID; +	LV2_Atom atom;  /**< Atom header. */ +	/* Contents (a series of complete atoms) follow here. */ +} LV2_Atom_Tuple; -/** -   An atom:Vector. -   May be cast to LV2_Atom. -*/ +/** The complete header of an atom:Vector. */  typedef struct { -	uint32_t type;        /**< Type of this atom (mapped URI). */ -	uint32_t size;        /**< Size in bytes, not including type and size. */ +	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 */ -	uint8_t  elems[];     /**< Sequence of element bodies */ +	/* Contents (a series of packed atom bodies) follow here. */  } LV2_Atom_Vector; -/** -   The body of an atom:Property. -   Note this type is not an LV2_Atom. -*/ -typedef struct _LV2_Atom_Property { -	uint32_t key;    /**< Key (predicate) (mapped URI). */ -	LV2_Atom value;  /**< Value (object) */ -} LV2_Atom_Property; - -/** -   An atom:Thing (Resource, Blank, or Message). -   May be cast to LV2_Atom. -*/ +/** The header of an atom:Property body (e.g. in an atom:Object). */  typedef struct { -	uint32_t type;          /**< Type of this atom (mapped URI). */ -	uint32_t size;          /**< Size in bytes, not including type and size. */ -	uint32_t context;       /**< ID of context graph, or 0 for default */ -	uint32_t id;            /**< URID (for Resource) or blank ID (for Blank) */ -	uint8_t  properties[];  /**< Sequence of LV2_Atom_Property */ -} LV2_Thing; +	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; -/** -   An atom:Event, a timestamped Atom. -   Note this type is not an LV2_Atom, but contains an Atom as payload. -*/ +/** The complete header of an atom:Property. */  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 body;       /**< Event body. */ -} LV2_Atom_Event; +	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; -/** -   An atom:Int32, a signed 32-bit integer. -   May be cast to LV2_Atom. -*/ +/** The complete header of an atom:Object. */  typedef struct { -	uint32_t type; -	uint32_t size; -	int32_t  value; -} LV2_Atom_Int32; +	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; -/** -   An atom:Int64, a signed 64-bit integer. -   May be cast to LV2_Atom. -*/ +/** The complete header of an atom:Response. */  typedef struct { -	uint32_t type; -	uint32_t size; -	int64_t  value; -} LV2_Atom_Int64; - -/** -   An atom:Float, a 32-bit IEEE-754 floating point number. -   May be cast to LV2_Atom. -*/ +	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 type; -	uint32_t size; -	float    value; -} LV2_Atom_Float; +	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; -/** -   An atom:Double, a 64-bit IEEE-754 floating point number. -   May be cast to LV2_Atom. -*/ +/** The header of an atom:Event.  Note this type is NOT an LV2_Atom. */  typedef struct { -	uint32_t type; -	uint32_t size; -	double   value; -} LV2_Atom_Double; +	/** 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 buffer of events (the contents of an atom:EventPort). +   A sequence of events (time-stamped atoms). -   The host MAY elect to allocate buffers as a single chunk of POD by using -   this struct as a header much like LV2_Atom, or it may choose to point to -   a fragment of a buffer elsewhere.  In either case, @ref data points to the -   start of the data contained in this buffer. +   This is used as the contents of an atom:EventPort, but is a generic Atom +   type which can be used anywhere. -   The buffer at @ref data contains a sequence of LV2_Atom_Event padded such -   that the start of each event is aligned to 64 bits, e.g.: +   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     |       |       |       |       |       |       |       |       | @@ -186,60 +190,11 @@ typedef struct {     </pre>  */  typedef struct { - -	/** -	   The contents of the event buffer. This may or may not reside in the -	   same block of memory as this header, plugins must not assume either. -	   The host guarantees this points to at least capacity bytes of allocated -	   memory (though only size bytes of that are valid events). -	*/ -	uint8_t* data; - -	/** -	   The number of events in this buffer. - -	   INPUTS: The host must set this field to the number of events contained -	   in the data buffer before calling run(). The plugin must not change -	   this field. - -	   OUTPUTS: The plugin must set this field to the number of events it has -	   written to the buffer before returning from run(). Any initial value -	   should be ignored by the plugin. -	*/ -	uint32_t event_count; - -	/** -	   The capacity of the data buffer in bytes. -	   This is set by the host and must not be changed by the plugin. -	   The host is allowed to change this between run() calls. -	*/ -	uint32_t capacity; - -	/** -	   The size of the initial portion of the data buffer containing data. - -	   INPUTS: The host must set this field to the number of bytes used -	   by all events it has written to the buffer (including headers) -	   before calling the plugin's run(). -	   The plugin must not change this field. - -	   OUTPUTS: The plugin must set this field to the number of bytes -	   used by all events it has written to the buffer (including headers) -	   before returning from run(). -	   Any initial value should be ignored by the plugin. -	*/ -	uint32_t size; - -} LV2_Atom_Buffer; - -/** -   Pad a size to 64 bits. -*/ -static inline uint32_t -lv2_atom_pad_size(uint32_t size) -{ -	return (size + 7) & (~7); -} +	LV2_Atom atom;      /**< Atom header. */ +	uint32_t capacity;  /**< Maximum size of contents. */ +	uint32_t pad; +	/* Contents (a series of events) follow here. */ +} LV2_Atom_Sequence;  #ifdef __cplusplus  }  /* extern "C" */ diff --git a/lv2/ns/ext/atom/atom.ttl b/lv2/ns/ext/atom/atom.ttl index c28b610..7d534d0 100644 --- a/lv2/ns/ext/atom/atom.ttl +++ b/lv2/ns/ext/atom/atom.ttl @@ -27,10 +27,11 @@  	doap:name "LV2 Atom" ;  	doap:shortdesc "A generic value container and several data types." ;  	doap:license <http://opensource.org/licenses/isc> ; -	rdfs:seeAlso <atom-buffer.h> ; +	rdfs:seeAlso <atom-helpers.h> , +		<forge.h> ;  	doap:release [ -		doap:revision "0.3" ; -		doap:created "2012-01-28" +		doap:revision "0.4" ; +		doap:created "2012-02-07"  	] ;  	doap:maintainer [  		a foaf:Person ; @@ -39,68 +40,118 @@  		rdfs:seeAlso <http://drobilla.net/drobilla.rdf>  	] ;  	lv2:documentation """ -<p>This extension defines a generic format for a typed piece of data, called an -lv2:Atom (e.g. integers, strings, buffers, data structures, -etc).  Atoms allow LV2 plugins and hosts to communicate, process, serialise, -and store values of any type via a generic mechanism (e.g. LV2 ports, events, -disk, shared memory, network).  Atoms are, with one exception, Plain -Old Data (POD) and may be safely copied (e.g. with a simple call to -<code>memcpy</code>).</p> +<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>An Atom can be trivially constructed in-place from an -<a href="http://lv2plug.in/ns/ext/event#Event">Event</a> as defined by the -<a href="http://lv2plug.in/ns/ext/event">LV2 Event</a> extension.  In other -words, an Event is simply an Atom with a time stamp header.  Atoms SHOULD -be used anywhere a "value" needs to be stored or communicated, to allow -implementations to be polymorphic and extensible.</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>Atoms (the start of the LV2_Atom header) MUST be 32-bit aligned.</p> - -<p>Atoms can be communicated in many ways.  Since an Atom is the payload of an -Event, an <a href="http://lv2plug.in/ns/ext/event#EventPort">EventPort</a> can -be used for communicating Atoms in realtime with sub-sample time stamp -accuracy.  This extension also defines two port types for connecting directly -to a single Atom: atom:ValuePort and atom:MessagePort, which both have the same -buffer format but different semantics (with respect to how the run() callback -interprets the Atom).</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 <code>body</code> of -<code>size</code> bytes.</p> +<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 <code>body</code>.</p> +binary layout for their body.</p> -<p>The <code>type</code> field is the URI of a subclass of Atom mapped to an -integer using the <a href="http://lv2plug.in/ns/ext/uri-map">URI Map</a> -extension's LV2_URI_Map_Feature::uri_to_id() with -<code>map = "http://lv2plug.in/ns/ext/event"</code>.  If a plugin or host -does not understand <code>type</code>, that atom SHOULD be gracefully ignored -(or copied if it does not have type 0).</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, actual specification of how references are used is left -to another extension.</p> +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 ; @@ -128,7 +179,7 @@ atom:Literal  <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 +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 @@ -143,22 +194,26 @@ 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->type     = map(expand("atom:Literal")); -     lit->size     = 14; -     lit->datatype = 0; -     lit->lang     = map("http://lexvo.org/id/term/en"); -     memcpy(lit->str, "Hello", sizeof("Hello"));  // Assumes enough space +     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->type     = map(expand("atom:Literal")); -     lit->size     = 64; -     lit->datatype = map("http://www.w3.org/2008/turtle#turtle"); -     lit->lang     = 0; -     memcpy(lit->str, ttl, strlen(ttl) + 1);  // Assumes enough space +     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>  """ . @@ -169,21 +224,7 @@ atom:URID  	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 using the <a -href="http://lv2plug.in/ns/ext/uri-map">URI Map</a> extension's -LV2_URI_Map_Feature::uri_to_id() with <code>map = NULL</code>.</p> -""" . - -atom:BlankID -	a rdfs:Class ; -	rdfs:subClassOf atom:Atom ; -	rdfs:label "Integer ID for a blank node" ; -	atom:cType "LV2_Atom_ID" ; -	lv2:documentation """ -<p>An unsigned 32-bit integer identifier for a blank node.  A BlankID is only -meaningful within a limited scope (e.g. the Atom in which it appears), and -MUST NOT be used as a global identifier.  In particular, a BlankID is NOT a -URID, and can not be mapped to/from a URI.</p> +<p>An unsigned 32-bit integer mapped from a URI (e.g. with LV2_URID_Map).</p>  """ .  atom:Vector @@ -192,7 +233,7 @@ atom:Vector  	rdfs:label "Vector" ;  	atom:cType "LV2_Atom_Vector" ;  	lv2:documentation """ -<p>A homogeneous sequence of atoms with equivalent type and size.</p> +<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 @@ -221,125 +262,84 @@ atom:Tuple  	rdfs:subClassOf atom:Atom ;  	rdfs:label "Tuple" ;  	lv2:documentation """ -<p>A sequence of lv2:Atom with varying <code>type</code> -and <code>size</code>.</p> +<p>A series of Atoms with varying <code>type</code> and <code>size</code>.</p> -<p>The body of a Tuple is simply a sequence of complete atoms, each aligned to -32 bits.</p> +<p>The body of a Tuple is simply a series of complete atoms, each aligned to +64 bits.</p>  """ . -atom:Thing +atom:Property  	a rdfs:Class ;  	rdfs:subClassOf atom:Atom ; -	rdfs:label "Thing" ; -	atom:cType "LV2_Thing" ; +	rdfs:label "Property" ; +	atom:cType "LV2_Atom_Property" ;  	lv2:documentation """ -<p>Abstract base class for a "Thing", i.e. an atom:Atom with a number of -properties.  An LV2_Object is an unsigned 32-bit integer <code>context</code> -and <code>id</code> followed by a sequence of LV2_Atom_Property .</p> - -<p>The <code>context</code> is mapped using the <a -href="http://lv2plug.in/ns/ext/uri-map">URI Map</a> extension's -LV2_URI_Map_Feature::uri_to_id() with <code>map = NULL</code>, and may be 0 -(the default context).</p> - -<p>Note this is an abstract class, i.e. no Atom can exist with <code>type = -uri_to_id(atom:Thing)</code>.  An Object is either an atom:Resource or an -atom:Blank, but the <code>body</code> always has the same binary format, -LV2_Object.  Thus, both named and anonymous objects can be handled with common -code using only a 64-bit header for both.</p> +<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:Resource +atom:Object  	a rdfs:Class ; -	rdfs:subClassOf atom:Thing ; -	atom:cType "LV2_Thing" ; +	rdfs:subClassOf atom:Atom ; +	rdfs:label "Object" ; +	atom:cType "LV2_Atom_Object" ;  	lv2:documentation """ -<p>An atom:Thing where <code>id</code> is the URI of the resource mapped to an -atom:URID.</p> +<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:Blank +atom:Resource  	a rdfs:Class ; -	rdfs:subClassOf atom:Thing ; -	atom:cType "LV2_Thing" ; +	rdfs:subClassOf atom:Object ; +	rdfs:label "Resource" ; +	atom:cType "LV2_Atom_Object" ;  	lv2:documentation """ -<p>An atom:Thing where <code>id</code> is the blank node ID of the object, -which is only meaningful within a certain limited scope (e.g. the container of -the Blank) and MUST NOT be used as a global ID.  In particular, <code>id</code> -is NOT a URID.</p> +<p>An atom:Object where the <code>id</code> field is a URID, i.e. an Object +with a URI.</p>  """ . -atom:Message +atom:Blank  	a rdfs:Class ; -	rdfs:subClassOf atom:Thing ; -	atom:cType "LV2_Thing" ; +	rdfs:subClassOf atom:Object ; +	rdfs:label "Blank" ; +	atom:cType "LV2_Atom_Object" ;  	lv2:documentation """ -<p>A atom:Thing where <code>id</code> is a message type ID.  Conceptually, a -Message is identical to a Blank, but is a distinct type with a single type -field to allow simple and fast dispatch by handling code.</p> - -<p>A Message may be serialised as a Blank by adding an rdf:type property with -the value <code>id</code> unmapped to a URI.</p> -""" . +<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 for sample accurate -transmission via LV2 ports.  See struct LV2_Atom_Event.</p> +<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:Bang -	a rdfs:Class ; -	rdfs:subClassOf atom:Atom ; -	rdfs:label "Bang (activity) (size = 0)" . - -atom:Number +atom:Sequence  	a rdfs:Class ;  	rdfs:subClassOf atom:Atom ; -	rdfs:label "Number (abstract class)." . - -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:Bool -	a rdfs:Class ; -	rdfs:subClassOf atom:Atom ; -	rdfs:label "An atom:Int32 where 0 is false and all other values true" ; -	atom:cType "LV2_Atom_Int32" . - -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:blobSupport -	a lv2:Feature ; -	rdfs:label "Blob support" ; +	rdfs:label "Sequence" ; +	atom:cType "LV2_Atom_Sequence" ;  	lv2:documentation """ -<p>Support for dynamically allocated blobs.  If a host supports this feature, -it MUST pass a LV2_Feature with <code>URI</code> -http://lv2plug.in/ns/ext/atom#blobSupport and <code>data</code> pointing to a -LV2_Blob_Support.</p> +<p>A sequence of atom:Event, i.e. a series of time-stamped Atoms.</p>  """ .  atom:AtomPort @@ -347,21 +347,20 @@ atom:AtomPort  	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 32-bit aligned LV2_Atom immediately followed by -<code>size</code> bytes of data.</p> - -<p>This is an abstract port type, i.e. a port MUST NOT only be an AtomPort, -but must be a more descriptive type that is a subclass of AtomPort which -defines the port's semantics (typically atom:ValuePort or atom:MessagePort). -</p> - -<p>Before calling a method on the 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 = 0</code> and <code>size = 0</code>).</p> +<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 @@ -369,67 +368,95 @@ atom:ValuePort  	rdfs:subClassOf atom:AtomPort ;  	rdfs:label "Value Port" ;  	lv2:documentation """ -<p>An AtomPort that interprets its data as a persistent and time-independent -"value".</p> + +<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 input values for all ports, 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 V of that ValuePort corresponds to a single set of outputs -for all ports.</li> -<li>If a ValuePort contains a reference then the blob it refers to is -constant; plugin MUST NOT modify the blob in any way.</li> +<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 can be thought of as purely functional ports: if a plugin -callback has only value ports, then the plugin callback is a pure function.</p> + +<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" ; -	rdfs:comment """ -An AtomPort that "receives", "consumes", "executes", or "sends" its value. -The Atom contained in a MessagePort is considered transient and/or -time-dependent, and is only valid for a single run invocation.  Unlike a -ValuePort, a MessagePort may be used to manipulate internal plugin state. - -Intuitively, a MessagePort contains a "message" or "command" or "event" -which is reacted to, NOT a "value" or "signal" (which is computed with). -""" . - -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. +	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:EventPort -	a rdfs:Class ; -	rdfs:label "Event port" ; -	rdfs:subClassOf lv2:Port ; +atom:bufferType +	a rdf:Property ; +	rdfs:domain atom:AtomPort ; +	rdfs:label "buffer type" ;  	lv2:documentation """ -<p>A port used for communicating time-stamped atoms in the audio context. -Ports of this type are connected to an LV2_Atom_Buffer, which contains a flat -time-stamped sequence of atom:Event.</p> +<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>This port type is intended as a simpler and atom compatible successor to <a -href="http://lv2plug.in/ns/ext/event#EventPort">ev:EventPort</a>.</p> +<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:domain lv2:Port ; -	rdfs:range atom:Atom ;  	rdfs:label "supports" ;  	lv2:documentation """ -<p>Indicates that a Port supports a certain atom:Atom type.  This is distinct from -the port type - e.g. the port type ValuePort can hold atoms with many different -types.  This property is used to describe which Atom types a Port expects to -receive or send.</p> +<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/ns/ext/atom/forge.h b/lv2/ns/ext/atom/forge.h index e8f5d40..2790778 100644 --- a/lv2/ns/ext/atom/forge.h +++ b/lv2/ns/ext/atom/forge.h @@ -1,5 +1,5 @@  /* -  Copyright 2008-2011 David Robillard <http://drobilla.net> +  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 @@ -15,57 +15,427 @@  */  /** -   @file forge.h Helper constructor functions for LV2 atoms. +   @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 { -	uint32_t ID; -	uint32_t Message; -	uint32_t Property; +	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; -static inline LV2_Atom_Forge* -lv2_atom_forge_new(LV2_URID_Map* map) +/** 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)  { -	LV2_Atom_Forge* forge = (LV2_Atom_Forge*)malloc(sizeof(LV2_Atom_Forge)); -	forge->ID       = map->map(map->handle, LV2_ATOM_URI "#ID"); -	forge->Message  = map->map(map->handle, LV2_ATOM_URI "#Message"); -	forge->Property = map->map(map->handle, LV2_ATOM_URI "#Property"); -	return forge; +	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_free(LV2_Atom_Forge* forge) +lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)  { -	free(forge); +	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");  } -static inline LV2_Atom_ID -lv2_atom_forge_make_id(LV2_Atom_Forge* forge, uint32_t id) +/** +   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)  { -	const LV2_Atom_ID atom = { forge->ID, sizeof(uint32_t), id }; -	return atom; +	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;  } -static inline void -lv2_atom_forge_set_message(LV2_Atom_Forge* forge, -                           LV2_Thing*      msg, -                           uint32_t        id) -{ -	msg->type    = forge->Message; -	msg->size    = sizeof(LV2_Thing) - sizeof(LV2_Atom); -	msg->context = 0; -	msg->id      = id; +/** +   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 diff --git a/lv2/ns/ext/atom/manifest.ttl b/lv2/ns/ext/atom/manifest.ttl index 20c974d..37f0f58 100644 --- a/lv2/ns/ext/atom/manifest.ttl +++ b/lv2/ns/ext/atom/manifest.ttl @@ -4,6 +4,6 @@  <http://lv2plug.in/ns/ext/atom>  	a lv2:Specification ;  	lv2:minorVersion 0 ; -	lv2:microVersion 3 ; +	lv2:microVersion 4 ;  	rdfs:seeAlso <atom.ttl> . diff --git a/lv2/ns/ext/state/state.ttl b/lv2/ns/ext/state/state.ttl index 84cda42..6c0656a 100644 --- a/lv2/ns/ext/state/state.ttl +++ b/lv2/ns/ext/state/state.ttl @@ -14,12 +14,20 @@  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -@prefix state: <http://lv2plug.in/ns/ext/state#> . +@prefix dcs:   <http://ontologi.es/doap-changeset#> .  @prefix doap:  <http://usefulinc.com/ns/doap#> .  @prefix foaf:  <http://xmlns.com/foaf/0.1/> .  @prefix lv2:   <http://lv2plug.in/ns/lv2core#> .  @prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .  @prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> . +@prefix state: <http://lv2plug.in/ns/ext/state#> . + +<http://drobilla.net/drobilla#me> +	a foaf:Person ; +	foaf:name "David Robillard" ; +	foaf:homepage <http://drobilla.net/> ; +	foaf:mbox <mailto:d@drobilla.net> ; +	rdfs:seeAlso <http://drobilla.net/drobilla> .  <http://lv2plug.in/ns/ext/state>  	a lv2:Specification ; @@ -28,7 +36,8 @@  	doap:license <http://opensource.org/licenses/isc> ;  	doap:release [  		doap:revision "0.5" ; -		doap:created "2012-01-29" +		doap:created "2012-01-29" ; +		dcs:blame <http://drobilla.net/drobilla#me>  	] ;  	doap:developer [  		a foaf:Person ; |