summaryrefslogtreecommitdiffstats
path: root/include/ingen
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-08-01 22:41:11 +0200
committerDavid Robillard <d@drobilla.net>2020-08-02 01:48:48 +0200
commitc0f567d3232cbe165e56cb2684cda52df7cfb90f (patch)
tree3ffbe6df3f2056fd579a954e00f0bea49b47104e /include/ingen
parent9eadae8edc7a35f87499f58c3e3b9cec68f74a80 (diff)
downloadingen-c0f567d3232cbe165e56cb2684cda52df7cfb90f.tar.gz
ingen-c0f567d3232cbe165e56cb2684cda52df7cfb90f.tar.bz2
ingen-c0f567d3232cbe165e56cb2684cda52df7cfb90f.zip
Move public headers to a separate include directory
This is more conventional and probably best practice (since it avoids polluting the include path with non-headers), and is supported by the clang-tidy llvm-header-guard check.
Diffstat (limited to 'include/ingen')
-rw-r--r--include/ingen/Arc.hpp40
-rw-r--r--include/ingen/Atom.hpp183
-rw-r--r--include/ingen/AtomForge.hpp123
-rw-r--r--include/ingen/AtomReader.hpp76
-rw-r--r--include/ingen/AtomSink.hpp47
-rw-r--r--include/ingen/AtomWriter.hpp86
-rw-r--r--include/ingen/ClashAvoider.hpp66
-rw-r--r--include/ingen/Clock.hpp66
-rw-r--r--include/ingen/ColorContext.hpp39
-rw-r--r--include/ingen/Configuration.hpp160
-rw-r--r--include/ingen/DataAccess.hpp68
-rw-r--r--include/ingen/EngineBase.hpp145
-rw-r--r--include/ingen/FilePath.hpp125
-rw-r--r--include/ingen/Forge.hpp86
-rw-r--r--include/ingen/InstanceAccess.hpp56
-rw-r--r--include/ingen/Interface.hpp149
-rw-r--r--include/ingen/LV2Features.hpp93
-rw-r--r--include/ingen/Library.hpp48
-rw-r--r--include/ingen/Log.hpp107
-rw-r--r--include/ingen/Message.hpp158
-rw-r--r--include/ingen/Module.hpp64
-rw-r--r--include/ingen/Node.hpp106
-rw-r--r--include/ingen/Parser.hpp99
-rw-r--r--include/ingen/Properties.hpp90
-rw-r--r--include/ingen/QueuedInterface.hpp66
-rw-r--r--include/ingen/Resource.hpp206
-rw-r--r--include/ingen/Serialiser.hpp106
-rw-r--r--include/ingen/SocketReader.hpp85
-rw-r--r--include/ingen/SocketWriter.hpp57
-rw-r--r--include/ingen/Status.hpp92
-rw-r--r--include/ingen/Store.hpp86
-rw-r--r--include/ingen/StreamWriter.hpp52
-rw-r--r--include/ingen/Tee.hpp63
-rw-r--r--include/ingen/TurtleWriter.hpp69
-rw-r--r--include/ingen/URI.hpp175
-rw-r--r--include/ingen/URIMap.hpp96
-rw-r--r--include/ingen/URIs.hpp241
-rw-r--r--include/ingen/World.hpp151
-rw-r--r--include/ingen/client/ArcModel.hpp67
-rw-r--r--include/ingen/client/BlockModel.hpp117
-rw-r--r--include/ingen/client/ClientStore.hpp132
-rw-r--r--include/ingen/client/GraphModel.hpp82
-rw-r--r--include/ingen/client/ObjectModel.hpp99
-rw-r--r--include/ingen/client/PluginModel.hpp127
-rw-r--r--include/ingen/client/PluginUI.hpp116
-rw-r--r--include/ingen/client/PortModel.hpp97
-rw-r--r--include/ingen/client/SigClientInterface.hpp63
-rw-r--r--include/ingen/client/SocketClient.hpp80
-rw-r--r--include/ingen/client/signal.hpp31
-rw-r--r--include/ingen/filesystem.hpp85
-rw-r--r--include/ingen/fmt.hpp38
-rw-r--r--include/ingen/ingen.h75
-rw-r--r--include/ingen/paths.hpp55
-rw-r--r--include/ingen/runtime_paths.hpp51
-rw-r--r--include/ingen/types.hpp54
55 files changed, 5194 insertions, 0 deletions
diff --git a/include/ingen/Arc.hpp b/include/ingen/Arc.hpp
new file mode 100644
index 00000000..62c95d67
--- /dev/null
+++ b/include/ingen/Arc.hpp
@@ -0,0 +1,40 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_ARC_HPP
+#define INGEN_ARC_HPP
+
+#include "ingen/ingen.h"
+#include "raul/Deletable.hpp"
+
+namespace Raul { class Path; }
+
+namespace ingen {
+
+/** A connection between two ports.
+ *
+ * @ingroup Ingen
+ */
+class INGEN_API Arc : public Raul::Deletable
+{
+public:
+ virtual const Raul::Path& tail_path() const = 0;
+ virtual const Raul::Path& head_path() const = 0;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ARC_HPP
diff --git a/include/ingen/Atom.hpp b/include/ingen/Atom.hpp
new file mode 100644
index 00000000..3fb8f091
--- /dev/null
+++ b/include/ingen/Atom.hpp
@@ -0,0 +1,183 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_ATOM_HPP
+#define INGEN_ATOM_HPP
+
+#include "ingen/ingen.h"
+#include "lv2/atom/atom.h"
+#include "lv2/urid/urid.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+
+namespace ingen {
+
+/**
+ A generic typed data container.
+
+ An Atom holds a value with some type and size, both specified by a uint32_t.
+ Values with size less than sizeof(void*) are stored inline: no dynamic
+ allocation occurs so Atoms may be created in hard real-time threads.
+ Otherwise, if the size is larger than sizeof(void*), the value will be
+ dynamically allocated in a separate chunk of memory.
+
+ In either case, the data is stored in a binary compatible format to LV2_Atom
+ (i.e., if the value is dynamically allocated, the header is repeated there).
+*/
+class INGEN_API Atom {
+public:
+ Atom() noexcept = default;
+
+ ~Atom() { dealloc(); }
+
+ /** Construct a raw atom.
+ *
+ * Typically this is not used directly, use Forge methods to make atoms.
+ */
+ Atom(uint32_t size, LV2_URID type, const void* body)
+ : _atom{size, type}
+ {
+ if (is_reference()) {
+ _body.ptr = static_cast<LV2_Atom*>(malloc(sizeof(LV2_Atom) + size));
+ memcpy(_body.ptr, &_atom, sizeof(LV2_Atom));
+ }
+ if (body) {
+ memcpy(get_body(), body, size);
+ }
+ }
+
+ Atom(const Atom& copy)
+ : _atom{copy._atom}
+ {
+ if (is_reference()) {
+ _body.ptr =
+ static_cast<LV2_Atom*>(malloc(sizeof(LV2_Atom) + _atom.size));
+
+ memcpy(_body.ptr, copy._body.ptr, sizeof(LV2_Atom) + _atom.size);
+ } else {
+ _body.val = copy._body.val;
+ }
+ }
+
+ Atom& operator=(const Atom& other) {
+ if (&other == this) {
+ return *this;
+ }
+ dealloc();
+ _atom = other._atom;
+ if (is_reference()) {
+ _body.ptr =
+ static_cast<LV2_Atom*>(malloc(sizeof(LV2_Atom) + _atom.size));
+
+ memcpy(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size);
+ } else {
+ _body.val = other._body.val;
+ }
+ return *this;
+ }
+
+ inline bool operator==(const Atom& other) const {
+ if (_atom.type != other._atom.type ||
+ _atom.size != other._atom.size) {
+ return false;
+ }
+ return is_reference()
+ ? !memcmp(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size)
+ : _body.val == other._body.val;
+ }
+
+ inline bool operator!=(const Atom& other) const {
+ return !operator==(other);
+ }
+
+ inline bool operator<(const Atom& other) const {
+ if (_atom.type == other._atom.type) {
+ const uint32_t min_size = std::min(_atom.size, other._atom.size);
+ const int cmp = is_reference()
+ ? memcmp(_body.ptr, other._body.ptr, min_size)
+ : memcmp(&_body.val, &other._body.val, min_size);
+ return cmp < 0 || (cmp == 0 && _atom.size < other._atom.size);
+ }
+ return type() < other.type();
+ }
+
+ /** Like assignment, but only works for value atoms (not references).
+ * Always real-time safe.
+ * @return true iff set succeeded.
+ */
+ inline bool set_rt(const Atom& other) {
+ if (is_reference()) {
+ return false;
+ } else {
+ _atom = other._atom;
+ _body.val = other._body.val;
+ return true;
+ }
+ }
+
+ inline uint32_t size() const { return _atom.size; }
+ inline LV2_URID type() const { return _atom.type; }
+ inline bool is_valid() const { return _atom.type; }
+
+ inline const void* get_body() const {
+ return is_reference() ? static_cast<void*>(_body.ptr + 1) : &_body.val;
+ }
+
+ inline void* get_body() {
+ return is_reference() ? static_cast<void*>(_body.ptr + 1) : &_body.val;
+ }
+
+ template <typename T> const T& get() const {
+ assert(size() == sizeof(T));
+ return *static_cast<const T*>(get_body());
+ }
+
+ template <typename T> const T* ptr() const {
+ return static_cast<const T*>(get_body());
+ }
+
+ const LV2_Atom* atom() const {
+ return is_reference() ? _body.ptr : &_atom;
+ }
+
+private:
+ /** Free dynamically allocated value, if applicable. */
+ inline void dealloc() {
+ if (is_reference()) {
+ free(_body.ptr);
+ }
+ }
+
+ /** Return true iff this value is dynamically allocated. */
+ inline bool is_reference() const {
+ return _atom.size > sizeof(_body.val);
+ }
+
+ LV2_Atom _atom = {0, 0};
+ union
+ {
+ intptr_t val;
+ LV2_Atom* ptr;
+ } _body = {};
+};
+
+} // namespace ingen
+
+#endif // INGEN_ATOM_HPP
diff --git a/include/ingen/AtomForge.hpp b/include/ingen/AtomForge.hpp
new file mode 100644
index 00000000..b1cec69d
--- /dev/null
+++ b/include/ingen/AtomForge.hpp
@@ -0,0 +1,123 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_ATOMFORGE_HPP
+#define INGEN_ATOMFORGE_HPP
+
+#include "ingen/types.hpp"
+#include "lv2/atom/atom.h"
+#include "lv2/atom/forge.h"
+#include "lv2/atom/util.h"
+#include "sord/sordmm.hpp"
+#include "sratom/sratom.h"
+
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+
+namespace ingen {
+
+/// An atom forge that writes to an automatically-resized memory buffer
+class AtomForge : public LV2_Atom_Forge
+{
+public:
+ explicit AtomForge(LV2_URID_Map& map)
+ : LV2_Atom_Forge{}
+ , _size{0}
+ , _capacity{8 * sizeof(LV2_Atom)}
+ , _sratom{sratom_new(&map)}
+ , _buf{static_cast<LV2_Atom*>(calloc(8, sizeof(LV2_Atom)))}
+ {
+ lv2_atom_forge_init(this, &map);
+ lv2_atom_forge_set_sink(this, c_append, c_deref, this);
+ }
+
+ /// Forge an atom from `node` in `model`
+ void read(Sord::World& world, SordModel* model, const SordNode* node)
+ {
+ sratom_read(_sratom.get(), this, world.c_obj(), model, node);
+ }
+
+ /// Return the top-level atom that has been forged
+ const LV2_Atom* atom() const { return _buf.get(); }
+
+ /// Clear the atom buffer and reset the forge
+ void clear()
+ {
+ lv2_atom_forge_set_sink(this, c_append, c_deref, this);
+ _size = 0;
+ *_buf = {0U, 0U};
+ }
+
+ /// Return the internal atom serialiser
+ Sratom& sratom() { return *_sratom; }
+
+private:
+ struct SratomDeleter { void operator()(Sratom* s) { sratom_free(s); } };
+
+ using AtomPtr = UPtr<LV2_Atom, FreeDeleter<LV2_Atom>>;
+ using SratomPtr = UPtr<Sratom, SratomDeleter>;
+
+ /// Append some data and return a reference to its start
+ intptr_t append(const void* buf, uint32_t len) {
+ // Record offset of the start of this write (+1 to avoid null)
+ const intptr_t ref = _size + 1;
+
+ // Update size and reallocate if necessary
+ if (lv2_atom_pad_size(_size + len) > _capacity) {
+ _capacity = lv2_atom_pad_size(_size + len);
+ _buf = AtomPtr{
+ static_cast<LV2_Atom*>(realloc(_buf.release(), _capacity))};
+ }
+
+ // Append new data
+ memcpy(reinterpret_cast<uint8_t*>(_buf.get()) + _size, buf, len);
+ _size += len;
+ return ref;
+ }
+
+ /// Dereference a reference previously returned by append()
+ LV2_Atom* deref(intptr_t ref) {
+ /* Make some assumptions and do unnecessary math to appease
+ -Wcast-align. This is questionable at best, though the forge should
+ only dereference references to aligned atoms. */
+ assert((ref - 1) % sizeof(LV2_Atom) == 0);
+ return static_cast<LV2_Atom*>(_buf.get() + (ref - 1) / sizeof(LV2_Atom));
+
+ // Alternatively:
+ // return (LV2_Atom*)((uint8_t*)_buf + ref - 1);
+ }
+
+ static LV2_Atom_Forge_Ref
+ c_append(void* handle, const void* buf, uint32_t len) {
+ return static_cast<AtomForge*>(handle)->append(buf, len);
+ }
+
+ static LV2_Atom*
+ c_deref(void* handle, LV2_Atom_Forge_Ref ref) {
+ return static_cast<AtomForge*>(handle)->deref(ref);
+ }
+
+ size_t _size; ///< Current atom size
+ size_t _capacity; ///< Allocated size of atom buffer
+ SratomPtr _sratom; ///< Atom serialiser
+ AtomPtr _buf; ///< Atom buffer
+};
+
+} // namespace ingen
+
+#endif // INGEN_ATOMFORGE_HPP
diff --git a/include/ingen/AtomReader.hpp b/include/ingen/AtomReader.hpp
new file mode 100644
index 00000000..75a3c690
--- /dev/null
+++ b/include/ingen/AtomReader.hpp
@@ -0,0 +1,76 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_ATOMREADER_HPP
+#define INGEN_ATOMREADER_HPP
+
+#include "ingen/AtomSink.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/ingen.h"
+#include "lv2/atom/atom.h"
+
+#include <boost/optional/optional.hpp>
+
+#include <cstdint>
+
+namespace Raul {
+class Path;
+} // namespace Raul
+
+namespace ingen {
+
+class URI;
+class Atom;
+class Interface;
+class Log;
+class Properties;
+class URIMap;
+class URIs;
+
+/** An AtomSink that calls methods on an Interface.
+ * @ingroup IngenShared
+ */
+class INGEN_API AtomReader : public AtomSink
+{
+public:
+ AtomReader(URIMap& map,
+ URIs& uris,
+ Log& log,
+ Interface& iface);
+
+ static bool is_message(const URIs& uris, const LV2_Atom* msg);
+
+ bool write(const LV2_Atom* msg, int32_t default_id=0) override;
+
+private:
+ void get_atom(const LV2_Atom* in, Atom& out);
+
+ boost::optional<URI> atom_to_uri(const LV2_Atom* atom);
+ boost::optional<Raul::Path> atom_to_path(const LV2_Atom* atom);
+ Resource::Graph atom_to_context(const LV2_Atom* atom);
+
+ void get_props(const LV2_Atom_Object* obj,
+ ingen::Properties& props);
+
+ URIMap& _map;
+ URIs& _uris;
+ Log& _log;
+ Interface& _iface;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ATOMREADER_HPP
diff --git a/include/ingen/AtomSink.hpp b/include/ingen/AtomSink.hpp
new file mode 100644
index 00000000..395eba54
--- /dev/null
+++ b/include/ingen/AtomSink.hpp
@@ -0,0 +1,47 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_ATOMSINK_HPP
+#define INGEN_ATOMSINK_HPP
+
+#include "ingen/ingen.h"
+#include "lv2/atom/atom.h"
+
+#include <cstdint>
+
+namespace ingen {
+
+/** A sink for LV2 Atoms.
+ * @ingroup IngenShared
+ */
+class INGEN_API AtomSink {
+public:
+ virtual ~AtomSink() = default;
+
+ /** Write an Atom to the sink.
+ *
+ * @param msg The atom to write.
+ * @param default_id The default response ID to use if no
+ * patch:sequenceNumber property is present on the message.
+ *
+ * @return True on success.
+ */
+ virtual bool write(const LV2_Atom* msg, int32_t default_id=0) = 0;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ATOMSINK_HPP
diff --git a/include/ingen/AtomWriter.hpp b/include/ingen/AtomWriter.hpp
new file mode 100644
index 00000000..f9052d93
--- /dev/null
+++ b/include/ingen/AtomWriter.hpp
@@ -0,0 +1,86 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_ATOMWRITER_HPP
+#define INGEN_ATOMWRITER_HPP
+
+#include "ingen/AtomForge.hpp"
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/ingen.h"
+#include "lv2/atom/forge.h"
+#include "lv2/urid/urid.h"
+
+#include <cstdint>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+
+class AtomSink;
+class URIMap;
+class URIs;
+
+/** An Interface that writes LV2 atoms to an AtomSink. */
+class INGEN_API AtomWriter : public Interface
+{
+public:
+ using result_type = void; ///< For boost::apply_visitor
+
+ AtomWriter(URIMap& map, URIs& uris, AtomSink& sink);
+
+ URI uri() const override { return URI("ingen:/clients/atom_writer"); }
+
+ void message(const Message& message) override;
+
+ void operator()(const BundleBegin&);
+ void operator()(const BundleEnd&);
+ void operator()(const Connect&);
+ void operator()(const Copy&);
+ void operator()(const Del&);
+ void operator()(const Delta&);
+ void operator()(const Disconnect&);
+ void operator()(const DisconnectAll&);
+ void operator()(const Error&);
+ void operator()(const Get&);
+ void operator()(const Move&);
+ void operator()(const Put&);
+ void operator()(const Redo&);
+ void operator()(const Response&);
+ void operator()(const SetProperty&);
+ void operator()(const Undo&);
+
+private:
+ void forge_uri(const URI& uri);
+ void forge_properties(const Properties& properties);
+ void forge_arc(const Raul::Path& tail, const Raul::Path& head);
+ void forge_request(LV2_Atom_Forge_Frame* frame, LV2_URID type, int32_t id);
+ void forge_context(Resource::Graph ctx);
+
+ void finish_msg();
+
+ URIMap& _map;
+ URIs& _uris;
+ AtomSink& _sink;
+ AtomForge _forge;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ATOMWRITER_HPP
diff --git a/include/ingen/ClashAvoider.hpp b/include/ingen/ClashAvoider.hpp
new file mode 100644
index 00000000..1d2cebf0
--- /dev/null
+++ b/include/ingen/ClashAvoider.hpp
@@ -0,0 +1,66 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLASHAVOIDER_HPP
+#define INGEN_CLASHAVOIDER_HPP
+
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+
+#include <map>
+#include <string>
+
+namespace ingen {
+
+class Store;
+class URI;
+
+/** Maps paths so they do not clash with an existing object in a store.
+ *
+ * @ingroup ingen
+ */
+class INGEN_API ClashAvoider
+{
+public:
+ explicit ClashAvoider(const Store& store);
+
+ URI map_uri(const URI& in);
+ Raul::Path map_path(const Raul::Path& in);
+
+ bool exists(const Raul::Path& path) const;
+
+ /** Adjust a new label by increasing the numeric suffix if any.
+ *
+ * @param old_path The old path that was mapped with `map_path()`
+ * @param new_path The new path that `old_path` was mapped to
+ * @param name The old name.
+ */
+ static std::string adjust_name(const Raul::Path& old_path,
+ const Raul::Path& new_path,
+ std::string name);
+
+private:
+ using Offsets = std::map<Raul::Path, unsigned>;
+ using SymbolMap = std::map<Raul::Path, Raul::Path>;
+
+ const Store& _store;
+ Offsets _offsets;
+ SymbolMap _symbol_map;
+};
+
+} // namespace ingen
+
+#endif // INGEN_CLASHAVOIDER_HPP
diff --git a/include/ingen/Clock.hpp b/include/ingen/Clock.hpp
new file mode 100644
index 00000000..27d8443d
--- /dev/null
+++ b/include/ingen/Clock.hpp
@@ -0,0 +1,66 @@
+/*
+ This file is part of Ingen.
+ Copyright 2016-2017 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_CLOCK_HPP
+#define INGEN_ENGINE_CLOCK_HPP
+
+#ifdef __MACH__
+# include <mach/mach.h>
+# include <mach/mach_time.h>
+#else
+# include <ctime>
+# include <sys/time.h>
+#endif
+
+#include <cstdint>
+
+namespace ingen {
+
+class Clock {
+public:
+#ifdef __MACH__
+
+ Clock() { mach_timebase_info(&_timebase); }
+
+ inline uint64_t now_microseconds() const {
+ const uint64_t now = mach_absolute_time();
+ return now * _timebase.numer / _timebase.denom / 1e3;
+ }
+
+private:
+ mach_timebase_info_data_t _timebase;
+
+#else
+
+ inline uint64_t now_microseconds() const {
+ struct timespec time{};
+ clock_gettime(_clock, &time);
+ return static_cast<uint64_t>(time.tv_sec) * 1e6 +
+ static_cast<uint64_t>(time.tv_nsec) / 1e3;
+ }
+
+private:
+# if defined(CLOCK_MONOTONIC_RAW)
+ const clockid_t _clock = CLOCK_MONOTONIC_RAW;
+# else
+ const clockid_t _clock = CLOCK_MONOTONIC;
+# endif
+#endif
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINE_CLOCK_HPP
diff --git a/include/ingen/ColorContext.hpp b/include/ingen/ColorContext.hpp
new file mode 100644
index 00000000..aadb2980
--- /dev/null
+++ b/include/ingen/ColorContext.hpp
@@ -0,0 +1,39 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_COLORCONTEXT_HPP
+#define INGEN_COLORCONTEXT_HPP
+
+#include "ingen/ingen.h"
+
+#include <cstdio>
+
+namespace ingen {
+
+class INGEN_API ColorContext {
+public:
+ enum class Color { RED = 31, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
+
+ ColorContext(FILE* stream, Color color);
+ ~ColorContext();
+
+private:
+ FILE* _stream;
+};
+
+} // namespace ingen
+
+#endif // INGEN_COLORCONTEXT_HPP
diff --git a/include/ingen/Configuration.hpp b/include/ingen/Configuration.hpp
new file mode 100644
index 00000000..4b290316
--- /dev/null
+++ b/include/ingen/Configuration.hpp
@@ -0,0 +1,160 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CONFIGURATION_HPP
+#define INGEN_CONFIGURATION_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/FilePath.hpp"
+#include "ingen/ingen.h"
+#include "lv2/urid/urid.h"
+#include "raul/Exception.hpp"
+
+#include <cstdio>
+#include <list>
+#include <map>
+#include <ostream>
+#include <string>
+
+namespace ingen {
+
+class Forge;
+class URIMap;
+
+/** Ingen configuration (command line options and/or configuration file).
+ * @ingroup IngenShared
+ */
+class INGEN_API Configuration {
+public:
+ explicit Configuration(Forge& forge);
+
+ /** The scope of a configuration option.
+ *
+ * This controls when and where an option will be saved or restored.
+ */
+ enum Scope {
+ GLOBAL = 1, ///< Applies to any Ingen instance
+ SESSION = 1<<1, ///< Applies to this Ingen instance only
+ GUI = 1<<2 ///< Persistent GUI settings saved at exit
+ };
+
+ /** Add a configuration option.
+ *
+ * @param key URI local name, in camelCase
+ * @param name Long option name (without leading "--")
+ * @param letter Short option name (without leading "-")
+ * @param desc Description
+ * @param scope Scope of option
+ * @param type Type
+ * @param value Default value
+ */
+ Configuration& add(const std::string& key,
+ const std::string& name,
+ char letter,
+ const std::string& desc,
+ Scope scope,
+ LV2_URID type,
+ const Atom& value);
+
+ void print_usage(const std::string& program, std::ostream& os);
+
+ struct OptionError : public Raul::Exception {
+ explicit OptionError(const std::string& m) : Exception(m) {}
+ };
+
+ struct FileError : public Raul::Exception {
+ explicit FileError(const std::string& m) : Exception(m) {}
+ };
+
+ /** Parse a command line.
+ *
+ * @throw OptionError
+ */
+ void parse(int argc, char **argv);
+
+ /** Load a specific file. */
+ bool load(const FilePath& path);
+
+ /** Save configuration to a file.
+ *
+ * @param uri_map URI map.
+ *
+ * @param app Application name.
+ *
+ * @param filename If absolute, the configuration will be saved to this
+ * path. Otherwise the configuration will be saved to the user
+ * configuration directory (e.g. ~/.config/ingen/filename).
+ *
+ * @param scopes Bitwise OR of Scope values. Only options which match the
+ * given scopes will be saved.
+ *
+ * @return The absolute path of the saved configuration file.
+ */
+ FilePath save(URIMap& uri_map,
+ const std::string& app,
+ const FilePath& filename,
+ unsigned scopes);
+
+ /** Load files from the standard configuration directories for the app.
+ *
+ * The system configuration file(s), e.g. /etc/xdg/appname/filename,
+ * will be loaded before the user's, e.g. ~/.config/appname/filename,
+ * so the user options will override the system options.
+ */
+ std::list<FilePath> load_default(const std::string& app,
+ const FilePath& filename);
+
+ const Atom& option(const std::string& long_name) const;
+ bool set(const std::string& long_name, const Atom& value);
+
+private:
+ struct Option {
+ std::string key;
+ std::string name;
+ char letter;
+ std::string desc;
+ Scope scope;
+ LV2_URID type;
+ Atom value;
+ };
+
+ struct OptionNameOrder {
+ inline bool operator()(const Option& a, const Option& b) {
+ return a.name < b.name;
+ }
+ };
+
+ using Options = std::map<std::string, Option>;
+ using ShortNames = std::map<char, std::string>;
+ using Keys = std::map<std::string, std::string>;
+
+ std::string variable_string(LV2_URID type) const;
+
+ int set_value_from_string(Configuration::Option& option,
+ const std::string& value);
+
+ Forge& _forge;
+ const std::string _shortdesc;
+ const std::string _desc;
+ Options _options;
+ Keys _keys;
+ ShortNames _short_names;
+ size_t _max_name_length;
+};
+
+} // namespace ingen
+
+#endif // INGEN_CONFIGURATION_HPP
diff --git a/include/ingen/DataAccess.hpp b/include/ingen/DataAccess.hpp
new file mode 100644
index 00000000..13b5ac47
--- /dev/null
+++ b/include/ingen/DataAccess.hpp
@@ -0,0 +1,68 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_DATAACCESS_HPP
+#define INGEN_ENGINE_DATAACCESS_HPP
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/Node.hpp"
+#include "ingen/Store.hpp"
+#include "ingen/World.hpp"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+#include "lv2/data-access/data-access.h"
+
+#include <cstdlib>
+#include <memory>
+#include <utility>
+
+namespace ingen {
+
+struct DataAccess : public ingen::LV2Features::Feature
+{
+ static void delete_feature(LV2_Feature* feature) {
+ free(feature->data);
+ delete feature;
+ }
+
+ const char* uri() const override { return "http://lv2plug.in/ns/ext/data-access"; }
+
+ SPtr<LV2_Feature> feature(World& world, Node* node) override {
+ Node* store_node = world.store()->get(node->path());
+ if (!store_node) {
+ return SPtr<LV2_Feature>();
+ }
+
+ LilvInstance* inst = store_node->instance();
+ if (!inst) {
+ return SPtr<LV2_Feature>();
+ }
+
+ const LV2_Descriptor* desc = lilv_instance_get_descriptor(inst);
+ auto* data = static_cast<LV2_Extension_Data_Feature*>(
+ malloc(sizeof(LV2_Extension_Data_Feature)));
+
+ data->data_access = desc->extension_data;
+
+ return std::make_shared<LV2_Feature>(
+ LV2_Feature{"http://lv2plug.in/ns/ext/data-access", data});
+ }
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINE_DATAACCESS_HPP
diff --git a/include/ingen/EngineBase.hpp b/include/ingen/EngineBase.hpp
new file mode 100644
index 00000000..36742601
--- /dev/null
+++ b/include/ingen/EngineBase.hpp
@@ -0,0 +1,145 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_ENGINEBASE_HPP
+#define INGEN_ENGINEBASE_HPP
+
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+
+namespace ingen {
+
+class Interface;
+
+/**
+ The audio engine which executes the graph.
+
+ @ingroup Ingen
+*/
+class INGEN_API EngineBase
+{
+public:
+ virtual ~EngineBase() = default;
+
+ /**
+ 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.
+ @param seq_size Sequence buffer size in bytes.
+ */
+ virtual void init(double sample_rate,
+ uint32_t block_length,
+ size_t seq_size) = 0;
+
+ /**
+ Return true iff the engine and driver supports dynamic ports.
+
+ This returns false in situations where top level ports can not be
+ created once the driver is running, which is the case for most
+ environments outside Jack.
+ */
+ virtual bool supports_dynamic_ports() const = 0;
+
+ /**
+ Activate the engine.
+ */
+ virtual bool activate() = 0;
+
+ /**
+ Deactivate the engine.
+ */
+ virtual void deactivate() = 0;
+
+ /**
+ Begin listening on network sockets.
+ */
+ virtual void listen() = 0;
+
+ /**
+ Return true iff events are waiting to be processed.
+ */
+ virtual bool pending_events() const = 0;
+
+ /**
+ Flush any pending events.
+
+ This function is only safe to call in sequential contexts, and runs both
+ process thread and main iterations in lock-step.
+
+ @param sleep_ms Interval in milliseconds to sleep between each block.
+ */
+ virtual void flush_events(const std::chrono::milliseconds& sleep_ms) = 0;
+
+ /**
+ Advance audio time by the given number of frames.
+ */
+ virtual void advance(uint32_t nframes) = 0;
+
+ /**
+ Locate to a given audio position.
+ */
+ virtual void locate(uint32_t start, uint32_t sample_count) = 0;
+
+ /**
+ Process audio for `sample_count` frames.
+
+ If the return value is non-zero, events have been processed and are
+ awaiting to be finalised (including responding and announcing any changes
+ to clients) via a call to main_iteration().
+
+ @return The number of events processed.
+ */
+ virtual unsigned run(uint32_t sample_count) = 0;
+
+ /**
+ Indicate that a quit is desired.
+
+ This function simply sets a flag which affects the return value of
+ main_iteration, it does not actually force the engine to stop running or
+ block. The code driving the engine is responsible for stopping and
+ cleaning up when main_iteration returns false.
+ */
+ virtual void quit() = 0;
+
+ /**
+ Run a single iteration of the main context.
+
+ The main context post-processes events and performs housekeeping duties
+ like collecting garbage. This should be called regularly, e.g. a few
+ times per second. The return value indicates whether execution should
+ continue; i.e. if false is returned, a quit has been requested and the
+ caller should cease calling main_iteration() and stop the engine.
+ */
+ virtual bool main_iteration() = 0;
+
+ /**
+ Register a client to receive updates about engine changes.
+ */
+ virtual void register_client(const SPtr<Interface>& client) = 0;
+
+ /**
+ Unregister a client.
+ */
+ virtual bool unregister_client(const SPtr<Interface>& client) = 0;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINEBASE_HPP
diff --git a/include/ingen/FilePath.hpp b/include/ingen/FilePath.hpp
new file mode 100644
index 00000000..337553ef
--- /dev/null
+++ b/include/ingen/FilePath.hpp
@@ -0,0 +1,125 @@
+/*
+ This file is part of Ingen.
+ Copyright 2018 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_FILE_PATH_HPP
+#define INGEN_FILE_PATH_HPP
+
+#include "ingen/ingen.h"
+
+#include <boost/utility/string_view.hpp>
+
+#include <ostream>
+#include <string>
+#include <utility>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define USE_WINDOWS_FILE_PATHS 1
+#endif
+
+namespace ingen {
+
+/** A path to a file.
+ *
+ * This is a minimal subset of the std::filesystem::path interface in C++17.
+ * Support for Windows paths is only partial and there is no support for
+ * character encoding conversion at all.
+ */
+class INGEN_API FilePath
+{
+public:
+#ifdef USE_WINDOWS_FILE_PATHS
+ using value_type = wchar_t;
+ static constexpr value_type preferred_separator = L'\\';
+#else
+ using value_type = char;
+ static constexpr value_type preferred_separator = '/';
+#endif
+
+ using string_type = std::basic_string<value_type>;
+
+ FilePath() = default;
+ FilePath(const FilePath&) = default;
+ FilePath(FilePath&&) = default;
+
+ FilePath(string_type str) : _str(std::move(str)) {}
+ FilePath(const value_type* str) : _str(str) {}
+ FilePath(const boost::basic_string_view<value_type>& sv)
+ : _str(sv.data(), sv.length())
+ {}
+
+ ~FilePath() = default;
+
+ FilePath& operator=(const FilePath& path) = default;
+ FilePath& operator=(FilePath&& path) noexcept;
+ FilePath& operator=(string_type&& str);
+
+ FilePath& operator/=(const FilePath& path);
+
+ FilePath& operator+=(const FilePath& path);
+ FilePath& operator+=(const string_type& str);
+ FilePath& operator+=(const value_type* str);
+ FilePath& operator+=(value_type chr);
+ FilePath& operator+=(boost::basic_string_view<value_type> sv);
+
+ void clear() noexcept { _str.clear(); }
+
+ const string_type& native() const noexcept { return _str; }
+ const string_type& string() const noexcept { return _str; }
+ const value_type* c_str() const noexcept { return _str.c_str(); }
+
+ operator string_type() const { return _str; }
+
+ static FilePath root_name();
+
+ FilePath root_directory() const;
+ FilePath root_path() const;
+ FilePath relative_path() const;
+ FilePath parent_path() const;
+ FilePath filename() const;
+ FilePath stem() const;
+ FilePath extension() const;
+
+ bool empty() const noexcept { return _str.empty(); }
+
+ bool is_absolute() const;
+ bool is_relative() const { return !is_absolute(); }
+
+private:
+ std::size_t find_first_sep() const;
+ std::size_t find_last_sep() const;
+
+ string_type _str;
+};
+
+INGEN_API bool operator==(const FilePath& lhs, const FilePath& rhs) noexcept;
+INGEN_API bool operator!=(const FilePath& lhs, const FilePath& rhs) noexcept;
+INGEN_API bool operator<(const FilePath& lhs, const FilePath& rhs) noexcept;
+INGEN_API bool operator<=(const FilePath& lhs, const FilePath& rhs) noexcept;
+INGEN_API bool operator>(const FilePath& lhs, const FilePath& rhs) noexcept;
+INGEN_API bool operator>=(const FilePath& lhs, const FilePath& rhs) noexcept;
+
+INGEN_API FilePath operator/(const FilePath& lhs, const FilePath& rhs);
+
+template <typename Char, typename Traits>
+std::basic_ostream<Char, Traits>&
+operator<<(std::basic_ostream<Char, Traits>& os, const FilePath& path)
+{
+ return os << path.string();
+}
+
+} // namespace ingen
+
+#endif // INGEN_FILE_PATH_HPP
diff --git a/include/ingen/Forge.hpp b/include/ingen/Forge.hpp
new file mode 100644
index 00000000..10b4e622
--- /dev/null
+++ b/include/ingen/Forge.hpp
@@ -0,0 +1,86 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_FORGE_HPP
+#define INGEN_FORGE_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/ingen.h"
+#include "lv2/atom/forge.h"
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+namespace ingen {
+
+class URIMap;
+class URI;
+
+/** Forge for Atoms.
+ * @ingroup IngenShared
+ */
+class INGEN_API Forge : public LV2_Atom_Forge {
+public:
+ explicit Forge(URIMap& map);
+
+ std::string str(const Atom& atom, bool quoted);
+
+ bool is_uri(const Atom& atom) const {
+ return atom.type() == URI || atom.type() == URID;
+ }
+
+ static Atom make() { return Atom(); }
+ Atom make(int32_t v) { return Atom(sizeof(v), Int, &v); }
+ Atom make(float v) { return Atom(sizeof(v), Float, &v); }
+ Atom make(bool v) {
+ const int32_t iv = v ? 1 : 0;
+ return Atom(sizeof(int32_t), Bool, &iv);
+ }
+
+ Atom make_urid(int32_t v) { return Atom(sizeof(int32_t), URID, &v); }
+
+ Atom make_urid(const ingen::URI& u);
+
+ static Atom alloc(uint32_t size, uint32_t type, const void* val) {
+ return Atom(size, type, val);
+ }
+
+ Atom alloc(const char* v) {
+ const size_t len = strlen(v);
+ return Atom(len + 1, String, v);
+ }
+
+ Atom alloc(const std::string& v) {
+ return Atom(v.length() + 1, String, v.c_str());
+ }
+
+ Atom alloc_uri(const char* v) {
+ const size_t len = strlen(v);
+ return Atom(len + 1, URI, v);
+ }
+
+ Atom alloc_uri(const std::string& v) {
+ return Atom(v.length() + 1, URI, v.c_str());
+ }
+
+private:
+ URIMap& _map;
+};
+
+} // namespace ingen
+
+#endif // INGEN_FORGE_HPP
diff --git a/include/ingen/InstanceAccess.hpp b/include/ingen/InstanceAccess.hpp
new file mode 100644
index 00000000..5d068ae1
--- /dev/null
+++ b/include/ingen/InstanceAccess.hpp
@@ -0,0 +1,56 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_INSTANCEACCESS_HPP
+#define INGEN_ENGINE_INSTANCEACCESS_HPP
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/Node.hpp"
+#include "ingen/Store.hpp"
+#include "ingen/World.hpp"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+
+#include <memory>
+#include <utility>
+
+namespace ingen {
+
+struct InstanceAccess : public ingen::LV2Features::Feature
+{
+ const char* uri() const override { return "http://lv2plug.in/ns/ext/instance-access"; }
+
+ SPtr<LV2_Feature> feature(World& world, Node* node) override {
+ Node* store_node = world.store()->get(node->path());
+ if (!store_node) {
+ return SPtr<LV2_Feature>();
+ }
+
+ LilvInstance* instance = store_node->instance();
+ if (!instance) {
+ return SPtr<LV2_Feature>();
+ }
+
+ return std::make_shared<LV2_Feature>(
+ LV2_Feature{"http://lv2plug.in/ns/ext/instance-access",
+ lilv_instance_get_handle(instance)});
+ }
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINE_INSTANCEACCESS_HPP
diff --git a/include/ingen/Interface.hpp b/include/ingen/Interface.hpp
new file mode 100644
index 00000000..6ce12c6a
--- /dev/null
+++ b/include/ingen/Interface.hpp
@@ -0,0 +1,149 @@
+/*
+ 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/>.
+*/
+
+/**
+ @defgroup Ingen Core Interfaces
+*/
+
+#ifndef INGEN_INTERFACE_HPP
+#define INGEN_INTERFACE_HPP
+
+#include "ingen/Message.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/Status.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <cstdint>
+#include <string>
+
+namespace Raul {
+class Path;
+} // namespace Raul
+
+namespace ingen {
+
+class Atom;
+class URI;
+
+/** Abstract interface for Ingen servers and clients.
+ *
+ * @ingroup Ingen
+ */
+class INGEN_API Interface
+{
+public:
+ using result_type = void;
+
+ Interface() = default;
+
+ virtual ~Interface() = default;
+
+ virtual URI uri() const = 0;
+
+ virtual SPtr<Interface> respondee() const { return SPtr<Interface>(); }
+
+ virtual void set_respondee(const SPtr<Interface>& respondee) {}
+
+ virtual void message(const Message& msg) = 0;
+
+ /** @name Convenience API
+ * @{
+ */
+
+ inline void operator()(const Message& msg) { message(msg); }
+
+ inline void set_response_id(int32_t id) { _seq = id; }
+
+ inline void bundle_begin() { message(BundleBegin{_seq++}); }
+ inline void bundle_end() { message(BundleEnd{_seq++}); }
+
+ inline void put(const URI& uri,
+ const Properties& properties,
+ Resource::Graph ctx = Resource::Graph::DEFAULT)
+ {
+ message(Put{_seq++, uri, properties, ctx});
+ }
+
+ inline void delta(const URI& uri,
+ const Properties& remove,
+ const Properties& add,
+ Resource::Graph ctx = Resource::Graph::DEFAULT)
+ {
+ message(Delta{_seq++, uri, remove, add, ctx});
+ }
+
+ inline void copy(const URI& old_uri, const URI& new_uri)
+ {
+ message(Copy{_seq++, old_uri, new_uri});
+ }
+
+ inline void move(const Raul::Path& old_path, const Raul::Path& new_path)
+ {
+ message(Move{_seq++, old_path, new_path});
+ }
+
+ inline void del(const URI& uri) { message(Del{_seq++, uri}); }
+
+ inline void connect(const Raul::Path& tail, const Raul::Path& head)
+ {
+ message(Connect{_seq++, tail, head});
+ }
+
+ inline void disconnect(const Raul::Path& tail, const Raul::Path& head)
+ {
+ message(Disconnect{_seq++, tail, head});
+ }
+
+ inline void disconnect_all(const Raul::Path& graph, const Raul::Path& path)
+ {
+ message(DisconnectAll{_seq++, graph, path});
+ }
+
+ inline void set_property(const URI& subject,
+ const URI& predicate,
+ const Atom& value,
+ Resource::Graph ctx = Resource::Graph::DEFAULT)
+ {
+ message(SetProperty{_seq++, subject, predicate, value, ctx});
+ }
+
+ inline void undo() { message(Undo{_seq++}); }
+
+ inline void redo() { message(Redo{_seq++}); }
+
+ inline void get(const URI& uri) { message(Get{_seq++, uri}); }
+
+ inline void response(int32_t id, Status status, const std::string& subject)
+ {
+ message(Response{id, status, subject});
+ }
+
+ inline void error(const std::string& error_message)
+ {
+ message(Error{_seq++, error_message});
+ }
+
+ /** @} */
+
+private:
+ int32_t _seq = 0;
+};
+
+} // namespace ingen
+
+#endif // INGEN_INTERFACE_HPP
diff --git a/include/ingen/LV2Features.hpp b/include/ingen/LV2Features.hpp
new file mode 100644
index 00000000..75d5b377
--- /dev/null
+++ b/include/ingen/LV2Features.hpp
@@ -0,0 +1,93 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_LV2FEATURES_HPP
+#define INGEN_LV2FEATURES_HPP
+
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/core/lv2.h"
+#include "raul/Noncopyable.hpp"
+
+#include <string>
+#include <vector>
+
+namespace ingen {
+
+class Node;
+class World;
+
+/** Features for use by LV2 plugins.
+ * @ingroup IngenShared
+ */
+class INGEN_API LV2Features {
+public:
+ LV2Features() = default;
+
+ class Feature {
+ public:
+ virtual ~Feature() = default;
+
+ virtual const char* uri() const = 0;
+
+ virtual SPtr<LV2_Feature> feature(World& world,
+ Node* block) = 0;
+
+protected:
+ static void free_feature(LV2_Feature* feature);
+ };
+
+ class EmptyFeature : public Feature {
+ public:
+ explicit EmptyFeature(const char* uri) : _uri(uri) {}
+
+ const char* uri() const override { return _uri; }
+
+ SPtr<LV2_Feature> feature(World& world, Node* block) override {
+ return SPtr<LV2_Feature>();
+ }
+
+ const char* _uri;
+ };
+
+ class FeatureArray : public Raul::Noncopyable {
+ public:
+ using FeatureVector = std::vector<SPtr<LV2_Feature>>;
+
+ explicit FeatureArray(FeatureVector& features);
+
+ ~FeatureArray();
+
+ LV2_Feature** array() { return _array; }
+
+ private:
+ FeatureVector _features;
+ LV2_Feature** _array;
+ };
+
+ void add_feature(const SPtr<Feature>& feature);
+ bool is_supported(const std::string& uri) const;
+
+ SPtr<FeatureArray> lv2_features(World& world, Node* node) const;
+
+private:
+ using Features = std::vector<SPtr<Feature>>;
+ Features _features;
+};
+
+} // namespace ingen
+
+#endif // INGEN_LV2FEATURES_HPP
diff --git a/include/ingen/Library.hpp b/include/ingen/Library.hpp
new file mode 100644
index 00000000..fd4f4260
--- /dev/null
+++ b/include/ingen/Library.hpp
@@ -0,0 +1,48 @@
+/*
+ This file is part of Ingen.
+ Copyright 2018 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_LIBRARY_HPP
+#define INGEN_LIBRARY_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/ingen.h"
+
+namespace ingen {
+
+/** A dynamically loaded library (module, plugin). */
+class INGEN_API Library {
+public:
+ Library(const FilePath& path);
+ ~Library();
+
+ Library(const Library&) = delete;
+ Library& operator=(const Library&) = delete;
+
+ using VoidFuncPtr = void (*)();
+
+ VoidFuncPtr get_function(const char* name);
+
+ static const char* get_last_error();
+
+ operator bool() const { return _lib; }
+
+private:
+ void* _lib;
+};
+
+} // namespace ingen
+
+#endif // INGEN_LIBRARY_HPP
diff --git a/include/ingen/Log.hpp b/include/ingen/Log.hpp
new file mode 100644
index 00000000..d668e873
--- /dev/null
+++ b/include/ingen/Log.hpp
@@ -0,0 +1,107 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_LOG_HPP
+#define INGEN_LOG_HPP
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/fmt.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/core/lv2.h"
+#include "lv2/log/log.h"
+#include "lv2/urid/urid.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <functional>
+#include <string>
+#include <utility>
+
+namespace ingen {
+
+class Node;
+class URIs;
+class World;
+
+class INGEN_API Log {
+public:
+ using Sink = std::function<int(LV2_URID, const char*, va_list)>;
+
+ Log(LV2_Log_Log* log, URIs& uris);
+
+ struct Feature : public LV2Features::Feature {
+ const char* uri() const override { return LV2_LOG__log; }
+
+ SPtr<LV2_Feature> feature(World& world, Node* block) override;
+
+ struct Handle {
+ LV2_Log_Log lv2_log;
+ Log* log;
+ Node* node;
+ };
+ };
+
+ void rt_error(const char* msg);
+
+ void error(const std::string& msg);
+ void info(const std::string& msg);
+ void warn(const std::string& msg);
+ void trace(const std::string& msg);
+
+ template <typename... Args>
+ void error(const char* format, Args&&... args)
+ {
+ error(fmt(format, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ void info(const char* format, Args&&... args)
+ {
+ info(fmt(format, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ void warn(const char* format, Args&&... args)
+ {
+ warn(fmt(format, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ void trace(const char* format, Args&&... args)
+ {
+ trace(fmt(format, std::forward<Args>(args)...));
+ }
+
+ int vtprintf(LV2_URID type, const char* fmt, va_list args);
+
+ void set_flush(bool f) { _flush = f; }
+ void set_trace(bool f) { _trace = f; }
+ void set_sink(Sink s) { _sink = std::move(s); }
+
+private:
+ void print(FILE* stream, const std::string& msg) const;
+
+ LV2_Log_Log* _log;
+ URIs& _uris;
+ Sink _sink;
+ bool _flush;
+ bool _trace;
+};
+
+} // namespace ingen
+
+#endif // INGEN_LOG_HPP
diff --git a/include/ingen/Message.hpp b/include/ingen/Message.hpp
new file mode 100644
index 00000000..09444d4a
--- /dev/null
+++ b/include/ingen/Message.hpp
@@ -0,0 +1,158 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_MESSAGE_HPP
+#define INGEN_MESSAGE_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/Status.hpp"
+#include "raul/Path.hpp"
+
+#include <boost/variant/variant.hpp>
+
+#include <cstdint>
+#include <string>
+
+namespace ingen {
+
+struct BundleBegin
+{
+ int32_t seq;
+};
+
+struct BundleEnd
+{
+ int32_t seq;
+};
+
+struct Connect
+{
+ int32_t seq;
+ Raul::Path tail;
+ Raul::Path head;
+};
+
+struct Copy
+{
+ int32_t seq;
+ URI old_uri;
+ URI new_uri;
+};
+
+struct Del
+{
+ int32_t seq;
+ URI uri;
+};
+
+struct Delta
+{
+ int32_t seq;
+ URI uri;
+ Properties remove;
+ Properties add;
+ Resource::Graph ctx;
+};
+
+struct Disconnect
+{
+ int32_t seq;
+ Raul::Path tail;
+ Raul::Path head;
+};
+
+struct DisconnectAll
+{
+ int32_t seq;
+ Raul::Path graph;
+ Raul::Path path;
+};
+
+struct Error
+{
+ int32_t seq;
+ std::string message;
+};
+
+struct Get
+{
+ int32_t seq;
+ URI subject;
+};
+
+struct Move
+{
+ int32_t seq;
+ Raul::Path old_path;
+ Raul::Path new_path;
+};
+
+struct Put
+{
+ int32_t seq;
+ URI uri;
+ Properties properties;
+ Resource::Graph ctx;
+};
+
+struct Redo
+{
+ int32_t seq;
+};
+
+struct Response
+{
+ int32_t id;
+ Status status;
+ std::string subject;
+};
+
+struct SetProperty
+{
+ int32_t seq;
+ URI subject;
+ URI predicate;
+ Atom value;
+ Resource::Graph ctx;
+};
+
+struct Undo
+{
+ int32_t seq;
+};
+
+using Message = boost::variant<BundleBegin,
+ BundleEnd,
+ Connect,
+ Copy,
+ Del,
+ Delta,
+ Disconnect,
+ DisconnectAll,
+ Error,
+ Get,
+ Move,
+ Put,
+ Redo,
+ Response,
+ SetProperty,
+ Undo>;
+
+} // namespace ingen
+
+#endif // INGEN_MESSAGE_HPP
diff --git a/include/ingen/Module.hpp b/include/ingen/Module.hpp
new file mode 100644
index 00000000..88f4afcd
--- /dev/null
+++ b/include/ingen/Module.hpp
@@ -0,0 +1,64 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_MODULE_HPP
+#define INGEN_MODULE_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/Library.hpp"
+#include "ingen/ingen.h"
+
+#include <memory>
+
+namespace ingen {
+
+class World;
+
+/** A dynamically loaded Ingen module.
+ *
+ * All components of Ingen reside in one of these.
+ * @ingroup IngenShared
+ */
+class INGEN_API Module {
+public:
+ Module() : library(nullptr) {}
+ virtual ~Module() = default;
+
+ Module(const Module&) = delete;
+ Module& operator=(const Module&) = delete;
+
+ virtual void load(ingen::World& world) = 0;
+ virtual void run(ingen::World& world) {}
+
+ /** 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.
+ */
+ std::unique_ptr<Library> library;
+};
+
+} // namespace ingen
+
+extern "C" {
+
+/** Prototype for the ingen_module_load() entry point in an ingen module. */
+INGEN_API ingen::Module* ingen_module_load();
+
+}
+
+#endif // INGEN_MODULE_HPP
diff --git a/include/ingen/Node.hpp b/include/ingen/Node.hpp
new file mode 100644
index 00000000..148a9103
--- /dev/null
+++ b/include/ingen/Node.hpp
@@ -0,0 +1,106 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_NODE_HPP
+#define INGEN_NODE_HPP
+
+#include "ingen/Resource.hpp"
+#include "ingen/ingen.h"
+#include "ingen/paths.hpp"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace Raul {
+class Path;
+class Symbol;
+} // namespace Raul
+
+namespace ingen {
+
+class Arc;
+class FilePath;
+class Store;
+class URIs;
+
+/** A node in the audio graph.
+ *
+ * The key property of nodes is that all nodes have a path and a symbol, as
+ * well as a URI.
+ *
+ * To avoid ugly inheritance issues and the need for excessive use of
+ * dynamic_cast, this class contains some members which are only applicable to
+ * certain types of node. There is a type tag which can be used to determine
+ * the type of any Node.
+ *
+ * @ingroup Ingen
+ */
+class INGEN_API Node : public Resource
+{
+public:
+ enum class GraphType {
+ GRAPH,
+ BLOCK,
+ PORT
+ };
+
+ using ArcsKey = std::pair<const Node*, const Node*>;
+ using Arcs = std::map<ArcsKey, SPtr<Arc>>;
+
+ // Graphs only
+ Arcs& arcs() { return _arcs; }
+ const Arcs& arcs() const { return _arcs; }
+
+ // Blocks and graphs only
+ virtual uint32_t num_ports() const { return 0; }
+ virtual Node* port(uint32_t index) const { return nullptr; }
+ virtual const Resource* plugin() const { return nullptr; }
+
+ // Plugin blocks only
+ virtual LilvInstance* instance() { return nullptr; }
+ virtual bool save_state(const FilePath& dir) const { return false; }
+
+ // All objects
+ virtual GraphType graph_type() const = 0;
+ virtual const Raul::Path& path() const = 0;
+ virtual const Raul::Symbol& symbol() const = 0;
+ virtual Node* graph_parent() const = 0;
+
+ URI base_uri() const {
+ if (uri().string()[uri().string().size() - 1] == '/') {
+ return uri();
+ }
+ return URI(uri().string() + '/');
+ }
+
+protected:
+ friend class Store;
+ virtual void set_path(const Raul::Path& p) = 0;
+
+ Node(const URIs& uris, const Raul::Path& path)
+ : Resource(uris, path_to_uri(path))
+ {}
+
+ Arcs _arcs; ///< Graphs only
+};
+
+} // namespace ingen
+
+#endif // INGEN_NODE_HPP
diff --git a/include/ingen/Parser.hpp b/include/ingen/Parser.hpp
new file mode 100644
index 00000000..45d087cd
--- /dev/null
+++ b/include/ingen/Parser.hpp
@@ -0,0 +1,99 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_PARSER_HPP
+#define INGEN_PARSER_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+#include "raul/Symbol.hpp"
+
+#include <boost/optional/optional.hpp>
+
+#include <set>
+#include <string>
+#include <utility>
+
+namespace Sord { class World; }
+
+namespace ingen {
+
+class Interface;
+class World;
+
+/**
+ Parser for reading graphs from Turtle files or strings.
+
+ @ingroup Ingen
+*/
+class INGEN_API Parser {
+public:
+ explicit Parser() = default;
+
+ virtual ~Parser() = default;
+
+ /** Record of a resource listed in a bundle manifest. */
+ struct ResourceRecord {
+ inline ResourceRecord(URI u, FilePath f)
+ : uri(std::move(u)), filename(std::move(f))
+ {}
+
+ inline bool operator<(const ResourceRecord& r) const {
+ return uri < r.uri;
+ }
+
+ URI uri; ///< URI of resource (e.g. a Graph)
+ FilePath filename; ///< Path of describing file (seeAlso)
+ };
+
+ /** Find all resources of a given type listed in a manifest file. */
+ virtual std::set<ResourceRecord> find_resources(Sord::World& world,
+ const URI& manifest_uri,
+ const URI& type_uri);
+
+ /** Parse a graph from RDF into a Interface (engine or client).
+ *
+ * If `path` is a file path, then the graph is loaded from that
+ * file. If it is a directory, then the manifest.ttl from that directory
+ * is used instead. In either case, any rdfs:seeAlso files are loaded and
+ * the graph parsed from the resulting combined model.
+ *
+ * @return whether or not load was successful.
+ */
+ virtual bool parse_file(
+ World& world,
+ Interface& target,
+ const FilePath& path,
+ const boost::optional<Raul::Path>& parent = boost::optional<Raul::Path>(),
+ const boost::optional<Raul::Symbol>& symbol = boost::optional<Raul::Symbol>(),
+ const boost::optional<Properties>& data = boost::optional<Properties>());
+
+ virtual boost::optional<URI> parse_string(
+ World& world,
+ Interface& target,
+ const std::string& str,
+ const URI& base_uri,
+ const boost::optional<Raul::Path>& parent = boost::optional<Raul::Path>(),
+ const boost::optional<Raul::Symbol>& symbol = boost::optional<Raul::Symbol>(),
+ const boost::optional<Properties>& data = boost::optional<Properties>());
+};
+
+} // namespace ingen
+
+#endif // INGEN_PARSER_HPP
diff --git a/include/ingen/Properties.hpp b/include/ingen/Properties.hpp
new file mode 100644
index 00000000..cd81ba59
--- /dev/null
+++ b/include/ingen/Properties.hpp
@@ -0,0 +1,90 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_PROPERTIES_HPP
+#define INGEN_PROPERTIES_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/URIs.hpp"
+
+#include <initializer_list>
+#include <map>
+#include <utility>
+
+namespace ingen {
+
+/** A property value (an Atom with a context). */
+class Property : public Atom {
+public:
+ enum class Graph {
+ DEFAULT, ///< Default context for "universal" properties
+ EXTERNAL, ///< Externally visible graph properties
+ INTERNAL ///< Internally visible graph properties
+ };
+
+ Property(const Atom& atom, Graph ctx=Graph::DEFAULT)
+ : Atom(atom)
+ , _ctx(ctx)
+ {}
+
+ Property(const URIs::Quark& quark, Graph ctx=Graph::DEFAULT)
+ : Atom(quark.urid_atom())
+ , _ctx(ctx)
+ {}
+
+ Graph context() const { return _ctx; }
+ void set_context(Graph ctx) { _ctx = ctx; }
+
+private:
+ Graph _ctx;
+};
+
+class Properties : public std::multimap<URI, Property> {
+public:
+ using Graph = Property::Graph;
+
+ Properties() = default;
+ Properties(const Properties& copy) = default;
+
+ Properties(std::initializer_list<value_type> l)
+ : std::multimap<URI, Property>(l)
+ {}
+
+ void put(const URI& key,
+ const Atom& value,
+ Graph ctx = Graph::DEFAULT) {
+ emplace(key, Property(value, ctx));
+ }
+
+ void put(const URI& key,
+ const URIs::Quark& value,
+ Graph ctx = Graph::DEFAULT) {
+ emplace(key, Property(value, ctx));
+ }
+
+ bool contains(const URI& key, const Atom& value) {
+ for (const_iterator i = find(key); i != end() && i->first == key; ++i) {
+ if (i->second == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+} // namespace ingen
+
+#endif // INGEN_PROPERTIES_HPP
diff --git a/include/ingen/QueuedInterface.hpp b/include/ingen/QueuedInterface.hpp
new file mode 100644
index 00000000..f45dd3da
--- /dev/null
+++ b/include/ingen/QueuedInterface.hpp
@@ -0,0 +1,66 @@
+/*
+ This file is part of Ingen.
+ Copyright 2018 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_QUEUEDINTERFACE_HPP
+#define INGEN_ENGINE_QUEUEDINTERFACE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+
+#include <mutex>
+#include <vector>
+
+namespace ingen {
+
+/** Stores all messages and emits them to a sink on demand.
+ *
+ * This can be used to make an interface thread-safe.
+ */
+class QueuedInterface : public Interface
+{
+public:
+ explicit QueuedInterface(SPtr<Interface> sink) : _sink(std::move(sink)) {}
+
+ URI uri() const override { return URI("ingen:/QueuedInterface"); }
+
+ void message(const Message& message) override {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _messages.emplace_back(message);
+ }
+
+ void emit() {
+ std::vector<Message> messages;
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _messages.swap(messages);
+ }
+
+ for (const auto& i : messages) {
+ _sink->message(i);
+ }
+ }
+
+ const SPtr<Interface>& sink() const { return _sink; }
+
+private:
+ std::mutex _mutex;
+ SPtr<Interface> _sink;
+ std::vector<Message> _messages;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINE_QUEUEDINTERFACE_HPP
diff --git a/include/ingen/Resource.hpp b/include/ingen/Resource.hpp
new file mode 100644
index 00000000..481e4c30
--- /dev/null
+++ b/include/ingen/Resource.hpp
@@ -0,0 +1,206 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_RESOURCE_HPP
+#define INGEN_RESOURCE_HPP
+
+#include "ingen/Properties.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/ingen.h"
+#include "raul/Deletable.hpp"
+
+#include <cassert>
+
+namespace ingen {
+
+class Atom;
+
+/** A resource with a URI described by properties.
+ *
+ * This is the base class for most things in Ingen, including graphs, blocks,
+ * ports, and the engine itself.
+ *
+ * @ingroup Ingen
+ */
+class INGEN_API Resource : public Raul::Deletable
+{
+public:
+ using Graph = Property::Graph;
+
+ Resource(const URIs& uris, URI uri)
+ : _uris(uris)
+ , _uri(std::move(uri))
+ {}
+
+ Resource(const Resource& resource) = default;
+
+ Resource& operator=(const Resource& rhs) {
+ assert(&rhs._uris == &_uris);
+ if (&rhs != this) {
+ _uri = rhs._uri;
+ _properties = rhs._properties;
+ }
+ return *this;
+ }
+
+ static URI graph_to_uri(Graph g) {
+ switch (g) {
+ case Graph::EXTERNAL: return URI(INGEN_NS "externalContext");
+ case Graph::INTERNAL: return URI(INGEN_NS "internalContext");
+ default: return URI(INGEN_NS "defaultContext");
+ }
+ }
+
+ static Graph uri_to_graph(const URI& uri) {
+ if (uri == INGEN_NS "externalContext") {
+ return Graph::EXTERNAL;
+ } else if (uri == INGEN_NS "internalContext") {
+ return Graph::INTERNAL;
+ }
+ return Graph::DEFAULT;
+ }
+
+ /** Get a single property value.
+ *
+ * This is only useful for properties with a single value. If the
+ * requested property has several values, the first will be returned.
+ */
+ virtual const Atom& get_property(const URI& uri) const;
+
+ /** Set (replace) a property value.
+ *
+ * This will first erase any properties with the given `uri`, so after
+ * this call exactly one property with predicate `uri` will be set.
+ */
+ virtual const Atom& set_property(const URI& uri,
+ const Atom& value,
+ Graph ctx = Graph::DEFAULT);
+
+ /** Set (replace) a property value.
+ *
+ * This will first erase any properties with the given `uri`, so after
+ * this call exactly one property with predicate `uri` will be set.
+ */
+ virtual const Atom& set_property(const URI& uri,
+ const URIs::Quark& value,
+ Graph ctx = Graph::DEFAULT);
+
+ /** Add a property value.
+ *
+ * This will not remove any existing values, so if properties with
+ * predicate `uri` and values other than `value` exist, this will result
+ * in multiple values for the property.
+ *
+ * @return True iff a new property was added.
+ */
+ virtual bool add_property(const URI& uri,
+ const Atom& value,
+ Graph ctx = Graph::DEFAULT);
+
+ /** Remove a property.
+ *
+ * If `value` is patch:wildcard then any property with `uri` for a
+ * predicate will be removed.
+ */
+ virtual void remove_property(const URI& uri,
+ const Atom& value);
+
+ /** Remove a property.
+ *
+ * If `value` is patch:wildcard then any property with `uri` for a
+ * predicate will be removed.
+ */
+ virtual void remove_property(const URI& uri,
+ const URIs::Quark& value);
+
+ /** Return true iff a property is set with a specific value. */
+ virtual bool has_property(const URI& uri,
+ const Atom& value) const;
+
+ /** Return true iff a property is set with a specific value. */
+ virtual bool has_property(const URI& uri,
+ const URIs::Quark& value) const;
+
+ /** Set (replace) several properties at once.
+ *
+ * This will erase all properties with keys in `p`, though multiple values
+ * for one property may exist in `p` will all be set (unlike simply
+ * calling set_property in a loop which would only set one value).
+ */
+ void set_properties(const Properties& props);
+
+ /** Add several properties at once. */
+ void add_properties(const Properties& props);
+
+ /** Remove several properties at once.
+ *
+ * This removes all matching properties (both key and value), or all
+ * properties with a matching key if the value in `p` is patch:wildcard.
+ */
+ void remove_properties(const Properties& props);
+
+ /** Hook called whenever a property is added.
+ *
+ * This can be used by derived classes to implement special behaviour for
+ * particular properties (e.g. ingen:value for ports).
+ */
+ virtual void on_property(const URI& uri, const Atom& value) {}
+
+ /** Hook called whenever a property value is removed.
+ *
+ * If all values for a key are removed, then value will be the wildcard.
+ *
+ * This can be used by derived classes to implement special behaviour for
+ * particular properties (e.g. ingen:value for ports).
+ */
+ virtual void on_property_removed(const URI& uri, const Atom& value) {}
+
+ /** Get the ingen type from a set of Properties.
+ *
+ * If some coherent ingen type is found, true is returned and the appropriate
+ * output parameter set to true. Otherwise false is returned.
+ */
+ static bool type(const URIs& uris,
+ const Properties& properties,
+ bool& graph,
+ bool& block,
+ bool& port,
+ bool& is_output);
+
+ virtual void set_uri(const URI& uri) { _uri = uri; }
+
+ /** Get all the properties with a given context. */
+ Properties properties(Resource::Graph ctx) const;
+
+ const URIs& uris() const { return _uris; }
+ const URI& uri() const { return _uri; }
+ const Properties& properties() const { return _properties; }
+ Properties& properties() { return _properties; }
+
+protected:
+ const Atom& set_property(const URI& uri, const Atom& value) const;
+
+ const URIs& _uris;
+
+private:
+ URI _uri;
+ mutable Properties _properties;
+};
+
+} // namespace ingen
+
+#endif // INGEN_RESOURCE_HPP
diff --git a/include/ingen/Serialiser.hpp b/include/ingen/Serialiser.hpp
new file mode 100644
index 00000000..1ac5c151
--- /dev/null
+++ b/include/ingen/Serialiser.hpp
@@ -0,0 +1,106 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_SERIALISER_HPP
+#define INGEN_SERIALISER_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "sord/sordmm.hpp"
+
+#include <string>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+
+class Arc;
+class Node;
+class URI;
+class World;
+
+/**
+ Serialiser for writing graphs to Turtle files or strings.
+
+ @ingroup Ingen
+*/
+class INGEN_API Serialiser
+{
+public:
+ explicit Serialiser(World& world);
+
+ virtual ~Serialiser();
+
+ /** Write a graph and all its contents as a complete bundle. */
+ virtual void write_bundle(const SPtr<const Node>& graph,
+ const URI& uri);
+
+ /** Begin a serialization to a string.
+ *
+ * This must be called before any serializing methods.
+ *
+ * The results of the serialization will be returned by the finish() method after
+ * the desired objects have been serialised.
+ *
+ * All serialized paths will have the root path chopped from their prefix
+ * (therefore all serialized paths must be descendants of the root)
+ */
+ virtual void start_to_string(const Raul::Path& root,
+ const URI& base_uri);
+
+ /** Begin a serialization to a file.
+ *
+ * This must be called before any serializing methods.
+ *
+ * All serialized paths will have the root path chopped from their prefix
+ * (therefore all serialized paths must be descendants of the root)
+ */
+ virtual void start_to_file(const Raul::Path& root,
+ const FilePath& filename);
+
+ /** Serialize an object (graph, block, or port).
+ *
+ * @throw std::logic_error
+ */
+ virtual void serialise(const SPtr<const Node>& object,
+ Property::Graph context = Property::Graph::DEFAULT);
+
+ /** Serialize an arc.
+ *
+ * @throw std::logic_error
+ */
+ virtual void serialise_arc(const Sord::Node& parent,
+ const SPtr<const Arc>& arc);
+
+ /** Finish serialization.
+ *
+ * If this is a file serialization, this must be called to finish and close
+ * the output file, and the empty string is returned.
+ *
+ * If this is a string serialization, the serialized result is returned.
+ */
+ virtual std::string finish();
+
+private:
+ struct Impl;
+ UPtr<Impl> me;
+};
+
+} // namespace ingen
+
+#endif // INGEN_SERIALISER_HPP
diff --git a/include/ingen/SocketReader.hpp b/include/ingen/SocketReader.hpp
new file mode 100644
index 00000000..22a0f4aa
--- /dev/null
+++ b/include/ingen/SocketReader.hpp
@@ -0,0 +1,85 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_SOCKET_READER_HPP
+#define INGEN_SOCKET_READER_HPP
+
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "serd/serd.h"
+#include "sord/sord.h"
+
+#include <thread>
+
+namespace Raul { class Socket; }
+
+namespace ingen {
+
+class Interface;
+class World;
+
+/** Calls Interface methods based on Turtle messages received via socket. */
+class INGEN_API SocketReader
+{
+public:
+ SocketReader(World& world,
+ Interface& iface,
+ SPtr<Raul::Socket> sock);
+
+ virtual ~SocketReader();
+
+protected:
+ virtual void on_hangup() {}
+
+private:
+ /// Serd source function for reading from socket
+ static size_t c_recv(void* buf, size_t size, size_t nmemb, void* stream);
+
+ /// Serd error function for getting socket error status
+ static int c_err(void* stream);
+
+ void run();
+
+ static SerdStatus set_base_uri(SocketReader* iface,
+ const SerdNode* uri_node);
+
+ static SerdStatus set_prefix(SocketReader* iface,
+ const SerdNode* name,
+ const SerdNode* uri_node);
+
+ static SerdStatus write_statement(SocketReader* iface,
+ SerdStatementFlags flags,
+ const SerdNode* graph,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const SerdNode* object,
+ const SerdNode* object_datatype,
+ const SerdNode* object_lang);
+
+ World& _world;
+ Interface& _iface;
+ SerdEnv* _env;
+ SordInserter* _inserter;
+ SordNode* _msg_node;
+ SPtr<Raul::Socket> _socket;
+ int _socket_error;
+ bool _exit_flag;
+ std::thread _thread;
+};
+
+} // namespace ingen
+
+#endif // INGEN_SOCKET_READER_HPP
diff --git a/include/ingen/SocketWriter.hpp b/include/ingen/SocketWriter.hpp
new file mode 100644
index 00000000..229f7b50
--- /dev/null
+++ b/include/ingen/SocketWriter.hpp
@@ -0,0 +1,57 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-2015 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_SOCKET_WRITER_HPP
+#define INGEN_SOCKET_WRITER_HPP
+
+#include "ingen/Message.hpp"
+#include "ingen/TurtleWriter.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <cstddef>
+
+namespace Raul {
+class Socket;
+} // namespace Raul
+
+namespace ingen {
+
+class URI;
+class URIMap;
+class URIs;
+
+/** An Interface that writes Turtle messages to a socket.
+ */
+class INGEN_API SocketWriter : public TurtleWriter
+{
+public:
+ SocketWriter(URIMap& map,
+ URIs& uris,
+ const URI& uri,
+ SPtr<Raul::Socket> sock);
+
+ void message(const Message& message) override;
+
+ size_t text_sink(const void* buf, size_t len) override;
+
+protected:
+ SPtr<Raul::Socket> _socket;
+};
+
+} // namespace ingen
+
+#endif // INGEN_SOCKET_WRITER_HPP
diff --git a/include/ingen/Status.hpp b/include/ingen/Status.hpp
new file mode 100644
index 00000000..c4ffd4c9
--- /dev/null
+++ b/include/ingen/Status.hpp
@@ -0,0 +1,92 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_STATUS_HPP
+#define INGEN_STATUS_HPP
+
+namespace ingen {
+
+enum class Status {
+ SUCCESS,
+ FAILURE,
+
+ BAD_INDEX,
+ BAD_OBJECT_TYPE,
+ BAD_REQUEST,
+ BAD_URI,
+ BAD_VALUE_TYPE,
+ BAD_VALUE,
+ CLIENT_NOT_FOUND,
+ CREATION_FAILED,
+ DIRECTION_MISMATCH,
+ EXISTS,
+ INTERNAL_ERROR,
+ INVALID_PARENT,
+ INVALID_POLY,
+ NOT_DELETABLE,
+ NOT_FOUND,
+ NOT_MOVABLE,
+ NOT_PREPARED,
+ NO_SPACE,
+ PARENT_DIFFERS,
+ PARENT_NOT_FOUND,
+ PROTOTYPE_NOT_FOUND,
+ PORT_NOT_FOUND,
+ TYPE_MISMATCH,
+ UNKNOWN_TYPE,
+ COMPILATION_FAILED
+};
+
+static inline const char*
+ingen_status_string(Status st)
+{
+ switch (st) {
+ case Status::SUCCESS: return "Success";
+ case Status::FAILURE: return "Failure";
+
+ case Status::BAD_INDEX: return "Invalid index";
+ case Status::BAD_OBJECT_TYPE: return "Invalid object type";
+ case Status::BAD_REQUEST: return "Invalid request";
+ case Status::BAD_URI: return "Invalid URI";
+ case Status::BAD_VALUE_TYPE: return "Invalid value type";
+ case Status::BAD_VALUE: return "Invalid value";
+ case Status::CLIENT_NOT_FOUND: return "Client not found";
+ case Status::CREATION_FAILED: return "Creation failed";
+ case Status::DIRECTION_MISMATCH: return "Direction mismatch";
+ case Status::EXISTS: return "Object exists";
+ case Status::INTERNAL_ERROR: return "Internal error";
+ case Status::INVALID_PARENT: return "Invalid parent";
+ case Status::INVALID_POLY: return "Invalid polyphony";
+ case Status::NOT_DELETABLE: return "Object not deletable";
+ case Status::NOT_FOUND: return "Object not found";
+ case Status::NOT_MOVABLE: return "Object not movable";
+ case Status::NOT_PREPARED: return "Not prepared";
+ case Status::NO_SPACE: return "Insufficient space";
+ case Status::PARENT_DIFFERS: return "Parent differs";
+ case Status::PARENT_NOT_FOUND: return "Parent not found";
+ case Status::PROTOTYPE_NOT_FOUND: return "Prototype not found";
+ case Status::PORT_NOT_FOUND: return "Port not found";
+ case Status::TYPE_MISMATCH: return "Type mismatch";
+ case Status::UNKNOWN_TYPE: return "Unknown type";
+ case Status::COMPILATION_FAILED: return "Graph compilation failed";
+ }
+
+ return "Unknown error";
+}
+
+} // namespace ingen
+
+#endif // INGEN_STATUS_HPP
diff --git a/include/ingen/Store.hpp b/include/ingen/Store.hpp
new file mode 100644
index 00000000..1aa90936
--- /dev/null
+++ b/include/ingen/Store.hpp
@@ -0,0 +1,86 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_STORE_HPP
+#define INGEN_STORE_HPP
+
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Deletable.hpp"
+#include "raul/Noncopyable.hpp"
+#include "raul/Path.hpp"
+
+#include <map>
+#include <mutex>
+#include <utility>
+
+namespace Raul { class Symbol; }
+
+namespace ingen {
+
+class Node;
+
+/** Store of objects in the graph hierarchy.
+ * @ingroup IngenShared
+ */
+class INGEN_API Store : public Raul::Noncopyable
+ , public Raul::Deletable
+ , public std::map< const Raul::Path, SPtr<Node> > {
+public:
+ void add(Node* o);
+
+ Node* get(const Raul::Path& path) {
+ const iterator i = find(path);
+ return (i == end()) ? nullptr : i->second.get();
+ }
+
+ using const_range = std::pair<const_iterator, const_iterator>;
+ using Objects = std::map<Raul::Path, SPtr<Node>>;
+ using Mutex = std::recursive_mutex;
+
+ iterator find_descendants_end(Store::iterator parent);
+ const_iterator find_descendants_end(Store::const_iterator parent) const;
+
+ const_range children_range(const SPtr<const Node>& o) const;
+
+ /** Remove the object at `top` and all its children from the store.
+ *
+ * @param top Iterator to first (topmost parent) object to remove.
+ *
+ * @param removed Filled with all the removed objects. Note this may be
+ * many objects since any children will be removed as well.
+ */
+ void remove(iterator top, Objects& removed);
+
+ /** Rename (move) the object at `top` to `new_path`.
+ *
+ * Note this invalidates `i`.
+ */
+ void rename(iterator top, const Raul::Path& new_path);
+
+ unsigned child_name_offset(const Raul::Path& parent,
+ const Raul::Symbol& symbol,
+ bool allow_zero=true) const;
+
+ Mutex& mutex() { return _mutex; }
+
+private:
+ Mutex _mutex;
+};
+
+} // namespace ingen
+
+#endif // INGEN_STORE_HPP
diff --git a/include/ingen/StreamWriter.hpp b/include/ingen/StreamWriter.hpp
new file mode 100644
index 00000000..620497f8
--- /dev/null
+++ b/include/ingen/StreamWriter.hpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-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/>.
+*/
+
+#ifndef INGEN_STREAMWRITER_HPP
+#define INGEN_STREAMWRITER_HPP
+
+#include "ingen/ColorContext.hpp"
+#include "ingen/TurtleWriter.hpp"
+#include "ingen/ingen.h"
+
+#include <cstdio>
+
+namespace ingen {
+
+class URI;
+class URIMap;
+class URIs;
+
+/** An Interface that writes Turtle messages to a stream.
+ */
+class INGEN_API StreamWriter : public TurtleWriter
+{
+public:
+ StreamWriter(URIMap& map,
+ URIs& uris,
+ const URI& uri,
+ FILE* stream,
+ ColorContext::Color color);
+
+ size_t text_sink(const void* buf, size_t len) override;
+
+protected:
+ FILE* _stream;
+ ColorContext::Color _color;
+};
+
+} // namespace ingen
+
+#endif // INGEN_STREAMWRITER_HPP
diff --git a/include/ingen/Tee.hpp b/include/ingen/Tee.hpp
new file mode 100644
index 00000000..b13b9e95
--- /dev/null
+++ b/include/ingen/Tee.hpp
@@ -0,0 +1,63 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_ENGINE_TEE_HPP
+#define INGEN_ENGINE_TEE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/types.hpp"
+
+#include <cstddef>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace ingen {
+
+/** Interface that forwards all calls to several sinks. */
+class Tee : public Interface
+{
+public:
+ using Sinks = std::vector<SPtr<Interface>>;
+
+ explicit Tee(Sinks sinks) : _sinks(std::move(sinks)) {}
+
+ SPtr<Interface> respondee() const override {
+ return _sinks.front()->respondee();
+ }
+
+ void set_respondee(const SPtr<Interface>& respondee) override {
+ _sinks.front()->set_respondee(respondee);
+ }
+
+ void message(const Message& message) override {
+ std::lock_guard<std::mutex> lock(_sinks_mutex);
+ for (const auto& s : _sinks) {
+ s->message(message);
+ }
+ }
+
+ URI uri() const override { return URI("ingen:/tee"); }
+
+private:
+ std::mutex _sinks_mutex;
+ Sinks _sinks;
+};
+
+} // namespace ingen
+
+#endif // INGEN_ENGINE_TEE_HPP
diff --git a/include/ingen/TurtleWriter.hpp b/include/ingen/TurtleWriter.hpp
new file mode 100644
index 00000000..9c88be2e
--- /dev/null
+++ b/include/ingen/TurtleWriter.hpp
@@ -0,0 +1,69 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-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/>.
+*/
+
+#ifndef INGEN_TURTLE_WRITER_HPP
+#define INGEN_TURTLE_WRITER_HPP
+
+#include "ingen/AtomSink.hpp"
+#include "ingen/AtomWriter.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/ingen.h"
+#include "lv2/atom/atom.h"
+#include "serd/serd.h"
+#include "sratom/sratom.h"
+
+#include <cstddef>
+#include <cstdint>
+
+namespace ingen {
+
+class URIMap;
+class URIs;
+
+/** An Interface that writes Turtle messages to a sink method.
+ *
+ * Derived classes must implement text_sink() to do something with the
+ * serialized messages.
+ */
+class INGEN_API TurtleWriter : public AtomWriter, public AtomSink
+{
+public:
+ TurtleWriter(URIMap& map, URIs& uris, URI uri);
+
+ ~TurtleWriter() override;
+
+ /** AtomSink method which receives calls serialized to LV2 atoms. */
+ bool write(const LV2_Atom* msg, int32_t default_id=0) override;
+
+ /** Pure virtual text sink which receives calls serialized to Turtle. */
+ virtual size_t text_sink(const void* buf, size_t len) = 0;
+
+ URI uri() const override { return _uri; }
+
+protected:
+ URIMap& _map;
+ Sratom* _sratom;
+ SerdNode _base;
+ SerdURI _base_uri;
+ SerdEnv* _env;
+ SerdWriter* _writer;
+ URI _uri;
+ bool _wrote_prefixes;
+};
+
+} // namespace ingen
+
+#endif // INGEN_TURTLE_WRITER_HPP
diff --git a/include/ingen/URI.hpp b/include/ingen/URI.hpp
new file mode 100644
index 00000000..78577d90
--- /dev/null
+++ b/include/ingen/URI.hpp
@@ -0,0 +1,175 @@
+/*
+ This file is part of Ingen.
+ Copyright 2018 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_URI_HPP
+#define INGEN_URI_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/ingen.h"
+#include "serd/serd.h"
+#include "sord/sordmm.hpp"
+
+#include <boost/utility/string_view.hpp>
+
+#include <cstddef>
+#include <cstdint>
+#include <ostream>
+#include <string>
+
+namespace ingen {
+
+class INGEN_API URI
+{
+public:
+ using Chunk = boost::string_view;
+
+ URI();
+ explicit URI(const std::string& str);
+ explicit URI(const char* str);
+ URI(const std::string& str, const URI& base);
+ URI(const Sord::Node& node);
+ URI(SerdNode node);
+ explicit URI(const FilePath& path);
+
+ URI(const URI& uri);
+ URI& operator=(const URI& uri);
+
+ URI(URI&& uri) noexcept;
+ URI& operator=(URI&& uri) noexcept;
+
+ ~URI();
+
+ URI make_relative(const URI& base) const;
+
+ bool empty() const { return !_node.buf; }
+
+ std::string string() const { return std::string(c_str(), _node.n_bytes); }
+ size_t length() const { return _node.n_bytes; }
+
+ const char* c_str() const
+ {
+ return reinterpret_cast<const char*>(_node.buf);
+ }
+
+ FilePath file_path() const {
+ return scheme() == "file" ? FilePath(path()) : FilePath();
+ }
+
+ operator std::string() const { return string(); }
+
+ const char* begin() const
+ {
+ return reinterpret_cast<const char*>(_node.buf);
+ }
+
+ const char* end() const
+ {
+ return reinterpret_cast<const char*>(_node.buf) + _node.n_bytes;
+ }
+
+ Chunk scheme() const { return make_chunk(_uri.scheme); }
+ Chunk authority() const { return make_chunk(_uri.authority); }
+ Chunk path() const { return make_chunk(_uri.path); }
+ Chunk query() const { return make_chunk(_uri.query); }
+ Chunk fragment() const { return make_chunk(_uri.fragment); }
+
+ static bool is_valid(const char* str)
+ {
+ return serd_uri_string_has_scheme(
+ reinterpret_cast<const uint8_t*>(str));
+ }
+
+ static bool is_valid(const std::string& str)
+ {
+ return is_valid(str.c_str());
+ }
+
+private:
+ URI(SerdNode node, SerdURI uri);
+
+ static Chunk make_chunk(const SerdChunk& chunk) {
+ return Chunk(reinterpret_cast<const char*>(chunk.buf), chunk.len);
+ }
+
+ SerdURI _uri;
+ SerdNode _node;
+};
+
+inline bool operator==(const URI& lhs, const URI& rhs)
+{
+ return lhs.string() == rhs.string();
+}
+
+inline bool operator==(const URI& lhs, const std::string& rhs)
+{
+ return lhs.string() == rhs;
+}
+
+inline bool operator==(const URI& lhs, const char* rhs)
+{
+ return lhs.string() == rhs;
+}
+
+inline bool operator==(const URI& lhs, const Sord::Node& rhs)
+{
+ return rhs.type() == Sord::Node::URI && lhs.string() == rhs.to_string();
+}
+
+inline bool operator==(const Sord::Node& lhs, const URI& rhs)
+{
+ return rhs == lhs;
+}
+
+inline bool operator!=(const URI& lhs, const URI& rhs)
+{
+ return lhs.string() != rhs.string();
+}
+
+inline bool operator!=(const URI& lhs, const std::string& rhs)
+{
+ return lhs.string() != rhs;
+}
+
+inline bool operator!=(const URI& lhs, const char* rhs)
+{
+ return lhs.string() != rhs;
+}
+
+inline bool operator!=(const URI& lhs, const Sord::Node& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const Sord::Node& lhs, const URI& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator<(const URI& lhs, const URI& rhs)
+{
+ return lhs.string() < rhs.string();
+}
+
+template <typename Char, typename Traits>
+inline std::basic_ostream<Char, Traits>&
+operator<<(std::basic_ostream<Char, Traits>& os, const URI& uri)
+{
+ return os << uri.string();
+}
+
+} // namespace ingen
+
+#endif // INGEN_URI_HPP
diff --git a/include/ingen/URIMap.hpp b/include/ingen/URIMap.hpp
new file mode 100644
index 00000000..7efef8d1
--- /dev/null
+++ b/include/ingen/URIMap.hpp
@@ -0,0 +1,96 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_URIMAP_HPP
+#define INGEN_URIMAP_HPP
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/core/lv2.h"
+#include "lv2/urid/urid.h"
+#include "raul/Noncopyable.hpp"
+
+#include <cstdint>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace ingen {
+
+class Log;
+class Node;
+class World;
+
+/** URI to integer map and implementation of LV2 URID extension.
+ * @ingroup IngenShared
+ */
+class INGEN_API URIMap : public Raul::Noncopyable {
+public:
+ URIMap(Log& log, LV2_URID_Map* map, LV2_URID_Unmap* unmap);
+
+ uint32_t map_uri(const char* uri);
+ uint32_t map_uri(const std::string& uri) { return map_uri(uri.c_str()); }
+ const char* unmap_uri(uint32_t urid) const;
+
+ class Feature : public LV2Features::Feature {
+ public:
+ Feature(const char* URI, void* data) : _feature{URI, data} {}
+
+ const char* uri() const override { return _feature.URI; }
+
+ SPtr<LV2_Feature> feature(World&, Node*) override {
+ return SPtr<LV2_Feature>(&_feature, NullDeleter<LV2_Feature>);
+ }
+
+ private:
+ LV2_Feature _feature;
+ };
+
+ struct URIDMapFeature : public Feature {
+ URIDMapFeature(URIMap* map, LV2_URID_Map* impl, Log& log);
+ LV2_URID map(const char* uri);
+ static LV2_URID default_map(LV2_URID_Map_Handle h, const char* c_uri);
+ LV2_URID_Map urid_map;
+ Log& log;
+ };
+
+ struct URIDUnmapFeature : public Feature {
+ URIDUnmapFeature(URIMap* map, LV2_URID_Unmap* impl);
+ const char* unmap(LV2_URID urid) const;
+ static const char* default_unmap(LV2_URID_Map_Handle h, LV2_URID urid);
+ LV2_URID_Unmap urid_unmap;
+ };
+
+ SPtr<URIDMapFeature> urid_map_feature() { return _urid_map_feature; }
+ SPtr<URIDUnmapFeature> urid_unmap_feature() { return _urid_unmap_feature; }
+
+private:
+ friend struct URIDMapFeature;
+ friend struct URIDUnMapFeature;
+
+ SPtr<URIDMapFeature> _urid_map_feature;
+ SPtr<URIDUnmapFeature> _urid_unmap_feature;
+
+ std::mutex _mutex;
+ std::unordered_map<std::string, LV2_URID> _map;
+ std::vector<std::string> _unmap;
+};
+
+} // namespace ingen
+
+#endif // INGEN_URIMAP_HPP
diff --git a/include/ingen/URIs.hpp b/include/ingen/URIs.hpp
new file mode 100644
index 00000000..9d4b2818
--- /dev/null
+++ b/include/ingen/URIs.hpp
@@ -0,0 +1,241 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_URIS_HPP
+#define INGEN_URIS_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/ingen.h"
+#include "lilv/lilv.h"
+#include "lv2/urid/urid.h"
+#include "raul/Noncopyable.hpp"
+
+namespace ingen {
+
+class Forge;
+class URIMap;
+
+/** Frequently used interned URIs.
+ *
+ * This class initially maps all the special URIs used throughout the code
+ * using the URIMap so they can be used quickly with the performance of
+ * integers, but still be dynamic.
+ *
+ * @ingroup ingen
+ */
+class INGEN_API URIs : public Raul::Noncopyable {
+public:
+ URIs(ingen::Forge& forge, URIMap* map, LilvWorld* lworld);
+
+ struct Quark : public URI {
+ Quark(ingen::Forge& forge,
+ URIMap* map,
+ LilvWorld* lworld,
+ const char* str);
+
+ Quark(const Quark& copy);
+
+ ~Quark();
+
+ const Atom& urid_atom() const { return _urid_atom; }
+ const Atom& uri_atom() const { return _uri_atom; }
+
+ LV2_URID urid() const { return _urid_atom.get<LV2_URID>(); }
+ const LilvNode* node() const { return _lilv_node; }
+
+ operator LV2_URID() const { return _urid_atom.get<LV2_URID>(); }
+ explicit operator Atom() const { return _urid_atom; }
+ operator const LilvNode*() const { return _lilv_node; }
+
+ private:
+ Atom _urid_atom;
+ Atom _uri_atom;
+ LilvNode* _lilv_node;
+ };
+
+ ingen::Forge& forge;
+
+ const Quark atom_AtomPort;
+ const Quark atom_Bool;
+ const Quark atom_Chunk;
+ const Quark atom_Float;
+ const Quark atom_Int;
+ const Quark atom_Object;
+ const Quark atom_Path;
+ const Quark atom_Sequence;
+ const Quark atom_Sound;
+ const Quark atom_String;
+ const Quark atom_URI;
+ const Quark atom_URID;
+ const Quark atom_bufferType;
+ const Quark atom_eventTransfer;
+ const Quark atom_supports;
+ const Quark bufsz_maxBlockLength;
+ const Quark bufsz_minBlockLength;
+ const Quark bufsz_sequenceSize;
+ const Quark doap_name;
+ const Quark ingen_Arc;
+ const Quark ingen_Block;
+ const Quark ingen_BundleEnd;
+ const Quark ingen_BundleStart;
+ const Quark ingen_Graph;
+ const Quark ingen_GraphPrototype;
+ const Quark ingen_Internal;
+ const Quark ingen_Redo;
+ const Quark ingen_Undo;
+ const Quark ingen_activity;
+ const Quark ingen_arc;
+ const Quark ingen_block;
+ const Quark ingen_broadcast;
+ const Quark ingen_canvasX;
+ const Quark ingen_canvasY;
+ const Quark ingen_enabled;
+ const Quark ingen_externalContext;
+ const Quark ingen_file;
+ const Quark ingen_head;
+ const Quark ingen_incidentTo;
+ const Quark ingen_internalContext;
+ const Quark ingen_loadedBundle;
+ const Quark ingen_maxRunLoad;
+ const Quark ingen_meanRunLoad;
+ const Quark ingen_minRunLoad;
+ const Quark ingen_numThreads;
+ const Quark ingen_polyphonic;
+ const Quark ingen_polyphony;
+ const Quark ingen_prototype;
+ const Quark ingen_sprungLayout;
+ const Quark ingen_tail;
+ const Quark ingen_uiEmbedded;
+ const Quark ingen_value;
+ const Quark log_Error;
+ const Quark log_Note;
+ const Quark log_Trace;
+ const Quark log_Warning;
+ const Quark lv2_AudioPort;
+ const Quark lv2_CVPort;
+ const Quark lv2_ControlPort;
+ const Quark lv2_InputPort;
+ const Quark lv2_OutputPort;
+ const Quark lv2_Plugin;
+ const Quark lv2_appliesTo;
+ const Quark lv2_binary;
+ const Quark lv2_connectionOptional;
+ const Quark lv2_control;
+ const Quark lv2_default;
+ const Quark lv2_designation;
+ const Quark lv2_enumeration;
+ const Quark lv2_extensionData;
+ const Quark lv2_index;
+ const Quark lv2_integer;
+ const Quark lv2_maximum;
+ const Quark lv2_microVersion;
+ const Quark lv2_minimum;
+ const Quark lv2_minorVersion;
+ const Quark lv2_name;
+ const Quark lv2_port;
+ const Quark lv2_portProperty;
+ const Quark lv2_prototype;
+ const Quark lv2_sampleRate;
+ const Quark lv2_scalePoint;
+ const Quark lv2_symbol;
+ const Quark lv2_toggled;
+ const Quark midi_Bender;
+ const Quark midi_ChannelPressure;
+ const Quark midi_Controller;
+ const Quark midi_MidiEvent;
+ const Quark midi_NoteOn;
+ const Quark midi_binding;
+ const Quark midi_controllerNumber;
+ const Quark midi_noteNumber;
+ const Quark morph_AutoMorphPort;
+ const Quark morph_MorphPort;
+ const Quark morph_currentType;
+ const Quark morph_supportsType;
+ const Quark opt_interface;
+ const Quark param_sampleRate;
+ const Quark patch_Copy;
+ const Quark patch_Delete;
+ const Quark patch_Get;
+ const Quark patch_Message;
+ const Quark patch_Move;
+ const Quark patch_Patch;
+ const Quark patch_Put;
+ const Quark patch_Response;
+ const Quark patch_Set;
+ const Quark patch_add;
+ const Quark patch_body;
+ const Quark patch_context;
+ const Quark patch_destination;
+ const Quark patch_property;
+ const Quark patch_remove;
+ const Quark patch_sequenceNumber;
+ const Quark patch_subject;
+ const Quark patch_value;
+ const Quark patch_wildcard;
+ const Quark pprops_logarithmic;
+ const Quark pset_Preset;
+ const Quark pset_preset;
+ const Quark rdf_type;
+ const Quark rdfs_Class;
+ const Quark rdfs_label;
+ const Quark rdfs_seeAlso;
+ const Quark rsz_minimumSize;
+ const Quark state_loadDefaultState;
+ const Quark state_state;
+ const Quark time_Position;
+ const Quark time_bar;
+ const Quark time_barBeat;
+ const Quark time_beatUnit;
+ const Quark time_beatsPerBar;
+ const Quark time_beatsPerMinute;
+ const Quark time_frame;
+ const Quark time_speed;
+ const Quark work_schedule;
+};
+
+inline bool
+operator==(const URIs::Quark& lhs, const Atom& rhs)
+{
+ if (rhs.type() == lhs.urid_atom().type()) {
+ return rhs == lhs.urid_atom();
+ } else if (rhs.type() == lhs.uri_atom().type()) {
+ return rhs == lhs.uri_atom();
+ }
+ return false;
+}
+
+inline bool
+operator==(const Atom& lhs, const URIs::Quark& rhs)
+{
+ return rhs == lhs;
+}
+
+inline bool
+operator!=(const Atom& lhs, const URIs::Quark& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool
+operator!=(const URIs::Quark& lhs, const Atom& rhs)
+{
+ return !(lhs == rhs);
+}
+
+} // namespace ingen
+
+#endif // INGEN_URIS_HPP
diff --git a/include/ingen/World.hpp b/include/ingen/World.hpp
new file mode 100644
index 00000000..e06c0a18
--- /dev/null
+++ b/include/ingen/World.hpp
@@ -0,0 +1,151 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_WORLD_HPP
+#define INGEN_WORLD_HPP
+
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/log/log.h"
+#include "lv2/urid/urid.h"
+#include "raul/Noncopyable.hpp"
+
+#include <mutex>
+#include <string>
+
+using LilvWorld = struct LilvWorldImpl;
+
+namespace Sord { class World; }
+
+namespace ingen {
+
+class Configuration;
+class EngineBase;
+class Forge;
+class Interface;
+class LV2Features;
+class Log;
+class Parser;
+class Serialiser;
+class Store;
+class URI;
+class URIMap;
+class URIs;
+
+/** The "world" all Ingen modules share.
+ *
+ * This is the root to which all components of Ingen are connected. It
+ * contains all necessary shared data (including the world for libraries like
+ * Sord and Lilv) and holds references to components.
+ *
+ * Some functionality in Ingen is implemented in dynamically loaded modules,
+ * which are loaded using this interface. When loaded, those modules add
+ * facilities to the World which can then be used throughout the code.
+ *
+ * The world is used in any process which uses the Ingen as a library, both
+ * client and server (e.g. the world may not actually contain an Engine, since
+ * it maybe running in another process or even on a different machine).
+ *
+ * @ingroup IngenShared
+ */
+class INGEN_API World : public Raul::Noncopyable {
+public:
+ /** Construct a new Ingen world.
+ * @param map LV2 URID map implementation, or null to use internal.
+ * @param unmap LV2 URID unmap implementation, or null to use internal.
+ * @param log LV2 log implementation, or null to use internal.
+ */
+ World(LV2_URID_Map* map, LV2_URID_Unmap* unmap, LV2_Log_Log* log);
+
+ virtual ~World();
+
+ /** Load configuration from files and command line.
+ * @param argc Argument count (as in C main())
+ * @param argv Argument vector (as in C main())
+ */
+ virtual void load_configuration(int& argc, char**& argv);
+
+ /** Load an Ingen module by name (e.g. "server", "gui", etc.)
+ * @return True on success.
+ */
+ virtual bool load_module(const char* name);
+
+ /** Run a loaded module (modules that "run" only, e.g. gui).
+ * @return True on success.
+ */
+ virtual bool run_module(const char* name);
+
+ /** A function to create a new remote Interface. */
+ using InterfaceFactory =
+ SPtr<Interface> (*)(World& world,
+ const URI& engine_uri,
+ const SPtr<Interface>& respondee);
+
+ /** Register an InterfaceFactory (for module implementations). */
+ virtual void add_interface_factory(const std::string& scheme,
+ InterfaceFactory factory);
+
+ /** Return a new Interface to control a server.
+ * @param engine_uri The URI of the possibly remote server to control.
+ * @param respondee The Interface that will receive responses to commands
+ * and broadcasts, if applicable.
+ */
+ virtual SPtr<Interface> new_interface(const URI& engine_uri,
+ const SPtr<Interface>& respondee);
+
+ /** Run a script. */
+ virtual bool run(const std::string& mime_type,
+ const std::string& filename);
+
+ virtual void set_engine(const SPtr<EngineBase>& e);
+ virtual void set_interface(const SPtr<Interface>& i);
+ virtual void set_store(const SPtr<Store>& s);
+
+ virtual SPtr<EngineBase> engine();
+ virtual SPtr<Interface> interface();
+ virtual SPtr<Parser> parser();
+ virtual SPtr<Serialiser> serialiser();
+ virtual SPtr<Store> store();
+
+ virtual int& argc();
+ virtual char**& argv();
+ virtual Configuration& conf();
+
+ /** Lock for rdf_world() or lilv_world(). */
+ virtual std::mutex& rdf_mutex();
+
+ virtual Sord::World* rdf_world();
+ virtual LilvWorld* lilv_world();
+
+ virtual LV2Features& lv2_features();
+ virtual ingen::Forge& forge();
+ virtual URIMap& uri_map();
+ virtual URIs& uris();
+
+ virtual void set_jack_uuid(const std::string& uuid);
+ virtual std::string jack_uuid();
+
+ virtual Log& log();
+
+private:
+ class Impl;
+
+ Impl* _impl;
+};
+
+} // namespace ingen
+
+#endif // INGEN_WORLD_HPP
diff --git a/include/ingen/client/ArcModel.hpp b/include/ingen/client/ArcModel.hpp
new file mode 100644
index 00000000..e42dd7bd
--- /dev/null
+++ b/include/ingen/client/ArcModel.hpp
@@ -0,0 +1,67 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_ARCMODEL_HPP
+#define INGEN_CLIENT_ARCMODEL_HPP
+
+#include "ingen/Arc.hpp"
+#include "ingen/client/PortModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+
+#include <cassert>
+
+namespace ingen {
+namespace client {
+
+class ClientStore;
+
+/** Class to represent a port->port connections in the engine.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ArcModel : public Arc
+{
+public:
+ SPtr<PortModel> tail() const { return _tail; }
+ SPtr<PortModel> head() const { return _head; }
+
+ const Raul::Path& tail_path() const override { return _tail->path(); }
+ const Raul::Path& head_path() const override { return _head->path(); }
+
+private:
+ friend class ClientStore;
+
+ ArcModel(SPtr<PortModel> tail, SPtr<PortModel> head)
+ : _tail(std::move(tail))
+ , _head(std::move(head))
+ {
+ assert(_tail);
+ assert(_head);
+ assert(_tail->parent());
+ assert(_head->parent());
+ assert(_tail->path() != _head->path());
+ }
+
+ const SPtr<PortModel> _tail;
+ const SPtr<PortModel> _head;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_ARCMODEL_HPP
diff --git a/include/ingen/client/BlockModel.hpp b/include/ingen/client/BlockModel.hpp
new file mode 100644
index 00000000..d003b7d1
--- /dev/null
+++ b/include/ingen/client/BlockModel.hpp
@@ -0,0 +1,117 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_BLOCKMODEL_HPP
+#define INGEN_CLIENT_BLOCKMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/client/PluginModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+
+class URIs;
+
+namespace client {
+
+class PortModel;
+
+/** Block model class, used by the client to store engine's state.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API BlockModel : public ObjectModel
+{
+public:
+ BlockModel(const BlockModel& copy);
+ virtual ~BlockModel();
+
+ GraphType graph_type() const override { return Node::GraphType::BLOCK; }
+
+ using Ports = std::vector<SPtr<const PortModel>>;
+
+ SPtr<const PortModel> get_port(const Raul::Symbol& symbol) const;
+ SPtr<const PortModel> get_port(uint32_t index) const;
+
+ Node* port(uint32_t index) const override;
+
+ const URI& plugin_uri() const { return _plugin_uri; }
+ const Resource* plugin() const override { return _plugin.get(); }
+ Resource* plugin() { return _plugin.get(); }
+ SPtr<PluginModel> plugin_model() const { return _plugin; }
+ uint32_t num_ports() const override { return _ports.size(); }
+ const Ports& ports() const { return _ports; }
+
+ void default_port_value_range(const SPtr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ void port_value_range(const SPtr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ std::string label() const;
+ std::string port_label(const SPtr<const PortModel>& port) const;
+
+ // Signals
+ INGEN_SIGNAL(new_port, void, SPtr<const PortModel>)
+ INGEN_SIGNAL(removed_port, void, SPtr<const PortModel>)
+
+protected:
+ friend class ClientStore;
+
+ BlockModel(URIs& uris, URI plugin_uri, const Raul::Path& path);
+
+ BlockModel(URIs& uris,
+ const SPtr<PluginModel>& plugin,
+ const Raul::Path& path);
+
+ explicit BlockModel(const Raul::Path& path);
+
+ void add_child(const SPtr<ObjectModel>& c) override;
+ bool remove_child(const SPtr<ObjectModel>& c) override;
+ void add_port(const SPtr<PortModel>& pm);
+ void remove_port(const SPtr<PortModel>& port);
+ void remove_port(const Raul::Path& port_path);
+ void set(const SPtr<ObjectModel>& model) override;
+
+ virtual void clear();
+
+ Ports _ports; ///< Vector of ports
+ URI _plugin_uri; ///< Plugin URI (if PluginModel is unknown)
+ SPtr<PluginModel> _plugin; ///< The plugin this block is an instance of
+
+private:
+ mutable uint32_t _num_values; ///< Size of _min_values and _max_values
+ mutable float* _min_values; ///< Port min values (cached for LV2)
+ mutable float* _max_values; ///< Port max values (cached for LV2)
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_BLOCKMODEL_HPP
diff --git a/include/ingen/client/ClientStore.hpp b/include/ingen/client/ClientStore.hpp
new file mode 100644
index 00000000..54eaf373
--- /dev/null
+++ b/include/ingen/client/ClientStore.hpp
@@ -0,0 +1,132 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_CLIENT_CLIENTSTORE_HPP
+#define INGEN_CLIENT_CLIENTSTORE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/Store.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+
+#include <map>
+
+namespace Raul {
+class Path;
+} // namespace Raul
+
+namespace ingen {
+
+class Atom;
+class Log;
+class Node;
+class Resource;
+class URIs;
+
+namespace client {
+
+class BlockModel;
+class GraphModel;
+class ObjectModel;
+class PluginModel;
+class PortModel;
+class SigClientInterface;
+
+/** Automatically manages models of objects in the engine.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ClientStore : public Store
+ , public Interface
+ , public INGEN_TRACKABLE {
+public:
+ ClientStore(
+ URIs& uris,
+ Log& log,
+ const SPtr<SigClientInterface>& emitter = SPtr<SigClientInterface>());
+
+ URI uri() const override { return URI("ingen:/clients/store"); }
+
+ SPtr<const ObjectModel> object(const Raul::Path& path) const;
+ SPtr<const PluginModel> plugin(const URI& uri) const;
+ SPtr<const Resource> resource(const URI& uri) const;
+
+ void clear();
+
+ using Plugins = std::map<const URI, SPtr<PluginModel>>;
+
+ SPtr<const Plugins> plugins() const { return _plugins; }
+ SPtr<Plugins> plugins() { return _plugins; }
+ void set_plugins(SPtr<Plugins> p) { _plugins = std::move(p); }
+
+ URIs& uris() { return _uris; }
+
+ void message(const Message& msg) override;
+
+ void operator()(const BundleBegin&) {}
+ void operator()(const BundleEnd&) {}
+ void operator()(const Connect&);
+ void operator()(const Copy&);
+ void operator()(const Del&);
+ void operator()(const Delta&);
+ void operator()(const Disconnect&);
+ void operator()(const DisconnectAll&);
+ void operator()(const Error&) {}
+ void operator()(const Get&) {}
+ void operator()(const Move&);
+ void operator()(const Put&);
+ void operator()(const Redo&) {}
+ void operator()(const Response&) {}
+ void operator()(const SetProperty&);
+ void operator()(const Undo&) {}
+
+ INGEN_SIGNAL(new_object, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(new_plugin, void, SPtr<PluginModel>)
+ INGEN_SIGNAL(plugin_deleted, void, URI)
+
+private:
+ SPtr<ObjectModel> _object(const Raul::Path& path);
+ SPtr<PluginModel> _plugin(const URI& uri);
+ SPtr<PluginModel> _plugin(const Atom& uri);
+ SPtr<Resource> _resource(const URI& uri);
+
+ void add_object(const SPtr<ObjectModel>& object);
+ SPtr<ObjectModel> remove_object(const Raul::Path& path);
+
+ void add_plugin(const SPtr<PluginModel>& pm);
+
+ SPtr<GraphModel> connection_graph(const Raul::Path& tail_path,
+ const Raul::Path& head_path);
+
+ // Slots for SigClientInterface signals
+ bool attempt_connection(const Raul::Path& tail_path,
+ const Raul::Path& head_path);
+
+ URIs& _uris;
+ Log& _log;
+ SPtr<SigClientInterface> _emitter;
+
+ SPtr<Plugins> _plugins; ///< Map, keyed by plugin URI
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_CLIENTSTORE_HPP
diff --git a/include/ingen/client/GraphModel.hpp b/include/ingen/client/GraphModel.hpp
new file mode 100644
index 00000000..2248e7e3
--- /dev/null
+++ b/include/ingen/client/GraphModel.hpp
@@ -0,0 +1,82 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_GRAPHMODEL_HPP
+#define INGEN_CLIENT_GRAPHMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/BlockModel.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <cstdint>
+
+namespace ingen {
+namespace client {
+
+class ArcModel;
+class ClientStore;
+
+/** Client's model of a graph.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API GraphModel : public BlockModel
+{
+public:
+ /* WARNING: Copy constructor creates a shallow copy WRT connections */
+
+ GraphType graph_type() const override { return Node::GraphType::GRAPH; }
+
+ SPtr<ArcModel> get_arc(const ingen::Node* tail,
+ const ingen::Node* head);
+
+ bool enabled() const;
+ bool polyphonic() const;
+ uint32_t internal_poly() const;
+
+ // Signals
+ INGEN_SIGNAL(new_block, void, SPtr<BlockModel>)
+ INGEN_SIGNAL(removed_block, void, SPtr<BlockModel>)
+ INGEN_SIGNAL(new_arc, void, SPtr<ArcModel>)
+ INGEN_SIGNAL(removed_arc, void, SPtr<ArcModel>)
+
+private:
+ friend class ClientStore;
+
+ GraphModel(URIs& uris, const Raul::Path& graph_path)
+ : BlockModel(uris,
+ static_cast<const URI&>(uris.ingen_Graph),
+ graph_path)
+ {
+ }
+
+ void clear() override;
+ void add_child(const SPtr<ObjectModel>& c) override;
+ bool remove_child(const SPtr<ObjectModel>& o) override;
+ void remove_arcs_on(const SPtr<PortModel>& p);
+
+ void add_arc(const SPtr<ArcModel>& arc);
+ void remove_arc(const ingen::Node* tail,
+ const ingen::Node* head);
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_GRAPHMODEL_HPP
diff --git a/include/ingen/client/ObjectModel.hpp b/include/ingen/client/ObjectModel.hpp
new file mode 100644
index 00000000..39729377
--- /dev/null
+++ b/include/ingen/client/ObjectModel.hpp
@@ -0,0 +1,99 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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/>.
+*/
+
+/**
+ @defgroup IngenClient Client-Side Models and Utilities
+*/
+
+#ifndef INGEN_CLIENT_OBJECTMODEL_HPP
+#define INGEN_CLIENT_OBJECTMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+#include "raul/Symbol.hpp"
+
+namespace ingen {
+
+class Atom;
+
+namespace client {
+
+/** Base class for all Node models (BlockModel, GraphModel, PortModel).
+ *
+ * There are no non-const public methods intentionally, models are not allowed
+ * to be manipulated directly by anything (but the Store) because of the
+ * asynchronous nature of engine control. To change something, use the
+ * controller (which the model probably shouldn't have a reference to but oh
+ * well, it reduces Collection Hell) and wait for the result (as a signal
+ * from this Model).
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ObjectModel : public Node
+{
+public:
+ bool is_a(const URIs::Quark& type) const;
+
+ const Atom& get_property(const URI& key) const override;
+
+ void on_property(const URI& uri, const Atom& value) override;
+ void on_property_removed(const URI& uri, const Atom& value) override;
+
+ const Raul::Path& path() const override { return _path; }
+ const Raul::Symbol& symbol() const override { return _symbol; }
+
+ SPtr<ObjectModel> parent() const { return _parent; }
+ bool polyphonic() const;
+
+ Node* graph_parent() const override { return _parent.get(); }
+
+ // Signals
+ INGEN_SIGNAL(new_child, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(removed_child, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(property_removed, void, const URI&, const Atom&)
+ INGEN_SIGNAL(destroyed, void)
+ INGEN_SIGNAL(moved, void)
+
+protected:
+ friend class ClientStore;
+
+ ObjectModel(URIs& uris, const Raul::Path& path);
+ ObjectModel(const ObjectModel& copy);
+
+ void set_path(const Raul::Path& p) override;
+ virtual void set_parent(const SPtr<ObjectModel>& p);
+ virtual void add_child(const SPtr<ObjectModel>& c) {}
+ virtual bool remove_child(const SPtr<ObjectModel>& c) { return true; }
+
+ virtual void set(const SPtr<ObjectModel>& o);
+
+ SPtr<ObjectModel> _parent;
+
+private:
+ Raul::Path _path;
+ Raul::Symbol _symbol;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_OBJECTMODEL_HPP
diff --git a/include/ingen/client/PluginModel.hpp b/include/ingen/client/PluginModel.hpp
new file mode 100644
index 00000000..dbefaf95
--- /dev/null
+++ b/include/ingen/client/PluginModel.hpp
@@ -0,0 +1,127 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_CLIENT_PLUGINMODEL_HPP
+#define INGEN_CLIENT_PLUGINMODEL_HPP
+
+#include "ingen/Forge.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/World.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "raul/Symbol.hpp"
+#include "sord/sordmm.hpp"
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+namespace ingen {
+
+class URIs;
+
+namespace client {
+
+class GraphModel;
+class BlockModel;
+class PluginUI;
+
+/** Model for a plugin available for loading.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PluginModel : public ingen::Resource
+{
+public:
+ PluginModel(URIs& uris,
+ const URI& uri,
+ const Atom& type,
+ const ingen::Properties& properties);
+
+ const Atom& type() const { return _type; }
+
+ URI type_uri() const
+ {
+ return URI(_type.is_valid() ? _uris.forge.str(_type, false)
+ : "http://www.w3.org/2002/07/owl#Nothing");
+ }
+
+ const Atom& get_property(const URI& key) const override;
+
+ Raul::Symbol default_block_symbol() const;
+ std::string human_name() const;
+ std::string port_human_name(uint32_t i) const;
+
+ using ScalePoints = std::map<float, std::string>;
+ ScalePoints port_scale_points(uint32_t i) const;
+
+ using Presets = std::map<URI, std::string>;
+ const Presets& presets() const { return _presets; }
+
+ static LilvWorld* lilv_world() { return _lilv_world; }
+ const LilvPlugin* lilv_plugin() const { return _lilv_plugin; }
+
+ const LilvPort* lilv_port(uint32_t index) const;
+
+ static void set_lilv_world(LilvWorld* world);
+
+ bool has_ui() const;
+
+ SPtr<PluginUI>
+ ui(ingen::World& world, const SPtr<const BlockModel>& block) const;
+
+ std::string documentation(bool html) const;
+ std::string port_documentation(uint32_t index, bool html) const;
+
+ static void set_rdf_world(Sord::World& world) {
+ _rdf_world = &world;
+ }
+
+ static Sord::World* rdf_world() { return _rdf_world; }
+
+ // Signals
+ INGEN_SIGNAL(changed, void)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(preset, void, const URI&, const std::string&)
+
+ bool fetched() const { return _fetched; }
+ void set_fetched(bool f) { _fetched = f; }
+
+protected:
+ friend class ClientStore;
+ void set(const SPtr<PluginModel>& p);
+
+ void add_preset(const URI& uri, const std::string& label);
+
+private:
+ static std::string get_documentation(const LilvNode* subject, bool html);
+
+ static Sord::World* _rdf_world;
+ static LilvWorld* _lilv_world;
+ static const LilvPlugins* _lilv_plugins;
+
+ Atom _type;
+ const LilvPlugin* _lilv_plugin;
+ Presets _presets;
+ bool _fetched;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PLUGINMODEL_HPP
diff --git a/include/ingen/client/PluginUI.hpp b/include/ingen/client/PluginUI.hpp
new file mode 100644
index 00000000..70ff7274
--- /dev/null
+++ b/include/ingen/client/PluginUI.hpp
@@ -0,0 +1,116 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_PLUGINUI_HPP
+#define INGEN_CLIENT_PLUGINUI_HPP
+
+#include "signal.hpp"
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "suil/suil.h"
+
+#include <cstdint>
+#include <set>
+
+namespace ingen {
+
+class Atom;
+class URI;
+class World;
+
+namespace client {
+
+class BlockModel;
+
+/** Custom user interface for a plugin.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PluginUI {
+public:
+ ~PluginUI();
+
+ /** Create a UI for the given block and plugin.
+ *
+ * This does not actually instantiate the UI itself, so signals can be
+ * connected first. The caller should connect to signal_property_changed,
+ * then call instantiate().
+ */
+ static SPtr<PluginUI> create(ingen::World& world,
+ const SPtr<const BlockModel>& block,
+ const LilvPlugin* plugin);
+
+ /** Instantiate the UI.
+ *
+ * If true is returned, instantiation was successfull and the widget can be
+ * obtained with get_widget(). Otherwise, instantiation failed, so there is
+ * no widget and the UI can not be used.
+ */
+ bool instantiate();
+ bool instantiated () { return _instance != nullptr; }
+
+ SuilWidget get_widget();
+
+ void port_event(uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+ bool is_resizable() const;
+
+ /** Signal emitted when the UI sets a property.
+ *
+ * The application must connect to this signal to communicate with the
+ * engine and/or update itself as necessary.
+ */
+ INGEN_SIGNAL(property_changed, void,
+ const URI&, // Subject
+ const URI&, // Predicate
+ const Atom&, // Object
+ Resource::Graph) // Context
+
+ ingen::World& world() const { return _world; }
+ SPtr<const BlockModel> block() const { return _block; }
+
+private:
+ PluginUI(ingen::World& world,
+ SPtr<const BlockModel> block,
+ LilvUIs* uis,
+ const LilvUI* ui,
+ const LilvNode* ui_type);
+
+ ingen::World& _world;
+ SPtr<const BlockModel> _block;
+ SuilInstance* _instance;
+ LilvUIs* _uis;
+ const LilvUI* _ui;
+ LilvNode* _ui_node;
+ LilvNode* _ui_type;
+ std::set<uint32_t> _subscribed_ports;
+
+ static SuilHost* ui_host;
+
+ SPtr<LV2Features::FeatureArray> _features;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PLUGINUI_HPP
diff --git a/include/ingen/client/PortModel.hpp b/include/ingen/client/PortModel.hpp
new file mode 100644
index 00000000..c386dff0
--- /dev/null
+++ b/include/ingen/client/PortModel.hpp
@@ -0,0 +1,97 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_PORTMODEL_HPP
+#define INGEN_CLIENT_PORTMODEL_HPP
+
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/core/lv2.h"
+#include "lv2/port-props/port-props.h"
+
+#include <cstdlib>
+#include <string>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+namespace client {
+
+/** Model of a port.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PortModel : public ObjectModel
+{
+public:
+ enum class Direction { INPUT, OUTPUT };
+
+ GraphType graph_type() const override { return Node::GraphType::PORT; }
+
+ bool supports(const URIs::Quark& value_type) const;
+
+ inline uint32_t index() const { return _index; }
+ inline const Atom& value() const { return get_property(_uris.ingen_value); }
+ inline bool is_input() const { return (_direction == Direction::INPUT); }
+ inline bool is_output() const { return (_direction == Direction::OUTPUT); }
+
+ bool port_property(const URIs::Quark& uri) const;
+
+ bool is_logarithmic() const { return port_property(_uris.pprops_logarithmic); }
+ bool is_enumeration() const { return port_property(_uris.lv2_enumeration); }
+ bool is_integer() const { return port_property(_uris.lv2_integer); }
+ bool is_toggle() const { return port_property(_uris.lv2_toggled); }
+ bool is_numeric() const {
+ return ObjectModel::is_a(_uris.lv2_ControlPort)
+ || ObjectModel::is_a(_uris.lv2_CVPort);
+ }
+ bool is_uri() const;
+
+ inline bool operator==(const PortModel& pm) const { return (path() == pm.path()); }
+
+ void on_property(const URI& uri, const Atom& value) override;
+
+ // Signals
+ INGEN_SIGNAL(value_changed, void, const Atom&)
+ INGEN_SIGNAL(voice_changed, void, uint32_t, const Atom&)
+ INGEN_SIGNAL(activity, void, const Atom&)
+
+private:
+ friend class ClientStore;
+
+ PortModel(URIs& uris,
+ const Raul::Path& path,
+ uint32_t index,
+ Direction dir)
+ : ObjectModel(uris, path)
+ , _index(index)
+ , _direction(dir)
+ {}
+
+ void add_child(const SPtr<ObjectModel>& c) override { throw; }
+ bool remove_child(const SPtr<ObjectModel>& c) override { throw; }
+
+ void set(const SPtr<ObjectModel>& model) override;
+
+ uint32_t _index;
+ Direction _direction;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PORTMODEL_HPP
diff --git a/include/ingen/client/SigClientInterface.hpp b/include/ingen/client/SigClientInterface.hpp
new file mode 100644
index 00000000..674714a3
--- /dev/null
+++ b/include/ingen/client/SigClientInterface.hpp
@@ -0,0 +1,63 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_CLIENT_SIGCLIENTINTERFACE_HPP
+#define INGEN_CLIENT_SIGCLIENTINTERFACE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+
+#include <cstdint>
+#include <string>
+
+namespace ingen {
+namespace client {
+
+/** A LibSigC++ signal emitting interface for clients to use.
+ *
+ * This simply emits a signal for every event that comes from the engine.
+ * For a higher level model based view of the engine, use ClientStore.
+ *
+ * The signals here match the calls to ClientInterface exactly. See the
+ * documentation for ClientInterface for meanings of signal parameters.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API SigClientInterface : public ingen::Interface,
+ public INGEN_TRACKABLE
+{
+public:
+ SigClientInterface() = default;
+
+ URI uri() const override { return URI("ingen:/clients/sig"); }
+
+ INGEN_SIGNAL(message, void, Message)
+
+ /** Fire pending signals. Only does anything on derived classes (that may queue) */
+ virtual bool emit_signals() { return false; }
+
+protected:
+ void message(const Message& msg) override {
+ _signal_message(msg);
+ }
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif
diff --git a/include/ingen/client/SocketClient.hpp b/include/ingen/client/SocketClient.hpp
new file mode 100644
index 00000000..8e551821
--- /dev/null
+++ b/include/ingen/client/SocketClient.hpp
@@ -0,0 +1,80 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-2015 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_CLIENT_SOCKET_CLIENT_HPP
+#define INGEN_CLIENT_SOCKET_CLIENT_HPP
+
+#include "ingen/SocketReader.hpp"
+#include "ingen/SocketWriter.hpp"
+#include "ingen/ingen.h"
+#include "raul/Socket.hpp"
+
+namespace ingen {
+namespace client {
+
+/** The client side of an Ingen socket connection. */
+class INGEN_API SocketClient : public SocketWriter
+{
+public:
+ SocketClient(World& world,
+ const URI& uri,
+ const SPtr<Raul::Socket>& sock,
+ const SPtr<Interface>& respondee)
+ : SocketWriter(world.uri_map(), world.uris(), uri, sock)
+ , _respondee(respondee)
+ , _reader(world, *respondee.get(), sock)
+ {}
+
+ SPtr<Interface> respondee() const override {
+ return _respondee;
+ }
+
+ void set_respondee(const SPtr<Interface>& respondee) override {
+ _respondee = respondee;
+ }
+
+ static SPtr<ingen::Interface>
+ new_socket_interface(ingen::World& world,
+ const URI& uri,
+ const SPtr<ingen::Interface>& respondee)
+ {
+ const Raul::Socket::Type type = (uri.scheme() == "unix"
+ ? Raul::Socket::Type::UNIX
+ : Raul::Socket::Type::TCP);
+
+ SPtr<Raul::Socket> sock(new Raul::Socket(type));
+ if (!sock->connect(uri)) {
+ world.log().error("Failed to connect <%1%> (%2%)\n",
+ sock->uri(), strerror(errno));
+ return SPtr<Interface>();
+ }
+ return SPtr<Interface>(new SocketClient(world, uri, sock, respondee));
+ }
+
+ static void register_factories(World& world) {
+ world.add_interface_factory("unix", &new_socket_interface);
+ world.add_interface_factory("tcp", &new_socket_interface);
+ }
+
+private:
+ SPtr<Interface> _respondee;
+ SocketReader _reader;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_SOCKET_CLIENT_HPP
diff --git a/include/ingen/client/signal.hpp b/include/ingen/client/signal.hpp
new file mode 100644
index 00000000..ba5b017b
--- /dev/null
+++ b/include/ingen/client/signal.hpp
@@ -0,0 +1,31 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_CLIENT_SIGNAL_HPP
+#define INGEN_CLIENT_SIGNAL_HPP
+
+#include <sigc++/sigc++.h>
+
+#define INGEN_SIGNAL(name, ...) \
+protected: \
+sigc::signal<__VA_ARGS__> _signal_##name; \
+public: \
+sigc::signal<__VA_ARGS__> signal_##name() const { return _signal_##name; } \
+sigc::signal<__VA_ARGS__>& signal_##name() { return _signal_##name; }
+
+#define INGEN_TRACKABLE sigc::trackable
+
+#endif // INGEN_CLIENT_SIGNAL_HPP
diff --git a/include/ingen/filesystem.hpp b/include/ingen/filesystem.hpp
new file mode 100644
index 00000000..44b9148e
--- /dev/null
+++ b/include/ingen/filesystem.hpp
@@ -0,0 +1,85 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_FILESYSTEM_HPP
+#define INGEN_FILESYSTEM_HPP
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+
+#include "ingen/FilePath.hpp"
+
+#ifdef _WIN32
+# include <windows.h>
+# include <io.h>
+# define F_OK 0
+# define mkdir(path, flags) _mkdir(path)
+#endif
+
+#include <cerrno>
+#include <climits>
+#include <cstdlib>
+#include <memory>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <vector>
+
+/* A minimal subset of the std::filesystem API from C++17. */
+
+namespace ingen {
+namespace filesystem {
+
+inline bool exists(const FilePath& path)
+{
+ return !access(path.c_str(), F_OK);
+}
+
+inline bool is_directory(const FilePath& path)
+{
+ struct stat info{};
+ stat(path.c_str(), &info);
+ return S_ISDIR(info.st_mode);
+}
+
+inline bool create_directories(const FilePath& path)
+{
+ std::vector<FilePath> paths;
+ for (FilePath p = path; p != path.root_directory(); p = p.parent_path()) {
+ paths.emplace_back(p);
+ }
+
+ for (auto p = paths.rbegin(); p != paths.rend(); ++p) {
+ if (mkdir(p->c_str(), 0755) && errno != EEXIST) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+inline FilePath current_path()
+{
+ struct Freer { void operator()(char* const ptr) { free(ptr); } };
+
+ std::unique_ptr<char, Freer> cpath(realpath(".", nullptr));
+
+ return FilePath(cpath.get());
+}
+
+} // namespace filesystem
+} // namespace ingen
+
+#endif // INGEN_FILESYSTEM_HPP
diff --git a/include/ingen/fmt.hpp b/include/ingen/fmt.hpp
new file mode 100644
index 00000000..3c792d3d
--- /dev/null
+++ b/include/ingen/fmt.hpp
@@ -0,0 +1,38 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_FMT_HPP
+#define INGEN_FMT_HPP
+
+#include <boost/format.hpp>
+
+#include <initializer_list>
+#include <string>
+
+namespace ingen {
+template <typename... Args>
+std::string
+fmt(const char* fmt, Args&&... args)
+{
+ boost::format f(fmt);
+ std::initializer_list<char> l{(static_cast<void>(f % args), char{})...};
+ (void)l;
+ return boost::str(f);
+}
+
+} // namespace ingen
+
+#endif // INGEN_FMT_HPP
diff --git a/include/ingen/ingen.h b/include/ingen/ingen.h
new file mode 100644
index 00000000..05b9e7b2
--- /dev/null
+++ b/include/ingen/ingen.h
@@ -0,0 +1,75 @@
+/*
+ This file is part of Ingen.
+ Copyright 2014-2017 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_H
+#define INGEN_H
+
+#ifdef INGEN_SHARED
+# ifdef _WIN32
+# define INGEN_LIB_IMPORT __declspec(dllimport)
+# define INGEN_LIB_EXPORT __declspec(dllexport)
+# else
+# define INGEN_LIB_IMPORT __attribute__((visibility("default")))
+# define INGEN_LIB_EXPORT __attribute__((visibility("default")))
+# endif
+# ifdef INGEN_INTERNAL
+# define INGEN_API INGEN_LIB_EXPORT
+# else
+# define INGEN_API INGEN_LIB_IMPORT
+# endif
+#else
+# define INGEN_API
+#endif
+
+#define INGEN_NS "http://drobilla.net/ns/ingen#"
+
+#define INGEN__Arc INGEN_NS "Arc"
+#define INGEN__Block INGEN_NS "Block"
+#define INGEN__BundleEnd INGEN_NS "BundleEnd"
+#define INGEN__BundleStart INGEN_NS "BundleStart"
+#define INGEN__Graph INGEN_NS "Graph"
+#define INGEN__GraphPrototype INGEN_NS "GraphPrototype"
+#define INGEN__Internal INGEN_NS "Internal"
+#define INGEN__Node INGEN_NS "Node"
+#define INGEN__Plugin INGEN_NS "Plugin"
+#define INGEN__Redo INGEN_NS "Redo"
+#define INGEN__Undo INGEN_NS "Undo"
+#define INGEN__activity INGEN_NS "activity"
+#define INGEN__arc INGEN_NS "arc"
+#define INGEN__block INGEN_NS "block"
+#define INGEN__broadcast INGEN_NS "broadcast"
+#define INGEN__canvasX INGEN_NS "canvasX"
+#define INGEN__canvasY INGEN_NS "canvasY"
+#define INGEN__enabled INGEN_NS "enabled"
+#define INGEN__externalContext INGEN_NS "externalContext"
+#define INGEN__file INGEN_NS "file"
+#define INGEN__head INGEN_NS "head"
+#define INGEN__incidentTo INGEN_NS "incidentTo"
+#define INGEN__internalContext INGEN_NS "internalContext"
+#define INGEN__loadedBundle INGEN_NS "loadedBundle"
+#define INGEN__maxRunLoad INGEN_NS "maxRunLoad"
+#define INGEN__meanRunLoad INGEN_NS "meanRunLoad"
+#define INGEN__minRunLoad INGEN_NS "minRunLoad"
+#define INGEN__numThreads INGEN_NS "numThreads"
+#define INGEN__polyphonic INGEN_NS "polyphonic"
+#define INGEN__polyphony INGEN_NS "polyphony"
+#define INGEN__prototype INGEN_NS "prototype"
+#define INGEN__sprungLayout INGEN_NS "sprungLayout"
+#define INGEN__tail INGEN_NS "tail"
+#define INGEN__uiEmbedded INGEN_NS "uiEmbedded"
+#define INGEN__value INGEN_NS "value"
+
+#endif // INGEN_H
diff --git a/include/ingen/paths.hpp b/include/ingen/paths.hpp
new file mode 100644
index 00000000..05496114
--- /dev/null
+++ b/include/ingen/paths.hpp
@@ -0,0 +1,55 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_PATHS_HPP
+#define INGEN_PATHS_HPP
+
+#include "ingen/URI.hpp"
+#include "raul/Path.hpp"
+
+#include <cstddef>
+#include <string>
+
+namespace ingen {
+
+inline URI main_uri() { return URI("ingen:/main"); }
+
+inline bool uri_is_path(const URI& uri)
+{
+ const size_t root_len = main_uri().string().length();
+ if (uri == main_uri()) {
+ return true;
+ } else {
+ return uri.string().substr(0, root_len + 1) ==
+ main_uri().string() + "/";
+ }
+}
+
+inline Raul::Path uri_to_path(const URI& uri)
+{
+ return (uri == main_uri())
+ ? Raul::Path("/")
+ : Raul::Path(uri.string().substr(main_uri().string().length()));
+}
+
+inline URI path_to_uri(const Raul::Path& path)
+{
+ return URI(main_uri().string() + path.c_str());
+}
+
+} // namespace ingen
+
+#endif // INGEN_PATHS_HPP
diff --git a/include/ingen/runtime_paths.hpp b/include/ingen/runtime_paths.hpp
new file mode 100644
index 00000000..30e877fb
--- /dev/null
+++ b/include/ingen/runtime_paths.hpp
@@ -0,0 +1,51 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_RUNTIME_PATHS_HPP
+#define INGEN_RUNTIME_PATHS_HPP
+
+#include "ingen/FilePath.hpp"
+#include "ingen/ingen.h"
+
+#include <string>
+#include <vector>
+
+namespace ingen {
+
+extern const char search_path_separator;
+
+INGEN_API void set_bundle_path(const char* path);
+INGEN_API void set_bundle_path_from_code(void (*function)());
+
+INGEN_API FilePath
+find_in_search_path(const std::string& name,
+ const std::vector<FilePath>& search_path);
+
+INGEN_API FilePath bundle_file_path(const std::string& name);
+INGEN_API FilePath data_file_path(const std::string& name);
+INGEN_API FilePath ingen_module_path(const std::string& name);
+
+INGEN_API FilePath user_config_dir();
+INGEN_API FilePath user_data_dir();
+INGEN_API std::vector<FilePath> system_config_dirs();
+INGEN_API std::vector<FilePath> system_data_dirs();
+INGEN_API std::vector<FilePath> config_dirs();
+INGEN_API std::vector<FilePath> data_dirs();
+INGEN_API std::vector<FilePath> ingen_module_dirs();
+
+} // namespace ingen
+
+#endif // INGEN_RUNTIME_PATHS_HPP
diff --git a/include/ingen/types.hpp b/include/ingen/types.hpp
new file mode 100644
index 00000000..2962d16a
--- /dev/null
+++ b/include/ingen/types.hpp
@@ -0,0 +1,54 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 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_TYPES_HPP
+#define INGEN_TYPES_HPP
+
+#include "raul/Maid.hpp"
+
+#include <cstdlib>
+#include <memory>
+
+namespace ingen {
+
+template <class T>
+void NullDeleter(T* ptr) {}
+
+template <class T>
+struct FreeDeleter { void operator()(T* const ptr) { free(ptr); } };
+
+template <class T, class Deleter = std::default_delete<T>>
+using UPtr = std::unique_ptr<T, Deleter>;
+
+template <class T>
+using SPtr = std::shared_ptr<T>;
+
+template <class T>
+using WPtr = std::weak_ptr<T>;
+
+template <class T>
+using MPtr = Raul::managed_ptr<T>;
+
+template <typename T, typename... Args>
+std::unique_ptr<T>
+make_unique(Args&&... args)
+{
+ return std::unique_ptr<T>{new T{std::forward<Args>(args)...}};
+}
+
+} // namespace ingen
+
+#endif // INGEN_TYPES_HPP