atom-forge.h (21830B)
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 */