diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DPF-Prymula-audioplugins/dpf/distrho/src/lv2/atom-forge.h	Mon Oct 16 21:53:34 2023 +0200
@@ -0,0 +1,710 @@
+/*
+  Copyright 2008-2016 David Robillard <http://drobilla.net>
+
+  Permission to use, copy, modify, and/or distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+   @file forge.h An API for constructing LV2 atoms.
+
+   This file provides an API for constructing Atoms which makes it relatively
+   simple to build nested atoms of arbitrary complexity without requiring
+   dynamic memory allocation.
+
+   The API is based on successively appending the appropriate pieces to build a
+   complete Atom.  The size of containers is automatically updated.  Functions
+   that begin a container return (via their frame argument) a stack frame which
+   must be popped when the container is finished.
+
+   All output is written to a user-provided buffer or sink function.  This
+   makes it popssible to create create atoms on the stack, on the heap, in LV2
+   port buffers, in a ringbuffer, or elsewhere, all using the same API.
+
+   This entire API is realtime safe if used with a buffer or a realtime safe
+   sink, except lv2_atom_forge_init() which is only realtime safe if the URI
+   map function is.
+
+   Note these functions are all static inline, do not take their address.
+
+   This header is non-normative, it is provided for convenience.
+*/
+
+/**
+   @defgroup forge Forge
+   @ingroup atom
+   @{
+*/
+
+#ifndef LV2_ATOM_FORGE_H
+#define LV2_ATOM_FORGE_H
+
+#include <assert.h>
+
+#include "atom.h"
+#include "atom-util.h"
+#include "urid.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#    define LV2_ATOM_FORGE_DEPRECATED __attribute__((__deprecated__))
+#else
+#    define LV2_ATOM_FORGE_DEPRECATED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#else
+#    include <stdbool.h>
+#endif
+
+// Disable deprecation warnings for Blank and Resource
+#if defined(__clang__)
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+/** Handle for LV2_Atom_Forge_Sink. */
+typedef void* LV2_Atom_Forge_Sink_Handle;
+
+/** A reference to a chunk of written output. */
+typedef intptr_t LV2_Atom_Forge_Ref;
+
+/** Sink function for writing output.  See lv2_atom_forge_set_sink(). */
+typedef LV2_Atom_Forge_Ref
+(*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
+                       const void*                buf,
+                       uint32_t                   size);
+
+/** Function for resolving a reference.  See lv2_atom_forge_set_sink(). */
+typedef LV2_Atom*
+(*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle,
+                             LV2_Atom_Forge_Ref         ref);
+
+/** A stack frame used for keeping track of nested Atom containers. */
+typedef struct _LV2_Atom_Forge_Frame {
+	struct _LV2_Atom_Forge_Frame* parent;
+	LV2_Atom_Forge_Ref            ref;
+} LV2_Atom_Forge_Frame;
+
+/** A "forge" for creating atoms by appending to a buffer. */
+typedef struct {
+	uint8_t* buf;
+	uint32_t offset;
+	uint32_t size;
+
+	LV2_Atom_Forge_Sink        sink;
+	LV2_Atom_Forge_Deref_Func  deref;
+	LV2_Atom_Forge_Sink_Handle handle;
+
+	LV2_Atom_Forge_Frame* stack;
+
+	LV2_URID Blank LV2_ATOM_FORGE_DEPRECATED;
+	LV2_URID Bool;
+	LV2_URID Chunk;
+	LV2_URID Double;
+	LV2_URID Float;
+	LV2_URID Int;
+	LV2_URID Long;
+	LV2_URID Literal;
+	LV2_URID Object;
+	LV2_URID Path;
+	LV2_URID Property;
+	LV2_URID Resource LV2_ATOM_FORGE_DEPRECATED;
+	LV2_URID Sequence;
+	LV2_URID String;
+	LV2_URID Tuple;
+	LV2_URID URI;
+	LV2_URID URID;
+	LV2_URID Vector;
+} LV2_Atom_Forge;
+
+static inline void
+lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
+
+/**
+   Initialise `forge`.
+
+   URIs will be mapped using `map` and stored, a reference to `map` itself is
+   not held.
+*/
+static inline void
+lv2_atom_forge_init(LV2_Atom_Forge* forge, const LV2_URID_Map* map)
+{
+	lv2_atom_forge_set_buffer(forge, NULL, 0);
+	forge->Blank    = map->map(map->handle, LV2_ATOM__Blank);
+	forge->Bool     = map->map(map->handle, LV2_ATOM__Bool);
+	forge->Chunk    = map->map(map->handle, LV2_ATOM__Chunk);
+	forge->Double   = map->map(map->handle, LV2_ATOM__Double);
+	forge->Float    = map->map(map->handle, LV2_ATOM__Float);
+	forge->Int      = map->map(map->handle, LV2_ATOM__Int);
+	forge->Long     = map->map(map->handle, LV2_ATOM__Long);
+	forge->Literal  = map->map(map->handle, LV2_ATOM__Literal);
+	forge->Object   = map->map(map->handle, LV2_ATOM__Object);
+	forge->Path     = map->map(map->handle, LV2_ATOM__Path);
+	forge->Property = map->map(map->handle, LV2_ATOM__Property);
+	forge->Resource = map->map(map->handle, LV2_ATOM__Resource);
+	forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence);
+	forge->String   = map->map(map->handle, LV2_ATOM__String);
+	forge->Tuple    = map->map(map->handle, LV2_ATOM__Tuple);
+	forge->URI      = map->map(map->handle, LV2_ATOM__URI);
+	forge->URID     = map->map(map->handle, LV2_ATOM__URID);
+	forge->Vector   = map->map(map->handle, LV2_ATOM__Vector);
+}
+
+/** Access the Atom pointed to by a reference. */
+static inline LV2_Atom*
+lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref)
+{
+	if (forge->buf) {
+		return (LV2_Atom*)ref;
+	} else {
+		return forge->deref(forge->handle, ref);
+	}
+}
+
+/**
+   @name Object Stack
+   @{
+*/
+
+/**
+   Push a stack frame.
+   This is done automatically by container functions (which take a stack frame
+   pointer), but may be called by the user to push the top level container when
+   writing to an existing Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_push(LV2_Atom_Forge*       forge,
+                    LV2_Atom_Forge_Frame* frame,
+                    LV2_Atom_Forge_Ref    ref)
+{
+	frame->parent = forge->stack;
+	frame->ref    = ref;
+	forge->stack  = frame;
+	return ref;
+}
+
+/** Pop a stack frame.  This must be called when a container is finished. */
+static inline void
+lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
+{
+	assert(frame == forge->stack);
+	forge->stack = frame->parent;
+}
+
+/** Return true iff the top of the stack has the given type. */
+static inline bool
+lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type)
+{
+	return forge->stack && forge->stack->ref &&
+		(lv2_atom_forge_deref(forge, forge->stack->ref)->type == type);
+}
+
+/** Return true iff `type` is an atom:Object. */
+static inline bool
+lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type)
+{
+	return (type == forge->Object ||
+	        type == forge->Blank ||
+	        type == forge->Resource);
+}
+
+/** Return true iff `type` is an atom:Object with a blank ID. */
+static inline bool
+lv2_atom_forge_is_blank(const LV2_Atom_Forge*       forge,
+                        uint32_t                    type,
+                        const LV2_Atom_Object_Body* body)
+{
+	return (type == forge->Blank ||
+	        (type == forge->Object && body->id == 0));
+}
+
+/**
+   @}
+   @name Output Configuration
+   @{
+*/
+
+/** Set the output buffer where `forge` will write atoms. */
+static inline void
+lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
+{
+	forge->buf    = buf;
+	forge->size   = (uint32_t)size;
+	forge->offset = 0;
+	forge->deref  = NULL;
+	forge->sink   = NULL;
+	forge->handle = NULL;
+	forge->stack  = NULL;
+}
+
+/**
+   Set the sink function where `forge` will write output.
+
+   The return value of forge functions is an LV2_Atom_Forge_Ref which is an
+   integer type safe to use as a pointer but is otherwise opaque.  The sink
+   function must return a ref that can be dereferenced to access as least
+   sizeof(LV2_Atom) bytes of the written data, so sizes can be updated.  For
+   ringbuffers, this should be possible as long as the size of the buffer is a
+   multiple of sizeof(LV2_Atom), since atoms are always aligned.
+
+   Note that 0 is an invalid reference, so if you are using a buffer offset be
+   sure to offset it such that 0 is never a valid reference.  You will get
+   confusing errors otherwise.
+*/
+static inline void
+lv2_atom_forge_set_sink(LV2_Atom_Forge*            forge,
+                        LV2_Atom_Forge_Sink        sink,
+                        LV2_Atom_Forge_Deref_Func  deref,
+                        LV2_Atom_Forge_Sink_Handle handle)
+{
+	forge->buf    = NULL;
+	forge->size   = forge->offset = 0;
+	forge->deref  = deref;
+	forge->sink   = sink;
+	forge->handle = handle;
+	forge->stack  = NULL;
+}
+
+/**
+   @}
+   @name Low Level Output
+   @{
+*/
+
+/**
+   Write raw output.  This is used internally, but is also useful for writing
+   atom types not explicitly supported by the forge API.  Note the caller is
+   responsible for ensuring the output is approriately padded.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
+{
+	LV2_Atom_Forge_Ref out = 0;
+	if (forge->sink) {
+		out = forge->sink(forge->handle, data, size);
+	} else {
+		out = (LV2_Atom_Forge_Ref)forge->buf + (LV2_Atom_Forge_Ref)forge->offset;
+		uint8_t* mem = forge->buf + forge->offset;
+		if (forge->offset + size > forge->size) {
+			return 0;
+		}
+		forge->offset += size;
+		memcpy(mem, data, size);
+	}
+	for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
+		lv2_atom_forge_deref(forge, f->ref)->size += size;
+	}
+	return out;
+}
+
+/** Pad output accordingly so next write is 64-bit aligned. */
+static inline void
+lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
+{
+	const uint64_t pad      = 0;
+	const uint32_t pad_size = lv2_atom_pad_size(written) - written;
+	lv2_atom_forge_raw(forge, &pad, pad_size);
+}
+
+/** Write raw output, padding to 64-bits as necessary. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
+{
+	LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size);
+	if (out) {
+		lv2_atom_forge_pad(forge, size);
+	}
+	return out;
+}
+
+/** Write a null-terminated string body. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
+                           const char*     str,
+                           uint32_t        len)
+{
+	LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len);
+	if (out && (out = lv2_atom_forge_raw(forge, "", 1))) {
+		lv2_atom_forge_pad(forge, len + 1);
+	}
+	return out;
+}
+
+/**
+   @}
+   @name Atom Output
+   @{
+*/
+
+/** Write an atom:Atom header. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
+{
+	const LV2_Atom a = { size, type };
+	return lv2_atom_forge_raw(forge, &a, sizeof(a));
+}
+
+/** Write a primitive (fixed-size) atom. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a)
+{
+	if (lv2_atom_forge_top_is(forge, forge->Vector)) {
+		return lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size);
+	} else {
+		return lv2_atom_forge_write(
+			forge, a, (uint32_t)sizeof(LV2_Atom) + a->size);
+	}
+}
+
+/** Write an atom:Int. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val)
+{
+	const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Long. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val)
+{
+	const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Float. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
+{
+	const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Double. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
+{
+	const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:Bool. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
+{
+	const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom:URID. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
+{
+	const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id };
+	return lv2_atom_forge_primitive(forge, &a.atom);
+}
+
+/** Write an atom compatible with atom:String.  Used internally. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
+                            uint32_t        type,
+                            const char*     str,
+                            uint32_t        len)
+{
+	const LV2_Atom_String a   = { { len + 1, type } };
+	LV2_Atom_Forge_Ref    out = lv2_atom_forge_raw(forge, &a, sizeof(a));
+	if (out) {
+		if (!lv2_atom_forge_string_body(forge, str, len)) {
+			LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
+			atom->size = atom->type = 0;
+			out = 0;
+		}
+	}
+	return out;
+}
+
+/** Write an atom:String.  Note that `str` need not be NULL terminated. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len)
+{
+	return lv2_atom_forge_typed_string(forge, forge->String, str, len);
+}
+
+/**
+   Write an atom:URI.  Note that `uri` need not be NULL terminated.
+   This does not map the URI, but writes the complete URI string.  To write
+   a mapped URI, use lv2_atom_forge_urid().
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len)
+{
+	return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
+}
+
+/** Write an atom:Path.  Note that `path` need not be NULL terminated. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len)
+{
+	return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
+}
+
+/** Write an atom:Literal. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_literal(LV2_Atom_Forge* forge,
+                       const char*     str,
+                       uint32_t        len,
+                       uint32_t        datatype,
+                       uint32_t        lang)
+{
+	const LV2_Atom_Literal a = {
+		{ (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1),
+		  forge->Literal },
+		{ datatype,
+		  lang }
+	};
+	LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
+	if (out) {
+		if (!lv2_atom_forge_string_body(forge, str, len)) {
+			LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
+			atom->size = atom->type = 0;
+			out = 0;
+		}
+	}
+	return out;
+}
+
+/** Start an atom:Vector. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_vector_head(LV2_Atom_Forge*       forge,
+                           LV2_Atom_Forge_Frame* frame,
+                           uint32_t              child_size,
+                           uint32_t              child_type)
+{
+	const LV2_Atom_Vector a = {
+		{ sizeof(LV2_Atom_Vector_Body), forge->Vector },
+		{ child_size, child_type }
+	};
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/** Write a complete atom:Vector. */
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_vector(LV2_Atom_Forge* forge,
+                      uint32_t        child_size,
+                      uint32_t        child_type,
+                      uint32_t        n_elems,
+                      const void*     elems)
+{
+	const LV2_Atom_Vector a = {
+		{ (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size),
+		  forge->Vector },
+		{ child_size, child_type }
+	};
+	LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
+	if (out) {
+		lv2_atom_forge_write(forge, elems, child_size * n_elems);
+	}
+	return out;
+}
+
+/**
+   Write the header of an atom:Tuple.
+
+   The passed frame will be initialised to represent this tuple.  To complete
+   the tuple, write a sequence of atoms, then pop the frame with
+   lv2_atom_forge_pop().
+
+   For example:
+   @code
+   // Write tuple (1, 2.0)
+   LV2_Atom_Forge_Frame frame;
+   LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
+   lv2_atom_forge_int32(forge, 1);
+   lv2_atom_forge_float(forge, 2.0);
+   lv2_atom_forge_pop(forge, &frame);
+   @endcode
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
+{
+	const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+   Write the header of an atom:Object.
+
+   The passed frame will be initialised to represent this object.  To complete
+   the object, write a sequence of properties, then pop the frame with
+   lv2_atom_forge_pop().
+
+   For example:
+   @code
+   LV2_URID eg_Cat  = map("http://example.org/Cat");
+   LV2_URID eg_name = map("http://example.org/name");
+
+   // Start object with type eg_Cat and blank ID
+   LV2_Atom_Forge_Frame frame;
+   lv2_atom_forge_object(forge, &frame, 0, eg_Cat);
+
+   // Append property eg:name = "Hobbes"
+   lv2_atom_forge_key(forge, eg_name);
+   lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
+
+   // Finish object
+   lv2_atom_forge_pop(forge, &frame);
+   @endcode
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_object(LV2_Atom_Forge*       forge,
+                      LV2_Atom_Forge_Frame* frame,
+                      LV2_URID              id,
+                      LV2_URID              otype)
+{
+	const LV2_Atom_Object a = {
+		{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object },
+		{ id, otype }
+	};
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+   The same as lv2_atom_forge_object(), but for object:Resource.
+
+   This function is deprecated and should not be used in new code.
+   Use lv2_atom_forge_object() directly instead.
+*/
+LV2_ATOM_FORGE_DEPRECATED
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_resource(LV2_Atom_Forge*       forge,
+                        LV2_Atom_Forge_Frame* frame,
+                        LV2_URID              id,
+                        LV2_URID              otype)
+{
+	const LV2_Atom_Object a = {
+		{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource },
+		{ id, otype }
+	};
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+   The same as lv2_atom_forge_object(), but for object:Blank.
+
+   This function is deprecated and should not be used in new code.
+   Use lv2_atom_forge_object() directly instead.
+*/
+LV2_ATOM_FORGE_DEPRECATED
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_blank(LV2_Atom_Forge*       forge,
+                     LV2_Atom_Forge_Frame* frame,
+                     uint32_t              id,
+                     LV2_URID              otype)
+{
+	const LV2_Atom_Object a = {
+		{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank },
+		{ id, otype }
+	};
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+   Write a property key in an Object, to be followed by the value.
+
+   See lv2_atom_forge_object() documentation for an example.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_key(LV2_Atom_Forge* forge,
+                   LV2_URID        key)
+{
+	const LV2_Atom_Property_Body a = { key, 0, { 0, 0 } };
+	return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
+}
+
+/**
+   Write the header for a property body in an object, with context.
+
+   If you do not need the context, which is almost certainly the case,
+   use the simpler lv2_atom_forge_key() instead.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
+                             LV2_URID        key,
+                             LV2_URID        context)
+{
+	const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
+	return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
+}
+
+/**
+   Write the header for a Sequence.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_sequence_head(LV2_Atom_Forge*       forge,
+                             LV2_Atom_Forge_Frame* frame,
+                             uint32_t              unit)
+{
+	const LV2_Atom_Sequence a = {
+		{ (uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence },
+		{ unit, 0 }
+	};
+	return lv2_atom_forge_push(
+		forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
+}
+
+/**
+   Write the time stamp header of an Event (in a Sequence) in audio frames.
+   After this, call the appropriate forge method(s) to write the body.  Note
+   the returned reference is to an LV2_Event which is NOT an Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
+{
+	return lv2_atom_forge_write(forge, &frames, sizeof(frames));
+}
+
+/**
+   Write the time stamp header of an Event (in a Sequence) in beats.  After
+   this, call the appropriate forge method(s) to write the body.  Note the
+   returned reference is to an LV2_Event which is NOT an Atom.
+*/
+static inline LV2_Atom_Forge_Ref
+lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
+{
+	return lv2_atom_forge_write(forge, &beats, sizeof(beats));
+}
+
+/**
+   @}
+   @}
+*/
+
+#if defined(__clang__)
+#    pragma clang diagnostic pop
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#    pragma GCC diagnostic pop
+#endif
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* LV2_ATOM_FORGE_H */