From c2cc2607f8d5b9eea933a18abd91b2ce708fc90c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 23 Feb 2012 01:53:15 +0000 Subject: Separately define body types for atoms with non-trivial bodies so the type definitions are useful when only the body is available (e.g. state API). Use a single int64_t stamp for frame times since range is more important now and subframes was never really used anyway. Add atom:frameTime and atom:beatTime for serialising events. Consistently use name "body" for all types of atom bodies. Add lv2_atom_forge_atom() and lv2_atom_forge_raw() for constructing arbitrary atoms. Merge similar string-like forge methods. Update language URI requirements to match current (and hopefully permanent, geeze) http://lexvo.org reality. --- lv2/lv2plug.in/ns/ext/atom/atom-test.c | 39 +++++----- lv2/lv2plug.in/ns/ext/atom/atom.h | 128 ++++++++++++++++++-------------- lv2/lv2plug.in/ns/ext/atom/atom.ttl | 40 +++++++--- lv2/lv2plug.in/ns/ext/atom/forge.h | 122 ++++++++++++++---------------- lv2/lv2plug.in/ns/ext/atom/manifest.ttl | 2 +- lv2/lv2plug.in/ns/ext/atom/util.h | 82 +++++++++++++++----- 6 files changed, 239 insertions(+), 174 deletions(-) (limited to 'lv2/lv2plug.in/ns/ext/atom') diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-test.c b/lv2/lv2plug.in/ns/ext/atom/atom-test.c index 8e56c79..7e90c15 100644 --- a/lv2/lv2plug.in/ns/ext/atom/atom-test.c +++ b/lv2/lv2plug.in/ns/ext/atom/atom-test.c @@ -94,43 +94,43 @@ main() // eg_one = (Int32)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); + if (one->body != 1) { + return test_fail("%d != 1\n", one->body); } // eg_two = (Int64)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); + if (two->body != 2) { + return test_fail("%ld != 2\n", two->body); } // eg_three = (Float)3.0 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); + if (three->body != 3) { + return test_fail("%f != 3\n", three->body); } // eg_four = (Double)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); + if (four->body != 4) { + return test_fail("%ld != 4\n", four->body); } // eg_true = (Bool)1 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); + if (t->body != 1) { + return test_fail("%ld != 1 (true)\n", t->body); } // eg_false = (Bool)0 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); + if (f->body != 0) { + return test_fail("%ld != 0 (false)\n", f->body); } // eg_path = (Path)"/foo/bar" @@ -159,8 +159,8 @@ main() LV2_URID eg_value = urid_map(NULL, "http://example.org/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); + if (urid->body != eg_value) { + return test_fail("%u != %u\n", urid->body, eg_value); } // eg_string = (String)"hello" @@ -226,9 +226,9 @@ main() 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_frame_time(&forge, 0); lv2_atom_forge_int32(&forge, 1); - lv2_atom_forge_audio_time(&forge, 1, 0); + lv2_atom_forge_frame_time(&forge, 1); lv2_atom_forge_int32(&forge, 2); lv2_atom_forge_pop(&forge, &seq_frame); @@ -240,17 +240,18 @@ main() return test_fail("1 == 2.0\n"); } else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) { return test_fail("1 == 2\n"); + } else if (!lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)one)) { + return test_fail("1 != 1\n"); } unsigned n_events = 0; LV2_SEQUENCE_FOREACH(seq, i) { LV2_Atom_Event* ev = lv2_sequence_iter_get(i); - if (ev->time.audio.frames != n_events - || ev->time.audio.subframes != 0) { + if (ev->time.frames != n_events) { return test_fail("Corrupt event %u has bad time\n", n_events); } else if (ev->body.type != forge.Int32) { return test_fail("Corrupt event %u has bad type\n", n_events); - } else if (((LV2_Atom_Int32*)&ev->body)->value != (int)n_events + 1) { + } else if (((LV2_Atom_Int32*)&ev->body)->body != (int)n_events + 1) { return test_fail("Event %u != %d\n", n_events, n_events + 1); } ++n_events; diff --git a/lv2/lv2plug.in/ns/ext/atom/atom.h b/lv2/lv2plug.in/ns/ext/atom/atom.h index 3609cc9..6f104e2 100644 --- a/lv2/lv2plug.in/ns/ext/atom/atom.h +++ b/lv2/lv2plug.in/ns/ext/atom/atom.h @@ -28,34 +28,37 @@ #define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" #define LV2_ATOM__Atom LV2_ATOM_URI "#Atom" -#define LV2_ATOM__Number LV2_ATOM_URI "#Number" +#define LV2_ATOM__AtomPort LV2_ATOM_URI "#AtomPort" +#define LV2_ATOM__AudioFrames LV2_ATOM_URI "#AudioFrames" +#define LV2_ATOM__Beats LV2_ATOM_URI "#Beats" +#define LV2_ATOM__Blank LV2_ATOM_URI "#Blank" +#define LV2_ATOM__Bool LV2_ATOM_URI "#Bool" +#define LV2_ATOM__Double LV2_ATOM_URI "#Double" +#define LV2_ATOM__Event LV2_ATOM_URI "#Event" +#define LV2_ATOM__Float LV2_ATOM_URI "#Float" #define LV2_ATOM__Int32 LV2_ATOM_URI "#Int32" #define LV2_ATOM__Int64 LV2_ATOM_URI "#Int64" -#define LV2_ATOM__Float LV2_ATOM_URI "#Float" -#define LV2_ATOM__Double LV2_ATOM_URI "#Double" -#define LV2_ATOM__Bool LV2_ATOM_URI "#Bool" -#define LV2_ATOM__String LV2_ATOM_URI "#String" #define LV2_ATOM__Literal LV2_ATOM_URI "#Literal" +#define LV2_ATOM__MessagePort LV2_ATOM_URI "#MessagePort" +#define LV2_ATOM__Number LV2_ATOM_URI "#Number" +#define LV2_ATOM__Object LV2_ATOM_URI "#Object" #define LV2_ATOM__Path LV2_ATOM_URI "#Path" -#define LV2_ATOM__URI LV2_ATOM_URI "#URI" -#define LV2_ATOM__URID LV2_ATOM_URI "#URID" -#define LV2_ATOM__Vector LV2_ATOM_URI "#Vector" -#define LV2_ATOM__Tuple LV2_ATOM_URI "#Tuple" #define LV2_ATOM__Property LV2_ATOM_URI "#Property" -#define LV2_ATOM__Object LV2_ATOM_URI "#Object" #define LV2_ATOM__Resource LV2_ATOM_URI "#Resource" -#define LV2_ATOM__Blank LV2_ATOM_URI "#Blank" -#define LV2_ATOM__TimeUnit LV2_ATOM_URI "#TimeUnit" -#define LV2_ATOM__AudioFrames LV2_ATOM_URI "#AudioFrames" -#define LV2_ATOM__Beats LV2_ATOM_URI "#Beats" -#define LV2_ATOM__Event LV2_ATOM_URI "#Event" #define LV2_ATOM__Sequence LV2_ATOM_URI "#Sequence" -#define LV2_ATOM__AtomPort LV2_ATOM_URI "#AtomPort" +#define LV2_ATOM__String LV2_ATOM_URI "#String" +#define LV2_ATOM__TimeUnit LV2_ATOM_URI "#TimeUnit" +#define LV2_ATOM__Tuple LV2_ATOM_URI "#Tuple" +#define LV2_ATOM__URI LV2_ATOM_URI "#URI" +#define LV2_ATOM__URID LV2_ATOM_URI "#URID" #define LV2_ATOM__ValuePort LV2_ATOM_URI "#ValuePort" -#define LV2_ATOM__MessagePort LV2_ATOM_URI "#MessagePort" +#define LV2_ATOM__Vector LV2_ATOM_URI "#Vector" +#define LV2_ATOM__beatTime LV2_ATOM_URI "#beatTime" #define LV2_ATOM__bufferType LV2_ATOM_URI "#bufferType" -#define LV2_ATOM__supports LV2_ATOM_URI "#supports" #define LV2_ATOM__eventTransfer LV2_ATOM_URI "#eventTransfer" +#define LV2_ATOM__frameTime LV2_ATOM_URI "#frameTime" +#define LV2_ATOM__supports LV2_ATOM_URI "#supports" +#define LV2_ATOM__timeUnit LV2_ATOM_URI "#timeUnit" #define LV2_ATOM_REFERENCE_TYPE 0 @@ -68,14 +71,18 @@ typedef char lv2_atom_assert_double_fits_in_64_bits[ ((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; /** - Return a pointer to the contents of an Atom. + Return a pointer to the contents of an Atom. The "contents" of an atom + is the data past the complete type-specific header. @param type The type of the atom, e.g. LV2_Atom_String. @param atom A variable-sized atom. */ #define LV2_ATOM_CONTENTS(type, atom) \ ((void*)((uint8_t*)(atom) + sizeof(type))) -/** Return a pointer to the body of @p atom (just past the LV2_Atom head). */ +/** + Return a pointer to the body of an Atom. The "body" of an atom is the + data just past the LV2_Atom head (i.e. the same offset for all types). +*/ #define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom) /** The header of an atom:Atom. */ @@ -86,26 +93,26 @@ typedef struct { /** An atom:Int32 or atom:Bool. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - int32_t value; /**< Integer value. */ + LV2_Atom atom; /**< Atom header. */ + int32_t body; /**< Integer value. */ } LV2_Atom_Int32; /** An atom:Int64. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - int64_t value; /**< Integer value. */ + LV2_Atom atom; /**< Atom header. */ + int64_t body; /**< Integer value. */ } LV2_Atom_Int64; /** An atom:Float. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - float value; /**< Floating point value. */ + LV2_Atom atom; /**< Atom header. */ + float body; /**< Floating point value. */ } LV2_Atom_Float; /** An atom:Double. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - double value; /**< Floating point value. */ + LV2_Atom atom; /**< Atom header. */ + double body; /**< Floating point value. */ } LV2_Atom_Double; /** An atom:Bool. May be cast to LV2_Atom. */ @@ -114,83 +121,87 @@ typedef LV2_Atom_Int32 LV2_Atom_Bool; /** An atom:URID. May be cast to LV2_Atom. */ typedef struct { LV2_Atom atom; /**< Atom header. */ - uint32_t id; /**< URID. */ + uint32_t body; /**< URID. */ } LV2_Atom_URID; -/** The complete header of an atom:String. */ +/** An atom:String. May be cast to LV2_Atom. */ typedef struct { LV2_Atom atom; /**< Atom header. */ /* Contents (a null-terminated UTF-8 string) follow here. */ } LV2_Atom_String; -/** The complete header of an atom:Literal. */ +/** The body of an atom:Literal. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ uint32_t datatype; /**< Datatype URID. */ uint32_t lang; /**< Language URID. */ /* Contents (a null-terminated UTF-8 string) follow here. */ +} LV2_Atom_Literal_Body; + +/** An atom:Literal. May be cast to LV2_Atom. */ +typedef struct { + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Literal_Body body; /**< Body. */ } LV2_Atom_Literal; -/** The complete header of an atom:Tuple. */ +/** An atom:Tuple. May be cast to LV2_Atom. */ typedef struct { LV2_Atom atom; /**< Atom header. */ /* Contents (a series of complete atoms) follow here. */ } LV2_Atom_Tuple; -/** The complete header of an atom:Vector. */ +/** The body of an atom:Vector. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ uint32_t elem_count; /**< The number of elements in the vector */ uint32_t elem_type; /**< The type of each element in the vector */ /* Contents (a series of packed atom bodies) follow here. */ +} LV2_Atom_Vector_Body; + +/** An atom:Vector. May be cast to LV2_Atom. */ +typedef struct { + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Vector_Body body; /**< Body. */ } LV2_Atom_Vector; -/** The header of an atom:Property body (e.g. in an atom:Object). */ +/** The body of an atom:Property (e.g. in an atom:Object). */ typedef struct { uint32_t key; /**< Key (predicate) (mapped URI). */ uint32_t context; /**< Context URID (may be, and generally is, 0). */ LV2_Atom value; /**< Value atom header. */ + /* Value atom body follows here. */ } LV2_Atom_Property_Body; -/** The complete header of an atom:Property. */ +/** An atom:Property. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - uint32_t key; /**< Key (predicate) (mapped URI). */ - uint32_t context; /**< Context URID (may be, and generally is, 0). */ - LV2_Atom value; /**< Value atom header. */ - /* Value atom body follows here. */ + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Property_Body body; /**< Body. */ } LV2_Atom_Property; -/** The complete header of an atom:Object. */ +/** The body of an atom:Object. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ uint32_t id; /**< URID (atom:Resource) or blank ID (atom:Blank). */ uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ /* Contents (a series of property bodies) follow here. */ -} LV2_Atom_Object; +} LV2_Atom_Object_Body; -/** A time stamp in frames. Note this type is NOT an LV2_Atom. */ +/** An atom:Object. May be cast to LV2_Atom. */ typedef struct { - uint32_t frames; /**< Time in frames relative to this block. */ - uint32_t subframes; /**< Fractional time in 1/(2^32)ths of a frame. */ -} LV2_Atom_Audio_Time; + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Object_Body body; /**< Body. */ +} LV2_Atom_Object; /** The header of an atom:Event. Note this type is NOT an LV2_Atom. */ typedef struct { /** Time stamp. Which type is valid is determined by context. */ union { - LV2_Atom_Audio_Time audio; /**< Time in audio frames. */ - double beats; /**< Time in beats. */ + int64_t frames; /**< Time in audio frames. */ + double beats; /**< Time in beats. */ } time; LV2_Atom body; /**< Event body atom header. */ /* Body atom contents follow here. */ } LV2_Atom_Event; /** - A sequence of events (time-stamped atoms). - - This is used as the contents of an atom:EventPort, but is a generic Atom - type which can be used anywhere. + The body of an atom:Sequence (a sequence of events). The unit field is either a URID that described an appropriate time stamp type, or may be 0 where a default stamp type is known. For @@ -207,10 +218,15 @@ typedef struct { */ typedef struct { - LV2_Atom atom; /**< Atom header. */ uint32_t unit; /**< URID of unit of event time stamps. */ uint32_t pad; /**< Currently unused. */ /* Contents (a series of events) follow here. */ +} LV2_Atom_Sequence_Body; + +/** An atom:Sequence. */ +typedef struct { + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Literal_Body body; /**< Body. */ } LV2_Atom_Sequence; /** diff --git a/lv2/lv2plug.in/ns/ext/atom/atom.ttl b/lv2/lv2plug.in/ns/ext/atom/atom.ttl index e6b5207..b939f33 100644 --- a/lv2/lv2plug.in/ns/ext/atom/atom.ttl +++ b/lv2/lv2plug.in/ns/ext/atom/atom.ttl @@ -30,14 +30,14 @@ rdfs:seeAlso , ; doap:release [ - doap:revision "0.5" ; - doap:created "2012-02-18" + doap:revision "0.6" ; + doap:created "2012-02-22" ; ] ; doap:maintainer [ a foaf:Person ; foaf:name "David Robillard" ; foaf:homepage ; - rdfs:seeAlso + rdfs:seeAlso ; ] ; lv2:documentation """

This extension defines a generic container for data, called an Atom, @@ -177,9 +177,8 @@ string in any language or a value of any type. A Literal has a encoding. The length of the string data in bytes is size - sizeof(LV2_Atom_Literal), including the terminating NULL character. The lang field SHOULD be a URI of the form -<http://lexvo.org/id/term/LANG> where LANG is an ISO 693-2 or ISO 693-3 language code.

+<http://lexvo.org/id/iso639-3/LANG> where LANG is an ISO 693-3 language code.

A Literal may have a datatype OR a lang, but never both.

@@ -190,7 +189,7 @@ void set_to_hello_in_english(LV2_Atom_Literal* lit) { lit->atom.type = map(expand("atom:Literal")); lit->atom.size = 14; lit->datatype = 0; - lit->lang = map("http://lexvo.org/id/term/en"); + lit->lang = map("http://lexvo.org/id/iso639-3/eng"); memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit), "Hello", sizeof("Hello")); // Assumes enough space @@ -265,7 +264,7 @@ struct VectorOf42Floats { uint32_t size; // sizeof(LV2_Atom_Vector) + (42 * sizeof(float); uint32_t elem_count; // 42 uint32_t elem_type; // map(expand("atom:Float")) - float elems[32]; + float elems[42]; }; @@ -347,14 +346,31 @@ atom:TimeUnit rdfs:label "Time Unit" ; lv2:documentation "

A unit for atom:Event time stamps.

" . -atom:AudioFrames +atom:frameTime + a rdfs:Property ; + rdfs:range xsd:decimal ; + rdfs:label "Frame time" ; + lv2:documentation """ +

Time stamp in audio frames. Typically used for events.

+""" . + +atom:beatTime + a rdfs:Property ; + rdfs:range xsd:decimal ; + rdfs:label "Beat time" ; + lv2:documentation """ +

Time stamp in beats. Typically used for events.

+""" . + +atom:Frames a rdfs:Class ; rdfs:subClassOf atom:TimeUnit ; - rdfs:label "Audio frames" ; + rdfs:label "Frames" ; lv2:documentation """

Time in audio frames. Converting this to absolute time depends on the -sample rate. When this is the stamp unit for an atom:Sequence, the events in -that sequence have LV2_Atom_Audio_Time stamps (event.time.audio)

""" . +sample rate. When this is the stamp unit for an atom:Sequence, its events have +int64_t time stamps (event.time.frames)

+""" . atom:Beats a rdfs:Class ; diff --git a/lv2/lv2plug.in/ns/ext/atom/forge.h b/lv2/lv2plug.in/ns/ext/atom/forge.h index 9c553d2..5ad6d1d 100644 --- a/lv2/lv2plug.in/ns/ext/atom/forge.h +++ b/lv2/lv2plug.in/ns/ext/atom/forge.h @@ -185,10 +185,13 @@ lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) forge->Vector = map->map(map->handle, LV2_ATOM_URI "#Vector"); } +/** + 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 void* -lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge, - const void* data, - uint32_t size) +lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size) { uint8_t* out = NULL; if (forge->sink) { @@ -209,27 +212,34 @@ lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge, 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) +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_write_nopad(forge, &pad, pad_size); + lv2_atom_forge_raw(forge, &pad, pad_size); } +/** Write raw output, padding to 64-bits as necessary. */ static inline void* -lv2_atom_forge_write(LV2_Atom_Forge* forge, - const void* data, - uint32_t size) +lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size) { - void* out = lv2_atom_forge_write_nopad(forge, data, size); + void* out = lv2_atom_forge_raw(forge, data, size); if (out) { lv2_atom_forge_pad(forge, size); } return out; } +/** Write an atom:Atom header. */ +static inline LV2_Atom* +lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t type, uint32_t size) +{ + const LV2_Atom a = { type, size }; + return (LV2_Atom*)lv2_atom_forge_raw(forge, &a, sizeof(a)); +} + /** Write an atom:Int32. */ static inline LV2_Atom_Int32* lv2_atom_forge_int32(LV2_Atom_Forge* forge, int32_t val) @@ -283,25 +293,26 @@ lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id) static inline uint8_t* lv2_atom_forge_string_body(LV2_Atom_Forge* forge, const uint8_t* str, - size_t len) + uint32_t len) { uint8_t* out = NULL; - if ((out = lv2_atom_forge_write_nopad(forge, str, len)) - && (out = lv2_atom_forge_write_nopad(forge, "", 1))) { + if ( (out = lv2_atom_forge_raw(forge, str, len)) + && (out = lv2_atom_forge_raw(forge, "", 1))) { lv2_atom_forge_pad(forge, len + 1); } return out; } -/** Write an atom:String. Note that @p str need not be NULL terminated. */ +/** Write an atom compatible with atom:String. Used internally. */ static inline LV2_Atom_String* -lv2_atom_forge_string(LV2_Atom_Forge* forge, - const uint8_t* str, - size_t len) +lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, + uint32_t type, + const uint8_t* str, + uint32_t len) { - const LV2_Atom_String a = { { forge->String, len + 1 } }; + const LV2_Atom_String a = { { type, len + 1 } }; LV2_Atom_String* out = (LV2_Atom_String*) - lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); + lv2_atom_forge_raw(forge, &a, sizeof(a)); if (out) { if (!lv2_atom_forge_string_body(forge, str, len)) { out->atom.type = 0; @@ -312,64 +323,47 @@ lv2_atom_forge_string(LV2_Atom_Forge* forge, return out; } +/** 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, const uint8_t* str, uint32_t len) +{ + return lv2_atom_forge_typed_string(forge, forge->String, str, len); +} + /** Write an atom:URI. Note that @p 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_String* -lv2_atom_forge_uri(LV2_Atom_Forge* forge, - const uint8_t* uri, - size_t len) +lv2_atom_forge_uri(LV2_Atom_Forge* forge, const uint8_t* uri, uint32_t len) { - const LV2_Atom_String a = { { forge->URI, len + 1 } }; - LV2_Atom_String* out = (LV2_Atom_String*) - lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); - if (out) { - if (!lv2_atom_forge_string_body(forge, uri, len)) { - out->atom.type = 0; - out->atom.size = 0; - out = NULL; - } - } - return out; + return lv2_atom_forge_typed_string(forge, forge->URI, uri, len); } /** Write an atom:Path. Note that @p path need not be NULL terminated. */ static inline LV2_Atom_String* -lv2_atom_forge_path(LV2_Atom_Forge* forge, - const uint8_t* path, - size_t len) +lv2_atom_forge_path(LV2_Atom_Forge* forge, const uint8_t* path, uint32_t len) { - const LV2_Atom_String a = { { forge->Path, len + 1 } }; - LV2_Atom_String* out = (LV2_Atom_String*) - lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); - if (out) { - if (!lv2_atom_forge_string_body(forge, path, len)) { - out->atom.type = 0; - out->atom.size = 0; - out = NULL; - } - } - return out; + return lv2_atom_forge_typed_string(forge, forge->Path, path, len); } /** Write an atom:Literal. */ static inline LV2_Atom_Literal* lv2_atom_forge_literal(LV2_Atom_Forge* forge, const uint8_t* str, - size_t len, + uint32_t len, uint32_t datatype, uint32_t lang) { const LV2_Atom_Literal a = { { forge->Literal, sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1 }, - datatype, - lang + { datatype, + lang } }; LV2_Atom_Literal* out = (LV2_Atom_Literal*) - lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); + lv2_atom_forge_raw(forge, &a, sizeof(a)); if (out) { if (!lv2_atom_forge_string_body(forge, str, len)) { out->atom.type = 0; @@ -387,11 +381,10 @@ lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, uint32_t elem_type, uint32_t elem_size) { - const size_t size = sizeof(LV2_Atom_Vector) + (elem_size * elem_count); + const uint32_t size = sizeof(LV2_Atom_Vector) + (elem_size * elem_count); const LV2_Atom_Vector a = { { forge->Vector, size - sizeof(LV2_Atom) }, - elem_count, - elem_type + { elem_count, elem_type } }; return (LV2_Atom_Vector*)lv2_atom_forge_write(forge, &a, sizeof(a)); } @@ -469,8 +462,7 @@ lv2_atom_forge_resource(LV2_Atom_Forge* forge, { const LV2_Atom_Object a = { { forge->Resource, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) }, - id, - otype + { id, otype } }; LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); return (LV2_Atom_Object*)lv2_atom_forge_push(forge, frame, atom); @@ -487,8 +479,7 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge, { const LV2_Atom_Object a = { { forge->Blank, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) }, - id, - otype + { id, otype } }; LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); return (LV2_Atom_Object*)lv2_atom_forge_push(forge, frame, atom); @@ -520,8 +511,7 @@ lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, { const LV2_Atom_Sequence a = { { forge->Sequence, sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom) }, - unit, - 0 + { unit, 0 } }; LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); return (LV2_Atom_Sequence*)lv2_atom_forge_push(forge, frame, atom); @@ -532,13 +522,10 @@ lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, After this, call the appropriate forge method(s) to write the body, passing the same @p parent parameter. Note the returned LV2_Event is NOT an Atom. */ -static inline LV2_Atom_Audio_Time* -lv2_atom_forge_audio_time(LV2_Atom_Forge* forge, - uint32_t frames, - uint32_t subframes) +static inline int64_t* +lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) { - const LV2_Atom_Audio_Time a = { frames, subframes }; - return (LV2_Atom_Audio_Time*)lv2_atom_forge_write(forge, &a, sizeof(a)); + return (int64_t*)lv2_atom_forge_write(forge, &frames, sizeof(frames)); } /** @@ -547,8 +534,7 @@ lv2_atom_forge_audio_time(LV2_Atom_Forge* forge, the same @p parent parameter. Note the returned LV2_Event is NOT an Atom. */ static inline double* -lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, - double beats) +lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats) { return (double*)lv2_atom_forge_write(forge, &beats, sizeof(beats)); } diff --git a/lv2/lv2plug.in/ns/ext/atom/manifest.ttl b/lv2/lv2plug.in/ns/ext/atom/manifest.ttl index 9730981..6af1973 100644 --- a/lv2/lv2plug.in/ns/ext/atom/manifest.ttl +++ b/lv2/lv2plug.in/ns/ext/atom/manifest.ttl @@ -4,5 +4,5 @@ a lv2:Specification ; lv2:minorVersion 0 ; - lv2:microVersion 5 ; + lv2:microVersion 6 ; rdfs:seeAlso . diff --git a/lv2/lv2plug.in/ns/ext/atom/util.h b/lv2/lv2plug.in/ns/ext/atom/util.h index 9015a01..8ca3795 100644 --- a/lv2/lv2plug.in/ns/ext/atom/util.h +++ b/lv2/lv2plug.in/ns/ext/atom/util.h @@ -62,12 +62,9 @@ lv2_atom_is_null(const LV2_Atom* atom) static inline bool lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) { - return (a == b) || ( - (a->type == b->type) && - (a->size == b->size) && - !memcmp(LV2_ATOM_CONTENTS(LV2_Atom, a), - LV2_ATOM_CONTENTS(LV2_Atom, b), - a->size)); + return (a == b) || ((a->type == b->type) && + (a->size == b->size) && + !memcmp(a + 1, b + 1, a->size)); } /** @@ -78,14 +75,30 @@ lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) /** An iterator over the elements of an LV2_Atom_Sequence. */ typedef LV2_Atom_Event* LV2_Atom_Sequence_Iter; -/** Get an iterator pointing to the first element in @p tup. */ +/** Get an iterator pointing to the first element in a Sequence body. */ +static inline LV2_Atom_Sequence_Iter +lv2_sequence_body_begin(const LV2_Atom_Sequence_Body* body) +{ + return (LV2_Atom_Sequence_Iter)(body + 1); +} + +/** Get an iterator pointing to the first element in a Sequence. */ static inline LV2_Atom_Sequence_Iter lv2_sequence_begin(const LV2_Atom_Sequence* seq) { - return (LV2_Atom_Sequence_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq)); + return (LV2_Atom_Sequence_Iter)(seq + 1); } -/** Return true iff @p i has reached the end of @p tup. */ +/** Return true iff @p i has reached the end of @p body. */ +static inline bool +lv2_sequence_body_is_end(const LV2_Atom_Sequence_Body* body, + uint32_t size, + LV2_Atom_Sequence_Iter i) +{ + return (uint8_t*)i >= ((uint8_t*)body + size); +} + +/** Return true iff @p i has reached the end of @p seq. */ static inline bool lv2_sequence_is_end(const LV2_Atom_Sequence* seq, LV2_Atom_Sequence_Iter i) { @@ -126,6 +139,12 @@ lv2_sequence_iter_get(LV2_Atom_Sequence_Iter i) !lv2_sequence_is_end(sequence, (iter)); \ (iter) = lv2_sequence_iter_next(iter)) +/** A version of LV2_SEQUENCE_FOREACH for when only the body is available. */ +#define LV2_SEQUENCE_BODY_FOREACH(body, size, iter) \ + for (LV2_Atom_Sequence_Iter (iter) = lv2_sequence_body_begin(body); \ + !lv2_sequence_body_is_end(body, size, (iter)); \ + (iter) = lv2_sequence_iter_next(iter)) + /** @} @name Tuple Iterator @@ -142,11 +161,20 @@ lv2_tuple_begin(const LV2_Atom_Tuple* tup) return (LV2_Atom_Tuple_Iter)(LV2_ATOM_BODY(tup)); } +/** Return true iff @p i has reached the end of @p body. */ +static inline bool +lv2_atom_tuple_body_is_end(const void* body, + uint32_t size, + LV2_Atom_Tuple_Iter i) +{ + return (uint8_t*)i >= ((uint8_t*)body + size); +} + /** Return true iff @p i has reached the end of @p tup. */ static inline bool lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i) { - return (uint8_t*)i >= ((uint8_t*)tup + sizeof(LV2_Atom) + tup->atom.size); + return lv2_atom_tuple_body_is_end(LV2_ATOM_BODY(tup), tup->atom.size, i); } /** Return an iterator to the element following @p i. */ @@ -182,6 +210,12 @@ lv2_tuple_iter_get(LV2_Atom_Tuple_Iter i) !lv2_tuple_is_end(tuple, (iter)); \ (iter) = lv2_tuple_iter_next(iter)) +/** A version of LV2_TUPLE_FOREACH for when only the body is available. */ +#define LV2_TUPLE_BODY_FOREACH(body, size, iter) \ + for (LV2_Atom_Tuple_Iter (iter) = (LV2_Atom_Tuple_Iter)body; \ + !lv2_atom_tuple_body_is_end(body, size, (iter)); \ + (iter) = lv2_tuple_iter_next(iter)) + /** @} @name Object Iterator @@ -191,26 +225,32 @@ lv2_tuple_iter_get(LV2_Atom_Tuple_Iter i) /** An iterator over the properties of an LV2_Atom_Object. */ typedef LV2_Atom_Property_Body* LV2_Atom_Object_Iter; +static inline LV2_Atom_Object_Iter +lv2_object_body_begin(const LV2_Atom_Object_Body* body) +{ + return (LV2_Atom_Object_Iter)(body + 1); +} + /** Get an iterator pointing to the first property in @p obj. */ static inline LV2_Atom_Object_Iter lv2_object_begin(const LV2_Atom_Object* obj) { - return (LV2_Atom_Object_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Object, obj)); + return (LV2_Atom_Object_Iter)(obj + 1); } -/** Return true iff @p i has reached the end of @p obj. */ static inline bool -lv2_object_is_end(const LV2_Atom_Object* obj, LV2_Atom_Object_Iter i) +lv2_atom_object_body_is_end(const LV2_Atom_Object_Body* body, + uint32_t size, + LV2_Atom_Object_Iter i) { - return (uint8_t*)i >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->atom.size); + return (uint8_t*)i >= ((uint8_t*)body + size); } -/** Return true iff @p l points to the same property as @p r. */ +/** Return true iff @p i has reached the end of @p obj. */ static inline bool -lv2_object_iter_equals(const LV2_Atom_Object_Iter l, - const LV2_Atom_Object_Iter r) +lv2_object_is_end(const LV2_Atom_Object* obj, LV2_Atom_Object_Iter i) { - return l == r; + return (uint8_t*)i >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->atom.size); } /** Return an iterator to the property following @p i. */ @@ -248,6 +288,12 @@ lv2_object_iter_get(LV2_Atom_Object_Iter i) !lv2_object_is_end(object, (iter)); \ (iter) = lv2_object_iter_next(iter)) +/** A version of LV2_OBJECT_FOREACH for when only the body is available. */ +#define LV2_OBJECT_BODY_FOREACH(body, size, iter) \ + for (LV2_Atom_Object_Iter (iter) = lv2_object_body_begin(body); \ + !lv2_atom_object_body_is_end(body, size, (iter)); \ + (iter) = lv2_object_iter_next(iter)) + /** @} @name Object Query -- cgit v1.2.1