summaryrefslogtreecommitdiffstats
path: root/src/World.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/World.cpp')
-rw-r--r--src/World.cpp339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/World.cpp b/src/World.cpp
new file mode 100644
index 00000000..693f9427
--- /dev/null
+++ b/src/World.cpp
@@ -0,0 +1,339 @@
+/*
+ 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 "ingen/World.hpp"
+
+#include "ingen/Atom.hpp"
+#include "ingen/Configuration.hpp"
+#include "ingen/DataAccess.hpp"
+#include "ingen/EngineBase.hpp"
+#include "ingen/FilePath.hpp"
+#include "ingen/Forge.hpp"
+#include "ingen/InstanceAccess.hpp"
+#include "ingen/LV2Features.hpp"
+#include "ingen/Library.hpp"
+#include "ingen/Log.hpp"
+#include "ingen/Module.hpp"
+#include "ingen/Parser.hpp"
+#include "ingen/Serialiser.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIMap.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/filesystem.hpp"
+#include "ingen/ingen.h"
+#include "ingen/runtime_paths.hpp"
+#include "lilv/lilv.h"
+#include "lv2/log/log.h"
+#include "sord/sordmm.hpp"
+
+#include <cstdint>
+#include <cstdlib>
+#include <list>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <utility>
+
+using std::string;
+
+namespace ingen {
+
+class Interface;
+class Store;
+
+/** Load a dynamic module from the default path.
+ *
+ * This will check in the directories specified in the environment variable
+ * INGEN_MODULE_PATH (typical colon delimited format), then the default module
+ * installation directory (ie /usr/local/lib/ingen), in that order.
+ *
+ * \param name The base name of the module, e.g. "ingen_jack"
+ */
+static std::unique_ptr<Library>
+ingen_load_library(Log& log, const string& name)
+{
+ const auto path = ingen_module_path(name);
+ if (path.empty()) {
+ log.error("Failed to find %1% (%2%)\n",
+ name, Library::get_last_error());
+ return nullptr;
+ }
+
+ UPtr<Library> library = make_unique<Library>(path);
+ if (*library) {
+ return library;
+ }
+
+ log.error("Unable to load %1% from %2% (%3%)\n",
+ name, path, Library::get_last_error());
+ return nullptr;
+}
+
+class World::Impl {
+public:
+ Impl(LV2_URID_Map* map,
+ LV2_URID_Unmap* unmap,
+ LV2_Log_Log* lv2_log)
+ : argc(nullptr)
+ , argv(nullptr)
+ , lv2_features(nullptr)
+ , rdf_world(new Sord::World())
+ , lilv_world(lilv_world_new(), lilv_world_free)
+ , uri_map(log, map, unmap)
+ , forge(uri_map)
+ , uris(forge, &uri_map, lilv_world.get())
+ , conf(forge)
+ , log(lv2_log, uris)
+ {
+ lv2_features = new LV2Features();
+ lv2_features->add_feature(uri_map.urid_map_feature());
+ lv2_features->add_feature(uri_map.urid_unmap_feature());
+ lv2_features->add_feature(SPtr<InstanceAccess>(new InstanceAccess()));
+ lv2_features->add_feature(SPtr<DataAccess>(new DataAccess()));
+ lv2_features->add_feature(SPtr<Log::Feature>(new Log::Feature()));
+ lilv_world_load_all(lilv_world.get());
+
+ // Set up RDF namespaces
+ rdf_world->add_prefix("atom", "http://lv2plug.in/ns/ext/atom#");
+ rdf_world->add_prefix("doap", "http://usefulinc.com/ns/doap#");
+ rdf_world->add_prefix("ingen", INGEN_NS);
+ rdf_world->add_prefix("lv2", "http://lv2plug.in/ns/lv2core#");
+ rdf_world->add_prefix("midi", "http://lv2plug.in/ns/ext/midi#");
+ rdf_world->add_prefix("owl", "http://www.w3.org/2002/07/owl#");
+ rdf_world->add_prefix("patch", "http://lv2plug.in/ns/ext/patch#");
+ rdf_world->add_prefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ rdf_world->add_prefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
+ rdf_world->add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#");
+
+ // Load internal 'plugin' information into lilv world
+ LilvNode* rdf_type = lilv_new_uri(
+ lilv_world.get(), "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+ LilvNode* ingen_Plugin = lilv_new_uri(
+ lilv_world.get(), INGEN__Plugin);
+ LilvNodes* internals = lilv_world_find_nodes(
+ lilv_world.get(), nullptr, rdf_type, ingen_Plugin);
+ LILV_FOREACH(nodes, i, internals) {
+ const LilvNode* internal = lilv_nodes_get(internals, i);
+ lilv_world_load_resource(lilv_world.get(), internal);
+ }
+ lilv_nodes_free(internals);
+ lilv_node_free(rdf_type);
+ lilv_node_free(ingen_Plugin);
+ }
+
+ ~Impl()
+ {
+ if (engine) {
+ engine->quit();
+ }
+
+ // Delete module objects but save pointers to libraries
+ typedef std::list<std::unique_ptr<Library>> Libs;
+ Libs libs;
+ for (auto& m : modules) {
+ libs.emplace_back(std::move(m.second->library));
+ delete m.second;
+ }
+
+ serialiser.reset();
+ parser.reset();
+ interface.reset();
+ engine.reset();
+ store.reset();
+
+ interface_factories.clear();
+ script_runners.clear();
+
+ delete lv2_features;
+
+ // Module libraries go out of scope and close here
+ }
+
+ typedef std::map<std::string, Module*> Modules;
+ Modules modules;
+
+ typedef std::map<const std::string, World::InterfaceFactory> InterfaceFactories;
+ InterfaceFactories interface_factories;
+
+ typedef bool (*ScriptRunner)(World& world, const char* filename);
+ typedef std::map<const std::string, ScriptRunner> ScriptRunners;
+ ScriptRunners script_runners;
+
+ using LilvWorldUPtr = std::unique_ptr<LilvWorld, decltype(&lilv_world_free)>;
+
+ int* argc;
+ char*** argv;
+ LV2Features* lv2_features;
+ UPtr<Sord::World> rdf_world;
+ LilvWorldUPtr lilv_world;
+ URIMap uri_map;
+ Forge forge;
+ URIs uris;
+ LV2_Log_Log* lv2_log;
+ Configuration conf;
+ Log log;
+ SPtr<Interface> interface;
+ SPtr<EngineBase> engine;
+ SPtr<Serialiser> serialiser;
+ SPtr<Parser> parser;
+ SPtr<Store> store;
+ std::mutex rdf_mutex;
+ std::string jack_uuid;
+};
+
+World::World(LV2_URID_Map* map, LV2_URID_Unmap* unmap, LV2_Log_Log* log)
+ : _impl(new Impl(map, unmap, log))
+{
+ _impl->serialiser = SPtr<Serialiser>(new Serialiser(*this));
+ _impl->parser = SPtr<Parser>(new Parser());
+}
+
+World::~World()
+{
+ delete _impl;
+}
+
+void
+World::load_configuration(int& argc, char**& argv)
+{
+ _impl->argc = &argc;
+ _impl->argv = &argv;
+
+ // Parse default configuration files
+ const auto files = _impl->conf.load_default("ingen", "options.ttl");
+ for (const auto& f : files) {
+ _impl->log.info("Loaded configuration %1%\n", f);
+ }
+
+ // Parse command line options, overriding configuration file values
+ _impl->conf.parse(argc, argv);
+ _impl->log.set_flush(_impl->conf.option("flush-log").get<int32_t>());
+ _impl->log.set_trace(_impl->conf.option("trace").get<int32_t>());
+}
+
+void World::set_engine(SPtr<EngineBase> e) { _impl->engine = e; }
+void World::set_interface(SPtr<Interface> i) { _impl->interface = i; }
+void World::set_store(SPtr<Store> s) { _impl->store = s; }
+
+SPtr<EngineBase> World::engine() { return _impl->engine; }
+SPtr<Interface> World::interface() { return _impl->interface; }
+SPtr<Parser> World::parser() { return _impl->parser; }
+SPtr<Serialiser> World::serialiser() { return _impl->serialiser; }
+SPtr<Store> World::store() { return _impl->store; }
+
+int& World::argc() { return *_impl->argc; }
+char**& World::argv() { return *_impl->argv; }
+Configuration& World::conf() { return _impl->conf; }
+Log& World::log() { return _impl->log; }
+
+std::mutex& World::rdf_mutex() { return _impl->rdf_mutex; }
+
+Sord::World* World::rdf_world() { return _impl->rdf_world.get(); }
+LilvWorld* World::lilv_world() { return _impl->lilv_world.get(); }
+
+LV2Features& World::lv2_features() { return *_impl->lv2_features; }
+Forge& World::forge() { return _impl->forge; }
+URIs& World::uris() { return _impl->uris; }
+URIMap& World::uri_map() { return _impl->uri_map; }
+
+bool
+World::load_module(const char* name)
+{
+ auto i = _impl->modules.find(name);
+ if (i != _impl->modules.end()) {
+ return true;
+ }
+ log().info("Loading %1% module\n", name);
+ std::unique_ptr<ingen::Library> lib = ingen_load_library(log(), name);
+ ingen::Module* (*module_load)() =
+ lib ? (ingen::Module* (*)())lib->get_function("ingen_module_load")
+ : nullptr;
+ if (module_load) {
+ Module* module = module_load();
+ if (module) {
+ module->library = std::move(lib);
+ module->load(*this);
+ _impl->modules.emplace(string(name), module);
+ return true;
+ }
+ }
+
+ log().error("Failed to load module `%1%' (%2%)\n",
+ name, lib->get_last_error());
+ return false;
+}
+
+bool
+World::run_module(const char* name)
+{
+ auto i = _impl->modules.find(name);
+ if (i == _impl->modules.end()) {
+ log().error("Attempt to run unloaded module `%1%'\n", name);
+ return false;
+ }
+
+ i->second->run(*this);
+ return true;
+}
+
+/** Get an interface for a remote engine at `engine_uri`
+ */
+SPtr<Interface>
+World::new_interface(const URI& engine_uri, SPtr<Interface> respondee)
+{
+ const Impl::InterfaceFactories::const_iterator i =
+ _impl->interface_factories.find(std::string(engine_uri.scheme()));
+ if (i == _impl->interface_factories.end()) {
+ log().warn("Unknown URI scheme `%1%'\n", engine_uri.scheme());
+ return SPtr<Interface>();
+ }
+
+ return i->second(*this, engine_uri, respondee);
+}
+
+/** Run a script of type `mime_type` at filename `filename` */
+bool
+World::run(const std::string& mime_type, const std::string& filename)
+{
+ const Impl::ScriptRunners::const_iterator i = _impl->script_runners.find(mime_type);
+ if (i == _impl->script_runners.end()) {
+ log().warn("Unknown script MIME type `%1%'\n", mime_type);
+ return false;
+ }
+
+ return i->second(*this, filename.c_str());
+}
+
+void
+World::add_interface_factory(const std::string& scheme, InterfaceFactory factory)
+{
+ _impl->interface_factories.emplace(scheme, factory);
+}
+
+void
+World::set_jack_uuid(const std::string& uuid)
+{
+ _impl->jack_uuid = uuid;
+}
+
+std::string
+World::jack_uuid()
+{
+ return _impl->jack_uuid;
+}
+
+} // namespace ingen