summaryrefslogtreecommitdiffstats
path: root/src/server/ingen_lv2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/ingen_lv2.cpp')
-rw-r--r--src/server/ingen_lv2.cpp850
1 files changed, 0 insertions, 850 deletions
diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp
deleted file mode 100644
index b2806ab6..00000000
--- a/src/server/ingen_lv2.cpp
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen 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 Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <cstdlib>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
-#include "lv2/lv2plug.in/ns/ext/log/log.h"
-#include "lv2/lv2plug.in/ns/ext/log/logger.h"
-#include "lv2/lv2plug.in/ns/ext/options/options.h"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-#include "ingen/AtomReader.hpp"
-#include "ingen/AtomWriter.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/World.hpp"
-#include "ingen/ingen.h"
-#include "ingen/runtime_paths.hpp"
-#include "ingen/types.hpp"
-#include "raul/Semaphore.hpp"
-
-#include "Buffer.hpp"
-#include "Driver.hpp"
-#include "Engine.hpp"
-#include "EnginePort.hpp"
-#include "EventWriter.hpp"
-#include "GraphImpl.hpp"
-#include "PostProcessor.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-
-#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#"
-
-namespace Ingen {
-
-/** Record of a graph in this bundle. */
-struct LV2Graph : public Parser::ResourceRecord {
- LV2Graph(Parser::ResourceRecord record);
-
- LV2_Descriptor descriptor;
-};
-
-/** Ingen LV2 library. */
-class Lib {
-public:
- explicit Lib(const char* bundle_path);
-
- typedef std::vector< SPtr<const LV2Graph> > Graphs;
-
- Graphs graphs;
-};
-
-namespace Server {
-
-class LV2Driver;
-
-void signal_main(RunContext& context, LV2Driver* driver);
-
-inline size_t
-ui_ring_size(SampleCount block_length)
-{
- return std::max((size_t)8192, (size_t)block_length * 16);
-}
-
-class LV2Driver : public Ingen::Server::Driver
- , public Ingen::AtomSink
-{
-public:
- LV2Driver(Engine& engine,
- SampleCount block_length,
- size_t seq_size,
- SampleCount sample_rate)
- : _engine(engine)
- , _main_sem(0)
- , _reader(engine.world()->uri_map(),
- engine.world()->uris(),
- engine.world()->log(),
- *engine.world()->interface().get())
- , _writer(engine.world()->uri_map(),
- engine.world()->uris(),
- *this)
- , _from_ui(ui_ring_size(block_length))
- , _to_ui(ui_ring_size(block_length))
- , _root_graph(nullptr)
- , _notify_capacity(0)
- , _block_length(block_length)
- , _seq_size(seq_size)
- , _sample_rate(sample_rate)
- , _frame_time(0)
- , _to_ui_overflow_sem(0)
- , _to_ui_overflow(false)
- , _instantiated(false)
- {}
-
- virtual bool dynamic_ports() const { return !_instantiated; }
-
- void pre_process_port(RunContext& context, EnginePort* port) {
- const URIs& uris = _engine.world()->uris();
- const SampleCount nframes = context.nframes();
- DuplexPort* graph_port = port->graph_port();
- Buffer* graph_buf = graph_port->buffer(0).get();
- void* lv2_buf = port->buffer();
-
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- graph_port->set_driver_buffer(lv2_buf, nframes * sizeof(float));
- } else if (graph_port->buffer_type() == uris.atom_Sequence) {
- graph_port->set_driver_buffer(lv2_buf, lv2_atom_total_size((LV2_Atom*)lv2_buf));
- if (graph_port->symbol() == "control") { // TODO: Safe to use index?
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_buf;
- bool enqueued = false;
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (AtomReader::is_message(uris, &ev->body)) {
- enqueued = enqueue_message(&ev->body) || enqueued;
- }
- }
-
- if (enqueued) {
- // Enqueued a message for processing, raise semaphore
- _main_sem.post();
- }
- }
- }
-
- if (graph_port->is_input()) {
- graph_port->monitor(context);
- } else {
- graph_buf->prepare_write(context);
- }
- }
-
- void post_process_port(RunContext& context, EnginePort* port) {
- DuplexPort* graph_port = port->graph_port();
-
- // No copying necessary, host buffers are used directly
- // Reset graph port buffer pointer to no longer point to the Jack buffer
- if (graph_port->is_driver_port()) {
- graph_port->set_driver_buffer(nullptr, 0);
- }
- }
-
- void run(uint32_t nframes) {
- _engine.locate(_frame_time, nframes);
-
- // Notify buffer is a Chunk with size set to the available space
- _notify_capacity = ((LV2_Atom_Sequence*)_ports[1]->buffer())->atom.size;
-
- for (auto& p : _ports) {
- pre_process_port(_engine.run_context(), p);
- }
-
- _engine.run(nframes);
- if (_engine.post_processor()->pending()) {
- _main_sem.post();
- }
-
- flush_to_ui(_engine.run_context());
-
- for (auto& p : _ports) {
- post_process_port(_engine.run_context(), p);
- }
-
- _frame_time += nframes;
- }
-
- virtual void deactivate() {
- _engine.quit();
- _main_sem.post();
- }
-
- virtual void set_root_graph(GraphImpl* graph) { _root_graph = graph; }
- virtual GraphImpl* root_graph() { return _root_graph; }
-
- virtual EnginePort* get_port(const Raul::Path& path) {
- for (auto& p : _ports) {
- if (p->graph_port()->path() == path) {
- return p;
- }
- }
-
- return nullptr;
- }
-
- /** Add a port. Called only during init or restore. */
- virtual void add_port(RunContext& context, EnginePort* port) {
- const uint32_t index = port->graph_port()->index();
- if (_ports.size() <= index) {
- _ports.resize(index + 1);
- }
- _ports[index] = port;
- }
-
- /** Remove a port. Called only during init or restore. */
- virtual void remove_port(RunContext& context, EnginePort* port) {
- const uint32_t index = port->graph_port()->index();
- _ports[index] = nullptr;
- }
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void register_port(EnginePort& port) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void unregister_port(EnginePort& port) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value) {}
-
- virtual EnginePort* create_port(DuplexPort* graph_port) {
- graph_port->set_is_driver_port(*_engine.buffer_factory());
- return new EnginePort(graph_port);
- }
-
- virtual void append_time_events(RunContext& context,
- Buffer& buffer)
- {
- const URIs& uris = _engine.world()->uris();
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)_ports[0]->buffer();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->body.type == uris.atom_Object) {
- const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == uris.time_Position) {
- buffer.append_event(ev->time.frames,
- ev->body.size,
- ev->body.type,
- (const uint8_t*)(&ev->body + 1));
- }
- }
- }
- }
-
- virtual int real_time_priority() { return 60; }
-
- /** Called in run thread for events received at control input port. */
- bool enqueue_message(const LV2_Atom* atom) {
- if (_from_ui.write(lv2_atom_total_size(atom), atom) == 0) {
-#ifndef NDEBUG
- _engine.log().error("Control input buffer overflow\n");
-#endif
- return false;
- }
- return true;
- }
-
- Raul::Semaphore& main_sem() { return _main_sem; }
-
- /** AtomSink::write implementation called by the PostProcessor in the main
- * thread to write responses to the UI.
- */
- bool write(const LV2_Atom* atom, int32_t default_id) {
- // Called from post-processor in main thread
- while (_to_ui.write(lv2_atom_total_size(atom), atom) == 0) {
- // Overflow, wait until ring is drained next cycle
- _to_ui_overflow = true;
- _to_ui_overflow_sem.wait();
- _to_ui_overflow = false;
- }
- return true;
- }
-
- void consume_from_ui() {
- const uint32_t read_space = _from_ui.read_space();
- void* buf = nullptr;
- for (uint32_t read = 0; read < read_space;) {
- LV2_Atom atom;
- if (!_from_ui.read(sizeof(LV2_Atom), &atom)) {
- _engine.log().rt_error("Error reading head from from-UI ring\n");
- break;
- }
-
- buf = realloc(buf, sizeof(LV2_Atom) + atom.size);
- memcpy(buf, &atom, sizeof(LV2_Atom));
-
- if (!_from_ui.read(atom.size, (char*)buf + sizeof(LV2_Atom))) {
- _engine.log().rt_error("Error reading body from from-UI ring\n");
- break;
- }
-
- _reader.write((LV2_Atom*)buf);
- read += sizeof(LV2_Atom) + atom.size;
- }
- free(buf);
- }
-
- void flush_to_ui(RunContext& context) {
- if (_ports.size() < 2) {
- _engine.log().rt_error("Standard control ports are not present\n");
- return;
- }
-
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)_ports[1]->buffer();
- if (!seq) {
- _engine.log().rt_error("Notify output not connected\n");
- return;
- }
-
- // Initialise output port buffer to an empty Sequence
- seq->atom.type = _engine.world()->uris().atom_Sequence;
- seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
-
- const uint32_t read_space = _to_ui.read_space();
- for (uint32_t read = 0; read < read_space;) {
- LV2_Atom atom;
- if (!_to_ui.peek(sizeof(LV2_Atom), &atom)) {
- _engine.log().rt_error("Error reading head from to-UI ring\n");
- break;
- }
-
- if (seq->atom.size + lv2_atom_pad_size(
- sizeof(LV2_Atom_Event) + atom.size)
- > _notify_capacity) {
- break; // Output port buffer full, resume next time
- }
-
- LV2_Atom_Event* ev = (LV2_Atom_Event*)(
- (uint8_t*)seq + lv2_atom_total_size(&seq->atom));
-
- ev->time.frames = 0; // TODO: Time?
- ev->body = atom;
-
- _to_ui.skip(sizeof(LV2_Atom));
- if (!_to_ui.read(ev->body.size, LV2_ATOM_BODY(&ev->body))) {
- _engine.log().rt_error("Error reading body from to-UI ring\n");
- break;
- }
-
- read += lv2_atom_total_size(&ev->body);
- seq->atom.size += lv2_atom_pad_size(
- sizeof(LV2_Atom_Event) + ev->body.size);
- }
-
- if (_to_ui_overflow) {
- _to_ui_overflow_sem.post();
- }
- }
-
- virtual SampleCount block_length() const { return _block_length; }
- virtual size_t seq_size() const { return _seq_size; }
- virtual SampleCount sample_rate() const { return _sample_rate; }
- virtual SampleCount frame_time() const { return _frame_time; }
-
- AtomReader& reader() { return _reader; }
- AtomWriter& writer() { return _writer; }
-
- typedef std::vector<EnginePort*> Ports;
-
- Ports& ports() { return _ports; }
-
- void set_instantiated(bool instantiated) { _instantiated = instantiated; }
-
-private:
- Engine& _engine;
- Ports _ports;
- Raul::Semaphore _main_sem;
- AtomReader _reader;
- AtomWriter _writer;
- Raul::RingBuffer _from_ui;
- Raul::RingBuffer _to_ui;
- GraphImpl* _root_graph;
- uint32_t _notify_capacity;
- SampleCount _block_length;
- size_t _seq_size;
- SampleCount _sample_rate;
- SampleCount _frame_time;
- Raul::Semaphore _to_ui_overflow_sem;
- bool _to_ui_overflow;
- bool _instantiated;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-extern "C" {
-
-using namespace Ingen;
-using namespace Ingen::Server;
-
-static void
-ingen_lv2_main(SPtr<Engine> engine, const SPtr<LV2Driver>& driver)
-{
- while (true) {
- // Wait until there is work to be done
- driver->main_sem().wait();
-
- // Convert pending messages to events and push to pre processor
- driver->consume_from_ui();
-
- // Run post processor and maid to finalise events from last time
- if (!engine->main_iteration()) {
- return;
- }
- }
-}
-
-struct IngenPlugin {
- IngenPlugin()
- : world(nullptr)
- , main(nullptr)
- , map(nullptr)
- , argc(0)
- , argv(nullptr)
- {}
-
- Ingen::World* world;
- SPtr<Engine> engine;
- std::thread* main;
- LV2_URID_Map* map;
- int argc;
- char** argv;
-};
-
-static Lib::Graphs
-find_graphs(const URI& manifest_uri)
-{
- Sord::World world;
- Parser parser;
-
- const std::set<Parser::ResourceRecord> resources = parser.find_resources(
- world,
- manifest_uri,
- URI(INGEN__Graph));
-
- Lib::Graphs graphs;
- for (const auto& r : resources) {
- graphs.push_back(SPtr<const LV2Graph>(new LV2Graph(r)));
- }
-
- return graphs;
-}
-
-static LV2_Handle
-ingen_instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature*const* features)
-{
- // Get features from features array
- LV2_URID_Map* map = nullptr;
- LV2_URID_Unmap* unmap = nullptr;
- LV2_Log_Log* log = nullptr;
- const LV2_Options_Option* options = nullptr;
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID__map)) {
- map = (LV2_URID_Map*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_URID__unmap)) {
- unmap = (LV2_URID_Unmap*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_LOG__log)) {
- log = (LV2_Log_Log*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_OPTIONS__options)) {
- options = (const LV2_Options_Option*)features[i]->data;
- }
- }
-
- LV2_Log_Logger logger;
- lv2_log_logger_init(&logger, map, log);
-
- if (!map) {
- lv2_log_error(&logger, "host did not provide URI map feature\n");
- return nullptr;
- } else if (!unmap) {
- lv2_log_error(&logger, "host did not provide URI unmap feature\n");
- return nullptr;
- }
-
- set_bundle_path(bundle_path);
- const std::string manifest_path = Ingen::bundle_file_path("manifest.ttl");
- SerdNode manifest_node = serd_node_new_file_uri(
- (const uint8_t*)manifest_path.c_str(), nullptr, nullptr, true);
-
- Lib::Graphs graphs = find_graphs(URI((const char*)manifest_node.buf));
- serd_node_free(&manifest_node);
-
- const LV2Graph* graph = nullptr;
- for (const auto& g : graphs) {
- if (g->uri == descriptor->URI) {
- graph = g.get();
- break;
- }
- }
-
- if (!graph) {
- lv2_log_error(&logger, "could not find graph <%s>\n", descriptor->URI);
- return nullptr;
- }
-
- IngenPlugin* plugin = new IngenPlugin();
- plugin->map = map;
- plugin->world = new Ingen::World(map, unmap, log);
- plugin->world->load_configuration(plugin->argc, plugin->argv);
-
- LV2_URID bufsz_max = map->map(map->handle, LV2_BUF_SIZE__maxBlockLength);
- LV2_URID bufsz_seq = map->map(map->handle, LV2_BUF_SIZE__sequenceSize);
- LV2_URID atom_Int = map->map(map->handle, LV2_ATOM__Int);
- int32_t block_length = 0;
- int32_t seq_size = 0;
- if (options) {
- for (const LV2_Options_Option* o = options; o->key; ++o) {
- if (o->key == bufsz_max && o->type == atom_Int) {
- block_length = *(const int32_t*)o->value;
- } else if (o->key == bufsz_seq && o->type == atom_Int) {
- seq_size = *(const int32_t*)o->value;
- }
- }
- }
- if (block_length == 0) {
- block_length = 4096;
- plugin->world->log().warn("No maximum block length given\n");
- }
- if (seq_size == 0) {
- seq_size = 16384;
- plugin->world->log().warn("No maximum sequence size given\n");
- }
-
- plugin->world->log().info(
- fmt("Block: %1% frames, Sequence: %2% bytes\n")
- % block_length % seq_size);
- plugin->world->conf().set(
- "queue-size",
- plugin->world->forge().make(std::max(block_length, seq_size) * 4));
-
- SPtr<Server::Engine> engine(new Server::Engine(plugin->world));
- plugin->engine = engine;
- plugin->world->set_engine(engine);
-
- SPtr<Interface> interface = engine->interface();
-
- plugin->world->set_interface(interface);
-
- Server::ThreadManager::set_flag(Server::THREAD_PRE_PROCESS);
- Server::ThreadManager::single_threaded = true;
-
- LV2Driver* driver = new LV2Driver(*engine.get(), block_length, seq_size, rate);
- engine->set_driver(SPtr<Ingen::Server::Driver>(driver));
-
- engine->activate();
- Server::ThreadManager::single_threaded = true;
-
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
-
- // Locate to time 0 to process initialization events
- engine->locate(0, block_length);
- engine->post_processor()->set_end_time(block_length);
-
- // Parse graph, filling the queue with events to create it
- plugin->world->interface()->bundle_begin();
- plugin->world->parser()->parse_file(plugin->world,
- plugin->world->interface().get(),
- graph->filename);
- plugin->world->interface()->bundle_end();
-
- // Drain event queue
- while (engine->pending_events()) {
- engine->process_all_events();
- engine->post_processor()->process();
- engine->maid()->cleanup();
- }
-
- /* Register client after loading graph so the to-ui ring does not overflow.
- Since we are not yet rolling, it won't be drained, causing a deadlock. */
- SPtr<Interface> client(&driver->writer(), NullDeleter<Interface>);
- interface->set_respondee(client);
- engine->register_client(client);
-
- driver->set_instantiated(true);
- return (LV2_Handle)plugin;
-}
-
-static void
-ingen_connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- using namespace Ingen::Server;
-
- IngenPlugin* me = (IngenPlugin*)instance;
- Server::Engine* engine = (Server::Engine*)me->world->engine().get();
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
- if (port < driver->ports().size()) {
- driver->ports().at(port)->set_buffer(data);
- } else {
- engine->log().rt_error("Connect to non-existent port\n");
- }
-}
-
-static void
-ingen_activate(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- SPtr<Server::Engine> engine = static_ptr_cast<Server::Engine>(me->world->engine());
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
- engine->activate();
- me->main = new std::thread(ingen_lv2_main, engine, driver);
-}
-
-static void
-ingen_run(LV2_Handle instance, uint32_t sample_count)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- SPtr<Server::Engine> engine = static_ptr_cast<Server::Engine>(me->world->engine());
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
-
- Server::ThreadManager::set_flag(Ingen::Server::THREAD_PROCESS);
- Server::ThreadManager::set_flag(Ingen::Server::THREAD_IS_REAL_TIME);
-
- driver->run(sample_count);
-}
-
-static void
-ingen_deactivate(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- me->world->engine()->deactivate();
- if (me->main) {
- me->main->join();
- delete me->main;
- me->main = nullptr;
- }
-}
-
-static void
-ingen_cleanup(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- me->world->set_engine(SPtr<Ingen::Server::Engine>());
- me->world->set_interface(SPtr<Ingen::Interface>());
- if (me->main) {
- me->main->join();
- delete me->main;
- }
-
- World* world = me->world;
- delete me;
- delete world;
-}
-
-static void
-get_state_features(const LV2_Feature* const* features,
- LV2_State_Map_Path** map,
- LV2_State_Make_Path** make)
-{
- for (int i = 0; features[i]; ++i) {
- if (map && !strcmp(features[i]->URI, LV2_STATE__mapPath)) {
- *map = (LV2_State_Map_Path*)features[i]->data;
- } else if (make && !strcmp(features[i]->URI, LV2_STATE__makePath)) {
- *make = (LV2_State_Make_Path*)features[i]->data;
- }
- }
-}
-
-static LV2_State_Status
-ingen_save(LV2_Handle instance,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- IngenPlugin* plugin = (IngenPlugin*)instance;
-
- LV2_State_Map_Path* map_path = nullptr;
- LV2_State_Make_Path* make_path = nullptr;
- get_state_features(features, &map_path, &make_path);
- if (!map_path || !make_path || !plugin->map) {
- plugin->world->log().error("Missing state:mapPath, state:makePath, or urid:Map\n");
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- LV2_URID ingen_file = plugin->map->map(plugin->map->handle, INGEN__file);
- LV2_URID atom_Path = plugin->map->map(plugin->map->handle,
- LV2_ATOM__Path);
-
- char* real_path = make_path->path(make_path->handle, "main.ttl");
- char* state_path = map_path->abstract_path(map_path->handle, real_path);
-
- auto root = plugin->world->store()->find(Raul::Path("/"));
-
- {
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
-
- plugin->world->serialiser()->start_to_file(root->second->path(), real_path);
- plugin->world->serialiser()->serialise(root->second);
- plugin->world->serialiser()->finish();
- }
-
- store(handle,
- ingen_file,
- state_path,
- strlen(state_path) + 1,
- atom_Path,
- LV2_STATE_IS_POD);
-
- free(state_path);
- free(real_path);
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-ingen_restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- IngenPlugin* plugin = (IngenPlugin*)instance;
-
- LV2_State_Map_Path* map_path = nullptr;
- get_state_features(features, &map_path, nullptr);
- if (!map_path) {
- plugin->world->log().error("Missing state:mapPath\n");
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- LV2_URID ingen_file = plugin->map->map(plugin->map->handle, INGEN__file);
- size_t size;
- uint32_t type;
- uint32_t valflags;
-
- // Get abstract path to graph file
- const char* path = (const char*)retrieve(
- handle, ingen_file, &size, &type, &valflags);
- if (!path) {
- return LV2_STATE_ERR_NO_PROPERTY;
- }
-
- // Convert to absolute path
- char* real_path = map_path->absolute_path(map_path->handle, path);
- if (!real_path) {
- return LV2_STATE_ERR_UNKNOWN;
- }
-
-#if 0
- // Remove existing root graph contents
- SPtr<Engine> engine = plugin->engine;
- for (const auto& b : engine->root_graph()->blocks()) {
- plugin->world->interface()->del(b.uri());
- }
-
- const uint32_t n_ports = engine->root_graph()->num_ports_non_rt();
- for (int32_t i = n_ports - 1; i >= 0; --i) {
- PortImpl* port = engine->root_graph()->port_impl(i);
- if (port->symbol() != "control" && port->symbol() != "notify") {
- plugin->world->interface()->del(port->uri());
- }
- }
-#endif
-
- // Load new graph
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
- plugin->world->parser()->parse_file(
- plugin->world, plugin->world->interface().get(), real_path);
-
- free(real_path);
- return LV2_STATE_SUCCESS;
-}
-
-static const void*
-ingen_extension_data(const char* uri)
-{
- static const LV2_State_Interface state = { ingen_save, ingen_restore };
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return nullptr;
-}
-
-LV2Graph::LV2Graph(Parser::ResourceRecord record)
- : Parser::ResourceRecord(std::move(record))
-{
- 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;
-}
-
-Lib::Lib(const char* bundle_path)
-{
- Ingen::set_bundle_path(bundle_path);
- const std::string manifest_path = Ingen::bundle_file_path("manifest.ttl");
- SerdNode manifest_node = serd_node_new_file_uri(
- (const uint8_t*)manifest_path.c_str(), nullptr, nullptr, true);
-
- graphs = find_graphs(URI((const char*)manifest_node.buf));
-
- serd_node_free(&manifest_node);
-}
-
-static void
-lib_cleanup(LV2_Lib_Handle handle)
-{
- Lib* lib = (Lib*)handle;
- delete lib;
-}
-
-static const LV2_Descriptor*
-lib_get_plugin(LV2_Lib_Handle handle, uint32_t index)
-{
- Lib* lib = (Lib*)handle;
- return index < lib->graphs.size() ? &lib->graphs[index]->descriptor : nullptr;
-}
-
-/** LV2 plugin library entry point */
-LV2_SYMBOL_EXPORT
-const LV2_Lib_Descriptor*
-lv2_lib_descriptor(const char* bundle_path,
- const LV2_Feature*const* features)
-{
- static const uint32_t desc_size = sizeof(LV2_Lib_Descriptor);
- Lib* lib = new Lib(bundle_path);
-
- // FIXME: memory leak. I think the LV2_Lib_Descriptor API is botched :(
- LV2_Lib_Descriptor* desc = (LV2_Lib_Descriptor*)malloc(desc_size);
- desc->handle = lib;
- desc->size = desc_size;
- desc->cleanup = lib_cleanup;
- desc->get_plugin = lib_get_plugin;
-
- return desc;
-}
-
-} // extern "C"