On Thu, 2009-07-30 at 11:27 +0100, james morris wrote:
> Are there any similar testing tools for LV2 plugins?
>
> Although I'm familiar with gdb and valgrind, I don't know how to go
> about using these with plugins, and I guess/assume a simple host
> (perhaps one specifically designed for testing) would be best for doing
> this? Are there any existing tools?
I've done a quick port of my little test app to LV2. I've attached it.
We could add the various control port input tests from demolition later.
My first test results:
calf - memory errors in 2 of the small plugins.
(plus the organ had an unknown port type so was skipped)
ll - OK, except 3 of the plugins couldn't be instantiated.
2 seem to have incorrect URLs in the cpp files.
Not sure about the other one.
swh - crashes (a known bug actually).
Damon
/*
* Test app to load & run all LV2 plugins for one cycle.
*
* Compile with:
* gcc `pkg-config --cflags --libs slv2 glib-2.0` -lm -o test-lv2 test-lv2.c
*
* Simply run it with './test-lv2' to test all plugins.
* Run it with './test-lv2 -p PACKAGE' to test a particular package.
* (Run ./test-lv2 --help to see the list of known packages.)
*
* Run it with 'valgrind --tool=memcheck ./test-lv2' to spot memory errors.
*
* Released under GNU General Public License version 2.
* Bits from lv2_jack_host Copyright (C) 2007-2009 Dave Robillard <drobilla.net>
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <slv2/slv2.h>
/* The sample rate to pass to the plugins. We don't output audio so it's not
too important. */
#define SAMPLE_RATE 48000
/* The number of samples to use for the run. Again, not too important. */
#define NUM_SAMPLES 256
/* The size of the event buffer. */
#define EVENT_BUFFER_CAPACITY 1024
static char *package = NULL;
static char *uri_prefix = NULL;
static int uri_prefix_len = 0;
static char *plugin_uri = NULL;
static SLV2Value audio_class;
static SLV2Value control_class;
static SLV2Value event_class;
/* LV2_URI_Map stuff. */
#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map"
typedef void* LV2_URI_Map_Callback_Data;
typedef struct {
LV2_URI_Map_Callback_Data callback_data;
uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data,
const char* map,
const char* uri);
} LV2_URI_Map_Feature;
/* LV2_Event stuff. */
#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event"
#define LV2_EVENT_AUDIO_STAMP 0
typedef struct {
uint32_t frames;
uint32_t subframes;
uint16_t type;
uint16_t size;
} LV2_Event;
typedef struct {
uint8_t* data;
uint16_t header_size;
uint16_t stamp_type;
uint32_t event_count;
uint32_t capacity;
uint32_t size;
} LV2_Event_Buffer;
typedef void* LV2_Event_Callback_Data;
typedef struct {
LV2_Event_Callback_Data callback_data;
uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data,
LV2_Event* event);
uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data,
LV2_Event* event);
} LV2_Event_Feature;
/** URI map feature, for event types (we use only MIDI) */
#define MIDI_EVENT_ID 1
uint32_t
uri_to_id(LV2_URI_Map_Callback_Data callback_data,
const char* map,
const char* uri)
{
if (!strcmp(map, LV2_EVENT_URI) && !strcmp(uri, SLV2_EVENT_CLASS_MIDI))
return MIDI_EVENT_ID;
else
return 0; // no id for you!
}
static LV2_URI_Map_Feature uri_map = { NULL, &uri_to_id };
static const LV2_Feature uri_map_feature = { "http://lv2plug.in/ns/ext/uri-map", &uri_map };
/** We don't support type 0 events, so the ref and unref functions just point
to the same empty function. */
uint32_t event_ref_func(LV2_Event_Callback_Data callback_data,
LV2_Event* event)
{
return 0;
}
static LV2_Event_Feature event_ref = { NULL, &event_ref_func, &event_ref_func };
static const LV2_Feature event_ref_feature = { "http://lv2plug.in/ns/ext/event",
&event_ref };
const LV2_Feature* features[3] = { &uri_map_feature, &event_ref_feature, NULL };
static gboolean
port_is_a (SLV2Plugin plugin,
SLV2Port port,
SLV2Value value)
{
SLV2Values port_classes = slv2_port_get_classes (plugin, port);
gint i, num_classes = slv2_values_size (port_classes);
const gchar *value_string = slv2_value_as_string (value);
SLV2Value class_value;
for (i = 0; i < num_classes; i++)
{
class_value = slv2_values_get_at (port_classes, i);
if (!strcmp (slv2_value_as_string (class_value), value_string))
return TRUE;
}
return FALSE;
}
static gpointer
create_buffer_for_port (SLV2Plugin plugin,
gint port_num)
{
SLV2Port port;
SLV2Value def, min, max;
LV2_Event_Buffer *event_buffer;
gfloat *buffer = NULL;
gint i;
port = slv2_plugin_get_port_by_index (plugin, port_num);
if (port_is_a (plugin, port, audio_class))
{
buffer = g_new (float, NUM_SAMPLES);
for (i = 0; i < NUM_SAMPLES; i++)
buffer[i] = 0.0F;
}
else if (port_is_a (plugin, port, control_class))
{
buffer = g_new (float, 1);
*buffer = 0.0f;
slv2_port_get_range (plugin, port, &def, &min, &max);
if (def)
{
*buffer = slv2_value_as_float (def);
slv2_value_free (def);
}
if (min)
slv2_value_free (min);
if (max)
slv2_value_free (max);
}
else if (port_is_a (plugin, port, event_class))
{
buffer = malloc (sizeof (LV2_Event_Buffer) + EVENT_BUFFER_CAPACITY);
event_buffer = (LV2_Event_Buffer*) buffer;
event_buffer->capacity = EVENT_BUFFER_CAPACITY;
event_buffer->header_size = sizeof (LV2_Event_Buffer);
event_buffer->data = (uint8_t*) buffer + event_buffer->header_size;
event_buffer->stamp_type = LV2_EVENT_AUDIO_STAMP;
event_buffer->event_count = 0;
event_buffer->size = 0;
}
else
g_print ("WARNING: Unknown port signal type. Skipping plugin.\n");
return buffer;
}
static void
test_lv2_plugin (SLV2Plugin plugin)
{
SLV2Value uri_value, name_value, plugin_class_value;
const gchar *uri, *name, *category;
SLV2PluginClass plugin_class;
SLV2Instance instance;
GList *buffers = NULL, *elem;
gpointer buffer;
gint num_ports, port_num;
gboolean run_test = TRUE;
uri_value = slv2_plugin_get_uri (plugin);
uri = slv2_value_as_string (uri_value);
if (plugin_uri && strcmp (uri, plugin_uri))
return;
if (uri_prefix && strncmp (uri, uri_prefix, uri_prefix_len))
return;
#if 1
g_print ("###############################################################################\n");
#endif
name_value = slv2_plugin_get_name (plugin);
name = slv2_value_as_string (name_value);
#if 1
g_print ("Testing %s (%s)\n", name, uri);
#endif
slv2_value_free (name_value);
plugin_class = slv2_plugin_get_class (plugin);
plugin_class_value = slv2_plugin_class_get_label (plugin_class);
category = slv2_value_as_string (plugin_class_value);
/* Instantiate the plugin. */
instance = slv2_plugin_instantiate (plugin, SAMPLE_RATE, features);
if (!instance)
{
g_print ("ERROR: Unable to instantiate plugin: %s\n", uri);
return;
}
/* Connect up the ports. */
num_ports = slv2_plugin_get_num_ports (plugin);
for (port_num = 0; port_num < num_ports; port_num++)
{
buffer = create_buffer_for_port (plugin, port_num);
if (buffer)
{
#if 0
g_print ("Connecting port: %i to: %p\n", port_num, buffer);
#endif
slv2_instance_connect_port (instance, port_num, buffer);
buffers = g_list_prepend (buffers, buffer);
}
else
{
run_test = FALSE;
break;
}
}
if (run_test)
{
/* Activate it. */
slv2_instance_activate (instance);
/* Run it. */
slv2_instance_run (instance, NUM_SAMPLES);
/* Deactivate it. */
slv2_instance_deactivate (instance);
}
/* Free the buffers. */
for (elem = buffers; elem; elem = elem->next)
g_free (elem->data);
g_list_free (buffers);
/* Free it. */
slv2_instance_free (instance);
}
static void
test_lv2_plugins (void)
{
SLV2World slv2_world;
SLV2Plugins slv2_plugins;
SLV2Plugin plugin;
gint num_plugins, i;
slv2_world = slv2_world_new ();
audio_class = slv2_value_new_uri (slv2_world, SLV2_PORT_CLASS_AUDIO);
control_class = slv2_value_new_uri (slv2_world, SLV2_PORT_CLASS_CONTROL);
event_class = slv2_value_new_uri (slv2_world, SLV2_PORT_CLASS_EVENT);
slv2_world_load_all (slv2_world);
slv2_plugins = slv2_world_get_all_plugins (slv2_world);
num_plugins = slv2_plugins_size (slv2_plugins);
for (i = 0; i < num_plugins; i++)
{
plugin = slv2_plugins_get_at (slv2_plugins, i);
test_lv2_plugin (plugin);
}
}
/* Command-line options. */
static GOptionEntry entries[] =
{
{ "package", 'p', 0, G_OPTION_ARG_STRING, &package,
"Package to test (one of calf, ll or swh)", "PACKAGE" },
{ "uri", 'u', 0, G_OPTION_ARG_STRING, &plugin_uri,
"URI of plugin to test", "URI" },
{ NULL }
};
int
main (int argc, char *argv[])
{
GOptionContext *context;
GError *error = NULL;
context = g_option_context_new ("- test LV2 plugins");
g_option_context_add_main_entries (context, entries, NULL);
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_print ("option parsing failed: %s\n", error->message);
exit (1);
}
/* If a package is specified, set the appropriate uri prefix to match. */
if (package)
{
if (!strcmp (package, "calf"))
uri_prefix = "http://calf.sourceforge.net/";
else if (!strcmp (package, "ll"))
uri_prefix = "http://ll-plugins.nongnu.org/lv2/";
else if (!strcmp (package, "swh"))
uri_prefix = "http://plugin.org.uk/swh-plugins/";
else
{
g_print ("unknown package: %s\n", package);
exit (1);
}
uri_prefix_len = strlen (uri_prefix);
}
test_lv2_plugins ();
return 0;
}
_______________________________________________
Linux-audio-dev mailing list
[email protected]
http://lists.linuxaudio.org/mailman/listinfo/linux-audio-dev