aboutsummaryrefslogtreecommitdiffstats
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/atom-port.lv2/atom-port.ttl127
-rw-r--r--ext/atom-port.lv2/manifest.ttl7
-rw-r--r--ext/atom.lv2/atom-helpers.h27
-rw-r--r--ext/atom.lv2/atom.h159
-rw-r--r--ext/atom.lv2/atom.ttl485
-rw-r--r--ext/message.lv2/message.ttl4
6 files changed, 403 insertions, 406 deletions
diff --git a/ext/atom-port.lv2/atom-port.ttl b/ext/atom-port.lv2/atom-port.ttl
deleted file mode 100644
index 7533606..0000000
--- a/ext/atom-port.lv2/atom-port.ttl
+++ /dev/null
@@ -1,127 +0,0 @@
-# LV2 Atom Port Extension
-# Copyright (C) 2010 David Robillard <d@drobilla.net>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-
-@prefix aport: <http://lv2plug.in/ns/ext/atom-port#> .
-@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 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-port>
- a lv2:Specification ;
- doap:name "LV2 Atom Port" ;
- doap:maintainer [
- a foaf:Person ;
- foaf:name "David Robillard" ;
- foaf:homepage <http://drobilla.net/> ;
- rdfs:seeAlso <http://drobilla.net/drobilla.rdf>
- ] ;
- rdfs:comment """
-This extension describes port types that hold polymorphic values
-(<a href="http://lv2plug.in/ns/ext/atom#Atom">atom:Atom</a>). There are
-two such port types with equivalent buffer formats but different semantics:
-value ports (aport:ValuePort) and message ports (aport:MessagePort).
-""" .
-
-
-aport:AtomPort a rdfs:Class ;
- rdfs:label "Atom Port" ;
- rdfs:subClassOf lv2:Port ;
- rdfs:comment """
-A port which contains a polymorphic value, or "atom".
-Ports of this type will be connected to a 32-bit aligned <a
-href="http://lv2plug.in/ns/ext/atom#Atom">atom:Atom</a> (i.e. a uint32_t type,
-immediately followed by a uint32_t size, immediately followed by that many
-bytes of data).
-
-This is an abstract port type. A port that is a aport:AtomPort MUST also
-have a more descriptive type that is a subClassOf aport:AtomPort which
-defines the port's semantics (typically aport:ValuePort or aport:MessagePort).
-
-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 type and size equal to zero).
-""" .
-
-
-#aport:respondsWith a rdf:Property ;
-# rdfs:domain aport:MessagePort ;
-# rdfs:range lv2:Symbol ;
-# rdfs:label "responds with" ;
-# rdfs:comment """
-#Indicates that a message port responds to messages via the port with the
-#given symbol on the same plugin instance. If
-#<pre>input aport:respondsWith output</pre> then after running the plugin with
-#a message <em>m</em> in <code>input</code> the host SHOULD interpret the aport:
-#in <code>output</code> as the response to <em>m</em>.
-#""" .
-
-
-aport:ValuePort a rdfs:Class ;
- rdfs:label "Value Port" ;
- rdfs:subClassOf aport:AtomPort ;
- rdfs:comment """
-An AtomPort that interprets its data as a persistent and time-independent
-"value".
-<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 an aport:ValuePort contains a reference then the blob it refers to is
-constant; plugin MUST NOT modify the blob in any way.</li>
-</ul>
-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.
-""" .
-
-
-aport:MessagePort a rdfs:Class ;
- rdfs:label "Message Port" ;
- rdfs:subClassOf aport:AtomPort ;
- rdfs:comment """
-An AtomPort that consumes or executes its value as a "message". The contents
-of a MessagePort are considered transient and/or time-dependent, and only
-apply for a single run invocation. Unlike a ValuePort, a MessagePort may
-be used to manipulate and access internal plugin state.
-
-Intuitively, a MessagePort contains a "command" or "event" (which is reacted
-to), NOT a "value" or "signal" (which is computed with).
-""" .
-
-aport:supports a rdf:Property ;
- rdfs:domain lv2:Port ;
- rdfs:range atom:AtomType ;
- rdfs:label "supports" ;
- rdfs:comment """
-Indicates that an atom port supports a certain value 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 ``understands''.
-""" .
-
diff --git a/ext/atom-port.lv2/manifest.ttl b/ext/atom-port.lv2/manifest.ttl
deleted file mode 100644
index e681793..0000000
--- a/ext/atom-port.lv2/manifest.ttl
+++ /dev/null
@@ -1,7 +0,0 @@
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-
-<http://lv2plug.in/ns/ext/atom-port>
- a lv2:Specification ;
- rdfs:seeAlso <atom-port.ttl> .
-
diff --git a/ext/atom.lv2/atom-helpers.h b/ext/atom.lv2/atom-helpers.h
index 5913aee..5c98a3f 100644
--- a/ext/atom.lv2/atom-helpers.h
+++ b/ext/atom.lv2/atom-helpers.h
@@ -46,24 +46,28 @@ lv2_atom_pad_size(uint16_t size)
typedef LV2_Atom_Property* LV2_Object_Iter;
+/** Get an iterator pointing to @a prop in some LV2_Object */
static inline LV2_Object_Iter
lv2_object_get_iter(LV2_Atom_Property* prop)
{
return (LV2_Object_Iter)prop;
}
+/** Return true iff @a iter has reached the end of @a object */
static inline bool
lv2_object_iter_is_end(const LV2_Atom* object, LV2_Object_Iter iter)
{
return (uint8_t*)iter >= (object->body + object->size);
}
+/** Return true iff @a l points to the same property as @a r */
static inline bool
lv2_object_iter_equals(const LV2_Object_Iter l, const LV2_Object_Iter r)
{
return l == r;
}
+/** Return an iterator to the property following @a iter */
static inline LV2_Object_Iter
lv2_object_iter_next(const LV2_Object_Iter iter)
{
@@ -71,6 +75,7 @@ lv2_object_iter_next(const LV2_Object_Iter iter)
(uint8_t*)iter + sizeof(LV2_Atom_Property) + lv2_atom_pad_size(iter->value.size));
}
+/** Return the property pointed to by @a iter */
static inline LV2_Atom_Property*
lv2_object_iter_get(LV2_Object_Iter iter)
{
@@ -86,6 +91,7 @@ lv2_object_iter_get(LV2_Object_Iter iter)
* LV2_Atom_Property* prop = lv2_object_iter_get(i);
* // Do things with prop here...
* }
+ * </pre>
*/
#define LV2_OBJECT_FOREACH(obj, iter) \
for (LV2_Object_Iter (iter) = lv2_object_get_iter((LV2_Atom_Property*)(obj)->body); \
@@ -98,17 +104,18 @@ lv2_object_iter_get(LV2_Object_Iter iter)
* Atom type that contains headerless 32-bit aligned properties.
* @param object Pointer to the atom that contains the property to add. object.size
* must be valid, but object.type is ignored.
- * @param size Must point to the size field of the container atom, and will be
- * padded up to 32 bits then increased by @a value_size.
- * @param body Must point to the body of the container atom.
+ * @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 @a body.
*/
static inline LV2_Atom_Property*
-lv2_atom_append_property(LV2_Atom* object,
- uint32_t key,
- uint16_t value_type,
- uint16_t value_size,
- const char* value_body)
+lv2_atom_append_property(LV2_Atom* object,
+ uint32_t key,
+ uint16_t value_type,
+ uint16_t value_size,
+ const uint8_t* value_body)
{
object->size = lv2_atom_pad_size(object->size);
LV2_Atom_Property* prop = (LV2_Atom_Property*)(object->body + object->size);
@@ -120,12 +127,14 @@ lv2_atom_append_property(LV2_Atom* object,
return prop;
}
+/** Return true iff @a atom is NULL */
static inline bool
lv2_atom_is_null(LV2_Atom* atom)
{
return !atom || (atom->type == 0 && atom->size == 0);
}
+/** Return true iff @a object has rdf:type @a type */
static inline bool
lv2_atom_is_a(LV2_Atom* object,
uint32_t rdf_type,
@@ -173,7 +182,7 @@ typedef struct {
* linear sweep. By allocating @a q on the stack, objects can be "queried"
* quickly without allocating any memory. This function is realtime safe.
*/
-int
+static inline int
lv2_object_query(LV2_Atom* object, LV2_Object_Query* query)
{
int matches = 0;
diff --git a/ext/atom.lv2/atom.h b/ext/atom.lv2/atom.h
index df73504..f547e80 100644
--- a/ext/atom.lv2/atom.h
+++ b/ext/atom.lv2/atom.h
@@ -51,16 +51,16 @@
*
* Note that an LV2_Atom is the latter two fields of an LV2_Event as defined
* by the <a href="http://lv2plug.in/ns/ext/event">LV2 events extension</a>.
- * The host MAY marshal an Event to an Atom simply by pointing to the offset
- * of the 'type' field of the LV2_Event, which is also the type field (i.e. start)
- * of a valid LV2_Atom. The macro LV2_ATOM_FROM_EVENT is provided in this
- * header for this purpose.
+ * The host MAY marshal an <a href="urn:struct:LV2_Event">LV2_Event</a> to
+ * an <a href="urn:struct:LV2_Atom">LV2_Atom</a> by simply pointing to the
+ * offset of <code>type</code>. The macro LV2_ATOM_FROM_EVENT is provided
+ * in this header for this purpose.
*/
typedef struct _LV2_Atom {
- /** The type of this atom. This number represents a URI, mapped to an
- * integer using the extension <http://lv2plug.in/ns/ext/uri-map>
- * with "http://lv2plug.in/ns/ext/atom" as the 'map' argument.
+ /** The type of this atom. This number is mapped from a URI using
+ * the extension <http://lv2plug.in/ns/ext/uri-map>
+ * with 'map' = "http://lv2plug.in/ns/ext/atom".
* Type 0 is a special case which indicates this atom
* is a reference and MUST NOT be copied manually.
*/
@@ -77,66 +77,47 @@ typedef struct _LV2_Atom {
/** Reference, an LV2_Atom with type 0 */
typedef LV2_Atom LV2_Atom_Reference;
-/** The body of an LV2_Atom with type atom:Vector */
+/** The body of an atom:String */
+typedef struct _LV2_Atom_String {
+ uint32_t lang; /**< The ID of the language of this string */
+ char* str; /**< Null-terminated string data in UTF-8 encoding */
+} LV2_Atom_String;
+
+/** The body of an atom:Vector */
typedef struct _LV2_Atom_Vector {
- uint16_t elem_count; /**< The size of each element in the vector */
+ uint16_t elem_count; /**< The number of elements in the vector */
uint16_t elem_type; /**< The type of each element in the vector */
- uint8_t elems[]; /**< Elements follow here */
+ uint8_t elems[]; /**< Sequence of element bodies */
} LV2_Atom_Vector;
-/** The body of an LV2_Atom with type atom:Property */
+/** The body of an atom:Property */
typedef struct _LV2_Atom_Property {
- uint32_t key; /**< Key (predicate) of Object or RDF triple (URIInt) */
- LV2_Atom value; /**< Value (object) of Object or RDF triple */
+ uint32_t key; /**< ID of key (predicate) */
+ LV2_Atom value; /**< Value (object) */
} LV2_Atom_Property;
-/** The body of an LV2_Atom with type atom:Triple */
-typedef struct _LV2_Atom_Triple {
- uint32_t subject; /**< Subject of RDF triple (URI mapped integer) */
- LV2_Atom_Property property; /** Property (predicate and object) of subject */
-} LV2_Atom_Triple;
+/** The body of an atom:Resource or atom:Blank */
+typedef struct _LV2_Atom_Object {
+ uint32_t context; /**< ID of context graph, or 0 for the default context */
+ uint32_t id; /**< ID for atom:Resource or blank ID for atom:Blank */
+ uint8_t properties[]; /**< Sequence of LV2_Atom_Property */
+} LV2_Atom_Object;
/* Optional Blob Support */
-
-typedef void* LV2_Blob_Data;
-
/** Dynamically Allocated LV2 Blob.
*
- * This is a blob of data of any type, dynamically allocated in memory.
+ * This is an opaque blob of data of any type, dynamically allocated in memory.
* Unlike an LV2_Atom, a blob is not necessarily POD. Plugins MUST only
* refer to blobs via a Reference (an LV2_Atom with type 0), there is no
* way for a plugin to directly copy or destroy a Blob.
+ *
+ * This is a pointer to host data which is opaque to the plugin.
+ * Plugins MUST NOT interpret this data in any way, except via host-provided
+ * functions in LV2_Blob_Support.
*/
-typedef struct _LV2_Blob {
-
- /** Pointer to opaque data.
- *
- * Plugins MUST NOT interpret this data in any way. Hosts may store
- * whatever information they need to associate with blobs here.
- */
- LV2_Blob_Data data;
-
- /** Get blob's type as a URI mapped to an integer.
- *
- * The return value may be any type URI, mapped to an integer with the
- * URI Map extension. If this type is an LV2_Atom type, get returns
- * a pointer to the LV2_Atom header (e.g. a blob with type atom:Int32
- * does NOT return a pointer to a int32_t).
- */
- uint32_t (*type)(struct _LV2_Blob* blob);
-
- /** Get blob's body.
- *
- * Returns a pointer to the start of the blob data. The format of this
- * data is defined by the return value of the type method. It MUST NOT
- * be used in any way by code which does not understand that type.
- */
- void* (*get)(struct _LV2_Blob* blob);
-
-} LV2_Blob;
-
+typedef void* LV2_Blob;
typedef void* LV2_Blob_Support_Data;
@@ -144,11 +125,10 @@ typedef void (*LV2_Blob_Destroy)(LV2_Blob* blob);
/** The data field of the LV2_Feature for atom:BlobSupport.
*
- * A host which supports blobs must pass an LV2_Feature struct to the
- * plugin's instantiate method with 'URI' equal to
- * "http://lv2plug.in/ns/ext/atom#BlobSupport" and 'data' pointing to an
- * instance of this struct. All fields of this struct MUST be set to
- * non-NULL values by the host, except possibly 'data'.
+ * A host which supports blobs must pass an LV2_Feature to the plugin's
+ * instantiate method with 'URI' = "http://lv2plug.in/ns/ext/atom#BlobSupport"
+ * and 'data' pointing to an instance of this struct. All fields of this
+ * struct MUST be set to non-NULL values by the host, except possibly 'data'.
*/
typedef struct {
@@ -167,35 +147,16 @@ typedef struct {
* uint16, like LV2_Atom.size.
*/
uint16_t ref_size;
-
- /** Initialize a reference to point to a newly allocated Blob.
- *
- * @param data Must be the data member of this struct.
- * @param ref Pointer to an area of memory at least as large as
- * the ref_size field of this struct. On return, this will
- * be the unique reference to the new blob, which is owned by the
- * caller. Assumed to be uninitialised, i.e. the caller MUST NOT
- * pass a valid (owned) reference since this could cause a memory leak.
- * @param destroy Function to destroy this blob. This function
- * MUST clean up any resources contained in the blob, but MUST NOT
- * attempt to free the memory pointed to by its LV2_Blob* parameter
- * (since this is allocated by the host).
- * @param type Type of blob to allocate (URI mapped integer).
- * @param size Size of blob to allocate in bytes.
- */
- void (*blob_new)(LV2_Blob_Support_Data data,
- LV2_Atom_Reference* ref,
- LV2_Blob_Destroy destroy,
- uint32_t type,
- size_t size);
-
- /** Return a pointer to the Blob referred to by @a ref.
+
+ /** Return the Blob referred to by @a ref.
*
* The returned value MUST NOT be used in any way other than by calling
- * methods defined in LV2_Blob (e.g. it MUST NOT be copied or destroyed).
+ * methods defined in LV2_Blob_Support (e.g. it MUST NOT be directly
+ * accessed, copied, or destroyed). The actual payload of the blob can
+ * be accessed with LV2_Blob_Support.blob_get.
*/
- LV2_Blob* (*ref_get)(LV2_Blob_Support_Data data,
- LV2_Atom_Reference* ref);
+ LV2_Blob (*ref_get)(LV2_Blob_Support_Data data,
+ LV2_Atom_Reference* ref);
/** Copy a reference.
* This copies a reference but not the blob it refers to,
@@ -223,6 +184,42 @@ typedef struct {
*/
void (*ref_reset)(LV2_Blob_Support_Data data,
LV2_Atom_Reference* ref);
+
+ /** Initialize a reference to point to a newly allocated Blob.
+ *
+ * @param data Must be the data member of this struct.
+ * @param ref Pointer to an area of memory at least as large as
+ * the ref_size field of this struct. On return, this will
+ * be the unique reference to the new blob, which is owned by the
+ * caller. Assumed to be uninitialised, i.e. the caller MUST NOT
+ * pass a valid reference since this could cause a memory leak.
+ * @param destroy Function to destroy this blob. This function
+ * MUST clean up any resources contained in the blob, but MUST NOT
+ * attempt to free the memory pointed to by its LV2_Blob* parameter
+ * (since this is allocated by the host).
+ * @param type ID of type of blob to allocate.
+ * @param size Size of blob to allocate in bytes.
+ */
+ void (*blob_new)(LV2_Blob_Support_Data data,
+ LV2_Atom_Reference* ref,
+ LV2_Blob_Destroy destroy,
+ uint32_t type,
+ size_t size);
+
+ /** Get blob's type as an ID.
+ *
+ * The return value may be any type URI, mapped to an integer with the
+ * URI Map extension with <code>context = NULL</code>.
+ */
+ uint32_t (*blob_type)(LV2_Blob blob);
+
+ /** Get blob's body.
+ *
+ * Returns a pointer to the start of the blob data. The format of this
+ * data is defined by the return value of the type method. It MUST NOT
+ * be used in any way by code which does not understand that type.
+ */
+ void* (*blob_data)(LV2_Blob blob);
} LV2_Blob_Support;
diff --git a/ext/atom.lv2/atom.ttl b/ext/atom.lv2/atom.ttl
index a7d663b..cf048aa 100644
--- a/ext/atom.lv2/atom.ttl
+++ b/ext/atom.lv2/atom.ttl
@@ -30,255 +30,380 @@
<http://lv2plug.in/ns/ext/atom>
a lv2:Specification ;
- doap:name "LV2 Atom" ;
- doap:maintainer [
- a foaf:Person ;
- foaf:name "David Robillard" ;
- foaf:homepage <http://drobilla.net/> ;
- rdfs:seeAlso <http://drobilla.net/drobilla.rdf>
- ] ;
+ doap:name "LV2 Atom" ;
+ doap:maintainer [
+ a foaf:Person ;
+ foaf:name "David Robillard" ;
+ foaf:homepage <http://drobilla.net/> ;
+ rdfs:seeAlso <http://drobilla.net/drobilla.rdf>
+ ] ;
rdfs:comment """
This extension defines a generic format for a typed piece of data, called an
-"atom" (e.g. integers, strings, buffers, data structures, etc). Atoms allow
-LV2 plugins and host to communicate and store values of any type and size via
-a generic mechanism (e.g. port buffers, event payloads, shared data, etc.).
-Atoms are simple a chunk of memory with a type and a size, and are (with
-one exception) Plain Old Data (POD) and may be safely copied (e.g. with a
-simple call to <code>memcpy</code>). Because they are POD, hosts and plugins
-can communicate atoms of any type, even if they do not understand that type.
-This allows two plugins that both understand some type to be used together in
-a host that does not itself understand that type, or allows a host to send
-atoms "through" a plugin that does not understand them (for e.g. routing,
-delaying, or buffering plugins).
-
-Atoms as defined by this extension can be trivially constructed in-place
-from events as defined by the <a href="http://lv2plug.in/ns/ext/event">LV2
-Event</a> extension. A valid LV2_Atom (see atom.h) is contained within
-any valid LV2_Event (see event.h). An LV2_Event is simply an LV2_Atom
-with a time stamp header prepended. Atoms SHOULD be used anywhere a "value"
-needs to be stored or communicated, to allow implementations to be
-polymorphic and extensible.
-
-Atoms (the beginning of the LV2_Atom header) MUST be 32-bit aligned.
-
-Optionally, the host MAY support "Blobs", which are dynamically allocated
-chunks of memory that (unlike Atoms) are not necessarily POD. Blobs are
-accessed via references, which are a special case of Atom that always have
-type 0, are not POD, and can only be copied using host provided functions.
-This allows plugins and hosts to work with data of any type at all.
-Blob data MUST NOT be used in any way by an implementation that does not
-understand that blob type (unlike other Atoms, meaningful type-oblivious use
-of a Blob is impossible).
+"<a href="#Atom">Atom</a>" (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>).
+
+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.
+
+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.
+
+Atoms (the start of the LV2_Atom header) MUST be 32-bit aligned.
+
+Optionally, the host MAY implement <a href="#blobSupport">blob support</a>.
+A <a href="#Blob">Blob</a> is a dynamically allocated chunk of memory
+that (unlike an Atom) is not necessarily POD. Blobs are accessed via a
+<a href="#Reference">Reference</a>, which is a special case of Atom that
+always has <code>type = 0</code>, is not POD, and can only be copied using
+host provided functions. This allows plugins and hosts to work with data
+of any type at all.
+
+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: <a href="ValuePort">ValuePort</a> and <a href="#MessagePort"
+>MessagePort</a>, which both have the same buffer format but different
+semantics (with respect to how the run() callback interprets the Atom).
This extension requires the host to support the <a
href="http://lv2plug.in/ns/ext/uri-map">LV2 URI Map</a> extension.
""" .
-atom:AtomType a rdfs:Class ;
- rdfs:label "LV2 Atom Type" ;
+atom:Atom a rdfs:Class ;
+ rdfs:label "Atom" ;
rdfs:comment """
-Base class for all types of LV2 Atom.
-
-All Atom types (instances of this class, which are themselves classes)
-must define a precise binary layout for that type of atom, which dictates
-the format of the data following the LV2_Atom header.
-
-The URIs of subclasses of atom:AtomType are mapped to integers and used as
-the type field of an LV2_Atom. If a plugin or host does not understand
-the type of an LV2_Atom, that atom SHOULD simply be ignored (though it
-MAY be simply copied if it is not a reference).
-
-All atoms are POD by definition, except references, which have type 0.
-An atom MUST NOT contain a reference. It is safe to copy any type of
-atom except type 0 with a simple memcpy using the size field, even if the
-implementation does not understand the actual type of that atom.
+Abstract base class for all atoms. An <a href="urn:struct:LV2_Atom"
+>LV2_Atom</a> has a 16-bit <code>type</code> and <code>size</code> followed by
+a <code>body</code>.
+
+All concrete Atom types (subclasses of this class) MUST define a precise
+binary layout for <code>body</code>.
+
+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 <a href="urn:struct:LV2_URI_Map_Feature"
+>LV2_URI_Map_Feature</a>::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
+(though it MAY be copied if it is not a <a href="#Reference">Reference</a>).
+
+All atoms are POD by definition except references, which 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>.
""" .
-atom:Reference a atom:AtomType ;
- rdfs:label "Reference" ;
+atom:Reference a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Reference" ;
rdfs:comment """
-Reference to a blob. The actual contents of a reference are opaque and host
-specific, and must not be copied, serialized, or otherwise interpreted by
-a plugin, except by using functions provided by the host.
+Reference to a <a href="#Blob">Blob</a>. The actual contents of a Reference
+are opaque and host specific, and must not be copied, serialized, or otherwise
+interpreted by a plugin, except via functions provided by the host in
+<a href="urn:struct:LV2_Blob_Support">LV2_Blob_Support</a>.
-References are a special case: a reference atom always has type 0.
-The NULL reference is the unique atom with type 0 and size 0.
+A Reference is a special case of Atom with <code>type = 0</code>.
+"Null" is the unique Atom with <code>type = 0</code> and <code>size = 0</code>.
""" .
-atom:String a atom:AtomType ;
- rdfs:label "String" ;
+atom:String a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "String" ;
rdfs:comment """
-A UTF-8 encoded string, where LV2_Atom.size refers to the length of the
-string in bytes (not characters).
+A UTF-8 encoded string, with an optional language tag. An
+<a href="urn:struct:LV2_Atom_String">LV2_Atom_String</a> has an <a href="#ID">ID</a>
+<code>lang</code> followed by the string data in UTF-8 encoding. The length of the
+string data in bytes is <code>size - sizeof(uint32_t)</code>, including the
+terminating NULL character. The <code>lang</code> may be any URI; to
+describe a human language, use 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.
+
+For example, "Hello" in English:
+<pre>
+struct LV2_Atom {
+ uint16_t type = uri_to_id(atom:String);
+ uint16_t size = 10;
+}
+uint32_t lang = uri_to_id("http://lexvo.org/id/term/en");
+char str[] = "Hello";
+</pre>
+and French:
+<pre>
+struct LV2_Atom {
+ uint16_t type = uri_to_id(atom:String);
+ uint16_t size = 12;
+}
+uint32_t lang = uri_to_id("http://lexvo.org/id/term/fr");
+char str[] = "Bonjour";
+</pre>
+or a Turtle string:
+<pre>
+struct LV2_Atom {
+ uint16_t type = uri_to_id(atom:String);
+ uint16_t size = 60;
+}
+uint32_t lang = uri_to_id("http://www.w3.org/2008/turtle#turtle");
+char str[] = "&lt;http://example.org/foo&gt; a &lt;http://example.org/Thing&gt; ."
+</pre>
""" .
-atom:URIInt a atom:AtomType ;
- rdfs:label "URI mapped to an integer" ;
+atom:ID a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Integer ID mapped from a URI" ;
rdfs:comment """
-A uint32_t interpreted as a URI mapped to an integer using the LV2
-URI map extension &lt;http://lv2plug.in/ns/ext/uri-map&gt;. Size is
-always 4.
+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
+<a href="urn:struct:LV2_URI_Map_Feature">LV2_URI_Map_Feature</a>::uri_to_id
+with <code>map = NULL</code>.
""" .
-atom:Vector a atom:AtomType ;
- rdfs:label "Vector" ;
+atom:Vector a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Vector" ;
rdfs:comment """
-A POD homogeneous sequence of atoms with equivalent type and size.
+A homogeneous sequence of atoms with equivalent type and size.
-The body of a vector begins with
-<pre>
-uint16_t elem_count; // The number of elements in the vector
-uint16_t elem_type; // The type of each element
-</pre>
-followed by <code>elem_count</code> bodies of atoms of type
-<code>elem_type</code>, each with equivalent size. For variably sized
-content types, this size can be calculated using the total byte size of the
-vector, e.g.
+An <a href="urn:struct:LV2_Atom_Vector">LV2_Atom_Vector</a> is a
+16-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 <a href="#Atom">Atom</a> type, i.e. the
+size of each element is the vector's <code>size / elem_count</code>.
+
+For example, an atom:Vector containing 42 elements of type atom:Float looks
+like this in memory:
<pre>
-uint16_t elem_size = (vector.size - (2 * sizeof(uint16_t))) / vector.count);
+struct LV2_Atom {
+ uint16_t type = uri_to_id(atom:Vector);
+ uint16_t size = sizeof(LV2_Atom) + sizeof(LV2_Atom_Vector) + (42 * sizeof(float);
+}
+struct LV2_Vector {
+ uint16_t elem_count = 42;
+ uint16_t elem_type = uri_to_id(atom:Float);
+}
+float elem_00;
+float elem_01;
+...
+float elem_41;
</pre>
+
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>.
-Note that an Atom is 32-bit aligned by definition, and both the Atom and
-Vector headers are 32-bits each, therefore the first element of a Vector is
-64-bit aligned.
-
-For example, an atom:Vector containing 42 elements of type atom:Int32 looks
-like this in memory (including the Atom header):
-<pre>
-uint16_t atom_type = uri_map(atom:Vector)
-uint16_t atom_size = (2 * sizeof(uint16_t)) + (42 * sizeof(int32_t))
-uint16_t elem_count = 42
-uint16_t elem_type = uri_map(atom:Int32)
-int32_t contents[42] = ...
-</pre>
+A Vector header is 64-bits, thus the first element of a Vector is 64-bit
+aligned if the Vector itself is 64-bit aligned.
""" .
-atom:Tuple a atom:AtomType ;
+atom:Tuple a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
rdfs:label "Tuple" ;
- rdfs:comment """
-A POD sequence of atoms with varying types and sizes.
+ rdfs:comment """
+A sequence of <a href="#Atom">atoms</a> with varying <code>type</code>
+and <code>size</code>.
-The body of a tuple is simply a series of complete atoms, aligned to
+The body of a Tuple is simply a sequence of complete atoms, each aligned to
32 bits.
""" .
-atom:Property a atom:AtomType ;
- rdfs:label "RDF property of some object" ;
+atom:Property a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Property of an Object" ;
rdfs:comment """
-A description of a single property for some object (i.e. an RDF
-statement with only predicate (key) and object (value) defined).
-<pre>
-uint32_t key;
-LV2_Atom value;
-</pre>
+A single property of some <a href="#Object">Object</a>. An
+<a href="urn:struct:LV2_Atom_Property">LV2_Atom_Property</a>
+has an <a href="#ID">ID</a> <code>key</code> and
+<a href="#Atom">Atom</a> <code>value</code>.
""" .
-atom:Triple a atom:AtomType ;
- rdfs:label "RDF triple" ;
+atom:Object a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Object" ;
rdfs:comment """
-A single RDF triple.
-
-The subject and predicate of a Triple are implicitly URIs, thus they are stored
-as URI mapped integers with type and size ommitted (i.e. a single uint32_t).
+Abstract base class for an "Object", i.e. an <a href="#Atom">Atom</a>
+with a number of <a href="#Property">properties</a>. An <a
+href="urn:struct:LV2_Atom_Object" >LV2_Atom_Object</a> is an unsigned 32-bit
+integer <code>context</code> and <code>id</code> followed by a sequence of
+<a href="urn:struct:LV2_Atom_Property" >properties</a>.
+
+The <code>context</code> is mapped using the <a
+href="http://lv2plug.in/ns/ext/uri-map">URI Map</a> extension's <a
+href="urn:struct:LV2_URI_Map_Feature">LV2_URI_Map_Feature</a>::uri_to_id
+with <code>map = NULL</code>, and may be 0 (the default context).
+
+Note this is an abstract class, i.e. no Atom can exist with
+<code>type = uri_to_id(atom:Object)</code>. An Object is
+either a <a href="urn:struct:LV2_Resource">Resource</a> or a <a
+href="urn:struct:Blank">Blank</a>, but the <code>body</code> always has the
+same binary format. Thus, both named and anonymous objects can be handled
+with common code using only a 64-bit header for both.
+""" .
-An atom:Triple is memory is a uint32_t subject immediately followed by the
-body of an atom:Property.
-An atom:Triple in memory is two uint32_t's followed by an LV2_Atom:
-<pre>
-uint32_t subject;
-uint32_t predicate;
-LV2_Atom object;
-</pre>
+atom:Resource a rdfs:Class ;
+ rdfs:subClassOf atom:Object ;
+ rdfs:comment """
+An <a href="#Object">Object</a> where <code>id</code> is the
+URI of the resource mapped to an <a href="#ID">ID</a>.
""" .
-atom:Triples a atom:AtomType ;
- rdfs:label "RDF triple set" ;
+atom:Blank a rdfs:Class ;
+ rdfs:subClassOf atom:Object ;
rdfs:comment """
-A description in RDF (i.e. a set of triples).
+An <a href="#Object">Object</a> 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 an <a href="ID">ID</a>.
+""" .
-An atom:Triples contains any number of RDF triples, describing one or
-several resources. The subject and predicate of all triples are implicitly
-URI mapped integers, type tags are omitted. The object of triples may be
-any atom.
-An atom:Triples in memory is a sequence of atom:Triple where each atom:Triple
-is immediately followed by the next (without time stamps or sizes), with
-padding to ensure each subject is 32-bit aligned, e.g.:
-<pre>
-uint32_t subject1;
-uint32_t predicate1;
-LV2_Atom object1;
-uint8_t pad[1]; /* e.g. if object1.size == 3 */
-uint32_t subject2;
-uint32_t predicate2;
-LV2_Atom object2;
-...
-</pre>
+atom:Model a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Model" ;
+ rdfs:comment """
+A description of a set of <a href="#Object">objects</a>. In memory, a Model is
+simply a sequence of objects.
""" .
-
-atom:Blank a atom:AtomType ;
- rdfs:label "Blank (anonymous resource)" ;
+atom:Bang a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Bang (activity) (<code>size = 0</code>)" .
+
+atom:Byte
+ a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Byte (<code>size = 1</code>)" .
+
+atom:Int32 a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Signed 32-bit integer" .
+
+atom:Int64 a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Signed 64-bit integer" .
+
+atom:Bool a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "Signed 32-bit integer where 0 is false" .
+
+atom:Float a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "32-bit IEEE-754 floating point number" .
+
+atom:Double a rdfs:Class ;
+ rdfs:subClassOf atom:Atom ;
+ rdfs:label "64-bit IEEE-754 floating point number" .
+
+atom:blobSupport a lv2:Feature ;
+ rdfs:label "Blob support" ;
rdfs:comment """
-A description of an RDF resource with no URI (a resource with blank node
-ID), e.g. the resource of type ex:Thing in the following Turtle description:
-<code>&lt;&gt; ex:hasThing [ a ex:Thing ]</code>
+Support for dynamically allocated blobs. If a host supports this feature, it
+MUST pass a <a href="urn:struct:LV2_Feature">LV2_Feature</a> with
+<code>URI</code> http://lv2plug.in/ns/ext/atom#blobSupport
+and <code>data</code> pointing to a <a href="urn:struct:LV2_Blob_Support"
+>LV2_Blob_Support</a>.
+""" .
-An atom:Blank is conceptually a dictionary where keys (RDF predicates) are
-URI mapped integers, and values (RDF objects) are any atom.
-An atom:Blank in memory is like an atom:Triples, but with subjects omitted:
-<pre>
-uint32_t predicate1;
-LV2_Atom object1;
-uint32_t predicate2;
-LV2_Atom object2;
-...
-</pre>
+atom:Blob a rdfs:Class ;
+ rdfs:label "Blob" ;
+ rdfs:comment """
+Base class for all dynamically allocated blobs. An <a
+href="urn:struct:LV2_Blob" >LV2_Blob</a> ia an opaque pointer to host
+data. The type and data of a blob can be accessed via host-provided
+functions in <a href="urn:struct:LV2_Blob_Support">LV2_Blob_Support</a>.
+The type of a blob can be any URI that describes a data format. Blobs are
+always allocated by the host, and unlike atoms are not necessarily POD.
+
+Blob data MUST NOT be used in any way by an implementation that does not
+understand that blob type (unlike Atoms, meaningful type-oblivious use
+of a Blob is impossible).
""" .
-atom:Bang a atom:AtomType ; rdfs:label "Bang (generic activity), size=0" .
-atom:Byte a atom:AtomType ; rdfs:label "A byte" .
-atom:Int32 a atom:AtomType ; rdfs:label "Signed 32-bit Integer" .
-atom:Bool a atom:AtomType ; rdfs:label "atom:Int32 where 0=false, 1=true" .
-atom:Float32 a atom:AtomType ; rdfs:label "32-bit Floating Point Number" .
-atom:Float64 a atom:AtomType ; rdfs:label "64-bit Floating Point Number" .
+atom:AtomPort a rdfs:Class ;
+ rdfs:subClassOf lv2:Port ;
+ rdfs:label "Atom Port" ;
+ rdfs:comment """
+A port which contains an <a href="#Atom">Atom</a>. Ports of this type will
+be connected to a 32-bit aligned <a href="urn:struct:LV2_Atom">LV2_Atom</a>
+immediately followed by <code>size</code> bytes of data.
+
+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 <a href="#ValuePort">ValuePort</a>
+or <a href="#MessagePort">MessagePort</a>).
+
+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>).
+""" .
-atom:blobSupport a lv2:Feature ;
- rdfs:label "Blob support" ;
- rdfs:comment """
-
-Support for dynamically allocated blobs. If a host supports this feature, it
-MUST pass an LV2_Feature with URI http://lv2plug.in/ns/ext/atom#blobSupport
-and a pointer to LV2_Blob_Support as data to the plugin's instantiate method.
-See atom.h for details.
+atom:ValuePort a rdfs:Class ;
+ rdfs:subClassOf atom:AtomPort ;
+ rdfs:label "Value Port" ;
+ rdfs:comment """
+An AtomPort that interprets its data as a persistent and time-independent
+"value".
+<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>
+</ul>
+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.
""" .
-atom:BlobType a rdfs:Class ;
- rdfs:label "Blob Type" ;
+atom:MessagePort a rdfs:Class ;
+ rdfs:subClassOf atom:AtomPort ;
+ rdfs:label "Message Port" ;
rdfs:comment """
-Base class for all types of dynamically allocated LV2 blobs. Blobs can be of
-any type at all, there are no restrictions on the binary format or contents
-of a blob. Blobs are dynamically allocated by the host (or a plugin via
-the host), and unlike Atoms are not necessarily POD.
+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.
-The type of a blob MAY be a atom:AtomType, in which case the start of the
-blob data is the start of the Atom header (LV2_Atom).
+Intuitively, a MessagePort contains a "message" or "command" or "event"
+which is reacted to, NOT a "value" or "signal" (which is computed with).
+""" .
+
+atom:supports a rdf:Property ;
+ rdfs:domain lv2:Port ;
+ rdfs:range atom:Atom ;
+ rdfs:label "supports" ;
+ rdfs:comment """
+Indicates that a Port supports a certain <a href="#Atom">Atom</a> 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.
""" .
diff --git a/ext/message.lv2/message.ttl b/ext/message.lv2/message.ttl
index 60ec021..ae7d438 100644
--- a/ext/message.lv2/message.ttl
+++ b/ext/message.lv2/message.ttl
@@ -76,7 +76,7 @@ This is an abstract port class, the actual format and semantics
of the port buffer (and messages) are defined by some other port type, i.e.
a cmdControlPort MUST have another type which defines the format and semantics
of the port buffer contents (likely candidates are
-<a href="http://lv2plug.in/ns/ext/atom-port#MessagePort">atom-port:MessagePort</a>
+<a href="http://lv2plug.in/ns/ext/atom#MessagePort">atom:MessagePort</a>
or <a href="http://lv2plug.in/ns/ext/event#EventPort">ev:EventPort</a>).
""" .
@@ -95,7 +95,7 @@ This is an abstract port class, the actual format and semantics
of the port buffer (and messages) are defined by some other port type, i.e.
a cmdControlPort MUST have another type which defines the format and semantics
of the port buffer contents (likely candidates are
-<a href="http://lv2plug.in/ns/ext/atom-port#MessagePort">atom-port:MessagePort</a>
+<a href="http://lv2plug.in/ns/ext/atom#MessagePort">atom:MessagePort</a>
or <a href="http://lv2plug.in/ns/ext/event#EventPort">ev:EventPort</a>).
""" .