summaryrefslogtreecommitdiffstats
path: root/src/engine/ingen_lv2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/ingen_lv2.cpp')
-rw-r--r--src/engine/ingen_lv2.cpp369
1 files changed, 292 insertions, 77 deletions
diff --git a/src/engine/ingen_lv2.cpp b/src/engine/ingen_lv2.cpp
index 424df46c..8d14cba7 100644
--- a/src/engine/ingen_lv2.cpp
+++ b/src/engine/ingen_lv2.cpp
@@ -16,55 +16,177 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef PLUGIN_URI
-#error "This file requires PLUGIN_URI to be defined"
-#endif
-
#include <stdlib.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/convert.h>
+#include <glib.h>
#include "lv2.h"
+#include "ingen-config.h"
+#include "raul/log.hpp"
+#include "raul/Thread.hpp"
+#include "raul/SharedPtr.hpp"
+#include "engine/AudioBuffer.hpp"
#include "engine/Engine.hpp"
+#include "engine/ThreadManager.hpp"
#include "engine/Driver.hpp"
#include "engine/ProcessContext.hpp"
#include "engine/PatchImpl.hpp"
+#include "engine/QueuedEngineInterface.hpp"
#include "module/World.hpp"
-
-extern "C" {
+#include "module/ingen_module.hpp"
+#include "shared/runtime_paths.hpp"
+#include "shared/Configuration.hpp"
+#include "serialisation/Parser.hpp"
+#include "interface/EngineInterface.hpp"
using namespace Ingen;
-/* Plugin */
+namespace Ingen {
+namespace LV2 {
+
+/** Record of a patch found in this LV2 bundle */
+struct LV2Patch {
+ LV2Patch(const std::string& u, const std::string& f);
+
+ const std::string uri;
+ const std::string filename;
+ LV2_Descriptor descriptor;
+};
+
+
+/* Static library data */
+typedef std::vector< SharedPtr<const LV2Patch> > LV2Patches;
+static bool initialised = false;
+static LV2Patches patches;
+static Configuration conf;
+static int argc = 0;
+static char** argv = NULL;
+static Shared::World* world = NULL;
+
+
+struct LV2Driver;
+
+class LV2Port : public DriverPort
+{
+public:
+ LV2Port(LV2Driver* driver, DuplexPort* patch_port)
+ : DriverPort(patch_port)
+ , _driver(driver)
+ , _buffer(NULL)
+ {}
+
+ // TODO: LV2 dynamic ports
+ void create() {}
+ void destroy() {}
+ void move(const Raul::Path& path) {}
+
+ void pre_process(ProcessContext& context) {
+ if (!is_input() || !_buffer)
+ return;
+
+ if (_patch_port->buffer_type() == PortType::AUDIO) {
+ AudioBuffer* patch_buf = (AudioBuffer*)_patch_port->buffer(0).get();
+ patch_buf->copy((Sample*)_buffer, 0, context.nframes() - 1);
+ } else if (_patch_port->buffer_type() == PortType::EVENTS) {
+ //Raul::warn << "TODO: LV2 event I/O" << std::endl;
+ }
+ }
+
+ void post_process(ProcessContext& context) {
+ if (is_input() || !_buffer)
+ return;
-struct IngenLV2Driver : public Ingen::Driver {
- IngenLV2Driver(Engine& engine, SampleCount buffer_size, SampleCount sample_rate)
+ if (_patch_port->buffer_type() == PortType::AUDIO) {
+ AudioBuffer* patch_buf = (AudioBuffer*)_patch_port->buffer(0).get();
+ memcpy((Sample*)_buffer, patch_buf->data(), context.nframes() * sizeof(Sample));
+ } else if (_patch_port->buffer_type() == PortType::EVENTS) {
+ //Raul::warn << "TODO: LV2 event I/O" << std::endl;
+ }
+ }
+
+ void* buffer() const { return _buffer; }
+ void set_buffer(void* buf) { _buffer = buf; }
+
+private:
+ LV2Driver* _driver;
+ void* _buffer;
+};
+
+
+struct LV2Driver : public Driver {
+private:
+ typedef std::vector<LV2Port*> Ports;
+
+public:
+ LV2Driver(Engine& engine, SampleCount buffer_size, SampleCount sample_rate)
: _context(engine)
+ , _root_patch(NULL)
, _buffer_size(buffer_size)
, _sample_rate(sample_rate)
, _frame_time(0)
- , _root_patch(NULL)
{}
- void activate() {}
- void deactivate() {}
- bool is_activated() const { return true; }
-
void run(uint32_t nframes) {
_context.locate(_frame_time, nframes, 0);
+
+ for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i)
+ (*i)->pre_process(_context);
+
if (_root_patch)
_root_patch->process(_context);
+
+ for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i)
+ (*i)->post_process(_context);
+
_frame_time += nframes;
}
- virtual void set_root_patch(PatchImpl* patch) {}
- virtual PatchImpl* root_patch() { return NULL; }
+ virtual void set_root_patch(PatchImpl* patch) { _root_patch = patch; }
+ virtual PatchImpl* root_patch() { return _root_patch; }
+
+ virtual void add_port(DriverPort* port) {
+ // Note this doesn't have to be realtime safe since there's no dynamic LV2 ports
+ ThreadManager::assert_thread(THREAD_PROCESS);
+ assert(dynamic_cast<LV2Port*>(port));
+ assert(port->patch_port()->index() == _ports.size());
+ _ports.push_back((LV2Port*)port);
+ }
+
+ virtual Raul::Deletable* remove_port(const Raul::Path& path, Ingen::DriverPort** port=NULL) {
+ // Note this doesn't have to be realtime safe since there's no dynamic LV2 ports
+ ThreadManager::assert_thread(THREAD_PROCESS);
+
+ for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+ if ((*i)->patch_port()->path() == path) {
+ _ports.erase(i);
+ return NULL;
+ }
+ }
+
+ Raul::warn << "Unable to find port " << path << std::endl;
+ return NULL;
+ }
+
+
+ virtual bool supports(Shared::PortType port_type, Shared::EventType event_type) {
+ return true;
+ }
+
+ virtual DriverPort* create_port(DuplexPort* patch_port) {
+ return new LV2Port(this, patch_port);
+ }
- virtual void add_port(DriverPort* port) {}
- virtual DriverPort* remove_port(const Raul::Path& path) { return NULL; }
+ virtual DriverPort* driver_port(const Raul::Path& path) {
+ ThreadManager::assert_thread(THREAD_PROCESS);
- virtual DriverPort* create_port(DuplexPort* patch_port) { return NULL; }
+ for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i)
+ if ((*i)->patch_port()->path() == path)
+ return (*i);
- virtual DriverPort* driver_port(const Raul::Path& path) { return NULL; }
+ return NULL;
+ }
- virtual SampleCount buffer_size() const { return _buffer_size; }
+ virtual SampleCount block_length() const { return _buffer_size; }
virtual SampleCount sample_rate() const { return _sample_rate; }
virtual SampleCount frame_time() const { return _frame_time;}
@@ -77,30 +199,84 @@ private:
SampleCount _buffer_size;
SampleCount _sample_rate;
SampleCount _frame_time;
+ Ports _ports;
};
+} // namespace LV2
+} // namespace Ingen
+
+
+/* LV2 Plugin Interface */
+
+extern "C" {
+
struct IngenPlugin {
- Ingen::Shared::World* world;
- SharedPtr<Ingen::Engine> engine;
+ Ingen::Shared::World* world;
};
-static void
-ingen_activate(LV2_Handle instance)
+static LV2_Handle
+ingen_instantiate(const LV2_Descriptor* descriptor,
+ double rate,
+ const char* bundle_path,
+ const LV2_Feature*const* features)
{
- IngenPlugin* plugin = (IngenPlugin*)instance;
- plugin->engine->activate(1);
-}
+ Shared::set_bundle_path(bundle_path);
+ using namespace LV2;
-static void
-ingen_cleanup(LV2_Handle instance)
-{
- IngenPlugin* plugin = (IngenPlugin*)instance;
- plugin->engine.reset();
- ingen_destroy_world();
- free(instance);
+ const LV2Patch* patch = NULL;
+ for (LV2Patches::iterator i = patches.begin(); i != patches.end(); ++i) {
+ if (&(*i)->descriptor == descriptor) {
+ patch = (*i).get();
+ break;
+ }
+ }
+
+ if (!patch) {
+ Raul::error << "Could not find patch " << descriptor->URI << std::endl;
+ return NULL;
+ }
+
+ IngenPlugin* plugin = (IngenPlugin*)malloc(sizeof(IngenPlugin));
+ //plugin->world = ingen_world_new(&conf, argc, argv);
+ plugin->world = LV2::world;
+
+ SharedPtr<Engine> engine(new Engine(plugin->world));
+ plugin->world->set_local_engine(engine);
+
+ SharedPtr<QueuedEngineInterface> interface(
+ new Ingen::QueuedEngineInterface(*plugin->world->local_engine(), event_queue_size));
+ plugin->world->set_engine(interface);
+ plugin->world->local_engine()->add_event_source(interface);
+
+ Raul::Thread::get().set_context(THREAD_PRE_PROCESS);
+ ThreadManager::single_threaded = true;
+
+ ProcessContext context(*engine.get());
+
+ // FIXME: fixed (or at least maximum) buffer size
+ engine->set_driver(SharedPtr<Driver>(new LV2Driver(*engine.get(), rate, 4096)));
+
+ engine->activate();
+ ThreadManager::single_threaded = true;
+
+ // FIXME: don't load all plugins, only necessary ones
+ plugin->world->engine()->load_plugins();
+ engine->process_events(context);
+
+ plugin->world->parser()->parse_document(plugin->world,
+ plugin->world->engine().get(), patch->filename);
+ engine->process_events(context);
+
+ engine->deactivate();
+
+ // Activate and deactivate to create root patch, allocate buffers, etc
+ //engine->activate();
+ //engine->deactivate();
+
+ return (LV2_Handle)plugin;
}
@@ -110,33 +286,40 @@ ingen_connect_port(LV2_Handle instance, uint32_t port, void* data)
}
-static LV2_Handle
-ingen_instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature*const* features)
+static void
+ingen_activate(LV2_Handle instance)
{
- IngenPlugin* plugin = (IngenPlugin*)malloc(sizeof(IngenPlugin));
+ IngenPlugin* me = (IngenPlugin*)instance;
+ me->world->local_engine()->activate();
+}
- Shared::bundle_path = bundle_path;
- plugin->world = ingen_get_world();
- plugin->engine = SharedPtr<Engine>(new Engine(plugin->world));
- plugin->world->local_engine = plugin->engine;
+static void
+ingen_run(LV2_Handle instance, uint32_t sample_count)
+{
+ IngenPlugin* me = (IngenPlugin*)instance;
+ // FIXME: don't do this every call
+ Raul::Thread::get().set_context(THREAD_PROCESS);
+ ((LV2::LV2Driver*)me->world->local_engine()->driver())->run(sample_count);
+}
- // FIXME: fixed buffer size
- plugin->engine->set_driver(PortType::AUDIO,
- SharedPtr<Driver>(new IngenLV2Driver(*plugin->engine, rate, 4096)));
- return (LV2_Handle)plugin;
+static void
+ingen_deactivate(LV2_Handle instance)
+{
+ IngenPlugin* me = (IngenPlugin*)instance;
+ me->world->local_engine()->deactivate();
}
static void
-ingen_run(LV2_Handle instance, uint32_t sample_count)
+ingen_cleanup(LV2_Handle instance)
{
- IngenPlugin* plugin = (IngenPlugin*)instance;
- ((IngenLV2Driver*)plugin->engine->driver())->run(sample_count);
+ IngenPlugin* me = (IngenPlugin*)instance;
+ me->world->set_local_engine(SharedPtr<Engine>());
+ me->world->set_engine(SharedPtr<EngineInterface>());
+ //ingen_world_free(me->world);
+ free(instance);
}
@@ -147,47 +330,79 @@ ingen_extension_data(const char* uri)
}
-static void
-ingen_deactivate(LV2_Handle instance)
+/* Library Code */
+
+namespace Ingen {
+namespace LV2 {
+
+LV2Patch::LV2Patch(const std::string& u, const std::string& f)
+ : uri(u), filename(f)
{
- IngenPlugin* plugin = (IngenPlugin*)instance;
- plugin->engine->deactivate();
+ descriptor.URI = uri.c_str();
+ descriptor.instantiate = ingen_instantiate;
+ descriptor.connect_port = ingen_connect_port;
+ descriptor.activate = ingen_activate;
+ descriptor.run = ingen_run;
+ descriptor.deactivate = ingen_deactivate;
+ descriptor.cleanup = ingen_cleanup;
+ descriptor.extension_data = ingen_extension_data;
}
+} // namespace LV2
+} // namespace Ingen
-/* Library */
-
-static LV2_Descriptor *ingen_descriptor = NULL;
static void
-init_descriptor()
+init()
{
- ingen_descriptor = (LV2_Descriptor*)malloc(sizeof(LV2_Descriptor));
-
- ingen_descriptor->URI = PLUGIN_URI;
- ingen_descriptor->instantiate = ingen_instantiate;
- ingen_descriptor->connect_port = ingen_connect_port;
- ingen_descriptor->activate = ingen_activate;
- ingen_descriptor->run = ingen_run;
- ingen_descriptor->deactivate = ingen_deactivate;
- ingen_descriptor->cleanup = ingen_cleanup;
- ingen_descriptor->extension_data = ingen_extension_data;
+ Shared::set_bundle_path_from_code((void*)&init);
+
+ using namespace LV2;
+
+ //Shared::World* world = ingen_world_new(&conf, argc, argv);
+
+ world = ingen_world_new(&conf, argc, argv);
+ if (!world->load("ingen_serialisation")) {
+ Raul::error << "Unable to load serialisation module" << std::endl;
+ //ingen_world_free(world);
+ return;
+ }
+
+
+ Serialisation::Parser::PatchRecords records(
+ world->parser()->find_patches(world,
+ Glib::filename_to_uri(Shared::bundle_file_path("manifest.ttl"))));
+
+ for (Serialisation::Parser::PatchRecords::iterator i = records.begin();
+ i != records.end(); ++i) {
+ patches.push_back(SharedPtr<const LV2Patch>(
+ new LV2Patch(i->uri.str(), i->filename)));
+ }
+
+
+ //ingen_world_free(world);
+
+ initialised = true;
}
+/* LV2 Library Interface */
+
+extern "C" {
+
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index)
{
- if (!ingen_descriptor)
- init_descriptor();
+ if (!LV2::initialised)
+ init();
- switch (index) {
- case 0:
- return ingen_descriptor;
- default:
+ if (index >= LV2::patches.size())
return NULL;
- }
+ else
+ return &LV2::patches[index]->descriptor;
+}
+
}