# LV2 Atom Extension # Copyright (C) 2007-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 atom: . @prefix doap: . @prefix foaf: . @prefix lv2: . @prefix rdf: . @prefix rdfs: . @prefix xsd: . a lv2:Specification ; 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). This extension requires the host to support the LV2 URI Map extension. """ . atom:AtomType a rdfs:Class ; rdfs:label "LV2 Atom Type" ; 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. """ . atom:Reference a atom:AtomType ; 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. 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. """ . atom:String a atom:AtomType ; 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). """ . atom:URIInt a atom:AtomType ; rdfs:label "URI mapped to an integer" ; 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. """ . atom:Vector a atom:AtomType ; rdfs:label "Vector" ; rdfs:comment """ A POD 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.
uint16_t elem_size = (vector.size - (2 * sizeof(uint16_t))) / vector.count);
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] = ...
""" . atom:Tuple a atom:AtomType ; rdfs:label "Tuple" ; rdfs:comment """ A POD sequence of atoms with varying types and sizes. The body of a tuple is simply a series of complete atoms, aligned to 32 bits. """ . atom:Property a atom:AtomType ; rdfs:label "RDF property of some 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;
""" . atom:Triple a atom:AtomType ; rdfs:label "RDF triple" ; 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). 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:Triples a atom:AtomType ; rdfs:label "RDF triple set" ; rdfs:comment """ A description in RDF (i.e. a set of triples). 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:Blank a atom:AtomType ; rdfs:label "Blank (anonymous resource)" ; 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 ] 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: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: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:BlobType a rdfs:Class ; rdfs:label "Blob Type" ; 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. 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). """ .