From 19045ab92aa7e996971584a0dc8780d1d58b498b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 19 Dec 2009 21:37:50 +0000 Subject: New ingen module (library, not e.g. LV2 plugin) design. Much cleaner interface and general usage of Ingen as a library. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2314 a436a847-0d15-0410-975c-d299462d15a1 --- src/module/Module.cpp | 91 --------------------------- src/module/Module.hpp | 15 ++++- src/module/World.cpp | 146 ++++++++++++++++++++++++++++++++++++++++++++ src/module/World.hpp | 35 +++++++++-- src/module/ingen_module.cpp | 29 +++------ src/module/ingen_module.hpp | 18 +++--- src/module/wscript | 2 +- 7 files changed, 208 insertions(+), 128 deletions(-) delete mode 100644 src/module/Module.cpp create mode 100644 src/module/World.cpp (limited to 'src/module') diff --git a/src/module/Module.cpp b/src/module/Module.cpp deleted file mode 100644 index 2e2c71a7..00000000 --- a/src/module/Module.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007-2009 Dave Robillard - * - * Ingen 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. - * - * 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 General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include "ingen-config.h" -#include "raul/SharedPtr.hpp" -#include "shared/runtime_paths.hpp" - -using namespace std; - -namespace Ingen { -namespace Shared { - - -/** 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_serialisation" - */ -SharedPtr -load_module(const string& name) -{ - Glib::Module* module = NULL; - - // Search INGEN_MODULE_PATH first - bool module_path_found; - string module_path = Glib::getenv("INGEN_MODULE_PATH", module_path_found); - if (module_path_found) { - string dir; - istringstream iss(module_path); - while (getline(iss, dir, ':')) { - string filename = Glib::Module::build_path(dir, name); - if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { - module = new Glib::Module(filename, Glib::MODULE_BIND_LAZY); - if (*module) { - cerr << "[Module] Loaded \"" << name << "\" from " << filename << endl; - return SharedPtr(module); - } else { - delete module; - cerr << Glib::Module::get_last_error() << endl; - } - } - } - } - - // Try default directory if not found - module = new Glib::Module( - Shared::module_path(name), - Glib::MODULE_BIND_LAZY); - - if (*module) { - cerr << "[Module] Loaded \"" << name << "\" from " << INGEN_MODULE_DIR << endl; - return SharedPtr(module); - } else if (!module_path_found) { - cerr << "[Module] Unable to find " << name - << " (" << Glib::Module::get_last_error() << ")" << endl; - return SharedPtr(); - } else { - cerr << "[Module] Unable to load " << name << " from " << module_path - << " (" << Glib::Module::get_last_error() << ")" << endl; - cerr << "Is Ingen installed? Use ./ingen.dev to run from the source tree." << endl; - return SharedPtr(); - } -} - - -} // namespace Shared -} // namespace Ingen - diff --git a/src/module/Module.hpp b/src/module/Module.hpp index d078264f..c9ac198f 100644 --- a/src/module/Module.hpp +++ b/src/module/Module.hpp @@ -15,6 +15,9 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef INGEN_MODULE_HPP +#define INGEN_MODULE_HPP + #include #include #include "raul/SharedPtr.hpp" @@ -22,14 +25,20 @@ namespace Ingen { namespace Shared { +class World; -/** Load a dynamic module from the default path. +/** A dynamically loaded Ingen module. * - * \param name The base name of the module, e.g. "ingen_serialisation" + * All components of Ingen reside in one of these. */ -SharedPtr load_module(const std::string& name); +struct Module { + virtual void load(Ingen::Shared::World* world) = 0; + + SharedPtr library; +}; } // namespace Shared } // namespace Ingen +#endif //INGEN_MODULE_HPP diff --git a/src/module/World.cpp b/src/module/World.cpp new file mode 100644 index 00000000..0bc87459 --- /dev/null +++ b/src/module/World.cpp @@ -0,0 +1,146 @@ +/* This file is part of Ingen. + * Copyright (C) 2007-2009 Dave Robillard + * + * Ingen 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. + * + * 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 General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "ingen-config.h" +#include "shared/runtime_paths.hpp" +#include "World.hpp" + +using namespace std; + +namespace Ingen { +namespace Shared { + +/** 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_serialisation" + */ +static SharedPtr +load_module(const string& name) +{ + Glib::Module* module = NULL; + + // Search INGEN_MODULE_PATH first + bool module_path_found; + string module_path = Glib::getenv("INGEN_MODULE_PATH", module_path_found); + if (module_path_found) { + string dir; + istringstream iss(module_path); + while (getline(iss, dir, ':')) { + string filename = Glib::Module::build_path(dir, name); + if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { + module = new Glib::Module(filename, Glib::MODULE_BIND_LAZY); + if (*module) { + cerr << "[Module] Loaded \"" << name << "\" from " << filename << endl; + return SharedPtr(module); + } else { + delete module; + cerr << Glib::Module::get_last_error() << endl; + } + } + } + } + + // Try default directory if not found + module = new Glib::Module( + Shared::module_path(name), + Glib::MODULE_BIND_LAZY); + + if (*module) { + cerr << "[Module] Loaded \"" << name << "\" from " << INGEN_MODULE_DIR << endl; + return SharedPtr(module); + } else if (!module_path_found) { + cerr << "[Module] Unable to find " << name + << " (" << Glib::Module::get_last_error() << ")" << endl; + return SharedPtr(); + } else { + cerr << "[Module] Unable to load " << name << " from " << module_path + << " (" << Glib::Module::get_last_error() << ")" << endl; + cerr << "Is Ingen installed? Use ./ingen.dev to run from the source tree." << endl; + return SharedPtr(); + } +} + +/** Load an Ingen module. + * @return true on success, false on failure + */ +bool +World::load(const char* name) +{ + SharedPtr lib = load_module(name); + Ingen::Shared::Module* (*module_load)() = NULL; + if (lib->get_symbol("ingen_module_load", (void*&)module_load)) { + Module* module = module_load(); + module->library = lib; + module->load(this); + modules.insert(make_pair(string(name), module)); + return true; + } else { + cerr << "Failed to load module " << name << endl; + return false; + } +} + + +/** Unload all loaded Ingen modules. + */ +void +World::unload_all() +{ + modules.clear(); +} + + +/** Get an interface for a remote engine at @a url + */ +SharedPtr +World::interface(const std::string& url) +{ + const string scheme = url.substr(0, url.find(":")); + const InterfaceFactories::const_iterator i = interface_factories.find(scheme); + if (i == interface_factories.end()) { + cerr << "WARNING: Unknown URI scheme `'" << scheme << "'" << endl; + return SharedPtr(); + } + + return i->second(this, url); +} + + +/** Run a script of type @a mime_type at filename @a filename */ +bool +World::run(const std::string& mime_type, const std::string& filename) +{ + const ScriptRunners::const_iterator i = script_runners.find(mime_type); + if (i == script_runners.end()) { + cerr << "WARNING: Unknown script MIME type `'" << mime_type << "'" << endl; + return false; + } + + return i->second(this, filename.c_str()); +} + + +} // namespace Shared +} // namespace Ingen diff --git a/src/module/World.hpp b/src/module/World.hpp index 27c9c764..e12ce5b2 100644 --- a/src/module/World.hpp +++ b/src/module/World.hpp @@ -18,8 +18,12 @@ #ifndef INGEN_WORLD_HPP #define INGEN_WORLD_HPP +#include +#include #include #include +#include "raul/Configuration.hpp" +#include "Module.hpp" typedef struct _SLV2World* SLV2World; @@ -49,10 +53,22 @@ class LV2Features; * The Ingen System(TM) and whatnot. */ struct World { - Redland::World* rdf_world; + World() : conf(0) {} - SLV2World slv2_world; - LV2Features* lv2_features; + bool load(const char* name); + void unload_all(); + + SharedPtr interface(const std::string& engine_url); + + bool run(const std::string& mime_type, const std::string& filename); + + int argc; + char** argv; + Raul::Configuration* conf; + + Redland::World* rdf_world; + SLV2World slv2_world; + LV2Features* lv2_features; boost::shared_ptr engine; boost::shared_ptr local_engine; @@ -60,7 +76,18 @@ struct World { boost::shared_ptr parser; boost::shared_ptr store; - boost::shared_ptr serialisation_module; +private: + typedef std::map< const std::string, boost::shared_ptr > Modules; + Modules modules; + + typedef SharedPtr (*InterfaceFactory)( + World* world, const std::string& url); + typedef std::map InterfaceFactories; + InterfaceFactories interface_factories; + + typedef bool (*ScriptRunner)(World* world, const char* filename); + typedef std::map ScriptRunners; + ScriptRunners script_runners; }; diff --git a/src/module/ingen_module.cpp b/src/module/ingen_module.cpp index c9a6d9d4..5faefebc 100644 --- a/src/module/ingen_module.cpp +++ b/src/module/ingen_module.cpp @@ -15,36 +15,30 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include "redlandmm/World.hpp" #include "shared/LV2Features.hpp" #include "ingen_module.hpp" #include "World.hpp" - #include "ingen-config.h" #ifdef HAVE_SLV2 #include "slv2/slv2.h" #endif -using namespace std; - -namespace Ingen { -namespace Shared { - -static World* world = NULL; +extern "C" { +static Ingen::Shared::World* world = NULL; -World* -get_world() +Ingen::Shared::World* +ingen_get_world() { - static World* world = NULL; + static Ingen::Shared::World* world = NULL; if (!world) { - world = new World(); + world = new Ingen::Shared::World(); world->rdf_world = new Redland::World(); #ifdef HAVE_SLV2 world->slv2_world = slv2_world_new_using_rdf_world(world->rdf_world->world()); - world->lv2_features = new LV2Features(); + world->lv2_features = new Ingen::Shared::LV2Features(); slv2_world_load_all(world->slv2_world); #endif world->engine.reset(); @@ -54,11 +48,11 @@ get_world() return world; } - void -destroy_world() +ingen_destroy_world() { if (world) { + world->unload_all(); #ifdef HAVE_SLV2 slv2_world_free(world->slv2_world); delete world->lv2_features; @@ -69,7 +63,4 @@ destroy_world() } } - -} // namesace Shared -} // namespace Ingen - +} // extern "C" diff --git a/src/module/ingen_module.hpp b/src/module/ingen_module.hpp index ef373430..1095a3e6 100644 --- a/src/module/ingen_module.hpp +++ b/src/module/ingen_module.hpp @@ -15,19 +15,17 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef INGEN_GLOBAL_H -#define INGEN_GLOBAL_H +#ifndef INGEN_LIB_MODULE_HPP +#define INGEN_LIB_MODULE_HPP -namespace Ingen { -namespace Shared { +namespace Ingen { namespace Shared { class World; } } -class World; +extern "C" { -World* get_world(); -void destroy_world(); +Ingen::Shared::World* ingen_get_world(); +void ingen_destroy_world(); -} // namesace Shared -} // namespace Ingen +} // extern "C" -#endif // INGEN_GLOBAL_H +#endif // INGEN_LIB_MODULE_HPP diff --git a/src/module/wscript b/src/module/wscript index 318bf645..8553618f 100644 --- a/src/module/wscript +++ b/src/module/wscript @@ -7,7 +7,7 @@ def build(bld): obj = bld.new_task_gen('cxx', 'shlib') obj.source = ''' - Module.cpp + World.cpp ingen_module.cpp ''' obj.export_incdirs = ['.'] -- cgit v1.2.1