diff options
48 files changed, 5122 insertions, 5237 deletions
diff --git a/lv2/atom/atom-test-utils.c b/lv2/atom/atom-test-utils.c index 50e8887..b015cec 100644 --- a/lv2/atom/atom-test-utils.c +++ b/lv2/atom/atom-test-utils.c @@ -30,44 +30,44 @@ static uint32_t n_uris = 0; static char* copy_string(const char* str) { - const size_t len = strlen(str); - char* dup = (char*)malloc(len + 1); - memcpy(dup, str, len + 1); - return dup; + const size_t len = strlen(str); + char* dup = (char*)malloc(len + 1); + memcpy(dup, str, len + 1); + return dup; } static LV2_URID urid_map(LV2_URID_Map_Handle handle, const char* uri) { - for (uint32_t i = 0; i < n_uris; ++i) { - if (!strcmp(uris[i], uri)) { - return i + 1; - } - } + for (uint32_t i = 0; i < n_uris; ++i) { + if (!strcmp(uris[i], uri)) { + return i + 1; + } + } - uris = (char**)realloc(uris, ++n_uris * sizeof(char*)); - uris[n_uris - 1] = copy_string(uri); - return n_uris; + uris = (char**)realloc(uris, ++n_uris * sizeof(char*)); + uris[n_uris - 1] = copy_string(uri); + return n_uris; } static void free_urid_map(void) { - for (uint32_t i = 0; i < n_uris; ++i) { - free(uris[i]); - } + for (uint32_t i = 0; i < n_uris; ++i) { + free(uris[i]); + } - free(uris); + free(uris); } LV2_LOG_FUNC(1, 2) static int test_fail(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, args); - va_end(args); - return 1; + va_list args; + va_start(args, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, args); + va_end(args); + return 1; } diff --git a/lv2/atom/atom-test.c b/lv2/atom/atom-test.c index 24f176e..39095a3 100644 --- a/lv2/atom/atom-test.c +++ b/lv2/atom/atom-test.c @@ -29,341 +29,339 @@ int main(void) { - LV2_URID_Map map = { NULL, urid_map }; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object"); - LV2_URID eg_one = urid_map(NULL, "http://example.org/one"); - LV2_URID eg_two = urid_map(NULL, "http://example.org/two"); - LV2_URID eg_three = urid_map(NULL, "http://example.org/three"); - LV2_URID eg_four = urid_map(NULL, "http://example.org/four"); - LV2_URID eg_true = urid_map(NULL, "http://example.org/true"); - LV2_URID eg_false = urid_map(NULL, "http://example.org/false"); - LV2_URID eg_path = urid_map(NULL, "http://example.org/path"); - LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri"); - LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid"); - LV2_URID eg_string = urid_map(NULL, "http://example.org/string"); - LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal"); - LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple"); - LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector"); - LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2"); - LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq"); - -#define BUF_SIZE 1024 + LV2_URID_Map map = {NULL, urid_map}; + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + + LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object"); + LV2_URID eg_one = urid_map(NULL, "http://example.org/one"); + LV2_URID eg_two = urid_map(NULL, "http://example.org/two"); + LV2_URID eg_three = urid_map(NULL, "http://example.org/three"); + LV2_URID eg_four = urid_map(NULL, "http://example.org/four"); + LV2_URID eg_true = urid_map(NULL, "http://example.org/true"); + LV2_URID eg_false = urid_map(NULL, "http://example.org/false"); + LV2_URID eg_path = urid_map(NULL, "http://example.org/path"); + LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri"); + LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid"); + LV2_URID eg_string = urid_map(NULL, "http://example.org/string"); + LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal"); + LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple"); + LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector"); + LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2"); + LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq"); + +#define BUF_SIZE 1024 #define NUM_PROPS 15 - 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_forge_deref( - &forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object)); - - // eg_one = (Int)1 - lv2_atom_forge_key(&forge, eg_one); - LV2_Atom_Int* one = (LV2_Atom_Int*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_int(&forge, 1)); - if (one->body != 1) { - return test_fail("%d != 1\n", one->body); - } - - // eg_two = (Long)2 - lv2_atom_forge_key(&forge, eg_two); - LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_long(&forge, 2)); - if (two->body != 2) { - return test_fail("%" PRId64 " != 2\n", two->body); - } - - // eg_three = (Float)3.0 - lv2_atom_forge_key(&forge, eg_three); - LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_float(&forge, 3.0f)); - if (three->body != 3) { - return test_fail("%f != 3\n", three->body); - } - - // eg_four = (Double)4.0 - lv2_atom_forge_key(&forge, eg_four); - LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_double(&forge, 4.0)); - if (four->body != 4) { - return test_fail("%f != 4\n", four->body); - } - - // eg_true = (Bool)1 - lv2_atom_forge_key(&forge, eg_true); - LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, true)); - if (t->body != 1) { - return test_fail("%d != 1 (true)\n", t->body); - } - - // eg_false = (Bool)0 - lv2_atom_forge_key(&forge, eg_false); - LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, false)); - if (f->body != 0) { - return test_fail("%d != 0 (false)\n", f->body); - } - - // eg_path = (Path)"/foo/bar" - const char* pstr = "/foo/bar"; - const uint32_t pstr_len = (uint32_t)strlen(pstr); - lv2_atom_forge_key(&forge, eg_path); - LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_uri(&forge, pstr, pstr_len)); - char* pbody = (char*)LV2_ATOM_BODY(path); - if (strcmp(pbody, pstr)) { - return test_fail("%s != \"%s\"\n", pbody, pstr); - } - - // eg_uri = (URI)"http://example.org/value" - const char* ustr = "http://example.org/value"; - const uint32_t ustr_len = (uint32_t)strlen(ustr); - lv2_atom_forge_key(&forge, eg_uri); - LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_uri(&forge, ustr, ustr_len)); - char* ubody = (char*)LV2_ATOM_BODY(uri); - if (strcmp(ubody, ustr)) { - return test_fail("%s != \"%s\"\n", ubody, ustr); - } - - // eg_urid = (URID)"http://example.org/value" - LV2_URID eg_value = urid_map(NULL, "http://example.org/value"); - lv2_atom_forge_key(&forge, eg_urid); - LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_urid(&forge, eg_value)); - if (urid->body != eg_value) { - return test_fail("%u != %u\n", urid->body, eg_value); - } - - // eg_string = (String)"hello" - lv2_atom_forge_key(&forge, eg_string); - LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_string( - &forge, "hello", strlen("hello"))); - char* sbody = (char*)LV2_ATOM_BODY(string); - if (strcmp(sbody, "hello")) { - return test_fail("%s != \"hello\"\n", sbody); - } - - // eg_literal = (Literal)"hello"@fr - lv2_atom_forge_key(&forge, eg_literal); - LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_literal( - &forge, "bonjour", strlen("bonjour"), - 0, urid_map(NULL, "http://lexvo.org/id/term/fr"))); - char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal); - if (strcmp(lbody, "bonjour")) { - return test_fail("%s != \"bonjour\"\n", lbody); - } - - // eg_tuple = "foo",true - lv2_atom_forge_key(&forge, eg_tuple); - LV2_Atom_Forge_Frame tuple_frame; - LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_tuple(&forge, &tuple_frame)); - LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_string( - &forge, "foo", strlen("foo"))); - LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, true)); - lv2_atom_forge_pop(&forge, &tuple_frame); - LV2_Atom* i = lv2_atom_tuple_begin(tuple); - if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Tuple iterator is empty\n"); - } - LV2_Atom* tup0i = i; - if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) { - return test_fail("Corrupt tuple element 0\n"); - } - i = lv2_atom_tuple_next(i); - if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Premature end of tuple iterator\n"); - } - LV2_Atom* tup1i = i; - if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) { - return test_fail("Corrupt tuple element 1\n"); - } - i = lv2_atom_tuple_next(i); - if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Tuple iter is not at end\n"); - } - - // eg_vector = (Vector<Int>)1,2,3,4 - lv2_atom_forge_key(&forge, eg_vector); - int32_t elems[] = { 1, 2, 3, 4 }; - LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_vector( - &forge, sizeof(int32_t), forge.Int, 4, 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_vector2 = (Vector<Int>)1,2,3,4 - lv2_atom_forge_key(&forge, eg_vector2); - LV2_Atom_Forge_Frame vec_frame; - LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_vector_head( - &forge, &vec_frame, sizeof(int32_t), forge.Int)); - for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) { - lv2_atom_forge_int(&forge, elems[e]); - } - lv2_atom_forge_pop(&forge, &vec_frame); - if (!lv2_atom_equals(&vector->atom, &vector2->atom)) { - return test_fail("Vector != Vector2\n"); - } - - // eg_seq = (Sequence)1, 2 - lv2_atom_forge_key(&forge, eg_seq); - LV2_Atom_Forge_Frame seq_frame; - LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0)); - lv2_atom_forge_frame_time(&forge, 0); - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_frame_time(&forge, 1); - lv2_atom_forge_int(&forge, 2); - lv2_atom_forge_pop(&forge, &seq_frame); - - lv2_atom_forge_pop(&forge, &obj_frame); - - // Test equality - LV2_Atom_Int itwo = { { forge.Int, sizeof(int32_t) }, 2 }; - if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) { - 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_ATOM_SEQUENCE_FOREACH(seq, ev) { - if (ev->time.frames != n_events) { - return test_fail("Corrupt event %u has bad time\n", n_events); - } else if (ev->body.type != forge.Int) { - return test_fail("Corrupt event %u has bad type\n", n_events); - } else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) { - return test_fail("Event %u != %u\n", n_events, n_events + 1); - } - ++n_events; - } - - int n_props = 0; - LV2_ATOM_OBJECT_FOREACH((LV2_Atom_Object*)obj, prop) { - if (!prop->key) { - return test_fail("Corrupt property %d has no key\n", n_props); - } else if (prop->context) { - return test_fail("Corrupt property %d has context\n", n_props); - } - ++n_props; - } - - if (n_props != NUM_PROPS) { - return test_fail("Corrupt object has %d properties != %d\n", - n_props, NUM_PROPS); - } - - struct { - const LV2_Atom* one; - const LV2_Atom* two; - const LV2_Atom* three; - const LV2_Atom* four; - const LV2_Atom* affirmative; - const LV2_Atom* negative; - const LV2_Atom* path; - const LV2_Atom* uri; - const LV2_Atom* urid; - const LV2_Atom* string; - const LV2_Atom* literal; - const LV2_Atom* tuple; - const LV2_Atom* vector; - const LV2_Atom* vector2; - const LV2_Atom* seq; - } matches; - - memset(&matches, 0, sizeof(matches)); - - LV2_Atom_Object_Query q[] = { - { eg_one, &matches.one }, - { eg_two, &matches.two }, - { eg_three, &matches.three }, - { eg_four, &matches.four }, - { eg_true, &matches.affirmative }, - { eg_false, &matches.negative }, - { eg_path, &matches.path }, - { eg_uri, &matches.uri }, - { eg_urid, &matches.urid }, - { eg_string, &matches.string }, - { eg_literal, &matches.literal }, - { eg_tuple, &matches.tuple }, - { eg_vector, &matches.vector }, - { eg_vector2, &matches.vector2 }, - { eg_seq, &matches.seq }, - LV2_ATOM_OBJECT_QUERY_END - }; - - int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q); - for (int n = 0; n < 2; ++n) { - if (n_matches != n_props) { - return test_fail("Query failed, %d matches != %d\n", - n_matches, n_props); - } else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) { - return test_fail("Bad match one\n"); - } else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) { - return test_fail("Bad match two\n"); - } else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) { - return test_fail("Bad match three\n"); - } else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) { - return test_fail("Bad match four\n"); - } else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) { - return test_fail("Bad match true\n"); - } else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) { - return test_fail("Bad match false\n"); - } else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) { - return test_fail("Bad match path\n"); - } else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) { - return test_fail("Bad match URI\n"); - } else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) { - return test_fail("Bad match string\n"); - } else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) { - return test_fail("Bad match literal\n"); - } else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) { - return test_fail("Bad match tuple\n"); - } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) { - return test_fail("Bad match vector\n"); - } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) { - return test_fail("Bad match vector2\n"); - } else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) { - return test_fail("Bad match sequence\n"); - } - memset(&matches, 0, sizeof(matches)); - - // clang-format off - n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj, - eg_one, &matches.one, - eg_two, &matches.two, - eg_three, &matches.three, - eg_four, &matches.four, - eg_true, &matches.affirmative, - eg_false, &matches.negative, - eg_path, &matches.path, - eg_uri, &matches.uri, - eg_urid, &matches.urid, - eg_string, &matches.string, - eg_literal, &matches.literal, - eg_tuple, &matches.tuple, - eg_vector, &matches.vector, - eg_vector2, &matches.vector2, - eg_seq, &matches.seq, - 0); - // clang-format on - } - - free_urid_map(); - - return 0; + 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_forge_deref( + &forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object)); + + // eg_one = (Int)1 + lv2_atom_forge_key(&forge, eg_one); + LV2_Atom_Int* one = + (LV2_Atom_Int*)lv2_atom_forge_deref(&forge, lv2_atom_forge_int(&forge, 1)); + if (one->body != 1) { + return test_fail("%d != 1\n", one->body); + } + + // eg_two = (Long)2 + lv2_atom_forge_key(&forge, eg_two); + LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_long(&forge, 2)); + if (two->body != 2) { + return test_fail("%" PRId64 " != 2\n", two->body); + } + + // eg_three = (Float)3.0 + lv2_atom_forge_key(&forge, eg_three); + LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_float(&forge, 3.0f)); + if (three->body != 3) { + return test_fail("%f != 3\n", three->body); + } + + // eg_four = (Double)4.0 + lv2_atom_forge_key(&forge, eg_four); + LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_double(&forge, 4.0)); + if (four->body != 4) { + return test_fail("%f != 4\n", four->body); + } + + // eg_true = (Bool)1 + lv2_atom_forge_key(&forge, eg_true); + LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_bool(&forge, true)); + if (t->body != 1) { + return test_fail("%d != 1 (true)\n", t->body); + } + + // eg_false = (Bool)0 + lv2_atom_forge_key(&forge, eg_false); + LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_bool(&forge, false)); + if (f->body != 0) { + return test_fail("%d != 0 (false)\n", f->body); + } + + // eg_path = (Path)"/foo/bar" + const char* pstr = "/foo/bar"; + const uint32_t pstr_len = (uint32_t)strlen(pstr); + lv2_atom_forge_key(&forge, eg_path); + LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_uri(&forge, pstr, pstr_len)); + char* pbody = (char*)LV2_ATOM_BODY(path); + if (strcmp(pbody, pstr)) { + return test_fail("%s != \"%s\"\n", pbody, pstr); + } + + // eg_uri = (URI)"http://example.org/value" + const char* ustr = "http://example.org/value"; + const uint32_t ustr_len = (uint32_t)strlen(ustr); + lv2_atom_forge_key(&forge, eg_uri); + LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_uri(&forge, ustr, ustr_len)); + char* ubody = (char*)LV2_ATOM_BODY(uri); + if (strcmp(ubody, ustr)) { + return test_fail("%s != \"%s\"\n", ubody, ustr); + } + + // eg_urid = (URID)"http://example.org/value" + LV2_URID eg_value = urid_map(NULL, "http://example.org/value"); + lv2_atom_forge_key(&forge, eg_urid); + LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_urid(&forge, eg_value)); + if (urid->body != eg_value) { + return test_fail("%u != %u\n", urid->body, eg_value); + } + + // eg_string = (String)"hello" + lv2_atom_forge_key(&forge, eg_string); + LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_string(&forge, "hello", strlen("hello"))); + char* sbody = (char*)LV2_ATOM_BODY(string); + if (strcmp(sbody, "hello")) { + return test_fail("%s != \"hello\"\n", sbody); + } + + // eg_literal = (Literal)"hello"@fr + lv2_atom_forge_key(&forge, eg_literal); + LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref( + &forge, + lv2_atom_forge_literal(&forge, + "bonjour", + strlen("bonjour"), + 0, + urid_map(NULL, "http://lexvo.org/id/term/fr"))); + char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal); + if (strcmp(lbody, "bonjour")) { + return test_fail("%s != \"bonjour\"\n", lbody); + } + + // eg_tuple = "foo",true + lv2_atom_forge_key(&forge, eg_tuple); + LV2_Atom_Forge_Frame tuple_frame; + LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_tuple(&forge, &tuple_frame)); + LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_string(&forge, "foo", strlen("foo"))); + LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_bool(&forge, true)); + lv2_atom_forge_pop(&forge, &tuple_frame); + LV2_Atom* i = lv2_atom_tuple_begin(tuple); + if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { + return test_fail("Tuple iterator is empty\n"); + } + LV2_Atom* tup0i = i; + if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) { + return test_fail("Corrupt tuple element 0\n"); + } + i = lv2_atom_tuple_next(i); + if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { + return test_fail("Premature end of tuple iterator\n"); + } + LV2_Atom* tup1i = i; + if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) { + return test_fail("Corrupt tuple element 1\n"); + } + i = lv2_atom_tuple_next(i); + if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { + return test_fail("Tuple iter is not at end\n"); + } + + // eg_vector = (Vector<Int>)1,2,3,4 + lv2_atom_forge_key(&forge, eg_vector); + int32_t elems[] = {1, 2, 3, 4}; + LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref( + &forge, + lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 4, 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_vector2 = (Vector<Int>)1,2,3,4 + lv2_atom_forge_key(&forge, eg_vector2); + LV2_Atom_Forge_Frame vec_frame; + LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref( + &forge, + lv2_atom_forge_vector_head(&forge, &vec_frame, sizeof(int32_t), forge.Int)); + for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) { + lv2_atom_forge_int(&forge, elems[e]); + } + lv2_atom_forge_pop(&forge, &vec_frame); + if (!lv2_atom_equals(&vector->atom, &vector2->atom)) { + return test_fail("Vector != Vector2\n"); + } + + // eg_seq = (Sequence)1, 2 + lv2_atom_forge_key(&forge, eg_seq); + LV2_Atom_Forge_Frame seq_frame; + LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref( + &forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0)); + lv2_atom_forge_frame_time(&forge, 0); + lv2_atom_forge_int(&forge, 1); + lv2_atom_forge_frame_time(&forge, 1); + lv2_atom_forge_int(&forge, 2); + lv2_atom_forge_pop(&forge, &seq_frame); + + lv2_atom_forge_pop(&forge, &obj_frame); + + // Test equality + LV2_Atom_Int itwo = {{forge.Int, sizeof(int32_t)}, 2}; + if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) { + 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_ATOM_SEQUENCE_FOREACH (seq, ev) { + if (ev->time.frames != n_events) { + return test_fail("Corrupt event %u has bad time\n", n_events); + } else if (ev->body.type != forge.Int) { + return test_fail("Corrupt event %u has bad type\n", n_events); + } else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) { + return test_fail("Event %u != %u\n", n_events, n_events + 1); + } + ++n_events; + } + + int n_props = 0; + LV2_ATOM_OBJECT_FOREACH ((LV2_Atom_Object*)obj, prop) { + if (!prop->key) { + return test_fail("Corrupt property %d has no key\n", n_props); + } else if (prop->context) { + return test_fail("Corrupt property %d has context\n", n_props); + } + ++n_props; + } + + if (n_props != NUM_PROPS) { + return test_fail( + "Corrupt object has %d properties != %d\n", n_props, NUM_PROPS); + } + + struct { + const LV2_Atom* one; + const LV2_Atom* two; + const LV2_Atom* three; + const LV2_Atom* four; + const LV2_Atom* affirmative; + const LV2_Atom* negative; + const LV2_Atom* path; + const LV2_Atom* uri; + const LV2_Atom* urid; + const LV2_Atom* string; + const LV2_Atom* literal; + const LV2_Atom* tuple; + const LV2_Atom* vector; + const LV2_Atom* vector2; + const LV2_Atom* seq; + } matches; + + memset(&matches, 0, sizeof(matches)); + + LV2_Atom_Object_Query q[] = {{eg_one, &matches.one}, + {eg_two, &matches.two}, + {eg_three, &matches.three}, + {eg_four, &matches.four}, + {eg_true, &matches.affirmative}, + {eg_false, &matches.negative}, + {eg_path, &matches.path}, + {eg_uri, &matches.uri}, + {eg_urid, &matches.urid}, + {eg_string, &matches.string}, + {eg_literal, &matches.literal}, + {eg_tuple, &matches.tuple}, + {eg_vector, &matches.vector}, + {eg_vector2, &matches.vector2}, + {eg_seq, &matches.seq}, + LV2_ATOM_OBJECT_QUERY_END}; + + int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q); + for (int n = 0; n < 2; ++n) { + if (n_matches != n_props) { + return test_fail("Query failed, %d matches != %d\n", n_matches, n_props); + } else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) { + return test_fail("Bad match one\n"); + } else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) { + return test_fail("Bad match two\n"); + } else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) { + return test_fail("Bad match three\n"); + } else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) { + return test_fail("Bad match four\n"); + } else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) { + return test_fail("Bad match true\n"); + } else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) { + return test_fail("Bad match false\n"); + } else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) { + return test_fail("Bad match path\n"); + } else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) { + return test_fail("Bad match URI\n"); + } else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) { + return test_fail("Bad match string\n"); + } else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) { + return test_fail("Bad match literal\n"); + } else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) { + return test_fail("Bad match tuple\n"); + } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) { + return test_fail("Bad match vector\n"); + } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) { + return test_fail("Bad match vector2\n"); + } else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) { + return test_fail("Bad match sequence\n"); + } + memset(&matches, 0, sizeof(matches)); + + // clang-format off + n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj, + eg_one, &matches.one, + eg_two, &matches.two, + eg_three, &matches.three, + eg_four, &matches.four, + eg_true, &matches.affirmative, + eg_false, &matches.negative, + eg_path, &matches.path, + eg_uri, &matches.uri, + eg_urid, &matches.urid, + eg_string, &matches.string, + eg_literal, &matches.literal, + eg_tuple, &matches.tuple, + eg_vector, &matches.vector, + eg_vector2, &matches.vector2, + eg_seq, &matches.seq, + 0); + // clang-format on + } + + free_urid_map(); + + return 0; } diff --git a/lv2/atom/atom.h b/lv2/atom/atom.h index a82c977..1ef94cc 100644 --- a/lv2/atom/atom.h +++ b/lv2/atom/atom.h @@ -69,7 +69,7 @@ // clang-format on -#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom +#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom #ifdef __cplusplus extern "C" { @@ -77,8 +77,8 @@ extern "C" { /** @cond */ /** This expression will fail to compile if double does not fit in 64 bits. */ -typedef char lv2_atom_assert_double_fits_in_64_bits[ - ((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; +typedef char lv2_atom_assert_double_fits_in_64_bits + [((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; /** @endcond */ /** @@ -87,14 +87,13 @@ typedef char lv2_atom_assert_double_fits_in_64_bits[ @param type The type of the atom, for example LV2_Atom_String. @param atom A variable-sized atom. */ -#define LV2_ATOM_CONTENTS(type, atom) \ - ((void*)((uint8_t*)(atom) + sizeof(type))) +#define LV2_ATOM_CONTENTS(type, atom) ((void*)((uint8_t*)(atom) + sizeof(type))) /** Const version of LV2_ATOM_CONTENTS. */ #define LV2_ATOM_CONTENTS_CONST(type, atom) \ - ((const void*)((const uint8_t*)(atom) + sizeof(type))) + ((const void*)((const uint8_t*)(atom) + sizeof(type))) /** Return a pointer to the body of an Atom. The "body" of an atom is the @@ -109,32 +108,32 @@ typedef char lv2_atom_assert_double_fits_in_64_bits[ /** The header of an atom:Atom. */ typedef struct { - uint32_t size; /**< Size in bytes, not including type and size. */ - uint32_t type; /**< Type of this atom (mapped URI). */ + uint32_t size; /**< Size in bytes, not including type and size. */ + uint32_t type; /**< Type of this atom (mapped URI). */ } LV2_Atom; /** An atom:Int or atom:Bool. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - int32_t body; /**< Integer value. */ + LV2_Atom atom; /**< Atom header. */ + int32_t body; /**< Integer value. */ } LV2_Atom_Int; /** An atom:Long. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - int64_t body; /**< Integer value. */ + LV2_Atom atom; /**< Atom header. */ + int64_t body; /**< Integer value. */ } LV2_Atom_Long; /** An atom:Float. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - float body; /**< 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 body; /**< 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. */ @@ -142,84 +141,84 @@ typedef LV2_Atom_Int LV2_Atom_Bool; /** An atom:URID. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - uint32_t body; /**< URID. */ + LV2_Atom atom; /**< Atom header. */ + uint32_t body; /**< URID. */ } LV2_Atom_URID; /** 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 atom; /**< Atom header. */ + /* Contents (a null-terminated UTF-8 string) follow here. */ } LV2_Atom_String; /** The body of an atom:Literal. */ typedef struct { - uint32_t datatype; /**< Datatype URID. */ - uint32_t lang; /**< Language URID. */ - /* Contents (a null-terminated UTF-8 string) follow here. */ + 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 atom; /**< Atom header. */ + LV2_Atom_Literal_Body body; /**< Body. */ } LV2_Atom_Literal; /** 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 atom; /**< Atom header. */ + /* Contents (a series of complete atoms) follow here. */ } LV2_Atom_Tuple; /** The body of an atom:Vector. */ typedef struct { - uint32_t child_size; /**< The size of each element in the vector. */ - uint32_t child_type; /**< The type of each element in the vector. */ - /* Contents (a series of packed atom bodies) follow here. */ + uint32_t child_size; /**< The size of each element in the vector. */ + uint32_t child_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 atom; /**< Atom header. */ + LV2_Atom_Vector_Body body; /**< Body. */ } LV2_Atom_Vector; /** The body of an atom:Property (typically 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. */ + 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; /** An atom:Property. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Property_Body body; /**< Body. */ + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Property_Body body; /**< Body. */ } LV2_Atom_Property; /** The body of an atom:Object. May be cast to LV2_Atom. */ typedef struct { - uint32_t id; /**< URID, or 0 for blank. */ - uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ - /* Contents (a series of property bodies) follow here. */ + uint32_t id; /**< URID, or 0 for blank. */ + uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ + /* Contents (a series of property bodies) follow here. */ } LV2_Atom_Object_Body; /** An atom:Object. May be cast to LV2_Atom. */ typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Object_Body body; /**< Body. */ + 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 { - 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. */ + /** Time stamp. Which type is valid is determined by context. */ + union { + 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; /** @@ -239,23 +238,23 @@ typedef struct { </pre> */ typedef struct { - uint32_t unit; /**< URID of unit of event time stamps. */ - uint32_t pad; /**< Currently unused. */ - /* Contents (a series of events) follow here. */ + 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_Sequence_Body body; /**< Body. */ + LV2_Atom atom; /**< Atom header. */ + LV2_Atom_Sequence_Body body; /**< Body. */ } LV2_Atom_Sequence; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_ATOM_H */ +#endif /* LV2_ATOM_H */ diff --git a/lv2/atom/forge-overflow-test.c b/lv2/atom/forge-overflow-test.c index ed5845a..8e5ede6 100644 --- a/lv2/atom/forge-overflow-test.c +++ b/lv2/atom/forge-overflow-test.c @@ -28,210 +28,208 @@ test_string_overflow(void) { #define MAX_CHARS 15 - static const size_t capacity = sizeof(LV2_Atom_String) + MAX_CHARS + 1; - static const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_URID_Map map = { NULL, urid_map }; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - // Check that writing increasingly long strings fails at the right point - for (size_t count = 0; count < MAX_CHARS; ++count) { - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - const LV2_Atom_Forge_Ref ref = - lv2_atom_forge_string(&forge, str, count); - if (!ref) { - return test_fail("Failed to write %zu byte string\n", count); - } - } - - // Failure writing to an exactly full forge - if (lv2_atom_forge_string(&forge, str, MAX_CHARS + 1)) { - return test_fail("Successfully wrote past end of buffer\n"); - } - - // Failure writing body after successfully writing header - lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); - if (lv2_atom_forge_string(&forge, "AB", 2)) { - return test_fail("Successfully wrote atom header past end\n"); - } - - free(buf); - return 0; + static const size_t capacity = sizeof(LV2_Atom_String) + MAX_CHARS + 1; + static const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + uint8_t* buf = (uint8_t*)malloc(capacity); + LV2_URID_Map map = {NULL, urid_map}; + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + + // Check that writing increasingly long strings fails at the right point + for (size_t count = 0; count < MAX_CHARS; ++count) { + lv2_atom_forge_set_buffer(&forge, buf, capacity); + + const LV2_Atom_Forge_Ref ref = lv2_atom_forge_string(&forge, str, count); + if (!ref) { + return test_fail("Failed to write %zu byte string\n", count); + } + } + + // Failure writing to an exactly full forge + if (lv2_atom_forge_string(&forge, str, MAX_CHARS + 1)) { + return test_fail("Successfully wrote past end of buffer\n"); + } + + // Failure writing body after successfully writing header + lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); + if (lv2_atom_forge_string(&forge, "AB", 2)) { + return test_fail("Successfully wrote atom header past end\n"); + } + + free(buf); + return 0; } static int test_literal_overflow(void) { - static const size_t capacity = sizeof(LV2_Atom_Literal) + 2; - - uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_URID_Map map = { NULL, urid_map }; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - // Failure in atom header - lv2_atom_forge_set_buffer(&forge, buf, 1); - if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Successfully wrote atom header past end\n"); - } - - // Failure in literal header - lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); - if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Successfully wrote literal header past end\n"); - } - - // Success (only room for one character + null terminator) - lv2_atom_forge_set_buffer(&forge, buf, capacity); - if (!lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Failed to write small enough literal\n"); - } - - // Failure in body - lv2_atom_forge_set_buffer(&forge, buf, capacity); - if (lv2_atom_forge_literal(&forge, "AB", 2, 0, 0)) { - return test_fail("Successfully wrote literal body past end\n"); - } - - free(buf); - return 0; + static const size_t capacity = sizeof(LV2_Atom_Literal) + 2; + + uint8_t* buf = (uint8_t*)malloc(capacity); + LV2_URID_Map map = {NULL, urid_map}; + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + + // Failure in atom header + lv2_atom_forge_set_buffer(&forge, buf, 1); + if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { + return test_fail("Successfully wrote atom header past end\n"); + } + + // Failure in literal header + lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); + if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { + return test_fail("Successfully wrote literal header past end\n"); + } + + // Success (only room for one character + null terminator) + lv2_atom_forge_set_buffer(&forge, buf, capacity); + if (!lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { + return test_fail("Failed to write small enough literal\n"); + } + + // Failure in body + lv2_atom_forge_set_buffer(&forge, buf, capacity); + if (lv2_atom_forge_literal(&forge, "AB", 2, 0, 0)) { + return test_fail("Successfully wrote literal body past end\n"); + } + + free(buf); + return 0; } static int test_sequence_overflow(void) { - static const size_t size = sizeof(LV2_Atom_Sequence) + 6 * sizeof(LV2_Atom); - LV2_URID_Map map = { NULL, urid_map }; + static const size_t size = sizeof(LV2_Atom_Sequence) + 6 * sizeof(LV2_Atom); + LV2_URID_Map map = {NULL, urid_map}; - // Test over a range that fails in the sequence header and event components - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); + // Test over a range that fails in the sequence header and event components + for (size_t capacity = 1; capacity < size; ++capacity) { + uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + lv2_atom_forge_set_buffer(&forge, buf, capacity); - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = - lv2_atom_forge_sequence_head(&forge, &frame, 0); + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(&forge, &frame, 0); - assert(capacity >= sizeof(LV2_Atom_Sequence) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Sequence) || !ref); - (void)ref; + assert(capacity >= sizeof(LV2_Atom_Sequence) || !frame.ref); + assert(capacity >= sizeof(LV2_Atom_Sequence) || !ref); + (void)ref; - lv2_atom_forge_frame_time(&forge, 0); - lv2_atom_forge_int(&forge, 42); - lv2_atom_forge_pop(&forge, &frame); + lv2_atom_forge_frame_time(&forge, 0); + lv2_atom_forge_int(&forge, 42); + lv2_atom_forge_pop(&forge, &frame); - free(buf); - } + free(buf); + } - return 0; + return 0; } static int test_vector_head_overflow(void) { - static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); - LV2_URID_Map map = { NULL, urid_map }; + static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); + LV2_URID_Map map = {NULL, urid_map}; - // Test over a range that fails in the vector header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); + // Test over a range that fails in the vector header and elements + for (size_t capacity = 1; capacity < size; ++capacity) { + uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + lv2_atom_forge_set_buffer(&forge, buf, capacity); - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector_head( - &forge, &frame, sizeof(int32_t), forge.Int); + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref ref = + lv2_atom_forge_vector_head(&forge, &frame, sizeof(int32_t), forge.Int); - assert(capacity >= sizeof(LV2_Atom_Vector) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); - (void)ref; + assert(capacity >= sizeof(LV2_Atom_Vector) || !frame.ref); + assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); + (void)ref; - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_int(&forge, 2); - lv2_atom_forge_int(&forge, 3); - lv2_atom_forge_pop(&forge, &frame); + lv2_atom_forge_int(&forge, 1); + lv2_atom_forge_int(&forge, 2); + lv2_atom_forge_int(&forge, 3); + lv2_atom_forge_pop(&forge, &frame); - free(buf); - } + free(buf); + } - return 0; + return 0; } static int test_vector_overflow(void) { - static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); - static const int32_t vec[] = { 1, 2, 3 }; - LV2_URID_Map map = { NULL, urid_map }; + static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); + static const int32_t vec[] = {1, 2, 3}; + LV2_URID_Map map = {NULL, urid_map}; - // Test over a range that fails in the vector header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); + // Test over a range that fails in the vector header and elements + for (size_t capacity = 1; capacity < size; ++capacity) { + uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + lv2_atom_forge_set_buffer(&forge, buf, capacity); - LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector( - &forge, sizeof(int32_t), forge.Int, 3, vec); + LV2_Atom_Forge_Ref ref = + lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 3, vec); - assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); - (void)ref; + assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); + (void)ref; - free(buf); - } + free(buf); + } - return 0; + return 0; } static int test_tuple_overflow(void) { - static const size_t size = sizeof(LV2_Atom_Tuple) + 3 * sizeof(LV2_Atom); - LV2_URID_Map map = { NULL, urid_map }; + static const size_t size = sizeof(LV2_Atom_Tuple) + 3 * sizeof(LV2_Atom); + LV2_URID_Map map = {NULL, urid_map}; - // Test over a range that fails in the tuple header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); + // Test over a range that fails in the tuple header and elements + for (size_t capacity = 1; capacity < size; ++capacity) { + uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); + LV2_Atom_Forge forge; + lv2_atom_forge_init(&forge, &map); + lv2_atom_forge_set_buffer(&forge, buf, capacity); - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = lv2_atom_forge_tuple(&forge, &frame); + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref ref = lv2_atom_forge_tuple(&forge, &frame); - assert(capacity >= sizeof(LV2_Atom_Tuple) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Tuple) || !ref); - (void)ref; + assert(capacity >= sizeof(LV2_Atom_Tuple) || !frame.ref); + assert(capacity >= sizeof(LV2_Atom_Tuple) || !ref); + (void)ref; - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_float(&forge, 2.0f); - lv2_atom_forge_string(&forge, "three", 5); - lv2_atom_forge_pop(&forge, &frame); + lv2_atom_forge_int(&forge, 1); + lv2_atom_forge_float(&forge, 2.0f); + lv2_atom_forge_string(&forge, "three", 5); + lv2_atom_forge_pop(&forge, &frame); - free(buf); - } + free(buf); + } - return 0; + return 0; } int main(void) { - const int ret = test_string_overflow() || test_literal_overflow() || - test_sequence_overflow() || test_vector_head_overflow() || - test_vector_overflow() || test_tuple_overflow(); + const int ret = test_string_overflow() || test_literal_overflow() || + test_sequence_overflow() || test_vector_head_overflow() || + test_vector_overflow() || test_tuple_overflow(); - free_urid_map(); + free_urid_map(); - return ret; + return ret; } diff --git a/lv2/atom/forge.h b/lv2/atom/forge.h index 0920e0a..42471f5 100644 --- a/lv2/atom/forge.h +++ b/lv2/atom/forge.h @@ -75,52 +75,52 @@ typedef void* LV2_Atom_Forge_Sink_Handle; 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); +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); +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; + 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_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_DEPRECATED; - LV2_URID Sequence; - LV2_URID String; - LV2_URID Tuple; - LV2_URID URI; - LV2_URID URID; - LV2_URID Vector; + 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_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_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 @@ -135,32 +135,32 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size); static inline void lv2_atom_forge_init(LV2_Atom_Forge* forge, 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); + 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) { - return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref); + return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref); } /** @@ -179,43 +179,42 @@ 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; + frame->parent = forge->stack; + frame->ref = ref; - if (ref) { - forge->stack = frame; // Don't push, so walking the stack is always safe - } + if (ref) { + forge->stack = frame; // Don't push, so walking the stack is always safe + } - return ref; + 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) { - if (frame->ref) { - // If frame has a valid ref, it must be the top of the stack - assert(frame == forge->stack); - forge->stack = frame->parent; - } - // Otherwise, frame was not pushed because of overflow, do nothing + if (frame->ref) { + // If frame has a valid ref, it must be the top of the stack + assert(frame == forge->stack); + forge->stack = frame->parent; + } + // Otherwise, frame was not pushed because of overflow, do nothing } /** 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 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 (type == forge->Object || type == forge->Blank || + type == forge->Resource); } /** Return true iff `type` is an atom:Object with a blank ID. */ @@ -224,8 +223,7 @@ 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)); + return (type == forge->Blank || (type == forge->Object && body->id == 0)); } /** @@ -238,13 +236,13 @@ lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge, 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; + forge->buf = buf; + forge->size = (uint32_t)size; + forge->offset = 0; + forge->deref = NULL; + forge->sink = NULL; + forge->handle = NULL; + forge->stack = NULL; } /** @@ -267,12 +265,12 @@ lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, 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; + forge->buf = NULL; + forge->size = forge->offset = 0; + forge->deref = deref; + forge->sink = sink; + forge->handle = handle; + forge->stack = NULL; } /** @@ -289,55 +287,53 @@ lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, 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 + 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; + LV2_Atom_Forge_Ref out = 0; + if (forge->sink) { + out = forge->sink(forge->handle, data, size); + } else { + out = (LV2_Atom_Forge_Ref)forge->buf + 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); + 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; + 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_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; + 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; } /** @@ -350,66 +346,66 @@ lv2_atom_forge_string_body(LV2_Atom_Forge* forge, 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)); + 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) { - return (lv2_atom_forge_top_is(forge, forge->Vector) - ? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size) - : lv2_atom_forge_write( - forge, a, (uint32_t)sizeof(LV2_Atom) + a->size)); + return ( + lv2_atom_forge_top_is(forge, forge->Vector) + ? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size) + : 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); + 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); + 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); + 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); + 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); + 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); + 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. */ @@ -419,23 +415,23 @@ lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, 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; + 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); + return lv2_atom_forge_typed_string(forge, forge->String, str, len); } /** @@ -446,14 +442,14 @@ lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) 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); + 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); + return lv2_atom_forge_typed_string(forge, forge->Path, path, len); } /** Write an atom:Literal. */ @@ -464,21 +460,19 @@ lv2_atom_forge_literal(LV2_Atom_Forge* forge, 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; + 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. */ @@ -488,12 +482,10 @@ lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, 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))); + 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. */ @@ -504,16 +496,15 @@ lv2_atom_forge_vector(LV2_Atom_Forge* forge, 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; + 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; } /** @@ -536,9 +527,9 @@ lv2_atom_forge_vector(LV2_Atom_Forge* forge, 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))); + const LV2_Atom_Tuple a = {{0, forge->Tuple}}; + return lv2_atom_forge_push( + forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); } /** @@ -571,12 +562,10 @@ lv2_atom_forge_object(LV2_Atom_Forge* forge, 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))); + 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))); } /** @@ -592,12 +581,10 @@ lv2_atom_forge_resource(LV2_Atom_Forge* forge, 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))); + 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))); } /** @@ -613,12 +600,10 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge, 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))); + 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))); } /** @@ -627,11 +612,10 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge, 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) +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)); + const LV2_Atom_Property_Body a = {key, 0, {0, 0}}; + return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); } /** @@ -645,8 +629,8 @@ 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)); + const LV2_Atom_Property_Body a = {key, context, {0, 0}}; + return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); } /** @@ -657,12 +641,10 @@ 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))); + 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))); } /** @@ -673,7 +655,7 @@ lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, 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)); + return lv2_atom_forge_write(forge, &frames, sizeof(frames)); } /** @@ -684,13 +666,13 @@ lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) 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)); + return lv2_atom_forge_write(forge, &beats, sizeof(beats)); } LV2_RESTORE_WARNINGS #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @@ -698,4 +680,4 @@ LV2_RESTORE_WARNINGS @} */ -#endif /* LV2_ATOM_FORGE_H */ +#endif /* LV2_ATOM_FORGE_H */ diff --git a/lv2/atom/util.h b/lv2/atom/util.h index 98c9edb..4818d96 100644 --- a/lv2/atom/util.h +++ b/lv2/atom/util.h @@ -49,30 +49,29 @@ extern "C" { static inline uint32_t lv2_atom_pad_size(uint32_t size) { - return (size + 7U) & (~7U); + return (size + 7U) & (~7U); } /** Return the total size of `atom`, including the header. */ static inline uint32_t lv2_atom_total_size(const LV2_Atom* atom) { - return (uint32_t)sizeof(LV2_Atom) + atom->size; + return (uint32_t)sizeof(LV2_Atom) + atom->size; } /** Return true iff `atom` is null. */ static inline bool lv2_atom_is_null(const LV2_Atom* atom) { - return !atom || (atom->type == 0 && atom->size == 0); + return !atom || (atom->type == 0 && atom->size == 0); } /** Return true iff `a` is equal to `b`. */ 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(a + 1, b + 1, a->size)); + return (a == b) || ((a->type == b->type) && (a->size == b->size) && + !memcmp(a + 1, b + 1, a->size)); } /** @@ -84,14 +83,14 @@ lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) static inline LV2_Atom_Event* lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) { - return (LV2_Atom_Event*)(body + 1); + return (LV2_Atom_Event*)(body + 1); } /** Get an iterator pointing to the end of a Sequence body. */ static inline LV2_Atom_Event* lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size) { - return (LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size)); + return (LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size)); } /** Return true iff `i` has reached the end of `body`. */ @@ -100,16 +99,15 @@ lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, uint32_t size, const LV2_Atom_Event* i) { - return (const uint8_t*)i >= ((const uint8_t*)body + size); + return (const uint8_t*)i >= ((const uint8_t*)body + size); } /** Return an iterator to the element following `i`. */ static inline LV2_Atom_Event* lv2_atom_sequence_next(const LV2_Atom_Event* i) { - return (LV2_Atom_Event*)((const uint8_t*)i - + sizeof(LV2_Atom_Event) - + lv2_atom_pad_size(i->body.size)); + return (LV2_Atom_Event*)((const uint8_t*)i + sizeof(LV2_Atom_Event) + + lv2_atom_pad_size(i->body.size)); } /** @@ -126,16 +124,16 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) } @endcode */ -#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ - for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ - !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) +#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ + for (LV2_Atom_Event * (iter) = lv2_atom_sequence_begin(&(seq)->body); \ + !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ + (iter) = lv2_atom_sequence_next(iter)) /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ -#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ - !lv2_atom_sequence_is_end(body, size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) +#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ + for (LV2_Atom_Event * (iter) = lv2_atom_sequence_begin(body); \ + !lv2_atom_sequence_is_end(body, size, (iter)); \ + (iter) = lv2_atom_sequence_next(iter)) /** @} @@ -151,7 +149,7 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) static inline void lv2_atom_sequence_clear(LV2_Atom_Sequence* seq) { - seq->atom.size = sizeof(LV2_Atom_Sequence_Body); + seq->atom.size = sizeof(LV2_Atom_Sequence_Body); } /** @@ -170,17 +168,17 @@ lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, uint32_t capacity, const LV2_Atom_Event* event) { - const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size; - if (capacity - seq->atom.size < total_size) { - return NULL; - } + const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size; + if (capacity - seq->atom.size < total_size) { + return NULL; + } - LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); - memcpy(e, event, total_size); + LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); + memcpy(e, event, total_size); - seq->atom.size += lv2_atom_pad_size(total_size); + seq->atom.size += lv2_atom_pad_size(total_size); - return e; + return e; } /** @@ -193,22 +191,22 @@ lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, static inline LV2_Atom* lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup) { - return (LV2_Atom*)(LV2_ATOM_BODY(tup)); + return (LV2_Atom*)(LV2_ATOM_BODY(tup)); } /** Return true iff `i` has reached the end of `body`. */ static inline bool lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i) { - return (const uint8_t*)i >= ((const uint8_t*)body + size); + return (const uint8_t*)i >= ((const uint8_t*)body + size); } /** Return an iterator to the element following `i`. */ static inline LV2_Atom* lv2_atom_tuple_next(const LV2_Atom* i) { - return (LV2_Atom*)( - (const uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size)); + return (LV2_Atom*)((const uint8_t*)i + sizeof(LV2_Atom) + + lv2_atom_pad_size(i->size)); } /** @@ -225,16 +223,17 @@ lv2_atom_tuple_next(const LV2_Atom* i) } @endcode */ -#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ - for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ - !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) +#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ + for (LV2_Atom * (iter) = lv2_atom_tuple_begin(tuple); \ + !lv2_atom_tuple_is_end( \ + LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ + (iter) = lv2_atom_tuple_next(iter)) /** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ #define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom* (iter) = (LV2_Atom*)(body); \ - !lv2_atom_tuple_is_end(body, size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) + for (LV2_Atom * (iter) = (LV2_Atom*)(body); \ + !lv2_atom_tuple_is_end(body, size, (iter)); \ + (iter) = lv2_atom_tuple_next(iter)) /** @} @@ -246,7 +245,7 @@ lv2_atom_tuple_next(const LV2_Atom* i) static inline LV2_Atom_Property_Body* lv2_atom_object_begin(const LV2_Atom_Object_Body* body) { - return (LV2_Atom_Property_Body*)(body + 1); + return (LV2_Atom_Property_Body*)(body + 1); } /** Return true iff `i` has reached the end of `obj`. */ @@ -255,18 +254,19 @@ lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, uint32_t size, const LV2_Atom_Property_Body* i) { - return (const uint8_t*)i >= ((const uint8_t*)body + size); + return (const uint8_t*)i >= ((const uint8_t*)body + size); } /** Return an iterator to the property following `i`. */ static inline LV2_Atom_Property_Body* lv2_atom_object_next(const LV2_Atom_Property_Body* i) { - const LV2_Atom* const value = (const LV2_Atom*)( - (const uint8_t*)i + 2 * sizeof(uint32_t)); - return (LV2_Atom_Property_Body*)( - (const uint8_t*)i + lv2_atom_pad_size( - (uint32_t)sizeof(LV2_Atom_Property_Body) + value->size)); + const LV2_Atom* const value = + (const LV2_Atom*)((const uint8_t*)i + 2 * sizeof(uint32_t)); + return (LV2_Atom_Property_Body*)((const uint8_t*)i + + lv2_atom_pad_size( + (uint32_t)sizeof(LV2_Atom_Property_Body) + + value->size)); } /** @@ -283,16 +283,16 @@ lv2_atom_object_next(const LV2_Atom_Property_Body* i) } @endcode */ -#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ - for (LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \ - !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) +#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ + for (LV2_Atom_Property_Body * (iter) = lv2_atom_object_begin(&(obj)->body); \ + !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ + (iter) = lv2_atom_object_next(iter)) /** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ -#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \ - !lv2_atom_object_is_end(body, size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) +#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ + for (LV2_Atom_Property_Body * (iter) = lv2_atom_object_begin(body); \ + !lv2_atom_object_is_end(body, size, (iter)); \ + (iter) = lv2_atom_object_next(iter)) /** @} @@ -302,12 +302,12 @@ lv2_atom_object_next(const LV2_Atom_Property_Body* i) /** A single entry in an Object query. */ typedef struct { - uint32_t key; /**< Key to query (input set by user) */ - const LV2_Atom** value; /**< Found value (output set by query function) */ + uint32_t key; /**< Key to query (input set by user) */ + const LV2_Atom** value; /**< Found value (output set by query function) */ } LV2_Atom_Object_Query; /** Sentinel for lv2_atom_object_query(). */ -static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL }; +static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = {0, NULL}; /** Get an object's values for various keys. @@ -338,26 +338,26 @@ static inline int lv2_atom_object_query(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query) { - int matches = 0; - int n_queries = 0; - - /* Count number of query keys so we can short-circuit when done */ - for (LV2_Atom_Object_Query* q = query; q->key; ++q) { - ++n_queries; - } - - LV2_ATOM_OBJECT_FOREACH(object, prop) { - for (LV2_Atom_Object_Query* q = query; q->key; ++q) { - if (q->key == prop->key && !*q->value) { - *q->value = &prop->value; - if (++matches == n_queries) { - return matches; - } - break; - } - } - } - return matches; + int matches = 0; + int n_queries = 0; + + /* Count number of query keys so we can short-circuit when done */ + for (LV2_Atom_Object_Query* q = query; q->key; ++q) { + ++n_queries; + } + + LV2_ATOM_OBJECT_FOREACH (object, prop) { + for (LV2_Atom_Object_Query* q = query; q->key; ++q) { + if (q->key == prop->key && !*q->value) { + *q->value = &prop->value; + if (++matches == n_queries) { + return matches; + } + break; + } + } + } + return matches; } /** @@ -366,37 +366,37 @@ lv2_atom_object_query(const LV2_Atom_Object* object, static inline int lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) { - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, body); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_BODY_FOREACH(body, size, prop) { - va_start(args, body); - for (int i = 0; i < n_queries; ++i) { - uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - if (qkey == prop->key && !*qval) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; + int matches = 0; + int n_queries = 0; + + /* Count number of keys so we can short-circuit when done */ + va_list args; + va_start(args, body); + for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { + if (!va_arg(args, const LV2_Atom**)) { + va_end(args); + return -1; + } + } + va_end(args); + + LV2_ATOM_OBJECT_BODY_FOREACH (body, size, prop) { + va_start(args, body); + for (int i = 0; i < n_queries; ++i) { + uint32_t qkey = va_arg(args, uint32_t); + const LV2_Atom** qval = va_arg(args, const LV2_Atom**); + if (qkey == prop->key && !*qval) { + *qval = &prop->value; + if (++matches == n_queries) { + va_end(args); + return matches; + } + break; + } + } + va_end(args); + } + return matches; } /** @@ -421,37 +421,37 @@ lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) static inline int lv2_atom_object_get(const LV2_Atom_Object* object, ...) { - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, object); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_FOREACH(object, prop) { - va_start(args, object); - for (int i = 0; i < n_queries; ++i) { - uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - if (qkey == prop->key && !*qval) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; + int matches = 0; + int n_queries = 0; + + /* Count number of keys so we can short-circuit when done */ + va_list args; + va_start(args, object); + for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { + if (!va_arg(args, const LV2_Atom**)) { + va_end(args); + return -1; + } + } + va_end(args); + + LV2_ATOM_OBJECT_FOREACH (object, prop) { + va_start(args, object); + for (int i = 0; i < n_queries; ++i) { + uint32_t qkey = va_arg(args, uint32_t); + const LV2_Atom** qval = va_arg(args, const LV2_Atom**); + if (qkey == prop->key && !*qval) { + *qval = &prop->value; + if (++matches == n_queries) { + va_end(args); + return matches; + } + break; + } + } + va_end(args); + } + return matches; } /** @@ -477,43 +477,42 @@ lv2_atom_object_get(const LV2_Atom_Object* object, ...) static inline int lv2_atom_object_get_typed(const LV2_Atom_Object* object, ...) { - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, object); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**) || - !va_arg(args, uint32_t)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_FOREACH(object, prop) { - va_start(args, object); - for (int i = 0; i < n_queries; ++i) { - const uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - const uint32_t qtype = va_arg(args, uint32_t); - if (!*qval && qkey == prop->key && qtype == prop->value.type) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; + int matches = 0; + int n_queries = 0; + + /* Count number of keys so we can short-circuit when done */ + va_list args; + va_start(args, object); + for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { + if (!va_arg(args, const LV2_Atom**) || !va_arg(args, uint32_t)) { + va_end(args); + return -1; + } + } + va_end(args); + + LV2_ATOM_OBJECT_FOREACH (object, prop) { + va_start(args, object); + for (int i = 0; i < n_queries; ++i) { + const uint32_t qkey = va_arg(args, uint32_t); + const LV2_Atom** qval = va_arg(args, const LV2_Atom**); + const uint32_t qtype = va_arg(args, uint32_t); + if (!*qval && qkey == prop->key && qtype == prop->value.type) { + *qval = &prop->value; + if (++matches == n_queries) { + va_end(args); + return matches; + } + break; + } + } + va_end(args); + } + return matches; } #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** diff --git a/lv2/buf-size/buf-size.h b/lv2/buf-size/buf-size.h index 98f23ab..98a812c 100644 --- a/lv2/buf-size/buf-size.h +++ b/lv2/buf-size/buf-size.h @@ -48,4 +48,4 @@ @} */ -#endif /* LV2_BUF_SIZE_H */ +#endif /* LV2_BUF_SIZE_H */ diff --git a/lv2/core/attributes.h b/lv2/core/attributes.h index 672d716..0281d97 100644 --- a/lv2/core/attributes.h +++ b/lv2/core/attributes.h @@ -27,29 +27,29 @@ */ #if defined(__GNUC__) && __GNUC__ > 3 -#define LV2_DEPRECATED __attribute__((__deprecated__)) +# define LV2_DEPRECATED __attribute__((__deprecated__)) #else -#define LV2_DEPRECATED +# define LV2_DEPRECATED #endif #if defined(__clang__) -#define LV2_DISABLE_DEPRECATION_WARNINGS \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +# define LV2_DISABLE_DEPRECATION_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #elif defined(__GNUC__) && __GNUC__ > 4 -#define LV2_DISABLE_DEPRECATION_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define LV2_DISABLE_DEPRECATION_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #else -#define LV2_DISABLE_DEPRECATION_WARNINGS +# define LV2_DISABLE_DEPRECATION_WARNINGS #endif #if defined(__clang__) -#define LV2_RESTORE_WARNINGS _Pragma("clang diagnostic pop") +# define LV2_RESTORE_WARNINGS _Pragma("clang diagnostic pop") #elif defined(__GNUC__) && __GNUC__ > 4 -#define LV2_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +# define LV2_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") #else -#define LV2_RESTORE_WARNINGS +# define LV2_RESTORE_WARNINGS #endif /** diff --git a/lv2/core/lv2.h b/lv2/core/lv2.h index c0376e9..82bc7ab 100644 --- a/lv2/core/lv2.h +++ b/lv2/core/lv2.h @@ -144,7 +144,7 @@ extern "C" { compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to interpret it. */ -typedef void * LV2_Handle; +typedef void* LV2_Handle; /** Feature. @@ -155,20 +155,20 @@ typedef void * LV2_Handle; Some features, such as lv2:isLive, do not require the host to pass data. */ typedef struct { - /** - A globally unique, case-sensitive identifier (URI) for this feature. + /** + A globally unique, case-sensitive identifier (URI) for this feature. - This MUST be a valid URI string as defined by RFC 3986. - */ - const char * URI; + This MUST be a valid URI string as defined by RFC 3986. + */ + const char* URI; - /** - Pointer to arbitrary data. + /** + Pointer to arbitrary data. - The format of this data is defined by the extension which describes the - feature with the given `URI`. - */ - void * data; + The format of this data is defined by the extension which describes the + feature with the given `URI`. + */ + void* data; } LV2_Feature; /** @@ -178,190 +178,187 @@ typedef struct { a plugin. */ typedef struct LV2_Descriptor { - /** - A globally unique, case-sensitive identifier for this plugin. - - This MUST be a valid URI string as defined by RFC 3986. All plugins with - the same URI MUST be compatible to some degree, see - http://lv2plug.in/ns/lv2core for details. - */ - const char * URI; - - /** - Instantiate the plugin. - - Note that instance initialisation should generally occur in activate() - rather than here. If a host calls instantiate(), it MUST call cleanup() - at some point in the future. - - @param descriptor Descriptor of the plugin to instantiate. - - @param sample_rate Sample rate, in Hz, for the new plugin instance. - - @param bundle_path Path to the LV2 bundle which contains this plugin - binary. It MUST include the trailing directory separator so that simply - appending a filename will yield the path to that file in the bundle. - - @param features A NULL terminated array of LV2_Feature structs which - represent the features the host supports. Plugins may refuse to - instantiate if required features are not found here. However, hosts MUST - NOT use this as a discovery mechanism: instead, use the RDF data to - determine which features are required and do not attempt to instantiate - unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host - that supports no features MUST pass a single element array containing - NULL. - - @return A handle for the new plugin instance, or NULL if instantiation - has failed. - */ - LV2_Handle (*instantiate)(const struct LV2_Descriptor * descriptor, - double sample_rate, - const char * bundle_path, - const LV2_Feature *const * features); - - /** - Connect a port on a plugin instance to a memory location. - - Plugin writers should be aware that the host may elect to use the same - buffer for more than one port and even use the same buffer for both - input and output (see lv2:inPlaceBroken in lv2.ttl). - - If the plugin has the feature lv2:hardRTCapable then there are various - things that the plugin MUST NOT do within the connect_port() function; - see lv2core.ttl for details. - - connect_port() MUST be called at least once for each port before run() - is called, unless that port is lv2:connectionOptional. The plugin must - pay careful attention to the block size passed to run() since the block - allocated may only just be large enough to contain the data, and is not - guaranteed to remain constant between run() calls. - - connect_port() may be called more than once for a plugin instance to - allow the host to change the buffers that the plugin is reading or - writing. These calls may be made before or after activate() or - deactivate() calls. - - @param instance Plugin instance containing the port. - - @param port Index of the port to connect. The host MUST NOT try to - connect a port index that is not defined in the plugin's RDF data. If - it does, the plugin's behaviour is undefined (a crash is likely). - - @param data_location Pointer to data of the type defined by the port - type in the plugin's RDF data (for example, an array of float for an - lv2:AudioPort). This pointer must be stored by the plugin instance and - used to read/write data when run() is called. Data present at the time - of the connect_port() call MUST NOT be considered meaningful. - */ - void (*connect_port)(LV2_Handle instance, - uint32_t port, - void * data_location); - - /** - Initialise a plugin instance and activate it for use. - - This is separated from instantiate() to aid real-time support and so - that hosts can reinitialise a plugin instance by calling deactivate() - and then activate(). In this case the plugin instance MUST reset all - state information dependent on the history of the plugin instance except - for any data locations provided by connect_port(). If there is nothing - for activate() to do then this field may be NULL. - - When present, hosts MUST call this function once before run() is called - for the first time. This call SHOULD be made as close to the run() call - as possible and indicates to real-time plugins that they are now live, - however plugins MUST NOT rely on a prompt call to run() after - activate(). - - The host MUST NOT call activate() again until deactivate() has been - called first. If a host calls activate(), it MUST call deactivate() at - some point in the future. Note that connect_port() may be called before - or after activate(). - */ - void (*activate)(LV2_Handle instance); - - /** - Run a plugin instance for a block. - - Note that if an activate() function exists then it must be called before - run(). If deactivate() is called for a plugin instance then run() may - not be called until activate() has been called again. - - If the plugin has the feature lv2:hardRTCapable then there are various - things that the plugin MUST NOT do within the run() function (see - lv2core.ttl for details). - - As a special case, when `sample_count` is 0, the plugin should update - any output ports that represent a single instant in time (for example, - control ports, but not audio ports). This is particularly useful for - latent plugins, which should update their latency output port so hosts - can pre-roll plugins to compute latency. Plugins MUST NOT crash when - `sample_count` is 0. - - @param instance Instance to be run. - - @param sample_count The block size (in samples) for which the plugin - instance must run. - */ - void (*run)(LV2_Handle instance, - uint32_t sample_count); - - /** - Deactivate a plugin instance (counterpart to activate()). - - Hosts MUST deactivate all activated instances after they have been run() - for the last time. This call SHOULD be made as close to the last run() - call as possible and indicates to real-time plugins that they are no - longer live, however plugins MUST NOT rely on prompt deactivation. If - there is nothing for deactivate() to do then this field may be NULL - - Deactivation is not similar to pausing since the plugin instance will be - reinitialised by activate(). However, deactivate() itself MUST NOT fully - reset plugin state. For example, the host may deactivate a plugin, then - store its state (using some extension to do so). - - Hosts MUST NOT call deactivate() unless activate() was previously - called. Note that connect_port() may be called before or after - deactivate(). - */ - void (*deactivate)(LV2_Handle instance); - - /** - Clean up a plugin instance (counterpart to instantiate()). - - Once an instance of a plugin has been finished with it must be deleted - using this function. The instance handle passed ceases to be valid after - this call. - - If activate() was called for a plugin instance then a corresponding call - to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT - call cleanup() unless instantiate() was previously called. - */ - void (*cleanup)(LV2_Handle instance); - - /** - Return additional plugin data defined by some extenion. - - A typical use of this facility is to return a struct containing function - pointers to extend the LV2_Descriptor API. - - The actual type and meaning of the returned object MUST be specified - precisely by the extension. This function MUST return NULL for any - unsupported URI. If a plugin does not support any extension data, this - field may be NULL. - - The host is never responsible for freeing the returned value. - */ - const void * (*extension_data)(const char * uri); + /** + A globally unique, case-sensitive identifier for this plugin. + + This MUST be a valid URI string as defined by RFC 3986. All plugins with + the same URI MUST be compatible to some degree, see + http://lv2plug.in/ns/lv2core for details. + */ + const char* URI; + + /** + Instantiate the plugin. + + Note that instance initialisation should generally occur in activate() + rather than here. If a host calls instantiate(), it MUST call cleanup() + at some point in the future. + + @param descriptor Descriptor of the plugin to instantiate. + + @param sample_rate Sample rate, in Hz, for the new plugin instance. + + @param bundle_path Path to the LV2 bundle which contains this plugin + binary. It MUST include the trailing directory separator so that simply + appending a filename will yield the path to that file in the bundle. + + @param features A NULL terminated array of LV2_Feature structs which + represent the features the host supports. Plugins may refuse to + instantiate if required features are not found here. However, hosts MUST + NOT use this as a discovery mechanism: instead, use the RDF data to + determine which features are required and do not attempt to instantiate + unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host + that supports no features MUST pass a single element array containing + NULL. + + @return A handle for the new plugin instance, or NULL if instantiation + has failed. + */ + LV2_Handle (*instantiate)(const struct LV2_Descriptor* descriptor, + double sample_rate, + const char* bundle_path, + const LV2_Feature* const* features); + + /** + Connect a port on a plugin instance to a memory location. + + Plugin writers should be aware that the host may elect to use the same + buffer for more than one port and even use the same buffer for both + input and output (see lv2:inPlaceBroken in lv2.ttl). + + If the plugin has the feature lv2:hardRTCapable then there are various + things that the plugin MUST NOT do within the connect_port() function; + see lv2core.ttl for details. + + connect_port() MUST be called at least once for each port before run() + is called, unless that port is lv2:connectionOptional. The plugin must + pay careful attention to the block size passed to run() since the block + allocated may only just be large enough to contain the data, and is not + guaranteed to remain constant between run() calls. + + connect_port() may be called more than once for a plugin instance to + allow the host to change the buffers that the plugin is reading or + writing. These calls may be made before or after activate() or + deactivate() calls. + + @param instance Plugin instance containing the port. + + @param port Index of the port to connect. The host MUST NOT try to + connect a port index that is not defined in the plugin's RDF data. If + it does, the plugin's behaviour is undefined (a crash is likely). + + @param data_location Pointer to data of the type defined by the port + type in the plugin's RDF data (for example, an array of float for an + lv2:AudioPort). This pointer must be stored by the plugin instance and + used to read/write data when run() is called. Data present at the time + of the connect_port() call MUST NOT be considered meaningful. + */ + void (*connect_port)(LV2_Handle instance, uint32_t port, void* data_location); + + /** + Initialise a plugin instance and activate it for use. + + This is separated from instantiate() to aid real-time support and so + that hosts can reinitialise a plugin instance by calling deactivate() + and then activate(). In this case the plugin instance MUST reset all + state information dependent on the history of the plugin instance except + for any data locations provided by connect_port(). If there is nothing + for activate() to do then this field may be NULL. + + When present, hosts MUST call this function once before run() is called + for the first time. This call SHOULD be made as close to the run() call + as possible and indicates to real-time plugins that they are now live, + however plugins MUST NOT rely on a prompt call to run() after + activate(). + + The host MUST NOT call activate() again until deactivate() has been + called first. If a host calls activate(), it MUST call deactivate() at + some point in the future. Note that connect_port() may be called before + or after activate(). + */ + void (*activate)(LV2_Handle instance); + + /** + Run a plugin instance for a block. + + Note that if an activate() function exists then it must be called before + run(). If deactivate() is called for a plugin instance then run() may + not be called until activate() has been called again. + + If the plugin has the feature lv2:hardRTCapable then there are various + things that the plugin MUST NOT do within the run() function (see + lv2core.ttl for details). + + As a special case, when `sample_count` is 0, the plugin should update + any output ports that represent a single instant in time (for example, + control ports, but not audio ports). This is particularly useful for + latent plugins, which should update their latency output port so hosts + can pre-roll plugins to compute latency. Plugins MUST NOT crash when + `sample_count` is 0. + + @param instance Instance to be run. + + @param sample_count The block size (in samples) for which the plugin + instance must run. + */ + void (*run)(LV2_Handle instance, uint32_t sample_count); + + /** + Deactivate a plugin instance (counterpart to activate()). + + Hosts MUST deactivate all activated instances after they have been run() + for the last time. This call SHOULD be made as close to the last run() + call as possible and indicates to real-time plugins that they are no + longer live, however plugins MUST NOT rely on prompt deactivation. If + there is nothing for deactivate() to do then this field may be NULL + + Deactivation is not similar to pausing since the plugin instance will be + reinitialised by activate(). However, deactivate() itself MUST NOT fully + reset plugin state. For example, the host may deactivate a plugin, then + store its state (using some extension to do so). + + Hosts MUST NOT call deactivate() unless activate() was previously + called. Note that connect_port() may be called before or after + deactivate(). + */ + void (*deactivate)(LV2_Handle instance); + + /** + Clean up a plugin instance (counterpart to instantiate()). + + Once an instance of a plugin has been finished with it must be deleted + using this function. The instance handle passed ceases to be valid after + this call. + + If activate() was called for a plugin instance then a corresponding call + to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT + call cleanup() unless instantiate() was previously called. + */ + void (*cleanup)(LV2_Handle instance); + + /** + Return additional plugin data defined by some extenion. + + A typical use of this facility is to return a struct containing function + pointers to extend the LV2_Descriptor API. + + The actual type and meaning of the returned object MUST be specified + precisely by the extension. This function MUST return NULL for any + unsupported URI. If a plugin does not support any extension data, this + field may be NULL. + + The host is never responsible for freeing the returned value. + */ + const void* (*extension_data)(const char* uri); } LV2_Descriptor; /** Helper macro needed for LV2_SYMBOL_EXPORT when using C++. */ #ifdef __cplusplus -# define LV2_SYMBOL_EXTERN extern "C" +# define LV2_SYMBOL_EXTERN extern "C" #else -# define LV2_SYMBOL_EXTERN +# define LV2_SYMBOL_EXTERN #endif /** @@ -369,9 +366,10 @@ typedef struct LV2_Descriptor { by the host as a symbol from the dynamic library. */ #ifdef _WIN32 -# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __declspec(dllexport) +# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __declspec(dllexport) #else -# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __attribute__((visibility("default"))) +# define LV2_SYMBOL_EXPORT \ + LV2_SYMBOL_EXTERN __attribute__((visibility("default"))) #endif /** @@ -398,13 +396,13 @@ typedef struct LV2_Descriptor { consistent between loads of the plugin library. */ LV2_SYMBOL_EXPORT -const LV2_Descriptor * lv2_descriptor(uint32_t index); +const LV2_Descriptor* +lv2_descriptor(uint32_t index); /** Type of the lv2_descriptor() function in a library (old discovery API). */ -typedef const LV2_Descriptor * -(*LV2_Descriptor_Function)(uint32_t index); +typedef const LV2_Descriptor* (*LV2_Descriptor_Function)(uint32_t index); /** Handle for a library descriptor. @@ -418,34 +416,33 @@ typedef void* LV2_Lib_Handle; lv2_lib_descriptor() function in the shared object. */ typedef struct { - /** - Opaque library data which must be passed as the first parameter to all - the methods of this struct. - */ - LV2_Lib_Handle handle; - - /** - The total size of this struct. This allows for this struct to be - expanded in the future if necessary. This MUST be set by the library to - sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this - struct beyond get_plugin() unless this field indicates they are present. - */ - uint32_t size; - - /** - Destroy this library descriptor and free all related resources. - */ - void (*cleanup)(LV2_Lib_Handle handle); - - /** - Plugin accessor. - - Plugins are accessed by index using values from 0 upwards. Out of range - indices MUST result in this function returning NULL, so the host can - enumerate plugins by increasing `index` until NULL is returned. - */ - const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle, - uint32_t index); + /** + Opaque library data which must be passed as the first parameter to all + the methods of this struct. + */ + LV2_Lib_Handle handle; + + /** + The total size of this struct. This allows for this struct to be + expanded in the future if necessary. This MUST be set by the library to + sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this + struct beyond get_plugin() unless this field indicates they are present. + */ + uint32_t size; + + /** + Destroy this library descriptor and free all related resources. + */ + void (*cleanup)(LV2_Lib_Handle handle); + + /** + Plugin accessor. + + Plugins are accessed by index using values from 0 upwards. Out of range + indices MUST result in this function returning NULL, so the host can + enumerate plugins by increasing `index` until NULL is returned. + */ + const LV2_Descriptor* (*get_plugin)(LV2_Lib_Handle handle, uint32_t index); } LV2_Lib_Descriptor; /** @@ -465,16 +462,15 @@ typedef struct { from that library have been destroyed. */ LV2_SYMBOL_EXPORT -const LV2_Lib_Descriptor * -lv2_lib_descriptor(const char * bundle_path, - const LV2_Feature *const * features); +const LV2_Lib_Descriptor* +lv2_lib_descriptor(const char* bundle_path, const LV2_Feature* const* features); /** Type of the lv2_lib_descriptor() function in an LV2 library. */ -typedef const LV2_Lib_Descriptor * -(*LV2_Lib_Descriptor_Function)(const char * bundle_path, - const LV2_Feature *const * features); +typedef const LV2_Lib_Descriptor* (*LV2_Lib_Descriptor_Function)( + const char* bundle_path, + const LV2_Feature* const* features); #ifdef __cplusplus } /* extern "C" */ diff --git a/lv2/core/lv2_util.h b/lv2/core/lv2_util.h index 0269c70..0301c77 100644 --- a/lv2/core/lv2_util.h +++ b/lv2/core/lv2_util.h @@ -38,17 +38,16 @@ extern "C" { present but have NULL data. */ static inline void* -lv2_features_data(const LV2_Feature*const* features, - const char* const uri) +lv2_features_data(const LV2_Feature* const* features, const char* const uri) { - if (features) { - for (const LV2_Feature*const* f = features; *f; ++f) { - if (!strcmp(uri, (*f)->URI)) { - return (*f)->data; - } - } - } - return NULL; + if (features) { + for (const LV2_Feature* const* f = features; *f; ++f) { + if (!strcmp(uri, (*f)->URI)) { + return (*f)->data; + } + } + } + return NULL; } /** @@ -76,27 +75,27 @@ lv2_features_data(const LV2_Feature*const* features, static inline const char* lv2_features_query(const LV2_Feature* const* features, ...) { - va_list args; - va_start(args, features); - - const char* uri = NULL; - while ((uri = va_arg(args, const char*))) { - void** data = va_arg(args, void**); - bool required = va_arg(args, int); - - *data = lv2_features_data(features, uri); - if (required && !*data) { - va_end(args); - return uri; - } - } - - va_end(args); - return NULL; + va_list args; + va_start(args, features); + + const char* uri = NULL; + while ((uri = va_arg(args, const char*))) { + void** data = va_arg(args, void**); + bool required = va_arg(args, int); + + *data = lv2_features_data(features, uri); + if (required && !*data) { + va_end(args); + return uri; + } + } + + va_end(args); + return NULL; } #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** diff --git a/lv2/data-access/data-access.h b/lv2/data-access/data-access.h index fb930ec..e5252cb 100644 --- a/lv2/data-access/data-access.h +++ b/lv2/data-access/data-access.h @@ -48,27 +48,27 @@ extern "C" { and data pointed to an instance of this struct. */ typedef struct { - /** - A pointer to a method the UI can call to get data (of a type specified - by some other extension) from the plugin. - - This call never is never guaranteed to return anything, UIs should - degrade gracefully if direct access to the plugin data is not possible - (in which case this function will return NULL). - - This is for access to large data that can only possibly work if the UI - and plugin are running in the same process. For all other things, use - the normal LV2 UI communication system. - */ - const void* (*data_access)(const char* uri); + /** + A pointer to a method the UI can call to get data (of a type specified + by some other extension) from the plugin. + + This call never is never guaranteed to return anything, UIs should + degrade gracefully if direct access to the plugin data is not possible + (in which case this function will return NULL). + + This is for access to large data that can only possibly work if the UI + and plugin are running in the same process. For all other things, use + the normal LV2 UI communication system. + */ + const void* (*data_access)(const char* uri); } LV2_Extension_Data_Feature; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_DATA_ACCESS_H */ +#endif /* LV2_DATA_ACCESS_H */ diff --git a/lv2/dynmanifest/dynmanifest.h b/lv2/dynmanifest/dynmanifest.h index 36d7ebb..6181f71 100644 --- a/lv2/dynmanifest/dynmanifest.h +++ b/lv2/dynmanifest/dynmanifest.h @@ -52,7 +52,7 @@ extern "C" { NOT even valid to compare this to NULL. The dynamic manifest generator MAY use it to reference internal data. */ -typedef void * LV2_Dyn_Manifest_Handle; +typedef void* LV2_Dyn_Manifest_Handle; /** Generate the dynamic manifest. @@ -70,8 +70,9 @@ typedef void * LV2_Dyn_Manifest_Handle; evaluate the result of the operation by examining the returned value and MUST NOT try to interpret the value of handle. */ -int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle, - const LV2_Feature *const * features); +int +lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle* handle, + const LV2_Feature* const* features); /** Fetch a "list" of subject URIs described in the dynamic manifest. @@ -96,8 +97,8 @@ int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle, @return 0 on success, otherwise a non-zero error code. */ -int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle, - FILE * fp); +int +lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle, FILE* fp); /** Function that fetches data related to a specific URI. @@ -129,9 +130,10 @@ int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle, @return 0 on success, otherwise a non-zero error code. */ -int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle, - FILE * fp, - const char * uri); +int +lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle, + FILE* fp, + const char* uri); /** Function that ends the operations on the dynamic manifest generator. @@ -144,7 +146,8 @@ int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle, @param handle Dynamic manifest generator handle. */ -void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle); +void +lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle); #ifdef __cplusplus } /* extern "C" */ diff --git a/lv2/event/event-helpers.h b/lv2/event/event-helpers.h index 6b39235..7e3f19c 100644 --- a/lv2/event/event-helpers.h +++ b/lv2/event/event-helpers.h @@ -47,96 +47,87 @@ LV2_DISABLE_DEPRECATION_WARNINGS * Note that these functions are all static inline which basically means: * do not take the address of these functions. */ - /** Pad a size to 64 bits (for event sizes) */ static inline uint16_t lv2_event_pad_size(uint16_t size) { - return (uint16_t)(size + 7U) & (uint16_t)(~7U); + return (uint16_t)(size + 7U) & (uint16_t)(~7U); } - /** Initialize (empty, reset..) an existing event buffer. * The contents of buf are ignored entirely and overwritten, except capacity * which is unmodified. */ static inline void -lv2_event_buffer_reset(LV2_Event_Buffer* buf, - uint16_t stamp_type, - uint8_t* data) +lv2_event_buffer_reset(LV2_Event_Buffer* buf, + uint16_t stamp_type, + uint8_t* data) { - buf->data = data; - buf->header_size = sizeof(LV2_Event_Buffer); - buf->stamp_type = stamp_type; - buf->event_count = 0; - buf->size = 0; + buf->data = data; + buf->header_size = sizeof(LV2_Event_Buffer); + buf->stamp_type = stamp_type; + buf->event_count = 0; + buf->size = 0; } - /** Allocate a new, empty event buffer. */ static inline LV2_Event_Buffer* lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type) { - const size_t size = sizeof(LV2_Event_Buffer) + capacity; - LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size); - if (buf != NULL) { - buf->capacity = capacity; - lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1)); - return buf; - } - return NULL; + const size_t size = sizeof(LV2_Event_Buffer) + capacity; + LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size); + if (buf != NULL) { + buf->capacity = capacity; + lv2_event_buffer_reset(buf, stamp_type, (uint8_t*)(buf + 1)); + return buf; + } + return NULL; } - /** An iterator over an LV2_Event_Buffer. * * Multiple simultaneous read iterators over a single buffer is fine, * but changing the buffer invalidates all iterators. */ typedef struct { - LV2_Event_Buffer* buf; - uint32_t offset; + LV2_Event_Buffer* buf; + uint32_t offset; } LV2_Event_Iterator; - /** Reset an iterator to point to the start of `buf`. * @return True if `iter` is valid, otherwise false (buffer is empty) */ static inline bool -lv2_event_begin(LV2_Event_Iterator* iter, - LV2_Event_Buffer* buf) +lv2_event_begin(LV2_Event_Iterator* iter, LV2_Event_Buffer* buf) { - iter->buf = buf; - iter->offset = 0; - return (buf->size > 0); + iter->buf = buf; + iter->offset = 0; + return (buf->size > 0); } - /** Check if `iter` is valid. * @return True if `iter` is valid, otherwise false (past end of buffer) */ static inline bool lv2_event_is_valid(LV2_Event_Iterator* iter) { - return (iter->buf && (iter->offset < iter->buf->size)); + return (iter->buf && (iter->offset < iter->buf->size)); } - /** Advance `iter` forward one event. * `iter` must be valid. * @return True if `iter` is valid, otherwise false (reached end of buffer) */ static inline bool lv2_event_increment(LV2_Event_Iterator* iter) { - if (!lv2_event_is_valid(iter)) { - return false; - } + if (!lv2_event_is_valid(iter)) { + return false; + } - LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); + LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); - iter->offset += lv2_event_pad_size( - (uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size)); + iter->offset += + lv2_event_pad_size((uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size)); - return true; + return true; } - /** Dereference an event iterator (get the event currently pointed at). * `iter` must be valid. * `data` if non-NULL, will be set to point to the contents of the event @@ -145,23 +136,21 @@ lv2_event_increment(LV2_Event_Iterator* iter) * if the end of the buffer is reached (in which case `data` is * also set to NULL). */ static inline LV2_Event* -lv2_event_get(LV2_Event_Iterator* iter, - uint8_t** data) +lv2_event_get(LV2_Event_Iterator* iter, uint8_t** data) { - if (!lv2_event_is_valid(iter)) { - return NULL; - } + if (!lv2_event_is_valid(iter)) { + return NULL; + } - LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); + LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); - if (data) { - *data = (uint8_t*)ev + sizeof(LV2_Event); - } + if (data) { + *data = (uint8_t*)ev + sizeof(LV2_Event); + } - return ev; + return ev; } - /** Write an event at `iter`. * The event (if any) pointed to by `iter` will be overwritten, and `iter` * incremented to point to the following event (i.e. several calls to this @@ -175,62 +164,60 @@ lv2_event_write(LV2_Event_Iterator* iter, uint16_t size, const uint8_t* data) { - if (!iter->buf) { - return false; - } + if (!iter->buf) { + return false; + } - if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) { - return false; - } + if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) { + return false; + } - LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); + LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); - ev->frames = frames; - ev->subframes = subframes; - ev->type = type; - ev->size = size; - memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size); - ++iter->buf->event_count; + ev->frames = frames; + ev->subframes = subframes; + ev->type = type; + ev->size = size; + memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size); + ++iter->buf->event_count; - size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size)); - iter->buf->size += size; - iter->offset += size; + size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size)); + iter->buf->size += size; + iter->offset += size; - return true; + return true; } - /** Reserve space for an event in the buffer and return a pointer to the memory where the caller can write the event data, or NULL if there is not enough room in the buffer. */ static inline uint8_t* lv2_event_reserve(LV2_Event_Iterator* iter, - uint32_t frames, - uint32_t subframes, - uint16_t type, - uint16_t size) + uint32_t frames, + uint32_t subframes, + uint16_t type, + uint16_t size) { - const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size); - if (iter->buf->capacity - iter->buf->size < total_size) { - return NULL; - } + const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size); + if (iter->buf->capacity - iter->buf->size < total_size) { + return NULL; + } - LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); + LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset); - ev->frames = frames; - ev->subframes = subframes; - ev->type = type; - ev->size = size; - ++iter->buf->event_count; + ev->frames = frames; + ev->subframes = subframes; + ev->type = type; + ev->size = size; + ++iter->buf->event_count; - const uint16_t padded_size = lv2_event_pad_size(total_size); - iter->buf->size += padded_size; - iter->offset += padded_size; + const uint16_t padded_size = lv2_event_pad_size(total_size); + iter->buf->size += padded_size; + iter->offset += padded_size; - return (uint8_t*)ev + sizeof(LV2_Event); + return (uint8_t*)ev + sizeof(LV2_Event); } - /** Write an event at `iter`. * The event (if any) pointed to by `iter` will be overwritten, and `iter` * incremented to point to the following event (i.e. several calls to this @@ -241,28 +228,28 @@ lv2_event_write_event(LV2_Event_Iterator* iter, const LV2_Event* ev, const uint8_t* data) { - const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size); - if (iter->buf->capacity - iter->buf->size < total_size) { - return false; - } + const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size); + if (iter->buf->capacity - iter->buf->size < total_size) { + return false; + } - LV2_Event* const write_ev = (LV2_Event*)(iter->buf->data + iter->offset); + LV2_Event* const write_ev = (LV2_Event*)(iter->buf->data + iter->offset); - *write_ev = *ev; - memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size); - ++iter->buf->event_count; + *write_ev = *ev; + memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size); + ++iter->buf->event_count; - const uint16_t padded_size = lv2_event_pad_size(total_size); - iter->buf->size += padded_size; - iter->offset += padded_size; + const uint16_t padded_size = lv2_event_pad_size(total_size); + iter->buf->size += padded_size; + iter->offset += padded_size; - return true; + return true; } LV2_RESTORE_WARNINGS #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif #endif /* LV2_EVENT_HELPERS_H */ diff --git a/lv2/event/event.h b/lv2/event/event.h index ff91e3b..a0afd6c 100644 --- a/lv2/event/event.h +++ b/lv2/event/event.h @@ -47,7 +47,7 @@ // clang-format on -#define LV2_EVENT_AUDIO_STAMP 0 ///< Special timestamp type for audio frames +#define LV2_EVENT_AUDIO_STAMP 0 ///< Special timestamp type for audio frames #include "lv2/core/attributes.h" @@ -82,49 +82,48 @@ static const uint32_t LV2_EVENT_PPQN = 3136573440U; */ LV2_DEPRECATED typedef struct { - /** - The frames portion of timestamp. The units used here can optionally be - set for a port (with the lv2ev:timeUnits property), otherwise this is - audio frames, corresponding to the sample_count parameter of the LV2 run - method (frame 0 is the first frame for that call to run). - */ - uint32_t frames; - - /** - The sub-frames portion of timestamp. The units used here can optionally - be set for a port (with the lv2ev:timeUnits property), otherwise this is - 1/(2^32) of an audio frame. - */ - uint32_t subframes; - - /** - The type of this event, as a number which represents some URI - defining an event type. This value MUST be some value previously - returned from a call to the uri_to_id function defined in the LV2 - URI map extension (see lv2_uri_map.h). - There are special rules which must be followed depending on the type - of an event. If the plugin recognizes an event type, the definition - of that event type will describe how to interpret the event, and - any required behaviour. Otherwise, if the type is 0, this event is a - non-POD event and lv2_event_unref MUST be called if the event is - 'dropped' (see above). Even if the plugin does not understand an event, - it may pass the event through to an output by simply copying (and NOT - calling lv2_event_unref). These rules are designed to allow for generic - event handling plugins and large non-POD events, but with minimal hassle - on simple plugins that "don't care" about these more advanced features. - */ - uint16_t type; - - /** - The size of the data portion of this event in bytes, which immediately - follows. The header size (12 bytes) is not included in this value. - */ - uint16_t size; - - /* size bytes of data follow here */ + /** + The frames portion of timestamp. The units used here can optionally be + set for a port (with the lv2ev:timeUnits property), otherwise this is + audio frames, corresponding to the sample_count parameter of the LV2 run + method (frame 0 is the first frame for that call to run). + */ + uint32_t frames; + + /** + The sub-frames portion of timestamp. The units used here can optionally + be set for a port (with the lv2ev:timeUnits property), otherwise this is + 1/(2^32) of an audio frame. + */ + uint32_t subframes; + + /** + The type of this event, as a number which represents some URI + defining an event type. This value MUST be some value previously + returned from a call to the uri_to_id function defined in the LV2 + URI map extension (see lv2_uri_map.h). + There are special rules which must be followed depending on the type + of an event. If the plugin recognizes an event type, the definition + of that event type will describe how to interpret the event, and + any required behaviour. Otherwise, if the type is 0, this event is a + non-POD event and lv2_event_unref MUST be called if the event is + 'dropped' (see above). Even if the plugin does not understand an event, + it may pass the event through to an output by simply copying (and NOT + calling lv2_event_unref). These rules are designed to allow for generic + event handling plugins and large non-POD events, but with minimal hassle + on simple plugins that "don't care" about these more advanced features. + */ + uint16_t type; + + /** + The size of the data portion of this event in bytes, which immediately + follows. The header size (12 bytes) is not included in this value. + */ + uint16_t size; + + /* size bytes of data follow here */ } LV2_Event; - /** A buffer of LV2 events (header only). @@ -143,92 +142,90 @@ typedef struct { */ LV2_DEPRECATED typedef struct { - /** - The contents of the event buffer. This may or may not reside in the - same block of memory as this header, plugins must not assume either. - The host guarantees this points to at least capacity bytes of allocated - memory (though only size bytes of that are valid events). - */ - uint8_t* data; - - /** - The size of this event header in bytes (including everything). - - This is to allow for extending this header in the future without - breaking binary compatibility. Whenever this header is copied, - it MUST be done using this field (and NOT the sizeof this struct). - */ - uint16_t header_size; - - /** - The type of the time stamps for events in this buffer. - As a special exception, '0' always means audio frames and subframes - (1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate. - - INPUTS: The host must set this field to the numeric ID of some URI - defining the meaning of the frames/subframes fields of contained events - (obtained by the LV2 URI Map uri_to_id function with the URI of this - extension as the 'map' argument, see lv2_uri_map.h). The host must - never pass a plugin a buffer which uses a stamp type the plugin does not - 'understand'. The value of this field must never change, except when - connect_port is called on the input port, at which time the host MUST - have set the stamp_type field to the value that will be used for all - subsequent run calls. - - OUTPUTS: The plugin may set this to any value that has been returned - from uri_to_id with the URI of this extension for a 'map' argument. - When connected to a buffer with connect_port, output ports MUST set this - field to the type of time stamp they will be writing. On any call to - connect_port on an event input port, the plugin may change this field on - any output port, it is the responsibility of the host to check if any of - these values have changed and act accordingly. - */ - uint16_t stamp_type; - - /** - The number of events in this buffer. - - INPUTS: The host must set this field to the number of events contained - in the data buffer before calling run(). The plugin must not change - this field. - - OUTPUTS: The plugin must set this field to the number of events it has - written to the buffer before returning from run(). Any initial value - should be ignored by the plugin. - */ - uint32_t event_count; - - /** - The size of the data buffer in bytes. - This is set by the host and must not be changed by the plugin. - The host is allowed to change this between run() calls. - */ - uint32_t capacity; - - /** - The size of the initial portion of the data buffer containing data. - - INPUTS: The host must set this field to the number of bytes used - by all events it has written to the buffer (including headers) - before calling the plugin's run(). - The plugin must not change this field. - - OUTPUTS: The plugin must set this field to the number of bytes - used by all events it has written to the buffer (including headers) - before returning from run(). - Any initial value should be ignored by the plugin. - */ - uint32_t size; + /** + The contents of the event buffer. This may or may not reside in the + same block of memory as this header, plugins must not assume either. + The host guarantees this points to at least capacity bytes of allocated + memory (though only size bytes of that are valid events). + */ + uint8_t* data; + + /** + The size of this event header in bytes (including everything). + + This is to allow for extending this header in the future without + breaking binary compatibility. Whenever this header is copied, + it MUST be done using this field (and NOT the sizeof this struct). + */ + uint16_t header_size; + + /** + The type of the time stamps for events in this buffer. + As a special exception, '0' always means audio frames and subframes + (1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate. + + INPUTS: The host must set this field to the numeric ID of some URI + defining the meaning of the frames/subframes fields of contained events + (obtained by the LV2 URI Map uri_to_id function with the URI of this + extension as the 'map' argument, see lv2_uri_map.h). The host must + never pass a plugin a buffer which uses a stamp type the plugin does not + 'understand'. The value of this field must never change, except when + connect_port is called on the input port, at which time the host MUST + have set the stamp_type field to the value that will be used for all + subsequent run calls. + + OUTPUTS: The plugin may set this to any value that has been returned + from uri_to_id with the URI of this extension for a 'map' argument. + When connected to a buffer with connect_port, output ports MUST set this + field to the type of time stamp they will be writing. On any call to + connect_port on an event input port, the plugin may change this field on + any output port, it is the responsibility of the host to check if any of + these values have changed and act accordingly. + */ + uint16_t stamp_type; + + /** + The number of events in this buffer. + + INPUTS: The host must set this field to the number of events contained + in the data buffer before calling run(). The plugin must not change + this field. + + OUTPUTS: The plugin must set this field to the number of events it has + written to the buffer before returning from run(). Any initial value + should be ignored by the plugin. + */ + uint32_t event_count; + + /** + The size of the data buffer in bytes. + This is set by the host and must not be changed by the plugin. + The host is allowed to change this between run() calls. + */ + uint32_t capacity; + + /** + The size of the initial portion of the data buffer containing data. + + INPUTS: The host must set this field to the number of bytes used + by all events it has written to the buffer (including headers) + before calling the plugin's run(). + The plugin must not change this field. + + OUTPUTS: The plugin must set this field to the number of bytes + used by all events it has written to the buffer (including headers) + before returning from run(). + Any initial value should be ignored by the plugin. + */ + uint32_t size; } LV2_Event_Buffer; - /** Opaque pointer to host data. */ LV2_DEPRECATED typedef void* LV2_Event_Callback_Data; - /** Non-POD events feature. @@ -239,67 +236,67 @@ typedef void* LV2_Event_Callback_Data; */ LV2_DEPRECATED typedef struct { - /** - Opaque pointer to host data. - - The plugin MUST pass this to any call to functions in this struct. - Otherwise, it must not be interpreted in any way. - */ - LV2_Event_Callback_Data callback_data; - - /** - Take a reference to a non-POD event. - - If a plugin receives an event with type 0, it means the event is a - pointer to some object in memory and not a flat sequence of bytes - in the buffer. When receiving a non-POD event, the plugin already - has an implicit reference to the event. If the event is stored AND - passed to an output, lv2_event_ref MUST be called on that event. - If the event is only stored OR passed through, this is not necessary - (as the plugin already has 1 implicit reference). - - @param event An event received at an input that will not be copied to - an output or stored in any way. - - @param context The calling context. Like event types, this is a mapped - URI, see lv2_context.h. Simple plugin with just a run() method should - pass 0 here (the ID of the 'standard' LV2 run context). The host - guarantees that this function is realtime safe iff the context is - realtime safe. - - PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. - */ - uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data, - LV2_Event* event); - - /** - Drop a reference to a non-POD event. - - If a plugin receives an event with type 0, it means the event is a - pointer to some object in memory and not a flat sequence of bytes - in the buffer. If the plugin does not pass the event through to - an output or store it internally somehow, it MUST call this function - on the event (more information on using non-POD events below). - - @param event An event received at an input that will not be copied to an - output or stored in any way. - - @param context The calling context. Like event types, this is a mapped - URI, see lv2_context.h. Simple plugin with just a run() method should - pass 0 here (the ID of the 'standard' LV2 run context). The host - guarantees that this function is realtime safe iff the context is - realtime safe. - - PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. - */ - uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data, - LV2_Event* event); + /** + Opaque pointer to host data. + + The plugin MUST pass this to any call to functions in this struct. + Otherwise, it must not be interpreted in any way. + */ + LV2_Event_Callback_Data callback_data; + + /** + Take a reference to a non-POD event. + + If a plugin receives an event with type 0, it means the event is a + pointer to some object in memory and not a flat sequence of bytes + in the buffer. When receiving a non-POD event, the plugin already + has an implicit reference to the event. If the event is stored AND + passed to an output, lv2_event_ref MUST be called on that event. + If the event is only stored OR passed through, this is not necessary + (as the plugin already has 1 implicit reference). + + @param event An event received at an input that will not be copied to + an output or stored in any way. + + @param context The calling context. Like event types, this is a mapped + URI, see lv2_context.h. Simple plugin with just a run() method should + pass 0 here (the ID of the 'standard' LV2 run context). The host + guarantees that this function is realtime safe iff the context is + realtime safe. + + PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. + */ + uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data, + LV2_Event* event); + + /** + Drop a reference to a non-POD event. + + If a plugin receives an event with type 0, it means the event is a + pointer to some object in memory and not a flat sequence of bytes + in the buffer. If the plugin does not pass the event through to + an output or store it internally somehow, it MUST call this function + on the event (more information on using non-POD events below). + + @param event An event received at an input that will not be copied to an + output or stored in any way. + + @param context The calling context. Like event types, this is a mapped + URI, see lv2_context.h. Simple plugin with just a run() method should + pass 0 here (the ID of the 'standard' LV2 run context). The host + guarantees that this function is realtime safe iff the context is + realtime safe. + + PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. + */ + uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data, + LV2_Event* event); } LV2_Event_Feature; LV2_RESTORE_WARNINGS #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** diff --git a/lv2/instance-access/instance-access.h b/lv2/instance-access/instance-access.h index 4070fc0..99e6e80 100644 --- a/lv2/instance-access/instance-access.h +++ b/lv2/instance-access/instance-access.h @@ -39,4 +39,4 @@ @} */ -#endif /* LV2_INSTANCE_ACCESS_H */ +#endif /* LV2_INSTANCE_ACCESS_H */ diff --git a/lv2/log/log.h b/lv2/log/log.h index cf938ca..92422bd 100644 --- a/lv2/log/log.h +++ b/lv2/log/log.h @@ -53,9 +53,9 @@ extern "C" { /** @cond */ #ifdef __GNUC__ /** Allow type checking of printf-like functions. */ -# define LV2_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) +# define LV2_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #else -# define LV2_LOG_FUNC(fmt, arg1) +# define LV2_LOG_FUNC(fmt, arg1) #endif /** @endcond */ @@ -68,48 +68,46 @@ typedef void* LV2_Log_Handle; Log feature (LV2_LOG__log) */ typedef struct { - /** - Opaque pointer to host data. - - This MUST be passed to methods in this struct whenever they are called. - Otherwise, it must not be interpreted in any way. - */ - LV2_Log_Handle handle; - - /** - Log a message, passing format parameters directly. - - The API of this function matches that of the standard C printf function, - except for the addition of the first two parameters. This function may - be called from any non-realtime context, or from any context if `type` - is @ref LV2_LOG__Trace. - */ - LV2_LOG_FUNC(3, 4) - int (*printf)(LV2_Log_Handle handle, - LV2_URID type, - const char* fmt, ...); - - /** - Log a message, passing format parameters in a va_list. - - The API of this function matches that of the standard C vprintf - function, except for the addition of the first two parameters. This - function may be called from any non-realtime context, or from any - context if `type` is @ref LV2_LOG__Trace. - */ - LV2_LOG_FUNC(3, 0) - int (*vprintf)(LV2_Log_Handle handle, - LV2_URID type, - const char* fmt, - va_list ap); + /** + Opaque pointer to host data. + + This MUST be passed to methods in this struct whenever they are called. + Otherwise, it must not be interpreted in any way. + */ + LV2_Log_Handle handle; + + /** + Log a message, passing format parameters directly. + + The API of this function matches that of the standard C printf function, + except for the addition of the first two parameters. This function may + be called from any non-realtime context, or from any context if `type` + is @ref LV2_LOG__Trace. + */ + LV2_LOG_FUNC(3, 4) + int (*printf)(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...); + + /** + Log a message, passing format parameters in a va_list. + + The API of this function matches that of the standard C vprintf + function, except for the addition of the first two parameters. This + function may be called from any non-realtime context, or from any + context if `type` is @ref LV2_LOG__Trace. + */ + LV2_LOG_FUNC(3, 0) + int (*vprintf)(LV2_Log_Handle handle, + LV2_URID type, + const char* fmt, + va_list ap); } LV2_Log_Log; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_LOG_H */ +#endif /* LV2_LOG_H */ diff --git a/lv2/log/logger.h b/lv2/log/logger.h index 669069c..80459a7 100644 --- a/lv2/log/logger.h +++ b/lv2/log/logger.h @@ -42,12 +42,12 @@ extern "C" { Logger convenience API state. */ typedef struct { - LV2_Log_Log* log; + LV2_Log_Log* log; - LV2_URID Error; - LV2_URID Note; - LV2_URID Trace; - LV2_URID Warning; + LV2_URID Error; + LV2_URID Note; + LV2_URID Trace; + LV2_URID Warning; } LV2_Log_Logger; /** @@ -59,14 +59,14 @@ typedef struct { static inline void lv2_log_logger_set_map(LV2_Log_Logger* logger, LV2_URID_Map* map) { - if (map) { - logger->Error = map->map(map->handle, LV2_LOG__Error); - logger->Note = map->map(map->handle, LV2_LOG__Note); - logger->Trace = map->map(map->handle, LV2_LOG__Trace); - logger->Warning = map->map(map->handle, LV2_LOG__Warning); - } else { - logger->Error = logger->Note = logger->Trace = logger->Warning = 0; - } + if (map) { + logger->Error = map->map(map->handle, LV2_LOG__Error); + logger->Note = map->map(map->handle, LV2_LOG__Note); + logger->Trace = map->map(map->handle, LV2_LOG__Trace); + logger->Warning = map->map(map->handle, LV2_LOG__Warning); + } else { + logger->Error = logger->Note = logger->Trace = logger->Warning = 0; + } } /** @@ -77,12 +77,10 @@ lv2_log_logger_set_map(LV2_Log_Logger* logger, LV2_URID_Map* map) in which case the implementation will fall back to printing to stderr. */ static inline void -lv2_log_logger_init(LV2_Log_Logger* logger, - LV2_URID_Map* map, - LV2_Log_Log* log) +lv2_log_logger_init(LV2_Log_Logger* logger, LV2_URID_Map* map, LV2_Log_Log* log) { - logger->log = log; - lv2_log_logger_set_map(logger, map); + logger->log = log; + lv2_log_logger_set_map(logger, map); } /** @@ -95,9 +93,9 @@ lv2_log_vprintf(LV2_Log_Logger* logger, const char* fmt, va_list args) { - return ((logger && logger->log) - ? logger->log->vprintf(logger->log->handle, type, fmt, args) - : vfprintf(stderr, fmt, args)); + return ((logger && logger->log) + ? logger->log->vprintf(logger->log->handle, type, fmt, args) + : vfprintf(stderr, fmt, args)); } /** Log an error via lv2_log_vprintf(). */ @@ -105,11 +103,11 @@ LV2_LOG_FUNC(2, 3) static inline int lv2_log_error(LV2_Log_Logger* logger, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const int ret = lv2_log_vprintf(logger, logger->Error, fmt, args); - va_end(args); - return ret; + va_list args; + va_start(args, fmt); + const int ret = lv2_log_vprintf(logger, logger->Error, fmt, args); + va_end(args); + return ret; } /** Log a note via lv2_log_vprintf(). */ @@ -117,11 +115,11 @@ LV2_LOG_FUNC(2, 3) static inline int lv2_log_note(LV2_Log_Logger* logger, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const int ret = lv2_log_vprintf(logger, logger->Note, fmt, args); - va_end(args); - return ret; + va_list args; + va_start(args, fmt); + const int ret = lv2_log_vprintf(logger, logger->Note, fmt, args); + va_end(args); + return ret; } /** Log a trace via lv2_log_vprintf(). */ @@ -129,11 +127,11 @@ LV2_LOG_FUNC(2, 3) static inline int lv2_log_trace(LV2_Log_Logger* logger, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const int ret = lv2_log_vprintf(logger, logger->Trace, fmt, args); - va_end(args); - return ret; + va_list args; + va_start(args, fmt); + const int ret = lv2_log_vprintf(logger, logger->Trace, fmt, args); + va_end(args); + return ret; } /** Log a warning via lv2_log_vprintf(). */ @@ -141,19 +139,19 @@ LV2_LOG_FUNC(2, 3) static inline int lv2_log_warning(LV2_Log_Logger* logger, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - const int ret = lv2_log_vprintf(logger, logger->Warning, fmt, args); - va_end(args); - return ret; + va_list args; + va_start(args, fmt); + const int ret = lv2_log_vprintf(logger, logger->Warning, fmt, args); + va_end(args); + return ret; } #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_LOG_LOGGER_H */ +#endif /* LV2_LOG_LOGGER_H */ diff --git a/lv2/midi/midi.h b/lv2/midi/midi.h index 6f70377..52f8131 100644 --- a/lv2/midi/midi.h +++ b/lv2/midi/midi.h @@ -93,124 +93,130 @@ extern "C" { lv2_midi_get_type() on the status byte. */ typedef enum { - LV2_MIDI_MSG_INVALID = 0, /**< Invalid Message */ - LV2_MIDI_MSG_NOTE_OFF = 0x80, /**< Note Off */ - LV2_MIDI_MSG_NOTE_ON = 0x90, /**< Note On */ - LV2_MIDI_MSG_NOTE_PRESSURE = 0xA0, /**< Note Pressure */ - LV2_MIDI_MSG_CONTROLLER = 0xB0, /**< Controller */ - LV2_MIDI_MSG_PGM_CHANGE = 0xC0, /**< Program Change */ - LV2_MIDI_MSG_CHANNEL_PRESSURE = 0xD0, /**< Channel Pressure */ - LV2_MIDI_MSG_BENDER = 0xE0, /**< Pitch Bender */ - LV2_MIDI_MSG_SYSTEM_EXCLUSIVE = 0xF0, /**< System Exclusive Begin */ - LV2_MIDI_MSG_MTC_QUARTER = 0xF1, /**< MTC Quarter Frame */ - LV2_MIDI_MSG_SONG_POS = 0xF2, /**< Song Position */ - LV2_MIDI_MSG_SONG_SELECT = 0xF3, /**< Song Select */ - LV2_MIDI_MSG_TUNE_REQUEST = 0xF6, /**< Tune Request */ - LV2_MIDI_MSG_CLOCK = 0xF8, /**< Clock */ - LV2_MIDI_MSG_START = 0xFA, /**< Start */ - LV2_MIDI_MSG_CONTINUE = 0xFB, /**< Continue */ - LV2_MIDI_MSG_STOP = 0xFC, /**< Stop */ - LV2_MIDI_MSG_ACTIVE_SENSE = 0xFE, /**< Active Sensing */ - LV2_MIDI_MSG_RESET = 0xFF /**< Reset */ + LV2_MIDI_MSG_INVALID = 0, /**< Invalid Message */ + LV2_MIDI_MSG_NOTE_OFF = 0x80, /**< Note Off */ + LV2_MIDI_MSG_NOTE_ON = 0x90, /**< Note On */ + LV2_MIDI_MSG_NOTE_PRESSURE = 0xA0, /**< Note Pressure */ + LV2_MIDI_MSG_CONTROLLER = 0xB0, /**< Controller */ + LV2_MIDI_MSG_PGM_CHANGE = 0xC0, /**< Program Change */ + LV2_MIDI_MSG_CHANNEL_PRESSURE = 0xD0, /**< Channel Pressure */ + LV2_MIDI_MSG_BENDER = 0xE0, /**< Pitch Bender */ + LV2_MIDI_MSG_SYSTEM_EXCLUSIVE = 0xF0, /**< System Exclusive Begin */ + LV2_MIDI_MSG_MTC_QUARTER = 0xF1, /**< MTC Quarter Frame */ + LV2_MIDI_MSG_SONG_POS = 0xF2, /**< Song Position */ + LV2_MIDI_MSG_SONG_SELECT = 0xF3, /**< Song Select */ + LV2_MIDI_MSG_TUNE_REQUEST = 0xF6, /**< Tune Request */ + LV2_MIDI_MSG_CLOCK = 0xF8, /**< Clock */ + LV2_MIDI_MSG_START = 0xFA, /**< Start */ + LV2_MIDI_MSG_CONTINUE = 0xFB, /**< Continue */ + LV2_MIDI_MSG_STOP = 0xFC, /**< Stop */ + LV2_MIDI_MSG_ACTIVE_SENSE = 0xFE, /**< Active Sensing */ + LV2_MIDI_MSG_RESET = 0xFF /**< Reset */ } LV2_Midi_Message_Type; /** Standard MIDI Controller Numbers. */ typedef enum { - LV2_MIDI_CTL_MSB_BANK = 0x00, /**< Bank Selection */ - LV2_MIDI_CTL_MSB_MODWHEEL = 0x01, /**< Modulation */ - LV2_MIDI_CTL_MSB_BREATH = 0x02, /**< Breath */ - LV2_MIDI_CTL_MSB_FOOT = 0x04, /**< Foot */ - LV2_MIDI_CTL_MSB_PORTAMENTO_TIME = 0x05, /**< Portamento Time */ - LV2_MIDI_CTL_MSB_DATA_ENTRY = 0x06, /**< Data Entry */ - LV2_MIDI_CTL_MSB_MAIN_VOLUME = 0x07, /**< Main Volume */ - LV2_MIDI_CTL_MSB_BALANCE = 0x08, /**< Balance */ - LV2_MIDI_CTL_MSB_PAN = 0x0A, /**< Panpot */ - LV2_MIDI_CTL_MSB_EXPRESSION = 0x0B, /**< Expression */ - LV2_MIDI_CTL_MSB_EFFECT1 = 0x0C, /**< Effect1 */ - LV2_MIDI_CTL_MSB_EFFECT2 = 0x0D, /**< Effect2 */ - LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 = 0x10, /**< General Purpose 1 */ - LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 = 0x11, /**< General Purpose 2 */ - LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 = 0x12, /**< General Purpose 3 */ - LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 = 0x13, /**< General Purpose 4 */ - LV2_MIDI_CTL_LSB_BANK = 0x20, /**< Bank Selection */ - LV2_MIDI_CTL_LSB_MODWHEEL = 0x21, /**< Modulation */ - LV2_MIDI_CTL_LSB_BREATH = 0x22, /**< Breath */ - LV2_MIDI_CTL_LSB_FOOT = 0x24, /**< Foot */ - LV2_MIDI_CTL_LSB_PORTAMENTO_TIME = 0x25, /**< Portamento Time */ - LV2_MIDI_CTL_LSB_DATA_ENTRY = 0x26, /**< Data Entry */ - LV2_MIDI_CTL_LSB_MAIN_VOLUME = 0x27, /**< Main Volume */ - LV2_MIDI_CTL_LSB_BALANCE = 0x28, /**< Balance */ - LV2_MIDI_CTL_LSB_PAN = 0x2A, /**< Panpot */ - LV2_MIDI_CTL_LSB_EXPRESSION = 0x2B, /**< Expression */ - LV2_MIDI_CTL_LSB_EFFECT1 = 0x2C, /**< Effect1 */ - LV2_MIDI_CTL_LSB_EFFECT2 = 0x2D, /**< Effect2 */ - LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 = 0x30, /**< General Purpose 1 */ - LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 = 0x31, /**< General Purpose 2 */ - LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 = 0x32, /**< General Purpose 3 */ - LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 = 0x33, /**< General Purpose 4 */ - LV2_MIDI_CTL_SUSTAIN = 0x40, /**< Sustain Pedal */ - LV2_MIDI_CTL_PORTAMENTO = 0x41, /**< Portamento */ - LV2_MIDI_CTL_SOSTENUTO = 0x42, /**< Sostenuto */ - LV2_MIDI_CTL_SOFT_PEDAL = 0x43, /**< Soft Pedal */ - LV2_MIDI_CTL_LEGATO_FOOTSWITCH = 0x44, /**< Legato Foot Switch */ - LV2_MIDI_CTL_HOLD2 = 0x45, /**< Hold2 */ - LV2_MIDI_CTL_SC1_SOUND_VARIATION = 0x46, /**< SC1 Sound Variation */ - LV2_MIDI_CTL_SC2_TIMBRE = 0x47, /**< SC2 Timbre */ - LV2_MIDI_CTL_SC3_RELEASE_TIME = 0x48, /**< SC3 Release Time */ - LV2_MIDI_CTL_SC4_ATTACK_TIME = 0x49, /**< SC4 Attack Time */ - LV2_MIDI_CTL_SC5_BRIGHTNESS = 0x4A, /**< SC5 Brightness */ - LV2_MIDI_CTL_SC6 = 0x4B, /**< SC6 */ - LV2_MIDI_CTL_SC7 = 0x4C, /**< SC7 */ - LV2_MIDI_CTL_SC8 = 0x4D, /**< SC8 */ - LV2_MIDI_CTL_SC9 = 0x4E, /**< SC9 */ - LV2_MIDI_CTL_SC10 = 0x4F, /**< SC10 */ - LV2_MIDI_CTL_GENERAL_PURPOSE5 = 0x50, /**< General Purpose 5 */ - LV2_MIDI_CTL_GENERAL_PURPOSE6 = 0x51, /**< General Purpose 6 */ - LV2_MIDI_CTL_GENERAL_PURPOSE7 = 0x52, /**< General Purpose 7 */ - LV2_MIDI_CTL_GENERAL_PURPOSE8 = 0x53, /**< General Purpose 8 */ - LV2_MIDI_CTL_PORTAMENTO_CONTROL = 0x54, /**< Portamento Control */ - LV2_MIDI_CTL_E1_REVERB_DEPTH = 0x5B, /**< E1 Reverb Depth */ - LV2_MIDI_CTL_E2_TREMOLO_DEPTH = 0x5C, /**< E2 Tremolo Depth */ - LV2_MIDI_CTL_E3_CHORUS_DEPTH = 0x5D, /**< E3 Chorus Depth */ - LV2_MIDI_CTL_E4_DETUNE_DEPTH = 0x5E, /**< E4 Detune Depth */ - LV2_MIDI_CTL_E5_PHASER_DEPTH = 0x5F, /**< E5 Phaser Depth */ - LV2_MIDI_CTL_DATA_INCREMENT = 0x60, /**< Data Increment */ - LV2_MIDI_CTL_DATA_DECREMENT = 0x61, /**< Data Decrement */ - LV2_MIDI_CTL_NRPN_LSB = 0x62, /**< Non-registered Parameter Number */ - LV2_MIDI_CTL_NRPN_MSB = 0x63, /**< Non-registered Parameter Number */ - LV2_MIDI_CTL_RPN_LSB = 0x64, /**< Registered Parameter Number */ - LV2_MIDI_CTL_RPN_MSB = 0x65, /**< Registered Parameter Number */ - LV2_MIDI_CTL_ALL_SOUNDS_OFF = 0x78, /**< All Sounds Off */ - LV2_MIDI_CTL_RESET_CONTROLLERS = 0x79, /**< Reset Controllers */ - LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH = 0x7A, /**< Local Control Switch */ - LV2_MIDI_CTL_ALL_NOTES_OFF = 0x7B, /**< All Notes Off */ - LV2_MIDI_CTL_OMNI_OFF = 0x7C, /**< Omni Off */ - LV2_MIDI_CTL_OMNI_ON = 0x7D, /**< Omni On */ - LV2_MIDI_CTL_MONO1 = 0x7E, /**< Mono1 */ - LV2_MIDI_CTL_MONO2 = 0x7F /**< Mono2 */ + LV2_MIDI_CTL_MSB_BANK = 0x00, /**< Bank Selection */ + LV2_MIDI_CTL_MSB_MODWHEEL = 0x01, /**< Modulation */ + LV2_MIDI_CTL_MSB_BREATH = 0x02, /**< Breath */ + LV2_MIDI_CTL_MSB_FOOT = 0x04, /**< Foot */ + LV2_MIDI_CTL_MSB_PORTAMENTO_TIME = 0x05, /**< Portamento Time */ + LV2_MIDI_CTL_MSB_DATA_ENTRY = 0x06, /**< Data Entry */ + LV2_MIDI_CTL_MSB_MAIN_VOLUME = 0x07, /**< Main Volume */ + LV2_MIDI_CTL_MSB_BALANCE = 0x08, /**< Balance */ + LV2_MIDI_CTL_MSB_PAN = 0x0A, /**< Panpot */ + LV2_MIDI_CTL_MSB_EXPRESSION = 0x0B, /**< Expression */ + LV2_MIDI_CTL_MSB_EFFECT1 = 0x0C, /**< Effect1 */ + LV2_MIDI_CTL_MSB_EFFECT2 = 0x0D, /**< Effect2 */ + LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 = 0x10, /**< General Purpose 1 */ + LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 = 0x11, /**< General Purpose 2 */ + LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 = 0x12, /**< General Purpose 3 */ + LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 = 0x13, /**< General Purpose 4 */ + LV2_MIDI_CTL_LSB_BANK = 0x20, /**< Bank Selection */ + LV2_MIDI_CTL_LSB_MODWHEEL = 0x21, /**< Modulation */ + LV2_MIDI_CTL_LSB_BREATH = 0x22, /**< Breath */ + LV2_MIDI_CTL_LSB_FOOT = 0x24, /**< Foot */ + LV2_MIDI_CTL_LSB_PORTAMENTO_TIME = 0x25, /**< Portamento Time */ + LV2_MIDI_CTL_LSB_DATA_ENTRY = 0x26, /**< Data Entry */ + LV2_MIDI_CTL_LSB_MAIN_VOLUME = 0x27, /**< Main Volume */ + LV2_MIDI_CTL_LSB_BALANCE = 0x28, /**< Balance */ + LV2_MIDI_CTL_LSB_PAN = 0x2A, /**< Panpot */ + LV2_MIDI_CTL_LSB_EXPRESSION = 0x2B, /**< Expression */ + LV2_MIDI_CTL_LSB_EFFECT1 = 0x2C, /**< Effect1 */ + LV2_MIDI_CTL_LSB_EFFECT2 = 0x2D, /**< Effect2 */ + LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 = 0x30, /**< General Purpose 1 */ + LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 = 0x31, /**< General Purpose 2 */ + LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 = 0x32, /**< General Purpose 3 */ + LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 = 0x33, /**< General Purpose 4 */ + LV2_MIDI_CTL_SUSTAIN = 0x40, /**< Sustain Pedal */ + LV2_MIDI_CTL_PORTAMENTO = 0x41, /**< Portamento */ + LV2_MIDI_CTL_SOSTENUTO = 0x42, /**< Sostenuto */ + LV2_MIDI_CTL_SOFT_PEDAL = 0x43, /**< Soft Pedal */ + LV2_MIDI_CTL_LEGATO_FOOTSWITCH = 0x44, /**< Legato Foot Switch */ + LV2_MIDI_CTL_HOLD2 = 0x45, /**< Hold2 */ + LV2_MIDI_CTL_SC1_SOUND_VARIATION = 0x46, /**< SC1 Sound Variation */ + LV2_MIDI_CTL_SC2_TIMBRE = 0x47, /**< SC2 Timbre */ + LV2_MIDI_CTL_SC3_RELEASE_TIME = 0x48, /**< SC3 Release Time */ + LV2_MIDI_CTL_SC4_ATTACK_TIME = 0x49, /**< SC4 Attack Time */ + LV2_MIDI_CTL_SC5_BRIGHTNESS = 0x4A, /**< SC5 Brightness */ + LV2_MIDI_CTL_SC6 = 0x4B, /**< SC6 */ + LV2_MIDI_CTL_SC7 = 0x4C, /**< SC7 */ + LV2_MIDI_CTL_SC8 = 0x4D, /**< SC8 */ + LV2_MIDI_CTL_SC9 = 0x4E, /**< SC9 */ + LV2_MIDI_CTL_SC10 = 0x4F, /**< SC10 */ + LV2_MIDI_CTL_GENERAL_PURPOSE5 = 0x50, /**< General Purpose 5 */ + LV2_MIDI_CTL_GENERAL_PURPOSE6 = 0x51, /**< General Purpose 6 */ + LV2_MIDI_CTL_GENERAL_PURPOSE7 = 0x52, /**< General Purpose 7 */ + LV2_MIDI_CTL_GENERAL_PURPOSE8 = 0x53, /**< General Purpose 8 */ + LV2_MIDI_CTL_PORTAMENTO_CONTROL = 0x54, /**< Portamento Control */ + LV2_MIDI_CTL_E1_REVERB_DEPTH = 0x5B, /**< E1 Reverb Depth */ + LV2_MIDI_CTL_E2_TREMOLO_DEPTH = 0x5C, /**< E2 Tremolo Depth */ + LV2_MIDI_CTL_E3_CHORUS_DEPTH = 0x5D, /**< E3 Chorus Depth */ + LV2_MIDI_CTL_E4_DETUNE_DEPTH = 0x5E, /**< E4 Detune Depth */ + LV2_MIDI_CTL_E5_PHASER_DEPTH = 0x5F, /**< E5 Phaser Depth */ + LV2_MIDI_CTL_DATA_INCREMENT = 0x60, /**< Data Increment */ + LV2_MIDI_CTL_DATA_DECREMENT = 0x61, /**< Data Decrement */ + LV2_MIDI_CTL_NRPN_LSB = 0x62, /**< Non-registered Parameter Number */ + LV2_MIDI_CTL_NRPN_MSB = 0x63, /**< Non-registered Parameter Number */ + LV2_MIDI_CTL_RPN_LSB = 0x64, /**< Registered Parameter Number */ + LV2_MIDI_CTL_RPN_MSB = 0x65, /**< Registered Parameter Number */ + LV2_MIDI_CTL_ALL_SOUNDS_OFF = 0x78, /**< All Sounds Off */ + LV2_MIDI_CTL_RESET_CONTROLLERS = 0x79, /**< Reset Controllers */ + LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH = 0x7A, /**< Local Control Switch */ + LV2_MIDI_CTL_ALL_NOTES_OFF = 0x7B, /**< All Notes Off */ + LV2_MIDI_CTL_OMNI_OFF = 0x7C, /**< Omni Off */ + LV2_MIDI_CTL_OMNI_ON = 0x7D, /**< Omni On */ + LV2_MIDI_CTL_MONO1 = 0x7E, /**< Mono1 */ + LV2_MIDI_CTL_MONO2 = 0x7F /**< Mono2 */ } LV2_Midi_Controller; /** Return true iff `msg` is a MIDI voice message (which has a channel). */ static inline bool -lv2_midi_is_voice_message(const uint8_t* msg) { - return msg[0] >= 0x80 && msg[0] < 0xF0; +lv2_midi_is_voice_message(const uint8_t* msg) +{ + return msg[0] >= 0x80 && msg[0] < 0xF0; } /** Return true iff `msg` is a MIDI system message (which has no channel). */ static inline bool -lv2_midi_is_system_message(const uint8_t* msg) { - switch (msg[0]) { - case 0xF4: case 0xF5: case 0xF7: case 0xF9: case 0xFD: - return false; - default: - return (msg[0] & 0xF0) == 0xF0; - } +lv2_midi_is_system_message(const uint8_t* msg) +{ + switch (msg[0]) { + case 0xF4: + case 0xF5: + case 0xF7: + case 0xF9: + case 0xFD: + return false; + default: + return (msg[0] & 0xF0) == 0xF0; + } } /** @@ -218,24 +224,25 @@ lv2_midi_is_system_message(const uint8_t* msg) { @param msg Pointer to the start (status byte) of a MIDI message. */ static inline LV2_Midi_Message_Type -lv2_midi_message_type(const uint8_t* msg) { - if (lv2_midi_is_voice_message(msg)) { - return (LV2_Midi_Message_Type)(msg[0] & 0xF0); - } +lv2_midi_message_type(const uint8_t* msg) +{ + if (lv2_midi_is_voice_message(msg)) { + return (LV2_Midi_Message_Type)(msg[0] & 0xF0); + } - if (lv2_midi_is_system_message(msg)) { - return (LV2_Midi_Message_Type)msg[0]; - } + if (lv2_midi_is_system_message(msg)) { + return (LV2_Midi_Message_Type)msg[0]; + } - return LV2_MIDI_MSG_INVALID; + return LV2_MIDI_MSG_INVALID; } #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_MIDI_H */ +#endif /* LV2_MIDI_H */ diff --git a/lv2/morph/morph.h b/lv2/morph/morph.h index 8b096e0..08dee94 100644 --- a/lv2/morph/morph.h +++ b/lv2/morph/morph.h @@ -45,4 +45,4 @@ @} */ -#endif /* LV2_MORPH_H */ +#endif /* LV2_MORPH_H */ diff --git a/lv2/options/options.h b/lv2/options/options.h index b0f8274..a403788 100644 --- a/lv2/options/options.h +++ b/lv2/options/options.h @@ -54,29 +54,29 @@ extern "C" { The context of an Option, which defines the subject it applies to. */ typedef enum { - /** - This option applies to the instance itself. The subject must be - ignored. - */ - LV2_OPTIONS_INSTANCE, - - /** - This option applies to some named resource. The subject is a URI mapped - to an integer (a LV2_URID, like the key) - */ - LV2_OPTIONS_RESOURCE, - - /** - This option applies to some blank node. The subject is a blank node - identifier, which is valid only within the current local scope. - */ - LV2_OPTIONS_BLANK, - - /** - This option applies to a port on the instance. The subject is the - port's index. - */ - LV2_OPTIONS_PORT + /** + This option applies to the instance itself. The subject must be + ignored. + */ + LV2_OPTIONS_INSTANCE, + + /** + This option applies to some named resource. The subject is a URI mapped + to an integer (a LV2_URID, like the key) + */ + LV2_OPTIONS_RESOURCE, + + /** + This option applies to some blank node. The subject is a blank node + identifier, which is valid only within the current local scope. + */ + LV2_OPTIONS_BLANK, + + /** + This option applies to a port on the instance. The subject is the + port's index. + */ + LV2_OPTIONS_PORT } LV2_Options_Context; /** @@ -92,60 +92,58 @@ typedef enum { accessed/manipulated using LV2_Options_Interface. */ typedef struct { - LV2_Options_Context context; /**< Context (type of subject). */ - uint32_t subject; /**< Subject. */ - LV2_URID key; /**< Key (property). */ - uint32_t size; /**< Size of value in bytes. */ - LV2_URID type; /**< Type of value (datatype). */ - const void* value; /**< Pointer to value (object). */ + LV2_Options_Context context; /**< Context (type of subject). */ + uint32_t subject; /**< Subject. */ + LV2_URID key; /**< Key (property). */ + uint32_t size; /**< Size of value in bytes. */ + LV2_URID type; /**< Type of value (datatype). */ + const void* value; /**< Pointer to value (object). */ } LV2_Options_Option; /** A status code for option functions. */ typedef enum { - LV2_OPTIONS_SUCCESS = 0, /**< Completed successfully. */ - LV2_OPTIONS_ERR_UNKNOWN = 1, /**< Unknown error. */ - LV2_OPTIONS_ERR_BAD_SUBJECT = 1 << 1, /**< Invalid/unsupported subject. */ - LV2_OPTIONS_ERR_BAD_KEY = 1 << 2, /**< Invalid/unsupported key. */ - LV2_OPTIONS_ERR_BAD_VALUE = 1 << 3 /**< Invalid/unsupported value. */ + LV2_OPTIONS_SUCCESS = 0, /**< Completed successfully. */ + LV2_OPTIONS_ERR_UNKNOWN = 1, /**< Unknown error. */ + LV2_OPTIONS_ERR_BAD_SUBJECT = 1 << 1, /**< Invalid/unsupported subject. */ + LV2_OPTIONS_ERR_BAD_KEY = 1 << 2, /**< Invalid/unsupported key. */ + LV2_OPTIONS_ERR_BAD_VALUE = 1 << 3 /**< Invalid/unsupported value. */ } LV2_Options_Status; /** Interface for dynamically setting options (LV2_OPTIONS__interface). */ typedef struct { - /** - Get the given options. + /** + Get the given options. - Each element of the passed options array MUST have type, subject, and - key set. All other fields (size, type, value) MUST be initialised to - zero, and are set to the option value if such an option is found. + Each element of the passed options array MUST have type, subject, and + key set. All other fields (size, type, value) MUST be initialised to + zero, and are set to the option value if such an option is found. - This function is in the "instantiation" LV2 threading class, so no other - instance functions may be called concurrently. + This function is in the "instantiation" LV2 threading class, so no other + instance functions may be called concurrently. - @return Bitwise OR of LV2_Options_Status values. - */ - uint32_t (*get)(LV2_Handle instance, - LV2_Options_Option* options); + @return Bitwise OR of LV2_Options_Status values. + */ + uint32_t (*get)(LV2_Handle instance, LV2_Options_Option* options); - /** - Set the given options. + /** + Set the given options. - This function is in the "instantiation" LV2 threading class, so no other - instance functions may be called concurrently. + This function is in the "instantiation" LV2 threading class, so no other + instance functions may be called concurrently. - @return Bitwise OR of LV2_Options_Status values. - */ - uint32_t (*set)(LV2_Handle instance, - const LV2_Options_Option* options); + @return Bitwise OR of LV2_Options_Status values. + */ + uint32_t (*set)(LV2_Handle instance, const LV2_Options_Option* options); } LV2_Options_Interface; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_OPTIONS_H */ +#endif /* LV2_OPTIONS_H */ diff --git a/lv2/parameters/parameters.h b/lv2/parameters/parameters.h index 49a3364..842f4da 100644 --- a/lv2/parameters/parameters.h +++ b/lv2/parameters/parameters.h @@ -65,4 +65,4 @@ @} */ -#endif /* LV2_PARAMETERS_H */ +#endif /* LV2_PARAMETERS_H */ diff --git a/lv2/patch/patch.h b/lv2/patch/patch.h index a68b0bb..2c35714 100644 --- a/lv2/patch/patch.h +++ b/lv2/patch/patch.h @@ -70,4 +70,4 @@ @} */ -#endif /* LV2_PATCH_H */ +#endif /* LV2_PATCH_H */ diff --git a/lv2/port-groups/port-groups.h b/lv2/port-groups/port-groups.h index 0dd3c0d..3e967f0 100644 --- a/lv2/port-groups/port-groups.h +++ b/lv2/port-groups/port-groups.h @@ -74,4 +74,4 @@ @} */ -#endif /* LV2_PORT_GROUPS_H */ +#endif /* LV2_PORT_GROUPS_H */ diff --git a/lv2/port-props/port-props.h b/lv2/port-props/port-props.h index a413d54..94b34ee 100644 --- a/lv2/port-props/port-props.h +++ b/lv2/port-props/port-props.h @@ -50,4 +50,4 @@ @} */ -#endif /* LV2_PORT_PROPS_H */ +#endif /* LV2_PORT_PROPS_H */ diff --git a/lv2/presets/presets.h b/lv2/presets/presets.h index d09b71f..9c1f8bd 100644 --- a/lv2/presets/presets.h +++ b/lv2/presets/presets.h @@ -45,4 +45,4 @@ @} */ -#endif /* LV2_PRESETS_H */ +#endif /* LV2_PRESETS_H */ diff --git a/lv2/resize-port/resize-port.h b/lv2/resize-port/resize-port.h index 068001c..c6a5fa1 100644 --- a/lv2/resize-port/resize-port.h +++ b/lv2/resize-port/resize-port.h @@ -46,9 +46,9 @@ extern "C" { /** A status code for state functions. */ typedef enum { - LV2_RESIZE_PORT_SUCCESS = 0, /**< Completed successfully. */ - LV2_RESIZE_PORT_ERR_UNKNOWN = 1, /**< Unknown error. */ - LV2_RESIZE_PORT_ERR_NO_SPACE = 2 /**< Insufficient space. */ + LV2_RESIZE_PORT_SUCCESS = 0, /**< Completed successfully. */ + LV2_RESIZE_PORT_ERR_UNKNOWN = 1, /**< Unknown error. */ + LV2_RESIZE_PORT_ERR_NO_SPACE = 2 /**< Insufficient space. */ } LV2_Resize_Port_Status; /** Opaque data for resize method. */ @@ -56,34 +56,34 @@ typedef void* LV2_Resize_Port_Feature_Data; /** Host feature to allow plugins to resize their port buffers. */ typedef struct { - /** Opaque data for resize method. */ - LV2_Resize_Port_Feature_Data data; + /** Opaque data for resize method. */ + LV2_Resize_Port_Feature_Data data; - /** - Resize a port buffer to at least `size` bytes. + /** + Resize a port buffer to at least `size` bytes. - This function MAY return an error, in which case the port buffer was not - resized and the port is still connected to the same location. Plugins - MUST gracefully handle this situation. + This function MAY return an error, in which case the port buffer was not + resized and the port is still connected to the same location. Plugins + MUST gracefully handle this situation. - This function is in the audio threading class. + This function is in the audio threading class. - The host MUST preserve the contents of the port buffer when resizing. + The host MUST preserve the contents of the port buffer when resizing. - Plugins MAY resize a port many times in a single run callback. Hosts - SHOULD make this as inexpensive as possible. - */ - LV2_Resize_Port_Status (*resize)(LV2_Resize_Port_Feature_Data data, - uint32_t index, - size_t size); + Plugins MAY resize a port many times in a single run callback. Hosts + SHOULD make this as inexpensive as possible. + */ + LV2_Resize_Port_Status (*resize)(LV2_Resize_Port_Feature_Data data, + uint32_t index, + size_t size); } LV2_Resize_Port_Resize; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_RESIZE_PORT_H */ +#endif /* LV2_RESIZE_PORT_H */ diff --git a/lv2/state/state.h b/lv2/state/state.h index 0de3ee4..55db43b 100644 --- a/lv2/state/state.h +++ b/lv2/state/state.h @@ -55,10 +55,13 @@ extern "C" { #endif -typedef void* LV2_State_Handle; ///< Opaque handle for state save/restore -typedef void* LV2_State_Free_Path_Handle; ///< Opaque handle for state:freePath feature -typedef void* LV2_State_Map_Path_Handle; ///< Opaque handle for state:mapPath feature -typedef void* LV2_State_Make_Path_Handle; ///< Opaque handle for state:makePath feature +typedef void* LV2_State_Handle; ///< Opaque handle for state save/restore +typedef void* + LV2_State_Free_Path_Handle; ///< Opaque handle for state:freePath feature +typedef void* + LV2_State_Map_Path_Handle; ///< Opaque handle for state:mapPath feature +typedef void* + LV2_State_Make_Path_Handle; ///< Opaque handle for state:makePath feature /** Flags describing value characteristics. @@ -67,52 +70,52 @@ typedef void* LV2_State_Make_Path_Handle; ///< Opaque handle for state:makePath (de-)serialise the value data, or whether it is even possible to do so. */ typedef enum { - /** - Plain Old Data. - - Values with this flag contain no pointers or references to other areas - of memory. It is safe to copy POD values with a simple memcpy and store - them for the duration of the process. A POD value is not necessarily - safe to trasmit between processes or machines (for example, filenames - are POD), see LV2_STATE_IS_PORTABLE for details. - - Implementations MUST NOT attempt to copy or serialise a non-POD value if - they do not understand its type (and thus know how to correctly do so). - */ - LV2_STATE_IS_POD = 1, - - /** - Portable (architecture independent) data. - - Values with this flag are in a format that is usable on any - architecture. A portable value saved on one machine can be restored on - another machine regardless of architecture. The format of portable - values MUST NOT depend on architecture-specific properties like - endianness or alignment. Portable values MUST NOT contain filenames. - */ - LV2_STATE_IS_PORTABLE = 1 << 1, - - /** - Native data. - - This flag is used by the host to indicate that the saved data is only - going to be used locally in the currently running process (for things - like instance duplication or snapshots), so the plugin should use the - most efficient representation possible and not worry about serialisation - and portability. - */ - LV2_STATE_IS_NATIVE = 1 << 2 + /** + Plain Old Data. + + Values with this flag contain no pointers or references to other areas + of memory. It is safe to copy POD values with a simple memcpy and store + them for the duration of the process. A POD value is not necessarily + safe to trasmit between processes or machines (for example, filenames + are POD), see LV2_STATE_IS_PORTABLE for details. + + Implementations MUST NOT attempt to copy or serialise a non-POD value if + they do not understand its type (and thus know how to correctly do so). + */ + LV2_STATE_IS_POD = 1, + + /** + Portable (architecture independent) data. + + Values with this flag are in a format that is usable on any + architecture. A portable value saved on one machine can be restored on + another machine regardless of architecture. The format of portable + values MUST NOT depend on architecture-specific properties like + endianness or alignment. Portable values MUST NOT contain filenames. + */ + LV2_STATE_IS_PORTABLE = 1 << 1, + + /** + Native data. + + This flag is used by the host to indicate that the saved data is only + going to be used locally in the currently running process (for things + like instance duplication or snapshots), so the plugin should use the + most efficient representation possible and not worry about serialisation + and portability. + */ + LV2_STATE_IS_NATIVE = 1 << 2 } LV2_State_Flags; /** A status code for state functions. */ typedef enum { - LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ - LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ - LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ - LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ - LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ - LV2_STATE_ERR_NO_PROPERTY = 5, /**< Failed due to missing property. */ - LV2_STATE_ERR_NO_SPACE = 6 /**< Failed due to insufficient space. */ + LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ + LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ + LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ + LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ + LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ + LV2_STATE_ERR_NO_PROPERTY = 5, /**< Failed due to missing property. */ + LV2_STATE_ERR_NO_SPACE = 6 /**< Failed due to insufficient space. */ } LV2_State_Status; /** @@ -148,13 +151,12 @@ typedef enum { The plugin MUST NOT attempt to use this function outside of the LV2_State_Interface.restore() context. */ -typedef LV2_State_Status (*LV2_State_Store_Function)( - LV2_State_Handle handle, - uint32_t key, - const void* value, - size_t size, - uint32_t type, - uint32_t flags); +typedef LV2_State_Status (*LV2_State_Store_Function)(LV2_State_Handle handle, + uint32_t key, + const void* value, + size_t size, + uint32_t type, + uint32_t flags); /** A host-provided function to retrieve a property. @@ -174,12 +176,11 @@ typedef LV2_State_Status (*LV2_State_Store_Function)( returns. The plugin MUST NOT attempt to use this function, or any value returned from it, outside of the LV2_State_Interface.restore() context. */ -typedef const void* (*LV2_State_Retrieve_Function)( - LV2_State_Handle handle, - uint32_t key, - size_t* size, - uint32_t* type, - uint32_t* flags); +typedef const void* (*LV2_State_Retrieve_Function)(LV2_State_Handle handle, + uint32_t key, + size_t* size, + uint32_t* type, + uint32_t* flags); /** LV2 Plugin State Interface. @@ -200,186 +201,184 @@ typedef const void* (*LV2_State_Retrieve_Function)( with meaningful types to avoid such problems in the future. */ typedef struct { - /** - Save plugin state using a host-provided `store` callback. - - @param instance The instance handle of the plugin. - @param store The host-provided store callback. - @param handle An opaque pointer to host data which MUST be passed as the - handle parameter to `store` if it is called. - @param flags Flags describing desired properties of this save. These - flags may be used to determine the most appropriate values to store. - @param features Extensible parameter for passing any additional - features to be used for this save. - - The plugin is expected to store everything necessary to completely - restore its state later. Plugins SHOULD store simple POD data whenever - possible, and consider the possibility of state being restored much - later on a different machine. - - The `handle` pointer and `store` function MUST NOT be used - beyond the scope of save(). - - This function has its own special threading class: it may not be called - concurrently with any "Instantiation" function, but it may be called - concurrently with functions in any other class, unless the definition of - that class prohibits it (for example, it may not be called concurrently - with a "Discovery" function, but it may be called concurrently with an - "Audio" function. The plugin is responsible for any locking or - lock-free techniques necessary to make this possible. - - Note that in the simple case where state is only modified by restore(), - there are no synchronization issues since save() is never called - concurrently with restore() (though run() may read it during a save). - - Plugins that dynamically modify state while running, however, must take - care to do so in such a way that a concurrent call to save() will save a - consistent representation of plugin state for a single instant in time. - */ - LV2_State_Status (*save)(LV2_Handle instance, - LV2_State_Store_Function store, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features); - - /** - Restore plugin state using a host-provided `retrieve` callback. - - @param instance The instance handle of the plugin. - @param retrieve The host-provided retrieve callback. - @param handle An opaque pointer to host data which MUST be passed as the - handle parameter to `retrieve` if it is called. - @param flags Currently unused. - @param features Extensible parameter for passing any additional - features to be used for this restore. - - The plugin MAY assume a restored value was set by a previous call to - LV2_State_Interface.save() by a plugin with the same URI. - - The plugin MUST gracefully fall back to a default value when a value can - not be retrieved. This allows the host to reset the plugin state with - an empty map. - - The `handle` pointer and `store` function MUST NOT be used - beyond the scope of restore(). - - This function is in the "Instantiation" threading class as defined by - LV2. This means it MUST NOT be called concurrently with any other - function on the same plugin instance. - */ - LV2_State_Status (*restore)(LV2_Handle instance, - LV2_State_Retrieve_Function retrieve, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature *const * features); + /** + Save plugin state using a host-provided `store` callback. + + @param instance The instance handle of the plugin. + @param store The host-provided store callback. + @param handle An opaque pointer to host data which MUST be passed as the + handle parameter to `store` if it is called. + @param flags Flags describing desired properties of this save. These + flags may be used to determine the most appropriate values to store. + @param features Extensible parameter for passing any additional + features to be used for this save. + + The plugin is expected to store everything necessary to completely + restore its state later. Plugins SHOULD store simple POD data whenever + possible, and consider the possibility of state being restored much + later on a different machine. + + The `handle` pointer and `store` function MUST NOT be used + beyond the scope of save(). + + This function has its own special threading class: it may not be called + concurrently with any "Instantiation" function, but it may be called + concurrently with functions in any other class, unless the definition of + that class prohibits it (for example, it may not be called concurrently + with a "Discovery" function, but it may be called concurrently with an + "Audio" function. The plugin is responsible for any locking or + lock-free techniques necessary to make this possible. + + Note that in the simple case where state is only modified by restore(), + there are no synchronization issues since save() is never called + concurrently with restore() (though run() may read it during a save). + + Plugins that dynamically modify state while running, however, must take + care to do so in such a way that a concurrent call to save() will save a + consistent representation of plugin state for a single instant in time. + */ + LV2_State_Status (*save)(LV2_Handle instance, + LV2_State_Store_Function store, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features); + + /** + Restore plugin state using a host-provided `retrieve` callback. + + @param instance The instance handle of the plugin. + @param retrieve The host-provided retrieve callback. + @param handle An opaque pointer to host data which MUST be passed as the + handle parameter to `retrieve` if it is called. + @param flags Currently unused. + @param features Extensible parameter for passing any additional + features to be used for this restore. + + The plugin MAY assume a restored value was set by a previous call to + LV2_State_Interface.save() by a plugin with the same URI. + + The plugin MUST gracefully fall back to a default value when a value can + not be retrieved. This allows the host to reset the plugin state with + an empty map. + + The `handle` pointer and `store` function MUST NOT be used + beyond the scope of restore(). + + This function is in the "Instantiation" threading class as defined by + LV2. This means it MUST NOT be called concurrently with any other + function on the same plugin instance. + */ + LV2_State_Status (*restore)(LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features); } LV2_State_Interface; /** Feature data for state:mapPath (@ref LV2_STATE__mapPath). */ typedef struct { - /** - Opaque host data. - */ - LV2_State_Map_Path_Handle handle; - - /** - Map an absolute path to an abstract path for use in plugin state. - @param handle MUST be the `handle` member of this struct. - @param absolute_path The absolute path of a file. - @return An abstract path suitable for use in plugin state. - - The plugin MUST use this function to map any paths that will be stored - in plugin state. The returned value is an abstract path which MAY not - be an actual file system path; absolute_path() MUST be used to map - it to an actual path in order to use the file. - - Plugins MUST NOT make any assumptions about abstract paths except that - they can be mapped back to the absolute path of the "same" file (though - not necessarily the same original path) using absolute_path(). - - This function may only be called within the context of - LV2_State_Interface methods. The caller must free the returned value - with LV2_State_Free_Path.free_path(). - */ - char* (*abstract_path)(LV2_State_Map_Path_Handle handle, - const char* absolute_path); - - /** - Map an abstract path from plugin state to an absolute path. - @param handle MUST be the `handle` member of this struct. - @param abstract_path An abstract path (typically from plugin state). - @return An absolute file system path. - - The plugin MUST use this function in order to actually open or otherwise - use any paths loaded from plugin state. - - This function may only be called within the context of - LV2_State_Interface methods. The caller must free the returned value - with LV2_State_Free_Path.free_path(). - */ - char* (*absolute_path)(LV2_State_Map_Path_Handle handle, - const char* abstract_path); + /** + Opaque host data. + */ + LV2_State_Map_Path_Handle handle; + + /** + Map an absolute path to an abstract path for use in plugin state. + @param handle MUST be the `handle` member of this struct. + @param absolute_path The absolute path of a file. + @return An abstract path suitable for use in plugin state. + + The plugin MUST use this function to map any paths that will be stored + in plugin state. The returned value is an abstract path which MAY not + be an actual file system path; absolute_path() MUST be used to map + it to an actual path in order to use the file. + + Plugins MUST NOT make any assumptions about abstract paths except that + they can be mapped back to the absolute path of the "same" file (though + not necessarily the same original path) using absolute_path(). + + This function may only be called within the context of + LV2_State_Interface methods. The caller must free the returned value + with LV2_State_Free_Path.free_path(). + */ + char* (*abstract_path)(LV2_State_Map_Path_Handle handle, + const char* absolute_path); + + /** + Map an abstract path from plugin state to an absolute path. + @param handle MUST be the `handle` member of this struct. + @param abstract_path An abstract path (typically from plugin state). + @return An absolute file system path. + + The plugin MUST use this function in order to actually open or otherwise + use any paths loaded from plugin state. + + This function may only be called within the context of + LV2_State_Interface methods. The caller must free the returned value + with LV2_State_Free_Path.free_path(). + */ + char* (*absolute_path)(LV2_State_Map_Path_Handle handle, + const char* abstract_path); } LV2_State_Map_Path; /** Feature data for state:makePath (@ref LV2_STATE__makePath). */ typedef struct { - /** - Opaque host data. - */ - LV2_State_Make_Path_Handle handle; - - /** - Return a path the plugin may use to create a new file. - @param handle MUST be the `handle` member of this struct. - @param path The path of the new file within a namespace unique to this - plugin instance. - @return The absolute path to use for the new file. - - This function can be used by plugins to create files and directories, - either at state saving time (if this feature is passed to - LV2_State_Interface.save()) or any time (if this feature is passed to - LV2_Descriptor.instantiate()). - - The host MUST do whatever is necessary for the plugin to be able to - create a file at the returned path (for example, using fopen()), - including creating any leading directories. - - If this function is passed to LV2_Descriptor.instantiate(), it may be - called from any non-realtime context. If it is passed to - LV2_State_Interface.save(), it may only be called within the dynamic - scope of that function call. - - The caller must free the returned value with - LV2_State_Free_Path.free_path(). - */ - char* (*path)(LV2_State_Make_Path_Handle handle, - const char* path); + /** + Opaque host data. + */ + LV2_State_Make_Path_Handle handle; + + /** + Return a path the plugin may use to create a new file. + @param handle MUST be the `handle` member of this struct. + @param path The path of the new file within a namespace unique to this + plugin instance. + @return The absolute path to use for the new file. + + This function can be used by plugins to create files and directories, + either at state saving time (if this feature is passed to + LV2_State_Interface.save()) or any time (if this feature is passed to + LV2_Descriptor.instantiate()). + + The host MUST do whatever is necessary for the plugin to be able to + create a file at the returned path (for example, using fopen()), + including creating any leading directories. + + If this function is passed to LV2_Descriptor.instantiate(), it may be + called from any non-realtime context. If it is passed to + LV2_State_Interface.save(), it may only be called within the dynamic + scope of that function call. + + The caller must free the returned value with + LV2_State_Free_Path.free_path(). + */ + char* (*path)(LV2_State_Make_Path_Handle handle, const char* path); } LV2_State_Make_Path; /** Feature data for state:freePath (@ref LV2_STATE__freePath). */ typedef struct { - /** - Opaque host data. - */ - LV2_State_Free_Path_Handle handle; - - /** - Free a path returned by a state feature. - - @param handle MUST be the `handle` member of this struct. - @param path The path previously returned by a state feature. - - This function can be used by plugins to free paths allocated by the host - and returned by state features (LV2_State_Map_Path.abstract_path(), - LV2_State_Map_Path.absolute_path(), and LV2_State_Make_Path.path()). - */ - void (*free_path)(LV2_State_Free_Path_Handle handle, - char* path); + /** + Opaque host data. + */ + LV2_State_Free_Path_Handle handle; + + /** + Free a path returned by a state feature. + + @param handle MUST be the `handle` member of this struct. + @param path The path previously returned by a state feature. + + This function can be used by plugins to free paths allocated by the host + and returned by state features (LV2_State_Map_Path.abstract_path(), + LV2_State_Map_Path.absolute_path(), and LV2_State_Make_Path.path()). + */ + void (*free_path)(LV2_State_Free_Path_Handle handle, char* path); } LV2_State_Free_Path; #ifdef __cplusplus diff --git a/lv2/time/time.h b/lv2/time/time.h index 10337ae..0bb3fbd 100644 --- a/lv2/time/time.h +++ b/lv2/time/time.h @@ -56,4 +56,4 @@ @} */ -#endif /* LV2_TIME_H */ +#endif /* LV2_TIME_H */ diff --git a/lv2/ui/ui.h b/lv2/ui/ui.h index ee3c47d..61b3b54 100644 --- a/lv2/ui/ui.h +++ b/lv2/ui/ui.h @@ -145,86 +145,85 @@ typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller, function. */ typedef struct LV2UI_Descriptor { - /** - The URI for this UI (not for the plugin it controls). - */ - const char* URI; - - /** - Create a new UI and return a handle to it. This function works - similarly to LV2_Descriptor::instantiate(). - - @param descriptor The descriptor for the UI to instantiate. - - @param plugin_uri The URI of the plugin that this UI will control. - - @param bundle_path The path to the bundle containing this UI, including - the trailing directory separator. - - @param write_function A function that the UI can use to send data to the - plugin's input ports. - - @param controller A handle for the UI instance to be passed as the - first parameter of UI methods. - - @param widget (output) widget pointer. The UI points this at its main - widget, which has the type defined by the UI type in the data file. - - @param features An array of LV2_Feature pointers. The host must pass - all feature URIs that it and the UI supports and any additional data, as - in LV2_Descriptor::instantiate(). Note that UI features and plugin - features are not necessarily the same. - - */ - LV2UI_Handle (*instantiate)(const struct LV2UI_Descriptor* descriptor, - const char* plugin_uri, - const char* bundle_path, - LV2UI_Write_Function write_function, - LV2UI_Controller controller, - LV2UI_Widget* widget, - const LV2_Feature* const* features); - - - /** - Destroy the UI. The host must not try to access the widget after - calling this function. - */ - void (*cleanup)(LV2UI_Handle ui); - - /** - Tell the UI that something interesting has happened at a plugin port. - - What is "interesting" and how it is written to `buffer` is defined by - `format`, which has the same meaning as in LV2UI_Write_Function(). - Format 0 is a special case for lv2:ControlPort, where this function - should be called when the port value changes (but not necessarily for - every change), `buffer_size` must be sizeof(float), and `buffer` - points to a single IEEE-754 float. - - By default, the host should only call this function for lv2:ControlPort - inputs. However, the UI can request updates for other ports statically - with ui:portNotification or dynamicaly with ui:portSubscribe. - - The UI MUST NOT retain any reference to `buffer` after this function - returns, it is only valid for the duration of the call. - - This member may be NULL if the UI is not interested in any port events. - */ - void (*port_event)(LV2UI_Handle ui, - uint32_t port_index, - uint32_t buffer_size, - uint32_t format, - const void* buffer); - - /** - Return a data structure associated with an extension URI, typically an - interface struct with additional function pointers - - This member may be set to NULL if the UI is not interested in supporting - any extensions. This is similar to LV2_Descriptor::extension_data(). - - */ - const void* (*extension_data)(const char* uri); + /** + The URI for this UI (not for the plugin it controls). + */ + const char* URI; + + /** + Create a new UI and return a handle to it. This function works + similarly to LV2_Descriptor::instantiate(). + + @param descriptor The descriptor for the UI to instantiate. + + @param plugin_uri The URI of the plugin that this UI will control. + + @param bundle_path The path to the bundle containing this UI, including + the trailing directory separator. + + @param write_function A function that the UI can use to send data to the + plugin's input ports. + + @param controller A handle for the UI instance to be passed as the + first parameter of UI methods. + + @param widget (output) widget pointer. The UI points this at its main + widget, which has the type defined by the UI type in the data file. + + @param features An array of LV2_Feature pointers. The host must pass + all feature URIs that it and the UI supports and any additional data, as + in LV2_Descriptor::instantiate(). Note that UI features and plugin + features are not necessarily the same. + + */ + LV2UI_Handle (*instantiate)(const struct LV2UI_Descriptor* descriptor, + const char* plugin_uri, + const char* bundle_path, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + LV2UI_Widget* widget, + const LV2_Feature* const* features); + + /** + Destroy the UI. The host must not try to access the widget after + calling this function. + */ + void (*cleanup)(LV2UI_Handle ui); + + /** + Tell the UI that something interesting has happened at a plugin port. + + What is "interesting" and how it is written to `buffer` is defined by + `format`, which has the same meaning as in LV2UI_Write_Function(). + Format 0 is a special case for lv2:ControlPort, where this function + should be called when the port value changes (but not necessarily for + every change), `buffer_size` must be sizeof(float), and `buffer` + points to a single IEEE-754 float. + + By default, the host should only call this function for lv2:ControlPort + inputs. However, the UI can request updates for other ports statically + with ui:portNotification or dynamicaly with ui:portSubscribe. + + The UI MUST NOT retain any reference to `buffer` after this function + returns, it is only valid for the duration of the call. + + This member may be NULL if the UI is not interested in any port events. + */ + void (*port_event)(LV2UI_Handle ui, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void* buffer); + + /** + Return a data structure associated with an extension URI, typically an + interface struct with additional function pointers + + This member may be set to NULL if the UI is not interested in supporting + any extensions. This is similar to LV2_Descriptor::extension_data(). + + */ + const void* (*extension_data)(const char* uri); } LV2UI_Descriptor; /** @@ -235,24 +234,24 @@ typedef struct LV2UI_Descriptor { LV2UI_Descriptor::extension_data()). */ typedef struct { - /** - Pointer to opaque data which must be passed to ui_resize(). - */ - LV2UI_Feature_Handle handle; + /** + Pointer to opaque data which must be passed to ui_resize(). + */ + LV2UI_Feature_Handle handle; - /** - Request/advertise a size change. + /** + Request/advertise a size change. - When provided by the host, the UI may call this function to inform the - host about the size of the UI. + When provided by the host, the UI may call this function to inform the + host about the size of the UI. - When provided by the UI, the host may call this function to notify the - UI that it should change its size accordingly. In this case, the host - must pass the LV2UI_Handle to provide access to the UI instance. + When provided by the UI, the host may call this function to notify the + UI that it should change its size accordingly. In this case, the host + must pass the LV2UI_Handle to provide access to the UI instance. - @return 0 on success. - */ - int (*ui_resize)(LV2UI_Feature_Handle handle, int width, int height); + @return 0 on success. + */ + int (*ui_resize)(LV2UI_Feature_Handle handle, int width, int height); } LV2UI_Resize; /** @@ -263,181 +262,179 @@ typedef struct { from the plugin (since symbol, unlike index, is a stable port identifier). */ typedef struct { - /** - Pointer to opaque data which must be passed to port_index(). - */ - LV2UI_Feature_Handle handle; - - /** - Get the index for the port with the given `symbol`. - - @return The index of the port, or LV2UI_INVALID_PORT_INDEX if no such - port is found. - */ - uint32_t (*port_index)(LV2UI_Feature_Handle handle, const char* symbol); + /** + Pointer to opaque data which must be passed to port_index(). + */ + LV2UI_Feature_Handle handle; + + /** + Get the index for the port with the given `symbol`. + + @return The index of the port, or LV2UI_INVALID_PORT_INDEX if no such + port is found. + */ + uint32_t (*port_index)(LV2UI_Feature_Handle handle, const char* symbol); } LV2UI_Port_Map; /** Feature to subscribe to port updates (LV2_UI__portSubscribe). */ typedef struct { - /** - Pointer to opaque data which must be passed to subscribe() and - unsubscribe(). - */ - LV2UI_Feature_Handle handle; - - /** - Subscribe to updates for a port. - - This means that the host will call the UI's port_event() function when - the port value changes (as defined by protocol). - - Calling this function with the same `port_index` and `port_protocol` - as an already active subscription has no effect. - - @param handle The handle field of this struct. - @param port_index The index of the port. - @param port_protocol The URID of the ui:PortProtocol. - @param features Features for this subscription. - @return 0 on success. - */ - uint32_t (*subscribe)(LV2UI_Feature_Handle handle, - uint32_t port_index, - uint32_t port_protocol, - const LV2_Feature* const* features); - - /** - Unsubscribe from updates for a port. - - This means that the host will cease calling calling port_event() when - the port value changes. - - Calling this function with a `port_index` and `port_protocol` that - does not refer to an active port subscription has no effect. - - @param handle The handle field of this struct. - @param port_index The index of the port. - @param port_protocol The URID of the ui:PortProtocol. - @param features Features for this subscription. - @return 0 on success. - */ - uint32_t (*unsubscribe)(LV2UI_Feature_Handle handle, - uint32_t port_index, - uint32_t port_protocol, - const LV2_Feature* const* features); + /** + Pointer to opaque data which must be passed to subscribe() and + unsubscribe(). + */ + LV2UI_Feature_Handle handle; + + /** + Subscribe to updates for a port. + + This means that the host will call the UI's port_event() function when + the port value changes (as defined by protocol). + + Calling this function with the same `port_index` and `port_protocol` + as an already active subscription has no effect. + + @param handle The handle field of this struct. + @param port_index The index of the port. + @param port_protocol The URID of the ui:PortProtocol. + @param features Features for this subscription. + @return 0 on success. + */ + uint32_t (*subscribe)(LV2UI_Feature_Handle handle, + uint32_t port_index, + uint32_t port_protocol, + const LV2_Feature* const* features); + + /** + Unsubscribe from updates for a port. + + This means that the host will cease calling calling port_event() when + the port value changes. + + Calling this function with a `port_index` and `port_protocol` that + does not refer to an active port subscription has no effect. + + @param handle The handle field of this struct. + @param port_index The index of the port. + @param port_protocol The URID of the ui:PortProtocol. + @param features Features for this subscription. + @return 0 on success. + */ + uint32_t (*unsubscribe)(LV2UI_Feature_Handle handle, + uint32_t port_index, + uint32_t port_protocol, + const LV2_Feature* const* features); } LV2UI_Port_Subscribe; /** A feature to notify the host that the user has grabbed a UI control. */ typedef struct { - /** - Pointer to opaque data which must be passed to touch(). - */ - LV2UI_Feature_Handle handle; - - /** - Notify the host that a control has been grabbed or released. - - The host should cease automating the port or otherwise manipulating the - port value until the control has been ungrabbed. - - @param handle The handle field of this struct. - @param port_index The index of the port associated with the control. - @param grabbed If true, the control has been grabbed, otherwise the - control has been released. - */ - void (*touch)(LV2UI_Feature_Handle handle, - uint32_t port_index, - bool grabbed); + /** + Pointer to opaque data which must be passed to touch(). + */ + LV2UI_Feature_Handle handle; + + /** + Notify the host that a control has been grabbed or released. + + The host should cease automating the port or otherwise manipulating the + port value until the control has been ungrabbed. + + @param handle The handle field of this struct. + @param port_index The index of the port associated with the control. + @param grabbed If true, the control has been grabbed, otherwise the + control has been released. + */ + void (*touch)(LV2UI_Feature_Handle handle, uint32_t port_index, bool grabbed); } LV2UI_Touch; /** A status code for LV2UI_Request_Value::request(). */ typedef enum { - /** - Completed successfully. - - The host will set the parameter later if the user choses a new value. - */ - LV2UI_REQUEST_VALUE_SUCCESS, - - /** - Parameter already being requested. - - The host is already requesting a parameter from the user (for example, a - dialog is visible), or the UI is otherwise busy and can not make this - request. - */ - LV2UI_REQUEST_VALUE_BUSY, - - /** - Unknown parameter. - - The host is not aware of this parameter, and is not able to set a new - value for it. - */ - LV2UI_REQUEST_VALUE_ERR_UNKNOWN, - - /** - Unsupported parameter. - - The host knows about this parameter, but does not support requesting a - new value for it from the user. This is likely because the host does - not have UI support for choosing a value with the appropriate type. - */ - LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED + /** + Completed successfully. + + The host will set the parameter later if the user choses a new value. + */ + LV2UI_REQUEST_VALUE_SUCCESS, + + /** + Parameter already being requested. + + The host is already requesting a parameter from the user (for example, a + dialog is visible), or the UI is otherwise busy and can not make this + request. + */ + LV2UI_REQUEST_VALUE_BUSY, + + /** + Unknown parameter. + + The host is not aware of this parameter, and is not able to set a new + value for it. + */ + LV2UI_REQUEST_VALUE_ERR_UNKNOWN, + + /** + Unsupported parameter. + + The host knows about this parameter, but does not support requesting a + new value for it from the user. This is likely because the host does + not have UI support for choosing a value with the appropriate type. + */ + LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED } LV2UI_Request_Value_Status; /** A feature to request a new parameter value from the host. */ typedef struct { - /** - Pointer to opaque data which must be passed to request(). - */ - LV2UI_Feature_Handle handle; - - /** - Request a value for a parameter from the host. - - This is mainly used by UIs to request values for complex parameters that - don't change often, such as file paths, but it may be used to request - any parameter value. - - This function returns immediately, and the return value indicates - whether the host can fulfill the request. The host may notify the - plugin about the new parameter value, for example when a file is - selected by the user, via the usual mechanism. Typically, the host will - send a message to the plugin that sets the new parameter value, and the - plugin will notify the UI via a message as usual for any other parameter - change. - - To provide an appropriate UI, the host can determine details about the - parameter from the plugin data as usual. The additional parameters of - this function provide support for more advanced use cases, but in the - simple common case, the plugin will simply pass the key of the desired - parameter and zero for everything else. - - @param handle The handle field of this struct. - - @param key The URID of the parameter. - - @param type The optional type of the value to request. This can be used - to request a specific value type for parameters that support several. - If non-zero, it must be the URID of an instance of rdfs:Class or - rdfs:Datatype. - - @param features Additional features for this request, or NULL. - - @return A status code which is 0 on success. - */ - LV2UI_Request_Value_Status (*request)(LV2UI_Feature_Handle handle, - LV2_URID key, - LV2_URID type, - const LV2_Feature* const* features); + /** + Pointer to opaque data which must be passed to request(). + */ + LV2UI_Feature_Handle handle; + + /** + Request a value for a parameter from the host. + + This is mainly used by UIs to request values for complex parameters that + don't change often, such as file paths, but it may be used to request + any parameter value. + + This function returns immediately, and the return value indicates + whether the host can fulfill the request. The host may notify the + plugin about the new parameter value, for example when a file is + selected by the user, via the usual mechanism. Typically, the host will + send a message to the plugin that sets the new parameter value, and the + plugin will notify the UI via a message as usual for any other parameter + change. + + To provide an appropriate UI, the host can determine details about the + parameter from the plugin data as usual. The additional parameters of + this function provide support for more advanced use cases, but in the + simple common case, the plugin will simply pass the key of the desired + parameter and zero for everything else. + + @param handle The handle field of this struct. + + @param key The URID of the parameter. + + @param type The optional type of the value to request. This can be used + to request a specific value type for parameters that support several. + If non-zero, it must be the URID of an instance of rdfs:Class or + rdfs:Datatype. + + @param features Additional features for this request, or NULL. + + @return A status code which is 0 on success. + */ + LV2UI_Request_Value_Status (*request)(LV2UI_Feature_Handle handle, + LV2_URID key, + LV2_URID type, + const LV2_Feature* const* features); } LV2UI_Request_Value; @@ -448,19 +445,19 @@ typedef struct { rapidly to update the UI. */ typedef struct { - /** - Run a single iteration of the UI's idle loop. - - This will be called rapidly in the UI thread at a rate appropriate - for a toolkit main loop. There are no precise timing guarantees, but - the host should attempt to call idle() at a high enough rate for smooth - animation, at least 30Hz. - - @return non-zero if the UI has been closed, in which case the host - should stop calling idle(), and can either completely destroy the UI, or - re-show it and resume calling idle(). - */ - int (*idle)(LV2UI_Handle ui); + /** + Run a single iteration of the UI's idle loop. + + This will be called rapidly in the UI thread at a rate appropriate + for a toolkit main loop. There are no precise timing guarantees, but + the host should attempt to call idle() at a high enough rate for smooth + animation, at least 30Hz. + + @return non-zero if the UI has been closed, in which case the host + should stop calling idle(), and can either completely destroy the UI, or + re-show it and resume calling idle(). + */ + int (*idle)(LV2UI_Handle ui); } LV2UI_Idle_Interface; /** @@ -472,51 +469,52 @@ typedef struct { If used: - The host MUST use LV2UI_Idle_Interface to drive the UI. - - The UI MUST return non-zero from LV2UI_Idle_Interface::idle() when it has been closed. + - The UI MUST return non-zero from LV2UI_Idle_Interface::idle() when it has + been closed. - If idle() returns non-zero, the host MUST call hide() and stop calling idle(). It MAY later call show() then resume calling idle(). */ typedef struct { - /** - Show a window for this UI. + /** + Show a window for this UI. - The window title MAY have been passed by the host to - LV2UI_Descriptor::instantiate() as an LV2_Options_Option with key - LV2_UI__windowTitle. + The window title MAY have been passed by the host to + LV2UI_Descriptor::instantiate() as an LV2_Options_Option with key + LV2_UI__windowTitle. - @return 0 on success, or anything else to stop being called. - */ - int (*show)(LV2UI_Handle ui); + @return 0 on success, or anything else to stop being called. + */ + int (*show)(LV2UI_Handle ui); - /** - Hide the window for this UI. + /** + Hide the window for this UI. - @return 0 on success, or anything else to stop being called. - */ - int (*hide)(LV2UI_Handle ui); + @return 0 on success, or anything else to stop being called. + */ + int (*hide)(LV2UI_Handle ui); } LV2UI_Show_Interface; /** Peak data for a slice of time, the update format for ui:peakProtocol. */ typedef struct { - /** - The start of the measurement period. This is just a running counter - that is only meaningful in comparison to previous values and must not be - interpreted as an absolute time. - */ - uint32_t period_start; - - /** - The size of the measurement period, in the same units as period_start. - */ - uint32_t period_size; - - /** - The peak value for the measurement period. This should be the maximal - value for abs(sample) over all the samples in the period. - */ - float peak; + /** + The start of the measurement period. This is just a running counter + that is only meaningful in comparison to previous values and must not be + interpreted as an absolute time. + */ + uint32_t period_start; + + /** + The size of the measurement period, in the same units as period_start. + */ + uint32_t period_size; + + /** + The peak value for the measurement period. This should be the maximal + value for abs(sample) over all the samples in the period. + */ + float peak; } LV2UI_Peak_Data; /** @@ -526,7 +524,8 @@ typedef struct { lv2_descriptor() but for UIs rather than plugins. */ LV2_SYMBOL_EXPORT -const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index); +const LV2UI_Descriptor* +lv2ui_descriptor(uint32_t index); /** The type of the lv2ui_descriptor() function. diff --git a/lv2/units/units.h b/lv2/units/units.h index 07db081..a9017d2 100644 --- a/lv2/units/units.h +++ b/lv2/units/units.h @@ -72,4 +72,4 @@ @} */ -#endif /* LV2_UNITS_H */ +#endif /* LV2_UNITS_H */ diff --git a/lv2/uri-map/uri-map.h b/lv2/uri-map/uri-map.h index 31e485a..be5068c 100644 --- a/lv2/uri-map/uri-map.h +++ b/lv2/uri-map/uri-map.h @@ -68,50 +68,50 @@ typedef void* LV2_URI_Map_Callback_Data; */ LV2_DEPRECATED typedef struct { - /** - Opaque pointer to host data. - - The plugin MUST pass this to any call to functions in this struct. - Otherwise, it must not be interpreted in any way. - */ - LV2_URI_Map_Callback_Data callback_data; - - /** - Get the numeric ID of a URI from the host. - - @param callback_data Must be the callback_data member of this struct. - @param map The 'context' of this URI. Certain extensions may define a - URI that must be passed here with certain restrictions on the return - value (e.g. limited range). This value may be NULL if the plugin needs - an ID for a URI in general. Extensions SHOULD NOT define a context - unless there is a specific need to do so, e.g. to restrict the range of - the returned value. - @param uri The URI to be mapped to an integer ID. - - This function is referentially transparent; any number of calls with the - same arguments is guaranteed to return the same value over the life of a - plugin instance (though the same URI may return different values with a - different map parameter). However, this function is not necessarily very - fast: plugins SHOULD cache any IDs they might need in performance - critical situations. - - The return value 0 is reserved and indicates that an ID for that URI - could not be created for whatever reason. Extensions MAY define more - precisely what this means in a certain context, but in general plugins - SHOULD handle this situation as gracefully as possible. However, hosts - SHOULD NOT return 0 from this function in non-exceptional circumstances - (e.g. the URI map SHOULD be dynamic). Hosts that statically support only - a fixed set of URIs should not expect plugins to function correctly. - */ - uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data, - const char* map, - const char* uri); + /** + Opaque pointer to host data. + + The plugin MUST pass this to any call to functions in this struct. + Otherwise, it must not be interpreted in any way. + */ + LV2_URI_Map_Callback_Data callback_data; + + /** + Get the numeric ID of a URI from the host. + + @param callback_data Must be the callback_data member of this struct. + @param map The 'context' of this URI. Certain extensions may define a + URI that must be passed here with certain restrictions on the return + value (e.g. limited range). This value may be NULL if the plugin needs + an ID for a URI in general. Extensions SHOULD NOT define a context + unless there is a specific need to do so, e.g. to restrict the range of + the returned value. + @param uri The URI to be mapped to an integer ID. + + This function is referentially transparent; any number of calls with the + same arguments is guaranteed to return the same value over the life of a + plugin instance (though the same URI may return different values with a + different map parameter). However, this function is not necessarily very + fast: plugins SHOULD cache any IDs they might need in performance + critical situations. + + The return value 0 is reserved and indicates that an ID for that URI + could not be created for whatever reason. Extensions MAY define more + precisely what this means in a certain context, but in general plugins + SHOULD handle this situation as gracefully as possible. However, hosts + SHOULD NOT return 0 from this function in non-exceptional circumstances + (e.g. the URI map SHOULD be dynamic). Hosts that statically support only + a fixed set of URIs should not expect plugins to function correctly. + */ + uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data, + const char* map, + const char* uri); } LV2_URI_Map_Feature; LV2_RESTORE_WARNINGS #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** diff --git a/lv2/urid/urid.h b/lv2/urid/urid.h index 60aeffb..f9f1ad2 100644 --- a/lv2/urid/urid.h +++ b/lv2/urid/urid.h @@ -67,72 +67,70 @@ typedef uint32_t LV2_URID; URID Map Feature (LV2_URID__map) */ typedef struct { - /** - Opaque pointer to host data. + /** + Opaque pointer to host data. - This MUST be passed to map_uri() whenever it is called. - Otherwise, it must not be interpreted in any way. - */ - LV2_URID_Map_Handle handle; + This MUST be passed to map_uri() whenever it is called. + Otherwise, it must not be interpreted in any way. + */ + LV2_URID_Map_Handle handle; - /** - Get the numeric ID of a URI. + /** + Get the numeric ID of a URI. - If the ID does not already exist, it will be created. + If the ID does not already exist, it will be created. - This function is referentially transparent; any number of calls with the - same arguments is guaranteed to return the same value over the life of a - plugin instance. Note, however, that several URIs MAY resolve to the - same ID if the host considers those URIs equivalent. + This function is referentially transparent; any number of calls with the + same arguments is guaranteed to return the same value over the life of a + plugin instance. Note, however, that several URIs MAY resolve to the + same ID if the host considers those URIs equivalent. - This function is not necessarily very fast or RT-safe: plugins SHOULD - cache any IDs they might need in performance critical situations. + This function is not necessarily very fast or RT-safe: plugins SHOULD + cache any IDs they might need in performance critical situations. - The return value 0 is reserved and indicates that an ID for that URI - could not be created for whatever reason. However, hosts SHOULD NOT - return 0 from this function in non-exceptional circumstances (i.e. the - URI map SHOULD be dynamic). + The return value 0 is reserved and indicates that an ID for that URI + could not be created for whatever reason. However, hosts SHOULD NOT + return 0 from this function in non-exceptional circumstances (i.e. the + URI map SHOULD be dynamic). - @param handle Must be the callback_data member of this struct. - @param uri The URI to be mapped to an integer ID. - */ - LV2_URID (*map)(LV2_URID_Map_Handle handle, - const char* uri); + @param handle Must be the callback_data member of this struct. + @param uri The URI to be mapped to an integer ID. + */ + LV2_URID (*map)(LV2_URID_Map_Handle handle, const char* uri); } LV2_URID_Map; /** URI Unmap Feature (LV2_URID__unmap) */ typedef struct { - /** - Opaque pointer to host data. - - This MUST be passed to unmap() whenever it is called. - Otherwise, it must not be interpreted in any way. - */ - LV2_URID_Unmap_Handle handle; - - /** - Get the URI for a previously mapped numeric ID. - - Returns NULL if `urid` is not yet mapped. Otherwise, the corresponding - URI is returned in a canonical form. This MAY not be the exact same - string that was originally passed to LV2_URID_Map::map(), but it MUST be - an identical URI according to the URI syntax specification (RFC3986). A - non-NULL return for a given `urid` will always be the same for the life - of the plugin. Plugins that intend to perform string comparison on - unmapped URIs SHOULD first canonicalise URI strings with a call to - map_uri() followed by a call to unmap_uri(). - - @param handle Must be the callback_data member of this struct. - @param urid The ID to be mapped back to the URI string. - */ - const char* (*unmap)(LV2_URID_Unmap_Handle handle, - LV2_URID urid); + /** + Opaque pointer to host data. + + This MUST be passed to unmap() whenever it is called. + Otherwise, it must not be interpreted in any way. + */ + LV2_URID_Unmap_Handle handle; + + /** + Get the URI for a previously mapped numeric ID. + + Returns NULL if `urid` is not yet mapped. Otherwise, the corresponding + URI is returned in a canonical form. This MAY not be the exact same + string that was originally passed to LV2_URID_Map::map(), but it MUST be + an identical URI according to the URI syntax specification (RFC3986). A + non-NULL return for a given `urid` will always be the same for the life + of the plugin. Plugins that intend to perform string comparison on + unmapped URIs SHOULD first canonicalise URI strings with a call to + map_uri() followed by a call to unmap_uri(). + + @param handle Must be the callback_data member of this struct. + @param urid The ID to be mapped back to the URI string. + */ + const char* (*unmap)(LV2_URID_Unmap_Handle handle, LV2_URID urid); } LV2_URID_Unmap; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** diff --git a/lv2/worker/worker.h b/lv2/worker/worker.h index d9b1051..94e56b4 100644 --- a/lv2/worker/worker.h +++ b/lv2/worker/worker.h @@ -50,9 +50,9 @@ extern "C" { Status code for worker functions. */ typedef enum { - LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */ - LV2_WORKER_ERR_UNKNOWN = 1, /**< Unknown error. */ - LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */ + LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */ + LV2_WORKER_ERR_UNKNOWN = 1, /**< Unknown error. */ + LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */ } LV2_Worker_Status; /** Opaque handle for LV2_Worker_Interface::work(). */ @@ -66,9 +66,9 @@ typedef void* LV2_Worker_Respond_Handle; passed to work_response() if this function returns LV2_WORKER_SUCCESS. */ typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)( - LV2_Worker_Respond_Handle handle, - uint32_t size, - const void* data); + LV2_Worker_Respond_Handle handle, + uint32_t size, + const void* data); /** Plugin Worker Interface. @@ -78,52 +78,52 @@ typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)( when called with LV2_WORKER__interface as its argument. */ typedef struct { - /** - The worker method. This is called by the host in a non-realtime context - as requested, possibly with an arbitrary message to handle. - - A response can be sent to run() using `respond`. The plugin MUST NOT - make any assumptions about which thread calls this method, except that - there are no real-time requirements and only one call may be executed at - a time. That is, the host MAY call this method from any non-real-time - thread, but MUST NOT make concurrent calls to this method from several - threads. - - @param instance The LV2 instance this is a method on. - @param respond A function for sending a response to run(). - @param handle Must be passed to `respond` if it is called. - @param size The size of `data`. - @param data Data from run(), or NULL. - */ - LV2_Worker_Status (*work)(LV2_Handle instance, - LV2_Worker_Respond_Function respond, - LV2_Worker_Respond_Handle handle, - uint32_t size, - const void* data); - - /** - Handle a response from the worker. This is called by the host in the - run() context when a response from the worker is ready. - - @param instance The LV2 instance this is a method on. - @param size The size of `body`. - @param body Message body, or NULL. - */ - LV2_Worker_Status (*work_response)(LV2_Handle instance, - uint32_t size, - const void* body); - - /** - Called when all responses for this cycle have been delivered. - - Since work_response() may be called after run() finished, this provides - a hook for code that must run after the cycle is completed. - - This field may be NULL if the plugin has no use for it. Otherwise, the - host MUST call it after every run(), regardless of whether or not any - responses were sent that cycle. - */ - LV2_Worker_Status (*end_run)(LV2_Handle instance); + /** + The worker method. This is called by the host in a non-realtime context + as requested, possibly with an arbitrary message to handle. + + A response can be sent to run() using `respond`. The plugin MUST NOT + make any assumptions about which thread calls this method, except that + there are no real-time requirements and only one call may be executed at + a time. That is, the host MAY call this method from any non-real-time + thread, but MUST NOT make concurrent calls to this method from several + threads. + + @param instance The LV2 instance this is a method on. + @param respond A function for sending a response to run(). + @param handle Must be passed to `respond` if it is called. + @param size The size of `data`. + @param data Data from run(), or NULL. + */ + LV2_Worker_Status (*work)(LV2_Handle instance, + LV2_Worker_Respond_Function respond, + LV2_Worker_Respond_Handle handle, + uint32_t size, + const void* data); + + /** + Handle a response from the worker. This is called by the host in the + run() context when a response from the worker is ready. + + @param instance The LV2 instance this is a method on. + @param size The size of `body`. + @param body Message body, or NULL. + */ + LV2_Worker_Status (*work_response)(LV2_Handle instance, + uint32_t size, + const void* body); + + /** + Called when all responses for this cycle have been delivered. + + Since work_response() may be called after run() finished, this provides + a hook for code that must run after the cycle is completed. + + This field may be NULL if the plugin has no use for it. Otherwise, the + host MUST call it after every run(), regardless of whether or not any + responses were sent that cycle. + */ + LV2_Worker_Status (*end_run)(LV2_Handle instance); } LV2_Worker_Interface; /** Opaque handle for LV2_Worker_Schedule. */ @@ -136,48 +136,48 @@ typedef void* LV2_Worker_Schedule_Handle; the plugin can use to schedule a worker call from run(). */ typedef struct { - /** - Opaque host data. - */ - LV2_Worker_Schedule_Handle handle; - - /** - Request from run() that the host call the worker. - - This function is in the audio threading class. It should be called from - run() to request that the host call the work() method in a non-realtime - context with the given arguments. - - This function is always safe to call from run(), but it is not - guaranteed that the worker is actually called from a different thread. - In particular, when free-wheeling (for example, during offline - rendering), the worker may be executed immediately. This allows - single-threaded processing with sample accuracy and avoids timing - problems when run() is executing much faster or slower than real-time. - - Plugins SHOULD be written in such a way that if the worker runs - immediately, and responses from the worker are delivered immediately, - the effect of the work takes place immediately with sample accuracy. - - The `data` MUST be safe for the host to copy and later pass to work(), - and the host MUST guarantee that it will be eventually passed to work() - if this function returns LV2_WORKER_SUCCESS. - - @param handle The handle field of this struct. - @param size The size of `data`. - @param data Message to pass to work(), or NULL. - */ - LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle, - uint32_t size, - const void* data); + /** + Opaque host data. + */ + LV2_Worker_Schedule_Handle handle; + + /** + Request from run() that the host call the worker. + + This function is in the audio threading class. It should be called from + run() to request that the host call the work() method in a non-realtime + context with the given arguments. + + This function is always safe to call from run(), but it is not + guaranteed that the worker is actually called from a different thread. + In particular, when free-wheeling (for example, during offline + rendering), the worker may be executed immediately. This allows + single-threaded processing with sample accuracy and avoids timing + problems when run() is executing much faster or slower than real-time. + + Plugins SHOULD be written in such a way that if the worker runs + immediately, and responses from the worker are delivered immediately, + the effect of the work takes place immediately with sample accuracy. + + The `data` MUST be safe for the host to copy and later pass to work(), + and the host MUST guarantee that it will be eventually passed to work() + if this function returns LV2_WORKER_SUCCESS. + + @param handle The handle field of this struct. + @param size The size of `data`. + @param data Message to pass to work(), or NULL. + */ + LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle, + uint32_t size, + const void* data); } LV2_Worker_Schedule; #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif /** @} */ -#endif /* LV2_WORKER_H */ +#endif /* LV2_WORKER_H */ diff --git a/plugins/eg-amp.lv2/amp.c b/plugins/eg-amp.lv2/amp.c index 77cf83f..244825f 100644 --- a/plugins/eg-amp.lv2/amp.c +++ b/plugins/eg-amp.lv2/amp.c @@ -42,11 +42,7 @@ In code, ports are referred to by index. An enumeration of port indices should be defined for readability. */ -typedef enum { - AMP_GAIN = 0, - AMP_INPUT = 1, - AMP_OUTPUT = 2 -} PortIndex; +typedef enum { AMP_GAIN = 0, AMP_INPUT = 1, AMP_OUTPUT = 2 } PortIndex; /** Every plugin defines a private structure for the plugin instance. All data @@ -55,10 +51,10 @@ typedef enum { stored, since there is no additional instance data. */ typedef struct { - // Port buffers - const float* gain; - const float* input; - float* output; + // Port buffers + const float* gain; + const float* input; + float* output; } Amp; /** @@ -77,9 +73,9 @@ instantiate(const LV2_Descriptor* descriptor, const char* bundle_path, const LV2_Feature* const* features) { - Amp* amp = (Amp*)calloc(1, sizeof(Amp)); + Amp* amp = (Amp*)calloc(1, sizeof(Amp)); - return (LV2_Handle)amp; + return (LV2_Handle)amp; } /** @@ -91,23 +87,21 @@ instantiate(const LV2_Descriptor* descriptor, context as run(). */ static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Amp* amp = (Amp*)instance; - - switch ((PortIndex)port) { - case AMP_GAIN: - amp->gain = (const float*)data; - break; - case AMP_INPUT: - amp->input = (const float*)data; - break; - case AMP_OUTPUT: - amp->output = (float*)data; - break; - } + Amp* amp = (Amp*)instance; + + switch ((PortIndex)port) { + case AMP_GAIN: + amp->gain = (const float*)data; + break; + case AMP_INPUT: + amp->input = (const float*)data; + break; + case AMP_OUTPUT: + amp->output = (float*)data; + break; + } } /** @@ -121,11 +115,10 @@ connect_port(LV2_Handle instance, */ static void activate(LV2_Handle instance) -{ -} +{} /** Define a macro for converting a gain in dB to a coefficient. */ -#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g)*0.05f) : 0.0f) /** The `run()` method is the main process function of the plugin. It processes @@ -136,34 +129,33 @@ activate(LV2_Handle instance) static void run(LV2_Handle instance, uint32_t n_samples) { - const Amp* amp = (const Amp*)instance; + const Amp* amp = (const Amp*)instance; - const float gain = *(amp->gain); - const float* const input = amp->input; - float* const output = amp->output; + const float gain = *(amp->gain); + const float* const input = amp->input; + float* const output = amp->output; - const float coef = DB_CO(gain); + const float coef = DB_CO(gain); - for (uint32_t pos = 0; pos < n_samples; pos++) { - output[pos] = input[pos] * coef; - } + for (uint32_t pos = 0; pos < n_samples; pos++) { + output[pos] = input[pos] * coef; + } } /** - The `deactivate()` method is the counterpart to `activate()`, and is called by - the host after running the plugin. It indicates that the host will not call - `run()` again until another call to `activate()` and is mainly useful for more - advanced plugins with ``live'' characteristics such as those with auxiliary - processing threads. As with `activate()`, this plugin has no use for this - information so this method does nothing. + The `deactivate()` method is the counterpart to `activate()`, and is called + by the host after running the plugin. It indicates that the host will not + call `run()` again until another call to `activate()` and is mainly useful + for more advanced plugins with ``live'' characteristics such as those with + auxiliary processing threads. As with `activate()`, this plugin has no use + for this information so this method does nothing. This method is in the ``instantiation'' threading class, so no other methods on this instance will be called concurrently with it. */ static void deactivate(LV2_Handle instance) -{ -} +{} /** Destroy a plugin instance (counterpart to `instantiate()`). @@ -174,7 +166,7 @@ deactivate(LV2_Handle instance) static void cleanup(LV2_Handle instance) { - free(instance); + free(instance); } /** @@ -190,7 +182,7 @@ cleanup(LV2_Handle instance) static const void* extension_data(const char* uri) { - return NULL; + return NULL; } /** @@ -198,19 +190,17 @@ extension_data(const char* uri) descriptors statically to avoid leaking memory and non-portable shared library constructors and destructors to clean up properly. */ -static const LV2_Descriptor descriptor = { - AMP_URI, - instantiate, - connect_port, - activate, - run, - deactivate, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor = {AMP_URI, + instantiate, + connect_port, + activate, + run, + deactivate, + cleanup, + extension_data}; /** - The `lv2_descriptor()` function is the entry point to the plugin library. The + The `lv2_descriptor()` function is the entry point to the plugin library. The host will load the library and call this function repeatedly with increasing indices to find all the plugins defined in the library. The index is not an indentifier, the URI of the returned descriptor is used to determine the @@ -223,5 +213,5 @@ LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-fifths.lv2/fifths.c b/plugins/eg-fifths.lv2/fifths.c index bafd0d9..7527895 100644 --- a/plugins/eg-fifths.lv2/fifths.c +++ b/plugins/eg-fifths.lv2/fifths.c @@ -31,40 +31,35 @@ #include <stdio.h> #include <stdlib.h> -enum { - FIFTHS_IN = 0, - FIFTHS_OUT = 1 -}; +enum { FIFTHS_IN = 0, FIFTHS_OUT = 1 }; typedef struct { - // Features - LV2_URID_Map* map; - LV2_Log_Logger logger; + // Features + LV2_URID_Map* map; + LV2_Log_Logger logger; - // Ports - const LV2_Atom_Sequence* in_port; - LV2_Atom_Sequence* out_port; + // Ports + const LV2_Atom_Sequence* in_port; + LV2_Atom_Sequence* out_port; - // URIs - FifthsURIs uris; + // URIs + FifthsURIs uris; } Fifths; static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Fifths* self = (Fifths*)instance; - switch (port) { - case FIFTHS_IN: - self->in_port = (const LV2_Atom_Sequence*)data; - break; - case FIFTHS_OUT: - self->out_port = (LV2_Atom_Sequence*)data; - break; - default: - break; - } + Fifths* self = (Fifths*)instance; + switch (port) { + case FIFTHS_IN: + self->in_port = (const LV2_Atom_Sequence*)data; + break; + case FIFTHS_OUT: + self->out_port = (LV2_Atom_Sequence*)data; + break; + default: + break; + } } static LV2_Handle @@ -73,119 +68,115 @@ instantiate(const LV2_Descriptor* descriptor, const char* path, const LV2_Feature* const* features) { - // Allocate and initialise instance structure. - Fifths* self = (Fifths*)calloc(1, sizeof(Fifths)); - if (!self) { - return NULL; - } - - // Scan host features for URID map - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - map_fifths_uris(self->map, &self->uris); - - return (LV2_Handle)self; + // Allocate and initialise instance structure. + Fifths* self = (Fifths*)calloc(1, sizeof(Fifths)); + if (!self) { + return NULL; + } + + // Scan host features for URID map + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->logger.log, false, + LV2_URID__map, &self->map, true, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->logger, self->map); + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + map_fifths_uris(self->map, &self->uris); + + return (LV2_Handle)self; } static void cleanup(LV2_Handle instance) { - free(instance); + free(instance); } static void -run(LV2_Handle instance, - uint32_t sample_count) +run(LV2_Handle instance, uint32_t sample_count) { - Fifths* self = (Fifths*)instance; - FifthsURIs* uris = &self->uris; - - // Struct for a 3 byte MIDI event, used for writing notes - typedef struct { - LV2_Atom_Event event; - uint8_t msg[3]; - } MIDINoteEvent; - - // Initially self->out_port contains a Chunk with size set to capacity - - // Get the capacity - const uint32_t out_capacity = self->out_port->atom.size; - - // Write an empty Sequence header to the output - lv2_atom_sequence_clear(self->out_port); - self->out_port->atom.type = self->in_port->atom.type; - - // Read incoming events - LV2_ATOM_SEQUENCE_FOREACH(self->in_port, ev) { - if (ev->body.type == uris->midi_Event) { - const uint8_t* const msg = (const uint8_t*)(ev + 1); - switch (lv2_midi_message_type(msg)) { - case LV2_MIDI_MSG_NOTE_ON: - case LV2_MIDI_MSG_NOTE_OFF: - // Forward note to output - lv2_atom_sequence_append_event( - self->out_port, out_capacity, ev); - - if (msg[1] <= 127 - 7) { - // Make a note one 5th (7 semitones) higher than input - MIDINoteEvent fifth; - - // Could simply do fifth.event = *ev here instead... - fifth.event.time.frames = ev->time.frames; // Same time - fifth.event.body.type = ev->body.type; // Same type - fifth.event.body.size = ev->body.size; // Same size - - fifth.msg[0] = msg[0]; // Same status - fifth.msg[1] = msg[1] + 7; // Pitch up 7 semitones - fifth.msg[2] = msg[2]; // Same velocity - - // Write 5th event - lv2_atom_sequence_append_event( - self->out_port, out_capacity, &fifth.event); - } - break; - default: - // Forward all other MIDI events directly - lv2_atom_sequence_append_event( - self->out_port, out_capacity, ev); - break; - } - } - } + Fifths* self = (Fifths*)instance; + FifthsURIs* uris = &self->uris; + + // Struct for a 3 byte MIDI event, used for writing notes + typedef struct { + LV2_Atom_Event event; + uint8_t msg[3]; + } MIDINoteEvent; + + // Initially self->out_port contains a Chunk with size set to capacity + + // Get the capacity + const uint32_t out_capacity = self->out_port->atom.size; + + // Write an empty Sequence header to the output + lv2_atom_sequence_clear(self->out_port); + self->out_port->atom.type = self->in_port->atom.type; + + // Read incoming events + LV2_ATOM_SEQUENCE_FOREACH (self->in_port, ev) { + if (ev->body.type == uris->midi_Event) { + const uint8_t* const msg = (const uint8_t*)(ev + 1); + switch (lv2_midi_message_type(msg)) { + case LV2_MIDI_MSG_NOTE_ON: + case LV2_MIDI_MSG_NOTE_OFF: + // Forward note to output + lv2_atom_sequence_append_event(self->out_port, out_capacity, ev); + + if (msg[1] <= 127 - 7) { + // Make a note one 5th (7 semitones) higher than input + MIDINoteEvent fifth; + + // Could simply do fifth.event = *ev here instead... + fifth.event.time.frames = ev->time.frames; // Same time + fifth.event.body.type = ev->body.type; // Same type + fifth.event.body.size = ev->body.size; // Same size + + fifth.msg[0] = msg[0]; // Same status + fifth.msg[1] = msg[1] + 7; // Pitch up 7 semitones + fifth.msg[2] = msg[2]; // Same velocity + + // Write 5th event + lv2_atom_sequence_append_event( + self->out_port, out_capacity, &fifth.event); + } + break; + default: + // Forward all other MIDI events directly + lv2_atom_sequence_append_event(self->out_port, out_capacity, ev); + break; + } + } + } } static const void* extension_data(const char* uri) { - return NULL; + return NULL; } -static const LV2_Descriptor descriptor = { - EG_FIFTHS_URI, - instantiate, - connect_port, - NULL, // activate, - run, - NULL, // deactivate, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor = {EG_FIFTHS_URI, + instantiate, + connect_port, + NULL, // activate, + run, + NULL, // deactivate, + cleanup, + extension_data}; LV2_SYMBOL_EXPORT -const LV2_Descriptor* lv2_descriptor(uint32_t index) +const LV2_Descriptor* +lv2_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-fifths.lv2/uris.h b/plugins/eg-fifths.lv2/uris.h index 54a723d..d26577e 100644 --- a/plugins/eg-fifths.lv2/uris.h +++ b/plugins/eg-fifths.lv2/uris.h @@ -26,29 +26,29 @@ #define EG_FIFTHS_URI "http://lv2plug.in/plugins/eg-fifths" typedef struct { - LV2_URID atom_Path; - LV2_URID atom_Resource; - LV2_URID atom_Sequence; - LV2_URID atom_URID; - LV2_URID atom_eventTransfer; - LV2_URID midi_Event; - LV2_URID patch_Set; - LV2_URID patch_property; - LV2_URID patch_value; + LV2_URID atom_Path; + LV2_URID atom_Resource; + LV2_URID atom_Sequence; + LV2_URID atom_URID; + LV2_URID atom_eventTransfer; + LV2_URID midi_Event; + LV2_URID patch_Set; + LV2_URID patch_property; + LV2_URID patch_value; } FifthsURIs; static inline void map_fifths_uris(LV2_URID_Map* map, FifthsURIs* uris) { - uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); - uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); - uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); - uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); - uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); - uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); - uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); - uris->patch_property = map->map(map->handle, LV2_PATCH__property); - uris->patch_value = map->map(map->handle, LV2_PATCH__value); + uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); + uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); + uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); + uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); + uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); + uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); + uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); + uris->patch_property = map->map(map->handle, LV2_PATCH__property); + uris->patch_value = map->map(map->handle, LV2_PATCH__value); } -#endif /* FIFTHS_URIS_H */ +#endif /* FIFTHS_URIS_H */ diff --git a/plugins/eg-metro.lv2/metro.c b/plugins/eg-metro.lv2/metro.c index 6182a74..46ca41b 100644 --- a/plugins/eg-metro.lv2/metro.c +++ b/plugins/eg-metro.lv2/metro.c @@ -32,37 +32,34 @@ #include <string.h> #ifndef M_PI -# define M_PI 3.14159265 +# define M_PI 3.14159265 #endif #define EG_METRO_URI "http://lv2plug.in/plugins/eg-metro" typedef struct { - LV2_URID atom_Blank; - LV2_URID atom_Float; - LV2_URID atom_Object; - LV2_URID atom_Path; - LV2_URID atom_Resource; - LV2_URID atom_Sequence; - LV2_URID time_Position; - LV2_URID time_barBeat; - LV2_URID time_beatsPerMinute; - LV2_URID time_speed; + LV2_URID atom_Blank; + LV2_URID atom_Float; + LV2_URID atom_Object; + LV2_URID atom_Path; + LV2_URID atom_Resource; + LV2_URID atom_Sequence; + LV2_URID time_Position; + LV2_URID time_barBeat; + LV2_URID time_beatsPerMinute; + LV2_URID time_speed; } MetroURIs; static const double attack_s = 0.005; static const double decay_s = 0.075; -enum { - METRO_CONTROL = 0, - METRO_OUT = 1 -}; +enum { METRO_CONTROL = 0, METRO_OUT = 1 }; /** During execution this plugin can be in one of 3 states: */ typedef enum { - STATE_ATTACK, // Envelope rising - STATE_DECAY, // Envelope lowering - STATE_OFF // Silent + STATE_ATTACK, // Envelope rising + STATE_DECAY, // Envelope lowering + STATE_OFF // Silent } State; /** @@ -77,50 +74,48 @@ typedef enum { the user to modify these parameters, the frequency of the wave, and so on. */ typedef struct { - LV2_URID_Map* map; // URID map feature - LV2_Log_Logger logger; // Logger API - MetroURIs uris; // Cache of mapped URIDs - - struct { - LV2_Atom_Sequence* control; - float* output; - } ports; - - // Variables to keep track of the tempo information sent by the host - double rate; // Sample rate - float bpm; // Beats per minute (tempo) - float speed; // Transport speed (usually 0=stop, 1=play) - - uint32_t elapsed_len; // Frames since the start of the last click - uint32_t wave_offset; // Current play offset in the wave - State state; // Current play state - - // One cycle of a sine wave - float* wave; - uint32_t wave_len; - - // Envelope parameters - uint32_t attack_len; - uint32_t decay_len; + LV2_URID_Map* map; // URID map feature + LV2_Log_Logger logger; // Logger API + MetroURIs uris; // Cache of mapped URIDs + + struct { + LV2_Atom_Sequence* control; + float* output; + } ports; + + // Variables to keep track of the tempo information sent by the host + double rate; // Sample rate + float bpm; // Beats per minute (tempo) + float speed; // Transport speed (usually 0=stop, 1=play) + + uint32_t elapsed_len; // Frames since the start of the last click + uint32_t wave_offset; // Current play offset in the wave + State state; // Current play state + + // One cycle of a sine wave + float* wave; + uint32_t wave_len; + + // Envelope parameters + uint32_t attack_len; + uint32_t decay_len; } Metro; static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Metro* self = (Metro*)instance; - - switch (port) { - case METRO_CONTROL: - self->ports.control = (LV2_Atom_Sequence*)data; - break; - case METRO_OUT: - self->ports.output = (float*)data; - break; - default: - break; - } + Metro* self = (Metro*)instance; + + switch (port) { + case METRO_CONTROL: + self->ports.control = (LV2_Atom_Sequence*)data; + break; + case METRO_OUT: + self->ports.output = (float*)data; + break; + default: + break; + } } /** @@ -130,11 +125,11 @@ connect_port(LV2_Handle instance, static void activate(LV2_Handle instance) { - Metro* self = (Metro*)instance; + Metro* self = (Metro*)instance; - self->elapsed_len = 0; - self->wave_offset = 0; - self->state = STATE_OFF; + self->elapsed_len = 0; + self->wave_offset = 0; + self->state = STATE_OFF; } /** @@ -149,64 +144,64 @@ instantiate(const LV2_Descriptor* descriptor, const char* path, const LV2_Feature* const* features) { - Metro* self = (Metro*)calloc(1, sizeof(Metro)); - if (!self) { - return NULL; - } - - // Scan host features for URID map - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - // Map URIS - MetroURIs* const uris = &self->uris; - LV2_URID_Map* const map = self->map; - uris->atom_Blank = map->map(map->handle, LV2_ATOM__Blank); - uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); - uris->atom_Object = map->map(map->handle, LV2_ATOM__Object); - uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); - uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); - uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); - uris->time_Position = map->map(map->handle, LV2_TIME__Position); - uris->time_barBeat = map->map(map->handle, LV2_TIME__barBeat); - uris->time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute); - uris->time_speed = map->map(map->handle, LV2_TIME__speed); - - // Initialise instance fields - self->rate = rate; - self->bpm = 120.0f; - self->attack_len = (uint32_t)(attack_s * rate); - self->decay_len = (uint32_t)(decay_s * rate); - self->state = STATE_OFF; - - // Generate one cycle of a sine wave at the desired frequency - const double freq = 440.0 * 2.0; - const double amp = 0.5; - self->wave_len = (uint32_t)(rate / freq); - self->wave = (float*)malloc(self->wave_len * sizeof(float)); - for (uint32_t i = 0; i < self->wave_len; ++i) { - self->wave[i] = (float)(sin(i * 2 * M_PI * freq / rate) * amp); - } - - return (LV2_Handle)self; + Metro* self = (Metro*)calloc(1, sizeof(Metro)); + if (!self) { + return NULL; + } + + // Scan host features for URID map + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->logger.log, false, + LV2_URID__map, &self->map, true, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->logger, self->map); + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + // Map URIS + MetroURIs* const uris = &self->uris; + LV2_URID_Map* const map = self->map; + uris->atom_Blank = map->map(map->handle, LV2_ATOM__Blank); + uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); + uris->atom_Object = map->map(map->handle, LV2_ATOM__Object); + uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); + uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); + uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); + uris->time_Position = map->map(map->handle, LV2_TIME__Position); + uris->time_barBeat = map->map(map->handle, LV2_TIME__barBeat); + uris->time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute); + uris->time_speed = map->map(map->handle, LV2_TIME__speed); + + // Initialise instance fields + self->rate = rate; + self->bpm = 120.0f; + self->attack_len = (uint32_t)(attack_s * rate); + self->decay_len = (uint32_t)(decay_s * rate); + self->state = STATE_OFF; + + // Generate one cycle of a sine wave at the desired frequency + const double freq = 440.0 * 2.0; + const double amp = 0.5; + self->wave_len = (uint32_t)(rate / freq); + self->wave = (float*)malloc(self->wave_len * sizeof(float)); + for (uint32_t i = 0; i < self->wave_len; ++i) { + self->wave[i] = (float)(sin(i * 2 * M_PI * freq / rate) * amp); + } + + return (LV2_Handle)self; } static void cleanup(LV2_Handle instance) { - free(instance); + free(instance); } /** @@ -216,47 +211,47 @@ cleanup(LV2_Handle instance) static void play(Metro* self, uint32_t begin, uint32_t end) { - float* const output = self->ports.output; - const uint32_t frames_per_beat = 60.0f / self->bpm * self->rate; - - if (self->speed == 0.0f) { - memset(output, 0, (end - begin) * sizeof(float)); - return; - } - - for (uint32_t i = begin; i < end; ++i) { - switch (self->state) { - case STATE_ATTACK: - // Amplitude increases from 0..1 until attack_len - output[i] = self->wave[self->wave_offset] * - self->elapsed_len / (float)self->attack_len; - if (self->elapsed_len >= self->attack_len) { - self->state = STATE_DECAY; - } - break; - case STATE_DECAY: - // Amplitude decreases from 1..0 until attack_len + decay_len - output[i] = 0.0f; - output[i] = self->wave[self->wave_offset] * - (1 - ((float)(self->elapsed_len - self->attack_len) / - (float)self->decay_len)); - if (self->elapsed_len >= self->attack_len + self->decay_len) { - self->state = STATE_OFF; - } - break; - case STATE_OFF: - output[i] = 0.0f; - } - - // We continuously play the sine wave regardless of envelope - self->wave_offset = (self->wave_offset + 1) % self->wave_len; - - // Update elapsed time and start attack if necessary - if (++self->elapsed_len == frames_per_beat) { - self->state = STATE_ATTACK; - self->elapsed_len = 0; - } - } + float* const output = self->ports.output; + const uint32_t frames_per_beat = 60.0f / self->bpm * self->rate; + + if (self->speed == 0.0f) { + memset(output, 0, (end - begin) * sizeof(float)); + return; + } + + for (uint32_t i = begin; i < end; ++i) { + switch (self->state) { + case STATE_ATTACK: + // Amplitude increases from 0..1 until attack_len + output[i] = self->wave[self->wave_offset] * self->elapsed_len / + (float)self->attack_len; + if (self->elapsed_len >= self->attack_len) { + self->state = STATE_DECAY; + } + break; + case STATE_DECAY: + // Amplitude decreases from 1..0 until attack_len + decay_len + output[i] = 0.0f; + output[i] = self->wave[self->wave_offset] * + (1 - ((float)(self->elapsed_len - self->attack_len) / + (float)self->decay_len)); + if (self->elapsed_len >= self->attack_len + self->decay_len) { + self->state = STATE_OFF; + } + break; + case STATE_OFF: + output[i] = 0.0f; + } + + // We continuously play the sine wave regardless of envelope + self->wave_offset = (self->wave_offset + 1) % self->wave_len; + + // Update elapsed time and start attack if necessary + if (++self->elapsed_len == frames_per_beat) { + self->state = STATE_ATTACK; + self->elapsed_len = 0; + } + } } /** @@ -266,94 +261,92 @@ play(Metro* self, uint32_t begin, uint32_t end) static void update_position(Metro* self, const LV2_Atom_Object* obj) { - const MetroURIs* uris = &self->uris; - - // Received new transport position/speed - LV2_Atom* beat = NULL; - LV2_Atom* bpm = NULL; - LV2_Atom* speed = NULL; - - // clang-format off - lv2_atom_object_get(obj, - uris->time_barBeat, &beat, - uris->time_beatsPerMinute, &bpm, - uris->time_speed, &speed, - NULL); - // clang-format on - - if (bpm && bpm->type == uris->atom_Float) { - // Tempo changed, update BPM - self->bpm = ((LV2_Atom_Float*)bpm)->body; - } - if (speed && speed->type == uris->atom_Float) { - // Speed changed, e.g. 0 (stop) to 1 (play) - self->speed = ((LV2_Atom_Float*)speed)->body; - } - if (beat && beat->type == uris->atom_Float) { - // Received a beat position, synchronise - // This hard sync may cause clicks, a real plugin would be more graceful - const float frames_per_beat = (float)(60.0 / self->bpm * self->rate); - const float bar_beats = ((LV2_Atom_Float*)beat)->body; - const float beat_beats = bar_beats - floorf(bar_beats); - self->elapsed_len = beat_beats * frames_per_beat; - if (self->elapsed_len < self->attack_len) { - self->state = STATE_ATTACK; - } else if (self->elapsed_len < self->attack_len + self->decay_len) { - self->state = STATE_DECAY; - } else { - self->state = STATE_OFF; - } - } + const MetroURIs* uris = &self->uris; + + // Received new transport position/speed + LV2_Atom* beat = NULL; + LV2_Atom* bpm = NULL; + LV2_Atom* speed = NULL; + // clang-format off + lv2_atom_object_get(obj, + uris->time_barBeat, &beat, + uris->time_beatsPerMinute, &bpm, + uris->time_speed, &speed, + NULL); + // clang-format on + + if (bpm && bpm->type == uris->atom_Float) { + // Tempo changed, update BPM + self->bpm = ((LV2_Atom_Float*)bpm)->body; + } + if (speed && speed->type == uris->atom_Float) { + // Speed changed, e.g. 0 (stop) to 1 (play) + self->speed = ((LV2_Atom_Float*)speed)->body; + } + if (beat && beat->type == uris->atom_Float) { + // Received a beat position, synchronise + // This hard sync may cause clicks, a real plugin would be more graceful + const float frames_per_beat = (float)(60.0 / self->bpm * self->rate); + const float bar_beats = ((LV2_Atom_Float*)beat)->body; + const float beat_beats = bar_beats - floorf(bar_beats); + self->elapsed_len = beat_beats * frames_per_beat; + if (self->elapsed_len < self->attack_len) { + self->state = STATE_ATTACK; + } else if (self->elapsed_len < self->attack_len + self->decay_len) { + self->state = STATE_DECAY; + } else { + self->state = STATE_OFF; + } + } } static void run(LV2_Handle instance, uint32_t sample_count) { - Metro* self = (Metro*)instance; - const MetroURIs* uris = &self->uris; - - // Work forwards in time frame by frame, handling events as we go - const LV2_Atom_Sequence* in = self->ports.control; - uint32_t last_t = 0; - for (const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&in->body); - !lv2_atom_sequence_is_end(&in->body, in->atom.size, ev); - ev = lv2_atom_sequence_next(ev)) { - - // Play the click for the time slice from last_t until now - play(self, last_t, ev->time.frames); - - // Check if this event is an Object - // (or deprecated Blank to tolerate old hosts) - if (ev->body.type == uris->atom_Object || - ev->body.type == uris->atom_Blank) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; - if (obj->body.otype == uris->time_Position) { - // Received position information, update - update_position(self, obj); - } - } - - // Update time for next iteration and move to next event - last_t = ev->time.frames; - } - - // Play for remainder of cycle - play(self, last_t, sample_count); + Metro* self = (Metro*)instance; + const MetroURIs* uris = &self->uris; + + // Work forwards in time frame by frame, handling events as we go + const LV2_Atom_Sequence* in = self->ports.control; + uint32_t last_t = 0; + for (const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&in->body); + !lv2_atom_sequence_is_end(&in->body, in->atom.size, ev); + ev = lv2_atom_sequence_next(ev)) { + // Play the click for the time slice from last_t until now + play(self, last_t, ev->time.frames); + + // Check if this event is an Object + // (or deprecated Blank to tolerate old hosts) + if (ev->body.type == uris->atom_Object || + ev->body.type == uris->atom_Blank) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; + if (obj->body.otype == uris->time_Position) { + // Received position information, update + update_position(self, obj); + } + } + + // Update time for next iteration and move to next event + last_t = ev->time.frames; + } + + // Play for remainder of cycle + play(self, last_t, sample_count); } static const LV2_Descriptor descriptor = { - EG_METRO_URI, - instantiate, - connect_port, - activate, - run, - NULL, // deactivate, - cleanup, - NULL, // extension_data + EG_METRO_URI, + instantiate, + connect_port, + activate, + run, + NULL, // deactivate, + cleanup, + NULL, // extension_data }; LV2_SYMBOL_EXPORT const LV2_Descriptor* -lv2_descriptor(uint32_t index) + lv2_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-midigate.lv2/midigate.c b/plugins/eg-midigate.lv2/midigate.c index 5bffeea..5379440 100644 --- a/plugins/eg-midigate.lv2/midigate.c +++ b/plugins/eg-midigate.lv2/midigate.c @@ -32,27 +32,27 @@ #define MIDIGATE_URI "http://lv2plug.in/plugins/eg-midigate" typedef enum { - MIDIGATE_CONTROL = 0, - MIDIGATE_IN = 1, - MIDIGATE_OUT = 2 + MIDIGATE_CONTROL = 0, + MIDIGATE_IN = 1, + MIDIGATE_OUT = 2 } PortIndex; typedef struct { - // Port buffers - const LV2_Atom_Sequence* control; - const float* in; - float* out; + // Port buffers + const LV2_Atom_Sequence* control; + const float* in; + float* out; - // Features - LV2_URID_Map* map; - LV2_Log_Logger logger; + // Features + LV2_URID_Map* map; + LV2_Log_Logger logger; - struct { - LV2_URID midi_MidiEvent; - } uris; + struct { + LV2_URID midi_MidiEvent; + } uris; - unsigned n_active_notes; - unsigned program; // 0 = normal, 1 = inverted + unsigned n_active_notes; + unsigned program; // 0 = normal, 1 = inverted } Midigate; static LV2_Handle @@ -61,59 +61,57 @@ instantiate(const LV2_Descriptor* descriptor, const char* bundle_path, const LV2_Feature* const* features) { - Midigate* self = (Midigate*)calloc(1, sizeof(Midigate)); - if (!self) { - return NULL; - } - - // Scan host features for URID map - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - self->uris.midi_MidiEvent = self->map->map( - self->map->handle, LV2_MIDI__MidiEvent); - - return (LV2_Handle)self; + Midigate* self = (Midigate*)calloc(1, sizeof(Midigate)); + if (!self) { + return NULL; + } + + // Scan host features for URID map + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->logger.log, false, + LV2_URID__map, &self->map, true, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->logger, self->map); + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + self->uris.midi_MidiEvent = + self->map->map(self->map->handle, LV2_MIDI__MidiEvent); + + return (LV2_Handle)self; } static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Midigate* self = (Midigate*)instance; - - switch ((PortIndex)port) { - case MIDIGATE_CONTROL: - self->control = (const LV2_Atom_Sequence*)data; - break; - case MIDIGATE_IN: - self->in = (const float*)data; - break; - case MIDIGATE_OUT: - self->out = (float*)data; - break; - } + Midigate* self = (Midigate*)instance; + + switch ((PortIndex)port) { + case MIDIGATE_CONTROL: + self->control = (const LV2_Atom_Sequence*)data; + break; + case MIDIGATE_IN: + self->in = (const float*)data; + break; + case MIDIGATE_OUT: + self->out = (float*)data; + break; + } } static void activate(LV2_Handle instance) { - Midigate* self = (Midigate*)instance; - self->n_active_notes = 0; - self->program = 0; + Midigate* self = (Midigate*)instance; + self->n_active_notes = 0; + self->program = 0; } /** @@ -124,14 +122,13 @@ activate(LV2_Handle instance) static void write_output(Midigate* self, uint32_t offset, uint32_t len) { - const bool active = (self->program == 0) - ? (self->n_active_notes > 0) - : (self->n_active_notes == 0); - if (active) { - memcpy(self->out + offset, self->in + offset, len * sizeof(float)); - } else { - memset(self->out + offset, 0, len * sizeof(float)); - } + const bool active = (self->program == 0) ? (self->n_active_notes > 0) + : (self->n_active_notes == 0); + if (active) { + memcpy(self->out + offset, self->in + offset, len * sizeof(float)); + } else { + memset(self->out + offset, 0, len * sizeof(float)); + } } /** @@ -159,40 +156,41 @@ write_output(Midigate* self, uint32_t offset, uint32_t len) static void run(LV2_Handle instance, uint32_t sample_count) { - Midigate* self = (Midigate*)instance; - uint32_t offset = 0; - - LV2_ATOM_SEQUENCE_FOREACH(self->control, ev) { - if (ev->body.type == self->uris.midi_MidiEvent) { - const uint8_t* const msg = (const uint8_t*)(ev + 1); - switch (lv2_midi_message_type(msg)) { - case LV2_MIDI_MSG_NOTE_ON: - ++self->n_active_notes; - break; - case LV2_MIDI_MSG_NOTE_OFF: - if (self->n_active_notes > 0) { - --self->n_active_notes; - } - break; - case LV2_MIDI_MSG_CONTROLLER: - if (msg[1] == LV2_MIDI_CTL_ALL_NOTES_OFF) { - self->n_active_notes = 0; - } - break; - case LV2_MIDI_MSG_PGM_CHANGE: - if (msg[1] == 0 || msg[1] == 1) { - self->program = msg[1]; - } - break; - default: break; - } - } - - write_output(self, offset, ev->time.frames - offset); - offset = (uint32_t)ev->time.frames; - } - - write_output(self, offset, sample_count - offset); + Midigate* self = (Midigate*)instance; + uint32_t offset = 0; + + LV2_ATOM_SEQUENCE_FOREACH (self->control, ev) { + if (ev->body.type == self->uris.midi_MidiEvent) { + const uint8_t* const msg = (const uint8_t*)(ev + 1); + switch (lv2_midi_message_type(msg)) { + case LV2_MIDI_MSG_NOTE_ON: + ++self->n_active_notes; + break; + case LV2_MIDI_MSG_NOTE_OFF: + if (self->n_active_notes > 0) { + --self->n_active_notes; + } + break; + case LV2_MIDI_MSG_CONTROLLER: + if (msg[1] == LV2_MIDI_CTL_ALL_NOTES_OFF) { + self->n_active_notes = 0; + } + break; + case LV2_MIDI_MSG_PGM_CHANGE: + if (msg[1] == 0 || msg[1] == 1) { + self->program = msg[1]; + } + break; + default: + break; + } + } + + write_output(self, offset, ev->time.frames - offset); + offset = (uint32_t)ev->time.frames; + } + + write_output(self, offset, sample_count - offset); } /** @@ -207,7 +205,7 @@ deactivate(LV2_Handle instance) static void cleanup(LV2_Handle instance) { - free(instance); + free(instance); } /** @@ -216,23 +214,21 @@ cleanup(LV2_Handle instance) static const void* extension_data(const char* uri) { - return NULL; + return NULL; } -static const LV2_Descriptor descriptor = { - MIDIGATE_URI, - instantiate, - connect_port, - activate, - run, - deactivate, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor = {MIDIGATE_URI, + instantiate, + connect_port, + activate, + run, + deactivate, + cleanup, + extension_data}; LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-params.lv2/params.c b/plugins/eg-params.lv2/params.c index eadd144..56c39cd 100644 --- a/plugins/eg-params.lv2/params.c +++ b/plugins/eg-params.lv2/params.c @@ -37,106 +37,101 @@ #define MAX_STRING 1024 -#define EG_PARAMS_URI "http://lv2plug.in/plugins/eg-params" +#define EG_PARAMS_URI "http://lv2plug.in/plugins/eg-params" #define N_PROPS 9 typedef struct { - LV2_URID plugin; - LV2_URID atom_Path; - LV2_URID atom_Sequence; - LV2_URID atom_URID; - LV2_URID atom_eventTransfer; - LV2_URID eg_spring; - LV2_URID midi_Event; - LV2_URID patch_Get; - LV2_URID patch_Set; - LV2_URID patch_Put; - LV2_URID patch_body; - LV2_URID patch_subject; - LV2_URID patch_property; - LV2_URID patch_value; + LV2_URID plugin; + LV2_URID atom_Path; + LV2_URID atom_Sequence; + LV2_URID atom_URID; + LV2_URID atom_eventTransfer; + LV2_URID eg_spring; + LV2_URID midi_Event; + LV2_URID patch_Get; + LV2_URID patch_Set; + LV2_URID patch_Put; + LV2_URID patch_body; + LV2_URID patch_subject; + LV2_URID patch_property; + LV2_URID patch_value; } URIs; typedef struct { - LV2_Atom_Int aint; - LV2_Atom_Long along; - LV2_Atom_Float afloat; - LV2_Atom_Double adouble; - LV2_Atom_Bool abool; - LV2_Atom astring; - char string[MAX_STRING]; - LV2_Atom apath; - char path[MAX_STRING]; - LV2_Atom_Float lfo; - LV2_Atom_Float spring; + LV2_Atom_Int aint; + LV2_Atom_Long along; + LV2_Atom_Float afloat; + LV2_Atom_Double adouble; + LV2_Atom_Bool abool; + LV2_Atom astring; + char string[MAX_STRING]; + LV2_Atom apath; + char path[MAX_STRING]; + LV2_Atom_Float lfo; + LV2_Atom_Float spring; } State; static inline void map_uris(LV2_URID_Map* map, URIs* uris) { - uris->plugin = map->map(map->handle, EG_PARAMS_URI); - - uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); - uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); - uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); - uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); - uris->eg_spring = map->map(map->handle, EG_PARAMS_URI "#spring"); - uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); - uris->patch_Get = map->map(map->handle, LV2_PATCH__Get); - uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); - uris->patch_Put = map->map(map->handle, LV2_PATCH__Put); - uris->patch_body = map->map(map->handle, LV2_PATCH__body); - uris->patch_subject = map->map(map->handle, LV2_PATCH__subject); - uris->patch_property = map->map(map->handle, LV2_PATCH__property); - uris->patch_value = map->map(map->handle, LV2_PATCH__value); + uris->plugin = map->map(map->handle, EG_PARAMS_URI); + + uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); + uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); + uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); + uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); + uris->eg_spring = map->map(map->handle, EG_PARAMS_URI "#spring"); + uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); + uris->patch_Get = map->map(map->handle, LV2_PATCH__Get); + uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); + uris->patch_Put = map->map(map->handle, LV2_PATCH__Put); + uris->patch_body = map->map(map->handle, LV2_PATCH__body); + uris->patch_subject = map->map(map->handle, LV2_PATCH__subject); + uris->patch_property = map->map(map->handle, LV2_PATCH__property); + uris->patch_value = map->map(map->handle, LV2_PATCH__value); } -enum { - PARAMS_IN = 0, - PARAMS_OUT = 1 -}; +enum { PARAMS_IN = 0, PARAMS_OUT = 1 }; typedef struct { - // Features - LV2_URID_Map* map; - LV2_URID_Unmap* unmap; - LV2_Log_Logger log; + // Features + LV2_URID_Map* map; + LV2_URID_Unmap* unmap; + LV2_Log_Logger log; - // Forge for creating atoms - LV2_Atom_Forge forge; + // Forge for creating atoms + LV2_Atom_Forge forge; - // Ports - const LV2_Atom_Sequence* in_port; - LV2_Atom_Sequence* out_port; + // Ports + const LV2_Atom_Sequence* in_port; + LV2_Atom_Sequence* out_port; - // URIs - URIs uris; + // URIs + URIs uris; - // Plugin state - StateMapItem props[N_PROPS]; - State state; + // Plugin state + StateMapItem props[N_PROPS]; + State state; - // Buffer for making strings from URIDs if unmap is not provided - char urid_buf[12]; + // Buffer for making strings from URIDs if unmap is not provided + char urid_buf[12]; } Params; static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Params* self = (Params*)instance; - switch (port) { - case PARAMS_IN: - self->in_port = (const LV2_Atom_Sequence*)data; - break; - case PARAMS_OUT: - self->out_port = (LV2_Atom_Sequence*)data; - break; - default: - break; - } + Params* self = (Params*)instance; + switch (port) { + case PARAMS_IN: + self->in_port = (const LV2_Atom_Sequence*)data; + break; + case PARAMS_OUT: + self->out_port = (LV2_Atom_Sequence*)data; + break; + default: + break; + } } static LV2_Handle @@ -145,86 +140,83 @@ instantiate(const LV2_Descriptor* descriptor, const char* path, const LV2_Feature* const* features) { - // Allocate instance - Params* self = (Params*)calloc(1, sizeof(Params)); - if (!self) { - return NULL; - } - - // Get host features - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->log.log, false, - LV2_URID__map, &self->map, true, - LV2_URID__unmap, &self->unmap, false, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->log, self->map); - if (missing) { - lv2_log_error(&self->log, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - // Map URIs and initialise forge - map_uris(self->map, &self->uris); - lv2_atom_forge_init(&self->forge, self->map); - - // Initialise state dictionary - // clang-format off - State* state = &self->state; - state_map_init( - self->props, self->map, self->map->handle, - EG_PARAMS_URI "#int", STATE_MAP_INIT(Int, &state->aint), - EG_PARAMS_URI "#long", STATE_MAP_INIT(Long, &state->along), - EG_PARAMS_URI "#float", STATE_MAP_INIT(Float, &state->afloat), - EG_PARAMS_URI "#double", STATE_MAP_INIT(Double, &state->adouble), - EG_PARAMS_URI "#bool", STATE_MAP_INIT(Bool, &state->abool), - EG_PARAMS_URI "#string", STATE_MAP_INIT(String, &state->astring), - EG_PARAMS_URI "#path", STATE_MAP_INIT(Path, &state->apath), - EG_PARAMS_URI "#lfo", STATE_MAP_INIT(Float, &state->lfo), - EG_PARAMS_URI "#spring", STATE_MAP_INIT(Float, &state->spring), - NULL); - // clang-format on - - return (LV2_Handle)self; + // Allocate instance + Params* self = (Params*)calloc(1, sizeof(Params)); + if (!self) { + return NULL; + } + + // Get host features + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->log.log, false, + LV2_URID__map, &self->map, true, + LV2_URID__unmap, &self->unmap, false, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->log, self->map); + if (missing) { + lv2_log_error(&self->log, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + // Map URIs and initialise forge + map_uris(self->map, &self->uris); + lv2_atom_forge_init(&self->forge, self->map); + + // Initialise state dictionary + // clang-format off + State* state = &self->state; + state_map_init( + self->props, self->map, self->map->handle, + EG_PARAMS_URI "#int", STATE_MAP_INIT(Int, &state->aint), + EG_PARAMS_URI "#long", STATE_MAP_INIT(Long, &state->along), + EG_PARAMS_URI "#float", STATE_MAP_INIT(Float, &state->afloat), + EG_PARAMS_URI "#double", STATE_MAP_INIT(Double, &state->adouble), + EG_PARAMS_URI "#bool", STATE_MAP_INIT(Bool, &state->abool), + EG_PARAMS_URI "#string", STATE_MAP_INIT(String, &state->astring), + EG_PARAMS_URI "#path", STATE_MAP_INIT(Path, &state->apath), + EG_PARAMS_URI "#lfo", STATE_MAP_INIT(Float, &state->lfo), + EG_PARAMS_URI "#spring", STATE_MAP_INIT(Float, &state->spring), + NULL); + // clang-format on + + return (LV2_Handle)self; } static void cleanup(LV2_Handle instance) { - free(instance); + free(instance); } /** Helper function to unmap a URID if possible. */ static const char* unmap(Params* self, LV2_URID urid) { - if (self->unmap) { - return self->unmap->unmap(self->unmap->handle, urid); - } else { - snprintf(self->urid_buf, sizeof(self->urid_buf), "%u", urid); - return self->urid_buf; - } + if (self->unmap) { + return self->unmap->unmap(self->unmap->handle, urid); + } else { + snprintf(self->urid_buf, sizeof(self->urid_buf), "%u", urid); + return self->urid_buf; + } } static LV2_State_Status -check_type(Params* self, - LV2_URID key, - LV2_URID type, - LV2_URID required_type) +check_type(Params* self, LV2_URID key, LV2_URID type, LV2_URID required_type) { - if (type != required_type) { - lv2_log_trace( - &self->log, "Bad type <%s> for <%s> (needs <%s>)\n", - unmap(self, type), - unmap(self, key), - unmap(self, required_type)); - return LV2_STATE_ERR_BAD_TYPE; - } - return LV2_STATE_SUCCESS; + if (type != required_type) { + lv2_log_trace(&self->log, + "Bad type <%s> for <%s> (needs <%s>)\n", + unmap(self, type), + unmap(self, key), + unmap(self, required_type)); + return LV2_STATE_ERR_BAD_TYPE; + } + return LV2_STATE_SUCCESS; } static LV2_State_Status @@ -235,36 +227,36 @@ set_parameter(Params* self, const void* body, bool from_state) { - // Look up property in state dictionary - const StateMapItem* entry = state_map_find(self->props, N_PROPS, key); - if (!entry) { - lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key)); - return LV2_STATE_ERR_NO_PROPERTY; - } - - // Ensure given type matches property's type - if (check_type(self, key, type, entry->value->type)) { - return LV2_STATE_ERR_BAD_TYPE; - } - - // Set property value in state dictionary - lv2_log_trace(&self->log, "Set <%s>\n", entry->uri); - memcpy(entry->value + 1, body, size); - entry->value->size = size; - return LV2_STATE_SUCCESS; + // Look up property in state dictionary + const StateMapItem* entry = state_map_find(self->props, N_PROPS, key); + if (!entry) { + lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key)); + return LV2_STATE_ERR_NO_PROPERTY; + } + + // Ensure given type matches property's type + if (check_type(self, key, type, entry->value->type)) { + return LV2_STATE_ERR_BAD_TYPE; + } + + // Set property value in state dictionary + lv2_log_trace(&self->log, "Set <%s>\n", entry->uri); + memcpy(entry->value + 1, body, size); + entry->value->size = size; + return LV2_STATE_SUCCESS; } static const LV2_Atom* get_parameter(Params* self, LV2_URID key) { - const StateMapItem* entry = state_map_find(self->props, N_PROPS, key); - if (entry) { - lv2_log_trace(&self->log, "Get <%s>\n", entry->uri); - return entry->value; - } - - lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key)); - return NULL; + const StateMapItem* entry = state_map_find(self->props, N_PROPS, key); + if (entry) { + lv2_log_trace(&self->log, "Get <%s>\n", entry->uri); + return entry->value; + } + + lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key)); + return NULL; } static LV2_State_Status @@ -275,15 +267,15 @@ write_param_to_forge(LV2_State_Handle handle, uint32_t type, uint32_t flags) { - LV2_Atom_Forge* forge = (LV2_Atom_Forge*)handle; + LV2_Atom_Forge* forge = (LV2_Atom_Forge*)handle; - if (!lv2_atom_forge_key(forge, key) || - !lv2_atom_forge_atom(forge, size, type) || - !lv2_atom_forge_write(forge, value, size)) { - return LV2_STATE_ERR_UNKNOWN; - } + if (!lv2_atom_forge_key(forge, key) || + !lv2_atom_forge_atom(forge, size, type) || + !lv2_atom_forge_write(forge, value, size)) { + return LV2_STATE_ERR_UNKNOWN; + } - return LV2_STATE_SUCCESS; + return LV2_STATE_SUCCESS; } static void @@ -295,31 +287,31 @@ store_prop(Params* self, LV2_URID key, const LV2_Atom* value) { - LV2_State_Status st = LV2_STATE_SUCCESS; - if (map_path && value->type == self->uris.atom_Path) { - // Map path to abstract path for portable storage - const char* path = (const char*)(value + 1); - char* apath = map_path->abstract_path(map_path->handle, path); - st = store(handle, - key, - apath, - strlen(apath) + 1, - self->uris.atom_Path, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); - free(apath); - } else { - // Store simple property - st = store(handle, - key, - value + 1, - value->size, - value->type, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); - } - - if (save_status && !*save_status) { - *save_status = st; - } + LV2_State_Status st = LV2_STATE_SUCCESS; + if (map_path && value->type == self->uris.atom_Path) { + // Map path to abstract path for portable storage + const char* path = (const char*)(value + 1); + char* apath = map_path->abstract_path(map_path->handle, path); + st = store(handle, + key, + apath, + strlen(apath) + 1, + self->uris.atom_Path, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + free(apath); + } else { + // Store simple property + st = store(handle, + key, + value + 1, + value->size, + value->type, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + } + + if (save_status && !*save_status) { + *save_status = st; + } } /** @@ -336,17 +328,17 @@ save(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - Params* self = (Params*)instance; - LV2_State_Map_Path* map_path = (LV2_State_Map_Path*)lv2_features_data( - features, LV2_STATE__mapPath); + Params* self = (Params*)instance; + LV2_State_Map_Path* map_path = + (LV2_State_Map_Path*)lv2_features_data(features, LV2_STATE__mapPath); - LV2_State_Status st = LV2_STATE_SUCCESS; - for (unsigned i = 0; i < N_PROPS; ++i) { - StateMapItem* prop = &self->props[i]; - store_prop(self, map_path, &st, store, handle, prop->urid, prop->value); - } + LV2_State_Status st = LV2_STATE_SUCCESS; + for (unsigned i = 0; i < N_PROPS; ++i) { + StateMapItem* prop = &self->props[i]; + store_prop(self, map_path, &st, store, handle, prop->urid, prop->value); + } - return st; + return st; } static void @@ -356,20 +348,20 @@ retrieve_prop(Params* self, LV2_State_Handle handle, LV2_URID key) { - // Retrieve value from saved state - size_t vsize = 0; - uint32_t vtype = 0; - uint32_t vflags = 0; - const void* value = retrieve(handle, key, &vsize, &vtype, &vflags); - - // Set plugin instance state - const LV2_State_Status st = value - ? set_parameter(self, key, vsize, vtype, value, true) - : LV2_STATE_ERR_NO_PROPERTY; - - if (!*restore_status) { - *restore_status = st; // Set status if there has been no error yet - } + // Retrieve value from saved state + size_t vsize = 0; + uint32_t vtype = 0; + uint32_t vflags = 0; + const void* value = retrieve(handle, key, &vsize, &vtype, &vflags); + + // Set plugin instance state + const LV2_State_Status st = + value ? set_parameter(self, key, vsize, vtype, value, true) + : LV2_STATE_ERR_NO_PROPERTY; + + if (!*restore_status) { + *restore_status = st; // Set status if there has been no error yet + } } /** State restore method. */ @@ -380,160 +372,162 @@ restore(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - Params* self = (Params*)instance; - LV2_State_Status st = LV2_STATE_SUCCESS; + Params* self = (Params*)instance; + LV2_State_Status st = LV2_STATE_SUCCESS; - for (unsigned i = 0; i < N_PROPS; ++i) { - retrieve_prop(self, &st, retrieve, handle, self->props[i].urid); - } + for (unsigned i = 0; i < N_PROPS; ++i) { + retrieve_prop(self, &st, retrieve, handle, self->props[i].urid); + } - return st; + return st; } static inline bool subject_is_plugin(Params* self, const LV2_Atom_URID* subject) { - // This simple plugin only supports one subject: itself - return (!subject || (subject->atom.type == self->uris.atom_URID && - subject->body == self->uris.plugin)); + // This simple plugin only supports one subject: itself + return (!subject || (subject->atom.type == self->uris.atom_URID && + subject->body == self->uris.plugin)); } static void run(LV2_Handle instance, uint32_t sample_count) { - Params* self = (Params*)instance; - URIs* uris = &self->uris; - - // Initially, self->out_port contains a Chunk with size set to capacity - // Set up forge to write directly to output port - const uint32_t out_capacity = self->out_port->atom.size; - lv2_atom_forge_set_buffer(&self->forge, - (uint8_t*)self->out_port, - out_capacity); - - // Start a sequence in the output port - LV2_Atom_Forge_Frame out_frame; - lv2_atom_forge_sequence_head(&self->forge, &out_frame, 0); - - // Read incoming events - LV2_ATOM_SEQUENCE_FOREACH(self->in_port, ev) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; - if (obj->body.otype == uris->patch_Set) { - // Get the property and value of the set message - const LV2_Atom_URID* subject = NULL; - const LV2_Atom_URID* property = NULL; - const LV2_Atom* value = NULL; - - // clang-format off - lv2_atom_object_get(obj, - uris->patch_subject, (const LV2_Atom**)&subject, - uris->patch_property, (const LV2_Atom**)&property, - uris->patch_value, &value, - 0); - // clang-format on - - if (!subject_is_plugin(self, subject)) { - lv2_log_error(&self->log, "Set for unknown subject\n"); - } else if (!property) { - lv2_log_error(&self->log, "Set with no property\n"); - } else if (property->atom.type != uris->atom_URID) { - lv2_log_error(&self->log, "Set property is not a URID\n"); - } else { - // Set property to the given value - const LV2_URID key = property->body; - set_parameter(self, key, value->size, value->type, value + 1, false); - } - } else if (obj->body.otype == uris->patch_Get) { - // Get the property of the get message - const LV2_Atom_URID* subject = NULL; - const LV2_Atom_URID* property = NULL; - - // clang-format off - lv2_atom_object_get(obj, - uris->patch_subject, (const LV2_Atom**)&subject, - uris->patch_property, (const LV2_Atom**)&property, - 0); - // clang-format on - - if (!subject_is_plugin(self, subject)) { - lv2_log_error(&self->log, "Get with unknown subject\n"); - } else if (!property) { - // Get with no property, emit complete state - lv2_atom_forge_frame_time(&self->forge, ev->time.frames); - LV2_Atom_Forge_Frame pframe; - lv2_atom_forge_object(&self->forge, &pframe, 0, uris->patch_Put); - lv2_atom_forge_key(&self->forge, uris->patch_body); - - LV2_Atom_Forge_Frame bframe; - lv2_atom_forge_object(&self->forge, &bframe, 0, 0); - save(self, write_param_to_forge, &self->forge, 0, NULL); - - lv2_atom_forge_pop(&self->forge, &bframe); - lv2_atom_forge_pop(&self->forge, &pframe); - } else if (property->atom.type != uris->atom_URID) { - lv2_log_error(&self->log, "Get property is not a URID\n"); - } else { - // Get for a specific property - const LV2_URID key = property->body; - const LV2_Atom* value = get_parameter(self, key); - if (value) { - lv2_atom_forge_frame_time(&self->forge, ev->time.frames); - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set); - lv2_atom_forge_key(&self->forge, uris->patch_property); - lv2_atom_forge_urid(&self->forge, property->body); - store_prop(self, NULL, NULL, write_param_to_forge, &self->forge, - uris->patch_value, value); - lv2_atom_forge_pop(&self->forge, &frame); - } - } - } else { - lv2_log_trace(&self->log, "Unknown object type <%s>\n", - unmap(self, obj->body.otype)); - } - } - - if (self->state.spring.body > 0.0f) { - const float spring = self->state.spring.body; - self->state.spring.body = (spring >= 0.001) ? spring - 0.001f : 0.0f; - lv2_atom_forge_frame_time(&self->forge, 0); - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set); - - lv2_atom_forge_key(&self->forge, uris->patch_property); - lv2_atom_forge_urid(&self->forge, uris->eg_spring); - lv2_atom_forge_key(&self->forge, uris->patch_value); - lv2_atom_forge_float(&self->forge, self->state.spring.body); - - lv2_atom_forge_pop(&self->forge, &frame); - } - - lv2_atom_forge_pop(&self->forge, &out_frame); + Params* self = (Params*)instance; + URIs* uris = &self->uris; + + // Initially, self->out_port contains a Chunk with size set to capacity + // Set up forge to write directly to output port + const uint32_t out_capacity = self->out_port->atom.size; + lv2_atom_forge_set_buffer( + &self->forge, (uint8_t*)self->out_port, out_capacity); + + // Start a sequence in the output port + LV2_Atom_Forge_Frame out_frame; + lv2_atom_forge_sequence_head(&self->forge, &out_frame, 0); + + // Read incoming events + LV2_ATOM_SEQUENCE_FOREACH (self->in_port, ev) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; + if (obj->body.otype == uris->patch_Set) { + // Get the property and value of the set message + const LV2_Atom_URID* subject = NULL; + const LV2_Atom_URID* property = NULL; + const LV2_Atom* value = NULL; + + // clang-format off + lv2_atom_object_get(obj, + uris->patch_subject, (const LV2_Atom**)&subject, + uris->patch_property, (const LV2_Atom**)&property, + uris->patch_value, &value, + 0); + // clang-format on + + if (!subject_is_plugin(self, subject)) { + lv2_log_error(&self->log, "Set for unknown subject\n"); + } else if (!property) { + lv2_log_error(&self->log, "Set with no property\n"); + } else if (property->atom.type != uris->atom_URID) { + lv2_log_error(&self->log, "Set property is not a URID\n"); + } else { + // Set property to the given value + const LV2_URID key = property->body; + set_parameter(self, key, value->size, value->type, value + 1, false); + } + } else if (obj->body.otype == uris->patch_Get) { + // Get the property of the get message + const LV2_Atom_URID* subject = NULL; + const LV2_Atom_URID* property = NULL; + + // clang-format off + lv2_atom_object_get(obj, + uris->patch_subject, (const LV2_Atom**)&subject, + uris->patch_property, (const LV2_Atom**)&property, + 0); + // clang-format on + + if (!subject_is_plugin(self, subject)) { + lv2_log_error(&self->log, "Get with unknown subject\n"); + } else if (!property) { + // Get with no property, emit complete state + lv2_atom_forge_frame_time(&self->forge, ev->time.frames); + LV2_Atom_Forge_Frame pframe; + lv2_atom_forge_object(&self->forge, &pframe, 0, uris->patch_Put); + lv2_atom_forge_key(&self->forge, uris->patch_body); + + LV2_Atom_Forge_Frame bframe; + lv2_atom_forge_object(&self->forge, &bframe, 0, 0); + save(self, write_param_to_forge, &self->forge, 0, NULL); + + lv2_atom_forge_pop(&self->forge, &bframe); + lv2_atom_forge_pop(&self->forge, &pframe); + } else if (property->atom.type != uris->atom_URID) { + lv2_log_error(&self->log, "Get property is not a URID\n"); + } else { + // Get for a specific property + const LV2_URID key = property->body; + const LV2_Atom* value = get_parameter(self, key); + if (value) { + lv2_atom_forge_frame_time(&self->forge, ev->time.frames); + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set); + lv2_atom_forge_key(&self->forge, uris->patch_property); + lv2_atom_forge_urid(&self->forge, property->body); + store_prop(self, + NULL, + NULL, + write_param_to_forge, + &self->forge, + uris->patch_value, + value); + lv2_atom_forge_pop(&self->forge, &frame); + } + } + } else { + lv2_log_trace( + &self->log, "Unknown object type <%s>\n", unmap(self, obj->body.otype)); + } + } + + if (self->state.spring.body > 0.0f) { + const float spring = self->state.spring.body; + self->state.spring.body = (spring >= 0.001) ? spring - 0.001f : 0.0f; + lv2_atom_forge_frame_time(&self->forge, 0); + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set); + + lv2_atom_forge_key(&self->forge, uris->patch_property); + lv2_atom_forge_urid(&self->forge, uris->eg_spring); + lv2_atom_forge_key(&self->forge, uris->patch_value); + lv2_atom_forge_float(&self->forge, self->state.spring.body); + + lv2_atom_forge_pop(&self->forge, &frame); + } + + lv2_atom_forge_pop(&self->forge, &out_frame); } static const void* extension_data(const char* uri) { - static const LV2_State_Interface state = { save, restore }; - if (!strcmp(uri, LV2_STATE__interface)) { - return &state; - } - return NULL; + static const LV2_State_Interface state = {save, restore}; + if (!strcmp(uri, LV2_STATE__interface)) { + return &state; + } + return NULL; } -static const LV2_Descriptor descriptor = { - EG_PARAMS_URI, - instantiate, - connect_port, - NULL, // activate, - run, - NULL, // deactivate, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor = {EG_PARAMS_URI, + instantiate, + connect_port, + NULL, // activate, + run, + NULL, // deactivate, + cleanup, + extension_data}; LV2_SYMBOL_EXPORT const LV2_Descriptor* -lv2_descriptor(uint32_t index) + lv2_descriptor(uint32_t index) { - return (index == 0) ? &descriptor : NULL; + return (index == 0) ? &descriptor : NULL; } diff --git a/plugins/eg-params.lv2/state_map.h b/plugins/eg-params.lv2/state_map.h index 85358f8..f534f60 100644 --- a/plugins/eg-params.lv2/state_map.h +++ b/plugins/eg-params.lv2/state_map.h @@ -24,33 +24,31 @@ /** Entry in an array that serves as a dictionary of properties. */ typedef struct { - const char* uri; - LV2_URID urid; - LV2_Atom* value; + const char* uri; + LV2_URID urid; + LV2_Atom* value; } StateMapItem; /** Comparator for StateMapItems sorted by URID. */ static int state_map_cmp(const void* a, const void* b) { - const StateMapItem* ka = (const StateMapItem*)a; - const StateMapItem* kb = (const StateMapItem*)b; - if (ka->urid < kb->urid) { - return -1; - } + const StateMapItem* ka = (const StateMapItem*)a; + const StateMapItem* kb = (const StateMapItem*)b; + if (ka->urid < kb->urid) { + return -1; + } - if (kb->urid < ka->urid) { - return 1; - } + if (kb->urid < ka->urid) { + return 1; + } - return 0; + return 0; } /** Helper macro for terse state map initialisation. */ #define STATE_MAP_INIT(type, ptr) \ - (LV2_ATOM__ ## type), \ - (sizeof(*ptr) - sizeof(LV2_Atom)), \ - (ptr) + (LV2_ATOM__##type), (sizeof(*ptr) - sizeof(LV2_Atom)), (ptr) /** Initialise a state map. @@ -76,29 +74,30 @@ state_map_cmp(const void* a, const void* b) NULL); */ static void -state_map_init(StateMapItem dict[], - LV2_URID_Map* map, - LV2_URID_Map_Handle handle, - /* const char* uri, const char* type, uint32_t size, LV2_Atom* value */ ...) +state_map_init( + StateMapItem dict[], + LV2_URID_Map* map, + LV2_URID_Map_Handle handle, + /* const char* uri, const char* type, uint32_t size, LV2_Atom* value */...) { - // Set dict entries from parameters - unsigned i = 0; - va_list args; - va_start(args, handle); - for (const char* uri = NULL; (uri = va_arg(args, const char*)); ++i) { - const char* type = va_arg(args, const char*); - const uint32_t size = va_arg(args, uint32_t); - LV2_Atom* const value = va_arg(args, LV2_Atom*); - dict[i].uri = uri; - dict[i].urid = map->map(map->handle, uri); - dict[i].value = value; - dict[i].value->size = size; - dict[i].value->type = map->map(map->handle, type); - } - va_end(args); - - // Sort for fast lookup by URID by state_map_find() - qsort(dict, i, sizeof(StateMapItem), state_map_cmp); + // Set dict entries from parameters + unsigned i = 0; + va_list args; + va_start(args, handle); + for (const char* uri = NULL; (uri = va_arg(args, const char*)); ++i) { + const char* type = va_arg(args, const char*); + const uint32_t size = va_arg(args, uint32_t); + LV2_Atom* const value = va_arg(args, LV2_Atom*); + dict[i].uri = uri; + dict[i].urid = map->map(map->handle, uri); + dict[i].value = value; + dict[i].value->size = size; + dict[i].value->type = map->map(map->handle, type); + } + va_end(args); + + // Sort for fast lookup by URID by state_map_find() + qsort(dict, i, sizeof(StateMapItem), state_map_cmp); } /** @@ -111,8 +110,7 @@ state_map_init(StateMapItem dict[], static StateMapItem* state_map_find(StateMapItem dict[], uint32_t n_entries, LV2_URID urid) { - const StateMapItem key = { NULL, urid, NULL }; - return (StateMapItem*)bsearch( - &key, dict, n_entries, sizeof(StateMapItem), state_map_cmp); + const StateMapItem key = {NULL, urid, NULL}; + return (StateMapItem*)bsearch( + &key, dict, n_entries, sizeof(StateMapItem), state_map_cmp); } - diff --git a/plugins/eg-sampler.lv2/atom_sink.h b/plugins/eg-sampler.lv2/atom_sink.h index 659b767..57035e1 100644 --- a/plugins/eg-sampler.lv2/atom_sink.h +++ b/plugins/eg-sampler.lv2/atom_sink.h @@ -30,11 +30,11 @@ static LV2_Atom_Forge_Ref atom_sink(LV2_Atom_Forge_Sink_Handle handle, const void* buf, uint32_t size) { - LV2_Atom* atom = (LV2_Atom*)handle; - const uint32_t offset = lv2_atom_total_size(atom); - memcpy((char*)atom + offset, buf, size); - atom->size += size; - return offset; + LV2_Atom* atom = (LV2_Atom*)handle; + const uint32_t offset = lv2_atom_total_size(atom); + memcpy((char*)atom + offset, buf, size); + atom->size += size; + return offset; } /** @@ -43,5 +43,5 @@ atom_sink(LV2_Atom_Forge_Sink_Handle handle, const void* buf, uint32_t size) static LV2_Atom* atom_sink_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref) { - return (LV2_Atom*)((char*)handle + ref); + return (LV2_Atom*)((char*)handle + ref); } diff --git a/plugins/eg-sampler.lv2/peaks.h b/plugins/eg-sampler.lv2/peaks.h index 2bf1023..ca5328d 100644 --- a/plugins/eg-sampler.lv2/peaks.h +++ b/plugins/eg-sampler.lv2/peaks.h @@ -39,42 +39,42 @@ #include <stdlib.h> #include <string.h> -#define PEAKS_URI "http://lv2plug.in/ns/peaks#" -#define PEAKS__PeakUpdate PEAKS_URI "PeakUpdate" -#define PEAKS__magnitudes PEAKS_URI "magnitudes" -#define PEAKS__offset PEAKS_URI "offset" -#define PEAKS__total PEAKS_URI "total" +#define PEAKS_URI "http://lv2plug.in/ns/peaks#" +#define PEAKS__PeakUpdate PEAKS_URI "PeakUpdate" +#define PEAKS__magnitudes PEAKS_URI "magnitudes" +#define PEAKS__offset PEAKS_URI "offset" +#define PEAKS__total PEAKS_URI "total" #ifndef MIN -# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -# define MAX(a, b) (((a) > (b)) ? (a) : (b)) +# define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif typedef struct { - LV2_URID atom_Float; - LV2_URID atom_Int; - LV2_URID atom_Vector; - LV2_URID peaks_PeakUpdate; - LV2_URID peaks_magnitudes; - LV2_URID peaks_offset; - LV2_URID peaks_total; + LV2_URID atom_Float; + LV2_URID atom_Int; + LV2_URID atom_Vector; + LV2_URID peaks_PeakUpdate; + LV2_URID peaks_magnitudes; + LV2_URID peaks_offset; + LV2_URID peaks_total; } PeaksURIs; typedef struct { - PeaksURIs uris; ///< URIDs used in protocol - const float* samples; ///< Sample data - uint32_t n_samples; ///< Total number of samples - uint32_t n_peaks; ///< Total number of peaks - uint32_t current_offset; ///< Current peak offset - bool sending; ///< True iff currently sending + PeaksURIs uris; ///< URIDs used in protocol + const float* samples; ///< Sample data + uint32_t n_samples; ///< Total number of samples + uint32_t n_peaks; ///< Total number of peaks + uint32_t current_offset; ///< Current peak offset + bool sending; ///< True iff currently sending } PeaksSender; typedef struct { - PeaksURIs uris; ///< URIDs used in protocol - float* peaks; ///< Received peaks, or zeroes - uint32_t n_peaks; ///< Total number of peaks + PeaksURIs uris; ///< URIDs used in protocol + float* peaks; ///< Received peaks, or zeroes + uint32_t n_peaks; ///< Total number of peaks } PeaksReceiver; /** @@ -83,13 +83,13 @@ typedef struct { static inline void peaks_map_uris(PeaksURIs* uris, LV2_URID_Map* map) { - uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); - uris->atom_Int = map->map(map->handle, LV2_ATOM__Int); - uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector); - uris->peaks_PeakUpdate = map->map(map->handle, PEAKS__PeakUpdate); - uris->peaks_magnitudes = map->map(map->handle, PEAKS__magnitudes); - uris->peaks_offset = map->map(map->handle, PEAKS__offset); - uris->peaks_total = map->map(map->handle, PEAKS__total); + uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); + uris->atom_Int = map->map(map->handle, LV2_ATOM__Int); + uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector); + uris->peaks_PeakUpdate = map->map(map->handle, PEAKS__PeakUpdate); + uris->peaks_magnitudes = map->map(map->handle, PEAKS__magnitudes); + uris->peaks_offset = map->map(map->handle, PEAKS__offset); + uris->peaks_total = map->map(map->handle, PEAKS__total); } /** @@ -100,9 +100,9 @@ peaks_map_uris(PeaksURIs* uris, LV2_URID_Map* map) static inline PeaksSender* peaks_sender_init(PeaksSender* sender, LV2_URID_Map* map) { - memset(sender, 0, sizeof(*sender)); - peaks_map_uris(&sender->uris, map); - return sender; + memset(sender, 0, sizeof(*sender)); + peaks_map_uris(&sender->uris, map); + return sender; } /** @@ -115,11 +115,11 @@ peaks_sender_start(PeaksSender* sender, uint32_t n_samples, uint32_t n_peaks) { - sender->samples = samples; - sender->n_samples = n_samples; - sender->n_peaks = n_peaks; - sender->current_offset = 0; - sender->sending = true; + sender->samples = samples; + sender->n_samples = n_samples; + sender->n_peaks = n_peaks; + sender->current_offset = 0; + sender->sending = true; } /** @@ -129,10 +129,10 @@ peaks_sender_start(PeaksSender* sender, [source,turtle] ---- [] - a peaks:PeakUpdate ; - peaks:offset 256 ; - peaks:total 1024 ; - peaks:magnitudes [ 0.2f, 0.3f, ... ] . + a peaks:PeakUpdate ; + peaks:offset 256 ; + peaks:total 1024 ; + peaks:magnitudes [ 0.2f, 0.3f, ... ] . ---- */ static inline bool @@ -141,53 +141,53 @@ peaks_sender_send(PeaksSender* sender, uint32_t n_frames, uint32_t offset) { - const PeaksURIs* uris = &sender->uris; - if (!sender->sending || sender->current_offset >= sender->n_peaks) { - return sender->sending = false; - } - - // Start PeakUpdate object - lv2_atom_forge_frame_time(forge, offset); - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, uris->peaks_PeakUpdate); - - // eg:offset = OFFSET - lv2_atom_forge_key(forge, uris->peaks_offset); - lv2_atom_forge_int(forge, sender->current_offset); - - // eg:total = TOTAL - lv2_atom_forge_key(forge, uris->peaks_total); - lv2_atom_forge_int(forge, sender->n_peaks); - - // eg:magnitudes = Vector<Float>(PEAK, PEAK, ...) - lv2_atom_forge_key(forge, uris->peaks_magnitudes); - LV2_Atom_Forge_Frame vec_frame; - lv2_atom_forge_vector_head( - forge, &vec_frame, sizeof(float), uris->atom_Float); - - // Calculate how many peaks to send this update - const uint32_t chunk_size = MAX(1u, sender->n_samples / sender->n_peaks); - const uint32_t space = forge->size - forge->offset; - const uint32_t remaining = sender->n_peaks - sender->current_offset; - const uint32_t n_update = MIN(remaining, - MIN(n_frames / 4u, space / sizeof(float))); - - // Calculate peak (maximum magnitude) for each chunk - for (uint32_t i = 0; i < n_update; ++i) { - const uint32_t start = (sender->current_offset + i) * chunk_size; - float peak = 0.0f; - for (uint32_t j = 0; j < chunk_size; ++j) { - peak = fmaxf(peak, fabsf(sender->samples[start + j])); - } - lv2_atom_forge_float(forge, peak); - } - - // Finish message - lv2_atom_forge_pop(forge, &vec_frame); - lv2_atom_forge_pop(forge, &frame); - - sender->current_offset += n_update; - return true; + const PeaksURIs* uris = &sender->uris; + if (!sender->sending || sender->current_offset >= sender->n_peaks) { + return sender->sending = false; + } + + // Start PeakUpdate object + lv2_atom_forge_frame_time(forge, offset); + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_object(forge, &frame, 0, uris->peaks_PeakUpdate); + + // eg:offset = OFFSET + lv2_atom_forge_key(forge, uris->peaks_offset); + lv2_atom_forge_int(forge, sender->current_offset); + + // eg:total = TOTAL + lv2_atom_forge_key(forge, uris->peaks_total); + lv2_atom_forge_int(forge, sender->n_peaks); + + // eg:magnitudes = Vector<Float>(PEAK, PEAK, ...) + lv2_atom_forge_key(forge, uris->peaks_magnitudes); + LV2_Atom_Forge_Frame vec_frame; + lv2_atom_forge_vector_head( + forge, &vec_frame, sizeof(float), uris->atom_Float); + + // Calculate how many peaks to send this update + const uint32_t chunk_size = MAX(1u, sender->n_samples / sender->n_peaks); + const uint32_t space = forge->size - forge->offset; + const uint32_t remaining = sender->n_peaks - sender->current_offset; + const uint32_t n_update = + MIN(remaining, MIN(n_frames / 4u, space / sizeof(float))); + + // Calculate peak (maximum magnitude) for each chunk + for (uint32_t i = 0; i < n_update; ++i) { + const uint32_t start = (sender->current_offset + i) * chunk_size; + float peak = 0.0f; + for (uint32_t j = 0; j < chunk_size; ++j) { + peak = fmaxf(peak, fabsf(sender->samples[start + j])); + } + lv2_atom_forge_float(forge, peak); + } + + // Finish message + lv2_atom_forge_pop(forge, &vec_frame); + lv2_atom_forge_pop(forge, &frame); + + sender->current_offset += n_update; + return true; } /** @@ -197,9 +197,9 @@ peaks_sender_send(PeaksSender* sender, static inline PeaksReceiver* peaks_receiver_init(PeaksReceiver* receiver, LV2_URID_Map* map) { - memset(receiver, 0, sizeof(*receiver)); - peaks_map_uris(&receiver->uris, map); - return receiver; + memset(receiver, 0, sizeof(*receiver)); + peaks_map_uris(&receiver->uris, map); + return receiver; } /** @@ -209,9 +209,9 @@ peaks_receiver_init(PeaksReceiver* receiver, LV2_URID_Map* map) static inline void peaks_receiver_clear(PeaksReceiver* receiver) { - free(receiver->peaks); - receiver->peaks = NULL; - receiver->n_peaks = 0; + free(receiver->peaks); + receiver->peaks = NULL; + receiver->n_peaks = 0; } /** @@ -225,56 +225,56 @@ peaks_receiver_clear(PeaksReceiver* receiver) static inline int peaks_receiver_receive(PeaksReceiver* receiver, const LV2_Atom_Object* update) { - const PeaksURIs* uris = &receiver->uris; - - // Get properties of interest from update - const LV2_Atom_Int* offset = NULL; - const LV2_Atom_Int* total = NULL; - const LV2_Atom_Vector* peaks = NULL; - - // clang-format off - lv2_atom_object_get_typed(update, - uris->peaks_offset, &offset, uris->atom_Int, - uris->peaks_total, &total, uris->atom_Int, - uris->peaks_magnitudes, &peaks, uris->atom_Vector, - 0); - // clang-format on - - if (!offset || !total || !peaks || - peaks->body.child_type != uris->atom_Float) { - return -1; // Invalid update - } - - const uint32_t n = (uint32_t)total->body; - if (receiver->n_peaks != n) { - // Update is for a different total number of peaks, resize - receiver->peaks = (float*)realloc(receiver->peaks, n * sizeof(float)); - if (receiver->n_peaks > 0 && receiver->n_peaks < n) { - /* The peaks array is being expanded. Copy the old peaks, - duplicating each as necessary to fill the new peaks buffer. - This preserves the current peaks so that the peaks array can be - reasonably drawn at any time, but the resolution will increase - as new updates arrive. */ - const int64_t n_per = n / receiver->n_peaks; - for (int64_t i = n - 1; i >= 0; --i) { - receiver->peaks[i] = receiver->peaks[i / n_per]; - } - } else if (receiver->n_peaks > 0) { - /* The peak array is being shrunk. Similar to the above. */ - const int64_t n_per = receiver->n_peaks / n; - for (int64_t i = n - 1; i >= 0; --i) { - receiver->peaks[i] = receiver->peaks[i * n_per]; - } - } - receiver->n_peaks = n; - } - - // Copy vector contents to corresponding range in peaks array - memcpy(receiver->peaks + offset->body, - peaks + 1, - peaks->atom.size - sizeof(LV2_Atom_Vector_Body)); - - return 0; + const PeaksURIs* uris = &receiver->uris; + + // Get properties of interest from update + const LV2_Atom_Int* offset = NULL; + const LV2_Atom_Int* total = NULL; + const LV2_Atom_Vector* peaks = NULL; + + // clang-format off + lv2_atom_object_get_typed(update, + uris->peaks_offset, &offset, uris->atom_Int, + uris->peaks_total, &total, uris->atom_Int, + uris->peaks_magnitudes, &peaks, uris->atom_Vector, + 0); + // clang-format on + + if (!offset || !total || !peaks || + peaks->body.child_type != uris->atom_Float) { + return -1; // Invalid update + } + + const uint32_t n = (uint32_t)total->body; + if (receiver->n_peaks != n) { + // Update is for a different total number of peaks, resize + receiver->peaks = (float*)realloc(receiver->peaks, n * sizeof(float)); + if (receiver->n_peaks > 0 && receiver->n_peaks < n) { + /* The peaks array is being expanded. Copy the old peaks, + duplicating each as necessary to fill the new peaks buffer. + This preserves the current peaks so that the peaks array can be + reasonably drawn at any time, but the resolution will increase + as new updates arrive. */ + const int64_t n_per = n / receiver->n_peaks; + for (int64_t i = n - 1; i >= 0; --i) { + receiver->peaks[i] = receiver->peaks[i / n_per]; + } + } else if (receiver->n_peaks > 0) { + /* The peak array is being shrunk. Similar to the above. */ + const int64_t n_per = receiver->n_peaks / n; + for (int64_t i = n - 1; i >= 0; --i) { + receiver->peaks[i] = receiver->peaks[i * n_per]; + } + } + receiver->n_peaks = n; + } + + // Copy vector contents to corresponding range in peaks array + memcpy(receiver->peaks + offset->body, + peaks + 1, + peaks->atom.size - sizeof(LV2_Atom_Vector_Body)); + + return 0; } #endif // PEAKS_H_INCLUDED diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c index cd410d1..6c64df5 100644 --- a/plugins/eg-sampler.lv2/sampler.c +++ b/plugins/eg-sampler.lv2/sampler.c @@ -42,48 +42,44 @@ #include <stdlib.h> #include <string.h> -enum { - SAMPLER_CONTROL = 0, - SAMPLER_NOTIFY = 1, - SAMPLER_OUT = 2 -}; +enum { SAMPLER_CONTROL = 0, SAMPLER_NOTIFY = 1, SAMPLER_OUT = 2 }; typedef struct { - SF_INFO info; // Info about sample from sndfile - float* data; // Sample data in float - char* path; // Path of file - uint32_t path_len; // Length of path + SF_INFO info; // Info about sample from sndfile + float* data; // Sample data in float + char* path; // Path of file + uint32_t path_len; // Length of path } Sample; typedef struct { - // Features - LV2_URID_Map* map; - LV2_Worker_Schedule* schedule; - LV2_Log_Logger logger; - - // Ports - const LV2_Atom_Sequence* control_port; - LV2_Atom_Sequence* notify_port; - float* output_port; - - // Communication utilities - LV2_Atom_Forge_Frame notify_frame; ///< Cached for worker replies - LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread - PeaksSender psend; ///< Audio peaks sender - - // URIs - SamplerURIs uris; - - // Playback state - Sample* sample; - uint32_t frame_offset; - float gain; - float gain_dB; - sf_count_t frame; - bool play; - bool activated; - bool gain_changed; - bool sample_changed; + // Features + LV2_URID_Map* map; + LV2_Worker_Schedule* schedule; + LV2_Log_Logger logger; + + // Ports + const LV2_Atom_Sequence* control_port; + LV2_Atom_Sequence* notify_port; + float* output_port; + + // Communication utilities + LV2_Atom_Forge_Frame notify_frame; ///< Cached for worker replies + LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread + PeaksSender psend; ///< Audio peaks sender + + // URIs + SamplerURIs uris; + + // Playback state + Sample* sample; + uint32_t frame_offset; + float gain; + float gain_dB; + sf_count_t frame; + bool play; + bool activated; + bool gain_changed; + bool sample_changed; } Sampler; /** @@ -95,8 +91,8 @@ typedef struct { ringbuffer. */ typedef struct { - LV2_Atom atom; - Sample* sample; + LV2_Atom atom; + Sample* sample; } SampleMessage; /** @@ -109,53 +105,53 @@ typedef struct { static Sample* load_sample(LV2_Log_Logger* logger, const char* path) { - lv2_log_trace(logger, "Loading %s\n", path); - - const size_t path_len = strlen(path); - Sample* const sample = (Sample*)calloc(1, sizeof(Sample)); - SF_INFO* const info = &sample->info; - SNDFILE* const sndfile = sf_open(path, SFM_READ, info); - float* data = NULL; - bool error = true; - if (!sndfile || !info->frames) { - lv2_log_error(logger, "Failed to open %s\n", path); - } else if (info->channels != 1) { - lv2_log_error(logger, "%s has %d channels\n", path, info->channels); - } else if (!(data = (float*)malloc(sizeof(float) * info->frames))) { - lv2_log_error(logger, "Failed to allocate memory for sample\n"); - } else { - error = false; - } - - if (error) { - free(sample); - free(data); - sf_close(sndfile); - return NULL; - } - - sf_seek(sndfile, 0ul, SEEK_SET); - sf_read_float(sndfile, data, info->frames); - sf_close(sndfile); - - // Fill sample struct and return it - sample->data = data; - sample->path = (char*)malloc(path_len + 1); - sample->path_len = (uint32_t)path_len; - memcpy(sample->path, path, path_len + 1); - - return sample; + lv2_log_trace(logger, "Loading %s\n", path); + + const size_t path_len = strlen(path); + Sample* const sample = (Sample*)calloc(1, sizeof(Sample)); + SF_INFO* const info = &sample->info; + SNDFILE* const sndfile = sf_open(path, SFM_READ, info); + float* data = NULL; + bool error = true; + if (!sndfile || !info->frames) { + lv2_log_error(logger, "Failed to open %s\n", path); + } else if (info->channels != 1) { + lv2_log_error(logger, "%s has %d channels\n", path, info->channels); + } else if (!(data = (float*)malloc(sizeof(float) * info->frames))) { + lv2_log_error(logger, "Failed to allocate memory for sample\n"); + } else { + error = false; + } + + if (error) { + free(sample); + free(data); + sf_close(sndfile); + return NULL; + } + + sf_seek(sndfile, 0ul, SEEK_SET); + sf_read_float(sndfile, data, info->frames); + sf_close(sndfile); + + // Fill sample struct and return it + sample->data = data; + sample->path = (char*)malloc(path_len + 1); + sample->path_len = (uint32_t)path_len; + memcpy(sample->path, path, path_len + 1); + + return sample; } static void free_sample(Sampler* self, Sample* sample) { - if (sample) { - lv2_log_trace(&self->logger, "Freeing %s\n", sample->path); - free(sample->path); - free(sample->data); - free(sample); - } + if (sample) { + lv2_log_trace(&self->logger, "Freeing %s\n", sample->path); + free(sample->path); + free(sample->data); + free(sample); + } } /** @@ -172,30 +168,30 @@ work(LV2_Handle instance, uint32_t size, const void* data) { - Sampler* self = (Sampler*)instance; - const LV2_Atom* atom = (const LV2_Atom*)data; - if (atom->type == self->uris.eg_freeSample) { - // Free old sample - const SampleMessage* msg = (const SampleMessage*)data; - free_sample(self, msg->sample); - } else if (atom->type == self->forge.Object) { - // Handle set message (load sample). - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data; - const char* path = read_set_file(&self->uris, obj); - if (!path) { - lv2_log_error(&self->logger, "Malformed set file request\n"); - return LV2_WORKER_ERR_UNKNOWN; - } - - // Load sample. - Sample* sample = load_sample(&self->logger, path); - if (sample) { - // Send new sample to run() to be applied - respond(handle, sizeof(Sample*), &sample); - } - } - - return LV2_WORKER_SUCCESS; + Sampler* self = (Sampler*)instance; + const LV2_Atom* atom = (const LV2_Atom*)data; + if (atom->type == self->uris.eg_freeSample) { + // Free old sample + const SampleMessage* msg = (const SampleMessage*)data; + free_sample(self, msg->sample); + } else if (atom->type == self->forge.Object) { + // Handle set message (load sample). + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data; + const char* path = read_set_file(&self->uris, obj); + if (!path) { + lv2_log_error(&self->logger, "Malformed set file request\n"); + return LV2_WORKER_ERR_UNKNOWN; + } + + // Load sample. + Sample* sample = load_sample(&self->logger, path); + if (sample) { + // Send new sample to run() to be applied + respond(handle, sizeof(Sample*), &sample); + } + } + + return LV2_WORKER_SUCCESS; } /** @@ -206,50 +202,44 @@ work(LV2_Handle instance, scheduled. */ static LV2_Worker_Status -work_response(LV2_Handle instance, - uint32_t size, - const void* data) +work_response(LV2_Handle instance, uint32_t size, const void* data) { - Sampler* self = (Sampler*)instance; - Sample* old_sample = self->sample; - Sample* new_sample = *(Sample*const*)data; + Sampler* self = (Sampler*)instance; + Sample* old_sample = self->sample; + Sample* new_sample = *(Sample* const*)data; - // Install the new sample - self->sample = *(Sample*const*)data; + // Install the new sample + self->sample = *(Sample* const*)data; - // Schedule work to free the old sample - SampleMessage msg = { { sizeof(Sample*), self->uris.eg_freeSample }, - old_sample }; - self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg); + // Schedule work to free the old sample + SampleMessage msg = {{sizeof(Sample*), self->uris.eg_freeSample}, old_sample}; + self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg); - // Send a notification that we're using a new sample - lv2_atom_forge_frame_time(&self->forge, self->frame_offset); - write_set_file(&self->forge, &self->uris, - new_sample->path, - new_sample->path_len); + // Send a notification that we're using a new sample + lv2_atom_forge_frame_time(&self->forge, self->frame_offset); + write_set_file( + &self->forge, &self->uris, new_sample->path, new_sample->path_len); - return LV2_WORKER_SUCCESS; + return LV2_WORKER_SUCCESS; } static void -connect_port(LV2_Handle instance, - uint32_t port, - void* data) +connect_port(LV2_Handle instance, uint32_t port, void* data) { - Sampler* self = (Sampler*)instance; - switch (port) { - case SAMPLER_CONTROL: - self->control_port = (const LV2_Atom_Sequence*)data; - break; - case SAMPLER_NOTIFY: - self->notify_port = (LV2_Atom_Sequence*)data; - break; - case SAMPLER_OUT: - self->output_port = (float*)data; - break; - default: - break; - } + Sampler* self = (Sampler*)instance; + switch (port) { + case SAMPLER_CONTROL: + self->control_port = (const LV2_Atom_Sequence*)data; + break; + case SAMPLER_NOTIFY: + self->notify_port = (LV2_Atom_Sequence*)data; + break; + case SAMPLER_OUT: + self->output_port = (float*)data; + break; + default: + break; + } } static LV2_Handle @@ -258,62 +248,62 @@ instantiate(const LV2_Descriptor* descriptor, const char* path, const LV2_Feature* const* features) { - // Allocate and initialise instance structure. - Sampler* self = (Sampler*)calloc(1, sizeof(Sampler)); - if (!self) { - return NULL; - } - - // Get host features - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - LV2_WORKER__schedule, &self->schedule, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - // Map URIs and initialise forge - map_sampler_uris(self->map, &self->uris); - lv2_atom_forge_init(&self->forge, self->map); - peaks_sender_init(&self->psend, self->map); - - self->gain = 1.0f; - self->gain_dB = 0.0f; - - return (LV2_Handle)self; + // Allocate and initialise instance structure. + Sampler* self = (Sampler*)calloc(1, sizeof(Sampler)); + if (!self) { + return NULL; + } + + // Get host features + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->logger.log, false, + LV2_URID__map, &self->map, true, + LV2_WORKER__schedule, &self->schedule, true, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->logger, self->map); + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + // Map URIs and initialise forge + map_sampler_uris(self->map, &self->uris); + lv2_atom_forge_init(&self->forge, self->map); + peaks_sender_init(&self->psend, self->map); + + self->gain = 1.0f; + self->gain_dB = 0.0f; + + return (LV2_Handle)self; } static void cleanup(LV2_Handle instance) { - Sampler* self = (Sampler*)instance; - free_sample(self, self->sample); - free(self); + Sampler* self = (Sampler*)instance; + free_sample(self, self->sample); + free(self); } static void activate(LV2_Handle instance) { - ((Sampler*)instance)->activated = true; + ((Sampler*)instance)->activated = true; } static void deactivate(LV2_Handle instance) { - ((Sampler*)instance)->activated = false; + ((Sampler*)instance)->activated = false; } /** Define a macro for converting a gain in dB to a coefficient. */ -#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g)*0.05f) : 0.0f) /** Handle an incoming event in the audio thread. @@ -324,88 +314,86 @@ deactivate(LV2_Handle instance) static void handle_event(Sampler* self, LV2_Atom_Event* ev) { - SamplerURIs* uris = &self->uris; - PeaksURIs* peaks_uris = &self->psend.uris; - - if (ev->body.type == uris->midi_Event) { - const uint8_t* const msg = (const uint8_t*)(ev + 1); - switch (lv2_midi_message_type(msg)) { - case LV2_MIDI_MSG_NOTE_ON: - self->frame = 0; - self->play = true; - break; - default: - break; - } - } else if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; - if (obj->body.otype == uris->patch_Set) { - // Get the property and value of the set message - const LV2_Atom* property = NULL; - const LV2_Atom* value = NULL; - - // clang-format off - lv2_atom_object_get(obj, - uris->patch_property, &property, - uris->patch_value, &value, - 0); - // clang-format on - - if (!property) { - lv2_log_error(&self->logger, "Set message with no property\n"); - return; - } else if (property->type != uris->atom_URID) { - lv2_log_error(&self->logger, "Set property is not a URID\n"); - return; - } - - const uint32_t key = ((const LV2_Atom_URID*)property)->body; - if (key == uris->eg_sample) { - // Sample change, send it to the worker. - lv2_log_trace(&self->logger, "Scheduling sample change\n"); - self->schedule->schedule_work(self->schedule->handle, - lv2_atom_total_size(&ev->body), - &ev->body); - } else if (key == uris->param_gain) { - // Gain change - if (value->type == uris->atom_Float) { - self->gain_dB = ((LV2_Atom_Float*)value)->body; - self->gain = DB_CO(self->gain_dB); - } - } - } else if (obj->body.otype == uris->patch_Get && self->sample) { - const LV2_Atom_URID* accept = NULL; - const LV2_Atom_Int* n_peaks = NULL; - - // clang-format off - lv2_atom_object_get_typed( - obj, - uris->patch_accept, &accept, uris->atom_URID, - peaks_uris->peaks_total, &n_peaks, peaks_uris->atom_Int, 0); - // clang-format on - - if (accept && accept->body == peaks_uris->peaks_PeakUpdate) { - // Received a request for peaks, prepare for transmission - peaks_sender_start(&self->psend, - self->sample->data, - self->sample->info.frames, - n_peaks->body); - } else { - // Received a get message, emit our state (probably to UI) - lv2_atom_forge_frame_time(&self->forge, self->frame_offset); - write_set_file(&self->forge, &self->uris, - self->sample->path, - self->sample->path_len); - } - } else { - lv2_log_trace(&self->logger, - "Unknown object type %u\n", obj->body.otype); - } - } else { - lv2_log_trace(&self->logger, - "Unknown event type %u\n", ev->body.type); - } - + SamplerURIs* uris = &self->uris; + PeaksURIs* peaks_uris = &self->psend.uris; + + if (ev->body.type == uris->midi_Event) { + const uint8_t* const msg = (const uint8_t*)(ev + 1); + switch (lv2_midi_message_type(msg)) { + case LV2_MIDI_MSG_NOTE_ON: + self->frame = 0; + self->play = true; + break; + default: + break; + } + } else if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; + if (obj->body.otype == uris->patch_Set) { + // Get the property and value of the set message + const LV2_Atom* property = NULL; + const LV2_Atom* value = NULL; + + // clang-format off + lv2_atom_object_get(obj, + uris->patch_property, &property, + uris->patch_value, &value, + 0); + // clang-format on + + if (!property) { + lv2_log_error(&self->logger, "Set message with no property\n"); + return; + } else if (property->type != uris->atom_URID) { + lv2_log_error(&self->logger, "Set property is not a URID\n"); + return; + } + + const uint32_t key = ((const LV2_Atom_URID*)property)->body; + if (key == uris->eg_sample) { + // Sample change, send it to the worker. + lv2_log_trace(&self->logger, "Scheduling sample change\n"); + self->schedule->schedule_work( + self->schedule->handle, lv2_atom_total_size(&ev->body), &ev->body); + } else if (key == uris->param_gain) { + // Gain change + if (value->type == uris->atom_Float) { + self->gain_dB = ((LV2_Atom_Float*)value)->body; + self->gain = DB_CO(self->gain_dB); + } + } + } else if (obj->body.otype == uris->patch_Get && self->sample) { + const LV2_Atom_URID* accept = NULL; + const LV2_Atom_Int* n_peaks = NULL; + + // clang-format off + lv2_atom_object_get_typed( + obj, + uris->patch_accept, &accept, uris->atom_URID, + peaks_uris->peaks_total, &n_peaks, peaks_uris->atom_Int, + 0); + // clang-format on + + if (accept && accept->body == peaks_uris->peaks_PeakUpdate) { + // Received a request for peaks, prepare for transmission + peaks_sender_start(&self->psend, + self->sample->data, + self->sample->info.frames, + n_peaks->body); + } else { + // Received a get message, emit our state (probably to UI) + lv2_atom_forge_frame_time(&self->forge, self->frame_offset); + write_set_file(&self->forge, + &self->uris, + self->sample->path, + self->sample->path_len); + } + } else { + lv2_log_trace(&self->logger, "Unknown object type %u\n", obj->body.otype); + } + } else { + lv2_log_trace(&self->logger, "Unknown event type %u\n", ev->body.type); + } } /** @@ -414,78 +402,77 @@ handle_event(Sampler* self, LV2_Atom_Event* ev) static void render(Sampler* self, uint32_t start, uint32_t end) { - float* output = self->output_port; - - if (self->play && self->sample) { - // Start/continue writing sample to output - for (; start < end; ++start) { - output[start] = self->sample->data[self->frame] * self->gain; - if (++self->frame == self->sample->info.frames) { - self->play = false; // Reached end of sample - break; - } - } - } - - // Write silence to remaining buffer - for (; start < end; ++start) { - output[start] = 0.0f; - } + float* output = self->output_port; + + if (self->play && self->sample) { + // Start/continue writing sample to output + for (; start < end; ++start) { + output[start] = self->sample->data[self->frame] * self->gain; + if (++self->frame == self->sample->info.frames) { + self->play = false; // Reached end of sample + break; + } + } + } + + // Write silence to remaining buffer + for (; start < end; ++start) { + output[start] = 0.0f; + } } static void run(LV2_Handle instance, uint32_t sample_count) { - Sampler* self = (Sampler*)instance; - - // Set up forge to write directly to notify output port. - const uint32_t notify_capacity = self->notify_port->atom.size; - lv2_atom_forge_set_buffer(&self->forge, - (uint8_t*)self->notify_port, - notify_capacity); - - // Start a sequence in the notify output port. - lv2_atom_forge_sequence_head(&self->forge, &self->notify_frame, 0); - - // Send update to UI if gain or sample has changed due to state restore - if (self->gain_changed || self->sample_changed) { - lv2_atom_forge_frame_time(&self->forge, 0); - - if (self->gain_changed) { - write_set_gain(&self->forge, &self->uris, self->gain_dB); - self->gain_changed = false; - } - - if (self->sample_changed) { - write_set_file(&self->forge, &self->uris, - self->sample->path, - self->sample->path_len); - self->sample_changed = false; - } - } - - // Iterate over incoming events, emitting audio along the way - self->frame_offset = 0; - LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev) { - // Render output up to the time of this event - render(self, self->frame_offset, ev->time.frames); - - /* Update current frame offset to this event's time. This is stored in - the instance because it is used for sychronous worker event - execution. This allows a sample load event to be executed with - sample accuracy when running in a non-realtime context (such as - exporting a session). */ - self->frame_offset = ev->time.frames; - - // Process this event - handle_event(self, ev); - } - - // Use available space after any emitted events to send peaks - peaks_sender_send(&self->psend, &self->forge, sample_count, self->frame_offset); - - // Render output for the rest of the cycle past the last event - render(self, self->frame_offset, sample_count); + Sampler* self = (Sampler*)instance; + + // Set up forge to write directly to notify output port. + const uint32_t notify_capacity = self->notify_port->atom.size; + lv2_atom_forge_set_buffer( + &self->forge, (uint8_t*)self->notify_port, notify_capacity); + + // Start a sequence in the notify output port. + lv2_atom_forge_sequence_head(&self->forge, &self->notify_frame, 0); + + // Send update to UI if gain or sample has changed due to state restore + if (self->gain_changed || self->sample_changed) { + lv2_atom_forge_frame_time(&self->forge, 0); + + if (self->gain_changed) { + write_set_gain(&self->forge, &self->uris, self->gain_dB); + self->gain_changed = false; + } + + if (self->sample_changed) { + write_set_file( + &self->forge, &self->uris, self->sample->path, self->sample->path_len); + self->sample_changed = false; + } + } + + // Iterate over incoming events, emitting audio along the way + self->frame_offset = 0; + LV2_ATOM_SEQUENCE_FOREACH (self->control_port, ev) { + // Render output up to the time of this event + render(self, self->frame_offset, ev->time.frames); + + /* Update current frame offset to this event's time. This is stored in + the instance because it is used for sychronous worker event + execution. This allows a sample load event to be executed with + sample accuracy when running in a non-realtime context (such as + exporting a session). */ + self->frame_offset = ev->time.frames; + + // Process this event + handle_event(self, ev); + } + + // Use available space after any emitted events to send peaks + peaks_sender_send( + &self->psend, &self->forge, sample_count, self->frame_offset); + + // Render output for the rest of the cycle past the last event + render(self, self->frame_offset, sample_count); } static LV2_State_Status @@ -495,39 +482,39 @@ save(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - Sampler* self = (Sampler*)instance; - if (!self->sample) { - return LV2_STATE_SUCCESS; - } - - LV2_State_Map_Path* map_path = (LV2_State_Map_Path*)lv2_features_data( - features, LV2_STATE__mapPath); - if (!map_path) { - return LV2_STATE_ERR_NO_FEATURE; - } - - // Map absolute sample path to an abstract state path - char* apath = map_path->abstract_path(map_path->handle, self->sample->path); - - // Store eg:sample = abstract path - store(handle, - self->uris.eg_sample, - apath, - strlen(apath) + 1, - self->uris.atom_Path, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); - - free(apath); - - // Store the gain value - store(handle, - self->uris.param_gain, - &self->gain_dB, - sizeof(self->gain_dB), - self->uris.atom_Float, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); - - return LV2_STATE_SUCCESS; + Sampler* self = (Sampler*)instance; + if (!self->sample) { + return LV2_STATE_SUCCESS; + } + + LV2_State_Map_Path* map_path = + (LV2_State_Map_Path*)lv2_features_data(features, LV2_STATE__mapPath); + if (!map_path) { + return LV2_STATE_ERR_NO_FEATURE; + } + + // Map absolute sample path to an abstract state path + char* apath = map_path->abstract_path(map_path->handle, self->sample->path); + + // Store eg:sample = abstract path + store(handle, + self->uris.eg_sample, + apath, + strlen(apath) + 1, + self->uris.atom_Path, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + free(apath); + + // Store the gain value + store(handle, + self->uris.param_gain, + &self->gain_dB, + sizeof(self->gain_dB), + self->uris.atom_Float, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + return LV2_STATE_SUCCESS; } static LV2_State_Status @@ -537,113 +524,112 @@ restore(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - Sampler* self = (Sampler*)instance; - - // Get host features - LV2_Worker_Schedule* schedule = NULL; - LV2_State_Map_Path* paths = NULL; - - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_STATE__mapPath, &paths, true, - LV2_WORKER__schedule, &schedule, false, - NULL); - // clang-format on - - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - return LV2_STATE_ERR_NO_FEATURE; - } - - // Get eg:sample from state - size_t size = 0; - uint32_t type = 0; - uint32_t valflags = 0; - const void* value = retrieve(handle, self->uris.eg_sample, - &size, &type, &valflags); - if (!value) { - lv2_log_error(&self->logger, "Missing eg:sample\n"); - return LV2_STATE_ERR_NO_PROPERTY; - } else if (type != self->uris.atom_Path) { - lv2_log_error(&self->logger, "Non-path eg:sample\n"); - return LV2_STATE_ERR_BAD_TYPE; - } - - // Map abstract state path to absolute path - const char* apath = (const char*)value; - char* path = paths->absolute_path(paths->handle, apath); - - // Replace current sample with the new one - if (!self->activated || !schedule) { - // No scheduling available, load sample immediately - lv2_log_trace(&self->logger, "Synchronous restore\n"); - Sample* sample = load_sample(&self->logger, path); - if (sample) { - free_sample(self, self->sample); - self->sample = sample; - self->sample_changed = true; - } - } else { - // Schedule sample to be loaded by the provided worker - lv2_log_trace(&self->logger, "Scheduling restore\n"); - LV2_Atom_Forge forge; - LV2_Atom* buf = (LV2_Atom*)calloc(1, strlen(path) + 128); - lv2_atom_forge_init(&forge, self->map); - lv2_atom_forge_set_sink(&forge, atom_sink, atom_sink_deref, buf); - write_set_file(&forge, &self->uris, path, strlen(path)); - - const uint32_t msg_size = lv2_atom_pad_size(buf->size); - schedule->schedule_work(self->schedule->handle, msg_size, buf + 1); - free(buf); - } - - free(path); - - // Get param:gain from state - value = retrieve(handle, self->uris.param_gain, &size, &type, &valflags); - if (!value) { - // Not an error, since older versions did not save this property - lv2_log_note(&self->logger, "Missing param:gain\n"); - return LV2_STATE_SUCCESS; - } else if (type != self->uris.atom_Float) { - lv2_log_error(&self->logger, "Non-float param:gain\n"); - return LV2_STATE_ERR_BAD_TYPE; - } - - self->gain_dB = *(const float*)value; - self->gain = DB_CO(self->gain_dB); - self->gain_changed = true; - - return LV2_STATE_SUCCESS; + Sampler* self = (Sampler*)instance; + + // Get host features + LV2_Worker_Schedule* schedule = NULL; + LV2_State_Map_Path* paths = NULL; + + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_STATE__mapPath, &paths, true, + LV2_WORKER__schedule, &schedule, false, + NULL); + // clang-format on + + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + return LV2_STATE_ERR_NO_FEATURE; + } + + // Get eg:sample from state + size_t size = 0; + uint32_t type = 0; + uint32_t valflags = 0; + const void* value = + retrieve(handle, self->uris.eg_sample, &size, &type, &valflags); + if (!value) { + lv2_log_error(&self->logger, "Missing eg:sample\n"); + return LV2_STATE_ERR_NO_PROPERTY; + } else if (type != self->uris.atom_Path) { + lv2_log_error(&self->logger, "Non-path eg:sample\n"); + return LV2_STATE_ERR_BAD_TYPE; + } + + // Map abstract state path to absolute path + const char* apath = (const char*)value; + char* path = paths->absolute_path(paths->handle, apath); + + // Replace current sample with the new one + if (!self->activated || !schedule) { + // No scheduling available, load sample immediately + lv2_log_trace(&self->logger, "Synchronous restore\n"); + Sample* sample = load_sample(&self->logger, path); + if (sample) { + free_sample(self, self->sample); + self->sample = sample; + self->sample_changed = true; + } + } else { + // Schedule sample to be loaded by the provided worker + lv2_log_trace(&self->logger, "Scheduling restore\n"); + LV2_Atom_Forge forge; + LV2_Atom* buf = (LV2_Atom*)calloc(1, strlen(path) + 128); + lv2_atom_forge_init(&forge, self->map); + lv2_atom_forge_set_sink(&forge, atom_sink, atom_sink_deref, buf); + write_set_file(&forge, &self->uris, path, strlen(path)); + + const uint32_t msg_size = lv2_atom_pad_size(buf->size); + schedule->schedule_work(self->schedule->handle, msg_size, buf + 1); + free(buf); + } + + free(path); + + // Get param:gain from state + value = retrieve(handle, self->uris.param_gain, &size, &type, &valflags); + if (!value) { + // Not an error, since older versions did not save this property + lv2_log_note(&self->logger, "Missing param:gain\n"); + return LV2_STATE_SUCCESS; + } else if (type != self->uris.atom_Float) { + lv2_log_error(&self->logger, "Non-float param:gain\n"); + return LV2_STATE_ERR_BAD_TYPE; + } + + self->gain_dB = *(const float*)value; + self->gain = DB_CO(self->gain_dB); + self->gain_changed = true; + + return LV2_STATE_SUCCESS; } static const void* extension_data(const char* uri) { - static const LV2_State_Interface state = { save, restore }; - static const LV2_Worker_Interface worker = { work, work_response, NULL }; - if (!strcmp(uri, LV2_STATE__interface)) { - return &state; - } else if (!strcmp(uri, LV2_WORKER__interface)) { - return &worker; - } - return NULL; + static const LV2_State_Interface state = {save, restore}; + static const LV2_Worker_Interface worker = {work, work_response, NULL}; + if (!strcmp(uri, LV2_STATE__interface)) { + return &state; + } else if (!strcmp(uri, LV2_WORKER__interface)) { + return &worker; + } + return NULL; } -static const LV2_Descriptor descriptor = { - EG_SAMPLER_URI, - instantiate, - connect_port, - activate, - run, - deactivate, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor = {EG_SAMPLER_URI, + instantiate, + connect_port, + activate, + run, + deactivate, + cleanup, + extension_data}; LV2_SYMBOL_EXPORT -const LV2_Descriptor* lv2_descriptor(uint32_t index) +const LV2_Descriptor* +lv2_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-sampler.lv2/sampler_ui.c b/plugins/eg-sampler.lv2/sampler_ui.c index f733216..533e720 100644 --- a/plugins/eg-sampler.lv2/sampler_ui.c +++ b/plugins/eg-sampler.lv2/sampler_ui.c @@ -48,195 +48,198 @@ #define MIN_CANVAS_H 80 typedef struct { - LV2_Atom_Forge forge; - LV2_URID_Map* map; - LV2UI_Request_Value* request_value; - LV2_Log_Logger logger; - SamplerURIs uris; - PeaksReceiver precv; - - LV2UI_Write_Function write; - LV2UI_Controller controller; - - GtkWidget* box; - GtkWidget* play_button; - GtkWidget* file_button; - GtkWidget* request_file_button; - GtkWidget* button_box; - GtkWidget* canvas; - - uint32_t width; - uint32_t requested_n_peaks; - char* filename; - - uint8_t forge_buf[1024]; - - // Optional show/hide interface - GtkWidget* window; - bool did_init; + LV2_Atom_Forge forge; + LV2_URID_Map* map; + LV2UI_Request_Value* request_value; + LV2_Log_Logger logger; + SamplerURIs uris; + PeaksReceiver precv; + + LV2UI_Write_Function write; + LV2UI_Controller controller; + + GtkWidget* box; + GtkWidget* play_button; + GtkWidget* file_button; + GtkWidget* request_file_button; + GtkWidget* button_box; + GtkWidget* canvas; + + uint32_t width; + uint32_t requested_n_peaks; + char* filename; + + uint8_t forge_buf[1024]; + + // Optional show/hide interface + GtkWidget* window; + bool did_init; } SamplerUI; static void on_file_set(GtkFileChooserButton* widget, void* handle) { - SamplerUI* ui = (SamplerUI*)handle; + SamplerUI* ui = (SamplerUI*)handle; - // Get the filename from the file chooser - char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); + // Get the filename from the file chooser + char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); - // Write a set message to the plugin to load new file - lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); - LV2_Atom* msg = (LV2_Atom*)write_set_file(&ui->forge, &ui->uris, - filename, strlen(filename)); + // Write a set message to the plugin to load new file + lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); + LV2_Atom* msg = (LV2_Atom*)write_set_file( + &ui->forge, &ui->uris, filename, strlen(filename)); - assert(msg); + assert(msg); - ui->write(ui->controller, 0, lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); - g_free(filename); + g_free(filename); } static void on_request_file(GtkButton* widget, void* handle) { - SamplerUI* ui = (SamplerUI*)handle; + SamplerUI* ui = (SamplerUI*)handle; - ui->request_value->request(ui->request_value->handle, - ui->uris.eg_sample, - 0, - NULL); + ui->request_value->request( + ui->request_value->handle, ui->uris.eg_sample, 0, NULL); } static void on_play_clicked(GtkFileChooserButton* widget, void* handle) { - SamplerUI* ui = (SamplerUI*)handle; - struct { - LV2_Atom atom; - uint8_t msg[3]; - } note_on; - - note_on.atom.type = ui->uris.midi_Event; - note_on.atom.size = 3; - note_on.msg[0] = LV2_MIDI_MSG_NOTE_ON; - note_on.msg[1] = 60; - note_on.msg[2] = 60; - ui->write(ui->controller, 0, sizeof(LV2_Atom) + 3, - ui->uris.atom_eventTransfer, - ¬e_on); + SamplerUI* ui = (SamplerUI*)handle; + struct { + LV2_Atom atom; + uint8_t msg[3]; + } note_on; + + note_on.atom.type = ui->uris.midi_Event; + note_on.atom.size = 3; + note_on.msg[0] = LV2_MIDI_MSG_NOTE_ON; + note_on.msg[1] = 60; + note_on.msg[2] = 60; + ui->write(ui->controller, + 0, + sizeof(LV2_Atom) + 3, + ui->uris.atom_eventTransfer, + ¬e_on); } static void request_peaks(SamplerUI* ui, uint32_t n_peaks) { - if (n_peaks == ui->requested_n_peaks) { - return; - } - - lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); - - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.patch_Get); - lv2_atom_forge_key(&ui->forge, ui->uris.patch_accept); - lv2_atom_forge_urid(&ui->forge, ui->precv.uris.peaks_PeakUpdate); - lv2_atom_forge_key(&ui->forge, ui->precv.uris.peaks_total); - lv2_atom_forge_int(&ui->forge, n_peaks); - lv2_atom_forge_pop(&ui->forge, &frame); - - LV2_Atom* msg = lv2_atom_forge_deref(&ui->forge, frame.ref); - ui->write(ui->controller, 0, lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); - - ui->requested_n_peaks = n_peaks; + if (n_peaks == ui->requested_n_peaks) { + return; + } + + lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); + + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.patch_Get); + lv2_atom_forge_key(&ui->forge, ui->uris.patch_accept); + lv2_atom_forge_urid(&ui->forge, ui->precv.uris.peaks_PeakUpdate); + lv2_atom_forge_key(&ui->forge, ui->precv.uris.peaks_total); + lv2_atom_forge_int(&ui->forge, n_peaks); + lv2_atom_forge_pop(&ui->forge, &frame); + + LV2_Atom* msg = lv2_atom_forge_deref(&ui->forge, frame.ref); + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); + + ui->requested_n_peaks = n_peaks; } /** Set Cairo color to a GDK color (to follow Gtk theme). */ static void cairo_set_source_gdk(cairo_t* cr, const GdkColor* color) { - cairo_set_source_rgb( - cr, color->red / 65535.0, color->green / 65535.0, color->blue / 65535.0); - + cairo_set_source_rgb( + cr, color->red / 65535.0, color->green / 65535.0, color->blue / 65535.0); } static gboolean on_canvas_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data) { - SamplerUI* ui = (SamplerUI*)data; + SamplerUI* ui = (SamplerUI*)data; - GtkAllocation size; - gtk_widget_get_allocation(widget, &size); + GtkAllocation size; + gtk_widget_get_allocation(widget, &size); - ui->width = size.width; - if (ui->width > 2 * ui->requested_n_peaks) { - request_peaks(ui, 2 * ui->requested_n_peaks); - } + ui->width = size.width; + if (ui->width > 2 * ui->requested_n_peaks) { + request_peaks(ui, 2 * ui->requested_n_peaks); + } - cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); - cairo_set_line_width(cr, 1.0); - cairo_translate(cr, 0.5, 0.5); + cairo_set_line_width(cr, 1.0); + cairo_translate(cr, 0.5, 0.5); - const double mid_y = size.height / 2.0; + const double mid_y = size.height / 2.0; - const float* const peaks = ui->precv.peaks; - const int32_t n_peaks = ui->precv.n_peaks; - if (peaks) { - // Draw waveform - const double scale = size.width / ((double)n_peaks - 1.0f); + const float* const peaks = ui->precv.peaks; + const int32_t n_peaks = ui->precv.n_peaks; + if (peaks) { + // Draw waveform + const double scale = size.width / ((double)n_peaks - 1.0f); - // Start at left origin - cairo_move_to(cr, 0, mid_y); + // Start at left origin + cairo_move_to(cr, 0, mid_y); - // Draw line through top peaks - for (int i = 0; i < n_peaks; ++i) { - const float peak = peaks[i]; - cairo_line_to(cr, i * scale, mid_y + (peak / 2.0f) * size.height); - } + // Draw line through top peaks + for (int i = 0; i < n_peaks; ++i) { + const float peak = peaks[i]; + cairo_line_to(cr, i * scale, mid_y + (peak / 2.0f) * size.height); + } - // Continue through bottom peaks - for (int i = n_peaks - 1; i >= 0; --i) { - const float peak = peaks[i]; - cairo_line_to(cr, i * scale, mid_y - (peak / 2.0f) * size.height); - } + // Continue through bottom peaks + for (int i = n_peaks - 1; i >= 0; --i) { + const float peak = peaks[i]; + cairo_line_to(cr, i * scale, mid_y - (peak / 2.0f) * size.height); + } - // Close shape - cairo_line_to(cr, 0, mid_y); + // Close shape + cairo_line_to(cr, 0, mid_y); - cairo_set_source_gdk(cr, widget->style->mid); - cairo_fill_preserve(cr); + cairo_set_source_gdk(cr, widget->style->mid); + cairo_fill_preserve(cr); - cairo_set_source_gdk(cr, widget->style->fg); - cairo_stroke(cr); - } + cairo_set_source_gdk(cr, widget->style->fg); + cairo_stroke(cr); + } - cairo_destroy(cr); - return TRUE; + cairo_destroy(cr); + return TRUE; } static void destroy_window(SamplerUI* ui) { - if (ui->window) { - gtk_container_remove(GTK_CONTAINER(ui->window), ui->box); - gtk_widget_destroy(ui->window); - ui->window = NULL; - } + if (ui->window) { + gtk_container_remove(GTK_CONTAINER(ui->window), ui->box); + gtk_widget_destroy(ui->window); + ui->window = NULL; + } } static gboolean on_window_closed(GtkWidget* widget, GdkEvent* event, gpointer data) { - SamplerUI* ui = (SamplerUI*)data; + SamplerUI* ui = (SamplerUI*)data; - // Remove widget so Gtk doesn't delete it when the window is closed - gtk_container_remove(GTK_CONTAINER(ui->window), ui->box); - ui->window = NULL; + // Remove widget so Gtk doesn't delete it when the window is closed + gtk_container_remove(GTK_CONTAINER(ui->window), ui->box); + ui->window = NULL; - return FALSE; + return FALSE; } static LV2UI_Handle @@ -248,103 +251,104 @@ instantiate(const LV2UI_Descriptor* descriptor, LV2UI_Widget* widget, const LV2_Feature* const* features) { - SamplerUI* ui = (SamplerUI*)calloc(1, sizeof(SamplerUI)); - if (!ui) { - return NULL; - } - - ui->write = write_function; - ui->controller = controller; - ui->width = MIN_CANVAS_W; - *widget = NULL; - ui->window = NULL; - ui->did_init = false; - - // Get host features - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &ui->logger.log , false, - LV2_URID__map, &ui->map, true, - LV2_UI__requestValue, &ui->request_value, false, - NULL); - // clang-format on - - lv2_log_logger_set_map(&ui->logger, ui->map); - if (missing) { - lv2_log_error(&ui->logger, "Missing feature <%s>\n", missing); - free(ui); - return NULL; - } - - // Map URIs and initialise forge - map_sampler_uris(ui->map, &ui->uris); - lv2_atom_forge_init(&ui->forge, ui->map); - peaks_receiver_init(&ui->precv, ui->map); - - // Construct Gtk UI - ui->box = gtk_vbox_new(FALSE, 4); - ui->play_button = gtk_button_new_with_label("â–¶"); - ui->canvas = gtk_drawing_area_new(); - ui->button_box = gtk_hbox_new(FALSE, 4); - ui->file_button = gtk_file_chooser_button_new( - "Load Sample", GTK_FILE_CHOOSER_ACTION_OPEN); - ui->request_file_button = gtk_button_new_with_label("Request Sample"); - gtk_widget_set_size_request(ui->canvas, MIN_CANVAS_W, MIN_CANVAS_H); - gtk_container_set_border_width(GTK_CONTAINER(ui->box), 4); - gtk_box_pack_start(GTK_BOX(ui->box), ui->canvas, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(ui->box), ui->button_box, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(ui->button_box), ui->play_button, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(ui->button_box), ui->request_file_button, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(ui->button_box), ui->file_button, TRUE, TRUE, 0); - - g_signal_connect(ui->file_button, "file-set", - G_CALLBACK(on_file_set), ui); - - g_signal_connect(ui->request_file_button, "clicked", - G_CALLBACK(on_request_file), ui); - - g_signal_connect(ui->play_button, "clicked", - G_CALLBACK(on_play_clicked), ui); - - g_signal_connect(G_OBJECT(ui->canvas), "expose_event", - G_CALLBACK(on_canvas_expose), ui); - - // Request state (filename) from plugin - lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); - LV2_Atom_Forge_Frame frame; - LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( - &ui->forge, &frame, 0, ui->uris.patch_Get); - - assert(msg); - - lv2_atom_forge_pop(&ui->forge, &frame); - - ui->write(ui->controller, 0, lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); - - *widget = ui->box; - - return ui; + SamplerUI* ui = (SamplerUI*)calloc(1, sizeof(SamplerUI)); + if (!ui) { + return NULL; + } + + ui->write = write_function; + ui->controller = controller; + ui->width = MIN_CANVAS_W; + *widget = NULL; + ui->window = NULL; + ui->did_init = false; + + // Get host features + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &ui->logger.log, false, + LV2_URID__map, &ui->map, true, + LV2_UI__requestValue, &ui->request_value, false, + NULL); + // clang-format on + + lv2_log_logger_set_map(&ui->logger, ui->map); + if (missing) { + lv2_log_error(&ui->logger, "Missing feature <%s>\n", missing); + free(ui); + return NULL; + } + + // Map URIs and initialise forge + map_sampler_uris(ui->map, &ui->uris); + lv2_atom_forge_init(&ui->forge, ui->map); + peaks_receiver_init(&ui->precv, ui->map); + + // Construct Gtk UI + ui->box = gtk_vbox_new(FALSE, 4); + ui->play_button = gtk_button_new_with_label("â–¶"); + ui->canvas = gtk_drawing_area_new(); + ui->button_box = gtk_hbox_new(FALSE, 4); + ui->file_button = + gtk_file_chooser_button_new("Load Sample", GTK_FILE_CHOOSER_ACTION_OPEN); + ui->request_file_button = gtk_button_new_with_label("Request Sample"); + gtk_widget_set_size_request(ui->canvas, MIN_CANVAS_W, MIN_CANVAS_H); + gtk_container_set_border_width(GTK_CONTAINER(ui->box), 4); + gtk_box_pack_start(GTK_BOX(ui->box), ui->canvas, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(ui->box), ui->button_box, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(ui->button_box), ui->play_button, FALSE, FALSE, 0); + gtk_box_pack_start( + GTK_BOX(ui->button_box), ui->request_file_button, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(ui->button_box), ui->file_button, TRUE, TRUE, 0); + + g_signal_connect(ui->file_button, "file-set", G_CALLBACK(on_file_set), ui); + + g_signal_connect( + ui->request_file_button, "clicked", G_CALLBACK(on_request_file), ui); + + g_signal_connect(ui->play_button, "clicked", G_CALLBACK(on_play_clicked), ui); + + g_signal_connect( + G_OBJECT(ui->canvas), "expose_event", G_CALLBACK(on_canvas_expose), ui); + + // Request state (filename) from plugin + lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf)); + LV2_Atom_Forge_Frame frame; + LV2_Atom* msg = + (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.patch_Get); + + assert(msg); + + lv2_atom_forge_pop(&ui->forge, &frame); + + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); + + *widget = ui->box; + + return ui; } static void cleanup(LV2UI_Handle handle) { - SamplerUI* ui = (SamplerUI*)handle; - - if (ui->window) { - destroy_window(ui); - } - - gtk_widget_destroy(ui->canvas); - gtk_widget_destroy(ui->play_button); - gtk_widget_destroy(ui->file_button); - gtk_widget_destroy(ui->request_file_button); - gtk_widget_destroy(ui->button_box); - gtk_widget_destroy(ui->box); - free(ui); + SamplerUI* ui = (SamplerUI*)handle; + + if (ui->window) { + destroy_window(ui); + } + + gtk_widget_destroy(ui->canvas); + gtk_widget_destroy(ui->play_button); + gtk_widget_destroy(ui->file_button); + gtk_widget_destroy(ui->request_file_button); + gtk_widget_destroy(ui->button_box); + gtk_widget_destroy(ui->box); + free(ui); } static void @@ -354,116 +358,112 @@ port_event(LV2UI_Handle handle, uint32_t format, const void* buffer) { - SamplerUI* ui = (SamplerUI*)handle; - if (format == ui->uris.atom_eventTransfer) { - const LV2_Atom* atom = (const LV2_Atom*)buffer; - if (lv2_atom_forge_is_object_type(&ui->forge, atom->type)) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; - if (obj->body.otype == ui->uris.patch_Set) { - const char* path = read_set_file(&ui->uris, obj); - if (path && (!ui->filename || strcmp(path, ui->filename))) { - g_free(ui->filename); - ui->filename = g_strdup(path); - gtk_file_chooser_set_filename( - GTK_FILE_CHOOSER(ui->file_button), path); - peaks_receiver_clear(&ui->precv); - ui->requested_n_peaks = 0; - request_peaks(ui, ui->width / 2 * 2); - } else if (!path) { - lv2_log_warning(&ui->logger, "Set message has no path\n"); - } - } else if (obj->body.otype == ui->precv.uris.peaks_PeakUpdate) { - if (!peaks_receiver_receive(&ui->precv, obj)) { - gtk_widget_queue_draw(ui->canvas); - } - } - } else { - lv2_log_error(&ui->logger, "Unknown message type\n"); - } - } else { - lv2_log_warning(&ui->logger, "Unknown port event format\n"); - } + SamplerUI* ui = (SamplerUI*)handle; + if (format == ui->uris.atom_eventTransfer) { + const LV2_Atom* atom = (const LV2_Atom*)buffer; + if (lv2_atom_forge_is_object_type(&ui->forge, atom->type)) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; + if (obj->body.otype == ui->uris.patch_Set) { + const char* path = read_set_file(&ui->uris, obj); + if (path && (!ui->filename || strcmp(path, ui->filename))) { + g_free(ui->filename); + ui->filename = g_strdup(path); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ui->file_button), + path); + peaks_receiver_clear(&ui->precv); + ui->requested_n_peaks = 0; + request_peaks(ui, ui->width / 2 * 2); + } else if (!path) { + lv2_log_warning(&ui->logger, "Set message has no path\n"); + } + } else if (obj->body.otype == ui->precv.uris.peaks_PeakUpdate) { + if (!peaks_receiver_receive(&ui->precv, obj)) { + gtk_widget_queue_draw(ui->canvas); + } + } + } else { + lv2_log_error(&ui->logger, "Unknown message type\n"); + } + } else { + lv2_log_warning(&ui->logger, "Unknown port event format\n"); + } } /* Optional non-embedded UI show interface. */ static int ui_show(LV2UI_Handle handle) { - SamplerUI* ui = (SamplerUI*)handle; + SamplerUI* ui = (SamplerUI*)handle; - if (ui->window) { - return 0; - } + if (ui->window) { + return 0; + } - if (!ui->did_init) { - int argc = 0; - gtk_init_check(&argc, NULL); - g_object_ref(ui->box); - ui->did_init = true; - } + if (!ui->did_init) { + int argc = 0; + gtk_init_check(&argc, NULL); + g_object_ref(ui->box); + ui->did_init = true; + } - ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_add(GTK_CONTAINER(ui->window), ui->box); + ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_add(GTK_CONTAINER(ui->window), ui->box); - g_signal_connect(G_OBJECT(ui->window), - "delete-event", - G_CALLBACK(on_window_closed), - handle); + g_signal_connect( + G_OBJECT(ui->window), "delete-event", G_CALLBACK(on_window_closed), handle); - gtk_widget_show_all(ui->window); - gtk_window_present(GTK_WINDOW(ui->window)); + gtk_widget_show_all(ui->window); + gtk_window_present(GTK_WINDOW(ui->window)); - return 0; + return 0; } /* Optional non-embedded UI hide interface. */ static int ui_hide(LV2UI_Handle handle) { - SamplerUI* ui = (SamplerUI*)handle; + SamplerUI* ui = (SamplerUI*)handle; - if (ui->window) { - destroy_window(ui); - } + if (ui->window) { + destroy_window(ui); + } - return 0; + return 0; } /* Idle interface for optional non-embedded UI. */ static int ui_idle(LV2UI_Handle handle) { - SamplerUI* ui = (SamplerUI*)handle; - if (ui->window) { - gtk_main_iteration_do(false); - } - return 0; + SamplerUI* ui = (SamplerUI*)handle; + if (ui->window) { + gtk_main_iteration_do(false); + } + return 0; } static const void* extension_data(const char* uri) { - static const LV2UI_Show_Interface show = { ui_show, ui_hide }; - static const LV2UI_Idle_Interface idle = { ui_idle }; - if (!strcmp(uri, LV2_UI__showInterface)) { - return &show; - } else if (!strcmp(uri, LV2_UI__idleInterface)) { - return &idle; - } - return NULL; + static const LV2UI_Show_Interface show = {ui_show, ui_hide}; + static const LV2UI_Idle_Interface idle = {ui_idle}; + if (!strcmp(uri, LV2_UI__showInterface)) { + return &show; + } else if (!strcmp(uri, LV2_UI__idleInterface)) { + return &idle; + } + return NULL; } -static const LV2UI_Descriptor descriptor = { - SAMPLER_UI_URI, - instantiate, - cleanup, - port_event, - extension_data -}; +static const LV2UI_Descriptor descriptor = {SAMPLER_UI_URI, + instantiate, + cleanup, + port_event, + extension_data}; LV2_SYMBOL_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-sampler.lv2/uris.h b/plugins/eg-sampler.lv2/uris.h index 8a0eb6f..d7201fa 100644 --- a/plugins/eg-sampler.lv2/uris.h +++ b/plugins/eg-sampler.lv2/uris.h @@ -29,49 +29,49 @@ #include <stdint.h> #include <stdio.h> -#define EG_SAMPLER_URI "http://lv2plug.in/plugins/eg-sampler" +#define EG_SAMPLER_URI "http://lv2plug.in/plugins/eg-sampler" #define EG_SAMPLER__applySample EG_SAMPLER_URI "#applySample" -#define EG_SAMPLER__freeSample EG_SAMPLER_URI "#freeSample" -#define EG_SAMPLER__sample EG_SAMPLER_URI "#sample" +#define EG_SAMPLER__freeSample EG_SAMPLER_URI "#freeSample" +#define EG_SAMPLER__sample EG_SAMPLER_URI "#sample" typedef struct { - LV2_URID atom_Float; - LV2_URID atom_Path; - LV2_URID atom_Resource; - LV2_URID atom_Sequence; - LV2_URID atom_URID; - LV2_URID atom_eventTransfer; - LV2_URID eg_applySample; - LV2_URID eg_freeSample; - LV2_URID eg_sample; - LV2_URID midi_Event; - LV2_URID param_gain; - LV2_URID patch_Get; - LV2_URID patch_Set; - LV2_URID patch_accept; - LV2_URID patch_property; - LV2_URID patch_value; + LV2_URID atom_Float; + LV2_URID atom_Path; + LV2_URID atom_Resource; + LV2_URID atom_Sequence; + LV2_URID atom_URID; + LV2_URID atom_eventTransfer; + LV2_URID eg_applySample; + LV2_URID eg_freeSample; + LV2_URID eg_sample; + LV2_URID midi_Event; + LV2_URID param_gain; + LV2_URID patch_Get; + LV2_URID patch_Set; + LV2_URID patch_accept; + LV2_URID patch_property; + LV2_URID patch_value; } SamplerURIs; static inline void map_sampler_uris(LV2_URID_Map* map, SamplerURIs* uris) { - uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); - uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); - uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); - uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); - uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); - uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); - uris->eg_applySample = map->map(map->handle, EG_SAMPLER__applySample); - uris->eg_freeSample = map->map(map->handle, EG_SAMPLER__freeSample); - uris->eg_sample = map->map(map->handle, EG_SAMPLER__sample); - uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); - uris->param_gain = map->map(map->handle, LV2_PARAMETERS__gain); - uris->patch_Get = map->map(map->handle, LV2_PATCH__Get); - uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); - uris->patch_accept = map->map(map->handle, LV2_PATCH__accept); - uris->patch_property = map->map(map->handle, LV2_PATCH__property); - uris->patch_value = map->map(map->handle, LV2_PATCH__value); + uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); + uris->atom_Path = map->map(map->handle, LV2_ATOM__Path); + uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource); + uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence); + uris->atom_URID = map->map(map->handle, LV2_ATOM__URID); + uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); + uris->eg_applySample = map->map(map->handle, EG_SAMPLER__applySample); + uris->eg_freeSample = map->map(map->handle, EG_SAMPLER__freeSample); + uris->eg_sample = map->map(map->handle, EG_SAMPLER__sample); + uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); + uris->param_gain = map->map(map->handle, LV2_PARAMETERS__gain); + uris->patch_Get = map->map(map->handle, LV2_PATCH__Get); + uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); + uris->patch_accept = map->map(map->handle, LV2_PATCH__accept); + uris->patch_property = map->map(map->handle, LV2_PATCH__property); + uris->patch_value = map->map(map->handle, LV2_PATCH__value); } /** @@ -85,21 +85,19 @@ map_sampler_uris(LV2_URID_Map* map, SamplerURIs* uris) ---- */ static inline LV2_Atom_Forge_Ref -write_set_gain(LV2_Atom_Forge* forge, - const SamplerURIs* uris, - const float gain) +write_set_gain(LV2_Atom_Forge* forge, const SamplerURIs* uris, const float gain) { - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref set = lv2_atom_forge_object( - forge, &frame, 0, uris->patch_Set); + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref set = + lv2_atom_forge_object(forge, &frame, 0, uris->patch_Set); - lv2_atom_forge_key(forge, uris->patch_property); - lv2_atom_forge_urid(forge, uris->param_gain); - lv2_atom_forge_key(forge, uris->patch_value); - lv2_atom_forge_float(forge, gain); + lv2_atom_forge_key(forge, uris->patch_property); + lv2_atom_forge_urid(forge, uris->param_gain); + lv2_atom_forge_key(forge, uris->patch_value); + lv2_atom_forge_float(forge, gain); - lv2_atom_forge_pop(forge, &frame); - return set; + lv2_atom_forge_pop(forge, &frame); + return set; } /** @@ -118,17 +116,17 @@ write_set_file(LV2_Atom_Forge* forge, const char* filename, const uint32_t filename_len) { - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref set = lv2_atom_forge_object( - forge, &frame, 0, uris->patch_Set); + LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Ref set = + lv2_atom_forge_object(forge, &frame, 0, uris->patch_Set); - lv2_atom_forge_key(forge, uris->patch_property); - lv2_atom_forge_urid(forge, uris->eg_sample); - lv2_atom_forge_key(forge, uris->patch_value); - lv2_atom_forge_path(forge, filename, filename_len); + lv2_atom_forge_key(forge, uris->patch_property); + lv2_atom_forge_urid(forge, uris->eg_sample); + lv2_atom_forge_key(forge, uris->patch_value); + lv2_atom_forge_path(forge, filename, filename_len); - lv2_atom_forge_pop(forge, &frame); - return set; + lv2_atom_forge_pop(forge, &frame); + return set; } /** @@ -142,46 +140,45 @@ write_set_file(LV2_Atom_Forge* forge, ---- */ static inline const char* -read_set_file(const SamplerURIs* uris, - const LV2_Atom_Object* obj) +read_set_file(const SamplerURIs* uris, const LV2_Atom_Object* obj) { - if (obj->body.otype != uris->patch_Set) { - fprintf(stderr, "Ignoring unknown message type %u\n", obj->body.otype); - return NULL; - } - - /* Get property URI. */ - const LV2_Atom* property = NULL; - lv2_atom_object_get(obj, uris->patch_property, &property, 0); - if (!property) { - fprintf(stderr, "Malformed set message has no body.\n"); - return NULL; - } - - if (property->type != uris->atom_URID) { - fprintf(stderr, "Malformed set message has non-URID property.\n"); - return NULL; - } - - if (((const LV2_Atom_URID*)property)->body != uris->eg_sample) { - fprintf(stderr, "Set message for unknown property.\n"); - return NULL; - } - - /* Get value. */ - const LV2_Atom* value = NULL; - lv2_atom_object_get(obj, uris->patch_value, &value, 0); - if (!value) { - fprintf(stderr, "Malformed set message has no value.\n"); - return NULL; - } - - if (value->type != uris->atom_Path) { - fprintf(stderr, "Set message value is not a Path.\n"); - return NULL; - } - - return (const char*)LV2_ATOM_BODY_CONST(value); + if (obj->body.otype != uris->patch_Set) { + fprintf(stderr, "Ignoring unknown message type %u\n", obj->body.otype); + return NULL; + } + + /* Get property URI. */ + const LV2_Atom* property = NULL; + lv2_atom_object_get(obj, uris->patch_property, &property, 0); + if (!property) { + fprintf(stderr, "Malformed set message has no body.\n"); + return NULL; + } + + if (property->type != uris->atom_URID) { + fprintf(stderr, "Malformed set message has non-URID property.\n"); + return NULL; + } + + if (((const LV2_Atom_URID*)property)->body != uris->eg_sample) { + fprintf(stderr, "Set message for unknown property.\n"); + return NULL; + } + + /* Get value. */ + const LV2_Atom* value = NULL; + lv2_atom_object_get(obj, uris->patch_value, &value, 0); + if (!value) { + fprintf(stderr, "Malformed set message has no value.\n"); + return NULL; + } + + if (value->type != uris->atom_Path) { + fprintf(stderr, "Set message value is not a Path.\n"); + return NULL; + } + + return (const char*)LV2_ATOM_BODY_CONST(value); } -#endif /* SAMPLER_URIS_H */ +#endif /* SAMPLER_URIS_H */ diff --git a/plugins/eg-scope.lv2/examploscope.c b/plugins/eg-scope.lv2/examploscope.c index b767508..ec013a1 100644 --- a/plugins/eg-scope.lv2/examploscope.c +++ b/plugins/eg-scope.lv2/examploscope.c @@ -42,40 +42,40 @@ UI using atom messages via a sequence port, similarly to MIDI I/O. */ typedef struct { - // Port buffers - float* input[2]; - float* output[2]; - const LV2_Atom_Sequence* control; - LV2_Atom_Sequence* notify; - - // Atom forge and URI mapping - LV2_URID_Map* map; - ScoLV2URIs uris; - LV2_Atom_Forge forge; - LV2_Atom_Forge_Frame frame; - - // Log feature and convenience API - LV2_Log_Logger logger; - - // Instantiation settings - uint32_t n_channels; - double rate; - - // UI state - bool ui_active; - bool send_settings_to_ui; - float ui_amp; - uint32_t ui_spp; + // Port buffers + float* input[2]; + float* output[2]; + const LV2_Atom_Sequence* control; + LV2_Atom_Sequence* notify; + + // Atom forge and URI mapping + LV2_URID_Map* map; + ScoLV2URIs uris; + LV2_Atom_Forge forge; + LV2_Atom_Forge_Frame frame; + + // Log feature and convenience API + LV2_Log_Logger logger; + + // Instantiation settings + uint32_t n_channels; + double rate; + + // UI state + bool ui_active; + bool send_settings_to_ui; + float ui_amp; + uint32_t ui_spp; } EgScope; /** ==== Port Indices ==== */ typedef enum { - SCO_CONTROL = 0, // Event input - SCO_NOTIFY = 1, // Event output - SCO_INPUT0 = 2, // Audio input 0 - SCO_OUTPUT0 = 3, // Audio output 0 - SCO_INPUT1 = 4, // Audio input 1 (stereo variant) - SCO_OUTPUT1 = 5, // Audio input 2 (stereo variant) + SCO_CONTROL = 0, // Event input + SCO_NOTIFY = 1, // Event output + SCO_INPUT0 = 2, // Audio input 0 + SCO_OUTPUT0 = 3, // Audio output 0 + SCO_INPUT1 = 4, // Audio input 1 (stereo variant) + SCO_OUTPUT1 = 5, // Audio input 2 (stereo variant) } PortIndex; /** ==== Instantiate Method ==== */ @@ -85,85 +85,83 @@ instantiate(const LV2_Descriptor* descriptor, const char* bundle_path, const LV2_Feature* const* features) { - (void)descriptor; // Unused variable - (void)bundle_path; // Unused variable - - // Allocate and initialise instance structure. - EgScope* self = (EgScope*)calloc(1, sizeof(EgScope)); - if (!self) { - return NULL; - } - - // Get host features - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - // Decide which variant to use depending on the plugin URI - if (!strcmp(descriptor->URI, SCO_URI "#Stereo")) { - self->n_channels = 2; - } else if (!strcmp(descriptor->URI, SCO_URI "#Mono")) { - self->n_channels = 1; - } else { - free(self); - return NULL; - } - - // Initialise local variables - self->ui_active = false; - self->send_settings_to_ui = false; - self->rate = rate; - - // Set default UI settings - self->ui_spp = 50; - self->ui_amp = 1.0f; - - // Map URIs and initialise forge/logger - map_sco_uris(self->map, &self->uris); - lv2_atom_forge_init(&self->forge, self->map); - - return (LV2_Handle)self; + (void)descriptor; // Unused variable + (void)bundle_path; // Unused variable + + // Allocate and initialise instance structure. + EgScope* self = (EgScope*)calloc(1, sizeof(EgScope)); + if (!self) { + return NULL; + } + + // Get host features + // clang-format off + const char* missing = lv2_features_query( + features, + LV2_LOG__log, &self->logger.log, false, + LV2_URID__map, &self->map, true, + NULL); + // clang-format on + + lv2_log_logger_set_map(&self->logger, self->map); + if (missing) { + lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); + free(self); + return NULL; + } + + // Decide which variant to use depending on the plugin URI + if (!strcmp(descriptor->URI, SCO_URI "#Stereo")) { + self->n_channels = 2; + } else if (!strcmp(descriptor->URI, SCO_URI "#Mono")) { + self->n_channels = 1; + } else { + free(self); + return NULL; + } + + // Initialise local variables + self->ui_active = false; + self->send_settings_to_ui = false; + self->rate = rate; + + // Set default UI settings + self->ui_spp = 50; + self->ui_amp = 1.0f; + + // Map URIs and initialise forge/logger + map_sco_uris(self->map, &self->uris); + lv2_atom_forge_init(&self->forge, self->map); + + return (LV2_Handle)self; } /** ==== Connect Port Method ==== */ static void -connect_port(LV2_Handle handle, - uint32_t port, - void* data) +connect_port(LV2_Handle handle, uint32_t port, void* data) { - EgScope* self = (EgScope*)handle; - - switch ((PortIndex)port) { - case SCO_CONTROL: - self->control = (const LV2_Atom_Sequence*)data; - break; - case SCO_NOTIFY: - self->notify = (LV2_Atom_Sequence*)data; - break; - case SCO_INPUT0: - self->input[0] = (float*)data; - break; - case SCO_OUTPUT0: - self->output[0] = (float*)data; - break; - case SCO_INPUT1: - self->input[1] = (float*)data; - break; - case SCO_OUTPUT1: - self->output[1] = (float*)data; - break; - } + EgScope* self = (EgScope*)handle; + + switch ((PortIndex)port) { + case SCO_CONTROL: + self->control = (const LV2_Atom_Sequence*)data; + break; + case SCO_NOTIFY: + self->notify = (LV2_Atom_Sequence*)data; + break; + case SCO_INPUT0: + self->input[0] = (float*)data; + break; + case SCO_OUTPUT0: + self->output[0] = (float*)data; + break; + case SCO_INPUT1: + self->input[1] = (float*)data; + break; + case SCO_OUTPUT1: + self->output[1] = (float*)data; + break; + } } /** @@ -174,9 +172,9 @@ connect_port(LV2_Handle handle, [source,turtle] -------- [] - a sco:RawAudio ; - sco:channelID 0 ; - sco:audioData [ 0.0, 0.0, ... ] . + a sco:RawAudio ; + sco:channelID 0 ; + sco:audioData [ 0.0, 0.0, ... ] . -------- where the value of the `sco:audioData` property, `[ 0.0, 0.0, ... ]`, is a @@ -190,134 +188,131 @@ tx_rawaudio(LV2_Atom_Forge* forge, const size_t n_samples, const float* data) { - LV2_Atom_Forge_Frame frame; + LV2_Atom_Forge_Frame frame; - // Forge container object of type 'RawAudio' - lv2_atom_forge_frame_time(forge, 0); - lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio); + // Forge container object of type 'RawAudio' + lv2_atom_forge_frame_time(forge, 0); + lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio); - // Add integer 'channelID' property - lv2_atom_forge_key(forge, uris->channelID); - lv2_atom_forge_int(forge, channel); + // Add integer 'channelID' property + lv2_atom_forge_key(forge, uris->channelID); + lv2_atom_forge_int(forge, channel); - // Add vector of floats 'audioData' property - lv2_atom_forge_key(forge, uris->audioData); - lv2_atom_forge_vector( - forge, sizeof(float), uris->atom_Float, n_samples, data); + // Add vector of floats 'audioData' property + lv2_atom_forge_key(forge, uris->audioData); + lv2_atom_forge_vector( + forge, sizeof(float), uris->atom_Float, n_samples, data); - // Close off object - lv2_atom_forge_pop(forge, &frame); + // Close off object + lv2_atom_forge_pop(forge, &frame); } /** ==== Run Method ==== */ static void run(LV2_Handle handle, uint32_t n_samples) { - EgScope* self = (EgScope*)handle; - - /* Ensure notify port buffer is large enough to hold all audio-samples and - configuration settings. A minimum size was requested in the .ttl file, - but check here just to be sure. - - TODO: Explain these magic numbers. - */ - const size_t size = (sizeof(float) * n_samples + 64) * self->n_channels; - const uint32_t space = self->notify->atom.size; - if (space < size + 128) { - /* Insufficient space, report error and do nothing. Note that a - real-time production plugin mustn't call log functions in run(), but - this can be useful for debugging and example purposes. - */ - lv2_log_error(&self->logger, "Buffer size is insufficient\n"); - return; - } - - // Prepare forge buffer and initialize atom-sequence - lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space); - lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0); - - /* Send settings to UI - - The plugin can continue to run while the UI is closed and re-opened. - The state and settings of the UI are kept here and transmitted to the UI - every time it asks for them or if the user initializes a 'load preset'. - */ - if (self->send_settings_to_ui && self->ui_active) { - self->send_settings_to_ui = false; - // Forge container object of type 'ui_state' - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_frame_time(&self->forge, 0); - lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State); - - // Add UI state as properties - lv2_atom_forge_key(&self->forge, self->uris.ui_spp); - lv2_atom_forge_int(&self->forge, self->ui_spp); - lv2_atom_forge_key(&self->forge, self->uris.ui_amp); - lv2_atom_forge_float(&self->forge, self->ui_amp); - lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate); - lv2_atom_forge_float(&self->forge, (float)self->rate); - lv2_atom_forge_pop(&self->forge, &frame); - } - - // Process incoming events from GUI - if (self->control) { - const LV2_Atom_Event* ev = lv2_atom_sequence_begin( - &(self->control)->body); - // For each incoming message... - while (!lv2_atom_sequence_is_end( - &self->control->body, self->control->atom.size, ev)) { - // If the event is an atom:Blank object - if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; - if (obj->body.otype == self->uris.ui_On) { - // If the object is a ui-on, the UI was activated - self->ui_active = true; - self->send_settings_to_ui = true; - } else if (obj->body.otype == self->uris.ui_Off) { - // If the object is a ui-off, the UI was closed - self->ui_active = false; - } else if (obj->body.otype == self->uris.ui_State) { - // If the object is a ui-state, it's the current UI settings - const LV2_Atom* spp = NULL; - const LV2_Atom* amp = NULL; - lv2_atom_object_get(obj, self->uris.ui_spp, &spp, - self->uris.ui_amp, &, - 0); - if (spp) { - self->ui_spp = ((const LV2_Atom_Int*)spp)->body; - } - if (amp) { - self->ui_amp = ((const LV2_Atom_Float*)amp)->body; - } - } - } - ev = lv2_atom_sequence_next(ev); - } - } - - // Process audio data - for (uint32_t c = 0; c < self->n_channels; ++c) { - if (self->ui_active) { - // If UI is active, send raw audio data to UI - tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]); - } - // If not processing audio in-place, forward audio - if (self->input[c] != self->output[c]) { - memcpy(self->output[c], self->input[c], sizeof(float) * n_samples); - } - } - - // Close off sequence - lv2_atom_forge_pop(&self->forge, &self->frame); + EgScope* self = (EgScope*)handle; + + /* Ensure notify port buffer is large enough to hold all audio-samples and + configuration settings. A minimum size was requested in the .ttl file, + but check here just to be sure. + + TODO: Explain these magic numbers. + */ + const size_t size = (sizeof(float) * n_samples + 64) * self->n_channels; + const uint32_t space = self->notify->atom.size; + if (space < size + 128) { + /* Insufficient space, report error and do nothing. Note that a + real-time production plugin mustn't call log functions in run(), but + this can be useful for debugging and example purposes. + */ + lv2_log_error(&self->logger, "Buffer size is insufficient\n"); + return; + } + + // Prepare forge buffer and initialize atom-sequence + lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space); + lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0); + + /* Send settings to UI + + The plugin can continue to run while the UI is closed and re-opened. + The state and settings of the UI are kept here and transmitted to the UI + every time it asks for them or if the user initializes a 'load preset'. + */ + if (self->send_settings_to_ui && self->ui_active) { + self->send_settings_to_ui = false; + // Forge container object of type 'ui_state' + LV2_Atom_Forge_Frame frame; + lv2_atom_forge_frame_time(&self->forge, 0); + lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State); + + // Add UI state as properties + lv2_atom_forge_key(&self->forge, self->uris.ui_spp); + lv2_atom_forge_int(&self->forge, self->ui_spp); + lv2_atom_forge_key(&self->forge, self->uris.ui_amp); + lv2_atom_forge_float(&self->forge, self->ui_amp); + lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate); + lv2_atom_forge_float(&self->forge, (float)self->rate); + lv2_atom_forge_pop(&self->forge, &frame); + } + + // Process incoming events from GUI + if (self->control) { + const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body); + // For each incoming message... + while (!lv2_atom_sequence_is_end( + &self->control->body, self->control->atom.size, ev)) { + // If the event is an atom:Blank object + if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body; + if (obj->body.otype == self->uris.ui_On) { + // If the object is a ui-on, the UI was activated + self->ui_active = true; + self->send_settings_to_ui = true; + } else if (obj->body.otype == self->uris.ui_Off) { + // If the object is a ui-off, the UI was closed + self->ui_active = false; + } else if (obj->body.otype == self->uris.ui_State) { + // If the object is a ui-state, it's the current UI settings + const LV2_Atom* spp = NULL; + const LV2_Atom* amp = NULL; + lv2_atom_object_get( + obj, self->uris.ui_spp, &spp, self->uris.ui_amp, &, 0); + if (spp) { + self->ui_spp = ((const LV2_Atom_Int*)spp)->body; + } + if (amp) { + self->ui_amp = ((const LV2_Atom_Float*)amp)->body; + } + } + } + ev = lv2_atom_sequence_next(ev); + } + } + + // Process audio data + for (uint32_t c = 0; c < self->n_channels; ++c) { + if (self->ui_active) { + // If UI is active, send raw audio data to UI + tx_rawaudio(&self->forge, &self->uris, c, n_samples, self->input[c]); + } + // If not processing audio in-place, forward audio + if (self->input[c] != self->output[c]) { + memcpy(self->output[c], self->input[c], sizeof(float) * n_samples); + } + } + + // Close off sequence + lv2_atom_forge_pop(&self->forge, &self->frame); } static void cleanup(LV2_Handle handle) { - free(handle); + free(handle); } - /** ==== State Methods ==== @@ -334,22 +329,26 @@ state_save(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - EgScope* self = (EgScope*)instance; - if (!self) { - return LV2_STATE_SUCCESS; - } - - store(handle, self->uris.ui_spp, - (void*)&self->ui_spp, sizeof(uint32_t), - self->uris.atom_Int, - LV2_STATE_IS_POD); - - store(handle, self->uris.ui_amp, - (void*)&self->ui_amp, sizeof(float), - self->uris.atom_Float, - LV2_STATE_IS_POD); - - return LV2_STATE_SUCCESS; + EgScope* self = (EgScope*)instance; + if (!self) { + return LV2_STATE_SUCCESS; + } + + store(handle, + self->uris.ui_spp, + (void*)&self->ui_spp, + sizeof(uint32_t), + self->uris.atom_Int, + LV2_STATE_IS_POD); + + store(handle, + self->uris.ui_amp, + (void*)&self->ui_amp, + sizeof(float), + self->uris.atom_Float, + LV2_STATE_IS_POD); + + return LV2_STATE_SUCCESS; } static LV2_State_Status @@ -359,72 +358,68 @@ state_restore(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - EgScope* self = (EgScope*)instance; - - size_t size = 0; - uint32_t type = 0; - uint32_t valflags = 0; - - const void* spp = retrieve( - handle, self->uris.ui_spp, &size, &type, &valflags); - if (spp && size == sizeof(uint32_t) && type == self->uris.atom_Int) { - self->ui_spp = *((const uint32_t*)spp); - self->send_settings_to_ui = true; - } - - const void* amp = retrieve( - handle, self->uris.ui_amp, &size, &type, &valflags); - if (amp && size == sizeof(float) && type == self->uris.atom_Float) { - self->ui_amp = *((const float*)amp); - self->send_settings_to_ui = true; - } - - return LV2_STATE_SUCCESS; + EgScope* self = (EgScope*)instance; + + size_t size = 0; + uint32_t type = 0; + uint32_t valflags = 0; + + const void* spp = + retrieve(handle, self->uris.ui_spp, &size, &type, &valflags); + if (spp && size == sizeof(uint32_t) && type == self->uris.atom_Int) { + self->ui_spp = *((const uint32_t*)spp); + self->send_settings_to_ui = true; + } + + const void* amp = + retrieve(handle, self->uris.ui_amp, &size, &type, &valflags); + if (amp && size == sizeof(float) && type == self->uris.atom_Float) { + self->ui_amp = *((const float*)amp); + self->send_settings_to_ui = true; + } + + return LV2_STATE_SUCCESS; } static const void* extension_data(const char* uri) { - static const LV2_State_Interface state = { state_save, state_restore }; - if (!strcmp(uri, LV2_STATE__interface)) { - return &state; - } - return NULL; + static const LV2_State_Interface state = {state_save, state_restore}; + if (!strcmp(uri, LV2_STATE__interface)) { + return &state; + } + return NULL; } /** ==== Plugin Descriptors ==== */ -static const LV2_Descriptor descriptor_mono = { - SCO_URI "#Mono", - instantiate, - connect_port, - NULL, - run, - NULL, - cleanup, - extension_data -}; - -static const LV2_Descriptor descriptor_stereo = { - SCO_URI "#Stereo", - instantiate, - connect_port, - NULL, - run, - NULL, - cleanup, - extension_data -}; +static const LV2_Descriptor descriptor_mono = {SCO_URI "#Mono", + instantiate, + connect_port, + NULL, + run, + NULL, + cleanup, + extension_data}; + +static const LV2_Descriptor descriptor_stereo = {SCO_URI "#Stereo", + instantiate, + connect_port, + NULL, + run, + NULL, + cleanup, + extension_data}; LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index) { - switch (index) { - case 0: - return &descriptor_mono; - case 1: - return &descriptor_stereo; - default: - return NULL; - } + switch (index) { + case 0: + return &descriptor_mono; + case 1: + return &descriptor_stereo; + default: + return NULL; + } } diff --git a/plugins/eg-scope.lv2/examploscope_ui.c b/plugins/eg-scope.lv2/examploscope_ui.c index e9e0c6f..e601843 100644 --- a/plugins/eg-scope.lv2/examploscope_ui.c +++ b/plugins/eg-scope.lv2/examploscope_ui.c @@ -38,7 +38,7 @@ #include <string.h> // Drawing area size -#define DAWIDTH (640) +#define DAWIDTH (640) #define DAHEIGHT (200) /** @@ -53,101 +53,100 @@ given 'index' position. */ typedef struct { - float data_min[DAWIDTH]; - float data_max[DAWIDTH]; + float data_min[DAWIDTH]; + float data_max[DAWIDTH]; - uint32_t idx; - uint32_t sub; + uint32_t idx; + uint32_t sub; } ScoChan; typedef struct { - LV2_Atom_Forge forge; - LV2_URID_Map* map; - ScoLV2URIs uris; - - LV2UI_Write_Function write; - LV2UI_Controller controller; - - GtkWidget* hbox; - GtkWidget* vbox; - GtkWidget* sep[2]; - GtkWidget* darea; - GtkWidget* btn_pause; - GtkWidget* lbl_speed; - GtkWidget* lbl_amp; - GtkWidget* spb_speed; - GtkWidget* spb_amp; - GtkAdjustment* spb_speed_adj; - GtkAdjustment* spb_amp_adj; - - ScoChan chn[2]; - uint32_t stride; - uint32_t n_channels; - bool paused; - float rate; - bool updating; + LV2_Atom_Forge forge; + LV2_URID_Map* map; + ScoLV2URIs uris; + + LV2UI_Write_Function write; + LV2UI_Controller controller; + + GtkWidget* hbox; + GtkWidget* vbox; + GtkWidget* sep[2]; + GtkWidget* darea; + GtkWidget* btn_pause; + GtkWidget* lbl_speed; + GtkWidget* lbl_amp; + GtkWidget* spb_speed; + GtkWidget* spb_amp; + GtkAdjustment* spb_speed_adj; + GtkAdjustment* spb_amp_adj; + + ScoChan chn[2]; + uint32_t stride; + uint32_t n_channels; + bool paused; + float rate; + bool updating; } EgScopeUI; - /** Send current UI settings to backend. */ static void send_ui_state(LV2UI_Handle handle) { - EgScopeUI* ui = (EgScopeUI*)handle; - const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp)); + EgScopeUI* ui = (EgScopeUI*)handle; + const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp)); - // Use local buffer on the stack to build atom - uint8_t obj_buf[1024]; - lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); + // Use local buffer on the stack to build atom + uint8_t obj_buf[1024]; + lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); - // Start a ui:State object - LV2_Atom_Forge_Frame frame; - LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( - &ui->forge, &frame, 0, ui->uris.ui_State); + // Start a ui:State object + LV2_Atom_Forge_Frame frame; + LV2_Atom* msg = + (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_State); - assert(msg); + assert(msg); - // msg[samples-per-pixel] = integer - lv2_atom_forge_key(&ui->forge, ui->uris.ui_spp); - lv2_atom_forge_int(&ui->forge, ui->stride); + // msg[samples-per-pixel] = integer + lv2_atom_forge_key(&ui->forge, ui->uris.ui_spp); + lv2_atom_forge_int(&ui->forge, ui->stride); - // msg[amplitude] = float - lv2_atom_forge_key(&ui->forge, ui->uris.ui_amp); - lv2_atom_forge_float(&ui->forge, gain); + // msg[amplitude] = float + lv2_atom_forge_key(&ui->forge, ui->uris.ui_amp); + lv2_atom_forge_float(&ui->forge, gain); - // Finish ui:State object - lv2_atom_forge_pop(&ui->forge, &frame); + // Finish ui:State object + lv2_atom_forge_pop(&ui->forge, &frame); - // Send message to plugin port '0' - ui->write(ui->controller, - 0, - lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); + // Send message to plugin port '0' + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); } /** Notify backend that UI is closed. */ static void send_ui_disable(LV2UI_Handle handle) { - EgScopeUI* ui = (EgScopeUI*)handle; - send_ui_state(handle); + EgScopeUI* ui = (EgScopeUI*)handle; + send_ui_state(handle); - uint8_t obj_buf[64]; - lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); + uint8_t obj_buf[64]; + lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); - LV2_Atom_Forge_Frame frame; - LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( - &ui->forge, &frame, 0, ui->uris.ui_Off); + LV2_Atom_Forge_Frame frame; + LV2_Atom* msg = + (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_Off); - assert(msg); + assert(msg); - lv2_atom_forge_pop(&ui->forge, &frame); - ui->write(ui->controller, - 0, - lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); + lv2_atom_forge_pop(&ui->forge, &frame); + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); } /** @@ -158,35 +157,35 @@ send_ui_disable(LV2UI_Handle handle) static void send_ui_enable(LV2UI_Handle handle) { - EgScopeUI* ui = (EgScopeUI*)handle; + EgScopeUI* ui = (EgScopeUI*)handle; - uint8_t obj_buf[64]; - lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); + uint8_t obj_buf[64]; + lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf)); - LV2_Atom_Forge_Frame frame; - LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object( - &ui->forge, &frame, 0, ui->uris.ui_On); + LV2_Atom_Forge_Frame frame; + LV2_Atom* msg = + (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_On); - assert(msg); + assert(msg); - lv2_atom_forge_pop(&ui->forge, &frame); - ui->write(ui->controller, - 0, - lv2_atom_total_size(msg), - ui->uris.atom_eventTransfer, - msg); + lv2_atom_forge_pop(&ui->forge, &frame); + ui->write(ui->controller, + 0, + lv2_atom_total_size(msg), + ui->uris.atom_eventTransfer, + msg); } /** Gtk widget callback. */ static gboolean on_cfg_changed(GtkWidget* widget, gpointer data) { - EgScopeUI* ui = (EgScopeUI*)data; - if (!ui->updating) { - // Only send UI state if the change is from user interaction - send_ui_state(data); - } - return TRUE; + EgScopeUI* ui = (EgScopeUI*)data; + if (!ui->updating) { + // Only send UI state if the change is from user interaction + send_ui_state(data); + } + return TRUE; } /** @@ -197,127 +196,127 @@ on_cfg_changed(GtkWidget* widget, gpointer data) static gboolean on_expose_event(GtkWidget* widget, GdkEventExpose* ev, gpointer data) { - EgScopeUI* ui = (EgScopeUI*)data; - const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp)); - - // Get cairo type for the gtk window - cairo_t* cr = gdk_cairo_create(ui->darea->window); - - // Limit cairo-drawing to exposed area - cairo_rectangle(cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height); - cairo_clip(cr); - - // Clear background - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); - cairo_rectangle(cr, 0, 0, DAWIDTH, DAHEIGHT * ui->n_channels); - cairo_fill(cr); - - cairo_set_line_width(cr, 1.0); - - const uint32_t start = ev->area.x; - const uint32_t end = ev->area.x + ev->area.width; - - assert(start < DAWIDTH); - assert(end <= DAWIDTH); - assert(start < end); - - for (uint32_t c = 0; c < ui->n_channels; ++c) { - ScoChan* chn = &ui->chn[c]; - - /* Drawing area Y-position of given sample-value. - * Note: cairo-pixel at 0 spans -0.5 .. +0.5, hence (DAHEIGHT / 2.0 -0.5) - * also the cairo Y-axis points upwards (hence 'minus value') - * - * == ( DAHEIGHT * (CHN) // channel offset - * + (DAHEIGHT / 2) - 0.5 // vertical center -- '0' - * - (DAHEIGHT / 2) * (VAL) * (GAIN) - * ) - */ - const float chn_y_offset = DAHEIGHT * c + DAHEIGHT * 0.5f - 0.5f; - const float chn_y_scale = DAHEIGHT * 0.5f * gain; - -#define CYPOS(VAL) (chn_y_offset - (VAL) * chn_y_scale) - - cairo_save(cr); - - /* Restrict drawing to current channel area, don't bleed drawing into - neighboring channels. */ - cairo_rectangle(cr, 0, DAHEIGHT * c, DAWIDTH, DAHEIGHT); - cairo_clip(cr); - - // Set color of wave-form - cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0); - - /* This is a somewhat 'smart' mechanism to plot audio data using - alternating up/down line-directions. It works well for both cases: - 1 pixel <= 1 sample and 1 pixel represents more than 1 sample, but - is not ideal for either. */ - if (start == chn->idx) { - cairo_move_to(cr, start - 0.5, CYPOS(0)); - } else { - cairo_move_to(cr, start - 0.5, CYPOS(chn->data_max[start])); - } - - uint32_t pathlength = 0; - for (uint32_t i = start; i < end; ++i) { - if (i == chn->idx) { - continue; - } else if (i % 2) { - cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i])); - cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i])); - ++pathlength; - } else { - cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i])); - cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i])); - ++pathlength; - } - - /** Limit the max cairo path length. This is an optimization trade - off: too short path: high load CPU/GPU load. too-long path: - bad anti-aliasing, or possibly lost points */ - if (pathlength > MAX_CAIRO_PATH) { - pathlength = 0; - cairo_stroke(cr); - if (i % 2) { - cairo_move_to(cr, i - .5, CYPOS(chn->data_max[i])); - } else { - cairo_move_to(cr, i - .5, CYPOS(chn->data_min[i])); - } - } - } - - if (pathlength > 0) { - cairo_stroke(cr); - } - - // Draw current position vertical line if display is slow - if (ui->stride >= ui->rate / 4800.0f || ui->paused) { - cairo_set_source_rgba(cr, .9, .2, .2, .6); - cairo_move_to(cr, chn->idx - .5, DAHEIGHT * c); - cairo_line_to(cr, chn->idx - .5, DAHEIGHT * (c + 1)); - cairo_stroke(cr); - } - - // Undo the 'clipping' restriction - cairo_restore(cr); - - // Channel separator - if (c > 0) { - cairo_set_source_rgba(cr, .5, .5, .5, 1.0); - cairo_move_to(cr, 0, DAHEIGHT * c - .5); - cairo_line_to(cr, DAWIDTH, DAHEIGHT * c - .5); - cairo_stroke(cr); - } - - // Zero scale line - cairo_set_source_rgba(cr, .3, .3, .7, .5); - cairo_move_to(cr, 0, DAHEIGHT * (c + .5) - .5); - cairo_line_to(cr, DAWIDTH, DAHEIGHT * (c + .5) - .5); - cairo_stroke(cr); - } - - cairo_destroy(cr); - return TRUE; + EgScopeUI* ui = (EgScopeUI*)data; + const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp)); + + // Get cairo type for the gtk window + cairo_t* cr = gdk_cairo_create(ui->darea->window); + + // Limit cairo-drawing to exposed area + cairo_rectangle(cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height); + cairo_clip(cr); + + // Clear background + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + cairo_rectangle(cr, 0, 0, DAWIDTH, DAHEIGHT * ui->n_channels); + cairo_fill(cr); + + cairo_set_line_width(cr, 1.0); + + const uint32_t start = ev->area.x; + const uint32_t end = ev->area.x + ev->area.width; + + assert(start < DAWIDTH); + assert(end <= DAWIDTH); + assert(start < end); + + for (uint32_t c = 0; c < ui->n_channels; ++c) { + ScoChan* chn = &ui->chn[c]; + + /* Drawing area Y-position of given sample-value. + * Note: cairo-pixel at 0 spans -0.5 .. +0.5, hence (DAHEIGHT / 2.0 -0.5) + * also the cairo Y-axis points upwards (hence 'minus value') + * + * == ( DAHEIGHT * (CHN) // channel offset + * + (DAHEIGHT / 2) - 0.5 // vertical center -- '0' + * - (DAHEIGHT / 2) * (VAL) * (GAIN) + * ) + */ + const float chn_y_offset = DAHEIGHT * c + DAHEIGHT * 0.5f - 0.5f; + const float chn_y_scale = DAHEIGHT * 0.5f * gain; + +#define CYPOS(VAL) (chn_y_offset - (VAL)*chn_y_scale) + + cairo_save(cr); + + /* Restrict drawing to current channel area, don't bleed drawing into + neighboring channels. */ + cairo_rectangle(cr, 0, DAHEIGHT * c, DAWIDTH, DAHEIGHT); + cairo_clip(cr); + + // Set color of wave-form + cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0); + + /* This is a somewhat 'smart' mechanism to plot audio data using + alternating up/down line-directions. It works well for both cases: + 1 pixel <= 1 sample and 1 pixel represents more than 1 sample, but + is not ideal for either. */ + if (start == chn->idx) { + cairo_move_to(cr, start - 0.5, CYPOS(0)); + } else { + cairo_move_to(cr, start - 0.5, CYPOS(chn->data_max[start])); + } + + uint32_t pathlength = 0; + for (uint32_t i = start; i < end; ++i) { + if (i == chn->idx) { + continue; + } else if (i % 2) { + cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i])); + cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i])); + ++pathlength; + } else { + cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i])); + cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i])); + ++pathlength; + } + + /** Limit the max cairo path length. This is an optimization trade + off: too short path: high load CPU/GPU load. too-long path: + bad anti-aliasing, or possibly lost points */ + if (pathlength > MAX_CAIRO_PATH) { + pathlength = 0; + cairo_stroke(cr); + if (i % 2) { + cairo_move_to(cr, i - .5, CYPOS(chn->data_max[i])); + } else { + cairo_move_to(cr, i - .5, CYPOS(chn->data_min[i])); + } + } + } + + if (pathlength > 0) { + cairo_stroke(cr); + } + + // Draw current position vertical line if display is slow + if (ui->stride >= ui->rate / 4800.0f || ui->paused) { + cairo_set_source_rgba(cr, .9, .2, .2, .6); + cairo_move_to(cr, chn->idx - .5, DAHEIGHT * c); + cairo_line_to(cr, chn->idx - .5, DAHEIGHT * (c + 1)); + cairo_stroke(cr); + } + + // Undo the 'clipping' restriction + cairo_restore(cr); + + // Channel separator + if (c > 0) { + cairo_set_source_rgba(cr, .5, .5, .5, 1.0); + cairo_move_to(cr, 0, DAHEIGHT * c - .5); + cairo_line_to(cr, DAWIDTH, DAHEIGHT * c - .5); + cairo_stroke(cr); + } + + // Zero scale line + cairo_set_source_rgba(cr, .3, .3, .7, .5); + cairo_move_to(cr, 0, DAHEIGHT * (c + .5) - .5); + cairo_line_to(cr, DAWIDTH, DAHEIGHT * (c + .5) - .5); + cairo_stroke(cr); + } + + cairo_destroy(cr); + return TRUE; } /** @@ -346,27 +345,27 @@ process_channel(EgScopeUI* ui, uint32_t* idx_start, uint32_t* idx_end) { - int overflow = 0; - *idx_start = chn->idx; - for (size_t i = 0; i < n_elem; ++i) { - if (data[i] < chn->data_min[chn->idx]) { - chn->data_min[chn->idx] = data[i]; - } - if (data[i] > chn->data_max[chn->idx]) { - chn->data_max[chn->idx] = data[i]; - } - if (++chn->sub >= ui->stride) { - chn->sub = 0; - chn->idx = (chn->idx + 1) % DAWIDTH; - if (chn->idx == 0) { - ++overflow; - } - chn->data_min[chn->idx] = 1.0f; - chn->data_max[chn->idx] = -1.0f; - } - } - *idx_end = chn->idx; - return overflow; + int overflow = 0; + *idx_start = chn->idx; + for (size_t i = 0; i < n_elem; ++i) { + if (data[i] < chn->data_min[chn->idx]) { + chn->data_min[chn->idx] = data[i]; + } + if (data[i] > chn->data_max[chn->idx]) { + chn->data_max[chn->idx] = data[i]; + } + if (++chn->sub >= ui->stride) { + chn->sub = 0; + chn->idx = (chn->idx + 1) % DAWIDTH; + if (chn->idx == 0) { + ++overflow; + } + chn->data_min[chn->idx] = 1.0f; + chn->data_max[chn->idx] = -1.0f; + } + } + *idx_end = chn->idx; + return overflow; } /** @@ -379,56 +378,57 @@ update_scope(EgScopeUI* ui, const size_t n_elem, float const* data) { - // Never trust input data which could lead to application failure. - if (channel < 0 || (uint32_t)channel > ui->n_channels) { - return; - } - - // Update state in sync with 1st channel - if (channel == 0) { - ui->stride = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_speed)); - const bool paused = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(ui->btn_pause)); - - if (paused != ui->paused) { - ui->paused = paused; - gtk_widget_queue_draw(ui->darea); - } - } - if (ui->paused) { - return; - } - - uint32_t idx_start = 0; // Display pixel start - uint32_t idx_end = 0; // Display pixel end - int overflow = 0; // Received more audio-data than display-pixel - - // Process this channel's audio-data for display - ScoChan* chn = &ui->chn[channel]; - overflow = process_channel(ui, chn, n_elem, data, &idx_start, &idx_end); - - // Signal gtk's main thread to redraw the widget after the last channel - if ((uint32_t)channel + 1 == ui->n_channels) { - if (overflow > 1) { - // Redraw complete widget - gtk_widget_queue_draw(ui->darea); - } else if (idx_end > idx_start) { - // Redraw area between start -> end pixel - gtk_widget_queue_draw_area(ui->darea, idx_start - 2, 0, 3 - + idx_end - idx_start, - DAHEIGHT * ui->n_channels); - } else if (idx_end < idx_start) { - // Wrap-around: redraw area between 0->start AND end->right-end - gtk_widget_queue_draw_area( - ui->darea, - idx_start - 2, 0, - 3 + DAWIDTH - idx_start, DAHEIGHT * ui->n_channels); - gtk_widget_queue_draw_area( - ui->darea, - 0, 0, - idx_end + 1, DAHEIGHT * ui->n_channels); - } - } + // Never trust input data which could lead to application failure. + if (channel < 0 || (uint32_t)channel > ui->n_channels) { + return; + } + + // Update state in sync with 1st channel + if (channel == 0) { + ui->stride = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_speed)); + const bool paused = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui->btn_pause)); + + if (paused != ui->paused) { + ui->paused = paused; + gtk_widget_queue_draw(ui->darea); + } + } + if (ui->paused) { + return; + } + + uint32_t idx_start = 0; // Display pixel start + uint32_t idx_end = 0; // Display pixel end + int overflow = 0; // Received more audio-data than display-pixel + + // Process this channel's audio-data for display + ScoChan* chn = &ui->chn[channel]; + overflow = process_channel(ui, chn, n_elem, data, &idx_start, &idx_end); + + // Signal gtk's main thread to redraw the widget after the last channel + if ((uint32_t)channel + 1 == ui->n_channels) { + if (overflow > 1) { + // Redraw complete widget + gtk_widget_queue_draw(ui->darea); + } else if (idx_end > idx_start) { + // Redraw area between start -> end pixel + gtk_widget_queue_draw_area(ui->darea, + idx_start - 2, + 0, + 3 + idx_end - idx_start, + DAHEIGHT * ui->n_channels); + } else if (idx_end < idx_start) { + // Wrap-around: redraw area between 0->start AND end->right-end + gtk_widget_queue_draw_area(ui->darea, + idx_start - 2, + 0, + 3 + DAWIDTH - idx_start, + DAHEIGHT * ui->n_channels); + gtk_widget_queue_draw_area( + ui->darea, 0, 0, idx_end + 1, DAHEIGHT * ui->n_channels); + } + } } static LV2UI_Handle @@ -440,199 +440,191 @@ instantiate(const LV2UI_Descriptor* descriptor, LV2UI_Widget* widget, const LV2_Feature* const* features) { - EgScopeUI* ui = (EgScopeUI*)calloc(1, sizeof(EgScopeUI)); - - if (!ui) { - fprintf(stderr, "EgScope.lv2 UI: out of memory\n"); - return NULL; - } - - ui->map = NULL; - *widget = NULL; - - if (!strcmp(plugin_uri, SCO_URI "#Mono")) { - ui->n_channels = 1; - } else if (!strcmp(plugin_uri, SCO_URI "#Stereo")) { - ui->n_channels = 2; - } else { - free(ui); - return NULL; - } - - for (int i = 0; features[i]; ++i) { - if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) { - ui->map = (LV2_URID_Map*)features[i]->data; - } - } - - if (!ui->map) { - fprintf(stderr, "EgScope.lv2 UI: Host does not support urid:map\n"); - free(ui); - return NULL; - } - - // Initialize private data structure - ui->write = write_function; - ui->controller = controller; - - ui->vbox = NULL; - ui->hbox = NULL; - ui->darea = NULL; - ui->stride = 25; - ui->paused = false; - ui->rate = 48000; - - ui->chn[0].idx = 0; - ui->chn[0].sub = 0; - ui->chn[1].idx = 0; - ui->chn[1].sub = 0; - memset(ui->chn[0].data_min, 0, sizeof(float) * DAWIDTH); - memset(ui->chn[0].data_max, 0, sizeof(float) * DAWIDTH); - memset(ui->chn[1].data_min, 0, sizeof(float) * DAWIDTH); - memset(ui->chn[1].data_max, 0, sizeof(float) * DAWIDTH); - - map_sco_uris(ui->map, &ui->uris); - lv2_atom_forge_init(&ui->forge, ui->map); - - // Setup UI - ui->hbox = gtk_hbox_new(FALSE, 0); - ui->vbox = gtk_vbox_new(FALSE, 0); - - ui->darea = gtk_drawing_area_new(); - gtk_widget_set_size_request(ui->darea, DAWIDTH, DAHEIGHT * ui->n_channels); - - ui->lbl_speed = gtk_label_new("Samples/Pixel"); - ui->lbl_amp = gtk_label_new("Amplitude"); - - ui->sep[0] = gtk_hseparator_new(); - ui->sep[1] = gtk_label_new(""); - ui->btn_pause = gtk_toggle_button_new_with_label("Pause"); - - ui->spb_speed_adj = (GtkAdjustment*)gtk_adjustment_new( - 25.0, 1.0, 1000.0, 1.0, 5.0, 0.0); - ui->spb_speed = gtk_spin_button_new(ui->spb_speed_adj, 1.0, 0); - - ui->spb_amp_adj = (GtkAdjustment*)gtk_adjustment_new( - 1.0, 0.1, 6.0, 0.1, 1.0, 0.0); - ui->spb_amp = gtk_spin_button_new(ui->spb_amp_adj, 0.1, 1); - - gtk_box_pack_start(GTK_BOX(ui->hbox), ui->darea, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(ui->hbox), ui->vbox, FALSE, FALSE, 4); - - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_speed, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_speed, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[0], FALSE, FALSE, 8); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_amp, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_amp, FALSE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[1], TRUE, FALSE, 8); - gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_pause, FALSE, FALSE, 2); - - g_signal_connect(G_OBJECT(ui->darea), "expose_event", - G_CALLBACK(on_expose_event), ui); - g_signal_connect(G_OBJECT(ui->spb_amp), "value-changed", - G_CALLBACK(on_cfg_changed), ui); - g_signal_connect(G_OBJECT(ui->spb_speed), "value-changed", - G_CALLBACK(on_cfg_changed), ui); - - *widget = ui->hbox; - - /* Send UIOn message to plugin, which will request state and enable message - transmission. */ - send_ui_enable(ui); - - return ui; + EgScopeUI* ui = (EgScopeUI*)calloc(1, sizeof(EgScopeUI)); + + if (!ui) { + fprintf(stderr, "EgScope.lv2 UI: out of memory\n"); + return NULL; + } + + ui->map = NULL; + *widget = NULL; + + if (!strcmp(plugin_uri, SCO_URI "#Mono")) { + ui->n_channels = 1; + } else if (!strcmp(plugin_uri, SCO_URI "#Stereo")) { + ui->n_channels = 2; + } else { + free(ui); + return NULL; + } + + for (int i = 0; features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) { + ui->map = (LV2_URID_Map*)features[i]->data; + } + } + + if (!ui->map) { + fprintf(stderr, "EgScope.lv2 UI: Host does not support urid:map\n"); + free(ui); + return NULL; + } + + // Initialize private data structure + ui->write = write_function; + ui->controller = controller; + + ui->vbox = NULL; + ui->hbox = NULL; + ui->darea = NULL; + ui->stride = 25; + ui->paused = false; + ui->rate = 48000; + + ui->chn[0].idx = 0; + ui->chn[0].sub = 0; + ui->chn[1].idx = 0; + ui->chn[1].sub = 0; + memset(ui->chn[0].data_min, 0, sizeof(float) * DAWIDTH); + memset(ui->chn[0].data_max, 0, sizeof(float) * DAWIDTH); + memset(ui->chn[1].data_min, 0, sizeof(float) * DAWIDTH); + memset(ui->chn[1].data_max, 0, sizeof(float) * DAWIDTH); + + map_sco_uris(ui->map, &ui->uris); + lv2_atom_forge_init(&ui->forge, ui->map); + + // Setup UI + ui->hbox = gtk_hbox_new(FALSE, 0); + ui->vbox = gtk_vbox_new(FALSE, 0); + + ui->darea = gtk_drawing_area_new(); + gtk_widget_set_size_request(ui->darea, DAWIDTH, DAHEIGHT * ui->n_channels); + + ui->lbl_speed = gtk_label_new("Samples/Pixel"); + ui->lbl_amp = gtk_label_new("Amplitude"); + + ui->sep[0] = gtk_hseparator_new(); + ui->sep[1] = gtk_label_new(""); + ui->btn_pause = gtk_toggle_button_new_with_label("Pause"); + + ui->spb_speed_adj = + (GtkAdjustment*)gtk_adjustment_new(25.0, 1.0, 1000.0, 1.0, 5.0, 0.0); + ui->spb_speed = gtk_spin_button_new(ui->spb_speed_adj, 1.0, 0); + + ui->spb_amp_adj = + (GtkAdjustment*)gtk_adjustment_new(1.0, 0.1, 6.0, 0.1, 1.0, 0.0); + ui->spb_amp = gtk_spin_button_new(ui->spb_amp_adj, 0.1, 1); + + gtk_box_pack_start(GTK_BOX(ui->hbox), ui->darea, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(ui->hbox), ui->vbox, FALSE, FALSE, 4); + + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_speed, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_speed, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[0], FALSE, FALSE, 8); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_amp, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_amp, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[1], TRUE, FALSE, 8); + gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_pause, FALSE, FALSE, 2); + + g_signal_connect( + G_OBJECT(ui->darea), "expose_event", G_CALLBACK(on_expose_event), ui); + g_signal_connect( + G_OBJECT(ui->spb_amp), "value-changed", G_CALLBACK(on_cfg_changed), ui); + g_signal_connect( + G_OBJECT(ui->spb_speed), "value-changed", G_CALLBACK(on_cfg_changed), ui); + + *widget = ui->hbox; + + /* Send UIOn message to plugin, which will request state and enable message + transmission. */ + send_ui_enable(ui); + + return ui; } static void cleanup(LV2UI_Handle handle) { - EgScopeUI* ui = (EgScopeUI*)handle; - /* Send UIOff message to plugin, which will save state and disable message - * transmission. */ - send_ui_disable(ui); - gtk_widget_destroy(ui->darea); - free(ui); + EgScopeUI* ui = (EgScopeUI*)handle; + /* Send UIOff message to plugin, which will save state and disable message + * transmission. */ + send_ui_disable(ui); + gtk_widget_destroy(ui->darea); + free(ui); } static int recv_raw_audio(EgScopeUI* ui, const LV2_Atom_Object* obj) { - const LV2_Atom* chan_val = NULL; - const LV2_Atom* data_val = NULL; - - // clang-format off - const int n_props = lv2_atom_object_get( - obj, - ui->uris.channelID, &chan_val, - ui->uris.audioData, &data_val, - NULL); - // clang-format on - - if (n_props != 2 || - chan_val->type != ui->uris.atom_Int || - data_val->type != ui->uris.atom_Vector) { - // Object does not have the required properties with correct types - fprintf(stderr, "eg-scope.lv2 UI error: Corrupt audio message\n"); - return 1; - } - - // Get the values we need from the body of the property value atoms - const int32_t chn = ((const LV2_Atom_Int*)chan_val)->body; - const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val; - if (vec->body.child_type != ui->uris.atom_Float) { - return 1; // Vector has incorrect element type - } - - // Number of elements = (total size - header size) / element size - const size_t n_elem = ((data_val->size - sizeof(LV2_Atom_Vector_Body)) - / sizeof(float)); - - // Float elements immediately follow the vector body header - const float* data = (const float*)(&vec->body + 1); - - // Update display - update_scope(ui, chn, n_elem, data); - return 0; + const LV2_Atom* chan_val = NULL; + const LV2_Atom* data_val = NULL; + const int n_props = lv2_atom_object_get( + obj, ui->uris.channelID, &chan_val, ui->uris.audioData, &data_val, NULL); + + if (n_props != 2 || chan_val->type != ui->uris.atom_Int || + data_val->type != ui->uris.atom_Vector) { + // Object does not have the required properties with correct types + fprintf(stderr, "eg-scope.lv2 UI error: Corrupt audio message\n"); + return 1; + } + + // Get the values we need from the body of the property value atoms + const int32_t chn = ((const LV2_Atom_Int*)chan_val)->body; + const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val; + if (vec->body.child_type != ui->uris.atom_Float) { + return 1; // Vector has incorrect element type + } + + // Number of elements = (total size - header size) / element size + const size_t n_elem = + ((data_val->size - sizeof(LV2_Atom_Vector_Body)) / sizeof(float)); + + // Float elements immediately follow the vector body header + const float* data = (const float*)(&vec->body + 1); + + // Update display + update_scope(ui, chn, n_elem, data); + return 0; } static int recv_ui_state(EgScopeUI* ui, const LV2_Atom_Object* obj) { - const LV2_Atom* spp_val = NULL; - const LV2_Atom* amp_val = NULL; - const LV2_Atom* rate_val = NULL; - - // clang-format off - const int n_props = lv2_atom_object_get( - obj, - ui->uris.ui_spp, &spp_val, - ui->uris.ui_amp, &_val, - ui->uris.param_sampleRate, &rate_val, - NULL); - // clang-format on - - if (n_props != 3 || - spp_val->type != ui->uris.atom_Int || - amp_val->type != ui->uris.atom_Float || - rate_val->type != ui->uris.atom_Float) { - // Object does not have the required properties with correct types - fprintf(stderr, "eg-scope.lv2 UI error: Corrupt state message\n"); - return 1; - } - - // Get the values we need from the body of the property value atoms - const int32_t spp = ((const LV2_Atom_Int*)spp_val)->body; - const float amp = ((const LV2_Atom_Float*)amp_val)->body; - const float rate = ((const LV2_Atom_Float*)rate_val)->body; - - // Disable transmission and update UI - ui->updating = true; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_speed), spp); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_amp), amp); - ui->updating = false; - ui->rate = rate; - - return 0; + const LV2_Atom* spp_val = NULL; + const LV2_Atom* amp_val = NULL; + const LV2_Atom* rate_val = NULL; + + const int n_props = lv2_atom_object_get(obj, + ui->uris.ui_spp, + &spp_val, + ui->uris.ui_amp, + &_val, + ui->uris.param_sampleRate, + &rate_val, + NULL); + + if (n_props != 3 || spp_val->type != ui->uris.atom_Int || + amp_val->type != ui->uris.atom_Float || + rate_val->type != ui->uris.atom_Float) { + // Object does not have the required properties with correct types + fprintf(stderr, "eg-scope.lv2 UI error: Corrupt state message\n"); + return 1; + } + + // Get the values we need from the body of the property value atoms + const int32_t spp = ((const LV2_Atom_Int*)spp_val)->body; + const float amp = ((const LV2_Atom_Float*)amp_val)->body; + const float rate = ((const LV2_Atom_Float*)rate_val)->body; + + // Disable transmission and update UI + ui->updating = true; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_speed), spp); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_amp), amp); + ui->updating = false; + ui->rate = rate; + + return 0; } /** @@ -650,35 +642,33 @@ port_event(LV2UI_Handle handle, uint32_t format, const void* buffer) { - EgScopeUI* ui = (EgScopeUI*)handle; - const LV2_Atom* atom = (const LV2_Atom*)buffer; - - /* Check type of data received - * - format == 0: Control port event (float) - * - format > 0: Message (atom) - */ - if (format == ui->uris.atom_eventTransfer && - lv2_atom_forge_is_object_type(&ui->forge, atom->type)) { - const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; - if (obj->body.otype == ui->uris.RawAudio) { - recv_raw_audio(ui, obj); - } else if (obj->body.otype == ui->uris.ui_State) { - recv_ui_state(ui, obj); - } - } + EgScopeUI* ui = (EgScopeUI*)handle; + const LV2_Atom* atom = (const LV2_Atom*)buffer; + + /* Check type of data received + * - format == 0: Control port event (float) + * - format > 0: Message (atom) + */ + if (format == ui->uris.atom_eventTransfer && + lv2_atom_forge_is_object_type(&ui->forge, atom->type)) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; + if (obj->body.otype == ui->uris.RawAudio) { + recv_raw_audio(ui, obj); + } else if (obj->body.otype == ui->uris.ui_State) { + recv_ui_state(ui, obj); + } + } } -static const LV2UI_Descriptor descriptor = { - SCO_URI "#ui", - instantiate, - cleanup, - port_event, - NULL -}; +static const LV2UI_Descriptor descriptor = {SCO_URI "#ui", + instantiate, + cleanup, + port_event, + NULL}; LV2_SYMBOL_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) { - return index == 0 ? &descriptor : NULL; + return index == 0 ? &descriptor : NULL; } diff --git a/plugins/eg-scope.lv2/uris.h b/plugins/eg-scope.lv2/uris.h index cba978f..8873786 100644 --- a/plugins/eg-scope.lv2/uris.h +++ b/plugins/eg-scope.lv2/uris.h @@ -24,47 +24,47 @@ #define SCO_URI "http://lv2plug.in/plugins/eg-scope" typedef struct { - // URIs defined in LV2 specifications - LV2_URID atom_Vector; - LV2_URID atom_Float; - LV2_URID atom_Int; - LV2_URID atom_eventTransfer; - LV2_URID param_sampleRate; + // URIs defined in LV2 specifications + LV2_URID atom_Vector; + LV2_URID atom_Float; + LV2_URID atom_Int; + LV2_URID atom_eventTransfer; + LV2_URID param_sampleRate; - /* URIs defined for this plugin. It is best to re-use existing URIs as - much as possible, but plugins may need more vocabulary specific to their - needs. These are used as types and properties for plugin:UI - communication, as well as for saving state. */ - LV2_URID RawAudio; - LV2_URID channelID; - LV2_URID audioData; - LV2_URID ui_On; - LV2_URID ui_Off; - LV2_URID ui_State; - LV2_URID ui_spp; - LV2_URID ui_amp; + /* URIs defined for this plugin. It is best to re-use existing URIs as + much as possible, but plugins may need more vocabulary specific to their + needs. These are used as types and properties for plugin:UI + communication, as well as for saving state. */ + LV2_URID RawAudio; + LV2_URID channelID; + LV2_URID audioData; + LV2_URID ui_On; + LV2_URID ui_Off; + LV2_URID ui_State; + LV2_URID ui_spp; + LV2_URID ui_amp; } ScoLV2URIs; static inline void map_sco_uris(LV2_URID_Map* map, ScoLV2URIs* uris) { - uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector); - uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); - uris->atom_Int = map->map(map->handle, LV2_ATOM__Int); - uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); - uris->param_sampleRate = map->map(map->handle, LV2_PARAMETERS__sampleRate); + uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector); + uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); + uris->atom_Int = map->map(map->handle, LV2_ATOM__Int); + uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer); + uris->param_sampleRate = map->map(map->handle, LV2_PARAMETERS__sampleRate); - /* Note the convention that URIs for types are capitalized, and URIs for - everything else (mainly properties) are not, just as in LV2 - specifications. */ - uris->RawAudio = map->map(map->handle, SCO_URI "#RawAudio"); - uris->audioData = map->map(map->handle, SCO_URI "#audioData"); - uris->channelID = map->map(map->handle, SCO_URI "#channelID"); - uris->ui_On = map->map(map->handle, SCO_URI "#UIOn"); - uris->ui_Off = map->map(map->handle, SCO_URI "#UIOff"); - uris->ui_State = map->map(map->handle, SCO_URI "#UIState"); - uris->ui_spp = map->map(map->handle, SCO_URI "#ui-spp"); - uris->ui_amp = map->map(map->handle, SCO_URI "#ui-amp"); + /* Note the convention that URIs for types are capitalized, and URIs for + everything else (mainly properties) are not, just as in LV2 + specifications. */ + uris->RawAudio = map->map(map->handle, SCO_URI "#RawAudio"); + uris->audioData = map->map(map->handle, SCO_URI "#audioData"); + uris->channelID = map->map(map->handle, SCO_URI "#channelID"); + uris->ui_On = map->map(map->handle, SCO_URI "#UIOn"); + uris->ui_Off = map->map(map->handle, SCO_URI "#UIOff"); + uris->ui_State = map->map(map->handle, SCO_URI "#UIState"); + uris->ui_spp = map->map(map->handle, SCO_URI "#ui-spp"); + uris->ui_amp = map->map(map->handle, SCO_URI "#ui-amp"); } -#endif /* SCO_URIS_H */ +#endif /* SCO_URIS_H */ |