summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ingen/EngineBase.hpp7
-rw-r--r--ingen/shared/Module.hpp17
-rw-r--r--src/server/DirectDriver.hpp78
-rw-r--r--src/server/Engine.cpp25
-rw-r--r--src/server/Engine.hpp1
-rw-r--r--src/server/events/CreatePort.cpp112
-rw-r--r--src/server/wscript13
-rw-r--r--src/shared/Module.cpp33
-rw-r--r--src/shared/World.cpp65
-rw-r--r--src/shared/wscript45
-rw-r--r--tests/empty.ingen/empty.ttl41
-rw-r--r--tests/empty.ingen/manifest.ttl17
-rw-r--r--tests/ingen_test.cpp117
-rw-r--r--wscript41
14 files changed, 475 insertions, 137 deletions
diff --git a/ingen/EngineBase.hpp b/ingen/EngineBase.hpp
index c9acb512..5288eafa 100644
--- a/ingen/EngineBase.hpp
+++ b/ingen/EngineBase.hpp
@@ -37,6 +37,13 @@ public:
virtual ~EngineBase() {}
/**
+ Initialise the engine for local use (e.g. without a Jack driver).
+ @param sample_rate Audio sampling rate in Hz.
+ @param block_length Audio block length (i.e. buffer size) in frames.
+ */
+ virtual void init(double sample_rate, uint32_t block_length) = 0;
+
+ /**
Activate the engine.
*/
virtual bool activate() = 0;
diff --git a/ingen/shared/Module.hpp b/ingen/shared/Module.hpp
index 1552a225..81179426 100644
--- a/ingen/shared/Module.hpp
+++ b/ingen/shared/Module.hpp
@@ -19,8 +19,6 @@
#include <glibmm/module.h>
-#include "raul/SharedPtr.hpp"
-
namespace Ingen {
namespace Shared {
@@ -32,12 +30,23 @@ class World;
* @ingroup IngenShared
*/
struct Module {
- virtual ~Module();
+ Module() : library(NULL) {}
+ virtual ~Module() {}
virtual void load(Ingen::Shared::World* world) = 0;
virtual void run(Ingen::Shared::World* world) {}
- SharedPtr<Glib::Module> library;
+ /** Library implementing this module.
+ *
+ * This is managed by the World and not this class, since closing the library
+ * in this destructor could possibly reference code from the library
+ * afterwards and cause a segfault on exit.
+ */
+ Glib::Module* library;
+
+private:
+ Module(const Module& noncopyable);
+ Module& operator=(const Module& noncopyable);
};
} // namespace Shared
diff --git a/src/server/DirectDriver.hpp b/src/server/DirectDriver.hpp
new file mode 100644
index 00000000..b6d66df6
--- /dev/null
+++ b/src/server/DirectDriver.hpp
@@ -0,0 +1,78 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2012 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/>.
+*/
+
+#ifndef INGEN_ENGINE_DIRECT_DRIVER_HPP
+#define INGEN_ENGINE_DIRECT_DRIVER_HPP
+
+#include "Driver.hpp"
+
+namespace Ingen {
+namespace Server {
+
+/** Driver for running Ingen directly as a library.
+ * \ingroup engine
+ */
+class DirectDriver : public Driver {
+public:
+ DirectDriver(double sample_rate, SampleCount block_length)
+ : _sample_rate(sample_rate)
+ , _block_length(block_length)
+ {}
+
+ virtual ~DirectDriver() {}
+
+ virtual void activate() {}
+
+ virtual void deactivate() {}
+
+ virtual EnginePort* create_port(DuplexPort* patch_port) {
+ return NULL;
+ }
+
+ virtual EnginePort* engine_port(ProcessContext& context,
+ const Raul::Path& path) {
+ return NULL;
+ }
+
+ virtual void add_port(ProcessContext& context, EnginePort* port) {}
+
+ virtual Raul::Deletable* remove_port(ProcessContext& context,
+ const Raul::Path& path,
+ EnginePort** port = NULL) {
+ return NULL;
+ }
+
+ virtual SampleCount block_length() const { return _block_length; }
+
+ virtual SampleCount sample_rate() const { return _sample_rate; }
+
+ virtual SampleCount frame_time() const {
+ return 0;
+ }
+
+ virtual bool is_realtime() const {
+ return false;
+ }
+
+private:
+ SampleCount _sample_rate;
+ SampleCount _block_length;
+};
+
+} // namespace Server
+} // namespace Ingen
+
+#endif // INGEN_ENGINE_DIRECT_DRIVER_HPP
diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp
index 69ad435b..9359bacf 100644
--- a/src/server/Engine.cpp
+++ b/src/server/Engine.cpp
@@ -14,7 +14,6 @@
along with Ingen. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <cassert>
#include <sys/mman.h>
#include <unistd.h>
@@ -31,6 +30,7 @@
#include "Broadcaster.hpp"
#include "BufferFactory.hpp"
+#include "DirectDriver.hpp"
#include "ControlBindings.hpp"
#include "Driver.hpp"
#include "Engine.hpp"
@@ -142,14 +142,24 @@ execute_and_delete_event(ProcessContext& context, Event* ev)
delete ev;
}
+void
+Engine::init(double sample_rate, uint32_t block_length)
+{
+ set_driver(SharedPtr<Driver>(new DirectDriver(sample_rate, block_length)));
+}
+
bool
Engine::activate()
{
- assert(_driver);
+ if (!_driver) {
+ return false;
+ }
+
ThreadManager::single_threaded = true;
_buffer_factory->set_block_length(_driver->block_length());
+ _pre_processor->start();
_message_context.Thread::start();
const Ingen::Shared::URIs& uris = world()->uris();
@@ -226,8 +236,15 @@ Engine::activate()
void
Engine::deactivate()
{
- _driver->deactivate();
- _root_patch->deactivate();
+ _pre_processor->stop();
+
+ if (_driver) {
+ _driver->deactivate();
+ }
+
+ if (_root_patch) {
+ _root_patch->deactivate();
+ }
ThreadManager::single_threaded = true;
}
diff --git a/src/server/Engine.hpp b/src/server/Engine.hpp
index 8fcb5ce6..edbe33ae 100644
--- a/src/server/Engine.hpp
+++ b/src/server/Engine.hpp
@@ -65,6 +65,7 @@ public:
virtual ~Engine();
// EngineBase methods
+ virtual void init(double sample_rate, uint32_t block_length);
virtual bool activate();
virtual void deactivate();
virtual unsigned run(uint32_t sample_count);
diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp
index d8c183cd..a783512f 100644
--- a/src/server/events/CreatePort.cpp
+++ b/src/server/events/CreatePort.cpp
@@ -90,73 +90,85 @@ CreatePort::CreatePort(Engine& engine,
void
CreatePort::pre_process()
{
- if (_status == UNKNOWN_TYPE || _engine.engine_store()->find_object(_path)) {
+ if (_status) {
Event::pre_process();
return;
}
- _patch = _engine.engine_store()->find_patch(_path.parent());
+ if (_engine.engine_store()->find_object(_path)) {
+ _status = EXISTS;
+ Event::pre_process();
+ return;
+ }
+
+ if (!(_patch = _engine.engine_store()->find_patch(_path.parent()))) {
+ _status = PARENT_NOT_FOUND;
+ Event::pre_process();
+ return;
+ }
const Ingen::Shared::URIs& uris = _engine.world()->uris();
- if (_patch != NULL) {
- assert(_patch->path() == _path.parent());
-
- size_t buffer_size = _engine.buffer_factory()->default_buffer_size(_buffer_type);
-
- const uint32_t old_num_ports = (_patch->external_ports())
- ? _patch->external_ports()->size()
- : 0;
-
- Resource::Properties::const_iterator index_i = _properties.find(uris.lv2_index);
- if (index_i == _properties.end()) {
- index_i = _properties.insert(
- std::make_pair(uris.lv2_index,
- _engine.world()->forge().make(int32_t(old_num_ports))));
- } else if (index_i->second.type() != uris.forge.Int
- || index_i->second.get_int32() != static_cast<int32_t>(old_num_ports)) {
- Event::pre_process();
- _status = BAD_INDEX;
- return;
- }
+ assert(_patch->path() == _path.parent());
- Resource::Properties::const_iterator poly_i = _properties.find(uris.ingen_polyphonic);
- bool polyphonic = (poly_i != _properties.end() &&
- poly_i->second.type() == uris.forge.Bool &&
- poly_i->second.get_bool());
+ size_t buffer_size = _engine.buffer_factory()->default_buffer_size(_buffer_type);
- _patch_port = _patch->create_port(*_engine.buffer_factory(), _path.symbol(),
- _port_type, _buffer_type, buffer_size,
- _is_output, polyphonic);
+ const uint32_t old_num_ports = (_patch->external_ports())
+ ? _patch->external_ports()->size()
+ : 0;
- _patch_port->properties().insert(_properties.begin(), _properties.end());
+ Resource::Properties::const_iterator index_i = _properties.find(uris.lv2_index);
+ if (index_i == _properties.end()) {
+ index_i = _properties.insert(
+ std::make_pair(uris.lv2_index,
+ _engine.world()->forge().make(int32_t(old_num_ports))));
+ } else if (index_i->second.type() != uris.forge.Int
+ || index_i->second.get_int32() != static_cast<int32_t>(old_num_ports)) {
+ _status = BAD_INDEX;
+ Event::pre_process();
+ return;
+ }
- assert(index_i->second == _engine.world()->forge().make((int)_patch_port->index()));
+ Resource::Properties::const_iterator poly_i = _properties.find(uris.ingen_polyphonic);
+ bool polyphonic = (poly_i != _properties.end() &&
+ poly_i->second.type() == uris.forge.Bool &&
+ poly_i->second.get_bool());
- if (_patch_port) {
- if (_is_output)
- _patch->add_output(new Raul::List<PortImpl*>::Node(_patch_port));
- else
- _patch->add_input(new Raul::List<PortImpl*>::Node(_patch_port));
+ if (!(_patch_port = _patch->create_port(
+ *_engine.buffer_factory(), _path.symbol(),
+ _port_type, _buffer_type, buffer_size, _is_output, polyphonic))) {
+ _status = CREATION_FAILED;
+ Event::pre_process();
+ return;
+ }
- if (_patch->external_ports())
- _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, *_patch->external_ports(), NULL);
- else
- _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, NULL);
+ _patch_port->properties().insert(_properties.begin(), _properties.end());
- _ports_array->at(old_num_ports) = _patch_port;
- _engine.engine_store()->add(_patch_port);
+ assert(index_i->second == _engine.world()->forge().make((int)_patch_port->index()));
- if (!_patch->parent()) {
- _engine_port = _engine.driver()->create_port(
- dynamic_cast<DuplexPort*>(_patch_port));
- }
+ if (_patch_port) {
+ if (_is_output)
+ _patch->add_output(new Raul::List<PortImpl*>::Node(_patch_port));
+ else
+ _patch->add_input(new Raul::List<PortImpl*>::Node(_patch_port));
+
+ if (_patch->external_ports())
+ _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, *_patch->external_ports(), NULL);
+ else
+ _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, NULL);
+
+ _ports_array->at(old_num_ports) = _patch_port;
+ _engine.engine_store()->add(_patch_port);
+
+ if (!_patch->parent()) {
+ _engine_port = _engine.driver()->create_port(
+ dynamic_cast<DuplexPort*>(_patch_port));
+ }
- assert(_ports_array->size() == _patch->num_ports_non_rt());
+ assert(_ports_array->size() == _patch->num_ports_non_rt());
- } else {
- _status = CREATION_FAILED;
- }
+ } else {
+ _status = CREATION_FAILED;
}
_update = _patch_port->properties();
diff --git a/src/server/wscript b/src/server/wscript
index 4cb61be5..8f505983 100644
--- a/src/server/wscript
+++ b/src/server/wscript
@@ -60,6 +60,19 @@ def build(bld):
core_libs = 'GLIBMM GTHREAD LV2 LILV RAUL SORD'
autowaf.use_lib(bld, obj, core_libs)
+ if bld.env['BUILD_TESTS']:
+ obj = bld(features = 'cxx cxxshlib',
+ source = core_source,
+ export_includes = ['../..'],
+ includes = ['.', '../..'],
+ name = 'libingen_server_profiled',
+ target = 'ingen_server_profiled',
+ install_path = '${LIBDIR}',
+ use = 'libingen_shared_profiled',
+ lib = bld.env['INGEN_TEST_LIBS'],
+ cxxflags = bld.env['INGEN_TEST_CXXFLAGS'])
+ autowaf.use_lib(bld, obj, core_libs)
+
if bld.is_defined('HAVE_JACK'):
obj = bld(features = 'cxx cxxshlib',
source = 'JackDriver.cpp ingen_jack.cpp',
diff --git a/src/shared/Module.cpp b/src/shared/Module.cpp
deleted file mode 100644
index 9ef8f0d6..00000000
--- a/src/shared/Module.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2012 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 <glibmm/module.h>
-
-#include "raul/log.hpp"
-#include "raul/SharedPtr.hpp"
-
-#include "ingen/shared/Module.hpp"
-
-namespace Ingen {
-namespace Shared {
-
-Module::~Module()
-{
- Raul::info("[Module] ")(Raul::fmt("Unloading %1%\n") % library->get_name());
-}
-
-} // namespace Shared
-} // namespace Ingen
diff --git a/src/shared/World.cpp b/src/shared/World.cpp
index b71ea8c8..608a8409 100644
--- a/src/shared/World.cpp
+++ b/src/shared/World.cpp
@@ -50,7 +50,7 @@ namespace Shared {
*
* \param name The base name of the module, e.g. "ingen_serialisation"
*/
-static SharedPtr<Glib::Module>
+Glib::Module*
ingen_load_module(const string& name)
{
Glib::Module* module = NULL;
@@ -61,15 +61,14 @@ ingen_load_module(const string& name)
if (module_path_found) {
string dir;
istringstream iss(module_path);
- while (getline(iss, dir, ':')) {
+ while (getline(iss, dir, G_SEARCHPATH_SEPARATOR)) {
string filename = Shared::module_path(name, dir);
if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
- module = new Glib::Module(filename, Glib::MODULE_BIND_LAZY);
+ module = new Glib::Module(filename);
if (*module) {
LOG(Raul::info)(Raul::fmt("Loading %1%\n") % filename);
- return SharedPtr<Glib::Module>(module);
+ return module;
} else {
- delete module;
Raul::error << Glib::Module::get_last_error() << endl;
}
}
@@ -77,23 +76,20 @@ ingen_load_module(const string& name)
}
// Try default directory if not found
- module = new Glib::Module(Shared::module_path(name), Glib::MODULE_BIND_LAZY);
+ module = new Glib::Module(Shared::module_path(name));
- // FIXME: SEGV on exit without this
- module->make_resident();
-
- if (*module) {
+ if (module) {
LOG(Raul::info)(Raul::fmt("Loading %1%\n") % Shared::module_path(name));
- return SharedPtr<Glib::Module>(module);
+ return module;
} else if (!module_path_found) {
LOG(Raul::error)(Raul::fmt("Unable to find %1% (%2%)\n")
% name % Glib::Module::get_last_error());
- return SharedPtr<Glib::Module>();
+ return NULL;
} else {
LOG(Raul::error)(Raul::fmt("Unable to load %1% from %2% (%3%)\n")
% name % module_path % Glib::Module::get_last_error());
LOG(Raul::error)("Is Ingen installed?\n");
- return SharedPtr<Glib::Module>();
+ return NULL;
}
}
@@ -131,28 +127,39 @@ public:
rdf_world->add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#");
}
- virtual ~Impl()
+ ~Impl()
{
serialiser.reset();
parser.reset();
-
+ interface.reset();
engine.reset();
store.reset();
- modules.clear();
interface_factories.clear();
script_runners.clear();
- lilv_world_free(lilv_world);
-
delete rdf_world;
delete lv2_features;
delete uris;
delete forge;
delete uri_map;
+
+ lilv_world_free(lilv_world);
+
+
+ for (Modules::iterator i = modules.begin(); i != modules.end(); ++i) {
+ // Keep a reference to the library
+ Glib::Module* lib = i->second->library;
+
+ // Destroy the Ingen module
+ delete i->second;
+
+ // Now all references to library code should be done, close it
+ delete lib;
+ }
}
- typedef std::map< const std::string, SharedPtr<Module> > Modules;
+ typedef std::map<const std::string, Module*> Modules;
Modules modules;
typedef std::map<const std::string, World::InterfaceFactory> InterfaceFactories;
@@ -189,7 +196,6 @@ World::World(int& argc,
World::~World()
{
- unload_modules();
delete _impl;
}
@@ -225,18 +231,21 @@ World::load_module(const char* name)
LOG(Raul::info)(Raul::fmt("Module `%1%' already loaded\n") % name);
return true;
}
- SharedPtr<Glib::Module> lib = ingen_load_module(name);
+ Glib::Module* lib = ingen_load_module(name);
Ingen::Shared::Module* (*module_load)() = NULL;
if (lib && lib->get_symbol("ingen_module_load", (void*&)module_load)) {
Module* module = module_load();
- module->library = lib;
- module->load(this);
- _impl->modules.insert(make_pair(string(name), module));
- return true;
- } else {
- LOG(Raul::error)(Raul::fmt("Failed to load module `%1%'\n") % name);
- return false;
+ if (module) {
+ module->library = lib;
+ module->load(this);
+ _impl->modules.insert(make_pair(string(name), module));
+ return true;
+ }
}
+
+ LOG(Raul::error)(Raul::fmt("Failed to load module `%1%'\n") % name);
+ delete lib;
+ return false;
}
bool
diff --git a/src/shared/wscript b/src/shared/wscript
index 15e6097e..751951e1 100644
--- a/src/shared/wscript
+++ b/src/shared/wscript
@@ -1,8 +1,25 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
+sources = [
+ 'AtomReader.cpp',
+ 'AtomWriter.cpp',
+ 'Builder.cpp',
+ 'ClashAvoider.cpp',
+ 'Configuration.cpp',
+ 'Forge.cpp',
+ 'LV2Features.cpp',
+ 'ResourceImpl.cpp',
+ 'Store.cpp',
+ 'URIMap.cpp',
+ 'URIs.cpp',
+ 'World.cpp',
+ 'runtime_paths.cpp',
+]
+
def build(bld):
obj = bld(features = 'cxx cxxshlib',
+ source = sources,
export_includes = ['../..'],
includes = ['../..'],
name = 'libingen_shared',
@@ -12,19 +29,15 @@ def build(bld):
lib = ['dl'])
autowaf.use_lib(bld, obj, 'GLIBMM LV2 LILV RAUL SORD LV2_MIDI')
- obj.source = '''
- AtomReader.cpp
- AtomWriter.cpp
- Builder.cpp
- ClashAvoider.cpp
- Configuration.cpp
- Forge.cpp
- LV2Features.cpp
- Module.cpp
- ResourceImpl.cpp
- Store.cpp
- URIMap.cpp
- URIs.cpp
- World.cpp
- runtime_paths.cpp
- '''
+ if bld.env['BUILD_TESTS']:
+ obj = bld(features = 'cxx cxxshlib',
+ source = sources,
+ export_includes = ['../..'],
+ includes = ['../..'],
+ name = 'libingen_shared_profiled',
+ target = 'ingen_shared_profiled',
+ install_path = '',
+ lib = ['dl'] + bld.env['INGEN_TEST_LIBS'],
+ cxxflags = bld.env['INGEN_TEST_CXXFLAGS'])
+ autowaf.use_lib(bld, obj, 'GLIBMM LV2 LILV RAUL SORD LV2_MIDI')
+
diff --git a/tests/empty.ingen/empty.ttl b/tests/empty.ingen/empty.ttl
new file mode 100644
index 00000000..ac905a2e
--- /dev/null
+++ b/tests/empty.ingen/empty.ttl
@@ -0,0 +1,41 @@
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix ingen: <http://drobilla.net/ns/ingen#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .
+@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+<control_in>
+ ingen:polyphonic false ;
+ atom:bufferType atom:Sequence ;
+ lv2:index 0 ;
+ lv2:name "Control" ;
+ lv2:portProperty lv2:connectionOptional ;
+ lv2:symbol "control_in" ;
+ a atom:AtomPort ,
+ lv2:InputPort .
+
+<control_out>
+ ingen:polyphonic false ;
+ atom:bufferType atom:Sequence ;
+ lv2:index 1 ;
+ lv2:name "Control" ;
+ lv2:symbol "control_out" ;
+ a atom:AtomPort ,
+ lv2:OutputPort .
+
+<>
+ ingen:polyphony 1 ;
+ <http://lv2plug.in/ns/extensions/ui#ui> ingen:PatchUIGtk2 ;
+ lv2:extensionData <http://lv2plug.in/ns/ext/state#interface> ;
+ lv2:port <control_in> ,
+ <control_out> ;
+ lv2:symbol "empty" ;
+ doap:name "empty" ;
+ a ingen:Patch ,
+ lv2:Plugin .
diff --git a/tests/empty.ingen/manifest.ttl b/tests/empty.ingen/manifest.ttl
new file mode 100644
index 00000000..5aec4db2
--- /dev/null
+++ b/tests/empty.ingen/manifest.ttl
@@ -0,0 +1,17 @@
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix ingen: <http://drobilla.net/ns/ingen#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .
+@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+<empty.ttl>
+ lv2:binary <libingen_lv2.so> ;
+ a ingen:Patch ,
+ lv2:Plugin ;
+ rdfs:seeAlso <empty.ttl> .
diff --git a/tests/ingen_test.cpp b/tests/ingen_test.cpp
new file mode 100644
index 00000000..0a882023
--- /dev/null
+++ b/tests/ingen_test.cpp
@@ -0,0 +1,117 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2012 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 <signal.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <string>
+
+#include <boost/optional.hpp>
+
+#include <glibmm/convert.h>
+#include <glibmm/miscutils.h>
+#include <glibmm/thread.h>
+#include <glibmm/timer.h>
+
+#include "raul/Configuration.hpp"
+#include "raul/Path.hpp"
+#include "raul/SharedPtr.hpp"
+#include "raul/Thread.hpp"
+#include "raul/log.hpp"
+
+#include "serd/serd.h"
+#include "sord/sordmm.hpp"
+
+#include "ingen_config.h"
+
+#include "ingen/EngineBase.hpp"
+#include "ingen/Interface.hpp"
+#include "ingen/serialisation/Parser.hpp"
+#include "ingen/shared/Configuration.hpp"
+#include "ingen/shared/World.hpp"
+#include "ingen/shared/runtime_paths.hpp"
+#include "ingen/client/ThreadedSigClientInterface.hpp"
+#ifdef WITH_BINDINGS
+#include "bindings/ingen_bindings.hpp"
+#endif
+
+using namespace std;
+using namespace Ingen;
+
+Ingen::Shared::World* world = NULL;
+
+void
+ingen_try(bool cond, const char* msg)
+{
+ if (!cond) {
+ cerr << "ingen: Error: " << msg << endl;
+ delete world;
+ exit(EXIT_FAILURE);
+ }
+}
+
+int
+main(int argc, char** argv)
+{
+ Glib::thread_init();
+ Shared::set_bundle_path_from_code((void*)&main);
+
+ // Create world
+ try {
+ world = new Ingen::Shared::World(argc, argv, NULL, NULL);
+ if (argc <= 1) {
+ world->conf().print_usage("ingen", cout);
+ return EXIT_FAILURE;
+ } else if (world->conf().option("help").get_bool()) {
+ world->conf().print_usage("ingen", cout);
+ return EXIT_SUCCESS;
+ }
+ } catch (std::exception& e) {
+ cout << "ingen: " << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ // Run engine
+ //SharedPtr<Interface> engine_interface;
+ ingen_try(world->load_module("server_profiled"),
+ "Unable to load server module");
+
+ //ingen_try(world->load_module("client"),
+ // "Unable to load client module");
+
+ ingen_try(world->engine(),
+ "Unable to create engine");
+
+ ingen_try(world->load_module("serialisation_profiled"),
+ "Unable to load serialisation module");
+
+ world->engine()->init(48000.0, 4096);
+ world->engine()->activate();
+
+ world->parser()->parse_file(world, world->interface().get(), argv[1]);
+ while (world->engine()->run(4096)) {
+ world->engine()->main_iteration();
+ }
+
+ // Shut down
+ if (world->engine())
+ world->engine()->deactivate();
+
+ delete world;
+ return 0;
+}
+
diff --git a/wscript b/wscript
index cefc8745..0229608c 100644
--- a/wscript
+++ b/wscript
@@ -31,6 +31,8 @@ def options(opt):
help="Do not build JACK session support")
opt.add_option('--no-socket', action='store_true', default=False, dest='no_socket',
help="Do not build Socket interface")
+ opt.add_option('--test', action='store_true', default=False, dest='build_tests',
+ help="Build unit tests")
opt.add_option('--log-debug', action='store_true', default=False, dest='log_debug',
help="Print debugging output")
@@ -78,6 +80,19 @@ def configure(conf):
if conf.is_defined('HAVE_NEW_JACK'):
autowaf.define(conf, 'INGEN_JACK_SESSION', 1)
+ conf.env['BUILD_TESTS'] = Options.options.build_tests
+ if conf.env['BUILD_TESTS']:
+ conf.check_cxx(lib='gcov',
+ define_name='HAVE_GCOV',
+ mandatory=False)
+
+ if conf.is_defined('HAVE_GCOV'):
+ conf.env['INGEN_TEST_LIBS'] = ['gcov']
+ conf.env['INGEN_TEST_CXXFLAGS'] = ['-fprofile-arcs', '-ftest-coverage']
+ else:
+ conf.env['INGEN_TEST_LIBS'] = []
+ conf.env['INGEN_TEST_CXXFLAGS'] = []
+
# Check for posix_memalign (OSX, amazingly, doesn't have it)
conf.check(function_name='posix_memalign',
defines='_POSIX_SOURCE=1',
@@ -142,12 +157,23 @@ def build(bld):
obj = bld(features = 'c cxx cxxprogram',
source = 'src/ingen/main.cpp',
target = bld.path.get_bld().make_node('ingen'),
- includes = ['.', '../..'],
- defines = 'VERSION="' + bld.env['INGEN_VERSION'] + '"',
+ includes = ['.'],
use = 'libingen_shared',
install_path = '${BINDIR}')
autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN LV2')
+ # Test program
+ if bld.env['BUILD_TESTS']:
+ obj = bld(features = 'cxx cxxprogram',
+ source = 'tests/ingen_test.cpp',
+ target = 'tests/ingen_test',
+ includes = ['.'],
+ use = 'libingen_shared_profiled',
+ install_path = '',
+ lib = bld.env['INGEN_TEST_LIBS'],
+ cxxflags = bld.env['INGEN_TEST_CXXFLAGS'])
+ autowaf.use_lib(bld, obj, 'GTHREAD GLIBMM SORD RAUL LILV INGEN LV2')
+
bld.install_files('${DATADIR}/applications', 'src/ingen/ingen.desktop')
bld.install_files('${BINDIR}', 'scripts/ingenish', chmod=Utils.O755)
@@ -174,3 +200,14 @@ def build(bld):
def lint(ctx):
subprocess.call('cpplint.py --filter=-whitespace/comments,-whitespace/tab,-whitespace/braces,-whitespace/labels,-build/header_guard,-readability/casting,-readability/todo,-build/namespaces,-whitespace/line_length,-runtime/rtti,-runtime/references,-whitespace/blank_line,-runtime/sizeof,-readability/streams,-whitespace/operators,-whitespace/parens,-build/include `find -name *.cpp -or -name *.hpp`', shell=True)
+
+def test(ctx):
+ os.environ['PATH'] = 'tests' + os.pathsep + os.getenv('PATH')
+ os.environ['LD_LIBRARY_PATH'] = os.path.join('src', 'shared')
+ os.environ['INGEN_MODULE_PATH'] = os.pathsep.join([
+ os.path.join('src', 'server') ,
+ os.path.join('src', 'serialisation')])
+
+ autowaf.pre_test(ctx, APPNAME, dirs=['.', 'src', 'tests'])
+ autowaf.run_tests(ctx, APPNAME, ['ingen_test ../tests/empty.ingen'], dirs=['.', 'src', 'tests'])
+ autowaf.post_test(ctx, APPNAME, dirs=['.', 'src', 'tests'])