diff options
-rw-r--r-- | lv2/input_lv2.cc | 27 | ||||
-rw-r--r-- | lv2/lv2.cc | 328 | ||||
-rw-r--r-- | lv2/lv2_instance.h | 5 | ||||
-rw-r--r-- | lv2/output_lv2.cc | 2 | ||||
-rw-r--r-- | lv2/output_lv2.h | 1 | ||||
-rw-r--r-- | src/configuration.cc | 17 | ||||
-rw-r--r-- | src/configuration.h | 2 | ||||
-rw-r--r-- | src/drumgizmo.cc | 41 | ||||
-rw-r--r-- | test/Makefile.am | 14 | ||||
-rw-r--r-- | test/kit/instr1.xml | 2 | ||||
-rw-r--r-- | test/kit/instr2.xml | 2 | ||||
-rw-r--r-- | test/kit/kit1.xml | 2 | ||||
-rw-r--r-- | test/kit/kit2.xml | 2 | ||||
-rw-r--r-- | test/lv2.cc | 332 | ||||
-rw-r--r-- | test/lv2_test_host.cc | 403 | ||||
-rw-r--r-- | test/lv2_test_host.h | 83 |
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*/ @@ -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__*/ |