summaryrefslogtreecommitdiffstats
path: root/test/test_plugin.lv2
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-01-11 02:35:06 +0100
committerDavid Robillard <d@drobilla.net>2021-03-24 10:58:32 -0400
commit52cd7ee00e64a021128034da5855a88be52f0871 (patch)
tree676708459122aeeaf65c9d4c05a39798e7c4be6f /test/test_plugin.lv2
parent71a2ff5170caaa052814cce19b3de927d10d0e24 (diff)
downloadlilv-52cd7ee00e64a021128034da5855a88be52f0871.tar.gz
lilv-52cd7ee00e64a021128034da5855a88be52f0871.tar.bz2
lilv-52cd7ee00e64a021128034da5855a88be52f0871.zip
WIP: Switch to Meson
Diffstat (limited to 'test/test_plugin.lv2')
-rw-r--r--test/test_plugin.lv2/manifest.ttl.in7
-rw-r--r--test/test_plugin.lv2/meson.build16
-rw-r--r--test/test_plugin.lv2/test_plugin.c441
-rw-r--r--test/test_plugin.lv2/test_plugin.ttl.in46
4 files changed, 510 insertions, 0 deletions
diff --git a/test/test_plugin.lv2/manifest.ttl.in b/test/test_plugin.lv2/manifest.ttl.in
new file mode 100644
index 0000000..48b009b
--- /dev/null
+++ b/test/test_plugin.lv2/manifest.ttl.in
@@ -0,0 +1,7 @@
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<http://example.org/lilv-test-plugin>
+ a lv2:Plugin ;
+ lv2:binary <test_plugin@SHLIB_EXT@> ;
+ rdfs:seeAlso <test_plugin.ttl> .
diff --git a/test/test_plugin.lv2/meson.build b/test/test_plugin.lv2/meson.build
new file mode 100644
index 0000000..eb12c4f
--- /dev/null
+++ b/test/test_plugin.lv2/meson.build
@@ -0,0 +1,16 @@
+module = shared_module('test_plugin',
+ 'test_plugin.c',
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '')
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'test_plugin.ttl']
+
+foreach f : ttl_files
+ configure_file(input: f + '.in',
+ output: f,
+ configuration: config)
+endforeach
+
diff --git a/test/test_plugin.lv2/test_plugin.c b/test/test_plugin.lv2/test_plugin.c
new file mode 100644
index 0000000..2be34b4
--- /dev/null
+++ b/test/test_plugin.lv2/test_plugin.c
@@ -0,0 +1,441 @@
+/*
+ Lilv Test Plugin
+ Copyright 2011-2019 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#define _POSIX_C_SOURCE 200809L
+
+#include "lv2/atom/atom.h"
+#include "lv2/core/lv2.h"
+#include "lv2/state/state.h"
+#include "lv2/urid/urid.h"
+
+#ifdef _MSC_VER
+# include <io.h>
+# define mkstemp(pat) _mktemp(pat)
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_URI "http://example.org/lilv-test-plugin"
+
+#define TMP_TEMPLATE "lilv_testXXXXXX"
+
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1, TEST_CONTROL = 2 };
+
+typedef struct {
+ LV2_URID_Map* map;
+ LV2_State_Free_Path* free_path;
+
+ struct {
+ LV2_URID atom_Float;
+ } uris;
+
+ char tmp_file_path[sizeof(TMP_TEMPLATE)];
+ char* rec_file_path;
+ FILE* rec_file;
+
+ float* input;
+ float* output;
+ unsigned num_runs;
+} Test;
+
+static void
+cleanup(LV2_Handle instance)
+{
+ Test* test = (Test*)instance;
+ if (test->rec_file) {
+ fclose(test->rec_file);
+ }
+
+ if (test->free_path) {
+ test->free_path->free_path(test->free_path->handle, test->rec_file_path);
+ }
+
+ free(instance);
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void* data)
+{
+ Test* test = (Test*)instance;
+ switch (port) {
+ case TEST_INPUT:
+ test->input = (float*)data;
+ break;
+ case TEST_OUTPUT:
+ test->output = (float*)data;
+ break;
+ case TEST_CONTROL:
+ test->output = (float*)data;
+ break;
+ default:
+ break;
+ }
+}
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor,
+ double rate,
+ const char* path,
+ const LV2_Feature* const* features)
+{
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+
+ Test* test = (Test*)calloc(1, sizeof(Test));
+ if (!test) {
+ return NULL;
+ }
+
+ strncpy(test->tmp_file_path, TMP_TEMPLATE, strlen(TMP_TEMPLATE) + 1);
+ mkstemp(test->tmp_file_path);
+
+ LV2_State_Make_Path* make_path = NULL;
+
+ for (int i = 0; features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
+ test->map = (LV2_URID_Map*)features[i]->data;
+ test->uris.atom_Float =
+ test->map->map(test->map->handle, LV2_ATOM__Float);
+ } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
+ make_path = (LV2_State_Make_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ test->free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ if (!test->map) {
+ fprintf(stderr, "Host does not support urid:map\n");
+ free(test);
+ return NULL;
+ }
+
+ if (make_path) {
+ if (!test->free_path) {
+ fprintf(stderr, "Host provided make_path without free_path\n");
+ free(test);
+ return NULL;
+ }
+
+ test->rec_file_path = make_path->path(make_path->handle, "recfile");
+ if (!(test->rec_file = fopen(test->rec_file_path, "w"))) {
+ fprintf(stderr, "ERROR: Failed to open rec file\n");
+ }
+ fprintf(test->rec_file, "instantiate\n");
+ }
+
+ return (LV2_Handle)test;
+}
+
+static void
+run(LV2_Handle instance, uint32_t sample_count)
+{
+ Test* test = (Test*)instance;
+ *test->output = *test->input;
+ if (sample_count == 1) {
+ ++test->num_runs;
+ } else if (sample_count == 2 && test->rec_file) {
+ // Append to rec file (changes size)
+ fprintf(test->rec_file, "run\n");
+ } else if (sample_count == 3 && test->rec_file) {
+ // Change the first byte of rec file (doesn't change size)
+ fseek(test->rec_file, 0, SEEK_SET);
+ fprintf(test->rec_file, "X");
+ fseek(test->rec_file, 0, SEEK_END);
+ }
+}
+
+static uint32_t
+map_uri(Test* plugin, const char* uri)
+{
+ return plugin->map->map(plugin->map->handle, uri);
+}
+
+static LV2_State_Status
+save(LV2_Handle instance,
+ LV2_State_Store_Function store,
+ void* callback_data,
+ uint32_t flags,
+ const LV2_Feature* const* features)
+{
+ (void)flags;
+
+ Test* plugin = (Test*)instance;
+
+ LV2_State_Map_Path* map_path = NULL;
+ LV2_State_Make_Path* make_path = NULL;
+ LV2_State_Free_Path* free_path = NULL;
+ for (int i = 0; features && features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
+ map_path = (LV2_State_Map_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
+ make_path = (LV2_State_Make_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ if (!map_path || !free_path) {
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/greeting"),
+ "hello",
+ strlen("hello") + 1,
+ map_uri(plugin, LV2_ATOM__String),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t urid = map_uri(plugin, "http://example.org/urivalue");
+ store(callback_data,
+ map_uri(plugin, "http://example.org/uri"),
+ &urid,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ // Try to store second value for the same property (should fail)
+ const uint32_t urid2 = map_uri(plugin, "http://example.org/urivalue2");
+ if (!store(callback_data,
+ map_uri(plugin, "http://example.org/uri"),
+ &urid2,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
+ return LV2_STATE_ERR_UNKNOWN;
+ }
+
+ // Try to store with a null key (should fail)
+ if (!store(callback_data,
+ 0,
+ &urid2,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
+ return LV2_STATE_ERR_UNKNOWN;
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/num-runs"),
+ &plugin->num_runs,
+ sizeof(plugin->num_runs),
+ map_uri(plugin, LV2_ATOM__Int),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const float two = 2.0f;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/two"),
+ &two,
+ sizeof(two),
+ map_uri(plugin, LV2_ATOM__Float),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t affirmative = 1;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/true"),
+ &affirmative,
+ sizeof(affirmative),
+ map_uri(plugin, LV2_ATOM__Bool),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t negative = 0;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/false"),
+ &negative,
+ sizeof(negative),
+ map_uri(plugin, LV2_ATOM__Bool),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint8_t blob[] = "I am a blob of arbitrary data.";
+ store(callback_data,
+ map_uri(plugin, "http://example.org/blob"),
+ blob,
+ sizeof(blob),
+ map_uri(plugin, "http://example.org/SomeUnknownType"),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ if (map_path) {
+ FILE* file = fopen(plugin->tmp_file_path, "w");
+ fprintf(file, "Hello\n");
+ fclose(file);
+ char* apath =
+ map_path->abstract_path(map_path->handle, plugin->tmp_file_path);
+ char* apath2 =
+ map_path->abstract_path(map_path->handle, plugin->tmp_file_path);
+ if (strcmp(apath, apath2)) {
+ fprintf(stderr, "ERROR: Path %s != %s\n", apath, apath2);
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/extfile"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+
+ free_path->free_path(free_path->handle, apath);
+ free_path->free_path(free_path->handle, apath2);
+
+ if (plugin->rec_file) {
+ fflush(plugin->rec_file);
+ apath = map_path->abstract_path(map_path->handle, plugin->rec_file_path);
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/recfile"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+
+ free_path->free_path(free_path->handle, apath);
+ }
+
+ if (make_path) {
+ char* spath = make_path->path(make_path->handle, "save");
+ FILE* sfile = fopen(spath, "w");
+ fprintf(sfile, "save");
+ fclose(sfile);
+
+ apath = map_path->abstract_path(map_path->handle, spath);
+ store(callback_data,
+ map_uri(plugin, "http://example.org/save-file"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+ free_path->free_path(free_path->handle, apath);
+ free_path->free_path(free_path->handle, spath);
+ }
+ }
+
+ return LV2_STATE_SUCCESS;
+}
+
+static LV2_State_Status
+restore(LV2_Handle instance,
+ LV2_State_Retrieve_Function retrieve,
+ void* callback_data,
+ uint32_t flags,
+ const LV2_Feature* const* features)
+{
+ (void)flags;
+
+ Test* plugin = (Test*)instance;
+
+ LV2_State_Map_Path* map_path = NULL;
+ LV2_State_Free_Path* free_path = NULL;
+ for (int i = 0; features && features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
+ map_path = (LV2_State_Map_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ size_t size = 0;
+ uint32_t type = 0;
+ uint32_t valflags = 0;
+
+ plugin->num_runs =
+ *(int32_t*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/num-runs"),
+ &size,
+ &type,
+ &valflags);
+
+ if (!map_path || !free_path) {
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
+
+ char* apath = (char*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/extfile"),
+ &size,
+ &type,
+ &valflags);
+
+ if (valflags != LV2_STATE_IS_POD) {
+ fprintf(stderr, "error: Restored bad file flags\n");
+ return LV2_STATE_ERR_BAD_FLAGS;
+ }
+
+ if (apath) {
+ char* path = map_path->absolute_path(map_path->handle, apath);
+ FILE* f = fopen(path, "r");
+ char str[8];
+ size_t n_read = fread(str, 1, sizeof(str), f);
+ fclose(f);
+ if (strncmp(str, "Hello\n", n_read)) {
+ fprintf(
+ stderr, "error: Restored bad file contents `%s' != `Hello'\n", str);
+ }
+ free_path->free_path(free_path->handle, path);
+ }
+
+ apath = (char*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/save-file"),
+ &size,
+ &type,
+ &valflags);
+ if (apath) {
+ char* spath = map_path->absolute_path(map_path->handle, apath);
+ FILE* sfile = fopen(spath, "r");
+ if (!sfile) {
+ fprintf(stderr, "error: Failed to open save file %s\n", spath);
+ } else {
+ fclose(sfile);
+ }
+ free_path->free_path(free_path->handle, spath);
+ } else {
+ fprintf(stderr, "error: Failed to restore save file.\n");
+ }
+
+ return LV2_STATE_SUCCESS;
+}
+
+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_Descriptor descriptor = {TEST_URI,
+ instantiate,
+ connect_port,
+ NULL, // activate,
+ run,
+ NULL, // deactivate,
+ cleanup,
+ extension_data};
+
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
+{
+ switch (index) {
+ case 0:
+ return &descriptor;
+ default:
+ return NULL;
+ }
+}
diff --git a/test/test_plugin.lv2/test_plugin.ttl.in b/test/test_plugin.lv2/test_plugin.ttl.in
new file mode 100644
index 0000000..1c16b4c
--- /dev/null
+++ b/test/test_plugin.lv2/test_plugin.ttl.in
@@ -0,0 +1,46 @@
+# Lilv Test Plugin
+# Copyright 2011-2015 David Robillard <d@drobilla.net>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+
+<http://example.org/lilv-test-plugin>
+ a lv2:Plugin ;
+ doap:name "Lilv Test" ;
+ doap:license <http://opensource.org/licenses/isc> ;
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/urid#Mapper> ;
+ lv2:optionalFeature lv2:hardRTCapable ;
+ lv2:extensionData <http://lv2plug.in/ns/ext/state#Interface> ;
+ lv2:port [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 0 ;
+ lv2:symbol "input" ;
+ lv2:name "Input"
+ ] , [
+ a lv2:OutputPort ,
+ lv2:ControlPort ;
+ lv2:index 1 ;
+ lv2:symbol "output" ;
+ lv2:name "Output"
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 2 ;
+ lv2:symbol "control" ;
+ lv2:name "Control"
+ ] .