1@prefix atom:  <http://lv2plug.in/ns/ext/atom#> .
2@prefix lv2:   <http://lv2plug.in/ns/lv2core#> .
3@prefix owl:   <http://www.w3.org/2002/07/owl#> .
4@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
5@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
6@prefix ui:    <http://lv2plug.in/ns/extensions/ui#> .
7@prefix units: <http://lv2plug.in/ns/extensions/units#> .
8@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
9
10<http://lv2plug.in/ns/ext/atom>
11	a owl:Ontology ;
12	rdfs:seeAlso <atom.h> ,
13		<util.h> ,
14		<forge.h> ,
15		<lv2-atom.doap.ttl> ;
16	lv2:documentation """
17
18<p>An #Atom is a simple generic data container for holding any type of Plain
19Old Data (POD).  An #Atom can contain simple primitive types like integers,
20floating point numbers, and strings; as well as structured data like lists and
21dictionary-like <q>Objects</q>.  Since Atoms are POD, they can be easily copied
22(e.g. using <code>memcpy</code>) anywhere and are suitable for use in real-time
23code.</p>
24
25<p>Every atom starts with an LV2_Atom header, followed by the contents.  This
26allows code to process atoms without requiring special code for every type of
27data.  For example, plugins that mutually understand a type can be used
28together in a host that does not understand that type, because the host is only
29required to copy atoms, not interpret their contents.  Similarly, plugins (such
30as routers, delays, or data structures) can meaningfully process atoms of a
31type unknown to them.</p>
32
33<p>Atoms should be used anywhere values of various types must be stored or
34transmitted.  The port type #AtomPort can be used to transmit atoms via ports.
35An #AtomPort that contains an #Sequence can be used for sample accurate event
36communication, such as MIDI, and replaces the earlier event extension.</p>
37
38<h3>Serialisation</h3>
39
40<p>Each Atom type defines a binary format for use at runtime, but also a
41serialisation that is natural to express in Turtle format.  Thus, this
42specification defines a powerful real-time appropriate data model, as well as a
43portable way to serialise any data in that model.  This is particularly useful
44for inter-process communication, saving/restoring state, and describing values
45in plugin data files.</p>
46
47<h3>Custom Atom Types</h3>
48
49<p>While it is possible to define new Atom types for any binary format, the
50standard types defined here are powerful enough to describe almost anything.
51Implementations SHOULD build structures out of the types provided here, rather
52than define new binary formats (e.g. use #Tuple or #Object rather than
53a new C <code>struct</code> type).  Current implementations have support for
54serialising all standard types, so new binary formats are an implementation
55burden which harms interoperabilty.  In particular, plugins SHOULD NOT expect
56UI communication or state saving with custom Atom types to work.  In general,
57new Atom types should only be defined where absolutely necessary due to
58performance reasons and serialisation is not a concern.</p>
59""" .
60
61atom:cType
62	a rdf:Property ,
63		owl:DatatypeProperty ,
64		owl:FunctionalProperty ;
65	rdfs:label "C type" ;
66	rdfs:domain rdfs:Class ;
67	rdfs:range lv2:Symbol ;
68	rdfs:comment """The identifier for a C type describing the binary representation of an Atom of this type.""" .
69
70atom:Atom
71	a rdfs:Class ;
72	rdfs:label "Atom" ;
73	atom:cType "LV2_Atom" ;
74	lv2:documentation """
75<p>Abstract base class for all atoms.  An LV2_Atom has a 32-bit
76<code>size</code> and <code>type</code> followed by a body of <code>size</code>
77bytes.  Atoms MUST be 64-bit aligned.</p>
78
79<p>All concrete Atom types (subclasses of this class) MUST define a precise
80binary layout for their body.</p>
81
82<p>The <code>type</code> field is the URI of an Atom type mapped to an integer.
83Implementations SHOULD gracefully pass through, or ignore, atoms with unknown
84types.</p>
85
86<p>All atoms are POD by definition except references, which as a special case
87have <code>type = 0</code>.  An Atom MUST NOT contain a Reference.  It is safe
88to copy any non-reference Atom with a simple <code>memcpy</code>, even if the
89implementation does not understand <code>type</code>.  Though this extension
90reserves the type 0 for references, the details of reference handling are
91currently unspecified.  A future revision of this extension, or a different
92extension, may define how to use non-POD data and references.  Implementations
93MUST NOT send references to another implementation unless the receiver is
94explicitly known to support references (e.g. by supporting a feature).</p>
95
96<p>The atom with both <code>type</code> <em>and</em> <code>size</code> 0 is
97<q>null</q>, which is not considered a Reference.</p>
98""" .
99
100atom:Chunk
101	a rdfs:Class ,
102		rdfs:Datatype ;
103	rdfs:subClassOf atom:Atom ;
104	rdfs:label "Chunk of memory" ;
105	owl:onDatatype xsd:base64Binary ;
106	lv2:documentation """
107<p>A chunk of memory with undefined contents.  This type is used to indicate a
108certain amount of space is available.  For example, output ports with a
109variably sized type are connected to a Chunk so the plugin knows the size of
110the buffer available for writing.</p>
111
112<p>The use of a Chunk should be constrained to a local scope, since
113interpreting it is impossible without context.  However, if serialised to RDF,
114a Chunk may be represented directly as an xsd:base64Binary string, e.g.:</p>
115
116<pre class="turtle-code">
117[] eg:someChunk "vu/erQ=="^^xsd:base64Binary .
118</pre>
119""" .
120
121atom:Number
122	a rdfs:Class ;
123	rdfs:subClassOf atom:Atom ;
124	rdfs:label "Number" .
125
126atom:Int
127	a rdfs:Class ,
128		rdfs:Datatype ;
129	rdfs:subClassOf atom:Number ;
130	rdfs:label "Signed 32-bit integer" ;
131	atom:cType "LV2_Atom_Int" ;
132	owl:onDatatype xsd:int .
133
134atom:Long
135	a rdfs:Class ,
136		rdfs:Datatype ;
137	rdfs:subClassOf atom:Number ;
138	rdfs:label "Signed 64-bit integer" ;
139	atom:cType "LV2_Atom_Long" ;
140	owl:onDatatype xsd:long .
141
142atom:Float
143	a rdfs:Class ,
144		rdfs:Datatype ;
145	rdfs:subClassOf atom:Number ;
146	rdfs:label "32-bit floating point number" ;
147	atom:cType "LV2_Atom_Float" ;
148	owl:onDatatype xsd:float .
149
150atom:Double
151	a rdfs:Class ,
152		rdfs:Datatype ;
153	rdfs:subClassOf atom:Number ;
154	rdfs:label "64-bit floating point number" ;
155	atom:cType "LV2_Atom_Double" ;
156	owl:onDatatype xsd:double .
157
158atom:Bool
159	a rdfs:Class ,
160		rdfs:Datatype ;
161	rdfs:subClassOf atom:Atom ;
162	rdfs:label "Boolean" ;
163	atom:cType "LV2_Atom_Bool" ;
164	owl:onDatatype xsd:boolean ;
165	rdfs:comment "An Int where 0 is false and any other value is true." .
166
167atom:String
168	a rdfs:Class ,
169		rdfs:Datatype ;
170	rdfs:subClassOf atom:Atom ;
171	rdfs:label "String" ;
172	atom:cType "LV2_Atom_String" ;
173	owl:onDatatype xsd:string ;
174	lv2:documentation """
175<p>A UTF-8 encoded string.</p>
176
177<p>The body of an LV2_Atom_String is a C string in UTF-8 encoding, i.e. an
178array of bytes (<code>uint8_t</code>) terminated with a NULL byte
179(<code>'\\0'</code>).</p>
180
181<p>This type is for free-form strings, but SHOULD NOT be used for typed data or
182text in any language.  Use atom:Literal unless translating the string does not
183make sense and the string has no meaningful datatype.</p>
184""" .
185
186atom:Literal
187	a rdfs:Class ;
188	rdfs:subClassOf atom:Atom ;
189	rdfs:label "String Literal" ;
190	atom:cType "LV2_Atom_Literal" ;
191	lv2:documentation """
192<p>A UTF-8 encoded string literal, with an optional datatype or language.</p>
193
194<p>This type is compatible with rdfs:Literal and is capable of expressing a
195string in any language or a value of any type.  A Literal has a
196<code>datatype</code> and <code>lang</code> followed by string data in UTF-8
197encoding.  The length of the string data in bytes is <code>size -
198sizeof(LV2_Atom_Literal)</code>, including the terminating NULL character.  The
199<code>lang</code> field SHOULD be a URI of the form
200&lt;http://lexvo.org/id/iso639-3/LANG&gt; or
201&lt;http://lexvo.org/id/iso639-1/LANG&gt; where LANG is a 3-character ISO 693-3
202language code, or a 2-character ISO 693-1 language code, respectively.</p>
203
204<p>A Literal may have a <code>datatype</code> OR a <code>lang</code>, but never
205both.</p>
206
207<p>For example, a Literal can be "Hello" in English:</p>
208<pre class="c-code">
209void set_to_hello_in_english(LV2_Atom_Literal* lit) {
210     lit->atom.type     = map(expand("atom:Literal"));
211     lit->atom.size     = 14;
212     lit->body.datatype = 0;
213     lit->body.lang     = map("http://lexvo.org/id/iso639-1/en");
214     memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
215            "Hello",
216            sizeof("Hello"));  // Assumes enough space
217}
218</pre>
219
220<p>or a Turtle string:</p>
221<pre class="c-code">
222void set_to_turtle_string(LV2_Atom_Literal* lit, const char* ttl) {
223     lit->atom.type     = map(expand("atom:Literal"));
224     lit->atom.size     = 64;
225     lit->body.datatype = map("http://www.w3.org/2008/turtle#turtle");
226     lit->body.lang     = 0;
227     memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
228            ttl,
229            strlen(ttl) + 1);  // Assumes enough space
230}
231</pre>
232""" .
233
234atom:Path
235	a rdfs:Class ,
236		rdfs:Datatype ;
237	rdfs:subClassOf atom:URI ;
238	owl:onDatatype atom:URI ;
239	rdfs:label "File path string" ;
240	lv2:documentation """
241<p>A local file path.</p>
242
243<p>A Path is a URI reference with only a path component: no scheme, authority,
244query, or fragment.  In particular, paths to files in the same bundle may be
245cleanly written in Turtle files as a relative URI.  However, implementations
246may assume any binary Path (e.g. in an event payload) is a valid file path
247which can passed to system functions like fopen() directly, without any
248character encoding or escape expansion required.</p>
249
250<p>Any implemenation that creates a Path atom to transmit to another is
251responsible for ensuring it is valid.  A Path SHOULD always be absolute, unless
252there is some mechanism in place that defines a base path.  Since this is not
253the case for plugin instances, effectively any Path sent to or received from a
254plugin instance MUST be absolute.</p>
255""" .
256
257atom:URI
258	a rdfs:Class ,
259		rdfs:Datatype ;
260	rdfs:subClassOf atom:String ;
261	owl:onDatatype xsd:anyURI ;
262	rdfs:label "URI string" ;
263	lv2:documentation """
264<p>A URI string.  This is useful when a URI is needed but mapping is
265inappropriate, for example with temporary or relative URIs.  Since the ability
266to distinguish URIs from plain strings is often necessary, URIs MUST NOT be
267transmitted as atom:String.</p>
268
269<p>This is not strictly a URI, since UTF-8 is allowed.  Escaping and related
270issues are the host's responsibility.</p>
271""" .
272
273atom:URID
274	a rdfs:Class ;
275	rdfs:subClassOf atom:Atom ;
276	rdfs:label "Integer URID" ;
277	atom:cType "LV2_Atom_URID" ;
278	lv2:documentation """
279<p>An unsigned 32-bit integer mapped from a URI (e.g. with LV2_URID_Map).</p>
280""" .
281
282atom:Vector
283	a rdfs:Class ;
284	rdfs:subClassOf atom:Atom ;
285	rdfs:label "Vector" ;
286	atom:cType "LV2_Atom_Vector" ;
287	lv2:documentation """
288<p>A homogeneous series of atom bodies with equivalent type and size.</p>
289
290<p>An LV2_Atom_Vector is a 32-bit <code>child_size</code> and
291<code>child_type</code> followed by <code>size / child_size</code> atom
292bodies.</p>
293
294<p>For example, an atom:Vector containing 42 elements of type atom:Float:</p>
295<pre class="c-code">
296struct VectorOf42Floats {
297    uint32_t size;        // sizeof(LV2_Atom_Vector_Body) + (42 * sizeof(float);
298    uint32_t type;        // map(expand("atom:Vector"))
299    uint32_t child_size;  // sizeof(float)
300    uint32_t child_type;  // map(expand("atom:Float"))
301    float    elems[42];
302};
303</pre>
304
305<p>Note that it is possible to construct a valid Atom for each element
306of the vector, even by an implementation which does not understand
307<code>child_type</code>.</p>
308
309<p>If serialised to RDF, a Vector SHOULD have the form:</p>
310
311<pre class="turtle-code">
312eg:someVector
313     a atom:Vector ;
314     atom:childType atom:Int ;
315     rdf:value (
316         "1"^^xsd:int
317         "2"^^xsd:int
318         "3"^^xsd:int
319         "4"^^xsd:int
320     ) .
321</pre>
322""" .
323
324atom:Tuple
325	a rdfs:Class ;
326	rdfs:subClassOf atom:Atom ;
327	rdfs:label "Tuple" ;
328	lv2:documentation """
329<p>A series of Atoms with varying <code>type</code> and <code>size</code>.</p>
330
331<p>The body of a Tuple is simply a series of complete atoms, each aligned to
33264 bits.</p>
333
334<p>If serialised to RDF, a Tuple SHOULD have the form:</p>
335
336<pre class="turtle-code">
337eg:someVector
338     a atom:Tuple ;
339     rdf:value (
340         "1"^^xsd:int
341         "3.5"^^xsd:float
342         "etc"
343     ) .
344</pre>
345
346""" .
347
348atom:Property
349	a rdfs:Class ;
350	rdfs:subClassOf atom:Atom ;
351	rdfs:label "Property" ;
352	atom:cType "LV2_Atom_Property" ;
353	lv2:documentation """
354<p>A property of an atom:Object.  An LV2_Atom_Property has a URID
355<code>key</code> and <code>context</code>, and an Atom <code>value</code>.
356This corresponds to an RDF Property, where the <q>key</q> is the <q>predicate</q>
357and the <q>value</q> is the object.</p>
358
359<p>The <code>context</code> field can be used to specify a different context
360for each property, where this is useful.  Otherwise, it may be 0.</p>
361
362<p>Properties generally only exist as part of an atom:Object.  Accordingly,
363they will typically be represented directly as properties in RDF (see
364atom:Object).  If this is not possible, they may be expressed as partial
365reified statements, e.g.:</p>
366
367<pre class="turtle-code">
368eg:someProperty
369    rdf:predicate eg:theKey ;
370    rdf:object eg:theValue .
371</pre>
372""" .
373
374atom:Object
375	a rdfs:Class ;
376	rdfs:subClassOf atom:Atom ;
377	rdfs:label "Object" ;
378	atom:cType "LV2_Atom_Object" ;
379	lv2:documentation """
380<p>An <q>Object</q> is an atom with a set of properties.  This corresponds to
381an RDF Resource, and can be thought of as a dictionary with URID keys.</p>
382
383<p>An LV2_Atom_Object body has a uint32_t <code>id</code> and
384<code>type</code>, followed by a series of atom:Property bodies
385(LV2_Atom_Property_Body).  The LV2_Atom_Object_Body::otype field is equivalent
386to a property with key rdf:type, but is included in the structure to allow for
387fast dispatching.</p>
388
389<p>Code SHOULD check for objects using lv2_atom_forge_is_object() or
390lv2_atom_forge_is_blank() if a forge is available, rather than checking the
391atom type directly.  This will correctly handle the deprecated atom:Resource
392and atom:Blank types.</p>
393
394<p>When serialised to RDF, an Object is represented as a resource, e.g.:</p>
395
396<pre class="turtle-code">
397eg:someObject
398    eg:firstPropertyKey "first property value" ;
399    eg:secondPropertyKey "first loser" ;
400    eg:andSoOn "and so on" .
401</pre>
402""" .
403
404atom:Resource
405	a rdfs:Class ;
406	rdfs:subClassOf atom:Object ;
407	rdfs:label "Resource" ;
408	owl:deprecated "true"^^xsd:boolean ;
409	atom:cType "LV2_Atom_Object" ;
410	lv2:documentation """
411<p>This class is deprecated.  Use atom:Object instead.</p>
412
413<p>An atom:Object where the <code>id</code> field is a URID, i.e. an Object
414with a URI.</p>
415""" .
416
417atom:Blank
418	a rdfs:Class ;
419	rdfs:subClassOf atom:Object ;
420	rdfs:label "Blank" ;
421	owl:deprecated "true"^^xsd:boolean ;
422	atom:cType "LV2_Atom_Object" ;
423	lv2:documentation """
424<p>This class is deprecated.  Use atom:Object with ID 0 instead.</p>
425
426<p>An atom:Object where the LV2_Atom_Object::id is a blank node ID (NOT a URI).
427The ID of a Blank is valid only within the context the Blank appears in.  For
428ports this is the context of the associated run() call, i.e. all ports share
429the same context so outputs can contain IDs that correspond to IDs of blanks in
430the input.</p>
431""" .
432
433atom:Sound
434	a rdfs:Class ;
435	rdfs:subClassOf atom:Vector ;
436	rdfs:label "Sound" ;
437	atom:cType "LV2_Atom_Sound" ;
438	lv2:documentation """
439<p>An atom:Vector of atom:Float which represents an audio waveform.  The format
440is the same as the buffer format for lv2:AudioPort (except the size may be
441arbitrary).  An atom:Sound inherently depends on the sample rate, which is
442assumed to be known from context.  Because of this, directly serialising an
443atom:Sound is probably a bad idea, use a standard format like WAV instead.</p>
444""" .
445
446atom:frameTime
447	a rdf:Property ,
448		owl:DatatypeProperty ,
449		owl:FunctionalProperty ;
450	rdfs:range xsd:decimal ;
451	rdfs:label "frame time" ;
452	lv2:documentation """
453<p>Time stamp in audio frames.  Typically used for events.</p>
454""" .
455
456atom:beatTime
457	a rdf:Property ,
458		owl:DatatypeProperty ,
459		owl:FunctionalProperty ;
460	rdfs:range xsd:decimal ;
461	rdfs:label "beat time" ;
462	lv2:documentation """
463<p>Time stamp in beats.  Typically used for events.</p>
464""" .
465
466atom:Event
467	a rdfs:Class ;
468	rdfs:label "Event" ;
469	atom:cType "LV2_Atom_Event" ;
470	lv2:documentation """
471<p>An atom with a time stamp prefix, typically an element of an atom:Sequence.
472Note this is not an Atom type.</p>
473""" .
474
475atom:Sequence
476	a rdfs:Class ;
477	rdfs:subClassOf atom:Atom ;
478	rdfs:label "Sequence" ;
479	atom:cType "LV2_Atom_Sequence" ;
480	lv2:documentation """
481<p>A sequence of atom:Event, i.e. a series of time-stamped Atoms.</p>
482
483<p>LV2_Atom_Sequence_Body.unit describes the time unit for the contained atoms.
484If the unit is known from context (e.g. run() stamps are always audio frames),
485this field may be zero.  Otherwise, it SHOULD be either units:frame or
486units:beat, in which case ev.time.frames or ev.time.beats is valid,
487respectively.</p>
488
489<p>If serialised to RDF, a Sequence has a similar form to atom:Vector, but for
490brevity the elements may be assumed to be atom:Event, e.g.:</p>
491
492<pre class="turtle-code">
493eg:someSequence
494    a atom:Sequence ;
495    rdf:value (
496        [
497            atom:frameTime 1 ;
498            rdf:value "901A01"^^midi:MidiEvent
499        ] [
500            atom:frameTime 3 ;
501            rdf:value "902B02"^^midi:MidiEvent
502        ]
503    ) .
504</pre>
505""" .
506
507atom:AtomPort
508	a rdfs:Class ;
509	rdfs:subClassOf lv2:Port ;
510	rdfs:label "Atom Port" ;
511	lv2:documentation """
512<p>A port which contains an atom:Atom.  Ports of this type are connected to an
513LV2_Atom with a type specified by atom:bufferType.</p>
514
515<p>Output ports with a variably sized type MUST be initialised by the host
516before every run() to an atom:Chunk with size set to the available space.  The
517plugin reads this size to know how much space is available for writing.  In all
518cases, the plugin MUST write a complete atom (including header) to outputs.
519However, to be robust, hosts SHOULD initialise output ports to a safe sentinel
520(e.g. the null Atom) before calling run().</p>
521""" .
522
523atom:bufferType
524	a rdf:Property ,
525		owl:ObjectProperty ;
526	rdfs:domain atom:AtomPort ;
527	rdfs:range rdfs:Class ;
528	rdfs:label "buffer type" ;
529	lv2:documentation """
530<p>Indicates that an AtomPort may be connected to a certain Atom type.  A port
531MAY support several buffer types.  The host MUST NOT connect a port to an Atom
532with a type not explicitly listed with this property.  The value of this
533property MUST be a sub-class of atom:Atom.  For example, an input port that is
534connected directly to an LV2_Atom_Double value is described like so:</p>
535
536<pre class="turtle-code">
537&lt;plugin&gt;
538    lv2:port [
539        a lv2:InputPort , atom:AtomPort ;
540        atom:bufferType atom:Double ;
541    ] .
542</pre>
543
544<p>This property only describes the types a port may be <em>directly</em>
545connected to.  It says nothing about the expected contents of containers.  For
546that, use atom:supports.</p>
547""" .
548
549atom:childType
550	a rdf:Property ,
551		owl:ObjectProperty ;
552	rdfs:label "child type" ;
553	rdfs:comment "The type of a container's children." .
554
555atom:supports
556	a rdf:Property ;
557	rdfs:label "supports" ;
558	rdfs:range rdfs:Class ;
559	lv2:documentation """
560<p>Indicates that a particular Atom type is supported.</p>
561
562<p>This property is defined loosely, it may be used to indicate that anything
563<q>supports</q> an Atom type, wherever that may be useful.  It applies
564<q>recursively</q> where collections are involved.</p>
565
566<p>In particular, this property can be used to describe which event types are
567expected by a port.  For example, a port that receives MIDI events is described
568like so:</p>
569
570<pre class="turtle-code">
571&lt;plugin&gt;
572    lv2:port [
573        a lv2:InputPort , atom:AtomPort ;
574        atom:bufferType atom:Sequence ;
575        atom:supports midi:MidiEvent ;
576    ] .
577</pre>
578""" .
579
580atom:eventTransfer
581	a ui:PortProtocol ;
582	rdfs:label "event transfer" ;
583	lv2:documentation """
584<p>Transfer of individual events in a port buffer.  Useful as the
585<code>format</code> for a LV2UI_Write_Function.</p>
586
587<p>This protocol applies to ports which contain events, usually in an
588atom:Sequence.  The host must transfer each individual event to the recipient.
589The format of the received data is an LV2_Atom, there is no timestamp
590header.</p>
591""" .
592
593atom:atomTransfer
594	a ui:PortProtocol ;
595	rdfs:label "atom transfer" ;
596	lv2:documentation """
597<p>Transfer of the complete atom in a port buffer.  Useful as the
598<code>format</code> for a LV2UI_Write_Function.</p>
599
600<p>This protocol applies to atom ports.  The host must transfer the complete
601atom contained in the port, including header.</p>
602""" .
603