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 */