summaryrefslogtreecommitdiffstats
path: root/include/ingen/client
diff options
context:
space:
mode:
Diffstat (limited to 'include/ingen/client')
-rw-r--r--include/ingen/client/ArcModel.hpp65
-rw-r--r--include/ingen/client/BlockModel.hpp124
-rw-r--r--include/ingen/client/ClientStore.hpp130
-rw-r--r--include/ingen/client/GraphModel.hpp89
-rw-r--r--include/ingen/client/ObjectModel.hpp100
-rw-r--r--include/ingen/client/PluginModel.hpp133
-rw-r--r--include/ingen/client/PluginUI.hpp119
-rw-r--r--include/ingen/client/PortModel.hpp101
-rw-r--r--include/ingen/client/SigClientInterface.hpp59
-rw-r--r--include/ingen/client/SocketClient.hpp92
-rw-r--r--include/ingen/client/client.h31
-rw-r--r--include/ingen/client/signal.hpp34
12 files changed, 1077 insertions, 0 deletions
diff --git a/include/ingen/client/ArcModel.hpp b/include/ingen/client/ArcModel.hpp
new file mode 100644
index 00000000..8104b188
--- /dev/null
+++ b/include/ingen/client/ArcModel.hpp
@@ -0,0 +1,65 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_ARCMODEL_HPP
+#define INGEN_CLIENT_ARCMODEL_HPP
+
+#include "ingen/Arc.hpp"
+#include "ingen/client/PortModel.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+
+#include <cassert>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace ingen::client {
+
+/** Class to represent a port->port connections in the engine.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ArcModel : public Arc
+{
+public:
+ std::shared_ptr<PortModel> tail() const { return _tail; }
+ std::shared_ptr<PortModel> head() const { return _head; }
+
+ const raul::Path& tail_path() const override { return _tail->path(); }
+ const raul::Path& head_path() const override { return _head->path(); }
+
+private:
+ friend class ClientStore;
+
+ ArcModel(std::shared_ptr<PortModel> tail, std::shared_ptr<PortModel> head)
+ : _tail(std::move(tail))
+ , _head(std::move(head))
+ {
+ assert(_tail);
+ assert(_head);
+ assert(_tail->parent());
+ assert(_head->parent());
+ assert(_tail->path() != _head->path());
+ }
+
+ const std::shared_ptr<PortModel> _tail;
+ const std::shared_ptr<PortModel> _head;
+};
+
+} // namespace ingen::client
+
+#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..d2641f77
--- /dev/null
+++ b/include/ingen/client/BlockModel.hpp
@@ -0,0 +1,124 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_BLOCKMODEL_HPP
+#define INGEN_CLIENT_BLOCKMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/client/PluginModel.hpp" // IWYU pragma: keep
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+// IWYU pragma: no_include <algorithm>
+
+namespace raul {
+class Path;
+class Symbol;
+} // namespace raul
+
+namespace ingen {
+
+class Resource;
+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);
+ ~BlockModel() override;
+
+ GraphType graph_type() const override { return Node::GraphType::BLOCK; }
+
+ using Ports = std::vector<std::shared_ptr<const PortModel>>;
+
+ std::shared_ptr<const PortModel> get_port(const raul::Symbol& symbol) const;
+ std::shared_ptr<const PortModel> get_port(uint32_t index) const;
+
+ Node* port(uint32_t index) const override;
+
+ const URI& plugin_uri() const { return _plugin_uri; }
+ const Resource* plugin() const override { return _plugin.get(); }
+ Resource* plugin() { return _plugin.get(); }
+ std::shared_ptr<PluginModel> plugin_model() const { return _plugin; }
+ uint32_t num_ports() const override { return _ports.size(); }
+ const Ports& ports() const { return _ports; }
+
+ void default_port_value_range(const std::shared_ptr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ void port_value_range(const std::shared_ptr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ std::string label() const;
+ std::string port_label(const std::shared_ptr<const PortModel>& port) const;
+
+ // Signals
+ INGEN_SIGNAL(new_port, void, std::shared_ptr<const PortModel>)
+ INGEN_SIGNAL(removed_port, void, std::shared_ptr<const PortModel>)
+
+protected:
+ friend class ClientStore;
+
+ BlockModel(URIs& uris, URI plugin_uri, const raul::Path& path);
+
+ BlockModel(URIs& uris,
+ const std::shared_ptr<PluginModel>& plugin,
+ const raul::Path& path);
+
+ explicit BlockModel(const raul::Path& path);
+
+ void add_child(const std::shared_ptr<ObjectModel>& c) override;
+ bool remove_child(const std::shared_ptr<ObjectModel>& c) override;
+ void add_port(const std::shared_ptr<PortModel>& pm);
+ void remove_port(const std::shared_ptr<PortModel>& port);
+ void remove_port(const raul::Path& port_path);
+ void set(const std::shared_ptr<ObjectModel>& model) override;
+
+ virtual void clear();
+
+ Ports _ports; ///< Vector of ports
+ URI _plugin_uri; ///< Plugin URI (if PluginModel is unknown)
+ std::shared_ptr<PluginModel> _plugin; ///< Plugin this 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..83cce726
--- /dev/null
+++ b/include/ingen/client/ClientStore.hpp
@@ -0,0 +1,130 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_CLIENTSTORE_HPP
+#define INGEN_CLIENT_CLIENTSTORE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/Store.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+
+#include <map>
+#include <memory>
+#include <utility>
+
+namespace raul {
+class Path;
+} // namespace raul
+
+namespace ingen {
+
+class Atom;
+class Log;
+class Resource;
+class URIs;
+
+namespace client {
+
+class GraphModel;
+class ObjectModel;
+class PluginModel;
+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 std::shared_ptr<SigClientInterface>& emitter =
+ std::shared_ptr<SigClientInterface>());
+
+ URI uri() const override { return URI("ingen:/clients/store"); }
+
+ std::shared_ptr<const ObjectModel> object(const raul::Path& path) const;
+ std::shared_ptr<const PluginModel> plugin(const URI& uri) const;
+ std::shared_ptr<const Resource> resource(const URI& uri) const;
+
+ void clear();
+
+ using Plugins = std::map<const URI, std::shared_ptr<PluginModel>>;
+
+ std::shared_ptr<const Plugins> plugins() const { return _plugins; }
+ std::shared_ptr<Plugins> plugins() { return _plugins; }
+
+ void set_plugins(std::shared_ptr<Plugins> p) { _plugins = std::move(p); }
+
+ URIs& uris() { return _uris; }
+
+ void message(const Message& msg) override;
+
+ void operator()(const BundleBegin&) noexcept {}
+ void operator()(const BundleEnd&) noexcept {}
+ 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&) noexcept {}
+ void operator()(const Get&) noexcept {}
+ void operator()(const Move&);
+ void operator()(const Put&);
+ void operator()(const Redo&) noexcept {}
+ void operator()(const Response&) noexcept {}
+ void operator()(const SetProperty&);
+ void operator()(const Undo&) noexcept {}
+
+ INGEN_SIGNAL(new_object, void, std::shared_ptr<ObjectModel>)
+ INGEN_SIGNAL(new_plugin, void, std::shared_ptr<PluginModel>)
+ INGEN_SIGNAL(plugin_deleted, void, URI)
+
+private:
+ std::shared_ptr<ObjectModel> _object(const raul::Path& path);
+ std::shared_ptr<PluginModel> _plugin(const URI& uri);
+ std::shared_ptr<PluginModel> _plugin(const Atom& uri);
+ std::shared_ptr<Resource> _resource(const URI& uri);
+
+ void add_object(const std::shared_ptr<ObjectModel>& object);
+ std::shared_ptr<ObjectModel> remove_object(const raul::Path& path);
+
+ void add_plugin(const std::shared_ptr<PluginModel>& pm);
+
+ std::shared_ptr<GraphModel> connection_graph(const raul::Path& tail_path,
+ const raul::Path& head_path);
+
+ // Slots for SigClientInterface signals
+ bool attempt_connection(const raul::Path& tail_path,
+ const raul::Path& head_path);
+
+ URIs& _uris;
+ Log& _log;
+ std::shared_ptr<SigClientInterface> _emitter;
+
+ std::shared_ptr<Plugins> _plugins; ///< Map, keyed by plugin URI
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_CLIENTSTORE_HPP
diff --git a/include/ingen/client/GraphModel.hpp b/include/ingen/client/GraphModel.hpp
new file mode 100644
index 00000000..0ae756d8
--- /dev/null
+++ b/include/ingen/client/GraphModel.hpp
@@ -0,0 +1,89 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_GRAPHMODEL_HPP
+#define INGEN_CLIENT_GRAPHMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/BlockModel.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+
+#include <cstdint>
+#include <memory>
+
+namespace raul {
+class Path;
+} // namespace raul
+
+namespace ingen {
+
+class URI;
+
+namespace client {
+
+class ArcModel;
+class ObjectModel;
+class PortModel;
+
+/** 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; }
+
+ std::shared_ptr<ArcModel>
+ get_arc(const ingen::Node* tail, const ingen::Node* head);
+
+ bool enabled() const;
+ bool polyphonic() const;
+ uint32_t internal_poly() const;
+
+ // Signals
+ INGEN_SIGNAL(new_block, void, std::shared_ptr<BlockModel>)
+ INGEN_SIGNAL(removed_block, void, std::shared_ptr<BlockModel>)
+ INGEN_SIGNAL(new_arc, void, std::shared_ptr<ArcModel>)
+ INGEN_SIGNAL(removed_arc, void, std::shared_ptr<ArcModel>)
+
+private:
+ friend class ClientStore;
+
+ GraphModel(URIs& uris, const raul::Path& graph_path)
+ : BlockModel(uris,
+ static_cast<const URI&>(uris.ingen_Graph),
+ graph_path)
+ {}
+
+ void clear() override;
+ void add_child(const std::shared_ptr<ObjectModel>& c) override;
+ bool remove_child(const std::shared_ptr<ObjectModel>& o) override;
+ void remove_arcs_on(const std::shared_ptr<PortModel>& p);
+
+ void add_arc(const std::shared_ptr<ArcModel>& arc);
+ void remove_arc(const ingen::Node* tail,
+ const ingen::Node* head);
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_GRAPHMODEL_HPP
diff --git a/include/ingen/client/ObjectModel.hpp b/include/ingen/client/ObjectModel.hpp
new file mode 100644
index 00000000..e92618f8
--- /dev/null
+++ b/include/ingen/client/ObjectModel.hpp
@@ -0,0 +1,100 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ @defgroup IngenClient Client-Side Models and Utilities
+*/
+
+#ifndef INGEN_CLIENT_OBJECTMODEL_HPP
+#define INGEN_CLIENT_OBJECTMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+#include "raul/Symbol.hpp"
+
+#include <memory>
+
+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; }
+
+ std::shared_ptr<ObjectModel> parent() const { return _parent; }
+ bool polyphonic() const;
+
+ Node* graph_parent() const override { return _parent.get(); }
+
+ // Signals
+ INGEN_SIGNAL(new_child, void, std::shared_ptr<ObjectModel>)
+ INGEN_SIGNAL(removed_child, void, std::shared_ptr<ObjectModel>)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(property_removed, void, const URI&, const Atom&)
+ INGEN_SIGNAL(destroyed, void)
+ INGEN_SIGNAL(moved, void)
+
+protected:
+ friend class ClientStore;
+
+ ObjectModel(URIs& uris, const raul::Path& path);
+ ObjectModel(const ObjectModel& copy);
+
+ void set_path(const raul::Path& p) override;
+ virtual void set_parent(const std::shared_ptr<ObjectModel>& p);
+ virtual void add_child(const std::shared_ptr<ObjectModel>& c) {}
+ virtual bool remove_child(const std::shared_ptr<ObjectModel>& c) { return true; }
+
+ virtual void set(const std::shared_ptr<ObjectModel>& o);
+
+ std::shared_ptr<ObjectModel> _parent;
+
+private:
+ raul::Path _path;
+ raul::Symbol _symbol;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_OBJECTMODEL_HPP
diff --git a/include/ingen/client/PluginModel.hpp b/include/ingen/client/PluginModel.hpp
new file mode 100644
index 00000000..7f86f680
--- /dev/null
+++ b/include/ingen/client/PluginModel.hpp
@@ -0,0 +1,133 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_PLUGINMODEL_HPP
+#define INGEN_CLIENT_PLUGINMODEL_HPP
+
+#include "ingen/Atom.hpp"
+#include "ingen/Forge.hpp"
+#include "ingen/Properties.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "lilv/lilv.h"
+#include "raul/Symbol.hpp"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+
+namespace Sord {
+class World;
+} // namespace Sord
+
+namespace ingen {
+
+class World;
+
+namespace client {
+
+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 index) const;
+
+ using ScalePoints = std::map<float, std::string>;
+ ScalePoints port_scale_points(uint32_t index) const;
+
+ using Presets = std::map<URI, std::string>;
+ const Presets& presets() const { return _presets; }
+
+ static LilvWorld* lilv_world() { return _lilv_world; }
+ const LilvPlugin* lilv_plugin() const { return _lilv_plugin; }
+
+ const LilvPort* lilv_port(uint32_t index) const;
+
+ static void set_lilv_world(LilvWorld* world);
+
+ bool has_ui() const;
+
+ std::shared_ptr<PluginUI>
+ ui(ingen::World& world,
+ const std::shared_ptr<const BlockModel>& block) const;
+
+ std::string documentation(bool html) const;
+ std::string port_documentation(uint32_t index, bool html) const;
+
+ static void set_rdf_world(Sord::World& world) {
+ _rdf_world = &world;
+ }
+
+ static Sord::World* rdf_world() { return _rdf_world; }
+
+ // Signals
+ INGEN_SIGNAL(changed, void)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(preset, void, const URI&, const std::string&)
+
+ bool fetched() const { return _fetched; }
+ void set_fetched(bool f) { _fetched = f; }
+
+protected:
+ friend class ClientStore;
+ void set(const std::shared_ptr<PluginModel>& p);
+
+ void add_preset(const URI& uri, const std::string& label);
+
+private:
+ static std::string get_documentation(const LilvNode* subject, bool html);
+
+ static Sord::World* _rdf_world;
+ static LilvWorld* _lilv_world;
+ static const LilvPlugins* _lilv_plugins;
+
+ Atom _type;
+ const LilvPlugin* _lilv_plugin;
+ Presets _presets;
+ bool _fetched{false};
+};
+
+} // 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..b291d521
--- /dev/null
+++ b/include/ingen/client/PluginUI.hpp
@@ -0,0 +1,119 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_PLUGINUI_HPP
+#define INGEN_CLIENT_PLUGINUI_HPP
+
+#include "signal.hpp"
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/ingen.h"
+#include "lilv/lilv.h"
+#include "suil/suil.h"
+
+#include <cstdint>
+#include <memory>
+#include <set>
+
+namespace ingen {
+
+class Atom;
+class URI;
+class World;
+
+namespace client {
+
+class BlockModel;
+
+/** Custom user interface for a plugin.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PluginUI
+{
+public:
+ ~PluginUI();
+
+ /** Create a UI for the given block and plugin.
+ *
+ * This does not actually instantiate the UI itself, so signals can be
+ * connected first. The caller should connect to signal_property_changed,
+ * then call instantiate().
+ */
+ static std::shared_ptr<PluginUI>
+ create(ingen::World& world,
+ const std::shared_ptr<const BlockModel>& block,
+ const LilvPlugin* plugin);
+
+ /** Instantiate the UI.
+ *
+ * If true is returned, instantiation was successfull and the widget can be
+ * obtained with get_widget(). Otherwise, instantiation failed, so there is
+ * no widget and the UI can not be used.
+ */
+ bool instantiate();
+ bool instantiated () { return _instance != nullptr; }
+
+ SuilWidget get_widget();
+
+ void port_event(uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+ bool is_resizable() const;
+
+ /** Signal emitted when the UI sets a property.
+ *
+ * The application must connect to this signal to communicate with the
+ * engine and/or update itself as necessary.
+ */
+ INGEN_SIGNAL(property_changed,
+ void,
+ const URI&, // Subject
+ const URI&, // Predicate
+ const Atom&, // Object
+ Resource::Graph) // Context
+
+ ingen::World& world() const { return _world; }
+ std::shared_ptr<const BlockModel> block() const { return _block; }
+
+private:
+ PluginUI(ingen::World& world,
+ std::shared_ptr<const BlockModel> block,
+ LilvUIs* uis,
+ const LilvUI* ui,
+ const LilvNode* ui_type);
+
+ ingen::World& _world;
+ std::shared_ptr<const BlockModel> _block;
+ SuilInstance* _instance{nullptr};
+ LilvUIs* _uis{nullptr};
+ const LilvUI* _ui{nullptr};
+ LilvNode* _ui_node{nullptr};
+ LilvNode* _ui_type{nullptr};
+ std::set<uint32_t> _subscribed_ports;
+
+ static SuilHost* ui_host;
+
+ std::shared_ptr<LV2Features::FeatureArray> _features;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PLUGINUI_HPP
diff --git a/include/ingen/client/PortModel.hpp b/include/ingen/client/PortModel.hpp
new file mode 100644
index 00000000..903a435d
--- /dev/null
+++ b/include/ingen/client/PortModel.hpp
@@ -0,0 +1,101 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_PORTMODEL_HPP
+#define INGEN_CLIENT_PORTMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+namespace ingen {
+
+class Atom;
+
+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;
+
+ uint32_t index() const { return _index; }
+ const Atom& value() const { return get_property(_uris.ingen_value); }
+ bool is_input() const { return (_direction == Direction::INPUT); }
+ 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;
+
+ 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 std::shared_ptr<ObjectModel>& c) override { throw; }
+ bool remove_child(const std::shared_ptr<ObjectModel>& c) override { throw; }
+
+ void set(const std::shared_ptr<ObjectModel>& model) override;
+
+ uint32_t _index;
+ Direction _direction;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PORTMODEL_HPP
diff --git a/include/ingen/client/SigClientInterface.hpp b/include/ingen/client/SigClientInterface.hpp
new file mode 100644
index 00000000..6bff2e33
--- /dev/null
+++ b/include/ingen/client/SigClientInterface.hpp
@@ -0,0 +1,59 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_SIGCLIENTINTERFACE_HPP
+#define INGEN_CLIENT_SIGCLIENTINTERFACE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+
+namespace ingen::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 ingen::client
+
+#endif
diff --git a/include/ingen/client/SocketClient.hpp b/include/ingen/client/SocketClient.hpp
new file mode 100644
index 00000000..7434da90
--- /dev/null
+++ b/include/ingen/client/SocketClient.hpp
@@ -0,0 +1,92 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_SOCKETCLIENT_HPP
+#define INGEN_CLIENT_SOCKETCLIENT_HPP
+
+#include "ingen/Log.hpp"
+#include "ingen/SocketReader.hpp"
+#include "ingen/SocketWriter.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/World.hpp"
+#include "ingen/ingen.h"
+#include "raul/Socket.hpp"
+
+#include <cerrno>
+#include <cstring>
+#include <memory>
+
+namespace ingen {
+
+class Interface;
+
+namespace client {
+
+/** The client side of an Ingen socket connection. */
+class INGEN_API SocketClient : public SocketWriter
+{
+public:
+ SocketClient(World& world,
+ const URI& uri,
+ const std::shared_ptr<raul::Socket>& sock,
+ const std::shared_ptr<Interface>& respondee)
+ : SocketWriter(world.uri_map(), world.uris(), uri, sock)
+ , _respondee(respondee)
+ , _reader(world, *respondee, sock)
+ {}
+
+ std::shared_ptr<Interface> respondee() const override {
+ return _respondee;
+ }
+
+ void set_respondee(const std::shared_ptr<Interface>& respondee) override
+ {
+ _respondee = respondee;
+ }
+
+ static std::shared_ptr<ingen::Interface>
+ new_socket_interface(ingen::World& world,
+ const URI& uri,
+ const std::shared_ptr<ingen::Interface>& respondee)
+ {
+ const raul::Socket::Type type = (uri.scheme() == "unix"
+ ? raul::Socket::Type::UNIX
+ : raul::Socket::Type::TCP);
+
+ const std::shared_ptr<raul::Socket> sock{new raul::Socket(type)};
+ if (!sock->connect(uri)) {
+ world.log().error("Failed to connect <%1%> (%2%)\n",
+ sock->uri(), strerror(errno));
+ return nullptr;
+ }
+ return std::shared_ptr<Interface>(
+ new SocketClient(world, uri, sock, respondee));
+ }
+
+ static void register_factories(World& world) {
+ world.add_interface_factory("unix", &new_socket_interface);
+ world.add_interface_factory("tcp", &new_socket_interface);
+ }
+
+private:
+ std::shared_ptr<Interface> _respondee;
+ SocketReader _reader;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_SOCKETCLIENT_HPP
diff --git a/include/ingen/client/client.h b/include/ingen/client/client.h
new file mode 100644
index 00000000..6f7ac9b5
--- /dev/null
+++ b/include/ingen/client/client.h
@@ -0,0 +1,31 @@
+/*
+ This file is part of Ingen.
+ Copyright 2014-2022 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_CLIENT_H
+#define INGEN_CLIENT_CLIENT_H
+
+#if defined(_WIN32) && !defined(INGEN_CLIENT_STATIC) && \
+ defined(INGEN_CLIENT_INTERNAL)
+# define INGEN_CLIENT_API __declspec(dllexport)
+#elif defined(_WIN32) && !defined(INGEN_CLIENT_STATIC)
+# define INGEN_CLIENT_API __declspec(dllimport)
+#elif defined(__GNUC__)
+# define INGEN_CLIENT_API __attribute__((visibility("default")))
+#else
+# define INGEN_CLIENT_API
+#endif
+
+#endif // INGEN_CLIENT_CLIENT_H
diff --git a/include/ingen/client/signal.hpp b/include/ingen/client/signal.hpp
new file mode 100644
index 00000000..ea382549
--- /dev/null
+++ b/include/ingen/client/signal.hpp
@@ -0,0 +1,34 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_CLIENT_SIGNAL_HPP
+#define INGEN_CLIENT_SIGNAL_HPP
+
+// IWYU pragma: begin_exports
+#include <sigc++/signal.h>
+#include <sigc++/trackable.h>
+// IWYU pragma: end_exports
+
+#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