/* 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 "ingen-config.h" #include #include #include #include #include #include #include #include #include #include "raul/Path.hpp" #include "raul/SharedPtr.hpp" #include "redlandmm/World.hpp" #include "shared/runtime_paths.hpp" #include "module/global.hpp" #include "module/Module.hpp" #include "module/World.hpp" #include "engine/tuning.hpp" #include "engine/Engine.hpp" #include "engine/QueuedEngineInterface.hpp" #include "engine/JackAudioDriver.hpp" #include "serialisation/Parser.hpp" #include "cmdline.h" #ifdef HAVE_LIBLO #include "engine/OSCEngineReceiver.hpp" #endif #ifdef HAVE_SOUP #include "engine/HTTPEngineReceiver.hpp" #endif #ifdef WITH_BINDINGS #include "bindings/ingen_bindings.hpp" #endif using namespace std; using namespace Ingen; using namespace Ingen::Shared; using namespace Raul; SharedPtr engine; void catch_int(int) { signal(SIGINT, catch_int); signal(SIGTERM, catch_int); cout << "[Main] Ingen interrupted." << endl; engine->quit(); } int main(int argc, char** argv) { /* Parse command line options */ gengetopt_args_info args; if (cmdline_parser (argc, argv, &args) != 0) return 1; if (argc <= 1) { cmdline_parser_print_help(); cerr << endl << "*** Ingen requires at least one command line parameter" << endl; cerr << "*** Just want a graphical application? Try 'ingen -eg'" << endl; return 1; } else if (args.connect_given && args.engine_flag) { cerr << "\n*** Nonsense arguments, can't both run a local engine " << "and connect to a remote one." << endl << "*** Run separate instances if that is what you want" << endl; return 1; } /* Set bundle path from executable location so resources/modules can be found */ Shared::set_bundle_path_from_code((void*)&main); SharedPtr engine_module; SharedPtr engine_http_module; SharedPtr engine_osc_module; SharedPtr engine_queued_module; SharedPtr engine_jack_module; SharedPtr client_module; SharedPtr gui_module; SharedPtr bindings_module; SharedPtr engine_interface; Glib::thread_init(); #if HAVE_SOUP g_type_init(); #endif Ingen::Shared::World* world = Ingen::Shared::get_world(); /* Set up RDF world */ world->rdf_world->add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#"); world->rdf_world->add_prefix("ingen", "http://drobilla.net/ns/ingen#"); world->rdf_world->add_prefix("ingenuity", "http://drobilla.net/ns/ingenuity#"); world->rdf_world->add_prefix("lv2", "http://lv2plug.in/ns/lv2core#"); world->rdf_world->add_prefix("lv2ev", "http://lv2plug.in/ns/ext/event#"); world->rdf_world->add_prefix("lv2var", "http://lv2plug.in/ns/ext/instance-var#"); world->rdf_world->add_prefix("lv2midi", "http://lv2plug.in/ns/ext/midi"); world->rdf_world->add_prefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); world->rdf_world->add_prefix("owl", "http://www.w3.org/2002/07/owl#"); world->rdf_world->add_prefix("doap", "http://usefulinc.com/ns/doap#"); world->rdf_world->add_prefix("dc", "http://purl.org/dc/elements/1.1/"); /* Run engine */ if (args.engine_flag) { engine_module = Ingen::Shared::load_module("ingen_engine"); engine_http_module = Ingen::Shared::load_module("ingen_engine_http"); engine_osc_module = Ingen::Shared::load_module("ingen_engine_osc"); engine_jack_module = Ingen::Shared::load_module("ingen_engine_jack"); engine_queued_module = Ingen::Shared::load_module("ingen_engine_queued"); if (!engine_queued_module) { cerr << "ERROR: Unable to load (queued) engine interface module" << endl; Ingen::Shared::destroy_world(); return 1; } if (engine_module) { Engine* (*new_engine)(Ingen::Shared::World* world) = NULL; if (engine_module->get_symbol("new_engine", (void*&)new_engine)) { engine = SharedPtr(new_engine(world)); world->local_engine = engine; /* Load queued (direct in-process) engine interface */ if (args.gui_given && engine_queued_module) { Ingen::QueuedEngineInterface* (*new_interface)(Ingen::Engine& engine); if (engine_queued_module->get_symbol("new_queued_interface", (void*&)new_interface)) { SharedPtr interface(new_interface(*engine)); world->local_engine->add_event_source(interface); engine_interface = interface; world->engine = engine_interface; } } else { #ifdef HAVE_LIBLO if (engine_osc_module) { Ingen::OSCEngineReceiver* (*new_receiver)( Ingen::Engine& engine, size_t queue_size, uint16_t port); if (engine_osc_module->get_symbol("new_osc_receiver", (void*&)new_receiver)) { SharedPtr source(new_receiver(*engine, pre_processor_queue_size, args.engine_port_arg)); world->local_engine->add_event_source(source); } } #endif #ifdef HAVE_SOUP if (engine_http_module) { // FIXE: leak Ingen::HTTPEngineReceiver* (*new_receiver)(Ingen::Engine& engine, uint16_t port); if (engine_http_module->get_symbol("new_http_receiver", (void*&)new_receiver)) { boost::shared_ptr receiver(new_receiver( *world->local_engine, args.engine_port_arg)); world->local_engine->add_event_source(receiver); } } #endif } } else { engine_module.reset(); } } else { cerr << "Unable to load engine module." << endl; } } /* Load client library */ if (args.load_given || args.gui_given) { client_module = Ingen::Shared::load_module("ingen_client"); if (!client_module) cerr << "Unable to load client module." << endl; } /* If we don't have a local engine interface (for GUI), use network */ if (client_module && ! engine_interface) { SharedPtr (*new_remote_interface)(const std::string&) = NULL; if (client_module->get_symbol("new_remote_interface", (void*&)new_remote_interface)) { engine_interface = new_remote_interface(args.connect_arg); } else { cerr << "Unable to find symbol 'new_remote_interface' in " "ingen_client module, aborting." << endl; return -1; } } /* Activate the engine, if we have one */ if (engine) { Ingen::JackAudioDriver* (*new_driver)( Ingen::Engine& engine, const std::string server_name, const std::string client_name, void* jack_client) = NULL; if (engine_jack_module->get_symbol("new_jack_audio_driver", (void*&)new_driver)) { engine->set_driver(DataType::AUDIO, SharedPtr(new_driver( *engine, "default", args.jack_name_arg, NULL))); } else { cerr << Glib::Module::get_last_error() << endl; } engine->activate(args.parallelism_arg); } world->engine = engine_interface; void (*gui_run)() = NULL; /* Load GUI */ bool run_gui = false; if (args.gui_given) { gui_module = Ingen::Shared::load_module("ingen_gui"); if (gui_module) { void (*init)(int, char**, Ingen::Shared::World*); bool found = gui_module->get_symbol("init", (void*&)init); found = found && gui_module->get_symbol("run", (void*&)gui_run); if (found) { run_gui = true; init(argc, argv, world); } else { cerr << "Unable to find hooks in GUI module, GUI not loaded." << endl; } } else { cerr << "Unable to load GUI module." << endl; } } /* Load a patch */ if (args.load_given && engine_interface) { boost::optional data_path = Path("/"); boost::optional parent; boost::optional symbol; if (args.path_given) { const Glib::ustring path = args.path_arg; if (Path::is_valid(path)) { const Path p(path); if (!p.is_root()) { parent = p.parent(); const string s = p.name(); if (Symbol::is_valid(s)) symbol = s; } } else { cerr << "Invalid path given: '" << path << endl; } } bool found = false; if (!world->serialisation_module) world->serialisation_module = Ingen::Shared::load_module("ingen_serialisation"); Serialisation::Parser* (*new_parser)() = NULL; if (world->serialisation_module) found = world->serialisation_module->get_symbol("new_parser", (void*&)new_parser); if (world->serialisation_module && found) { SharedPtr parser(new_parser()); // Assumption: Containing ':' means URI, otherwise filename string uri = args.load_arg; if (uri.find(':') == string::npos) { if (Glib::path_is_absolute(args.load_arg)) uri = Glib::filename_to_uri(args.load_arg); else uri = Glib::filename_to_uri(Glib::build_filename( Glib::get_current_dir(), args.load_arg)); } engine_interface->load_plugins(); parser->parse_document(world, engine_interface.get(), uri, data_path, parent, symbol); } else { cerr << "Unable to load serialisation module, aborting." << endl; return -1; } } /* Run GUI (if applicable) */ if (run_gui) gui_run(); /* Run a script */ if (args.run_given) { #ifdef WITH_BINDINGS bool (*run_script)(Ingen::Shared::World*, const char*) = NULL; SharedPtr bindings_module = Ingen::Shared::load_module("ingen_bindings"); if (bindings_module) { bindings_module->make_resident(); bool found = bindings_module->get_symbol("run", (void*&)(run_script)); if (found) { setenv("PYTHONPATH", "../../bindings", 1); run_script(world, args.run_arg); } else { cerr << "FAILED: " << Glib::Module::get_last_error() << endl; } } else { cerr << Glib::Module::get_last_error() << endl; } #else cerr << "This build of ingen does not support scripting." << endl; #endif /* Listen to OSC and do our own main thing. */ } else if (engine && !run_gui) { signal(SIGINT, catch_int); signal(SIGTERM, catch_int); engine->main(); } if (engine) { engine->deactivate(); engine.reset(); } engine_interface.reset(); client_module.reset(); world->serialisation_module.reset(); gui_module.reset(); engine_module.reset(); Ingen::Shared::destroy_world(); return 0; }