Mercurial > hg > pub > prymula > com
comparison DPF-Prymula-audioplugins/dpf/distrho/src/lv2/atom-forge.h @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:cf2cb71d31dd | 3:84e66ea83026 |
---|---|
1 /* | |
2 Copyright 2008-2016 David Robillard <http://drobilla.net> | |
3 | |
4 Permission to use, copy, modify, and/or distribute this software for any | |
5 purpose with or without fee is hereby granted, provided that the above | |
6 copyright notice and this permission notice appear in all copies. | |
7 | |
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 */ | |
16 | |
17 /** | |
18 @file forge.h An API for constructing LV2 atoms. | |
19 | |
20 This file provides an API for constructing Atoms which makes it relatively | |
21 simple to build nested atoms of arbitrary complexity without requiring | |
22 dynamic memory allocation. | |
23 | |
24 The API is based on successively appending the appropriate pieces to build a | |
25 complete Atom. The size of containers is automatically updated. Functions | |
26 that begin a container return (via their frame argument) a stack frame which | |
27 must be popped when the container is finished. | |
28 | |
29 All output is written to a user-provided buffer or sink function. This | |
30 makes it popssible to create create atoms on the stack, on the heap, in LV2 | |
31 port buffers, in a ringbuffer, or elsewhere, all using the same API. | |
32 | |
33 This entire API is realtime safe if used with a buffer or a realtime safe | |
34 sink, except lv2_atom_forge_init() which is only realtime safe if the URI | |
35 map function is. | |
36 | |
37 Note these functions are all static inline, do not take their address. | |
38 | |
39 This header is non-normative, it is provided for convenience. | |
40 */ | |
41 | |
42 /** | |
43 @defgroup forge Forge | |
44 @ingroup atom | |
45 @{ | |
46 */ | |
47 | |
48 #ifndef LV2_ATOM_FORGE_H | |
49 #define LV2_ATOM_FORGE_H | |
50 | |
51 #include <assert.h> | |
52 | |
53 #include "atom.h" | |
54 #include "atom-util.h" | |
55 #include "urid.h" | |
56 | |
57 #if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) | |
58 # define LV2_ATOM_FORGE_DEPRECATED __attribute__((__deprecated__)) | |
59 #else | |
60 # define LV2_ATOM_FORGE_DEPRECATED | |
61 #endif | |
62 | |
63 #ifdef __cplusplus | |
64 extern "C" { | |
65 #else | |
66 # include <stdbool.h> | |
67 #endif | |
68 | |
69 // Disable deprecation warnings for Blank and Resource | |
70 #if defined(__clang__) | |
71 # pragma clang diagnostic push | |
72 # pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
73 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |
74 # pragma GCC diagnostic push | |
75 # pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
76 #endif | |
77 | |
78 /** Handle for LV2_Atom_Forge_Sink. */ | |
79 typedef void* LV2_Atom_Forge_Sink_Handle; | |
80 | |
81 /** A reference to a chunk of written output. */ | |
82 typedef intptr_t LV2_Atom_Forge_Ref; | |
83 | |
84 /** Sink function for writing output. See lv2_atom_forge_set_sink(). */ | |
85 typedef LV2_Atom_Forge_Ref | |
86 (*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle, | |
87 const void* buf, | |
88 uint32_t size); | |
89 | |
90 /** Function for resolving a reference. See lv2_atom_forge_set_sink(). */ | |
91 typedef LV2_Atom* | |
92 (*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle, | |
93 LV2_Atom_Forge_Ref ref); | |
94 | |
95 /** A stack frame used for keeping track of nested Atom containers. */ | |
96 typedef struct _LV2_Atom_Forge_Frame { | |
97 struct _LV2_Atom_Forge_Frame* parent; | |
98 LV2_Atom_Forge_Ref ref; | |
99 } LV2_Atom_Forge_Frame; | |
100 | |
101 /** A "forge" for creating atoms by appending to a buffer. */ | |
102 typedef struct { | |
103 uint8_t* buf; | |
104 uint32_t offset; | |
105 uint32_t size; | |
106 | |
107 LV2_Atom_Forge_Sink sink; | |
108 LV2_Atom_Forge_Deref_Func deref; | |
109 LV2_Atom_Forge_Sink_Handle handle; | |
110 | |
111 LV2_Atom_Forge_Frame* stack; | |
112 | |
113 LV2_URID Blank LV2_ATOM_FORGE_DEPRECATED; | |
114 LV2_URID Bool; | |
115 LV2_URID Chunk; | |
116 LV2_URID Double; | |
117 LV2_URID Float; | |
118 LV2_URID Int; | |
119 LV2_URID Long; | |
120 LV2_URID Literal; | |
121 LV2_URID Object; | |
122 LV2_URID Path; | |
123 LV2_URID Property; | |
124 LV2_URID Resource LV2_ATOM_FORGE_DEPRECATED; | |
125 LV2_URID Sequence; | |
126 LV2_URID String; | |
127 LV2_URID Tuple; | |
128 LV2_URID URI; | |
129 LV2_URID URID; | |
130 LV2_URID Vector; | |
131 } LV2_Atom_Forge; | |
132 | |
133 static inline void | |
134 lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size); | |
135 | |
136 /** | |
137 Initialise `forge`. | |
138 | |
139 URIs will be mapped using `map` and stored, a reference to `map` itself is | |
140 not held. | |
141 */ | |
142 static inline void | |
143 lv2_atom_forge_init(LV2_Atom_Forge* forge, const LV2_URID_Map* map) | |
144 { | |
145 lv2_atom_forge_set_buffer(forge, NULL, 0); | |
146 forge->Blank = map->map(map->handle, LV2_ATOM__Blank); | |
147 forge->Bool = map->map(map->handle, LV2_ATOM__Bool); | |
148 forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk); | |
149 forge->Double = map->map(map->handle, LV2_ATOM__Double); | |
150 forge->Float = map->map(map->handle, LV2_ATOM__Float); | |
151 forge->Int = map->map(map->handle, LV2_ATOM__Int); | |
152 forge->Long = map->map(map->handle, LV2_ATOM__Long); | |
153 forge->Literal = map->map(map->handle, LV2_ATOM__Literal); | |
154 forge->Object = map->map(map->handle, LV2_ATOM__Object); | |
155 forge->Path = map->map(map->handle, LV2_ATOM__Path); | |
156 forge->Property = map->map(map->handle, LV2_ATOM__Property); | |
157 forge->Resource = map->map(map->handle, LV2_ATOM__Resource); | |
158 forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence); | |
159 forge->String = map->map(map->handle, LV2_ATOM__String); | |
160 forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple); | |
161 forge->URI = map->map(map->handle, LV2_ATOM__URI); | |
162 forge->URID = map->map(map->handle, LV2_ATOM__URID); | |
163 forge->Vector = map->map(map->handle, LV2_ATOM__Vector); | |
164 } | |
165 | |
166 /** Access the Atom pointed to by a reference. */ | |
167 static inline LV2_Atom* | |
168 lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref) | |
169 { | |
170 if (forge->buf) { | |
171 return (LV2_Atom*)ref; | |
172 } else { | |
173 return forge->deref(forge->handle, ref); | |
174 } | |
175 } | |
176 | |
177 /** | |
178 @name Object Stack | |
179 @{ | |
180 */ | |
181 | |
182 /** | |
183 Push a stack frame. | |
184 This is done automatically by container functions (which take a stack frame | |
185 pointer), but may be called by the user to push the top level container when | |
186 writing to an existing Atom. | |
187 */ | |
188 static inline LV2_Atom_Forge_Ref | |
189 lv2_atom_forge_push(LV2_Atom_Forge* forge, | |
190 LV2_Atom_Forge_Frame* frame, | |
191 LV2_Atom_Forge_Ref ref) | |
192 { | |
193 frame->parent = forge->stack; | |
194 frame->ref = ref; | |
195 forge->stack = frame; | |
196 return ref; | |
197 } | |
198 | |
199 /** Pop a stack frame. This must be called when a container is finished. */ | |
200 static inline void | |
201 lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) | |
202 { | |
203 assert(frame == forge->stack); | |
204 forge->stack = frame->parent; | |
205 } | |
206 | |
207 /** Return true iff the top of the stack has the given type. */ | |
208 static inline bool | |
209 lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type) | |
210 { | |
211 return forge->stack && forge->stack->ref && | |
212 (lv2_atom_forge_deref(forge, forge->stack->ref)->type == type); | |
213 } | |
214 | |
215 /** Return true iff `type` is an atom:Object. */ | |
216 static inline bool | |
217 lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type) | |
218 { | |
219 return (type == forge->Object || | |
220 type == forge->Blank || | |
221 type == forge->Resource); | |
222 } | |
223 | |
224 /** Return true iff `type` is an atom:Object with a blank ID. */ | |
225 static inline bool | |
226 lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge, | |
227 uint32_t type, | |
228 const LV2_Atom_Object_Body* body) | |
229 { | |
230 return (type == forge->Blank || | |
231 (type == forge->Object && body->id == 0)); | |
232 } | |
233 | |
234 /** | |
235 @} | |
236 @name Output Configuration | |
237 @{ | |
238 */ | |
239 | |
240 /** Set the output buffer where `forge` will write atoms. */ | |
241 static inline void | |
242 lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) | |
243 { | |
244 forge->buf = buf; | |
245 forge->size = (uint32_t)size; | |
246 forge->offset = 0; | |
247 forge->deref = NULL; | |
248 forge->sink = NULL; | |
249 forge->handle = NULL; | |
250 forge->stack = NULL; | |
251 } | |
252 | |
253 /** | |
254 Set the sink function where `forge` will write output. | |
255 | |
256 The return value of forge functions is an LV2_Atom_Forge_Ref which is an | |
257 integer type safe to use as a pointer but is otherwise opaque. The sink | |
258 function must return a ref that can be dereferenced to access as least | |
259 sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For | |
260 ringbuffers, this should be possible as long as the size of the buffer is a | |
261 multiple of sizeof(LV2_Atom), since atoms are always aligned. | |
262 | |
263 Note that 0 is an invalid reference, so if you are using a buffer offset be | |
264 sure to offset it such that 0 is never a valid reference. You will get | |
265 confusing errors otherwise. | |
266 */ | |
267 static inline void | |
268 lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, | |
269 LV2_Atom_Forge_Sink sink, | |
270 LV2_Atom_Forge_Deref_Func deref, | |
271 LV2_Atom_Forge_Sink_Handle handle) | |
272 { | |
273 forge->buf = NULL; | |
274 forge->size = forge->offset = 0; | |
275 forge->deref = deref; | |
276 forge->sink = sink; | |
277 forge->handle = handle; | |
278 forge->stack = NULL; | |
279 } | |
280 | |
281 /** | |
282 @} | |
283 @name Low Level Output | |
284 @{ | |
285 */ | |
286 | |
287 /** | |
288 Write raw output. This is used internally, but is also useful for writing | |
289 atom types not explicitly supported by the forge API. Note the caller is | |
290 responsible for ensuring the output is approriately padded. | |
291 */ | |
292 static inline LV2_Atom_Forge_Ref | |
293 lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size) | |
294 { | |
295 LV2_Atom_Forge_Ref out = 0; | |
296 if (forge->sink) { | |
297 out = forge->sink(forge->handle, data, size); | |
298 } else { | |
299 out = (LV2_Atom_Forge_Ref)forge->buf + (LV2_Atom_Forge_Ref)forge->offset; | |
300 uint8_t* mem = forge->buf + forge->offset; | |
301 if (forge->offset + size > forge->size) { | |
302 return 0; | |
303 } | |
304 forge->offset += size; | |
305 memcpy(mem, data, size); | |
306 } | |
307 for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) { | |
308 lv2_atom_forge_deref(forge, f->ref)->size += size; | |
309 } | |
310 return out; | |
311 } | |
312 | |
313 /** Pad output accordingly so next write is 64-bit aligned. */ | |
314 static inline void | |
315 lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written) | |
316 { | |
317 const uint64_t pad = 0; | |
318 const uint32_t pad_size = lv2_atom_pad_size(written) - written; | |
319 lv2_atom_forge_raw(forge, &pad, pad_size); | |
320 } | |
321 | |
322 /** Write raw output, padding to 64-bits as necessary. */ | |
323 static inline LV2_Atom_Forge_Ref | |
324 lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size) | |
325 { | |
326 LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size); | |
327 if (out) { | |
328 lv2_atom_forge_pad(forge, size); | |
329 } | |
330 return out; | |
331 } | |
332 | |
333 /** Write a null-terminated string body. */ | |
334 static inline LV2_Atom_Forge_Ref | |
335 lv2_atom_forge_string_body(LV2_Atom_Forge* forge, | |
336 const char* str, | |
337 uint32_t len) | |
338 { | |
339 LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len); | |
340 if (out && (out = lv2_atom_forge_raw(forge, "", 1))) { | |
341 lv2_atom_forge_pad(forge, len + 1); | |
342 } | |
343 return out; | |
344 } | |
345 | |
346 /** | |
347 @} | |
348 @name Atom Output | |
349 @{ | |
350 */ | |
351 | |
352 /** Write an atom:Atom header. */ | |
353 static inline LV2_Atom_Forge_Ref | |
354 lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type) | |
355 { | |
356 const LV2_Atom a = { size, type }; | |
357 return lv2_atom_forge_raw(forge, &a, sizeof(a)); | |
358 } | |
359 | |
360 /** Write a primitive (fixed-size) atom. */ | |
361 static inline LV2_Atom_Forge_Ref | |
362 lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a) | |
363 { | |
364 if (lv2_atom_forge_top_is(forge, forge->Vector)) { | |
365 return lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size); | |
366 } else { | |
367 return lv2_atom_forge_write( | |
368 forge, a, (uint32_t)sizeof(LV2_Atom) + a->size); | |
369 } | |
370 } | |
371 | |
372 /** Write an atom:Int. */ | |
373 static inline LV2_Atom_Forge_Ref | |
374 lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val) | |
375 { | |
376 const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val }; | |
377 return lv2_atom_forge_primitive(forge, &a.atom); | |
378 } | |
379 | |
380 /** Write an atom:Long. */ | |
381 static inline LV2_Atom_Forge_Ref | |
382 lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val) | |
383 { | |
384 const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val }; | |
385 return lv2_atom_forge_primitive(forge, &a.atom); | |
386 } | |
387 | |
388 /** Write an atom:Float. */ | |
389 static inline LV2_Atom_Forge_Ref | |
390 lv2_atom_forge_float(LV2_Atom_Forge* forge, float val) | |
391 { | |
392 const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val }; | |
393 return lv2_atom_forge_primitive(forge, &a.atom); | |
394 } | |
395 | |
396 /** Write an atom:Double. */ | |
397 static inline LV2_Atom_Forge_Ref | |
398 lv2_atom_forge_double(LV2_Atom_Forge* forge, double val) | |
399 { | |
400 const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val }; | |
401 return lv2_atom_forge_primitive(forge, &a.atom); | |
402 } | |
403 | |
404 /** Write an atom:Bool. */ | |
405 static inline LV2_Atom_Forge_Ref | |
406 lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val) | |
407 { | |
408 const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 }; | |
409 return lv2_atom_forge_primitive(forge, &a.atom); | |
410 } | |
411 | |
412 /** Write an atom:URID. */ | |
413 static inline LV2_Atom_Forge_Ref | |
414 lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id) | |
415 { | |
416 const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id }; | |
417 return lv2_atom_forge_primitive(forge, &a.atom); | |
418 } | |
419 | |
420 /** Write an atom compatible with atom:String. Used internally. */ | |
421 static inline LV2_Atom_Forge_Ref | |
422 lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, | |
423 uint32_t type, | |
424 const char* str, | |
425 uint32_t len) | |
426 { | |
427 const LV2_Atom_String a = { { len + 1, type } }; | |
428 LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); | |
429 if (out) { | |
430 if (!lv2_atom_forge_string_body(forge, str, len)) { | |
431 LV2_Atom* atom = lv2_atom_forge_deref(forge, out); | |
432 atom->size = atom->type = 0; | |
433 out = 0; | |
434 } | |
435 } | |
436 return out; | |
437 } | |
438 | |
439 /** Write an atom:String. Note that `str` need not be NULL terminated. */ | |
440 static inline LV2_Atom_Forge_Ref | |
441 lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) | |
442 { | |
443 return lv2_atom_forge_typed_string(forge, forge->String, str, len); | |
444 } | |
445 | |
446 /** | |
447 Write an atom:URI. Note that `uri` need not be NULL terminated. | |
448 This does not map the URI, but writes the complete URI string. To write | |
449 a mapped URI, use lv2_atom_forge_urid(). | |
450 */ | |
451 static inline LV2_Atom_Forge_Ref | |
452 lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len) | |
453 { | |
454 return lv2_atom_forge_typed_string(forge, forge->URI, uri, len); | |
455 } | |
456 | |
457 /** Write an atom:Path. Note that `path` need not be NULL terminated. */ | |
458 static inline LV2_Atom_Forge_Ref | |
459 lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len) | |
460 { | |
461 return lv2_atom_forge_typed_string(forge, forge->Path, path, len); | |
462 } | |
463 | |
464 /** Write an atom:Literal. */ | |
465 static inline LV2_Atom_Forge_Ref | |
466 lv2_atom_forge_literal(LV2_Atom_Forge* forge, | |
467 const char* str, | |
468 uint32_t len, | |
469 uint32_t datatype, | |
470 uint32_t lang) | |
471 { | |
472 const LV2_Atom_Literal a = { | |
473 { (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1), | |
474 forge->Literal }, | |
475 { datatype, | |
476 lang } | |
477 }; | |
478 LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); | |
479 if (out) { | |
480 if (!lv2_atom_forge_string_body(forge, str, len)) { | |
481 LV2_Atom* atom = lv2_atom_forge_deref(forge, out); | |
482 atom->size = atom->type = 0; | |
483 out = 0; | |
484 } | |
485 } | |
486 return out; | |
487 } | |
488 | |
489 /** Start an atom:Vector. */ | |
490 static inline LV2_Atom_Forge_Ref | |
491 lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, | |
492 LV2_Atom_Forge_Frame* frame, | |
493 uint32_t child_size, | |
494 uint32_t child_type) | |
495 { | |
496 const LV2_Atom_Vector a = { | |
497 { sizeof(LV2_Atom_Vector_Body), forge->Vector }, | |
498 { child_size, child_type } | |
499 }; | |
500 return lv2_atom_forge_push( | |
501 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
502 } | |
503 | |
504 /** Write a complete atom:Vector. */ | |
505 static inline LV2_Atom_Forge_Ref | |
506 lv2_atom_forge_vector(LV2_Atom_Forge* forge, | |
507 uint32_t child_size, | |
508 uint32_t child_type, | |
509 uint32_t n_elems, | |
510 const void* elems) | |
511 { | |
512 const LV2_Atom_Vector a = { | |
513 { (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size), | |
514 forge->Vector }, | |
515 { child_size, child_type } | |
516 }; | |
517 LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); | |
518 if (out) { | |
519 lv2_atom_forge_write(forge, elems, child_size * n_elems); | |
520 } | |
521 return out; | |
522 } | |
523 | |
524 /** | |
525 Write the header of an atom:Tuple. | |
526 | |
527 The passed frame will be initialised to represent this tuple. To complete | |
528 the tuple, write a sequence of atoms, then pop the frame with | |
529 lv2_atom_forge_pop(). | |
530 | |
531 For example: | |
532 @code | |
533 // Write tuple (1, 2.0) | |
534 LV2_Atom_Forge_Frame frame; | |
535 LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame); | |
536 lv2_atom_forge_int32(forge, 1); | |
537 lv2_atom_forge_float(forge, 2.0); | |
538 lv2_atom_forge_pop(forge, &frame); | |
539 @endcode | |
540 */ | |
541 static inline LV2_Atom_Forge_Ref | |
542 lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) | |
543 { | |
544 const LV2_Atom_Tuple a = { { 0, forge->Tuple } }; | |
545 return lv2_atom_forge_push( | |
546 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
547 } | |
548 | |
549 /** | |
550 Write the header of an atom:Object. | |
551 | |
552 The passed frame will be initialised to represent this object. To complete | |
553 the object, write a sequence of properties, then pop the frame with | |
554 lv2_atom_forge_pop(). | |
555 | |
556 For example: | |
557 @code | |
558 LV2_URID eg_Cat = map("http://example.org/Cat"); | |
559 LV2_URID eg_name = map("http://example.org/name"); | |
560 | |
561 // Start object with type eg_Cat and blank ID | |
562 LV2_Atom_Forge_Frame frame; | |
563 lv2_atom_forge_object(forge, &frame, 0, eg_Cat); | |
564 | |
565 // Append property eg:name = "Hobbes" | |
566 lv2_atom_forge_key(forge, eg_name); | |
567 lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes")); | |
568 | |
569 // Finish object | |
570 lv2_atom_forge_pop(forge, &frame); | |
571 @endcode | |
572 */ | |
573 static inline LV2_Atom_Forge_Ref | |
574 lv2_atom_forge_object(LV2_Atom_Forge* forge, | |
575 LV2_Atom_Forge_Frame* frame, | |
576 LV2_URID id, | |
577 LV2_URID otype) | |
578 { | |
579 const LV2_Atom_Object a = { | |
580 { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object }, | |
581 { id, otype } | |
582 }; | |
583 return lv2_atom_forge_push( | |
584 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
585 } | |
586 | |
587 /** | |
588 The same as lv2_atom_forge_object(), but for object:Resource. | |
589 | |
590 This function is deprecated and should not be used in new code. | |
591 Use lv2_atom_forge_object() directly instead. | |
592 */ | |
593 LV2_ATOM_FORGE_DEPRECATED | |
594 static inline LV2_Atom_Forge_Ref | |
595 lv2_atom_forge_resource(LV2_Atom_Forge* forge, | |
596 LV2_Atom_Forge_Frame* frame, | |
597 LV2_URID id, | |
598 LV2_URID otype) | |
599 { | |
600 const LV2_Atom_Object a = { | |
601 { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource }, | |
602 { id, otype } | |
603 }; | |
604 return lv2_atom_forge_push( | |
605 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
606 } | |
607 | |
608 /** | |
609 The same as lv2_atom_forge_object(), but for object:Blank. | |
610 | |
611 This function is deprecated and should not be used in new code. | |
612 Use lv2_atom_forge_object() directly instead. | |
613 */ | |
614 LV2_ATOM_FORGE_DEPRECATED | |
615 static inline LV2_Atom_Forge_Ref | |
616 lv2_atom_forge_blank(LV2_Atom_Forge* forge, | |
617 LV2_Atom_Forge_Frame* frame, | |
618 uint32_t id, | |
619 LV2_URID otype) | |
620 { | |
621 const LV2_Atom_Object a = { | |
622 { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank }, | |
623 { id, otype } | |
624 }; | |
625 return lv2_atom_forge_push( | |
626 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
627 } | |
628 | |
629 /** | |
630 Write a property key in an Object, to be followed by the value. | |
631 | |
632 See lv2_atom_forge_object() documentation for an example. | |
633 */ | |
634 static inline LV2_Atom_Forge_Ref | |
635 lv2_atom_forge_key(LV2_Atom_Forge* forge, | |
636 LV2_URID key) | |
637 { | |
638 const LV2_Atom_Property_Body a = { key, 0, { 0, 0 } }; | |
639 return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); | |
640 } | |
641 | |
642 /** | |
643 Write the header for a property body in an object, with context. | |
644 | |
645 If you do not need the context, which is almost certainly the case, | |
646 use the simpler lv2_atom_forge_key() instead. | |
647 */ | |
648 static inline LV2_Atom_Forge_Ref | |
649 lv2_atom_forge_property_head(LV2_Atom_Forge* forge, | |
650 LV2_URID key, | |
651 LV2_URID context) | |
652 { | |
653 const LV2_Atom_Property_Body a = { key, context, { 0, 0 } }; | |
654 return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); | |
655 } | |
656 | |
657 /** | |
658 Write the header for a Sequence. | |
659 */ | |
660 static inline LV2_Atom_Forge_Ref | |
661 lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, | |
662 LV2_Atom_Forge_Frame* frame, | |
663 uint32_t unit) | |
664 { | |
665 const LV2_Atom_Sequence a = { | |
666 { (uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence }, | |
667 { unit, 0 } | |
668 }; | |
669 return lv2_atom_forge_push( | |
670 forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |
671 } | |
672 | |
673 /** | |
674 Write the time stamp header of an Event (in a Sequence) in audio frames. | |
675 After this, call the appropriate forge method(s) to write the body. Note | |
676 the returned reference is to an LV2_Event which is NOT an Atom. | |
677 */ | |
678 static inline LV2_Atom_Forge_Ref | |
679 lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) | |
680 { | |
681 return lv2_atom_forge_write(forge, &frames, sizeof(frames)); | |
682 } | |
683 | |
684 /** | |
685 Write the time stamp header of an Event (in a Sequence) in beats. After | |
686 this, call the appropriate forge method(s) to write the body. Note the | |
687 returned reference is to an LV2_Event which is NOT an Atom. | |
688 */ | |
689 static inline LV2_Atom_Forge_Ref | |
690 lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats) | |
691 { | |
692 return lv2_atom_forge_write(forge, &beats, sizeof(beats)); | |
693 } | |
694 | |
695 /** | |
696 @} | |
697 @} | |
698 */ | |
699 | |
700 #if defined(__clang__) | |
701 # pragma clang diagnostic pop | |
702 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |
703 # pragma GCC diagnostic pop | |
704 #endif | |
705 | |
706 #ifdef __cplusplus | |
707 } /* extern "C" */ | |
708 #endif | |
709 | |
710 #endif /* LV2_ATOM_FORGE_H */ |