From c6883595c3a4a34bf1a459c3bc1fba91d27f18f8 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 25 Oct 2010 04:05:28 +0000 Subject: Simplify and improve atom extension. Merge atom-port extension into atom extension. Link to code documentation from atom HTML documentation. --- ext/atom-port.lv2/atom-port.ttl | 127 ----------- ext/atom-port.lv2/manifest.ttl | 7 - ext/atom.lv2/atom-helpers.h | 27 ++- ext/atom.lv2/atom.h | 159 +++++++------ ext/atom.lv2/atom.ttl | 485 +++++++++++++++++++++++++--------------- ext/message.lv2/message.ttl | 4 +- wscript | 1 - 7 files changed, 403 insertions(+), 407 deletions(-) delete mode 100644 ext/atom-port.lv2/atom-port.ttl delete mode 100644 ext/atom-port.lv2/manifest.ttl 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 -# -# 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: . -@prefix atom: . -@prefix doap: . -@prefix foaf: . -@prefix lv2: . -@prefix rdf: . -@prefix rdfs: . -@prefix xsd: . - - - a lv2:Specification ; - doap:name "LV2 Atom Port" ; - doap:maintainer [ - a foaf:Person ; - foaf:name "David Robillard" ; - foaf:homepage ; - rdfs:seeAlso - ] ; - rdfs:comment """ -This extension describes port types that hold polymorphic values -(atom:Atom). 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 atom:Atom (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 -#
input aport:respondsWith output
then after running the plugin with -#a message m in input the host SHOULD interpret the aport: -#in output as the response to m. -#""" . - - -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". -
    -
  • 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.
  • -
  • 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.
  • -
  • If an aport:ValuePort contains a reference then the blob it refers to is -constant; plugin MUST NOT modify the blob in any way.
  • -
-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: . -@prefix rdfs: . - - - a lv2:Specification ; - rdfs:seeAlso . - 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... * } + * */ #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 LV2 events extension. - * 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 LV2_Event to + * an LV2_Atom by simply pointing to the + * offset of type. 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 - * 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 + * 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 context = NULL. + */ + 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 @@ a lv2:Specification ; - doap:name "LV2 Atom" ; - doap:maintainer [ - a foaf:Person ; - foaf:name "David Robillard" ; - foaf:homepage ; - rdfs:seeAlso - ] ; + doap:name "LV2 Atom" ; + doap:maintainer [ + a foaf:Person ; + foaf:name "David Robillard" ; + foaf:homepage ; + rdfs:seeAlso + ] ; 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 memcpy). 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 LV2 -Event 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). +"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 +memcpy). + +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 +Event as defined by the +LV2 Event 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 blob support. +A Blob is a dynamically allocated chunk of memory +that (unlike an Atom) is not necessarily POD. Blobs are accessed via a +Reference, which is a special case of Atom that +always has type = 0, 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 EventPort +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: ValuePort and MessagePort, 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 LV2 URI Map 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 LV2_Atom has a 16-bit type and size followed by +a body. + +All concrete Atom types (subclasses of this class) MUST define a precise +binary layout for body. + +The type field is the URI of a subclass of Atom mapped to an +integer using the URI Map +extension's LV2_URI_Map_Feature::uri_to_id with +map = "http://lv2plug.in/ns/ext/event". If a plugin or host +does not understand type, that atom SHOULD be gracefully ignored +(though it MAY be 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 non-reference Atom with a simple memcpy, even if +the implementation does not understand type. """ . -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 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 via functions provided by the host in +LV2_Blob_Support. -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 type = 0. +"Null" is the unique Atom with type = 0 and size = 0. """ . -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 +LV2_Atom_String has an ID +lang followed by the string data in UTF-8 encoding. The length of the +string data in bytes is size - sizeof(uint32_t), including the +terminating NULL character. The lang may be any URI; to +describe a human language, use http://lexvo.org/id/term/LANG where LANG is +an ISO 693-2 or +ISO 693-3 language code. + +For example, "Hello" in English: +
+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";
+
+and French: +
+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";
+
+or a Turtle string: +
+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[] = "<http://example.org/foo> a <http://example.org/Thing> ."
+
""" . -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 <http://lv2plug.in/ns/ext/uri-map>. Size is -always 4. +An unsigned 32-bit integer mapped from a URI using the +URI Map extension's +LV2_URI_Map_Feature::uri_to_id +with map = NULL. """ . -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 -
-uint16_t elem_count; // The number of elements in the vector
-uint16_t elem_type;  // The type of each element
-
-followed by elem_count bodies of atoms of type -elem_type, 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 LV2_Atom_Vector is a +16-bit elem_count and elem_type followed +by elem_count atom bodies of type elem_type. +The element type must be a fixed size Atom type, i.e. the +size of each element is the vector's size / elem_count. + +For example, an atom:Vector containing 42 elements of type atom:Float looks +like this in memory:
-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;
 
+ Note that it is possible to construct a valid Atom for each element of the vector, even by an implementation which does not understand elem_type. -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): -
-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] = ...
-
+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 atoms with varying type +and size. -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). -
-uint32_t key;
-LV2_Atom value;
-
+A single property of some Object. An +LV2_Atom_Property +has an ID key and +Atom value. """ . -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 Atom +with a number of properties. An LV2_Atom_Object is an unsigned 32-bit +integer context and id followed by a sequence of +properties. + +The context is mapped using the URI Map extension's LV2_URI_Map_Feature::uri_to_id +with map = NULL, and may be 0 (the default context). + +Note this is an abstract class, i.e. no Atom can exist with +type = uri_to_id(atom:Object). An Object is +either a Resource or a Blank, but the body 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: -
-uint32_t subject;
-uint32_t predicate;
-LV2_Atom object;
-
+atom:Resource a rdfs:Class ; + rdfs:subClassOf atom:Object ; + rdfs:comment """ +An Object where id is the +URI of the resource mapped to an ID. """ . -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 Object where id 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, id is NOT an ID. +""" . -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.: -
-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;
-...
-
+atom:Model a rdfs:Class ; + rdfs:subClassOf atom:Atom ; + rdfs:label "Model" ; + rdfs:comment """ +A description of a set of objects. 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) (size = 0)" . + +atom:Byte + a rdfs:Class ; + rdfs:subClassOf atom:Atom ; + rdfs:label "Byte (size = 1)" . + +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: -<> ex:hasThing [ a ex:Thing ] +Support for dynamically allocated blobs. If a host supports this feature, it +MUST pass a LV2_Feature with +URI http://lv2plug.in/ns/ext/atom#blobSupport +and data pointing to a LV2_Blob_Support. +""" . -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: -
-uint32_t predicate1;
-LV2_Atom object1;
-uint32_t predicate2;
-LV2_Atom object2;
-...
-
+atom:Blob a rdfs:Class ; + rdfs:label "Blob" ; + rdfs:comment """ +Base class for all dynamically allocated blobs. An LV2_Blob ia an opaque pointer to host +data. The type and data of a blob can be accessed via host-provided +functions in LV2_Blob_Support. +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 Atom. Ports of this type will +be connected to a 32-bit aligned LV2_Atom +immediately followed by size 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 ValuePort +or 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 = 0 and size = 0). +""" . -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". +
    +
  • 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.
  • +
  • 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.
  • +
  • If a ValuePort contains a reference then the blob it refers to is +constant; plugin MUST NOT modify the blob in any way.
  • +
+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 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. """ . 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 -atom-port:MessagePort +atom:MessagePort or ev:EventPort). """ . @@ -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 -atom-port:MessagePort +atom:MessagePort or ev:EventPort). """ . diff --git a/wscript b/wscript index 4e8ad30..2875271 100644 --- a/wscript +++ b/wscript @@ -67,7 +67,6 @@ def build_extension(bld, name, dir): def build(bld): ext = ''' atom - atom-port contexts data-access dyn-manifest -- cgit v1.2.1