1 /*
2   Copyright 2008-2016 David Robillard <http://drobilla.net>
3   Copyright 2018 Ethan Reker <http://cutthroughrecordings.com>
4   Copyright 2019 Guillaume Piolat <http://www.auburnsounds.com>
5 
6   Permission to use, copy, modify, and/or distribute this software for any
7   purpose with or without fee is hereby granted, provided that the above
8   copyright notice and this permission notice appear in all copies.
9 
10   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 module dplug.lv2.atom;
19 
20 version(LV2):
21 
22 /**
23    @defgroup atom Atom
24 
25    A generic value container and several data types, see
26    <http://lv2plug.in/ns/ext/atom> for details.
27 
28    @{
29 */
30 
31 import core.stdc.stdint;
32 import core.stdc.stddef;
33 import core.stdc.string;
34 
35 
36 enum LV2_ATOM_URI  =  "http://lv2plug.in/ns/ext/atom";        ///< http://lv2plug.in/ns/ext/atom
37 enum LV2_ATOM_PREFIX = LV2_ATOM_URI ~ "#";                    ///< http://lv2plug.in/ns/ext/atom#
38 enum LV2_ATOM__Atom        =  LV2_ATOM_PREFIX ~ "Atom";           ///< http://lv2plug.in/ns/ext/atom#Atom
39 enum LV2_ATOM__AtomPort    =  LV2_ATOM_PREFIX ~ "AtomPort";       ///< http://lv2plug.in/ns/ext/atom#AtomPort
40 enum LV2_ATOM__Blank       =  LV2_ATOM_PREFIX ~ "Blank";          ///< http://lv2plug.in/ns/ext/atom#Blank
41 enum LV2_ATOM__Bool        =  LV2_ATOM_PREFIX ~ "Bool";           ///< http://lv2plug.in/ns/ext/atom#Bool
42 enum LV2_ATOM__Chunk       =  LV2_ATOM_PREFIX ~ "Chunk";          ///< http://lv2plug.in/ns/ext/atom#Chunk
43 enum LV2_ATOM__Double      =  LV2_ATOM_PREFIX ~ "Double";         ///< http://lv2plug.in/ns/ext/atom#Double
44 enum LV2_ATOM__Event       =  LV2_ATOM_PREFIX ~ "Event";          ///< http://lv2plug.in/ns/ext/atom#Event
45 enum LV2_ATOM__Float       =  LV2_ATOM_PREFIX ~ "Float";          ///< http://lv2plug.in/ns/ext/atom#Float
46 enum LV2_ATOM__Int         =  LV2_ATOM_PREFIX ~ "Int";            ///< http://lv2plug.in/ns/ext/atom#Int
47 enum LV2_ATOM__Literal     =  LV2_ATOM_PREFIX ~ "Literal";        ///< http://lv2plug.in/ns/ext/atom#Literal
48 enum LV2_ATOM__Long        =  LV2_ATOM_PREFIX ~ "Long";           ///< http://lv2plug.in/ns/ext/atom#Long
49 enum LV2_ATOM__Number      =  LV2_ATOM_PREFIX ~ "Number";         ///< http://lv2plug.in/ns/ext/atom#Number
50 enum LV2_ATOM__Object      =  LV2_ATOM_PREFIX ~ "Object";         ///< http://lv2plug.in/ns/ext/atom#Object
51 enum LV2_ATOM__Path        =  LV2_ATOM_PREFIX ~ "Path";           ///< http://lv2plug.in/ns/ext/atom#Path
52 enum LV2_ATOM__Property    =  LV2_ATOM_PREFIX ~ "Property";       ///< http://lv2plug.in/ns/ext/atom#Property
53 enum LV2_ATOM__Resource    =  LV2_ATOM_PREFIX ~ "Resource";       ///< http://lv2plug.in/ns/ext/atom#Resource
54 enum LV2_ATOM__Sequence    =  LV2_ATOM_PREFIX ~ "Sequence";       ///< http://lv2plug.in/ns/ext/atom#Sequence
55 enum LV2_ATOM__Sound       =  LV2_ATOM_PREFIX ~ "Sound";          ///< http://lv2plug.in/ns/ext/atom#Sound
56 enum LV2_ATOM__String      =  LV2_ATOM_PREFIX ~ "String";         ///< http://lv2plug.in/ns/ext/atom#String
57 enum LV2_ATOM__Tuple       =  LV2_ATOM_PREFIX ~ "Tuple";          ///< http://lv2plug.in/ns/ext/atom#Tuple
58 enum LV2_ATOM__URI         =  LV2_ATOM_PREFIX ~ "URI";            ///< http://lv2plug.in/ns/ext/atom#URI
59 enum LV2_ATOM__URID        =  LV2_ATOM_PREFIX ~ "URID";           ///< http://lv2plug.in/ns/ext/atom#URID
60 enum LV2_ATOM__Vector      =  LV2_ATOM_PREFIX ~ "Vector";         ///< http://lv2plug.in/ns/ext/atom#Vector
61 enum LV2_ATOM__atomTransfer=  LV2_ATOM_PREFIX ~ "atomTransfer";   ///< http://lv2plug.in/ns/ext/atom#atomTransfer
62 enum LV2_ATOM__beatTime    =  LV2_ATOM_PREFIX ~ "beatTime";       ///< http://lv2plug.in/ns/ext/atom#beatTime
63 enum LV2_ATOM__bufferType  =  LV2_ATOM_PREFIX ~ "bufferType";     ///< http://lv2plug.in/ns/ext/atom#bufferType
64 enum LV2_ATOM__childType   =  LV2_ATOM_PREFIX ~ "childType";      ///< http://lv2plug.in/ns/ext/atom#childType
65 enum LV2_ATOM__eventTransfer = LV2_ATOM_PREFIX~ "eventTransfer";  ///< http://lv2plug.in/ns/ext/atom#eventTransfer
66 enum LV2_ATOM__frameTime   =  LV2_ATOM_PREFIX ~ "frameTime";      ///< http://lv2plug.in/ns/ext/atom#frameTime
67 enum LV2_ATOM__supports    =  LV2_ATOM_PREFIX ~ "supports";       ///< http://lv2plug.in/ns/ext/atom#supports
68 enum LV2_ATOM__timeUnit    =  LV2_ATOM_PREFIX ~ "timeUnit";       ///< http://lv2plug.in/ns/ext/atom#timeUnit
69 enum LV2_ATOM_REFERENCE_TYPE = 0;  ///< The special type for a reference atom
70 
71 extern(C) {
72 
73     /** @cond */
74     /** This expression will fail to compile if double does not fit in 64 bits. */
75     // typedef char lv2_atom_assert_double_fits_in_64_bits[
76     //     ((sizeof(double) <= sizeof(uint64_t)) * 2) - 1];
77     // alias lv2_atom_assert_double_fits_in_64_bits[((sizeof(double) <= sizeof(uint64_t)) * 2) - 1] = char;
78     /** @endcond */
79 
80     /**
81     Return a pointer to the contents of an Atom.  The "contents" of an atom
82     is the data past the complete type-specific header.
83     @param type The type of the atom, e.g. LV2_Atom_String.
84     @param atom A variable-sized atom.
85     */
86     // #define LV2_ATOM_CONTENTS(type, atom) \
87     //     ((void*)((uint8_t*)(atom) + sizeof(type)))
88     void* LV2_ATOM_CONTENTS(alias type)(LV2_Atom* atom)
89     {
90         return cast(void*)(cast(uint8_t*)(cast(void*)atom) + type.sizeof);
91     }
92 
93     // /**
94     // Const version of LV2_ATOM_CONTENTS.
95     // */
96     // #define LV2_ATOM_CONTENTS_CONST(type, atom) \
97     //     ((const void*)((const uint8_t*)(atom) + sizeof(type)))
98     template LV2_ATOM_CONTENTS_CONST(alias type, alias atom)
99     {
100         auto LV2_ATOM_CONTENTS_CONST = (cast(const void*)(cast(const uint8_t*)(atom) + sizeof(type)));
101     }
102 
103     /**
104     Return a pointer to the body of an Atom.  The "body" of an atom is the
105     data just past the LV2_Atom head (i.e. the same offset for all types).
106     */
107 
108     void* LV2_ATOM_BODY(LV2_Atom* atom) nothrow @nogc
109     {
110         return LV2_ATOM_CONTENTS!LV2_Atom(atom);
111     }
112 
113 
114     /**
115     Const version of LV2_ATOM_BODY.
116     */
117     // #define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
118     alias LV2_ATOM_BODY_CONST(atom) = LV2_ATOM_CONTENTS_CONST!(LV2_Atom, atom);
119 
120 
121     /** The header of an atom:Atom. */
122     struct LV2_Atom {
123         uint32_t size;  /**< Size in bytes, not including type and size. */
124         uint32_t type;  /**< Type of this atom (mapped URI). */
125     }
126 
127     /** An atom:Int or atom:Bool.  May be cast to LV2_Atom. */
128     struct LV2_Atom_Int {
129         LV2_Atom atom;  /**< Atom header. */
130         int32_t  body_;  /**< Integer value. */
131     }
132 
133     /** An atom:Long.  May be cast to LV2_Atom. */
134     struct LV2_Atom_Long {
135         LV2_Atom atom;  /**< Atom header. */
136         int64_t  body_;  /**< Integer value. */
137     }
138 
139     /** An atom:Float.  May be cast to LV2_Atom. */
140     struct LV2_Atom_Float {
141         LV2_Atom atom;  /**< Atom header. */
142         float    body_;  /**< Floating point value. */
143     }
144 
145     /** An atom:Double.  May be cast to LV2_Atom. */
146     struct LV2_Atom_Double {
147         LV2_Atom atom;  /**< Atom header. */
148         double   body_;  /**< Floating point value. */
149     }
150 
151     /** An atom:Bool.  May be cast to LV2_Atom. */
152     alias LV2_Atom_Bool = LV2_Atom_Int;
153 
154     /** An atom:URID.  May be cast to LV2_Atom. */
155     struct LV2_Atom_URID {
156         LV2_Atom atom;  /**< Atom header. */
157         uint32_t body_;  /**< URID. */
158     }
159 
160     /** An atom:String.  May be cast to LV2_Atom. */
161     struct LV2_Atom_String {
162         LV2_Atom atom;  /**< Atom header. */
163         /* Contents (a null-terminated UTF-8 string) follow here. */
164     }
165 
166     /** The body of an atom:Literal. */
167     struct LV2_Atom_Literal_Body {
168         uint32_t datatype;  /**< Datatype URID. */
169         uint32_t lang;      /**< Language URID. */
170         /* Contents (a null-terminated UTF-8 string) follow here. */
171     }
172 
173     /** An atom:Literal.  May be cast to LV2_Atom. */
174     struct LV2_Atom_Literal {
175         LV2_Atom              atom;  /**< Atom header. */
176         LV2_Atom_Literal_Body body_;  /**< Body. */
177     }
178 
179     /** An atom:Tuple.  May be cast to LV2_Atom. */
180     struct LV2_Atom_Tuple {
181         LV2_Atom atom;  /**< Atom header. */
182         /* Contents (a series of complete atoms) follow here. */
183     }
184 
185     /** The body of an atom:Vector. */
186     struct LV2_Atom_Vector_Body {
187         uint32_t child_size;  /**< The size of each element in the vector. */
188         uint32_t child_type;  /**< The type of each element in the vector. */
189         /* Contents (a series of packed atom bodies) follow here. */
190     }
191 
192     /** An atom:Vector.  May be cast to LV2_Atom. */
193     struct LV2_Atom_Vector {
194         LV2_Atom             atom;  /**< Atom header. */
195         LV2_Atom_Vector_Body body_;  /**< Body. */
196     }
197 
198     /** The body of an atom:Property (e.g. in an atom:Object). */
199     struct LV2_Atom_Property_Body {
200         uint32_t key;      /**< Key (predicate) (mapped URI). */
201         uint32_t context;  /**< Context URID (may be, and generally is, 0). */
202         LV2_Atom value;    /**< Value atom header. */
203         /* Value atom body follows here. */
204     }
205 
206     /** An atom:Property.  May be cast to LV2_Atom. */
207     struct LV2_Atom_Property {
208         LV2_Atom               atom;  /**< Atom header. */
209         LV2_Atom_Property_Body body_;  /**< Body. */
210     }
211 
212     /** The body of an atom:Object. May be cast to LV2_Atom. */
213     struct LV2_Atom_Object_Body {
214         uint32_t id;     /**< URID, or 0 for blank. */
215         uint32_t otype;  /**< Type URID (same as rdf:type, for fast dispatch). */
216         /* Contents (a series of property bodies) follow here. */
217     }
218 
219     /** An atom:Object.  May be cast to LV2_Atom. */
220     struct LV2_Atom_Object {
221         LV2_Atom             atom;  /**< Atom header. */
222         LV2_Atom_Object_Body body_;  /**< Body. */
223     }
224 
225     /** The header of an atom:Event.  Note this type is NOT an LV2_Atom. */
226     struct LV2_Atom_Event {
227         /** Time stamp.  Which type is valid is determined by context. */
228         union Time {
229             int64_t frames;  /**< Time in audio frames. */
230             double  beats;   /**< Time in beats. */
231         }
232         Time time;
233         LV2_Atom body_;  /**< Event body atom header. */
234         /* Body atom contents follow here. */
235     }
236 
237     /**
238     The body of an atom:Sequence (a sequence of events).
239 
240     The unit field is either a URID that described an appropriate time stamp
241     type, or may be 0 where a default stamp type is known.  For
242     LV2_Descriptor::run(), the default stamp type is audio frames.
243 
244     The contents of a sequence is a series of LV2_Atom_Event, each aligned
245     to 64-bits, e.g.:
246     <pre>
247     | Event 1 (size 6)                              | Event 2
248     |       |       |       |       |       |       |       |       |
249     | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
250     |FRAMES |SUBFRMS|TYPE   |SIZE   |DATADATADATAPAD|FRAMES |SUBFRMS|...
251     </pre>
252     */
253     struct LV2_Atom_Sequence_Body {
254         uint32_t unit;  /**< URID of unit of event time stamps. */
255         uint32_t pad;   /**< Currently unused. */
256         /* Contents (a series of events) follow here. */
257     }
258 
259     /** An atom:Sequence. */
260     struct LV2_Atom_Sequence {
261         LV2_Atom               atom;  /**< Atom header. */
262         LV2_Atom_Sequence_Body body_;  /**< Body. */
263     }
264 
265 }
266 
267 
268 nothrow:
269 @nogc:
270 
271 /** Pad a size to 64 bits. */
272 uint32_t lv2_atom_pad_size(uint32_t size)
273 {
274     return (size + 7U) & (~7U);
275 }
276 
277 /** Get an iterator pointing to the first event in a Sequence body. */
278 LV2_Atom_Event* lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body_)
279 {
280     return cast(LV2_Atom_Event*)(body_ + 1);
281 }
282 
283 /** Get an iterator pointing to the end of a Sequence body. */
284 LV2_Atom_Event* lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body_, uint32_t size)
285 {
286     return cast(LV2_Atom_Event*)(cast(const uint8_t*)body_ + lv2_atom_pad_size(size));
287 }
288 
289 /** Return true iff `i` has reached the end of `body`. */
290 bool lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body_,
291                               uint32_t                      size,
292                               const LV2_Atom_Event*         i)
293 {
294     return cast(const uint8_t*)i >= (cast(const uint8_t*)body_ + size);
295 }
296 
297 /** Return an iterator to the element following `i`. */
298 LV2_Atom_Event* lv2_atom_sequence_next(const LV2_Atom_Event* i)
299 {
300     return cast(LV2_Atom_Event*)(cast(const uint8_t*)i
301                                  + LV2_Atom_Event.sizeof
302         + lv2_atom_pad_size(i.body_.size));
303 }
304 
305 
306 /** Return a pointer to the first property in `body`. */
307 LV2_Atom_Property_Body* lv2_atom_object_begin(const LV2_Atom_Object_Body* body_)
308 {
309     return cast(LV2_Atom_Property_Body*)(body_ + 1);
310 }
311 
312 /** Return true iff `i` has reached the end of `obj`. */
313 bool lv2_atom_object_is_end(const LV2_Atom_Object_Body*   body_,
314                             uint32_t                      size,
315                             const LV2_Atom_Property_Body* i)
316 {
317     return cast(const uint8_t*)i >= (cast(const uint8_t*)body_ + size);
318 }
319 
320 /** Return an iterator to the property following `i`. */
321 LV2_Atom_Property_Body* lv2_atom_object_next(const LV2_Atom_Property_Body* i)
322 {
323     const (LV2_Atom*) value = cast(const LV2_Atom*)(
324                                                     cast(const uint8_t*)i + 2 * uint32_t.sizeof);
325     return cast(LV2_Atom_Property_Body*)(
326                                          cast(const uint8_t*)i + lv2_atom_pad_size(
327                                                                                    cast(uint32_t)LV2_Atom_Property_Body.sizeof + value.size));
328 }