From c0f567d3232cbe165e56cb2684cda52df7cfb90f Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 1 Aug 2020 22:41:11 +0200 Subject: 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. --- include/ingen/Arc.hpp | 40 +++++ include/ingen/Atom.hpp | 183 +++++++++++++++++++++ include/ingen/AtomForge.hpp | 123 ++++++++++++++ include/ingen/AtomReader.hpp | 76 +++++++++ include/ingen/AtomSink.hpp | 47 ++++++ include/ingen/AtomWriter.hpp | 86 ++++++++++ include/ingen/ClashAvoider.hpp | 66 ++++++++ include/ingen/Clock.hpp | 66 ++++++++ include/ingen/ColorContext.hpp | 39 +++++ include/ingen/Configuration.hpp | 160 ++++++++++++++++++ include/ingen/DataAccess.hpp | 68 ++++++++ include/ingen/EngineBase.hpp | 145 +++++++++++++++++ include/ingen/FilePath.hpp | 125 +++++++++++++++ include/ingen/Forge.hpp | 86 ++++++++++ include/ingen/InstanceAccess.hpp | 56 +++++++ include/ingen/Interface.hpp | 149 +++++++++++++++++ include/ingen/LV2Features.hpp | 93 +++++++++++ include/ingen/Library.hpp | 48 ++++++ include/ingen/Log.hpp | 107 ++++++++++++ include/ingen/Message.hpp | 158 ++++++++++++++++++ include/ingen/Module.hpp | 64 ++++++++ include/ingen/Node.hpp | 106 ++++++++++++ include/ingen/Parser.hpp | 99 ++++++++++++ include/ingen/Properties.hpp | 90 +++++++++++ include/ingen/QueuedInterface.hpp | 66 ++++++++ include/ingen/Resource.hpp | 206 ++++++++++++++++++++++++ include/ingen/Serialiser.hpp | 106 ++++++++++++ include/ingen/SocketReader.hpp | 85 ++++++++++ include/ingen/SocketWriter.hpp | 57 +++++++ include/ingen/Status.hpp | 92 +++++++++++ include/ingen/Store.hpp | 86 ++++++++++ include/ingen/StreamWriter.hpp | 52 ++++++ include/ingen/Tee.hpp | 63 ++++++++ include/ingen/TurtleWriter.hpp | 69 ++++++++ include/ingen/URI.hpp | 175 ++++++++++++++++++++ include/ingen/URIMap.hpp | 96 +++++++++++ include/ingen/URIs.hpp | 241 ++++++++++++++++++++++++++++ include/ingen/World.hpp | 151 +++++++++++++++++ include/ingen/client/ArcModel.hpp | 67 ++++++++ include/ingen/client/BlockModel.hpp | 117 ++++++++++++++ include/ingen/client/ClientStore.hpp | 132 +++++++++++++++ include/ingen/client/GraphModel.hpp | 82 ++++++++++ include/ingen/client/ObjectModel.hpp | 99 ++++++++++++ include/ingen/client/PluginModel.hpp | 127 +++++++++++++++ include/ingen/client/PluginUI.hpp | 116 +++++++++++++ include/ingen/client/PortModel.hpp | 97 +++++++++++ include/ingen/client/SigClientInterface.hpp | 63 ++++++++ include/ingen/client/SocketClient.hpp | 80 +++++++++ include/ingen/client/signal.hpp | 31 ++++ include/ingen/filesystem.hpp | 85 ++++++++++ include/ingen/fmt.hpp | 38 +++++ include/ingen/ingen.h | 75 +++++++++ include/ingen/paths.hpp | 55 +++++++ include/ingen/runtime_paths.hpp | 51 ++++++ include/ingen/types.hpp | 54 +++++++ 55 files changed, 5194 insertions(+) create mode 100644 include/ingen/Arc.hpp create mode 100644 include/ingen/Atom.hpp create mode 100644 include/ingen/AtomForge.hpp create mode 100644 include/ingen/AtomReader.hpp create mode 100644 include/ingen/AtomSink.hpp create mode 100644 include/ingen/AtomWriter.hpp create mode 100644 include/ingen/ClashAvoider.hpp create mode 100644 include/ingen/Clock.hpp create mode 100644 include/ingen/ColorContext.hpp create mode 100644 include/ingen/Configuration.hpp create mode 100644 include/ingen/DataAccess.hpp create mode 100644 include/ingen/EngineBase.hpp create mode 100644 include/ingen/FilePath.hpp create mode 100644 include/ingen/Forge.hpp create mode 100644 include/ingen/InstanceAccess.hpp create mode 100644 include/ingen/Interface.hpp create mode 100644 include/ingen/LV2Features.hpp create mode 100644 include/ingen/Library.hpp create mode 100644 include/ingen/Log.hpp create mode 100644 include/ingen/Message.hpp create mode 100644 include/ingen/Module.hpp create mode 100644 include/ingen/Node.hpp create mode 100644 include/ingen/Parser.hpp create mode 100644 include/ingen/Properties.hpp create mode 100644 include/ingen/QueuedInterface.hpp create mode 100644 include/ingen/Resource.hpp create mode 100644 include/ingen/Serialiser.hpp create mode 100644 include/ingen/SocketReader.hpp create mode 100644 include/ingen/SocketWriter.hpp create mode 100644 include/ingen/Status.hpp create mode 100644 include/ingen/Store.hpp create mode 100644 include/ingen/StreamWriter.hpp create mode 100644 include/ingen/Tee.hpp create mode 100644 include/ingen/TurtleWriter.hpp create mode 100644 include/ingen/URI.hpp create mode 100644 include/ingen/URIMap.hpp create mode 100644 include/ingen/URIs.hpp create mode 100644 include/ingen/World.hpp create mode 100644 include/ingen/client/ArcModel.hpp create mode 100644 include/ingen/client/BlockModel.hpp create mode 100644 include/ingen/client/ClientStore.hpp create mode 100644 include/ingen/client/GraphModel.hpp create mode 100644 include/ingen/client/ObjectModel.hpp create mode 100644 include/ingen/client/PluginModel.hpp create mode 100644 include/ingen/client/PluginUI.hpp create mode 100644 include/ingen/client/PortModel.hpp create mode 100644 include/ingen/client/SigClientInterface.hpp create mode 100644 include/ingen/client/SocketClient.hpp create mode 100644 include/ingen/client/signal.hpp create mode 100644 include/ingen/filesystem.hpp create mode 100644 include/ingen/fmt.hpp create mode 100644 include/ingen/ingen.h create mode 100644 include/ingen/paths.hpp create mode 100644 include/ingen/runtime_paths.hpp create mode 100644 include/ingen/types.hpp (limited to 'include') 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 + + 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 . +*/ + +#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 + + 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 . +*/ + +#ifndef INGEN_ATOM_HPP +#define INGEN_ATOM_HPP + +#include "ingen/ingen.h" +#include "lv2/atom/atom.h" +#include "lv2/urid/urid.h" + +#include +#include +#include +#include +#include + +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(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(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(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(_body.ptr + 1) : &_body.val; + } + + inline void* get_body() { + return is_reference() ? static_cast(_body.ptr + 1) : &_body.val; + } + + template const T& get() const { + assert(size() == sizeof(T)); + return *static_cast(get_body()); + } + + template const T* ptr() const { + return static_cast(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 + + 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 . +*/ + +#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 +#include +#include +#include + +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(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>; + using SratomPtr = UPtr; + + /// 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(realloc(_buf.release(), _capacity))}; + } + + // Append new data + memcpy(reinterpret_cast(_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(_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(handle)->append(buf, len); + } + + static LV2_Atom* + c_deref(void* handle, LV2_Atom_Forge_Ref ref) { + return static_cast(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 + + 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 . +*/ + +#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 + +#include + +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 atom_to_uri(const LV2_Atom* atom); + boost::optional 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 + + 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 . +*/ + +#ifndef INGEN_ATOMSINK_HPP +#define INGEN_ATOMSINK_HPP + +#include "ingen/ingen.h" +#include "lv2/atom/atom.h" + +#include + +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 + + 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 . +*/ + +#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 + +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 + + 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 . +*/ + +#ifndef INGEN_CLASHAVOIDER_HPP +#define INGEN_CLASHAVOIDER_HPP + +#include "ingen/ingen.h" +#include "raul/Path.hpp" + +#include +#include + +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; + using SymbolMap = std::map; + + 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 + + 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 . +*/ + +#ifndef INGEN_ENGINE_CLOCK_HPP +#define INGEN_ENGINE_CLOCK_HPP + +#ifdef __MACH__ +# include +# include +#else +# include +# include +#endif + +#include + +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(time.tv_sec) * 1e6 + + static_cast(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 + + 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 . +*/ + +#ifndef INGEN_COLORCONTEXT_HPP +#define INGEN_COLORCONTEXT_HPP + +#include "ingen/ingen.h" + +#include + +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 + + 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 . +*/ + +#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 +#include +#include +#include +#include + +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 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; + using ShortNames = std::map; + using Keys = std::map; + + 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 + + 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 . +*/ + +#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 +#include +#include + +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 feature(World& world, Node* node) override { + Node* store_node = world.store()->get(node->path()); + if (!store_node) { + return SPtr(); + } + + LilvInstance* inst = store_node->instance(); + if (!inst) { + return SPtr(); + } + + const LV2_Descriptor* desc = lilv_instance_get_descriptor(inst); + auto* data = static_cast( + malloc(sizeof(LV2_Extension_Data_Feature))); + + data->data_access = desc->extension_data; + + return std::make_shared( + 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 + + 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 . +*/ + +#ifndef INGEN_ENGINEBASE_HPP +#define INGEN_ENGINEBASE_HPP + +#include "ingen/ingen.h" +#include "ingen/types.hpp" + +#include +#include +#include + +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& client) = 0; + + /** + Unregister a client. + */ + virtual bool unregister_client(const SPtr& 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 + + 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 . +*/ + +#ifndef INGEN_FILE_PATH_HPP +#define INGEN_FILE_PATH_HPP + +#include "ingen/ingen.h" + +#include + +#include +#include +#include + +#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; + + 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& 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 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 +std::basic_ostream& +operator<<(std::basic_ostream& 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 + + 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 . +*/ + +#ifndef INGEN_FORGE_HPP +#define INGEN_FORGE_HPP + +#include "ingen/Atom.hpp" +#include "ingen/ingen.h" +#include "lv2/atom/forge.h" + +#include +#include +#include + +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 + + 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 . +*/ + +#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 +#include + +namespace ingen { + +struct InstanceAccess : public ingen::LV2Features::Feature +{ + const char* uri() const override { return "http://lv2plug.in/ns/ext/instance-access"; } + + SPtr feature(World& world, Node* node) override { + Node* store_node = world.store()->get(node->path()); + if (!store_node) { + return SPtr(); + } + + LilvInstance* instance = store_node->instance(); + if (!instance) { + return SPtr(); + } + + return std::make_shared( + 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 + + 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 . +*/ + +/** + @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 +#include + +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 respondee() const { return SPtr(); } + + virtual void set_respondee(const SPtr& 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 + + 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 . +*/ + +#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 +#include + +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 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 feature(World& world, Node* block) override { + return SPtr(); + } + + const char* _uri; + }; + + class FeatureArray : public Raul::Noncopyable { + public: + using FeatureVector = std::vector>; + + explicit FeatureArray(FeatureVector& features); + + ~FeatureArray(); + + LV2_Feature** array() { return _array; } + + private: + FeatureVector _features; + LV2_Feature** _array; + }; + + void add_feature(const SPtr& feature); + bool is_supported(const std::string& uri) const; + + SPtr lv2_features(World& world, Node* node) const; + +private: + using Features = std::vector>; + 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 + + 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 . +*/ + +#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 + + 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 . +*/ + +#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 +#include +#include +#include +#include + +namespace ingen { + +class Node; +class URIs; +class World; + +class INGEN_API Log { +public: + using Sink = std::function; + + Log(LV2_Log_Log* log, URIs& uris); + + struct Feature : public LV2Features::Feature { + const char* uri() const override { return LV2_LOG__log; } + + SPtr 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 + void error(const char* format, Args&&... args) + { + error(fmt(format, std::forward(args)...)); + } + + template + void info(const char* format, Args&&... args) + { + info(fmt(format, std::forward(args)...)); + } + + template + void warn(const char* format, Args&&... args) + { + warn(fmt(format, std::forward(args)...)); + } + + template + void trace(const char* format, Args&&... args) + { + trace(fmt(format, std::forward(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 + + 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 . +*/ + +#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 + +#include +#include + +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; + +} // 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 + + 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 . +*/ + +#ifndef INGEN_MODULE_HPP +#define INGEN_MODULE_HPP + +#include "ingen/FilePath.hpp" +#include "ingen/Library.hpp" +#include "ingen/ingen.h" + +#include + +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; +}; + +} // 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 + + 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 . +*/ + +#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 +#include +#include +#include + +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; + using Arcs = std::map>; + + // 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 + + 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 . +*/ + +#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 + +#include +#include +#include + +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 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& parent = boost::optional(), + const boost::optional& symbol = boost::optional(), + const boost::optional& data = boost::optional()); + + virtual boost::optional parse_string( + World& world, + Interface& target, + const std::string& str, + const URI& base_uri, + const boost::optional& parent = boost::optional(), + const boost::optional& symbol = boost::optional(), + const boost::optional& data = boost::optional()); +}; + +} // 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 + + 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 . +*/ + +#ifndef INGEN_PROPERTIES_HPP +#define INGEN_PROPERTIES_HPP + +#include "ingen/Atom.hpp" +#include "ingen/URIs.hpp" + +#include +#include +#include + +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 { +public: + using Graph = Property::Graph; + + Properties() = default; + Properties(const Properties& copy) = default; + + Properties(std::initializer_list l) + : std::multimap(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 + + 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 . +*/ + +#ifndef INGEN_ENGINE_QUEUEDINTERFACE_HPP +#define INGEN_ENGINE_QUEUEDINTERFACE_HPP + +#include "ingen/Interface.hpp" +#include "ingen/Message.hpp" + +#include +#include + +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 sink) : _sink(std::move(sink)) {} + + URI uri() const override { return URI("ingen:/QueuedInterface"); } + + void message(const Message& message) override { + std::lock_guard lock(_mutex); + _messages.emplace_back(message); + } + + void emit() { + std::vector messages; + { + std::lock_guard lock(_mutex); + _messages.swap(messages); + } + + for (const auto& i : messages) { + _sink->message(i); + } + } + + const SPtr& sink() const { return _sink; } + +private: + std::mutex _mutex; + SPtr _sink; + std::vector _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 + + 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 . +*/ + +#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 + +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 + + 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 . +*/ + +#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 + +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& 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& object, + Property::Graph context = Property::Graph::DEFAULT); + + /** Serialize an arc. + * + * @throw std::logic_error + */ + virtual void serialise_arc(const Sord::Node& parent, + const SPtr& 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 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 + + 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 . +*/ + +#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 + +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 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 _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 + + 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 . +*/ + +#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 + +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 sock); + + void message(const Message& message) override; + + size_t text_sink(const void* buf, size_t len) override; + +protected: + SPtr _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 + + 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 . +*/ + +#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 + + 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 . +*/ + +#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 +#include +#include + +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 > { +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; + using Objects = std::map>; + 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& 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 + + 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 . +*/ + +#ifndef INGEN_STREAMWRITER_HPP +#define INGEN_STREAMWRITER_HPP + +#include "ingen/ColorContext.hpp" +#include "ingen/TurtleWriter.hpp" +#include "ingen/ingen.h" + +#include + +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 + + 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 . +*/ + +#ifndef INGEN_ENGINE_TEE_HPP +#define INGEN_ENGINE_TEE_HPP + +#include "ingen/Interface.hpp" +#include "ingen/Message.hpp" +#include "ingen/types.hpp" + +#include +#include +#include +#include + +namespace ingen { + +/** Interface that forwards all calls to several sinks. */ +class Tee : public Interface +{ +public: + using Sinks = std::vector>; + + explicit Tee(Sinks sinks) : _sinks(std::move(sinks)) {} + + SPtr respondee() const override { + return _sinks.front()->respondee(); + } + + void set_respondee(const SPtr& respondee) override { + _sinks.front()->set_respondee(respondee); + } + + void message(const Message& message) override { + std::lock_guard 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 + + 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 . +*/ + +#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 +#include + +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 + + 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 . +*/ + +#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 + +#include +#include +#include +#include + +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(_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(_node.buf); + } + + const char* end() const + { + return reinterpret_cast(_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(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(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 +inline std::basic_ostream& +operator<<(std::basic_ostream& 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 + + 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 . +*/ + +#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 +#include +#include +#include +#include + +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 feature(World&, Node*) override { + return SPtr(&_feature, NullDeleter); + } + + 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 urid_map_feature() { return _urid_map_feature; } + SPtr urid_unmap_feature() { return _urid_unmap_feature; } + +private: + friend struct URIDMapFeature; + friend struct URIDUnMapFeature; + + SPtr _urid_map_feature; + SPtr _urid_unmap_feature; + + std::mutex _mutex; + std::unordered_map _map; + std::vector _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 + + 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 . +*/ + +#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(); } + const LilvNode* node() const { return _lilv_node; } + + operator LV2_URID() const { return _urid_atom.get(); } + 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 + + 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 . +*/ + +#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 +#include + +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 (*)(World& world, + const URI& engine_uri, + const SPtr& 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 new_interface(const URI& engine_uri, + const SPtr& respondee); + + /** Run a script. */ + virtual bool run(const std::string& mime_type, + const std::string& filename); + + virtual void set_engine(const SPtr& e); + virtual void set_interface(const SPtr& i); + virtual void set_store(const SPtr& s); + + virtual SPtr engine(); + virtual SPtr interface(); + virtual SPtr parser(); + virtual SPtr serialiser(); + virtual SPtr 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 + + 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 . +*/ + +#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 + +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 tail() const { return _tail; } + SPtr 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 tail, SPtr 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 _tail; + const SPtr _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 + + 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 . +*/ + +#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 +#include +#include +#include + +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 get_port(const Raul::Symbol& symbol) const; + SPtr 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 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& port, + float& min, + float& max, + uint32_t srate = 1) const; + + void port_value_range(const SPtr& port, + float& min, + float& max, + uint32_t srate = 1) const; + + std::string label() const; + std::string port_label(const SPtr& port) const; + + // Signals + INGEN_SIGNAL(new_port, void, SPtr) + INGEN_SIGNAL(removed_port, void, SPtr) + +protected: + friend class ClientStore; + + BlockModel(URIs& uris, URI plugin_uri, const Raul::Path& path); + + BlockModel(URIs& uris, + const SPtr& plugin, + const Raul::Path& path); + + explicit BlockModel(const Raul::Path& path); + + void add_child(const SPtr& c) override; + bool remove_child(const SPtr& c) override; + void add_port(const SPtr& pm); + void remove_port(const SPtr& port); + void remove_port(const Raul::Path& port_path); + void set(const SPtr& model) override; + + virtual void clear(); + + Ports _ports; ///< Vector of ports + URI _plugin_uri; ///< Plugin URI (if PluginModel is unknown) + SPtr _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 + + 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 . +*/ + +#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 + +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& emitter = SPtr()); + + URI uri() const override { return URI("ingen:/clients/store"); } + + SPtr object(const Raul::Path& path) const; + SPtr plugin(const URI& uri) const; + SPtr resource(const URI& uri) const; + + void clear(); + + using Plugins = std::map>; + + SPtr plugins() const { return _plugins; } + SPtr plugins() { return _plugins; } + void set_plugins(SPtr 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) + INGEN_SIGNAL(new_plugin, void, SPtr) + INGEN_SIGNAL(plugin_deleted, void, URI) + +private: + SPtr _object(const Raul::Path& path); + SPtr _plugin(const URI& uri); + SPtr _plugin(const Atom& uri); + SPtr _resource(const URI& uri); + + void add_object(const SPtr& object); + SPtr remove_object(const Raul::Path& path); + + void add_plugin(const SPtr& pm); + + SPtr 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 _emitter; + + SPtr _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 + + 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 . +*/ + +#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 + +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 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) + INGEN_SIGNAL(removed_block, void, SPtr) + INGEN_SIGNAL(new_arc, void, SPtr) + INGEN_SIGNAL(removed_arc, void, SPtr) + +private: + friend class ClientStore; + + GraphModel(URIs& uris, const Raul::Path& graph_path) + : BlockModel(uris, + static_cast(uris.ingen_Graph), + graph_path) + { + } + + void clear() override; + void add_child(const SPtr& c) override; + bool remove_child(const SPtr& o) override; + void remove_arcs_on(const SPtr& p); + + void add_arc(const SPtr& 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 + + 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 . +*/ + +/** + @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 parent() const { return _parent; } + bool polyphonic() const; + + Node* graph_parent() const override { return _parent.get(); } + + // Signals + INGEN_SIGNAL(new_child, void, SPtr) + INGEN_SIGNAL(removed_child, void, SPtr) + 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& p); + virtual void add_child(const SPtr& c) {} + virtual bool remove_child(const SPtr& c) { return true; } + + virtual void set(const SPtr& o); + + SPtr _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 + + 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 . +*/ + +#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 +#include +#include + +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; + ScalePoints port_scale_points(uint32_t i) const; + + using Presets = std::map; + 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 + ui(ingen::World& world, const SPtr& 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& 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 + + 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 . +*/ + +#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 +#include + +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 create(ingen::World& world, + const SPtr& 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 block() const { return _block; } + +private: + PluginUI(ingen::World& world, + SPtr block, + LilvUIs* uis, + const LilvUI* ui, + const LilvNode* ui_type); + + ingen::World& _world; + SPtr _block; + SuilInstance* _instance; + LilvUIs* _uis; + const LilvUI* _ui; + LilvNode* _ui_node; + LilvNode* _ui_type; + std::set _subscribed_ports; + + static SuilHost* ui_host; + + SPtr _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 + + 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 . +*/ + +#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 +#include + +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& c) override { throw; } + bool remove_child(const SPtr& c) override { throw; } + + void set(const SPtr& 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 + + 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 . +*/ + +#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 +#include + +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 + + 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 . +*/ + +#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& sock, + const SPtr& respondee) + : SocketWriter(world.uri_map(), world.uris(), uri, sock) + , _respondee(respondee) + , _reader(world, *respondee.get(), sock) + {} + + SPtr respondee() const override { + return _respondee; + } + + void set_respondee(const SPtr& respondee) override { + _respondee = respondee; + } + + static SPtr + new_socket_interface(ingen::World& world, + const URI& uri, + const SPtr& respondee) + { + const Raul::Socket::Type type = (uri.scheme() == "unix" + ? Raul::Socket::Type::UNIX + : Raul::Socket::Type::TCP); + + SPtr sock(new Raul::Socket(type)); + if (!sock->connect(uri)) { + world.log().error("Failed to connect <%1%> (%2%)\n", + sock->uri(), strerror(errno)); + return SPtr(); + } + return SPtr(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 _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 + + 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 . +*/ + +#ifndef INGEN_CLIENT_SIGNAL_HPP +#define INGEN_CLIENT_SIGNAL_HPP + +#include + +#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 + + 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 . +*/ + +#ifndef INGEN_FILESYSTEM_HPP +#define INGEN_FILESYSTEM_HPP + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 + +#include "ingen/FilePath.hpp" + +#ifdef _WIN32 +# include +# include +# define F_OK 0 +# define mkdir(path, flags) _mkdir(path) +#endif + +#include +#include +#include +#include +#include +#include +#include + +/* 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 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 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 + + 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 . +*/ + +#ifndef INGEN_FMT_HPP +#define INGEN_FMT_HPP + +#include + +#include +#include + +namespace ingen { +template +std::string +fmt(const char* fmt, Args&&... args) +{ + boost::format f(fmt); + std::initializer_list l{(static_cast(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 + + 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 . +*/ + +#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 + + 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 . +*/ + +#ifndef INGEN_PATHS_HPP +#define INGEN_PATHS_HPP + +#include "ingen/URI.hpp" +#include "raul/Path.hpp" + +#include +#include + +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 + + 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 . +*/ + +#ifndef INGEN_RUNTIME_PATHS_HPP +#define INGEN_RUNTIME_PATHS_HPP + +#include "ingen/FilePath.hpp" +#include "ingen/ingen.h" + +#include +#include + +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& 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 system_config_dirs(); +INGEN_API std::vector system_data_dirs(); +INGEN_API std::vector config_dirs(); +INGEN_API std::vector data_dirs(); +INGEN_API std::vector 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 + + 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 . +*/ + +#ifndef INGEN_TYPES_HPP +#define INGEN_TYPES_HPP + +#include "raul/Maid.hpp" + +#include +#include + +namespace ingen { + +template +void NullDeleter(T* ptr) {} + +template +struct FreeDeleter { void operator()(T* const ptr) { free(ptr); } }; + +template > +using UPtr = std::unique_ptr; + +template +using SPtr = std::shared_ptr; + +template +using WPtr = std::weak_ptr; + +template +using MPtr = Raul::managed_ptr; + +template +std::unique_ptr +make_unique(Args&&... args) +{ + return std::unique_ptr{new T{std::forward(args)...}}; +} + +} // namespace ingen + +#endif // INGEN_TYPES_HPP -- cgit v1.2.1