aboutsummaryrefslogtreecommitdiffstats
path: root/lv2/lv2plug.in/ns/ext/atom
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-02-18 06:55:00 +0000
committerDavid Robillard <d@drobilla.net>2012-02-18 06:55:00 +0000
commitd0b752f49f0af4aa64c92d49d8e6ec1e6b545c5b (patch)
treec87f129e3613c0d96d82813bfb97efdcb4d687f2 /lv2/lv2plug.in/ns/ext/atom
parent9c2c83e11d161442f3064b1ae7bc8b778b57542d (diff)
downloadlv2-d0b752f49f0af4aa64c92d49d8e6ec1e6b545c5b.tar.xz
Make forge API more fool-proof and automatically update container sizes to any depth.
Diffstat (limited to 'lv2/lv2plug.in/ns/ext/atom')
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/atom-test.c79
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/forge.h202
2 files changed, 154 insertions, 127 deletions
diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-test.c b/lv2/lv2plug.in/ns/ext/atom/atom-test.c
index 55d453c..2cc0da9 100644
--- a/lv2/lv2plug.in/ns/ext/atom/atom-test.c
+++ b/lv2/lv2plug.in/ns/ext/atom/atom-test.c
@@ -86,47 +86,48 @@ main()
uint8_t buf[BUF_SIZE];
lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE);
+ LV2_Atom_Forge_Frame obj_frame;
LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(
- &forge, NULL, 0, eg_Object);
+ &forge, &obj_frame, 0, eg_Object);
// eg_one = (Int32)1
- lv2_atom_forge_property_head(&forge, obj, eg_one, 0);
- LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, obj, 1);
+ lv2_atom_forge_property_head(&forge, eg_one, 0);
+ LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, 1);
if (one->value != 1) {
return test_fail("%d != 1\n", one->value);
}
// eg_two = (Int64)2
- lv2_atom_forge_property_head(&forge, obj, eg_two, 0);
- LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, obj, 2);
+ lv2_atom_forge_property_head(&forge, eg_two, 0);
+ LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, 2);
if (two->value != 2) {
return test_fail("%ld != 2\n", two->value);
}
// eg_three = (Float)3.0
- lv2_atom_forge_property_head(&forge, obj, eg_three, 0);
- LV2_Atom_Float* three = lv2_atom_forge_float(&forge, obj, 3.0f);
+ lv2_atom_forge_property_head(&forge, eg_three, 0);
+ LV2_Atom_Float* three = lv2_atom_forge_float(&forge, 3.0f);
if (three->value != 3) {
return test_fail("%f != 3\n", three->value);
}
// eg_four = (Double)4.0
- lv2_atom_forge_property_head(&forge, obj, eg_four, 0);
- LV2_Atom_Double* four = lv2_atom_forge_double(&forge, obj, 4.0);
+ lv2_atom_forge_property_head(&forge, eg_four, 0);
+ LV2_Atom_Double* four = lv2_atom_forge_double(&forge, 4.0);
if (four->value != 4) {
return test_fail("%ld != 4\n", four->value);
}
// eg_true = (Bool)1
- lv2_atom_forge_property_head(&forge, obj, eg_true, 0);
- LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, obj, true);
+ lv2_atom_forge_property_head(&forge, eg_true, 0);
+ LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, true);
if (t->value != 1) {
return test_fail("%ld != 1 (true)\n", t->value);
}
// eg_false = (Bool)0
- lv2_atom_forge_property_head(&forge, obj, eg_false, 0);
- LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, obj, false);
+ lv2_atom_forge_property_head(&forge, eg_false, 0);
+ LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, false);
if (f->value != 0) {
return test_fail("%ld != 0 (false)\n", f->value);
}
@@ -134,8 +135,8 @@ main()
// eg_uri = (URI)"http://example.org/value"
const uint8_t* ustr = (const uint8_t*)"http://example.org/value";
const size_t ustr_len = strlen((const char*)ustr);
- lv2_atom_forge_property_head(&forge, obj, eg_uri, 0);
- LV2_Atom_String* uri = lv2_atom_forge_uri(&forge, obj, ustr, ustr_len);
+ lv2_atom_forge_property_head(&forge, eg_uri, 0);
+ LV2_Atom_String* uri = lv2_atom_forge_uri(&forge, ustr, ustr_len);
uint8_t* body = (uint8_t*)LV2_ATOM_BODY(uri);
if (strcmp((const char*)body, (const char*)ustr)) {
return test_fail("%s != \"%s\"\n",
@@ -144,25 +145,25 @@ main()
// eg_urid = (URID)"http://example.org/value"
LV2_URID eg_value = urid_map(NULL, "http://example.org/value");
- lv2_atom_forge_property_head(&forge, obj, eg_urid, 0);
- LV2_Atom_URID* urid = lv2_atom_forge_urid(&forge, obj, eg_value);
+ lv2_atom_forge_property_head(&forge, eg_urid, 0);
+ LV2_Atom_URID* urid = lv2_atom_forge_urid(&forge, eg_value);
if (urid->id != eg_value) {
return test_fail("%u != %u\n", urid->id, eg_value);
}
// eg_string = (String)"hello"
- lv2_atom_forge_property_head(&forge, obj, eg_string, 0);
+ lv2_atom_forge_property_head(&forge, eg_string, 0);
LV2_Atom_String* string = lv2_atom_forge_string(
- &forge, obj, (const uint8_t*)"hello", strlen("hello"));
+ &forge, (const uint8_t*)"hello", strlen("hello"));
uint8_t* sbody = (uint8_t*)LV2_ATOM_BODY(string);
if (strcmp((const char*)sbody, "hello")) {
return test_fail("%s != \"hello\"\n", (const char*)body);
}
// eg_literal = (Literal)"hello"@fr
- lv2_atom_forge_property_head(&forge, obj, eg_literal, 0);
+ lv2_atom_forge_property_head(&forge, eg_literal, 0);
LV2_Atom_Literal* literal = lv2_atom_forge_literal(
- &forge, obj, (const uint8_t*)"bonjour", strlen("bonjour"),
+ &forge, (const uint8_t*)"bonjour", strlen("bonjour"),
0, urid_map(NULL, "http://lexvo.org/id/term/fr"));
body = (uint8_t*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal);
if (strcmp((const char*)body, "bonjour")) {
@@ -170,12 +171,14 @@ main()
}
// eg_tuple = "foo",true
- lv2_atom_forge_property_head(&forge, obj, eg_tuple, 0);
- LV2_Atom_Tuple* tuple = lv2_atom_forge_tuple(&forge, obj);
- LV2_Atom_String* tup0 = lv2_atom_forge_string(
- &forge, (LV2_Atom*)tuple, (const uint8_t*)"foo", strlen("foo"));
- LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, (LV2_Atom*)tuple, true);
- obj->size += ((LV2_Atom*)tuple)->size;
+ lv2_atom_forge_property_head(&forge, eg_tuple, 0);
+ LV2_Atom_Forge_Frame tuple_frame;
+ LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_tuple(
+ &forge, &tuple_frame);
+ LV2_Atom_String* tup0 = lv2_atom_forge_string(
+ &forge, (const uint8_t*)"foo", strlen("foo"));
+ LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, true);
+ lv2_atom_forge_pop(&forge, &tuple_frame);
LV2_Atom_Tuple_Iter i = lv2_tuple_begin(tuple);
if (lv2_tuple_is_end(tuple, i)) {
return test_fail("Tuple iterator is empty\n");
@@ -198,23 +201,26 @@ main()
}
// eg_vector = (Vector<Int32>)1,2,3,4
- lv2_atom_forge_property_head(&forge, obj, eg_vector, 0);
+ lv2_atom_forge_property_head(&forge, eg_vector, 0);
int32_t elems[] = { 1, 2, 3, 4 };
LV2_Atom_Vector* vector = lv2_atom_forge_vector(
- &forge, obj, 4, forge.Int32, sizeof(int32_t), elems);
+ &forge, 4, forge.Int32, sizeof(int32_t), elems);
void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector);
if (memcmp(elems, vec_body, sizeof(elems))) {
return test_fail("Corrupt vector\n");
}
// eg_seq = (Sequence)1, 2
- lv2_atom_forge_property_head(&forge, obj, eg_seq, 0);
- LV2_Atom_Sequence* seq = lv2_atom_forge_sequence_head(&forge, obj, 0, 0);
- lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 0, 0);
- lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 1);
- lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 1, 0);
- lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 2);
- obj->size += seq->atom.size - sizeof(LV2_Atom);
+ lv2_atom_forge_property_head(&forge, eg_seq, 0);
+ LV2_Atom_Forge_Frame seq_frame;
+ LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_sequence_head(&forge, &seq_frame, 0);
+ lv2_atom_forge_audio_time(&forge, 0, 0);
+ lv2_atom_forge_int32(&forge, 1);
+ lv2_atom_forge_audio_time(&forge, 1, 0);
+ lv2_atom_forge_int32(&forge, 2);
+ lv2_atom_forge_pop(&forge, &seq_frame);
+
+ lv2_atom_forge_pop(&forge, &obj_frame);
// Test equality
LV2_Atom_Int32 itwo = { { forge.Int32, sizeof(int32_t) }, 2 };
@@ -279,6 +285,7 @@ main()
{ eg_four, &matches.four },
{ eg_true, &matches.affirmative },
{ eg_false, &matches.negative },
+ { eg_uri, &matches.uri },
{ eg_urid, &matches.urid },
{ eg_string, &matches.string },
{ eg_literal, &matches.literal },
diff --git a/lv2/lv2plug.in/ns/ext/atom/forge.h b/lv2/lv2plug.in/ns/ext/atom/forge.h
index 9735302..0f32db3 100644
--- a/lv2/lv2plug.in/ns/ext/atom/forge.h
+++ b/lv2/lv2plug.in/ns/ext/atom/forge.h
@@ -19,8 +19,7 @@
This file provides a simple API which can be used to create complex nested
atoms by calling the provided functions to append atoms (or atom headers) in
- the correct order. The size of the parent atom is automatically updated,
- but the caller must handle this situation if atoms are more deeply nested.
+ the correct order.
All output is written to a user-provided buffer. This entire API is
realtime safe and suitable for writing to output port buffers in the run
@@ -53,9 +52,13 @@ typedef uint32_t (*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
const void* buf,
uint32_t size);
-/**
- A "forge" for creating atoms by appending to a buffer.
-*/
+/** 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* atom;
+} LV2_Atom_Forge_Frame;
+
+/** A "forge" for creating atoms by appending to a buffer. */
typedef struct {
uint8_t* buf;
uint32_t offset;
@@ -64,6 +67,8 @@ typedef struct {
LV2_Atom_Forge_Sink sink;
LV2_Atom_Forge_Sink_Handle handle;
+ LV2_Atom_Forge_Frame* stack;
+
LV2_URID Blank;
LV2_URID Bool;
LV2_URID Double;
@@ -81,7 +86,25 @@ typedef struct {
LV2_URID Vector;
} LV2_Atom_Forge;
-/** Set the output buffer where @c forge will write atoms. */
+static inline LV2_Atom*
+lv2_atom_forge_push(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ LV2_Atom* atom)
+{
+ frame->parent = forge->stack;
+ frame->atom = atom;
+ forge->stack = frame;
+ return atom;
+}
+
+static inline void
+lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
+{
+ assert(frame == forge->stack);
+ forge->stack = frame->parent;
+}
+
+/** Set the output buffer where @p forge will write atoms. */
static inline void
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
{
@@ -90,6 +113,7 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
forge->offset = 0;
}
+/** Set the sink function where @p forge will write output. */
static inline void
lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
LV2_Atom_Forge_Sink sink,
@@ -102,15 +126,16 @@ lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
}
/**
- Initialise @c forge.
+ Initialise @p forge.
- URIs will be mapped using @c map and stored, a reference to @c map itself is
+ URIs will be mapped using @p map and stored, a reference to @p map itself is
not held.
*/
static inline void
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
{
lv2_atom_forge_set_buffer(forge, NULL, 0);
+ forge->stack = NULL;
forge->Blank = map->map(map->handle, LV2_ATOM_URI "#Blank");
forge->Bool = map->map(map->handle, LV2_ATOM_URI "#Bool");
forge->Double = map->map(map->handle, LV2_ATOM_URI "#Double");
@@ -130,7 +155,6 @@ lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
static inline void*
lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const void* data,
uint32_t size)
{
@@ -138,97 +162,94 @@ lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge,
if (forge->offset + size > forge->size) {
return NULL;
}
- if (parent) {
- parent->size += size;
- }
forge->offset += size;
memcpy(out, data, size);
+ for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
+ f->atom->size += size;
+ }
return out;
}
static inline void
lv2_atom_forge_pad(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
uint32_t written)
{
const uint64_t pad = 0;
const uint32_t pad_size = lv2_atom_pad_size(written) - written;
- lv2_atom_forge_write_nopad(forge, parent, &pad, pad_size);
+ lv2_atom_forge_write_nopad(forge, &pad, pad_size);
}
static inline void*
lv2_atom_forge_write(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const void* data,
uint32_t size)
{
- void* out = lv2_atom_forge_write_nopad(forge, parent, data, size);
+ void* out = lv2_atom_forge_write_nopad(forge, data, size);
if (out) {
- lv2_atom_forge_pad(forge, parent, size);
+ lv2_atom_forge_pad(forge, size);
}
return out;
}
/** Write an atom:Int32. */
static inline LV2_Atom_Int32*
-lv2_atom_forge_int32(LV2_Atom_Forge* forge, LV2_Atom* parent, int32_t val)
+lv2_atom_forge_int32(LV2_Atom_Forge* forge, int32_t val)
{
const LV2_Atom_Int32 a = { { forge->Int32, sizeof(val) }, val };
- return (LV2_Atom_Int32*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_Int32*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/** Write an atom:Int64. */
static inline LV2_Atom_Int64*
-lv2_atom_forge_int64(LV2_Atom_Forge* forge, LV2_Atom* parent, int64_t val)
+lv2_atom_forge_int64(LV2_Atom_Forge* forge, int64_t val)
{
const LV2_Atom_Int64 a = { { forge->Int64, sizeof(val) }, val };
- return (LV2_Atom_Int64*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_Int64*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/** Write an atom:Float. */
static inline LV2_Atom_Float*
-lv2_atom_forge_float(LV2_Atom_Forge* forge, LV2_Atom* parent, float val)
+lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
{
const LV2_Atom_Float a = { { forge->Float, sizeof(val) }, val };
- return (LV2_Atom_Float*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_Float*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/** Write an atom:Double. */
static inline LV2_Atom_Double*
-lv2_atom_forge_double(LV2_Atom_Forge* forge, LV2_Atom* parent, double val)
+lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
{
const LV2_Atom_Double a = { { forge->Double, sizeof(val) }, val };
return (LV2_Atom_Double*)lv2_atom_forge_write(
- forge, parent, &a, sizeof(a));
+ forge, &a, sizeof(a));
}
/** Write an atom:Bool. */
static inline LV2_Atom_Bool*
-lv2_atom_forge_bool(LV2_Atom_Forge* forge, LV2_Atom* parent, bool val)
+lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
{
const LV2_Atom_Bool a = { { forge->Bool, sizeof(val) }, val };
- return (LV2_Atom_Bool*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_Bool*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/** Write an atom:URID. */
static inline LV2_Atom_URID*
-lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_Atom* parent, LV2_URID id)
+lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
{
const LV2_Atom_URID a = { { forge->Int32, sizeof(id) }, id };
- return (LV2_Atom_URID*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_URID*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/** Write a string body. Used internally. */
static inline uint8_t*
lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const uint8_t* str,
size_t len)
{
uint8_t* out = NULL;
- if ((out = lv2_atom_forge_write_nopad(forge, parent, str, len))
- && (out = lv2_atom_forge_write_nopad(forge, parent, "", 1))) {
- lv2_atom_forge_pad(forge, parent, len + 1);
+ if ((out = lv2_atom_forge_write_nopad(forge, str, len))
+ && (out = lv2_atom_forge_write_nopad(forge, "", 1))) {
+ lv2_atom_forge_pad(forge, len + 1);
}
return out;
}
@@ -236,15 +257,14 @@ lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
/** Write an atom:String. Note that @p str need not be NULL terminated. */
static inline LV2_Atom_String*
lv2_atom_forge_string(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const uint8_t* str,
size_t len)
{
const LV2_Atom_String a = { { forge->String, len + 1 } };
LV2_Atom_String* out = (LV2_Atom_String*)
- lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a));
+ lv2_atom_forge_write_nopad(forge, &a, sizeof(a));
if (out) {
- if (!lv2_atom_forge_string_body(forge, parent, str, len)) {
+ if (!lv2_atom_forge_string_body(forge, str, len)) {
out->atom.type = 0;
out->atom.size = 0;
out = NULL;
@@ -260,17 +280,16 @@ lv2_atom_forge_string(LV2_Atom_Forge* forge,
*/
static inline LV2_Atom_String*
lv2_atom_forge_uri(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const uint8_t* uri,
size_t len)
{
const LV2_Atom_String a = { { forge->URI, len + 1 } };
LV2_Atom_String* out = (LV2_Atom_String*)
- lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a));
+ lv2_atom_forge_write_nopad(forge, &a, sizeof(a));
if (!out) {
return NULL;
}
- if (!lv2_atom_forge_string_body(forge, parent, uri, len)) {
+ if (!lv2_atom_forge_string_body(forge, uri, len)) {
out->atom.type = 0;
out->atom.size = 0;
return NULL;
@@ -281,7 +300,6 @@ lv2_atom_forge_uri(LV2_Atom_Forge* forge,
/** Write an atom:Literal. */
static inline LV2_Atom_Literal*
lv2_atom_forge_literal(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
const uint8_t* str,
size_t len,
uint32_t datatype,
@@ -294,9 +312,9 @@ lv2_atom_forge_literal(LV2_Atom_Forge* forge,
lang
};
LV2_Atom_Literal* out = (LV2_Atom_Literal*)
- lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a));
+ lv2_atom_forge_write_nopad(forge, &a, sizeof(a));
if (out) {
- if (!lv2_atom_forge_string_body(forge, parent, str, len)) {
+ if (!lv2_atom_forge_string_body(forge, str, len)) {
out->atom.type = 0;
out->atom.size = 0;
out = NULL;
@@ -308,7 +326,6 @@ lv2_atom_forge_literal(LV2_Atom_Forge* forge,
/** Write an atom:Vector header, but not the vector body. */
static inline LV2_Atom_Vector*
lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
uint32_t elem_count,
uint32_t elem_type,
uint32_t elem_size)
@@ -320,22 +337,21 @@ lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
elem_type
};
return (LV2_Atom_Vector*)lv2_atom_forge_write(
- forge, parent, &a, sizeof(a));
+ forge, &a, sizeof(a));
}
/** Write a complete atom:Vector. */
static inline LV2_Atom_Vector*
lv2_atom_forge_vector(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
uint32_t elem_count,
uint32_t elem_type,
uint32_t elem_size,
void* elems)
{
LV2_Atom_Vector* out = lv2_atom_forge_vector_head(
- forge, parent, elem_count, elem_type, elem_size);
+ forge, elem_count, elem_type, elem_size);
if (out) {
- lv2_atom_forge_write(forge, parent, elems, elem_size * elem_count);
+ lv2_atom_forge_write(forge, elems, elem_size * elem_count);
}
return out;
}
@@ -343,32 +359,34 @@ lv2_atom_forge_vector(LV2_Atom_Forge* forge,
/**
Write the header of an atom:Tuple.
- To complete the tuple, write a sequence of atoms, always passing the
- returned tuple as the @c parent parameter (or otherwise ensuring the size is
- updated correctly).
+ 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* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, NULL);
- lv2_atom_forge_int32(forge, tup, 1);
- lv2_atom_forge_float(forge, tup, 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_Tuple*
-lv2_atom_forge_tuple(LV2_Atom_Forge* forge,
- LV2_Atom* parent)
+static inline LV2_Atom*
+lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
{
- const LV2_Atom_Tuple a = { { forge->Tuple, 0 } };
- return (LV2_Atom_Tuple*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ const LV2_Atom_Tuple a = { { forge->Tuple, 0 } };
+ LV2_Atom* atom = lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, atom);
}
/**
Write the header of an atom:Resource.
- To complete the object, write a sequence of properties, always passing the
- object as the @c parent parameter (or otherwise ensuring the size is updated
- correctly).
+ 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
@@ -376,42 +394,48 @@ lv2_atom_forge_tuple(LV2_Atom_Forge* forge,
LV2_URID eg_name = map("http://example.org/name");
// Write object header
- LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(forge, NULL, 0, eg_Cat);
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(forge, &frame, 1, eg_Cat);
// Write property: eg:name = "Hobbes"
- lv2_atom_forge_property_head(forge, obj, eg_name, 0);
- lv2_atom_forge_string(forge, obj, "Hobbes", strlen("Hobbes"));
+ lv2_atom_forge_property_head(forge, eg_name, 0);
+ lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
+
+ // Finish object
+ lv2_atom_forge_pop(forge, &frame);
@endcode
*/
-static inline LV2_Atom_Object*
-lv2_atom_forge_resource(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
- LV2_URID id,
- LV2_URID otype)
+static inline LV2_Atom*
+lv2_atom_forge_resource(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ LV2_URID id,
+ LV2_URID otype)
{
const LV2_Atom_Object a = {
{ forge->Resource, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) },
id,
otype
};
- return (LV2_Atom_Object*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, atom);
}
/**
The same as lv2_atom_forge_resource(), but for object:Blank.
*/
-static inline LV2_Atom_Object*
-lv2_atom_forge_blank(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
- uint32_t id,
- LV2_URID otype)
+static inline LV2_Atom*
+lv2_atom_forge_blank(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ uint32_t id,
+ LV2_URID otype)
{
const LV2_Atom_Object a = {
{ forge->Blank, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) },
id,
otype
};
- return (LV2_Atom_Object*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, atom);
}
/**
@@ -420,13 +444,12 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge,
*/
static inline LV2_Atom_Property_Body*
lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
LV2_URID key,
LV2_URID context)
{
const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
return (LV2_Atom_Property_Body*)lv2_atom_forge_write(
- forge, parent, &a, 2 * sizeof(uint32_t));
+ forge, &a, 2 * sizeof(uint32_t));
}
/**
@@ -434,48 +457,45 @@ lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
The size of the returned sequence will be 0, so passing it as the parent
parameter to other forge methods will do the right thing.
*/
-static inline LV2_Atom_Sequence*
-lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
- uint32_t capacity,
- uint32_t unit)
+static inline LV2_Atom*
+lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
+ LV2_Atom_Forge_Frame* frame,
+ uint32_t unit)
{
const LV2_Atom_Sequence a = {
{ forge->Sequence, sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom) },
unit,
0
};
- return (LV2_Atom_Sequence*)lv2_atom_forge_write(
- forge, parent, &a, sizeof(a));
+ LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
+ return lv2_atom_forge_push(forge, frame, atom);
}
/**
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, passing
- the same @c parent parameter. Note the returned LV2_Event is NOT an Atom.
+ the same @p parent parameter. Note the returned LV2_Event is NOT an Atom.
*/
static inline LV2_Atom_Event*
lv2_atom_forge_audio_time(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
uint32_t frames,
uint32_t subframes)
{
const LV2_Atom_Audio_Time a = { frames, subframes };
- return (LV2_Atom_Event*)lv2_atom_forge_write(forge, parent, &a, sizeof(a));
+ return (LV2_Atom_Event*)lv2_atom_forge_write(forge, &a, sizeof(a));
}
/**
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, passing
- the same @c parent parameter. Note the returned LV2_Event is NOT an Atom.
+ the same @p parent parameter. Note the returned LV2_Event is NOT an Atom.
*/
static inline LV2_Atom_Event*
lv2_atom_forge_beat_time(LV2_Atom_Forge* forge,
- LV2_Atom* parent,
double beats)
{
return (LV2_Atom_Event*)lv2_atom_forge_write(
- forge, parent, &beats, sizeof(beats));
+ forge, &beats, sizeof(beats));
}
#ifdef __cplusplus