summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lv2/input_lv2.cc27
-rw-r--r--lv2/lv2.cc328
-rw-r--r--lv2/lv2_instance.h5
-rw-r--r--lv2/output_lv2.cc2
-rw-r--r--lv2/output_lv2.h1
-rw-r--r--src/configuration.cc17
-rw-r--r--src/configuration.h2
-rw-r--r--src/drumgizmo.cc41
-rw-r--r--test/Makefile.am14
-rw-r--r--test/kit/instr1.xml2
-rw-r--r--test/kit/instr2.xml2
-rw-r--r--test/kit/kit1.xml2
-rw-r--r--test/kit/kit2.xml2
-rw-r--r--test/lv2.cc332
-rw-r--r--test/lv2_test_host.cc403
-rw-r--r--test/lv2_test_host.h83
16 files changed, 908 insertions, 355 deletions
diff --git a/lv2/input_lv2.cc b/lv2/input_lv2.cc
index d995e75..e70d293 100644
--- a/lv2/input_lv2.cc
+++ b/lv2/input_lv2.cc
@@ -66,6 +66,11 @@ void InputLV2::pre()
event_t *InputLV2::run(size_t pos, size_t len, size_t *nevents)
{
+ if(eventPort == NULL) {
+ *nevents = 0;
+ return NULL;
+ }
+
event_t *list;
size_t listsize;
@@ -99,11 +104,6 @@ event_t *InputLV2::run(size_t pos, size_t len, size_t *nevents)
list[listsize].offset = ev->time.frames;
listsize++;
}
- /*
- start_frame = ev->frames;
- plugin->frame = 0;
- plugin->play = true;
- */
}
ev = lv2_atom_sequence_next(ev);
}
@@ -115,20 +115,3 @@ event_t *InputLV2::run(size_t pos, size_t len, size_t *nevents)
void InputLV2::post()
{
}
-
-#ifdef TEST_INPUT_LV2
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_INPUT_LV2*/
diff --git a/lv2/lv2.cc b/lv2/lv2.cc
index 3aeb5f0..d87665d 100644
--- a/lv2/lv2.cc
+++ b/lv2/lv2.cc
@@ -25,24 +25,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
#include <stdlib.h>
#include <string.h>
#include "lv2_gui.h"
-
#include "lv2_instance.h"
#include <hugin.hpp>
-#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
-
-#define NS_ATOM "http://lv2plug.in/ns/ext/atom#"
-#define NS_DG "http://drumgizmo.org/lv2/atom#"
+#define DRUMGIZMO_URI "http://drumgizmo.org/lv2"
+#define NS_DG DRUMGIZMO_URI "/atom#"
-/*
- * Stuff to handle DrumGizmo* transmission from instance to GUI.
- */
+// Stuff to handle DrumGizmo* transmission from instance to GUI.
static LV2_DrumGizmo_Descriptor dg_descriptor;
static DrumGizmo *dg_get_pci(LV2_Handle instance)
@@ -51,56 +47,6 @@ static DrumGizmo *dg_get_pci(LV2_Handle instance)
return dglv2->dg;
}
-/*
- * Stuff to save/restore plugin state.
- */
-/*
-void dg_save(LV2_Handle instance,
- LV2_State_Store_Function store,
- void* callback_data,
- uint32_t flags,
- const LV2_Feature *const * features)
-{
- DGLV2 *dglv2 = (DGLV2 *)instance;
- printf("dg_save\n");
-
- std::string config = dglv2->dg->configString();
- printf("%s\n", config.c_str());
-
- store(callback_data,
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_DG "config"),
- config.data(), config.length(),
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_ATOM "String"),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-}
-
-void dg_restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- void* callback_data,
- uint32_t flags,
- const LV2_Feature *const * features)
-{
- DGLV2 *dglv2 = (DGLV2 *)instance;
- printf("dg_restore\n");
-
- size_t size;
- uint32_t type;
- // uint32_t flags;
-
- const char* data =
- (const char*)retrieve(callback_data,
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_DG "config"),
- &size, &type, &flags);
- std::string config;
- config.append(data, size);
- dglv2->dg->setConfigString(config);
-
- dglv2->in->loadMidiMap(dglv2->dg->midimapfile);
-}
-*/
LV2_State_Status
dg_save(LV2_Handle instance,
LV2_State_Store_Function store,
@@ -109,32 +55,26 @@ dg_save(LV2_Handle instance,
const LV2_Feature *const * features)
{
DGLV2 *dglv2 = (DGLV2 *)instance;
- printf("dg_save\n");
+
+ if(!dglv2 || !dglv2->map || !dglv2->map->map) {
+ // Missing urid feature?
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
std::string config = dglv2->dg->configString();
- printf("%s\n", config.c_str());
+
+ // Backwards compatible fix for errornously stored '\0' byte in < v0.9.8.
+ // Remove when we reach v1.0
+ config += "\n";
store(handle,
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_DG "config"),
- config.c_str(),
- config.length() + 1, // Careful! Need space for terminator
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_ATOM "chunk"),
+ dglv2->map->map(dglv2->map->handle, NS_DG "config"),
+ config.data(),
+ config.length(),
+ dglv2->map->map(dglv2->map->handle, LV2_ATOM__Chunk),
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-/*
- MyPlugin* plugin = (MyPlugin*)instance;
- const char* greeting = plugin->state.greeting;
-
- store(handle,
- plugin->uris.my_greeting,
- greeting,
- strlen(greeting) + 1, // Careful! Need space for terminator
- plugin->uris.atom_String,
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-*/
- printf("dg_save\n");
- return LV2_STATE_SUCCESS;
+
+ return LV2_STATE_SUCCESS;
}
LV2_State_Status
@@ -145,43 +85,32 @@ dg_restore(LV2_Handle instance,
const LV2_Feature *const * features)
{
DGLV2 *dglv2 = (DGLV2 *)instance;
- DEBUG(lv2, "dg_restore begin\n");
- size_t size;
- uint32_t type;
- // uint32_t flags;
+ if(!dglv2 || !dglv2->map || !dglv2->map->map) {
+ // Missing urid feature?
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
+
+ size_t size;
+ uint32_t type;
const char* data =
(const char*)retrieve(handle,
- dglv2->urimap->uri_to_id(dglv2->urimap->callback_data,
- NULL, NS_DG "config"),
+ dglv2->map->map(dglv2->map->handle, NS_DG "config"),
&size, &type, &flags);
+
DEBUG(lv2, "Config string size: %d, data*: %p\n", (int)size, data);
if(data && size) {
std::string config;
- config.append(data, size - 1);
+
+ // Fix for errornously stored '\0' byte in < v0.9.8.
+ // Remove when we reach v1.0
+ if(data[size - 1] == '\0') size--;
+
+ config.append(data, size);
dglv2->dg->setConfigString(config);
- //dglv2->in->loadMidiMap(dglv2->dg->midimapfile);
}
-
- /*
- MyPlugin* plugin = (MyPlugin*)instance;
-
- size_t size;
- uint32_t type;
- uint32_t flags;
- const char* greeting = retrieve(
- handle, plugin->uris.my_greeting, &size, &type, &flags);
-
- if (greeting) {
- free(plugin->state->greeting);
- plugin->state->greeting = strdup(greeting);
- } else {
- plugin->state->greeting = strdup(DEFAULT_GREETING);
- }
- */
- DEBUG(lv2, "dg_restore done\n");
return LV2_STATE_SUCCESS;
}
@@ -191,42 +120,6 @@ static LV2_State_Interface dg_persist = {
dg_restore
};
-/** A globally unique, case-sensitive identifier for this plugin type.
- *
- * All plugins with the same URI MUST be compatible in terms of 'port
- * signature', meaning they have the same number of ports, same port
- * shortnames, and roughly the same functionality. URIs should
- * probably contain a version number (or similar) for this reason.
- *
- * Rationale: When serializing session/patch/etc files, hosts MUST
- * refer to a loaded plugin by the plugin URI only. In the future
- * loading a plugin with this URI MUST yield a plugin with the
- * same ports (etc) which is 100% compatible. */
-#define DRUMGIZMO_URI "http://drumgizmo.org/lv2"
-
-/** Function pointer that instantiates a plugin.
- *
- * A handle is returned indicating the new plugin instance. The
- * instantiation function accepts a sample rate as a parameter as well
- * as the plugin descriptor from which this instantiate function was
- * found. This function must return NULL if instantiation fails.
- *
- * bundle_path is a string of the path to the LV2 bundle which contains
- * this plugin binary. It MUST include the trailing directory separator
- * (e.g. '/') so that BundlePath + filename gives the path to a file
- * in the bundle.
- *
- * features is 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
- * SHOULD NOT use this as a discovery mechanism, instead reading the
- * data file before attempting to instantiate the plugin). This array
- * must always exist; if a host has no features, it MUST pass a single
- * element array containing NULL (to simplify plugins).
- *
- * 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. */
LV2_Handle instantiate(const struct _LV2_Descriptor *descriptor,
double sample_rate,
const char *bundle_path,
@@ -234,14 +127,10 @@ LV2_Handle instantiate(const struct _LV2_Descriptor *descriptor,
{
DGLV2 *dglv2 = new DGLV2;
- dglv2->urimap = NULL;
+ dglv2->map = NULL;
for (int i = 0 ; features[i] ; i++) {
- printf("DG: feature: %s\n", features[i]->URI);
- if (!strcmp(features[i]->URI, LV2_URI_MAP_URI)) {
- dglv2->urimap = (LV2_URI_Map_Feature*)features[i]->data;
- }
- if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
- dglv2->makepath = (LV2_State_Make_Path*)features[i]->data;
+ if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
+ dglv2->map = (LV2_URID_Map*)features[i]->data;
}
}
@@ -253,57 +142,12 @@ LV2_Handle instantiate(const struct _LV2_Descriptor *descriptor,
dglv2->buffer = NULL;
dglv2->buffer_size = 0;
- /*
- char* path = dglv2->makepath->path(dglv2->makepath->handle,
- "hello.txt");
- FILE* myfile = fopen(path, "w");
- fprintf(myfile, "world");
- fclose(myfile);
- */
-
dglv2->dg = new DrumGizmo(dglv2->out, dglv2->in);
dglv2->dg->setSamplerate(sample_rate);
- // dglv2->dg->loadkit(getenv("DRUMGIZMO_DRUMKIT"));
- // dglv2->dg->init(true);
return (LV2_Handle)dglv2;
}
-/** Function pointer that connects a port on a plugin instance to a memory
- * location where the block of data for the port will be read/written.
- *
- * The data location is expected to be of the type defined in the
- * plugin's data file (e.g. an array of float for an lv2:AudioPort).
- * Memory issues are managed by the host. The plugin must read/write
- * the data at these locations every time run() is called, data
- * present at the time of this connection call MUST NOT be
- * considered meaningful.
- *
- * The host MUST NOT try to connect a data buffer to a port index
- * that is not defined in the RDF data for the plugin. If it does,
- * the plugin's behaviour is undefined.
- *
- * 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. Note that there may be realtime constraints
- * on connect_port (see lv2:hardRTCapable in lv2.ttl).
- *
- * connect_port() MUST be called at least once for each port before
- * run() is called. The plugin must pay careful attention to the block
- * size passed to the run function as the block allocated may only just
- * be large enough to contain the block of data (typically samples), and
- * is not guaranteed to be constant.
- *
- * 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).
- * However, overlapped buffers or use of a single buffer for both
- * audio and control data may result in unexpected behaviour.
- *
- * 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 lv2.ttl). */
void connect_port(LV2_Handle instance,
uint32_t port,
void *data_location)
@@ -320,99 +164,31 @@ void connect_port(LV2_Handle instance,
}
}
-/** Function pointer that initialises a plugin instance and activates
- * 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 the plugin writer may provide
- * a NULL rather than an empty function.
- *
- * 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(). activate() may not be called again
- * unless deactivate() is called first (after which activate() may be
- * called again, followed by deactivate, etc. etc.). 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 a call to
- * activate(). */
void activate(LV2_Handle instance)
{
+ // We don't really need to do anything here.
DGLV2 *dglv2 = (DGLV2 *)instance;
- //dglv2->dg->run();
(void)dglv2;
}
-/** Function pointer that runs a plugin instance for a block.
- *
- * Two parameters are required: the first is a handle to the particular
- * instance to be run and the second indicates the block size (in
- * samples) for which the plugin instance may run.
- *
- * Note that if an activate() function exists then it must be called
- * before run(). If deactivate() is called for a plugin instance then
- * the plugin instance may not be reused 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 lv2.ttl). */
void run(LV2_Handle instance,
uint32_t sample_count)
{
static size_t pos = 0;
DGLV2 *dglv2 = (DGLV2 *)instance;
- // The buffer is not used anymore - declared NULL in 'instantiate'.
- /*
- if(dglv2->buffer_size != sample_count) {
- if(dglv2->buffer) free(dglv2->buffer);
- dglv2->buffer_size = sample_count;
- dglv2->buffer = (sample_t*)malloc(sizeof(sample_t) * dglv2->buffer_size);
- printf("(Re)allocate buffer: %d samples\n", dglv2->buffer_size);
- }
- */
dglv2->dg->run(pos, dglv2->buffer, sample_count);
pos += sample_count;
}
-/** This is the counterpart to activate() (see above). If there is
- * nothing for deactivate() to do then the plugin writer may provide
- * a NULL rather than an empty function.
- *
- * Hosts must deactivate all activated units 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. Note that connect_port() may be called before or
- * after a call to deactivate().
- *
- * Note that deactivation is not similar to pausing as the plugin
- * instance will be reinitialised when activate() is called to reuse it.
- * Hosts MUST NOT call deactivate() unless activate() was previously
- * called. */
void deactivate(LV2_Handle instance)
{
+ // We don't really need to do anything here.
DGLV2 *dglv2 = (DGLV2 *)instance;
dglv2->dg->stop();
}
-/** This is the counterpart to instantiate() (see above). Once an instance
- * of a plugin has been finished with it can 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)
{
DGLV2 *dglv2 = (DGLV2 *)instance;
@@ -421,34 +197,8 @@ void cleanup(LV2_Handle instance)
delete dglv2->out;
}
-/** Function pointer that can be used to return additional instance data for
- * a plugin defined by some extenion (e.g. a struct containing additional
- * function pointers).
- *
- * The actual type and meaning of the returned object MUST be specified
- * precisely by the extension if it defines any extra data. If a particular
- * extension does not define extra instance data, this function MUST return
- * NULL for that extension's URI. If a plugin does not support any
- * extensions that define extra instance data, this function pointer may be
- * set to NULL rather than providing an empty function.
- *
- * The only parameter is the URI of the extension. The plugin MUST return
- * NULL if it does not support the extension, but hosts SHOULD NOT use this
- * as a discovery method (e.g. hosts should only call this function for
- * extensions known to be supported by the plugin from the data file).
- *
- * The host is never responsible for freeing the returned value.
- *
- * NOTE: This function should return a struct (likely containing function
- * pointers) and NOT a direct function pointer. Standard C and C++ do not
- * allow type casts from void* to a function pointer type. To provide
- * additional functions a struct should be returned containing the extra
- * function pointers (which is valid standard code, and a much better idea
- * for extensibility anyway). */
const void* extension_data(const char *uri)
{
- printf("extension_data(%s)\n", uri);
-
if(!strcmp(uri, PLUGIN_INSTANCE_URI)) return &dg_descriptor;
if(!strcmp(uri, LV2_STATE__interface)) return &dg_persist;
return NULL;
diff --git a/lv2/lv2_instance.h b/lv2/lv2_instance.h
index b4772f6..e050e22 100644
--- a/lv2/lv2_instance.h
+++ b/lv2/lv2_instance.h
@@ -29,7 +29,7 @@
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
#include <lv2/lv2plug.in/ns/ext/state/state.h>
-#include <lv2/lv2plug.in/ns/ext/uri-map/uri-map.h>
+#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
#include "input_lv2.h"
#include "output_lv2.h"
@@ -42,8 +42,7 @@ typedef struct {
DrumGizmo *dg;
sample_t *buffer;
size_t buffer_size;
- LV2_URI_Map_Feature *urimap;
- LV2_State_Make_Path *makepath;
+ LV2_URID_Map* map;
} DGLV2;
#endif/*__DRUMGIZMO_LV2_INSTANCE_H__*/
diff --git a/lv2/output_lv2.cc b/lv2/output_lv2.cc
index ef2500b..09999cb 100644
--- a/lv2/output_lv2.cc
+++ b/lv2/output_lv2.cc
@@ -62,11 +62,9 @@ void OutputLV2::pre(size_t nsamples)
{
}
-#include <stdio.h>
void OutputLV2::run(int ch, sample_t *samples, size_t nsamples)
{
if(ch < NUM_OUTPUTS) {
- // if(outputPorts[ch].size != nsamples) printf("port.%d nsamples.%d\n", outputPorts[ch].size, nsamples);
if(outputPorts[ch].samples) {
memcpy(outputPorts[ch].samples, samples, nsamples * sizeof(sample_t));
}
diff --git a/lv2/output_lv2.h b/lv2/output_lv2.h
index 1b4e8c9..a3a2555 100644
--- a/lv2/output_lv2.h
+++ b/lv2/output_lv2.h
@@ -55,7 +55,6 @@ public:
sample_t *getBuffer(int c);
- // sample_t *outputPort[NUM_OUTPUTS];
OutputPort outputPorts[NUM_OUTPUTS];
};
diff --git a/src/configuration.cc b/src/configuration.cc
index 965dcf9..5c733ee 100644
--- a/src/configuration.cc
+++ b/src/configuration.cc
@@ -35,19 +35,4 @@ float Conf::velocity_randomiser_weight = 0.1;
int Conf::samplerate = 44100;
-#ifdef TEST_CONFIGURATION
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_CONFIGURATION*/
+bool Conf::enable_resampling = true;
diff --git a/src/configuration.h b/src/configuration.h
index c49f997..b8be49f 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -36,6 +36,8 @@ namespace Conf {
extern float velocity_randomiser_weight;
extern int samplerate;
+
+ extern bool enable_resampling;
};
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index ddb6358..6fd454e 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -282,24 +282,26 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
//
// Write audio
//
-#ifndef WITH_RESAMPLER
- // No resampling needed
- for(size_t c = 0; c < kit.channels.size(); c++) {
- sample_t *buf = samples;
- bool internal = false;
- if(oe->getBuffer(c)) {
- buf = oe->getBuffer(c);
- internal = true;
- }
- if(buf) {
- memset(buf, 0, nsamples * sizeof(sample_t));
-
- getSamples(c, pos, buf, nsamples);
+#ifdef WITH_RESAMPLER
+ if(Conf::enable_resampling == false) { // No resampling needed
+#endif
+ for(size_t c = 0; c < kit.channels.size(); c++) {
+ sample_t *buf = samples;
+ bool internal = false;
+ if(oe->getBuffer(c)) {
+ buf = oe->getBuffer(c);
+ internal = true;
+ }
+ if(buf) {
+ memset(buf, 0, nsamples * sizeof(sample_t));
+
+ getSamples(c, pos, buf, nsamples);
- if(!internal) oe->run(c, samples, nsamples);
+ if(!internal) oe->run(c, samples, nsamples);
+ }
}
- }
-#else/*WITH_RESAMPLER*/
+#ifdef WITH_RESAMPLER
+ } else {
// Resampling needed
//
@@ -337,6 +339,8 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
for(size_t c = 0; c < kit.channels.size(); c++) {
oe->run(c, resampler_output_buffer[c], nsamples);
}
+
+ }
#endif/*WITH_RESAMPLER*/
ie->post();
@@ -546,6 +550,11 @@ bool DrumGizmo::setConfigString(std::string cfg)
str2float(p.value("velocity_randomiser_weight"));
}
+ if(p.value("enable_resampling") != "") {
+ Conf::enable_resampling =
+ p.value("enable_resampling") == "true";
+ }
+
std::string newkit = p.value("drumkitfile");
if(newkit != "" && kit.file() != newkit) {
/*
diff --git a/test/Makefile.am b/test/Makefile.am
index e43a6ba..5aaf33f 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,7 +1,7 @@
# Rules for the test code (use `make check` to execute)
include $(top_srcdir)/src/Makefile.am.drumgizmo
-TESTS = engine gui resampler
+TESTS = engine gui resampler lv2
check_PROGRAMS = $(TESTS)
@@ -29,4 +29,14 @@ resampler_LDFLAGS = $(ZITA_LIBS) $(SAMPLERATE_LIBS) $(CPPUNIT_LIBS)
resampler_SOURCES = \
$(top_srcdir)/src/chresampler.cc \
test.cc \
- resampler.cc \ No newline at end of file
+ resampler.cc
+
+lv2_CXXFLAGS = -DOUTPUT=\"lv2\" $(CPPUNIT_CFLAGS) \
+ `pkg-config --cflags serd-0` `pkg-config --cflags lilv-0` \
+ -DLV2_PATH=\"$(libdir)/lv2\"
+lv2_LDFLAGS = $(CPPUNIT_LIBS) `pkg-config --libs serd-0` \
+ `pkg-config --libs lilv-0` -lcrypto
+lv2_SOURCES = \
+ test.cc \
+ lv2_test_host.cc \
+ lv2.cc
diff --git a/test/kit/instr1.xml b/test/kit/instr1.xml
index 3257c95..6b600d5 100644
--- a/test/kit/instr1.xml
+++ b/test/kit/instr1.xml
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<instrument name="snare">
+<instrument name="instr1">
<samples>
<sample name="stroke1">
<audiofile channel="ch1" file="1111.wav"/>
diff --git a/test/kit/instr2.xml b/test/kit/instr2.xml
index 30a988a..76cbc80 100644
--- a/test/kit/instr2.xml
+++ b/test/kit/instr2.xml
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<instrument name="snare">
+<instrument name="instr2">
<samples>
<sample name="stroke1">
<audiofile channel="ch1" file="2222.wav"/>
diff --git a/test/kit/kit1.xml b/test/kit/kit1.xml
index 41cede4..dd4c93e 100644
--- a/test/kit/kit1.xml
+++ b/test/kit/kit1.xml
@@ -13,7 +13,7 @@
<channelmap in="ch3" out="ch3"/>
<channelmap in="ch4" out="ch4"/>
</instrument>
- <instrument name="instr1" file="instr2.xml">
+ <instrument name="instr2" file="instr2.xml">
<channelmap in="ch1" out="ch1"/>
<channelmap in="ch2" out="ch2"/>
<channelmap in="ch3" out="ch3"/>
diff --git a/test/kit/kit2.xml b/test/kit/kit2.xml
index 41cede4..dd4c93e 100644
--- a/test/kit/kit2.xml
+++ b/test/kit/kit2.xml
@@ -13,7 +13,7 @@
<channelmap in="ch3" out="ch3"/>
<channelmap in="ch4" out="ch4"/>
</instrument>
- <instrument name="instr1" file="instr2.xml">
+ <instrument name="instr2" file="instr2.xml">
<channelmap in="ch1" out="ch1"/>
<channelmap in="ch2" out="ch2"/>
<channelmap in="ch3" out="ch3"/>
diff --git a/test/lv2.cc b/test/lv2.cc
new file mode 100644
index 0000000..bfd2ce5
--- /dev/null
+++ b/test/lv2.cc
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * lv2.cc
+ *
+ * Thu Feb 12 14:55:41 CET 2015
+ * Copyright 2015 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <unistd.h>
+#include <memory.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+
+#include "lv2_test_host.h"
+
+#define DG_URI "http://drumgizmo.org/lv2"
+
+/**
+ * Tests that should be performed:
+ * -------------------------------
+ * - Run without port connects (shouldn't crash)
+ * - Run without output ports connects (shouldn't crash)
+ * - Run with buffer size 0
+ * - Run with VERY LARGE buffer size (>1MB?)
+ * - Run with buffer size a prime number (and thereby not power of 2)
+ * - Run with HUGE number of midi events in one buffer (10000)
+ */
+class test_lv2 : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(test_lv2);
+ CPPUNIT_TEST(open_and_verify);
+ CPPUNIT_TEST(run_no_ports_connected);
+ CPPUNIT_TEST(run_no_output_ports_connected);
+ CPPUNIT_TEST(test1);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() {}
+ void tearDown() {}
+
+ void open_and_verify()
+ {
+ int res;
+
+ LV2TestHost h(LV2_PATH);
+
+ res = h.open(DG_URI);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.verify();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.close();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ }
+
+ void run_no_ports_connected()
+ {
+ int res;
+
+ LV2TestHost h(LV2_PATH);
+
+ res = h.open(DG_URI);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.verify();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.createInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ const char config_fmt[] =
+ "<config>\n"
+ " <value name=\"drumkitfile\">%s</value>\n"
+ " <value name=\"midimapfile\">%s</value>\n"
+ " <value name=\"enable_velocity_modifier\">%s</value>\n"
+ " <value name=\"velocity_modifier_falloff\">%f</value>\n"
+ " <value name=\"velocity_modifier_weight\">%f</value>\n"
+ " <value name=\"enable_velocity_randomiser\">%s</value>\n"
+ " <value name=\"velocity_randomiser_weight\">%f</value>\n"
+ " <value name=\"enable_resampling\">%s</value>\n"
+ "</config>";
+
+ const char drumkitfile[] = "kit/kit1.xml";
+ const char midimapfile[] = "kit/midimap.xml";
+ bool enable_velocity_modifier = true;
+ float velocity_modifier_falloff = 0.5;
+ float velocity_modifier_weight = 0.25;
+ bool enable_velocity_randomiser = false;
+ float velocity_randomiser_weight = 0.1;
+ bool enable_resampling = false;
+
+ char config[sizeof(config_fmt) * 2];
+ sprintf(config, config_fmt,
+ drumkitfile,
+ midimapfile,
+ enable_velocity_modifier?"true":"false",
+ velocity_modifier_falloff,
+ velocity_modifier_weight,
+ enable_velocity_randomiser?"true":"false",
+ velocity_randomiser_weight,
+ enable_resampling?"true":"false"
+ );
+
+ res = h.loadConfig(config, strlen(config));
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ // run for 1 samples to trigger kit loading
+ res = h.run(1);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ sleep(1); // wait for kit to get loaded (async),
+
+ res = h.run(100);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.destroyInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.close();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ }
+
+ void run_no_output_ports_connected()
+ {
+ int res;
+
+ LV2TestHost h(LV2_PATH);
+
+ res = h.open(DG_URI);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.verify();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.createInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ const char config_fmt[] =
+ "<config>\n"
+ " <value name=\"drumkitfile\">%s</value>\n"
+ " <value name=\"midimapfile\">%s</value>\n"
+ " <value name=\"enable_velocity_modifier\">%s</value>\n"
+ " <value name=\"velocity_modifier_falloff\">%f</value>\n"
+ " <value name=\"velocity_modifier_weight\">%f</value>\n"
+ " <value name=\"enable_velocity_randomiser\">%s</value>\n"
+ " <value name=\"velocity_randomiser_weight\">%f</value>\n"
+ " <value name=\"enable_resampling\">%s</value>\n"
+ "</config>";
+
+ const char drumkitfile[] = "kit/kit1.xml";
+ const char midimapfile[] = "kit/midimap.xml";
+ bool enable_velocity_modifier = true;
+ float velocity_modifier_falloff = 0.5;
+ float velocity_modifier_weight = 0.25;
+ bool enable_velocity_randomiser = false;
+ float velocity_randomiser_weight = 0.1;
+ bool enable_resampling = false;
+
+ char config[sizeof(config_fmt) * 2];
+ sprintf(config, config_fmt,
+ drumkitfile,
+ midimapfile,
+ enable_velocity_modifier?"true":"false",
+ velocity_modifier_falloff,
+ velocity_modifier_weight,
+ enable_velocity_randomiser?"true":"false",
+ velocity_randomiser_weight,
+ enable_resampling?"true":"false"
+ );
+
+ res = h.loadConfig(config, strlen(config));
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ // Port buffers:
+ char sequence_buffer[4096];
+
+ LV2TestHost::Sequence seq(sequence_buffer, sizeof(sequence_buffer));
+ res = h.connectPort(0, seq.data());
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ // run for 1 samples to trigger kit loading
+ res = h.run(1);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ sleep(1); // wait for kit to get loaded (async),
+
+ seq.addMidiNote(5, 1, 127);
+ res = h.run(100);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.destroyInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.close();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ }
+
+ void test1()
+ {
+ int res;
+
+ LV2TestHost h(LV2_PATH);
+
+ res = h.open(DG_URI);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.verify();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.createInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ const char config_fmt[] =
+ "<config>\n"
+ " <value name=\"drumkitfile\">%s</value>\n"
+ " <value name=\"midimapfile\">%s</value>\n"
+ " <value name=\"enable_velocity_modifier\">%s</value>\n"
+ " <value name=\"velocity_modifier_falloff\">%f</value>\n"
+ " <value name=\"velocity_modifier_weight\">%f</value>\n"
+ " <value name=\"enable_velocity_randomiser\">%s</value>\n"
+ " <value name=\"velocity_randomiser_weight\">%f</value>\n"
+ " <value name=\"enable_resampling\">%s</value>\n"
+ "</config>";
+
+ const char drumkitfile[] = "kit/kit1.xml";
+ const char midimapfile[] = "kit/midimap.xml";
+ bool enable_velocity_modifier = true;
+ float velocity_modifier_falloff = 0.5;
+ float velocity_modifier_weight = 0.25;
+ bool enable_velocity_randomiser = false;
+ float velocity_randomiser_weight = 0.1;
+ bool enable_resampling = false;
+
+ char config[sizeof(config_fmt) * 2];
+ sprintf(config, config_fmt,
+ drumkitfile,
+ midimapfile,
+ enable_velocity_modifier?"true":"false",
+ velocity_modifier_falloff,
+ velocity_modifier_weight,
+ enable_velocity_randomiser?"true":"false",
+ velocity_randomiser_weight,
+ enable_resampling?"true":"false"
+ );
+
+ res = h.loadConfig(config, strlen(config));
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ // Port buffers:
+ char sequence_buffer[4096];
+ float pcm_buffer[16][10];
+
+ LV2TestHost::Sequence seq(sequence_buffer, sizeof(sequence_buffer));
+ res = h.connectPort(0, seq.data());
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ for(int i = 1; i <= 16; i++) {
+ memset(pcm_buffer, 1, sizeof(pcm_buffer));
+ res += h.connectPort(i, pcm_buffer[i-1]);
+ }
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ // run for 1 samples to trigger kit loading
+ res = h.run(1);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ sleep(1); // wait for kit to get loaded (async),
+
+ /*
+ seq.addMidiNote(5, 1, 127);
+ for(int i = 0; i < 10; i++) {
+ res = h.run(10);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ printf("Iteration:\n");
+ for(int k = 0; k < 4; k++) {
+ printf("#%d ", k);
+ for(int j = 0; j < 10; j++) printf("[%f]", pcm_buffer[k][j]);
+ printf("\n");
+ }
+ printf("\n");
+
+ seq.clear();
+ }
+ */
+
+ seq.addMidiNote(5, 1, 127);
+ res = h.run(10);
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ union {
+ float f;
+ unsigned int u;
+ } comp_val;
+
+ comp_val.u = 1040744448;
+
+ for(int k = 0; k < 4; k++) {
+ for(int j = 0; j < 10; j++) {
+ CPPUNIT_ASSERT(pcm_buffer[k][j] == ((j==4)?comp_val.f:0));
+ }
+ }
+ seq.clear();
+
+ res = h.destroyInstance();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+
+ res = h.close();
+ CPPUNIT_ASSERT_EQUAL(0, res);
+ }
+};
+
+// Registers the fixture into the 'registry'
+CPPUNIT_TEST_SUITE_REGISTRATION(test_lv2);
diff --git a/test/lv2_test_host.cc b/test/lv2_test_host.cc
new file mode 100644
index 0000000..07685d0
--- /dev/null
+++ b/test/lv2_test_host.cc
@@ -0,0 +1,403 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * lv2_test_host.cc
+ *
+ * Wed Feb 11 23:11:21 CET 2015
+ * Copyright 2015 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "lv2_test_host.h"
+
+#include <serd/serd.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <lv2/lv2plug.in/ns/ext/atom/forge.h>
+#include <lv2/lv2plug.in/ns/ext/state/state.h>
+#include <lv2/lv2plug.in/ns/ext/midi/midi.h>
+
+///////////////////////////////
+// Base64 encoder:
+//
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <string>
+class Base64 {
+public:
+ Base64()
+ {
+ mbio = (void*)BIO_new(BIO_s_mem());
+ BIO *b64bio = BIO_new(BIO_f_base64());
+ bio = (void*)BIO_push(b64bio, (BIO*)mbio);
+ }
+
+ ~Base64()
+ {
+ BIO_free_all((BIO*)bio);
+ }
+
+ std::string write(std::string in)
+ {
+ return this->write(in.data(), in.length());
+ }
+
+ std::string write(const char *in, size_t size)
+ {
+ std::string out;
+
+ BIO_write((BIO*)bio, in, size);
+
+ size_t osize = BIO_ctrl_pending((BIO*)mbio);
+ char *outbuf = (char*)malloc(osize);
+
+ int len = BIO_read((BIO*)mbio, outbuf, osize);
+ if(len < 1) return "";
+ out.append(outbuf, len);
+
+ free(outbuf);
+
+ return out;
+ }
+
+ std::string flush()
+ {
+ std::string out;
+
+ (void)BIO_flush((BIO*)bio);
+
+ size_t size = BIO_ctrl_pending((BIO*)mbio);
+ char *outbuf = (char*)malloc(size);
+
+ int len = BIO_read((BIO*)mbio, outbuf, size);
+ if(len < 1) return "";
+ out.append(outbuf, len);
+
+ free(outbuf);
+
+ return out;
+ }
+
+private:
+ void *bio;
+ void *mbio;
+};
+//
+// Base64 encoder
+///////////////////////////////
+
+
+// TODO: Use map<int, std::string> instead
+static char** uris = NULL;
+static size_t n_uris = 0;
+
+static LV2_URID map_uri(LV2_URID_Map_Handle handle, const char* uri)
+{
+ for(size_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] = strdup(uri);
+
+ return n_uris;
+}
+
+static const char* unmap_uri(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+ if(urid > 0 && urid <= n_uris) {
+ return uris[urid - 1];
+ }
+ return NULL;
+}
+
+LV2_URID_Map map = { NULL, map_uri };
+LV2_Feature map_feature = { LV2_URID_MAP_URI, &map };
+LV2_URID_Unmap unmap = { NULL, unmap_uri };
+LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap };
+const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL };
+
+LV2TestHost::Sequence::Sequence(void *buffer, size_t buffer_size)
+{
+ this->buffer = buffer;
+ this->buffer_size = buffer_size;
+
+ seq = (LV2_Atom_Sequence *)buffer;
+
+ seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
+ seq->atom.type = map.map(map.handle, LV2_ATOM__Sequence);
+ seq->body.unit = 0;
+ seq->body.pad = 0;
+}
+
+// Keep this to support atom extension from lv2 < 1.10
+static inline void
+_lv2_atom_sequence_clear(LV2_Atom_Sequence* seq)
+{
+ seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
+}
+
+void LV2TestHost::Sequence::clear()
+{
+ _lv2_atom_sequence_clear(seq);
+}
+
+// Keep this to support atom extension from lv2 < 1.10
+static inline LV2_Atom_Event*
+_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;
+ }
+
+ 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);
+
+ return e;
+}
+
+void LV2TestHost::Sequence::addMidiNote(uint64_t pos,
+ uint8_t key, int8_t velocity)
+{
+ typedef struct {
+ LV2_Atom_Event event;
+ uint8_t msg[3];
+ } MIDINoteEvent;
+
+ uint8_t note_on = 0x90;
+
+ MIDINoteEvent ev;
+ ev.event.time.frames = pos;// sample position
+ ev.event.body.type = map.map(map.handle, LV2_MIDI__MidiEvent);
+ ev.event.body.size = sizeof(MIDINoteEvent);
+
+ ev.msg[0] = note_on;
+ ev.msg[1] = key;
+ ev.msg[2] = velocity;
+
+ LV2_Atom_Event *e =
+ _lv2_atom_sequence_append_event(seq, this->buffer_size, &ev.event);
+ (void)e;
+}
+
+void *LV2TestHost::Sequence::data()
+{
+ return buffer;
+}
+
+LV2TestHost::LV2TestHost(const char *lv2_path)
+{
+ if(lv2_path) {
+ setenv("LV2_PATH", lv2_path, 1);
+ }
+
+ world = lilv_world_new();
+ if(world == NULL) return;
+
+ lilv_world_load_all(world);
+}
+
+LV2TestHost::~LV2TestHost()
+{
+ if(world) lilv_world_free(world);
+}
+
+int LV2TestHost::open(const char *plugin_uri)
+{
+ if(world == NULL) return 1;
+
+ plugins = lilv_world_get_all_plugins(world);
+ if(plugins == NULL) return 2;
+
+ uri = lilv_new_uri(world, plugin_uri);
+ if(uri == NULL) return 3;
+
+ plugin = lilv_plugins_get_by_uri(plugins, uri);
+ if(plugin == NULL) return 4;
+
+
+ return 0;
+}
+
+int LV2TestHost::verify()
+{
+ bool verify = lilv_plugin_verify(plugin);
+ if(!verify) return 1;
+ return 0;
+}
+
+int LV2TestHost::close()
+{
+ // plugin is a const pointer; nothing to close here.
+ return 0;
+}
+
+/* // Get metadata
+
+static void dumpNodes(LilvNodes *nodes)
+{
+ LilvIter* iter = lilv_nodes_begin(nodes);
+ while(iter) {
+ const LilvNode* node = lilv_nodes_get(nodes, iter);
+ printf(" - '%s'\n", lilv_node_as_uri(node));
+ iter = lilv_nodes_next(nodes, iter);
+ }
+}
+
+void getMetadata()
+{
+ LilvNode* name = lilv_plugin_get_name(plugin);
+ if(name) printf("Name: %s\n", lilv_node_as_uri(name));
+
+ // ---> line 731 in lilv.h
+ bool has_latency = lilv_plugin_has_latency(plugin);
+ printf("Has latency: %d\n", has_latency);
+
+ if(has_latency) {
+ uint32_t latency_port_index = lilv_plugin_get_latency_port_index(plugin);
+ const LilvPort* port =
+ lilv_plugin_get_port_by_index(plugin, latency_port_index);
+ // Do something to actually get latency from port....
+ }
+
+ LilvNode* author = lilv_plugin_get_author_name(plugin);
+ if(author) printf("Author: %s\n", lilv_node_as_uri(author));
+
+ LilvNode* email = lilv_plugin_get_author_email(plugin);
+ if(email) printf("Email: %s\n", lilv_node_as_uri(email));
+
+ LilvNode* homepage = lilv_plugin_get_author_homepage(plugin);
+ if(homepage) printf("Homepage: %s\n", lilv_node_as_uri(homepage));
+
+ LilvNodes* supported = lilv_plugin_get_supported_features(plugin);
+ LilvNodes* required = lilv_plugin_get_required_features(plugin);
+ LilvNodes* optional = lilv_plugin_get_optional_features(plugin);
+
+ printf("Supported:\n");
+ dumpNodes(supported);
+
+ printf("Required:\n");
+ dumpNodes(required);
+
+ printf("Optional:\n");
+ dumpNodes(optional);
+
+ lilv_nodes_free(supported);
+ lilv_nodes_free(required);
+ lilv_nodes_free(optional);
+}
+*/
+/*
+int LV2TestHost::getPorts()
+{
+ // Iterate ports:
+ const LilvPort* port;
+ uint32_t portidx = 0;
+ while( (port = lilv_plugin_get_port_by_index(plugin, portidx)) != 0) {
+ printf("Port: %d\n", portidx);
+
+ LilvNode* port_name = lilv_port_get_name(plugin, port);
+ if(port_name) printf(" Name: %s\n", lilv_node_as_uri(port_name));
+
+ portidx++;
+ }
+}
+*/
+int LV2TestHost::createInstance()
+{
+ instance = lilv_plugin_instantiate(plugin, 48000, features);
+ if(instance == NULL) return 1;
+ return 0;
+}
+
+int LV2TestHost::destroyInstance()
+{
+ if(instance) lilv_instance_free(instance);
+ return 0;
+}
+
+int LV2TestHost::activate()
+{
+ lilv_instance_activate(instance);
+ return 0;
+}
+
+int LV2TestHost::deactivate()
+{
+ lilv_instance_deactivate(instance);
+ return 0;
+}
+
+int LV2TestHost::loadConfig(const char *config, size_t size)
+{
+ Base64 b64;
+ std::string b64_config = b64.write(config, size);
+ b64_config += b64.flush();
+
+ //printf("Base 64 config: [%s]\n", b64_config.c_str());
+
+ const char ttl_config_fmt[] =
+ "<http://drumgizmo.org/lv2/atom#config>\n"
+ " a pset:Preset ;\n"
+ " lv2:appliesTo <http://drumgizmo.org/lv2> ;\n"
+ " state:state [\n"
+ " <http://drumgizmo.org/lv2/atom#config> \"\"\"%s\"\"\"^^xsd:base64Binary\n"
+ " ] .\n";
+
+ char ttl_config[sizeof(ttl_config_fmt) * 2 + b64_config.size()];
+ sprintf(ttl_config, ttl_config_fmt, b64_config.c_str());
+
+ //printf("ttl config: [%s]\n", ttl_config);
+
+ {
+ LilvState* restore_state =
+ lilv_state_new_from_string(world, &map, ttl_config);
+
+ lilv_state_restore(restore_state, instance, NULL, NULL,
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE,
+ features);
+ }
+
+ return 0;
+}
+
+int LV2TestHost::connectPort(int port, void *portdata)
+{
+ // if(lilv_port_is_a(p, port, lv2_ControlPort)) ...
+
+ lilv_instance_connect_port(instance, port, portdata);
+
+ return 0;
+}
+
+int LV2TestHost::run(int num_samples)
+{
+ lilv_instance_run(instance, num_samples);
+ return 0;
+}
diff --git a/test/lv2_test_host.h b/test/lv2_test_host.h
new file mode 100644
index 0000000..04f48c6
--- /dev/null
+++ b/test/lv2_test_host.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * lv2_test_host.h
+ *
+ * Wed Feb 11 23:11:20 CET 2015
+ * Copyright 2015 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __DRUMGIZMO_LV2_TEST_HOST_H__
+#define __DRUMGIZMO_LV2_TEST_HOST_H__
+
+#include <lilv/lilv.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
+
+class LV2TestHost {
+public:
+ class Sequence {
+ public:
+ Sequence(void *buffer, size_t buffer_size);
+ void clear();
+ void addMidiNote(uint64_t pos, uint8_t key, int8_t velocity);
+ void *data();
+
+ private:
+ void *buffer;
+ size_t buffer_size;
+ LV2_Atom_Sequence *seq;
+ };
+
+ LV2TestHost(const char *lv2_path);
+ ~LV2TestHost();
+
+ int open(const char *plugin_uri);
+ int close();
+
+ int verify();
+
+ //void getMetadata();
+ //int getPorts();
+
+ int createInstance();
+ int destroyInstance();
+
+ int connectPort(int port, void *portdata);
+
+ int activate();
+ int deactivate();
+
+ int loadConfig(const char *config, size_t size);
+ int run(int num_samples);
+
+
+
+private:
+ LilvWorld* world;
+ const LilvPlugins* plugins;
+ LilvNode* uri;
+ const LilvPlugin* plugin;
+
+ LilvInstance* instance;
+
+ size_t buffer_size;
+};
+
+#endif/*__DRUMGIZMO_LV2_TEST_HOST_H__*/