summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/ArcImpl.cpp114
-rw-r--r--src/server/ArcImpl.hpp84
-rw-r--r--src/server/BlockFactory.cpp229
-rw-r--r--src/server/BlockFactory.hpp67
-rw-r--r--src/server/BlockImpl.cpp303
-rw-r--r--src/server/BlockImpl.hpp207
-rw-r--r--src/server/Broadcaster.cpp97
-rw-r--r--src/server/Broadcaster.hpp118
-rw-r--r--src/server/Buffer.cpp468
-rw-r--r--src/server/Buffer.hpp244
-rw-r--r--src/server/BufferFactory.cpp190
-rw-r--r--src/server/BufferFactory.hpp118
-rw-r--r--src/server/BufferRef.hpp38
-rw-r--r--src/server/ClientUpdate.cpp155
-rw-r--r--src/server/ClientUpdate.hpp80
-rw-r--r--src/server/CompiledGraph.cpp274
-rw-r--r--src/server/CompiledGraph.hpp84
-rw-r--r--src/server/ControlBindings.cpp425
-rw-r--r--src/server/ControlBindings.hpp148
-rw-r--r--src/server/DirectDriver.hpp108
-rw-r--r--src/server/Driver.hpp110
-rw-r--r--src/server/DuplexPort.cpp236
-rw-r--r--src/server/DuplexPort.hpp98
-rw-r--r--src/server/Engine.cpp526
-rw-r--r--src/server/Engine.hpp221
-rw-r--r--src/server/EnginePort.hpp66
-rw-r--r--src/server/Event.hpp163
-rw-r--r--src/server/EventWriter.cpp147
-rw-r--r--src/server/EventWriter.hpp86
-rw-r--r--src/server/FrameTimer.hpp110
-rw-r--r--src/server/GraphImpl.cpp379
-rw-r--r--src/server/GraphImpl.hpp200
-rw-r--r--src/server/GraphPlugin.hpp63
-rw-r--r--src/server/InputPort.cpp261
-rw-r--r--src/server/InputPort.hpp128
-rw-r--r--src/server/InternalBlock.cpp73
-rw-r--r--src/server/InternalBlock.hpp48
-rw-r--r--src/server/InternalPlugin.cpp67
-rw-r--r--src/server/InternalPlugin.hpp57
-rw-r--r--src/server/JackDriver.cpp584
-rw-r--r--src/server/JackDriver.hpp169
-rw-r--r--src/server/LV2Block.cpp742
-rw-r--r--src/server/LV2Block.hpp152
-rw-r--r--src/server/LV2Options.hpp71
-rw-r--r--src/server/LV2Plugin.cpp143
-rw-r--r--src/server/LV2Plugin.hpp72
-rw-r--r--src/server/LV2ResizeFeature.hpp65
-rw-r--r--src/server/Load.hpp57
-rw-r--r--src/server/NodeImpl.cpp50
-rw-r--r--src/server/NodeImpl.hpp109
-rw-r--r--src/server/OutputPort.hpp51
-rw-r--r--src/server/PluginImpl.hpp96
-rw-r--r--src/server/PortAudioDriver.cpp297
-rw-r--r--src/server/PortAudioDriver.hpp132
-rw-r--r--src/server/PortImpl.cpp569
-rw-r--r--src/server/PortImpl.hpp312
-rw-r--r--src/server/PortType.hpp91
-rw-r--r--src/server/PostProcessor.cpp114
-rw-r--r--src/server/PostProcessor.hpp74
-rw-r--r--src/server/PreProcessContext.hpp84
-rw-r--r--src/server/PreProcessor.cpp248
-rw-r--r--src/server/PreProcessor.hpp87
-rw-r--r--src/server/RunContext.cpp195
-rw-r--r--src/server/RunContext.hpp161
-rw-r--r--src/server/SocketListener.cpp190
-rw-r--r--src/server/SocketListener.hpp41
-rw-r--r--src/server/SocketServer.hpp80
-rw-r--r--src/server/Task.cpp158
-rw-r--r--src/server/Task.hpp120
-rw-r--r--src/server/ThreadManager.hpp68
-rw-r--r--src/server/UndoStack.cpp253
-rw-r--r--src/server/UndoStack.hpp107
-rw-r--r--src/server/Worker.cpp163
-rw-r--r--src/server/Worker.hpp76
-rw-r--r--src/server/events.hpp35
-rw-r--r--src/server/events/Connect.cpp188
-rw-r--r--src/server/events/Connect.hpp74
-rw-r--r--src/server/events/Copy.cpp216
-rw-r--r--src/server/events/Copy.hpp68
-rw-r--r--src/server/events/CreateBlock.cpp180
-rw-r--r--src/server/events/CreateBlock.hpp66
-rw-r--r--src/server/events/CreateGraph.cpp236
-rw-r--r--src/server/events/CreateGraph.hpp74
-rw-r--r--src/server/events/CreatePort.cpp219
-rw-r--r--src/server/events/CreatePort.hpp82
-rw-r--r--src/server/events/Delete.cpp216
-rw-r--r--src/server/events/Delete.hpp86
-rw-r--r--src/server/events/Delta.cpp670
-rw-r--r--src/server/events/Delta.hpp133
-rw-r--r--src/server/events/Disconnect.cpp224
-rw-r--r--src/server/events/Disconnect.hpp87
-rw-r--r--src/server/events/DisconnectAll.cpp176
-rw-r--r--src/server/events/DisconnectAll.hpp78
-rw-r--r--src/server/events/Get.cpp111
-rw-r--r--src/server/events/Get.hpp65
-rw-r--r--src/server/events/Mark.cpp112
-rw-r--r--src/server/events/Mark.hpp69
-rw-r--r--src/server/events/Move.cpp91
-rw-r--r--src/server/events/Move.hpp57
-rw-r--r--src/server/events/SetPortValue.cpp139
-rw-r--r--src/server/events/SetPortValue.hpp71
-rw-r--r--src/server/events/Undo.cpp85
-rw-r--r--src/server/events/Undo.hpp58
-rw-r--r--src/server/ingen_engine.cpp44
-rw-r--r--src/server/ingen_jack.cpp58
-rw-r--r--src/server/ingen_lv2.cpp850
-rw-r--r--src/server/ingen_portaudio.cpp54
-rw-r--r--src/server/internals/BlockDelay.cpp89
-rw-r--r--src/server/internals/BlockDelay.hpp62
-rw-r--r--src/server/internals/Controller.cpp174
-rw-r--r--src/server/internals/Controller.hpp71
-rw-r--r--src/server/internals/Note.cpp420
-rw-r--r--src/server/internals/Note.hpp109
-rw-r--r--src/server/internals/Time.cpp78
-rw-r--r--src/server/internals/Time.hpp59
-rw-r--r--src/server/internals/Trigger.cpp187
-rw-r--r--src/server/internals/Trigger.hpp75
-rw-r--r--src/server/jackey.h72
-rw-r--r--src/server/mix.cpp112
-rw-r--r--src/server/mix.hpp40
-rw-r--r--src/server/types.hpp27
-rw-r--r--src/server/util.hpp63
-rw-r--r--src/server/wscript104
123 files changed, 0 insertions, 19285 deletions
diff --git a/src/server/ArcImpl.cpp b/src/server/ArcImpl.cpp
deleted file mode 100644
index 5b96ca03..00000000
--- a/src/server/ArcImpl.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/URIs.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-
-#include "ArcImpl.hpp"
-#include "BlockImpl.hpp"
-#include "Buffer.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "InputPort.hpp"
-#include "OutputPort.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** Constructor for an arc from a block's output port.
- *
- * This handles both polyphonic and monophonic blocks, transparently to the
- * user (InputPort).
- */
-ArcImpl::ArcImpl(PortImpl* tail, PortImpl* head)
- : _tail(tail)
- , _head(head)
-{
- assert(tail != head);
- assert(tail->path() != head->path());
-}
-
-ArcImpl::~ArcImpl()
-{
- if (is_linked()) {
- InputPort* iport = dynamic_cast<InputPort*>(_head);
- if (iport) {
- iport->remove_arc(*this);
- }
- }
-}
-
-const Raul::Path&
-ArcImpl::tail_path() const
-{
- return _tail->path();
-}
-
-const Raul::Path&
-ArcImpl::head_path() const
-{
- return _head->path();
-}
-
-BufferRef
-ArcImpl::buffer(uint32_t voice, SampleCount offset) const
-{
- return _tail->buffer(std::min(voice, _tail->poly() - 1));
-}
-
-bool
-ArcImpl::must_mix() const
-{
- return (_tail->poly() > _head->poly() ||
- (_tail->buffer(0)->is_sequence() != _head->buffer(0)->is_sequence()));
-}
-
-bool
-ArcImpl::can_connect(const PortImpl* src, const InputPort* dst)
-{
- const Ingen::URIs& uris = src->bufs().uris();
- return (
- // (Audio | Control | CV) => (Audio | Control | CV)
- ( (src->is_a(PortType::ID::CONTROL) ||
- src->is_a(PortType::ID::AUDIO) ||
- src->is_a(PortType::ID::CV))
- && (dst->is_a(PortType::ID::CONTROL)
- || dst->is_a(PortType::ID::AUDIO)
- || dst->is_a(PortType::ID::CV)))
-
- // Equal types
- || (src->type() == dst->type() &&
- src->buffer_type() == dst->buffer_type())
-
- // Control => atom:Float Value
- || (src->is_a(PortType::ID::CONTROL) && dst->supports(uris.atom_Float))
-
- // Audio => atom:Sound Value
- || (src->is_a(PortType::ID::AUDIO) && dst->supports(uris.atom_Sound))
-
- // atom:Float Value => Control
- || (src->supports(uris.atom_Float) && dst->is_a(PortType::ID::CONTROL))
-
- // atom:Float Value => CV
- || (src->supports(uris.atom_Float) && dst->is_a(PortType::ID::CV))
-
- // atom:Sound Value => Audio
- || (src->supports(uris.atom_Sound) && dst->is_a(PortType::ID::AUDIO)));
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/ArcImpl.hpp b/src/server/ArcImpl.hpp
deleted file mode 100644
index 40a6d179..00000000
--- a/src/server/ArcImpl.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_ARC_IMPL_HPP
-#define INGEN_ENGINE_ARC_IMPL_HPP
-
-#include <cstdlib>
-
-#include <boost/intrusive/slist.hpp>
-
-#include "ingen/Arc.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "raul/Deletable.hpp"
-
-#include "BufferRef.hpp"
-#include "RunContext.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class PortImpl;
-class InputPort;
-
-/** Represents a single inbound connection for an InputPort.
- *
- * This can be a group of ports (coming from a polyphonic Block) or
- * a single Port. This class exists basically as an abstraction of mixing
- * down polyphonic inputs, so InputPort can just deal with mixing down
- * multiple connections (oblivious to the polyphonic situation of the
- * connection itself).
- *
- * This is stored in an intrusive slist in InputPort.
- *
- * \ingroup engine
- */
-class ArcImpl
- : private Raul::Noncopyable
- , public Arc
- , public boost::intrusive::slist_base_hook<>
-{
-public:
- ArcImpl(PortImpl* tail, PortImpl* head);
- ~ArcImpl();
-
- inline PortImpl* tail() const { return _tail; }
- inline PortImpl* head() const { return _head; }
-
- const Raul::Path& tail_path() const;
- const Raul::Path& head_path() const;
-
- /** Get the buffer for a particular voice.
- * An Arc is smart - it knows the destination port requesting the
- * buffer, and will return accordingly (e.g. the same buffer for every
- * voice in a mono->poly arc).
- */
- BufferRef buffer(uint32_t voice, SampleCount offset=0) const;
-
- /** Whether this arc must mix down voices into a local buffer */
- bool must_mix() const;
-
- static bool can_connect(const PortImpl* src, const InputPort* dst);
-
-protected:
- PortImpl* const _tail;
- PortImpl* const _head;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_ARC_IMPL_HPP
diff --git a/src/server/BlockFactory.cpp b/src/server/BlockFactory.cpp
deleted file mode 100644
index 7dcfd6af..00000000
--- a/src/server/BlockFactory.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-
-#include "lilv/lilv.h"
-
-#include "ingen/LV2Features.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/World.hpp"
-#include "internals/BlockDelay.hpp"
-#include "internals/Controller.hpp"
-#include "internals/Note.hpp"
-#include "internals/Time.hpp"
-#include "internals/Trigger.hpp"
-
-#include "BlockFactory.hpp"
-#include "InternalPlugin.hpp"
-#include "LV2Plugin.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-using namespace Internals;
-
-BlockFactory::BlockFactory(Ingen::World* world)
- : _world(world)
- , _has_loaded(false)
-{
- load_internal_plugins();
-}
-
-BlockFactory::~BlockFactory()
-{
- for (auto& p : _plugins) {
- delete p.second;
- }
-
- _plugins.clear();
-}
-
-const BlockFactory::Plugins&
-BlockFactory::plugins()
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- if (!_has_loaded) {
- load_lv2_plugins();
- _has_loaded = true;
- }
- return _plugins;
-}
-
-std::set<PluginImpl*>
-BlockFactory::refresh()
-{
- // Record current plugins, and those that are currently zombies
- const Plugins old_plugins(_plugins);
- std::set<PluginImpl*> zombies;
- for (const auto& p : _plugins) {
- if (p.second->is_zombie()) {
- zombies.insert(p.second);
- }
- }
-
- // Re-load plugins
- load_lv2_plugins();
-
- // Add any new plugins to response
- std::set<PluginImpl*> new_plugins;
- for (const auto& p : _plugins) {
- auto o = old_plugins.find(p.first);
- if (o == old_plugins.end()) {
- new_plugins.insert(p.second);
- }
- }
-
- // Add any resurrected plugins to response
- for (const auto& z : zombies) {
- if (!z->is_zombie()) {
- new_plugins.insert(z);
- }
- }
-
- return new_plugins;
-}
-
-PluginImpl*
-BlockFactory::plugin(const URI& uri)
-{
- load_plugin(uri);
- const Plugins::const_iterator i = _plugins.find(uri);
- return ((i != _plugins.end()) ? i->second : nullptr);
-}
-
-void
-BlockFactory::load_internal_plugins()
-{
- Ingen::URIs& uris = _world->uris();
- InternalPlugin* block_delay_plug = BlockDelayNode::internal_plugin(uris);
- _plugins.emplace(block_delay_plug->uri(), block_delay_plug);
-
- InternalPlugin* controller_plug = ControllerNode::internal_plugin(uris);
- _plugins.emplace(controller_plug->uri(), controller_plug);
-
- InternalPlugin* note_plug = NoteNode::internal_plugin(uris);
- _plugins.emplace(note_plug->uri(), note_plug);
-
- InternalPlugin* time_plug = TimeNode::internal_plugin(uris);
- _plugins.emplace(time_plug->uri(), time_plug);
-
- InternalPlugin* trigger_plug = TriggerNode::internal_plugin(uris);
- _plugins.emplace(trigger_plug->uri(), trigger_plug);
-}
-
-void
-BlockFactory::load_plugin(const URI& uri)
-{
- if (_has_loaded || _plugins.find(uri) != _plugins.end()) {
- return;
- }
-
- LilvNode* node = lilv_new_uri(_world->lilv_world(), uri.c_str());
- const LilvPlugins* plugs = lilv_world_get_all_plugins(_world->lilv_world());
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugs, node);
- if (plug) {
- LV2Plugin* const ingen_plugin = new LV2Plugin(_world, plug);
- _plugins.emplace(uri, ingen_plugin);
- }
- lilv_node_free(node);
-}
-
-/** Loads information about all LV2 plugins into internal plugin database.
- */
-void
-BlockFactory::load_lv2_plugins()
-{
- // Build an array of port type nodes for checking compatibility
- typedef std::vector< SPtr<LilvNode> > Types;
- Types types;
- for (unsigned t = PortType::ID::AUDIO; t <= PortType::ID::ATOM; ++t) {
- const URI& uri(PortType((PortType::ID)t).uri());
- types.push_back(
- SPtr<LilvNode>(lilv_new_uri(_world->lilv_world(), uri.c_str()),
- lilv_node_free));
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(_world->lilv_world());
- LILV_FOREACH(plugins, i, plugins) {
- const LilvPlugin* lv2_plug = lilv_plugins_get(plugins, i);
- const URI uri(lilv_node_as_uri(lilv_plugin_get_uri(lv2_plug)));
-
- // Ignore plugins that require features Ingen doesn't support
- LilvNodes* features = lilv_plugin_get_required_features(lv2_plug);
- bool supported = true;
- LILV_FOREACH(nodes, f, features) {
- const char* feature = lilv_node_as_uri(lilv_nodes_get(features, f));
- if (!_world->lv2_features().is_supported(feature)) {
- supported = false;
- _world->log().warn(
- fmt("Ignoring <%1%>; required feature <%2%>\n")
- % uri % feature);
- break;
- }
- }
- lilv_nodes_free(features);
- if (!supported) {
- continue;
- }
-
- // Ignore plugins that are missing ports
- if (!lilv_plugin_get_port_by_index(lv2_plug, 0)) {
- _world->log().warn(
- fmt("Ignoring <%1%>; missing or corrupt ports\n") % uri);
- continue;
- }
-
- const uint32_t n_ports = lilv_plugin_get_num_ports(lv2_plug);
- for (uint32_t p = 0; p < n_ports; ++p) {
- const LilvPort* port = lilv_plugin_get_port_by_index(lv2_plug, p);
- supported = false;
- for (const auto& t : types) {
- if (lilv_port_is_a(lv2_plug, port, t.get())) {
- supported = true;
- break;
- }
- }
- if (!supported &&
- !lilv_port_has_property(lv2_plug,
- port,
- _world->uris().lv2_connectionOptional)) {
- _world->log().warn(
- fmt("Ignoring <%1%>; unsupported port <%2%>\n")
- % uri % lilv_node_as_string(
- lilv_port_get_symbol(lv2_plug, port)));
- break;
- }
- }
- if (!supported) {
- continue;
- }
-
- auto p = _plugins.find(uri);
- if (p == _plugins.end()) {
- LV2Plugin* const plugin = new LV2Plugin(_world, lv2_plug);
- _plugins.emplace(uri, plugin);
- } else if (lilv_plugin_verify(lv2_plug)) {
- p->second->set_is_zombie(false);
- }
- }
-
- _world->log().info(fmt("Loaded %1% plugins\n") % _plugins.size());
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/BlockFactory.hpp b/src/server/BlockFactory.hpp
deleted file mode 100644
index 25885f75..00000000
--- a/src/server/BlockFactory.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BLOCKFACTORY_HPP
-#define INGEN_ENGINE_BLOCKFACTORY_HPP
-
-#include <map>
-#include <set>
-
-#include "ingen/World.hpp"
-#include "ingen/types.hpp"
-#include "raul/Noncopyable.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class PluginImpl;
-
-/** Discovers and loads plugin libraries.
- *
- * \ingroup engine
- */
-class BlockFactory : public Raul::Noncopyable
-{
-public:
- explicit BlockFactory(Ingen::World* world);
- ~BlockFactory();
-
- /** Reload plugin list.
- *
- * @return The set of newly loaded plugins.
- */
- std::set<PluginImpl*> refresh();
-
- void load_plugin(const URI& uri);
-
- typedef std::map<URI, PluginImpl*> Plugins;
- const Plugins& plugins();
-
- PluginImpl* plugin(const URI& uri);
-
-private:
- void load_lv2_plugins();
- void load_internal_plugins();
-
- Plugins _plugins;
- Ingen::World* _world;
- bool _has_loaded;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BLOCKFACTORY_HPP
diff --git a/src/server/BlockImpl.cpp b/src/server/BlockImpl.cpp
deleted file mode 100644
index e95645f9..00000000
--- a/src/server/BlockImpl.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <cstdint>
-
-#include "raul/Array.hpp"
-
-#include "Buffer.hpp"
-#include "Engine.hpp"
-#include "BlockImpl.hpp"
-#include "GraphImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortImpl.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-BlockImpl::BlockImpl(PluginImpl* plugin,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
- : NodeImpl(plugin->uris(), parent, symbol)
- , _plugin(plugin)
- , _polyphony((polyphonic && parent) ? parent->internal_poly() : 1)
- , _mark(Mark::UNVISITED)
- , _polyphonic(polyphonic)
- , _activated(false)
- , _enabled(true)
-{
- assert(_plugin);
- assert(_polyphony > 0);
-}
-
-BlockImpl::~BlockImpl()
-{
- if (_activated) {
- deactivate();
- }
-
- if (is_linked()) {
- parent_graph()->remove_block(*this);
- }
-}
-
-Node*
-BlockImpl::port(uint32_t index) const
-{
- return (*_ports)[index];
-}
-
-const Resource*
-BlockImpl::plugin() const
-{
- return _plugin;
-}
-
-const PluginImpl*
-BlockImpl::plugin_impl() const
-{
- return _plugin;
-}
-
-void
-BlockImpl::activate(BufferFactory& bufs)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- _activated = true;
- for (uint32_t p = 0; p < num_ports(); ++p) {
- PortImpl* const port = _ports->at(p);
- port->activate(bufs);
- }
-}
-
-void
-BlockImpl::deactivate()
-{
- _activated = false;
- for (uint32_t p = 0; p < num_ports(); ++p) {
- PortImpl* const port = _ports->at(p);
- port->deactivate();
- }
-}
-
-bool
-BlockImpl::prepare_poly(BufferFactory& bufs, uint32_t poly)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- if (!_polyphonic) {
- poly = 1;
- }
-
- if (_ports) {
- for (uint32_t i = 0; i < _ports->size(); ++i) {
- _ports->at(i)->prepare_poly(bufs, poly);
- }
- }
-
- return true;
-}
-
-bool
-BlockImpl::apply_poly(RunContext& context, uint32_t poly)
-{
- if (!_polyphonic) {
- poly = 1;
- }
-
- _polyphony = poly;
-
- if (_ports) {
- for (uint32_t i = 0; i < num_ports(); ++i) {
- _ports->at(i)->apply_poly(context, poly);
- }
- }
-
- return true;
-}
-
-void
-BlockImpl::set_buffer_size(RunContext& context,
- BufferFactory& bufs,
- LV2_URID type,
- uint32_t size)
-{
- if (_ports) {
- for (uint32_t i = 0; i < _ports->size(); ++i) {
- PortImpl* const p = _ports->at(i);
- if (p->buffer_type() == type) {
- p->set_buffer_size(context, bufs, size);
- }
- }
- }
-}
-
-PortImpl*
-BlockImpl::nth_port_by_type(uint32_t n, bool input, PortType type)
-{
- uint32_t count = 0;
- for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
- PortImpl* const port = _ports->at(i);
- if (port->is_input() == input && port->type() == type) {
- if (count++ == n) {
- return port;
- }
- }
- }
- return nullptr;
-}
-
-PortImpl*
-BlockImpl::port_by_symbol(const char* symbol)
-{
- for (uint32_t p = 0; _ports && p < _ports->size(); ++p) {
- if (_ports->at(p)->symbol() == symbol) {
- return _ports->at(p);
- }
- }
- return nullptr;
-}
-
-void
-BlockImpl::pre_process(RunContext& context)
-{
- // Mix down input ports
- for (uint32_t i = 0; i < num_ports(); ++i) {
- PortImpl* const port = _ports->at(i);
- port->pre_process(context);
- port->connect_buffers();
- }
-}
-
-void
-BlockImpl::bypass(RunContext& context)
-{
- if (!_ports) {
- return;
- }
-
- // Prepare port buffers for reading, converting/mixing if necessary
- for (uint32_t i = 0; i < _ports->size(); ++i) {
- _ports->at(i)->connect_buffers();
- _ports->at(i)->pre_run(context);
- }
-
- // Dumb bypass
- for (PortType t : { PortType::AUDIO, PortType::CV, PortType::ATOM }) {
- for (uint32_t i = 0;; ++i) {
- PortImpl* in = nth_port_by_type(i, true, t);
- PortImpl* out = nth_port_by_type(i, false, t);
- if (!out) {
- break; // Finished writing all outputs
- } else if (in) {
- // Copy corresponding input to output
- for (uint32_t v = 0; v < _polyphony; ++v) {
- out->buffer(v)->copy(context, in->buffer(v).get());
- }
- } else {
- // Output but no corresponding input, clear
- for (uint32_t v = 0; v < _polyphony; ++v) {
- out->buffer(v)->clear();
- }
- }
- }
- }
- post_process(context);
-}
-
-void
-BlockImpl::process(RunContext& context)
-{
- pre_process(context);
-
- if (!_enabled) {
- bypass(context);
- post_process(context);
- return;
- }
-
- RunContext subcontext(context);
- for (SampleCount offset = 0; offset < context.nframes();) {
- // Find earliest offset of a value change
- SampleCount chunk_end = context.nframes();
- for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
- PortImpl* const port = _ports->at(i);
- if (port->type() == PortType::CONTROL && port->is_input()) {
- const SampleCount o = port->next_value_offset(
- offset, context.nframes());
- if (o < chunk_end) {
- chunk_end = o;
- }
- }
- }
-
- // Slice context into a chunk from now until the next change
- subcontext.slice(offset, chunk_end - offset);
-
- // Prepare port buffers for reading, converting/mixing if necessary
- for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
- _ports->at(i)->connect_buffers(offset);
- _ports->at(i)->pre_run(subcontext);
- }
-
- // Run the chunk
- run(subcontext);
-
- // Emit control port outputs as events
- for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
- PortImpl* const port = _ports->at(i);
- if (port->type() == PortType::CONTROL && port->is_output()) {
- // TODO: Only emit events when value has actually changed?
- for (uint32_t v = 0; v < _polyphony; ++v) {
- port->buffer(v)->append_event(offset, port->buffer(v)->value());
- }
- }
- }
-
- offset = chunk_end;
- subcontext.slice(offset, chunk_end - offset);
- }
-
- post_process(context);
-}
-
-void
-BlockImpl::post_process(RunContext& context)
-{
- // Write output ports
- for (uint32_t i = 0; _ports && i < _ports->size(); ++i) {
- _ports->at(i)->post_process(context);
- }
-}
-
-void
-BlockImpl::set_port_buffer(uint32_t voice,
- uint32_t port_num,
- BufferRef buf,
- SampleCount offset)
-{
- /*std::cout << path() << " set port " << port_num << " voice " << voice
- << " buffer " << buf << " offset " << offset << std::endl;*/
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/BlockImpl.hpp b/src/server/BlockImpl.hpp
deleted file mode 100644
index d663e319..00000000
--- a/src/server/BlockImpl.hpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BLOCKIMPL_HPP
-#define INGEN_ENGINE_BLOCKIMPL_HPP
-
-#include <set>
-
-#include <boost/intrusive/slist.hpp>
-#include <boost/optional.hpp>
-
-#include "lilv/lilv.h"
-
-#include "raul/Array.hpp"
-
-#include "BufferRef.hpp"
-#include "NodeImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortType.hpp"
-#include "RunContext.hpp"
-#include "types.hpp"
-
-namespace Raul {
-class Maid;
-}
-
-namespace Ingen {
-namespace Server {
-
-class Buffer;
-class BufferFactory;
-class Engine;
-class GraphImpl;
-class PluginImpl;
-class PortImpl;
-class RunContext;
-class Worker;
-
-/** A Block in a Graph (which is also a Block).
- *
- * This is what is often called a "Module" in modular synthesizers. A Block is
- * a unit with input/output ports, a process() method, and some other things.
- *
- * \ingroup engine
- */
-class BlockImpl : public NodeImpl
- , public boost::intrusive::slist_base_hook<> // In GraphImpl
-{
-public:
- typedef Raul::Array<PortImpl*> Ports;
-
- BlockImpl(PluginImpl* plugin,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate rate);
-
- virtual ~BlockImpl();
-
- virtual GraphType graph_type() const { return GraphType::BLOCK; }
-
- /** Activate this Block.
- *
- * This function must be called in a non-realtime thread before it is
- * inserted in to a graph. Any non-realtime actions that need to be
- * done before the Block is ready for use should be done here.
- */
- virtual void activate(BufferFactory& bufs);
-
- /** Deactivate this Block.
- *
- * This function must be called in a non-realtime thread after the
- * block has been removed from its graph (i.e. processing is finished).
- */
- virtual void deactivate();
-
- /** Duplicate this Node. */
- virtual BlockImpl* duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent) { return nullptr; }
-
- /** Return true iff this block is activated */
- bool activated() const { return _activated; }
-
- /** Return true iff this block is enabled (not bypassed). */
- bool enabled() const { return _enabled; }
-
- /** Enable or disable (bypass) this block. */
- void set_enabled(bool e) { _enabled = e; }
-
- /** Load a preset from the world for this block. */
- virtual LilvState* load_preset(const URI& uri) { return nullptr; }
-
- /** Restore `state`. */
- virtual void apply_state(const UPtr<Worker>& worker, const LilvState* state) {}
-
- /** Save current state as preset. */
- virtual boost::optional<Resource>
- save_preset(const URI& bundle,
- const Properties& props) { return boost::optional<Resource>(); }
-
- /** Learn the next incoming MIDI event (for internals) */
- virtual void learn() {}
-
- /** Do whatever needs doing in the process thread before process() is called */
- virtual void pre_process(RunContext& context);
-
- /** Run block for an entire process cycle (calls run()). */
- virtual void process(RunContext& context);
-
- /** Bypass block for an entire process cycle (called from process()). */
- virtual void bypass(RunContext& context);
-
- /** Run block for a portion of process cycle (called from process()). */
- virtual void run(RunContext& context) = 0;
-
- /** Do whatever needs doing in the process thread after process() is called */
- virtual void post_process(RunContext& context);
-
- /** Set the buffer of a port to a given buffer (e.g. connect plugin to buffer) */
- virtual void set_port_buffer(uint32_t voice,
- uint32_t port_num,
- BufferRef buf,
- SampleCount offset);
-
- virtual Node* port(uint32_t index) const;
- virtual PortImpl* port_impl(uint32_t index) const { return (*_ports)[index]; }
-
- /** Get a port by symbol. */
- virtual PortImpl* port_by_symbol(const char* symbol);
-
- /** Blocks that are connected to this Block's inputs. */
- std::set<BlockImpl*>& providers() { return _providers; }
-
- /** Blocks that are connected to this Block's outputs. */
- std::set<BlockImpl*>& dependants() { return _dependants; }
-
- /** Flag block as polyphonic.
- *
- * Note this will not actually allocate voices etc., prepare_poly
- * and apply_poly must be called after this function to truly make
- * a block polyphonic.
- */
- virtual void set_polyphonic(bool p) { _polyphonic = p; }
-
- virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly);
- virtual bool apply_poly(RunContext& context, uint32_t poly);
-
- /** Information about the Plugin this Block is an instance of.
- * Not the best name - not all blocks come from plugins (ie Graph)
- */
- virtual const Resource* plugin() const;
-
- /** Information about the Plugin this Block is an instance of.
- * Not the best name - not all blocks come from plugins (ie Graph)
- */
- virtual const PluginImpl* plugin_impl() const;
-
- virtual void plugin(PluginImpl* pi) { _plugin = pi; }
-
- virtual void set_buffer_size(RunContext& context,
- BufferFactory& bufs,
- LV2_URID type,
- uint32_t size);
-
- /** The Graph this Block belongs to. */
- inline GraphImpl* parent_graph() const { return (GraphImpl*)_parent; }
-
- uint32_t num_ports() const { return _ports ? _ports->size() : 0; }
- virtual uint32_t polyphony() const { return _polyphony; }
-
- /** Mark used during graph compilation */
- enum class Mark { UNVISITED, VISITING, VISITED };
- Mark get_mark() const { return _mark; }
- void set_mark(Mark m) { _mark = m; }
-
-protected:
- PortImpl* nth_port_by_type(uint32_t n, bool input, PortType type);
-
- PluginImpl* _plugin;
- MPtr<Ports> _ports; ///< Access in audio thread only
- uint32_t _polyphony;
- std::set<BlockImpl*> _providers; ///< Blocks connected to this one's input ports
- std::set<BlockImpl*> _dependants; ///< Blocks this one's output ports are connected to
- Mark _mark; ///< Mark for graph compilation algorithm
- bool _polyphonic;
- bool _activated;
- bool _enabled;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BLOCKIMPL_HPP
diff --git a/src/server/Broadcaster.cpp b/src/server/Broadcaster.cpp
deleted file mode 100644
index 00fefddd..00000000
--- a/src/server/Broadcaster.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <utility>
-
-#include "ingen/Interface.hpp"
-
-#include "Broadcaster.hpp"
-#include "PluginImpl.hpp"
-#include "BlockFactory.hpp"
-
-namespace Ingen {
-namespace Server {
-
-Broadcaster::Broadcaster()
- : _must_broadcast(false)
- , _bundle_depth(0)
-{}
-
-Broadcaster::~Broadcaster()
-{
- std::lock_guard<std::mutex> lock(_clients_mutex);
- _clients.clear();
- _broadcastees.clear();
-}
-
-/** Register a client to receive messages over the notification band.
- */
-void
-Broadcaster::register_client(SPtr<Interface> client)
-{
- std::lock_guard<std::mutex> lock(_clients_mutex);
- _clients.insert(client);
-}
-
-/** Remove a client from the list of registered clients.
- *
- * @return true if client was found and removed.
- */
-bool
-Broadcaster::unregister_client(SPtr<Interface> client)
-{
- std::lock_guard<std::mutex> lock(_clients_mutex);
- const size_t erased = _clients.erase(client);
- _broadcastees.erase(client);
- return (erased > 0);
-}
-
-void
-Broadcaster::set_broadcast(SPtr<Interface> client, bool broadcast)
-{
- if (broadcast) {
- _broadcastees.insert(client);
- } else {
- _broadcastees.erase(client);
- }
- _must_broadcast.store(!_broadcastees.empty());
-}
-
-void
-Broadcaster::send_plugins(const BlockFactory::Plugins& plugins)
-{
- std::lock_guard<std::mutex> lock(_clients_mutex);
- for (const auto& c : _clients) {
- send_plugins_to(c.get(), plugins);
- }
-}
-
-void
-Broadcaster::send_plugins_to(Interface* client,
- const BlockFactory::Plugins& plugins)
-{
- client->bundle_begin();
-
- for (const auto& p : plugins) {
- const PluginImpl* const plugin = p.second;
- client->put(plugin->uri(), plugin->properties());
- }
-
- client->bundle_end();
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/Broadcaster.hpp b/src/server/Broadcaster.hpp
deleted file mode 100644
index 3981b265..00000000
--- a/src/server/Broadcaster.hpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BROADCASTER_HPP
-#define INGEN_ENGINE_BROADCASTER_HPP
-
-#include <atomic>
-#include <list>
-#include <mutex>
-#include <set>
-#include <string>
-
-#include "ingen/Interface.hpp"
-#include "ingen/types.hpp"
-
-#include "BlockFactory.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** Broadcaster for all clients.
- *
- * This is an Interface that forwards all messages to all registered
- * clients (for updating all clients on state changes in the engine).
- *
- * \ingroup engine
- */
-class Broadcaster : public Interface
-{
-public:
- Broadcaster();
- ~Broadcaster();
-
- void register_client(SPtr<Interface> client);
- bool unregister_client(SPtr<Interface> client);
-
- void set_broadcast(SPtr<Interface> client, bool broadcast);
-
- /** Ignore a client when broadcasting.
- *
- * This is used to prevent feeding back updates to the client that
- * initiated a property set in the first place.
- */
- void set_ignore_client(SPtr<Interface> client) { _ignore_client = client; }
- void clear_ignore_client() { _ignore_client.reset(); }
-
- /** Return true iff there are any clients with broadcasting enabled.
- *
- * This is used in the audio thread to decide whether or not notifications
- * should be calculated and emitted.
- */
- bool must_broadcast() const { return _must_broadcast; }
-
- /** A handle that represents a transfer of possibly several changes.
- *
- * This object going out of scope signifies the transfer is completed.
- * This makes doing the right thing in recursive functions that send
- * updates simple (e.g. Event::post_process()).
- */
- class Transfer : public Raul::Noncopyable {
- public:
- explicit Transfer(Broadcaster& b) : broadcaster(b) {
- if (++broadcaster._bundle_depth == 1) {
- broadcaster.bundle_begin();
- }
- }
- ~Transfer() {
- if (--broadcaster._bundle_depth == 0) {
- broadcaster.bundle_end();
- }
- }
- Broadcaster& broadcaster;
- };
-
- void send_plugins(const BlockFactory::Plugins& plugins);
- void send_plugins_to(Interface*, const BlockFactory::Plugins& plugins);
-
- void message(const Message& msg) override {
- std::lock_guard<std::mutex> lock(_clients_mutex);
- for (const auto& c : _clients) {
- if (c != _ignore_client) {
- c->message(msg);
- }
- }
- }
-
- URI uri() const override { return URI("ingen:/broadcaster"); }
-
-private:
- friend class Transfer;
-
- typedef std::set<SPtr<Interface>> Clients;
-
- std::mutex _clients_mutex;
- Clients _clients;
- std::set< SPtr<Interface> > _broadcastees;
- std::atomic<bool> _must_broadcast;
- unsigned _bundle_depth;
- SPtr<Interface> _ignore_client;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BROADCASTER_HPP
diff --git a/src/server/Buffer.cpp b/src/server/Buffer.cpp
deleted file mode 100644
index 34867fa3..00000000
--- a/src/server/Buffer.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- 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/>.
-*/
-
-#define __STDC_LIMIT_MACROS 1
-
-#include <cmath>
-#include <cstdint>
-#include <cstring>
-#include <new>
-
-#ifdef __SSE__
-# include <xmmintrin.h>
-#endif
-
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen_config.h"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "ingen/Log.hpp"
-
-#include "Buffer.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "RunContext.hpp"
-
-namespace Ingen {
-namespace Server {
-
-Buffer::Buffer(BufferFactory& bufs,
- LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity,
- bool external,
- void* buf)
- : _factory(bufs)
- , _next(nullptr)
- , _buf(external ? nullptr : aligned_alloc(capacity))
- , _latest_event(0)
- , _type(type)
- , _value_type(value_type)
- , _capacity(capacity)
- , _refs(0)
- , _external(external)
-{
- if (!external && !_buf) {
- bufs.engine().log().rt_error("Failed to allocate buffer\n");
- throw std::bad_alloc();
- }
-
- if (type != bufs.uris().atom_Sound) {
- /* Audio buffers are not atoms, the buffer is the start of a float
- array which is already silent since the buffer is zeroed. All other
- buffers are atoms. */
- if (_buf) {
- LV2_Atom* atom = get<LV2_Atom>();
- atom->size = capacity - sizeof(LV2_Atom);
- atom->type = type;
-
- clear();
- }
-
- if (value_type && value_type != type) {
- /* Buffer with a different value type. These buffers (probably
- sequences) have a "value" that persists independently of the buffer
- contents. This is used to represent things like a Sequence of
- Float, which acts like an individual float (has a value), but the
- buffer itself only transmits changes and does not necessarily
- contain the current value. */
- _value_buffer = bufs.get_buffer(value_type, 0, 0);
- }
- }
-}
-
-Buffer::~Buffer()
-{
- if (!_external) {
- free(_buf);
- }
-}
-
-void
-Buffer::recycle()
-{
- _factory.recycle(this);
-}
-
-void
-Buffer::set_type(GetFn get, LV2_URID type, LV2_URID value_type)
-{
- _type = type;
- _value_type = value_type;
- if (type == _factory.uris().atom_Sequence && value_type) {
- _value_buffer = (_factory.*get)(value_type, 0, 0);
- }
-}
-
-void
-Buffer::clear()
-{
- if (is_audio() && _buf) {
- memset(_buf, 0, _capacity);
- } else if (is_control()) {
- get<LV2_Atom_Float>()->body = 0;
- } else if (is_sequence()) {
- LV2_Atom_Sequence* seq = get<LV2_Atom_Sequence>();
- seq->atom.type = _factory.uris().atom_Sequence;
- seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
- seq->body.unit = 0;
- seq->body.pad = 0;
- _latest_event = 0;
- }
-}
-
-void
-Buffer::render_sequence(const RunContext& context, const Buffer* src, bool add)
-{
- const LV2_URID atom_Float = _factory.uris().atom_Float;
- const LV2_Atom_Sequence* seq = src->get<const LV2_Atom_Sequence>();
- const LV2_Atom_Float* init = (const LV2_Atom_Float*)src->value();
- float value = init ? init->body : 0.0f;
- SampleCount offset = context.offset();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->time.frames >= offset && ev->body.type == atom_Float) {
- write_block(value, offset, ev->time.frames, add);
- value = ((const LV2_Atom_Float*)&ev->body)->body;
- offset = ev->time.frames;
- }
- }
- write_block(value, offset, context.offset() + context.nframes(), add);
-}
-
-void
-Buffer::copy(const RunContext& context, const Buffer* src)
-{
- if (!_buf) {
- return;
- } else if (_type == src->type()) {
- const uint32_t src_size = src->size();
- if (src_size <= _capacity) {
- memcpy(_buf, src->_buf, src_size);
- } else {
- clear();
- }
- } else if (src->is_audio() && is_control()) {
- samples()[0] = src->samples()[0];
- } else if (src->is_control() && is_audio()) {
- set_block(src->samples()[0], 0, context.nframes());
- } else if (src->is_sequence() && is_audio() &&
- src->value_type() == _factory.uris().atom_Float) {
- render_sequence(context, src, false);
- } else {
- clear();
- }
-}
-
-void
-Buffer::resize(uint32_t capacity)
-{
- if (!_external) {
- _buf = realloc(_buf, capacity);
- _capacity = capacity;
- clear();
- } else {
- _factory.engine().log().error("Attempt to resize external buffer\n");
- }
-}
-
-void*
-Buffer::port_data(PortType port_type, SampleCount offset)
-{
- switch (port_type.id()) {
- case PortType::ID::CONTROL:
- return &_value_buffer->get<LV2_Atom_Float>()->body;
- case PortType::ID::CV:
- case PortType::ID::AUDIO:
- if (_type == _factory.uris().atom_Float) {
- return &get<LV2_Atom_Float>()->body;
- } else if (_type == _factory.uris().atom_Sound) {
- return (Sample*)_buf + offset;
- }
- break;
- case PortType::ID::ATOM:
- if (_type != _factory.uris().atom_Sound) {
- return _buf;
- }
- default: break;
- }
- return nullptr;
-}
-
-const void*
-Buffer::port_data(PortType port_type, SampleCount offset) const
-{
- return const_cast<void*>(
- const_cast<Buffer*>(this)->port_data(port_type, offset));
-}
-
-#ifdef __SSE__
-/** Vector fabsf */
-static inline __m128
-mm_abs_ps(__m128 x)
-{
- const __m128 sign_mask = _mm_set1_ps(-0.0f); // -0.0f = 1 << 31
- return _mm_andnot_ps(sign_mask, x);
-}
-#endif
-
-float
-Buffer::peak(const RunContext& context) const
-{
-#ifdef __SSE__
- const __m128* const vbuf = (const __m128*)samples();
- __m128 vpeak = mm_abs_ps(vbuf[0]);
- const SampleCount nblocks = context.nframes() / 4;
-
- // First, find the vector absolute max of the buffer
- for (SampleCount i = 1; i < nblocks; ++i) {
- vpeak = _mm_max_ps(vpeak, mm_abs_ps(vbuf[i]));
- }
-
- // Now we need the single max of vpeak
- // vpeak = ABCD
- // tmp = CDAB
- __m128 tmp = _mm_shuffle_ps(vpeak, vpeak, _MM_SHUFFLE(2, 3, 0, 1));
-
- // vpeak = MAX(A,C) MAX(B,D) MAX(C,A) MAX(D,B)
- vpeak = _mm_max_ps(vpeak, tmp);
-
- // tmp = BADC of the new vpeak
- // tmp = MAX(B,D) MAX(A,C) MAX(D,B) MAX(C,A)
- tmp = _mm_shuffle_ps(vpeak, vpeak, _MM_SHUFFLE(1, 0, 3, 2));
-
- // vpeak = MAX(MAX(A,C), MAX(B,D)), ...
- vpeak = _mm_max_ps(vpeak, tmp);
-
- // peak = vpeak[0]
- float peak;
- _mm_store_ss(&peak, vpeak);
-
- return peak;
-#else
- const Sample* const buf = samples();
- float peak = 0.0f;
- for (SampleCount i = 0; i < context.nframes(); ++i) {
- peak = fmaxf(peak, fabsf(buf[i]));
- }
- return peak;
-#endif
-}
-
-void
-Buffer::prepare_write(RunContext& context)
-{
- if (_type == _factory.uris().atom_Sequence) {
- LV2_Atom* atom = get<LV2_Atom>();
-
- atom->type = (LV2_URID)_factory.uris().atom_Sequence;
- atom->size = sizeof(LV2_Atom_Sequence_Body);
- _latest_event = 0;
- }
-}
-
-void
-Buffer::prepare_output_write(RunContext& context)
-{
- if (_type == _factory.uris().atom_Sequence) {
- LV2_Atom* atom = get<LV2_Atom>();
-
- atom->type = (LV2_URID)_factory.uris().atom_Chunk;
- atom->size = _capacity - sizeof(LV2_Atom);
- _latest_event = 0;
- }
-}
-
-bool
-Buffer::append_event(int64_t frames,
- uint32_t size,
- uint32_t type,
- const uint8_t* data)
-{
- assert(frames >= _latest_event);
-
- LV2_Atom* atom = get<LV2_Atom>();
- if (atom->type == _factory.uris().atom_Chunk) {
- clear(); // Chunk initialized with prepare_output_write(), clear
- }
-
- if (sizeof(LV2_Atom) + atom->size + lv2_atom_pad_size(size) > _capacity) {
- return false;
- }
-
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)atom;
- LV2_Atom_Event* ev = (LV2_Atom_Event*)(
- (uint8_t*)seq + lv2_atom_total_size(&seq->atom));
-
- ev->time.frames = frames;
- ev->body.size = size;
- ev->body.type = type;
- memcpy(ev + 1, data, size);
-
- atom->size += sizeof(LV2_Atom_Event) + lv2_atom_pad_size(size);
-
- _latest_event = frames;
-
- return true;
-}
-
-bool
-Buffer::append_event(int64_t frames, const LV2_Atom* body)
-{
- return append_event(frames, body->size, body->type, (const uint8_t*)(body + 1));
-}
-
-bool
-Buffer::append_event_buffer(const Buffer* buf)
-{
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)get<LV2_Atom>();
- LV2_Atom_Sequence* bseq = (LV2_Atom_Sequence*)buf->get<LV2_Atom>();
- if (seq->atom.type == _factory.uris().atom_Chunk) {
- clear(); // Chunk initialized with prepare_output_write(), clear
- }
-
- const uint32_t total_size = lv2_atom_total_size(&seq->atom);
- uint8_t* const end = (uint8_t*)seq + total_size;
- const uint32_t n_bytes = bseq->atom.size - sizeof(bseq->body);
- if (sizeof(LV2_Atom) + total_size + n_bytes >= _capacity) {
- return false; // Not enough space
- }
-
- memcpy(end, bseq + 1, n_bytes);
- seq->atom.size += n_bytes;
-
- _latest_event = std::max(_latest_event, buf->_latest_event);
-
- return true;
-}
-
-SampleCount
-Buffer::next_value_offset(SampleCount offset, SampleCount end) const
-{
- if (_type == _factory.uris().atom_Sequence && _value_type) {
- const LV2_Atom_Sequence* seq = get<const LV2_Atom_Sequence>();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->time.frames > offset &&
- ev->time.frames < end &&
- ev->body.type == _value_type) {
- return ev->time.frames;
- }
- }
- }
-
- /* For CV buffers, it's possible to scan for a value change here, which for
- stepped CV would do the right thing, but in the worst case (e.g. with
- sine waves), when connected to a control port would split the cycle for
- every frame which isn't feasible. Instead, just return end, so the
- cycle will not be split.
-
- A plugin that takes CV and emits discrete change events, possibly with a
- maximum rate or fuzz factor, would allow the user to choose which
- behaviour, at the cost of some overhead.
- */
-
- return end;
-}
-
-const LV2_Atom*
-Buffer::value() const
-{
- return _value_buffer ? _value_buffer->get<const LV2_Atom>() : nullptr;
-}
-
-void
-Buffer::set_value(const Atom& value)
-{
- if (!value.is_valid() || !_value_buffer) {
- return;
- }
-
- const uint32_t total_size = sizeof(LV2_Atom) + value.size();
- if (total_size > _value_buffer->capacity()) {
- _value_buffer = _factory.claim_buffer(value.type(), 0, total_size);
- }
-
- memcpy(_value_buffer->get<LV2_Atom*>(), value.atom(), total_size);
-}
-
-void
-Buffer::update_value_buffer(SampleCount offset)
-{
- if (!_value_buffer || !_value_type) {
- return;
- }
-
- LV2_Atom_Sequence* seq = get<LV2_Atom_Sequence>();
- LV2_Atom_Event* latest = nullptr;
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->time.frames > offset) {
- break;
- } else if (ev->body.type == _value_type) {
- latest = ev;
- }
- }
-
- if (latest) {
- memcpy(_value_buffer->get<LV2_Atom>(),
- &latest->body,
- lv2_atom_total_size(&latest->body));
- }
-}
-
-#ifndef NDEBUG
-void
-Buffer::dump_cv(const RunContext& context) const
-{
- float value = samples()[0];
- fprintf(stderr, "{ 0000: %.02f\n", value);
- for (uint32_t i = 0; i < context.nframes(); ++i) {
- if (samples()[i] != value) {
- value = samples()[i];
- fprintf(stderr, " %4d: %.02f\n", i, value);
- }
- }
- fprintf(stderr, "}\n");
-}
-#endif
-
-void* Buffer::aligned_alloc(size_t size)
-{
-#ifdef HAVE_POSIX_MEMALIGN
- void* buf;
- if (!posix_memalign((void**)&buf, 16, size)) {
- memset(buf, 0, size);
- return buf;
- }
-#else
- return (LV2_buf*)calloc(1, size);
-#endif
- return nullptr;
-}
-
-void
-intrusive_ptr_add_ref(Buffer* b)
-{
- b->ref();
-}
-
-void
-intrusive_ptr_release(Buffer* b)
-{
- b->deref();
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/Buffer.hpp b/src/server/Buffer.hpp
deleted file mode 100644
index a95fcd3c..00000000
--- a/src/server/Buffer.hpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BUFFER_HPP
-#define INGEN_ENGINE_BUFFER_HPP
-
-#include <atomic>
-#include <cassert>
-
-#include "ingen/types.hpp"
-#include "ingen/ingen.h"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "raul/Deletable.hpp"
-
-#include "BufferFactory.hpp"
-#include "PortType.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BufferFactory;
-class Engine;
-class RunContext;
-
-class INGEN_API Buffer
-{
-public:
- Buffer(BufferFactory& bufs,
- LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity,
- bool external = false,
- void* buf = nullptr);
-
- Buffer(const Buffer&) = delete;
- Buffer& operator=(const Buffer&) = delete;
-
- void clear();
- void resize(uint32_t capacity);
- void copy(const RunContext& context, const Buffer* src);
- void prepare_write(RunContext& context);
-
- void* port_data(PortType port_type, SampleCount offset);
- const void* port_data(PortType port_type, SampleCount offset) const;
-
- inline LV2_URID type() const { return _type; }
- inline LV2_URID value_type() const { return _value_type; }
- inline uint32_t capacity() const { return _capacity; }
- inline uint32_t size() const {
- return is_audio() ? _capacity : sizeof(LV2_Atom) + get<LV2_Atom>()->size;
- }
-
- typedef BufferRef (BufferFactory::*GetFn)(LV2_URID, LV2_URID, uint32_t);
-
- /** Set the buffer type and optional value type for this buffer.
- *
- * @param get Called to get auxiliary buffers if necessary.
- * @param type Type of buffer.
- * @param value_type Type of values in buffer if applicable (for sequences).
- */
- void set_type(GetFn get, LV2_URID type, LV2_URID value_type);
-
- inline bool is_audio() const {
- return _type == _factory.uris().atom_Sound;
- }
-
- inline bool is_control() const {
- return _type == _factory.uris().atom_Float;
- }
-
- inline bool is_sequence() const {
- return _type == _factory.uris().atom_Sequence;
- }
-
- /// Audio or float buffers only
- inline const Sample* samples() const {
- if (is_control()) {
- return (const Sample*)LV2_ATOM_BODY_CONST(get<LV2_Atom_Float>());
- } else if (is_audio()) {
- return (const Sample*)_buf;
- }
- return nullptr;
- }
-
- /// Audio buffers only
- inline Sample* samples() {
- if (is_control()) {
- return (Sample*)LV2_ATOM_BODY(get<LV2_Atom_Float>());
- } else if (is_audio()) {
- return (Sample*)_buf;
- }
- return nullptr;
- }
-
- /// Numeric buffers only
- inline Sample value_at(SampleCount offset) const {
- if (is_audio() || is_control()) {
- return samples()[offset];
- } else if (_value_buffer) {
- return ((LV2_Atom_Float*)value())->body;
- }
- return 0.0f;
- }
-
- inline void set_block(const Sample val,
- const SampleCount start,
- const SampleCount end)
- {
- if (is_sequence()) {
- append_event(start, sizeof(val), _factory.uris().atom_Float,
- reinterpret_cast<const uint8_t*>(
- static_cast<const float*>(&val)));
- _value_buffer->get<LV2_Atom_Float>()->body = val;
- return;
- }
-
- assert(is_audio() || is_control());
- assert(end <= _capacity / sizeof(Sample));
- // Note: Do not change this without ensuring GCC can still vectorize it
- Sample* const buf = samples() + start;
- for (SampleCount i = 0; i < (end - start); ++i) {
- buf[i] = val;
- }
- }
-
- inline void add_block(const Sample val,
- const SampleCount start,
- const SampleCount end)
- {
- assert(is_audio() || is_control());
- assert(end <= _capacity / sizeof(Sample));
- // Note: Do not change this without ensuring GCC can still vectorize it
- Sample* const buf = samples() + start;
- for (SampleCount i = 0; i < (end - start); ++i) {
- buf[i] += val;
- }
- }
-
- inline void write_block(const Sample val,
- const SampleCount start,
- const SampleCount end,
- const bool add)
- {
- if (add) {
- add_block(val, start, end);
- } else {
- set_block(val, start, end);
- }
- }
-
- /// Audio buffers only
- float peak(const RunContext& context) const;
-
- /// Sequence buffers only
- void prepare_output_write(RunContext& context);
-
- /// Sequence buffers only
- bool append_event(int64_t frames,
- uint32_t size,
- uint32_t type,
- const uint8_t* data);
-
- /// Sequence buffers only
- bool append_event(int64_t frames, const LV2_Atom* body);
-
- /// Sequence buffers only
- bool append_event_buffer(const Buffer* buf);
-
- /// Value buffer for numeric sequences
- BufferRef value_buffer() { return _value_buffer; }
-
- /// Return the current value
- const LV2_Atom* value() const;
-
- /// Set/initialise current value in value buffer
- void set_value(const Atom& value);
-
- /// Return offset of the first value change after `offset`
- SampleCount next_value_offset(SampleCount offset, SampleCount end) const;
-
- /// Update value buffer to value as of offset
- void update_value_buffer(SampleCount offset);
-
- /// Set/add to audio buffer from the Sequence of Float in `src`
- void render_sequence(const RunContext& context, const Buffer* src, bool add);
-
-#ifndef NDEBUG
- void dump_cv(const RunContext& context) const;
-#endif
-
- void set_capacity(uint32_t capacity) { _capacity = capacity; }
-
- void set_buffer(void* buf) { assert(_external); _buf = buf; }
-
- static void* aligned_alloc(size_t size);
-
- template<typename T> const T* get() const { return reinterpret_cast<const T*>(_buf); }
- template<typename T> T* get() { return reinterpret_cast<T*>(_buf); }
-
- inline void ref() { ++_refs; }
-
- inline void deref() {
- if ((--_refs) == 0) {
- recycle();
- }
- }
-
-private:
- friend class BufferFactory;
- ~Buffer();
-
- void recycle();
-
- BufferFactory& _factory;
- Buffer* _next; ///< Intrusive linked list for BufferFactory
- void* _buf; ///< Actual buffer memory
- BufferRef _value_buffer; ///< Value buffer for numeric sequences
- int64_t _latest_event;
- LV2_URID _type;
- LV2_URID _value_type;
- uint32_t _capacity;
- std::atomic<unsigned> _refs; ///< Intrusive reference count
- bool _external; ///< Buffer is externally allocated
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BUFFER_HPP
diff --git a/src/server/BufferFactory.cpp b/src/server/BufferFactory.cpp
deleted file mode 100644
index d5d947d0..00000000
--- a/src/server/BufferFactory.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Log.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-
-#include "Buffer.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-
-namespace Ingen {
-namespace Server {
-
-BufferFactory::BufferFactory(Engine& engine, URIs& uris)
- : _free_audio(nullptr)
- , _free_control(nullptr)
- , _free_sequence(nullptr)
- , _free_object(nullptr)
- , _engine(engine)
- , _uris(uris)
- , _seq_size(0)
- , _silent_buffer(nullptr)
-{
-}
-
-BufferFactory::~BufferFactory()
-{
- _silent_buffer.reset();
- free_list(_free_audio.load());
- free_list(_free_control.load());
- free_list(_free_sequence.load());
- free_list(_free_object.load());
-}
-
-Forge&
-BufferFactory::forge()
-{
- return _engine.world()->forge();
-}
-
-Raul::Maid&
-BufferFactory::maid()
-{
- return *_engine.maid();
-}
-
-void
-BufferFactory::free_list(Buffer* head)
-{
- while (head) {
- Buffer* next = head->_next;
- delete head;
- head = next;
- }
-}
-
-void
-BufferFactory::set_block_length(SampleCount block_length)
-{
- _silent_buffer = create(_uris.atom_Sound, audio_buffer_size(block_length));
-}
-
-uint32_t
-BufferFactory::audio_buffer_size(SampleCount nframes)
-{
- return nframes * sizeof(Sample);
-}
-
-uint32_t
-BufferFactory::audio_buffer_size() const
-{
- return _engine.block_length() * sizeof(Sample);
-}
-
-uint32_t
-BufferFactory::default_size(LV2_URID type) const
-{
- if (type == _uris.atom_Float) {
- return sizeof(LV2_Atom_Float);
- } else if (type == _uris.atom_Sound) {
- return audio_buffer_size(_engine.block_length());
- } else if (type == _uris.atom_URID) {
- return sizeof(LV2_Atom_URID);
- } else if (type == _uris.atom_Sequence) {
- if (_seq_size == 0) {
- return _engine.sequence_size();
- } else {
- return _seq_size;
- }
- } else {
- return 0;
- }
-}
-
-Buffer*
-BufferFactory::try_get_buffer(LV2_URID type)
-{
- std::atomic<Buffer*>& head_ptr = free_list(type);
- Buffer* head = nullptr;
- Buffer* next;
- do {
- head = head_ptr.load();
- if (!head) {
- break;
- }
- next = head->_next;
- } while (!head_ptr.compare_exchange_weak(head, next));
-
- return head;
-}
-
-BufferRef
-BufferFactory::get_buffer(LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity)
-{
- Buffer* try_head = try_get_buffer(type);
- if (!try_head) {
- return create(type, value_type, capacity);
- }
-
- try_head->_next = nullptr;
- try_head->set_type(&BufferFactory::get_buffer, type, value_type);
- try_head->clear();
- return BufferRef(try_head);
-}
-
-BufferRef
-BufferFactory::claim_buffer(LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity)
-{
- Buffer* try_head = try_get_buffer(type);
- if (!try_head) {
- _engine.world()->log().rt_error("Failed to obtain buffer");
- return BufferRef();
- }
-
- try_head->_next = nullptr;
- try_head->set_type(&BufferFactory::claim_buffer, type, value_type);
- return BufferRef(try_head);
-}
-
-BufferRef
-BufferFactory::silent_buffer()
-{
- return _silent_buffer;
-}
-
-BufferRef
-BufferFactory::create(LV2_URID type, LV2_URID value_type, uint32_t capacity)
-{
- if (capacity == 0) {
- capacity = default_size(type);
- } else if (type == _uris.atom_Float) {
- capacity = std::max(capacity, (uint32_t)sizeof(LV2_Atom_Float));
- } else if (type == _uris.atom_Sound) {
- capacity = std::max(capacity, default_size(_uris.atom_Sound));
- }
-
- return BufferRef(new Buffer(*this, type, value_type, capacity));
-}
-
-void
-BufferFactory::recycle(Buffer* buf)
-{
- std::atomic<Buffer*>& head_ptr = free_list(buf->type());
- Buffer* try_head;
- do {
- try_head = head_ptr.load();
- buf->_next = try_head;
- } while (!head_ptr.compare_exchange_weak(try_head, buf));
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/BufferFactory.hpp b/src/server/BufferFactory.hpp
deleted file mode 100644
index 8265fc98..00000000
--- a/src/server/BufferFactory.hpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BUFFERFACTORY_HPP
-#define INGEN_ENGINE_BUFFERFACTORY_HPP
-
-#include <atomic>
-#include <map>
-#include <mutex>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/ingen.h"
-#include "ingen/types.hpp"
-#include "raul/RingBuffer.hpp"
-
-#include "BufferRef.hpp"
-#include "PortType.hpp"
-#include "types.hpp"
-
-namespace Raul { class Maid; }
-
-namespace Ingen {
-
-class URIs;
-
-namespace Server {
-
-class Engine;
-
-class INGEN_API BufferFactory {
-public:
- BufferFactory(Engine& engine, URIs& uris);
- ~BufferFactory();
-
- static uint32_t audio_buffer_size(SampleCount nframes);
-
- uint32_t audio_buffer_size() const;
- uint32_t default_size(LV2_URID type) const;
-
- /** Dynamically allocate a new Buffer. */
- BufferRef create(LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity = 0);
-
- /** Get a new buffer, reusing if possible, allocating if otherwise. */
- BufferRef get_buffer(LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity);
-
- /** Claim an existing buffer, never allocates, real-time safe. */
- BufferRef claim_buffer(LV2_URID type,
- LV2_URID value_type,
- uint32_t capacity);
-
- /** Return a reference to a shared silent buffer. */
- BufferRef silent_buffer();
-
- void set_block_length(SampleCount block_length);
- void set_seq_size(uint32_t seq_size) { _seq_size = seq_size; }
-
- Forge& forge();
- Raul::Maid& maid();
-
- URIs& uris() { return _uris; }
- Engine& engine() { return _engine; }
-
-private:
- friend class Buffer;
- void recycle(Buffer* buf);
-
- Buffer* try_get_buffer(LV2_URID type);
-
- inline std::atomic<Buffer*>& free_list(LV2_URID type) {
- if (type == _uris.atom_Float) {
- return _free_control;
- } else if (type == _uris.atom_Sound) {
- return _free_audio;
- } else if (type == _uris.atom_Sequence) {
- return _free_sequence;
- } else {
- return _free_object;
- }
- }
-
- void free_list(Buffer* head);
-
- std::atomic<Buffer*> _free_audio;
- std::atomic<Buffer*> _free_control;
- std::atomic<Buffer*> _free_sequence;
- std::atomic<Buffer*> _free_object;
-
- std::mutex _mutex;
- Engine& _engine;
- URIs& _uris;
- uint32_t _seq_size;
-
- BufferRef _silent_buffer;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BUFFERFACTORY_HPP
diff --git a/src/server/BufferRef.hpp b/src/server/BufferRef.hpp
deleted file mode 100644
index 2a1cbc27..00000000
--- a/src/server/BufferRef.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_BUFFER_REF_HPP
-#define INGEN_ENGINE_BUFFER_REF_HPP
-
-#include <boost/intrusive_ptr.hpp>
-
-#include "ingen/ingen.h"
-
-namespace Ingen {
-namespace Server {
-
-class Buffer;
-
-typedef boost::intrusive_ptr<Buffer> BufferRef;
-
-// Defined in Buffer.cpp
-INGEN_API void intrusive_ptr_add_ref(Buffer* b);
-INGEN_API void intrusive_ptr_release(Buffer* b);
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BUFFER_REF_HPP
diff --git a/src/server/ClientUpdate.cpp b/src/server/ClientUpdate.cpp
deleted file mode 100644
index 60dd02e3..00000000
--- a/src/server/ClientUpdate.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Interface.hpp"
-#include "ingen/URIs.hpp"
-
-#include "BlockImpl.hpp"
-#include "BufferFactory.hpp"
-#include "ClientUpdate.hpp"
-#include "GraphImpl.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-void
-ClientUpdate::put(const URI& uri,
- const Properties& props,
- Resource::Graph ctx)
-{
- const ClientUpdate::Put put = { uri, props, ctx };
- puts.push_back(put);
-}
-
-void
-ClientUpdate::put_port(const PortImpl* port)
-{
- const URIs& uris = port->bufs().uris();
- if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) {
- Properties props = port->properties();
- props.erase(uris.ingen_value);
- props.emplace(uris.ingen_value, port->value());
- put(port->uri(), props);
- } else {
- put(port->uri(), port->properties());
- }
-}
-
-void
-ClientUpdate::put_block(const BlockImpl* block)
-{
- const PluginImpl* const plugin = block->plugin_impl();
- const URIs& uris = plugin->uris();
-
- if (uris.ingen_Graph == plugin->type()) {
- put_graph((const GraphImpl*)block);
- } else {
- put(block->uri(), block->properties());
- for (size_t j = 0; j < block->num_ports(); ++j) {
- put_port(block->port_impl(j));
- }
- }
-}
-
-void
-ClientUpdate::put_graph(const GraphImpl* graph)
-{
- put(graph->uri(),
- graph->properties(Resource::Graph::INTERNAL),
- Resource::Graph::INTERNAL);
-
- put(graph->uri(),
- graph->properties(Resource::Graph::EXTERNAL),
- Resource::Graph::EXTERNAL);
-
- // Enqueue blocks
- for (const auto& b : graph->blocks()) {
- put_block(&b);
- }
-
- // Enqueue ports
- for (uint32_t i = 0; i < graph->num_ports_non_rt(); ++i) {
- put_port(graph->port_impl(i));
- }
-
- // Enqueue arcs
- for (const auto& a : graph->arcs()) {
- const SPtr<const Arc> arc = a.second;
- const Connect connect = { arc->tail_path(), arc->head_path() };
- connects.push_back(connect);
- }
-}
-
-void
-ClientUpdate::put_plugin(PluginImpl* plugin)
-{
- put(plugin->uri(), plugin->properties());
-
- for (const auto& p : plugin->presets()) {
- put_preset(plugin->uris(), plugin->uri(), p.first, p.second);
- }
-}
-
-void
-ClientUpdate::put_preset(const URIs& uris,
- const URI& plugin,
- const URI& preset,
- const std::string& label)
-{
- const Properties props{
- { uris.rdf_type, uris.pset_Preset.urid },
- { uris.rdfs_label, uris.forge.alloc(label) },
- { uris.lv2_appliesTo, uris.forge.make_urid(plugin) }};
- put(preset, props);
-}
-
-void
-ClientUpdate::del(const URI& subject)
-{
- dels.push_back(subject);
-}
-
-/** Returns true if a is closer to the root than b. */
-static inline bool
-put_higher_than(const ClientUpdate::Put& a, const ClientUpdate::Put& b)
-{
- return (std::count(a.uri.begin(), a.uri.end(), '/') <
- std::count(b.uri.begin(), b.uri.end(), '/'));
-}
-
-void
-ClientUpdate::send(Interface& dest)
-{
- // Send deletions
- for (const URI& subject : dels) {
- dest.del(subject);
- }
-
- // Send puts in increasing depth order so parents are sent first
- std::stable_sort(puts.begin(), puts.end(), put_higher_than);
- for (const ClientUpdate::Put& put : puts) {
- dest.put(put.uri, put.properties, put.ctx);
- }
-
- // Send connections
- for (const ClientUpdate::Connect& connect : connects) {
- dest.connect(connect.tail, connect.head);
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/ClientUpdate.hpp b/src/server/ClientUpdate.hpp
deleted file mode 100644
index f1a361f7..00000000
--- a/src/server/ClientUpdate.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_CLIENTUPDATE_HPP
-#define INGEN_ENGINE_CLIENTUPDATE_HPP
-
-#include <string>
-#include <vector>
-
-#include "ingen/Resource.hpp"
-#include "raul/Path.hpp"
-
-namespace Ingen {
-
-class Interface;
-class URIs;
-
-namespace Server {
-
-class PortImpl;
-class BlockImpl;
-class GraphImpl;
-class PluginImpl;
-
-/** A sequence of puts/connects/deletes to update clients.
- *
- * Events like Get construct this in pre_process() and later send it in
- * post_process() to avoid the need to lock.
- */
-struct ClientUpdate {
- void put(const URI& uri,
- const Properties& props,
- Resource::Graph ctx = Resource::Graph::DEFAULT);
-
- void put_port(const PortImpl* port);
- void put_block(const BlockImpl* block);
- void put_graph(const GraphImpl* graph);
- void put_plugin(PluginImpl* plugin);
- void put_preset(const URIs& uris,
- const URI& plugin,
- const URI& preset,
- const std::string& label);
-
- void del(const URI& subject);
-
- void send(Interface& dest);
-
- struct Put {
- URI uri;
- Properties properties;
- Resource::Graph ctx;
- };
-
- struct Connect {
- Raul::Path tail;
- Raul::Path head;
- };
-
- std::vector<URI> dels;
- std::vector<Put> puts;
- std::vector<Connect> connects;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_CLIENTUPDATE_HPP
diff --git a/src/server/CompiledGraph.cpp b/src/server/CompiledGraph.cpp
deleted file mode 100644
index 35b07935..00000000
--- a/src/server/CompiledGraph.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2015-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/>.
-*/
-
-#include <algorithm>
-
-#include "ingen/ColorContext.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/World.hpp"
-
-#include "CompiledGraph.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** Graph contains ambiguous feedback with no delay nodes. */
-class FeedbackException : public std::exception {
-public:
- FeedbackException(const BlockImpl* node, const BlockImpl* root=nullptr)
- : node(node)
- , root(root)
- {}
-
- const BlockImpl* node;
- const BlockImpl* root;
-};
-
-static bool
-has_provider_with_many_dependants(BlockImpl* n)
-{
- for (BlockImpl* p : n->providers()) {
- if (p->dependants().size() > 1) {
- return true;
- }
- }
-
- return false;
-}
-
-CompiledGraph::CompiledGraph(GraphImpl* graph)
- : _master(std::unique_ptr<Task>(new Task(Task::Mode::SEQUENTIAL)))
-{
- compile_graph(graph);
-}
-
-MPtr<CompiledGraph>
-CompiledGraph::compile(Raul::Maid& maid, GraphImpl& graph)
-{
- try {
- return maid.make_managed<CompiledGraph>(&graph);
- } catch (const FeedbackException& e) {
- Log& log = graph.engine().log();
- if (e.node && e.root) {
- log.error(fmt("Feedback compiling %1% from %2%\n")
- % e.node->path() % e.root->path());
- } else {
- log.error(fmt("Feedback compiling %1%\n")
- % e.node->path());
- }
- return MPtr<CompiledGraph>();
- }
-}
-
-static size_t
-num_unvisited_dependants(BlockImpl* block)
-{
- size_t count = 0;
- for (BlockImpl* b : block->dependants()) {
- if (b->get_mark() == BlockImpl::Mark::UNVISITED) {
- ++count;
- }
- }
- return count;
-}
-
-static size_t
-parallel_depth(BlockImpl* block)
-{
- if (has_provider_with_many_dependants(block)) {
- return 2;
- }
-
- size_t min_provider_depth = std::numeric_limits<size_t>::max();
- for (auto p : block->providers()) {
- min_provider_depth = std::min(min_provider_depth, parallel_depth(p));
- }
-
- return 2 + min_provider_depth;
-}
-
-void
-CompiledGraph::compile_graph(GraphImpl* graph)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- // Start with sink nodes (no outputs, or connected only to graph outputs)
- std::set<BlockImpl*> blocks;
- for (auto& b : graph->blocks()) {
- // Mark all blocks as unvisited initially
- b.set_mark(BlockImpl::Mark::UNVISITED);
-
- if (b.dependants().empty()) {
- // Block has no dependants, add to initial working set
- blocks.insert(&b);
- }
- }
-
- // Keep compiling working set until all nodes are visited
- while (!blocks.empty()) {
- std::set<BlockImpl*> predecessors;
-
- // Calculate maximum sequential depth to consume this phase
- size_t depth = std::numeric_limits<size_t>::max();
- for (auto i : blocks) {
- depth = std::min(depth, parallel_depth(i));
- }
-
- Task par(Task::Mode::PARALLEL);
- for (auto b : blocks) {
- assert(num_unvisited_dependants(b) == 0);
- Task seq(Task::Mode::SEQUENTIAL);
- compile_block(b, seq, depth, predecessors);
- par.push_front(std::move(seq));
- }
- _master->push_front(std::move(par));
- blocks = predecessors;
- }
-
- _master = Task::simplify(std::move(_master));
-
- if (graph->engine().world()->conf().option("trace").get<int32_t>()) {
- ColorContext ctx(stderr, ColorContext::Color::YELLOW);
- dump(graph->path());
- }
-}
-
-/** Throw a FeedbackException iff `dependant` has `root` as a dependency. */
-static void
-check_feedback(const BlockImpl* root, BlockImpl* provider)
-{
- if (provider == root) {
- throw FeedbackException(root);
- }
-
- for (auto p : provider->providers()) {
- const BlockImpl::Mark mark = p->get_mark();
- switch (mark) {
- case BlockImpl::Mark::UNVISITED:
- p->set_mark(BlockImpl::Mark::VISITING);
- check_feedback(root, p);
- break;
- case BlockImpl::Mark::VISITING:
- throw FeedbackException(p, root);
- case BlockImpl::Mark::VISITED:
- break;
- }
- p->set_mark(mark);
- }
-}
-
-void
-CompiledGraph::compile_provider(const BlockImpl* root,
- BlockImpl* block,
- Task& task,
- size_t max_depth,
- std::set<BlockImpl*>& k)
-{
- if (block->dependants().size() > 1) {
- /* Provider has other dependants, so this is the tail of a sequential task.
- Add provider to future working set and stop traversal. */
- check_feedback(root, block);
- if (num_unvisited_dependants(block) == 0) {
- k.insert(block);
- }
- } else if (max_depth > 0) {
- // Calling dependant has only this provider, add here
- if (task.mode() == Task::Mode::PARALLEL) {
- // Inside a parallel task, compile into a new sequential child
- Task seq(Task::Mode::SEQUENTIAL);
- compile_block(block, seq, max_depth, k);
- task.push_front(std::move(seq));
- } else {
- // Prepend to given sequential task
- compile_block(block, task, max_depth, k);
- }
- } else {
- if (num_unvisited_dependants(block) == 0) {
- k.insert(block);
- }
- }
-}
-
-void
-CompiledGraph::compile_block(BlockImpl* n,
- Task& task,
- size_t max_depth,
- std::set<BlockImpl*>& k)
-{
- switch (n->get_mark()) {
- case BlockImpl::Mark::UNVISITED:
- n->set_mark(BlockImpl::Mark::VISITING);
-
- // Execute this task after the providers to follow
- task.push_front(Task(Task::Mode::SINGLE, n));
-
- if (n->providers().size() < 2) {
- // Single provider, prepend it to this sequential task
- for (auto p : n->providers()) {
- compile_provider(n, p, task, max_depth - 1, k);
- }
- } else if (has_provider_with_many_dependants(n)) {
- // Stop recursion and enqueue providers for the next round
- for (auto p : n->providers()) {
- if (num_unvisited_dependants(p) == 0) {
- k.insert(p);
- }
- }
- } else {
- // Multiple providers with only this node as dependant,
- // make a new parallel task to execute them
- Task par(Task::Mode::PARALLEL);
- for (auto p : n->providers()) {
- compile_provider(n, p, par, max_depth - 1, k);
- }
- task.push_front(std::move(par));
- }
- n->set_mark(BlockImpl::Mark::VISITED);
- break;
-
- case BlockImpl::Mark::VISITING:
- throw FeedbackException(n);
-
- case BlockImpl::Mark::VISITED:
- break;
- }
-}
-
-void
-CompiledGraph::run(RunContext& context)
-{
- _master->run(context);
-}
-
-void
-CompiledGraph::dump(const std::string& name) const
-{
- auto sink = [](const std::string& s) {
- fwrite(s.c_str(), 1, s.size(), stderr);
- };
-
- sink("(compiled-graph ");
- sink(name);
- _master->dump(sink, 2, false);
- sink(")\n");
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/CompiledGraph.hpp b/src/server/CompiledGraph.hpp
deleted file mode 100644
index 6b802611..00000000
--- a/src/server/CompiledGraph.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- 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_ENGINE_COMPILEDGRAPH_HPP
-#define INGEN_ENGINE_COMPILEDGRAPH_HPP
-
-#include <functional>
-#include <set>
-#include <vector>
-
-#include "ingen/types.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Noncopyable.hpp"
-
-#include "Task.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class GraphImpl;
-class RunContext;
-
-/** A graph ``compiled'' into a quickly executable form.
- *
- * This is a flat sequence of nodes ordered such that the process thread can
- * execute the nodes in order and have nodes always executed before any of
- * their dependencies.
- */
-class CompiledGraph : public Raul::Maid::Disposable
- , public Raul::Noncopyable
-{
-public:
- static MPtr<CompiledGraph> compile(Raul::Maid& maid, GraphImpl& graph);
-
- void run(RunContext& context);
-
-private:
- friend class Raul::Maid; ///< Allow make_managed to construct
-
- CompiledGraph(GraphImpl* graph);
-
- typedef std::set<BlockImpl*> BlockSet;
-
- void dump(const std::string& name) const;
-
- void compile_graph(GraphImpl* graph);
-
- void compile_block(BlockImpl* n,
- Task& task,
- size_t max_depth,
- BlockSet& k);
-
- void compile_provider(const BlockImpl* root,
- BlockImpl* block,
- Task& task,
- size_t max_depth,
- BlockSet& k);
-
- std::unique_ptr<Task> _master;
-};
-
-inline MPtr<CompiledGraph> compile(Raul::Maid& maid, GraphImpl& graph)
-{
- return CompiledGraph::compile(maid, graph);
-}
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_COMPILEDGRAPH_HPP
diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp
deleted file mode 100644
index 3901d1c2..00000000
--- a/src/server/ControlBindings.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cmath>
-
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
-
-#include "Buffer.hpp"
-#include "ControlBindings.hpp"
-#include "Engine.hpp"
-#include "PortImpl.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-ControlBindings::ControlBindings(Engine& engine)
- : _engine(engine)
- , _learn_binding(nullptr)
- , _bindings(new Bindings())
- , _feedback(new Buffer(*_engine.buffer_factory(),
- engine.world()->uris().atom_Sequence,
- 0,
- 4096)) // FIXME: capacity?
-{
- lv2_atom_forge_init(
- &_forge, &engine.world()->uri_map().urid_map_feature()->urid_map);
-}
-
-ControlBindings::~ControlBindings()
-{
- _feedback.reset();
- delete _learn_binding.load();
-}
-
-ControlBindings::Key
-ControlBindings::port_binding(PortImpl* port) const
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- const Ingen::URIs& uris = _engine.world()->uris();
- const Atom& binding = port->get_property(uris.midi_binding);
- return binding_key(binding);
-}
-
-ControlBindings::Key
-ControlBindings::binding_key(const Atom& binding) const
-{
- const Ingen::URIs& uris = _engine.world()->uris();
- Key key;
- LV2_Atom* num = nullptr;
- if (binding.type() == uris.atom_Object) {
- const LV2_Atom_Object_Body* obj = (const LV2_Atom_Object_Body*)
- binding.get_body();
- if (obj->otype == uris.midi_Bender) {
- key = Key(Type::MIDI_BENDER);
- } else if (obj->otype == uris.midi_ChannelPressure) {
- key = Key(Type::MIDI_CHANNEL_PRESSURE);
- } else if (obj->otype == uris.midi_Controller) {
- lv2_atom_object_body_get(
- binding.size(), obj, (LV2_URID)uris.midi_controllerNumber, &num, NULL);
- if (!num) {
- _engine.log().rt_error("Controller binding missing number\n");
- } else if (num->type != uris.atom_Int) {
- _engine.log().rt_error("Controller number not an integer\n");
- } else {
- key = Key(Type::MIDI_CC, ((LV2_Atom_Int*)num)->body);
- }
- } else if (obj->otype == uris.midi_NoteOn) {
- lv2_atom_object_body_get(
- binding.size(), obj, (LV2_URID)uris.midi_noteNumber, &num, NULL);
- if (!num) {
- _engine.log().rt_error("Note binding missing number\n");
- } else if (num->type != uris.atom_Int) {
- _engine.log().rt_error("Note number not an integer\n");
- } else {
- key = Key(Type::MIDI_NOTE, ((LV2_Atom_Int*)num)->body);
- }
- }
- } else if (binding.type()) {
- _engine.log().rt_error("Unknown binding type\n");
- }
- return key;
-}
-
-ControlBindings::Key
-ControlBindings::midi_event_key(uint16_t size, const uint8_t* buf, uint16_t& value)
-{
- switch (lv2_midi_message_type(buf)) {
- case LV2_MIDI_MSG_CONTROLLER:
- value = static_cast<int8_t>(buf[2]);
- return Key(Type::MIDI_CC, static_cast<int8_t>(buf[1]));
- case LV2_MIDI_MSG_BENDER:
- value = (static_cast<int8_t>(buf[2]) << 7) + static_cast<int8_t>(buf[1]);
- return Key(Type::MIDI_BENDER);
- case LV2_MIDI_MSG_CHANNEL_PRESSURE:
- value = static_cast<int8_t>(buf[1]);
- return Key(Type::MIDI_CHANNEL_PRESSURE);
- case LV2_MIDI_MSG_NOTE_ON:
- value = 1.0f;
- return Key(Type::MIDI_NOTE, static_cast<int8_t>(buf[1]));
- default:
- return Key();
- }
-}
-
-bool
-ControlBindings::set_port_binding(RunContext& context,
- PortImpl* port,
- Binding* binding,
- const Atom& value)
-{
- const Key key = binding_key(value);
- if (!!key) {
- binding->key = key;
- binding->port = port;
- _bindings->insert(*binding);
- return true;
- } else {
- return false;
- }
-}
-
-void
-ControlBindings::port_value_changed(RunContext& ctx,
- PortImpl* port,
- Key key,
- const Atom& value_atom)
-{
- Ingen::World* world = ctx.engine().world();
- const Ingen::URIs& uris = world->uris();
- if (!!key) {
- int16_t value = port_value_to_control(
- ctx, port, key.type, value_atom);
- uint16_t size = 0;
- uint8_t buf[4];
- switch (key.type) {
- case Type::MIDI_CC:
- size = 3;
- buf[0] = LV2_MIDI_MSG_CONTROLLER;
- buf[1] = key.num;
- buf[2] = static_cast<int8_t>(value);
- break;
- case Type::MIDI_CHANNEL_PRESSURE:
- size = 2;
- buf[0] = LV2_MIDI_MSG_CHANNEL_PRESSURE;
- buf[1] = static_cast<int8_t>(value);
- break;
- case Type::MIDI_BENDER:
- size = 3;
- buf[0] = LV2_MIDI_MSG_BENDER;
- buf[1] = (value & 0x007F);
- buf[2] = (value & 0x7F00) >> 7;
- break;
- case Type::MIDI_NOTE:
- size = 3;
- if (value == 1) {
- buf[0] = LV2_MIDI_MSG_NOTE_ON;
- } else if (value == 0) {
- buf[0] = LV2_MIDI_MSG_NOTE_OFF;
- }
- buf[1] = key.num;
- buf[2] = 0x64; // MIDI spec default
- break;
- default:
- break;
- }
- if (size > 0) {
- _feedback->append_event(ctx.nframes() - 1, size, (LV2_URID)uris.midi_MidiEvent, buf);
- }
- }
-}
-
-void
-ControlBindings::start_learn(PortImpl* port)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- Binding* b = _learn_binding.load();
- if (!b) {
- _learn_binding = new Binding(Type::NULL_CONTROL, port);
- } else {
- b->port = port;
- }
-}
-
-static void
-get_range(RunContext& context, const PortImpl* port, float* min, float* max)
-{
- *min = port->minimum().get<float>();
- *max = port->maximum().get<float>();
- if (port->is_sample_rate()) {
- *min *= context.engine().sample_rate();
- *max *= context.engine().sample_rate();
- }
-}
-
-float
-ControlBindings::control_to_port_value(RunContext& context,
- const PortImpl* port,
- Type type,
- int16_t value) const
-{
- float normal = 0.0f;
- switch (type) {
- case Type::MIDI_CC:
- case Type::MIDI_CHANNEL_PRESSURE:
- normal = (float)value / 127.0f;
- break;
- case Type::MIDI_BENDER:
- normal = (float)value / 16383.0f;
- break;
- case Type::MIDI_NOTE:
- normal = (value == 0.0f) ? 0.0f : 1.0f;
- break;
- default:
- break;
- }
-
- if (port->is_logarithmic()) {
- normal = (expf(normal) - 1.0f) / ((float)M_E - 1.0f);
- }
-
- float min, max;
- get_range(context, port, &min, &max);
-
- return normal * (max - min) + min;
-}
-
-int16_t
-ControlBindings::port_value_to_control(RunContext& context,
- PortImpl* port,
- Type type,
- const Atom& value_atom) const
-{
- if (value_atom.type() != port->bufs().forge().Float) {
- return 0;
- }
-
- float min, max;
- get_range(context, port, &min, &max);
-
- const float value = value_atom.get<float>();
- float normal = (value - min) / (max - min);
-
- if (normal < 0.0f) {
- normal = 0.0f;
- }
-
- if (normal > 1.0f) {
- normal = 1.0f;
- }
-
- if (port->is_logarithmic()) {
- normal = logf(normal * ((float)M_E - 1.0f) + 1.0);
- }
-
- switch (type) {
- case Type::MIDI_CC:
- case Type::MIDI_CHANNEL_PRESSURE:
- return lrintf(normal * 127.0f);
- case Type::MIDI_BENDER:
- return lrintf(normal * 16383.0f);
- case Type::MIDI_NOTE:
- return (value > 0.0f) ? 1 : 0;
- default:
- return 0;
- }
-}
-
-static void
-forge_binding(const URIs& uris,
- LV2_Atom_Forge* forge,
- ControlBindings::Type binding_type,
- int32_t value)
-{
- LV2_Atom_Forge_Frame frame;
- switch (binding_type) {
- case ControlBindings::Type::MIDI_CC:
- lv2_atom_forge_object(forge, &frame, 0, uris.midi_Controller);
- lv2_atom_forge_key(forge, uris.midi_controllerNumber);
- lv2_atom_forge_int(forge, value);
- break;
- case ControlBindings::Type::MIDI_BENDER:
- lv2_atom_forge_object(forge, &frame, 0, uris.midi_Bender);
- break;
- case ControlBindings::Type::MIDI_CHANNEL_PRESSURE:
- lv2_atom_forge_object(forge, &frame, 0, uris.midi_ChannelPressure);
- break;
- case ControlBindings::Type::MIDI_NOTE:
- lv2_atom_forge_object(forge, &frame, 0, uris.midi_NoteOn);
- lv2_atom_forge_key(forge, uris.midi_noteNumber);
- lv2_atom_forge_int(forge, value);
- break;
- case ControlBindings::Type::MIDI_RPN: // TODO
- case ControlBindings::Type::MIDI_NRPN: // TODO
- case ControlBindings::Type::NULL_CONTROL:
- break;
- }
-}
-
-void
-ControlBindings::set_port_value(RunContext& context,
- PortImpl* port,
- Type type,
- int16_t value)
-{
- float min, max;
- get_range(context, port, &min, &max);
-
- const float val = control_to_port_value(context, port, type, value);
-
- // TODO: Set port value property so it is saved
- port->set_control_value(context, context.start(), val);
-
- URIs& uris = context.engine().world()->uris();
- context.notify(uris.ingen_value, context.start(), port,
- sizeof(float), _forge.Float, &val);
-}
-
-bool
-ControlBindings::finish_learn(RunContext& context, Key key)
-{
- const Ingen::URIs& uris = context.engine().world()->uris();
- Binding* binding = _learn_binding.exchange(nullptr);
- if (!binding || (key.type == Type::MIDI_NOTE && !binding->port->is_toggled())) {
- return false;
- }
-
- binding->key = key;
- _bindings->insert(*binding);
-
- LV2_Atom buf[16];
- memset(buf, 0, sizeof(buf));
- lv2_atom_forge_set_buffer(&_forge, (uint8_t*)buf, sizeof(buf));
- forge_binding(uris, &_forge, key.type, key.num);
- const LV2_Atom* atom = buf;
- context.notify(uris.midi_binding,
- context.start(),
- binding->port,
- atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
-
- return true;
-}
-
-void
-ControlBindings::get_all(const Raul::Path& path, std::vector<Binding*>& bindings)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- for (Binding& b : *_bindings) {
- if (b.port->path() == path || b.port->path().is_child_of(path)) {
- bindings.push_back(&b);
- }
- }
-}
-
-void
-ControlBindings::remove(RunContext& ctx, const std::vector<Binding*>& bindings)
-{
- for (Binding* b : bindings) {
- _bindings->erase(*b);
- }
-}
-
-void
-ControlBindings::pre_process(RunContext& ctx, Buffer* buffer)
-{
- uint16_t value = 0;
- Ingen::World* world = ctx.engine().world();
- const Ingen::URIs& uris = world->uris();
-
- _feedback->clear();
- if ((!_learn_binding && _bindings->empty()) || !buffer->get<LV2_Atom>()) {
- return; // Don't bother reading input
- }
-
- LV2_Atom_Sequence* seq = buffer->get<LV2_Atom_Sequence>();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->body.type == uris.midi_MidiEvent) {
- const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body);
- const Key key = midi_event_key(ev->body.size, buf, value);
-
- if (_learn_binding && !!key) {
- finish_learn(ctx, key); // Learn new binding
- }
-
- // Set all controls bound to this key
- const Binding k = {key, nullptr};
- for (Bindings::const_iterator i = _bindings->lower_bound(k);
- i != _bindings->end() && i->key == key;
- ++i) {
- set_port_value(ctx, i->port, key.type, value);
- }
- }
- }
-}
-
-void
-ControlBindings::post_process(RunContext& context, Buffer* buffer)
-{
- if (buffer->get<LV2_Atom>()) {
- buffer->append_event_buffer(_feedback.get());
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/ControlBindings.hpp b/src/server/ControlBindings.hpp
deleted file mode 100644
index 3160f8b2..00000000
--- a/src/server/ControlBindings.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_CONTROLBINDINGS_HPP
-#define INGEN_ENGINE_CONTROLBINDINGS_HPP
-
-#include <atomic>
-#include <cstdint>
-#include <vector>
-
-#include <boost/intrusive/options.hpp>
-#include <boost/intrusive/set.hpp>
-
-#include "ingen/Atom.hpp"
-#include "ingen/types.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "BufferFactory.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-class RunContext;
-class PortImpl;
-
-class ControlBindings {
-public:
- enum class Type : uint16_t {
- NULL_CONTROL,
- MIDI_BENDER,
- MIDI_CC,
- MIDI_RPN,
- MIDI_NRPN,
- MIDI_CHANNEL_PRESSURE,
- MIDI_NOTE
- };
-
- struct Key {
- Key(Type t=Type::NULL_CONTROL, int16_t n=0) : type(t), num(n) {}
- inline bool operator<(const Key& other) const {
- return ((type < other.type) ||
- (type == other.type && num < other.num));
- }
- inline bool operator==(const Key& other) const {
- return type == other.type && num == other.num;
- }
- inline bool operator!() const { return type == Type::NULL_CONTROL; }
- Type type;
- int16_t num;
- };
-
- /** One binding of a controller to a port. */
- struct Binding : public boost::intrusive::set_base_hook<>,
- public Raul::Maid::Disposable {
- Binding(Key k=Key(), PortImpl* p=nullptr) : key(std::move(k)), port(p) {}
-
- inline bool operator<(const Binding& rhs) const { return key < rhs.key; }
-
- Key key;
- PortImpl* port;
- };
-
- /** Comparator for bindings by key. */
- struct BindingLess {
- bool operator()(const Binding& lhs, const Binding& rhs) const {
- return lhs.key < rhs.key;
- }
- };
-
- explicit ControlBindings(Engine& engine);
- ~ControlBindings();
-
- Key port_binding(PortImpl* port) const;
- Key binding_key(const Atom& binding) const;
-
- void start_learn(PortImpl* port);
-
- /** Set the binding for `port` to `binding` and take ownership of it. */
- bool set_port_binding(RunContext& ctx,
- PortImpl* port,
- Binding* binding,
- const Atom& value);
-
- void port_value_changed(RunContext& ctx,
- PortImpl* port,
- Key key,
- const Atom& value_atom);
-
- void pre_process(RunContext& ctx, Buffer* buffer);
- void post_process(RunContext& ctx, Buffer* buffer);
-
- /** Get all bindings for `path` or children of `path`. */
- void get_all(const Raul::Path& path, std::vector<Binding*>& bindings);
-
- /** Remove a set of bindings from an earlier call to get_all(). */
- void remove(RunContext& ctx, const std::vector<Binding*>& bindings);
-
-private:
- typedef boost::intrusive::multiset<
- Binding,
- boost::intrusive::compare<BindingLess> > Bindings;
-
- Key midi_event_key(uint16_t size, const uint8_t* buf, uint16_t& value);
-
- void set_port_value(RunContext& context,
- PortImpl* port,
- Type type,
- int16_t value);
-
- bool finish_learn(RunContext& context, Key key);
-
- float control_to_port_value(RunContext& context,
- const PortImpl* port,
- Type type,
- int16_t value) const;
-
- int16_t port_value_to_control(RunContext& context,
- PortImpl* port,
- Type type,
- const Atom& value_atom) const;
-
- Engine& _engine;
- std::atomic<Binding*> _learn_binding;
- SPtr<Bindings> _bindings;
- BufferRef _feedback;
- LV2_Atom_Forge _forge;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_CONTROLBINDINGS_HPP
diff --git a/src/server/DirectDriver.hpp b/src/server/DirectDriver.hpp
deleted file mode 100644
index 58b4f898..00000000
--- a/src/server/DirectDriver.hpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- 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_ENGINE_DIRECT_DRIVER_HPP
-#define INGEN_ENGINE_DIRECT_DRIVER_HPP
-
-#include <boost/intrusive/slist.hpp>
-
-#include "Driver.hpp"
-#include "Engine.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** Driver for running Ingen directly as a library.
- * \ingroup engine
- */
-class DirectDriver : public Driver {
-public:
- DirectDriver(Engine& engine,
- double sample_rate,
- SampleCount block_length,
- size_t seq_size)
- : _engine(engine)
- , _sample_rate(sample_rate)
- , _block_length(block_length)
- , _seq_size(seq_size)
- {}
-
- virtual ~DirectDriver() {
- _ports.clear_and_dispose([](EnginePort* p) { delete p; });
- }
-
- bool dynamic_ports() const { return true; }
-
- virtual EnginePort* create_port(DuplexPort* graph_port) {
- return new EnginePort(graph_port);
- }
-
- virtual EnginePort* get_port(const Raul::Path& path) {
- for (auto& p : _ports) {
- if (p.graph_port()->path() == path) {
- return &p;
- }
- }
-
- return nullptr;
- }
-
- virtual void add_port(RunContext& context, EnginePort* port) {
- _ports.push_back(*port);
- }
-
- virtual void remove_port(RunContext& context, EnginePort* port) {
- _ports.erase(_ports.iterator_to(*port));
- }
-
- virtual void rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path) {}
-
- virtual void port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value) {}
-
- virtual void register_port(EnginePort& port) {}
- virtual void unregister_port(EnginePort& port) {}
-
- virtual SampleCount block_length() const { return _block_length; }
-
- virtual size_t seq_size() const { return _seq_size; }
-
- virtual SampleCount sample_rate() const { return _sample_rate; }
-
- virtual SampleCount frame_time() const { return _engine.run_context().start(); }
-
- virtual void append_time_events(RunContext& context, Buffer& buffer) {}
-
- virtual int real_time_priority() { return 60; }
-
-private:
- typedef boost::intrusive::slist<EnginePort,
- boost::intrusive::cache_last<true>
- > Ports;
-
- Engine& _engine;
- Ports _ports;
- SampleCount _sample_rate;
- SampleCount _block_length;
- size_t _seq_size;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_DIRECT_DRIVER_HPP
diff --git a/src/server/Driver.hpp b/src/server/Driver.hpp
deleted file mode 100644
index 9ae4b836..00000000
--- a/src/server/Driver.hpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- 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_ENGINE_DRIVER_HPP
-#define INGEN_ENGINE_DRIVER_HPP
-
-#include "raul/Noncopyable.hpp"
-
-#include "DuplexPort.hpp"
-#include "EnginePort.hpp"
-
-namespace Raul { class Path; }
-
-namespace Ingen {
-namespace Server {
-
-class DuplexPort;
-class EnginePort;
-
-/** Engine driver base class.
- *
- * A Driver is responsible for managing system ports, and possibly running the
- * audio graph.
- *
- * \ingroup engine
- */
-class Driver : public Raul::Noncopyable {
-public:
- virtual ~Driver() = default;
-
- /** Activate driver (begin processing graph and events). */
- virtual bool activate() { return true; }
-
- /** Deactivate driver (stop processing graph and events). */
- virtual void deactivate() {}
-
- /** Create a port ready to be inserted with add_input (non realtime).
- * May return NULL if the Driver can not create the port for some reason.
- */
- virtual EnginePort* create_port(DuplexPort* graph_port) = 0;
-
- /** Find a system port by path. */
- virtual EnginePort* get_port(const Raul::Path& path) = 0;
-
- /** Add a system visible port (e.g. a port on the root graph). */
- virtual void add_port(RunContext& context, EnginePort* port) = 0;
-
- /** Remove a system visible port.
- *
- * This removes the port from the driver in the process thread but does not
- * destroy the port. To actually remove the system port, unregister_port()
- * must be called later in another thread.
- */
- virtual void remove_port(RunContext& context, EnginePort* port) = 0;
-
- /** Return true iff driver supports dynamic adding/removing of ports. */
- virtual bool dynamic_ports() const { return false; }
-
- /** Register a system visible port. */
- virtual void register_port(EnginePort& port) = 0;
-
- /** Register a system visible port. */
- virtual void unregister_port(EnginePort& port) = 0;
-
- /** Rename a system visible port. */
- virtual void rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path) = 0;
-
- /** Apply a system visible port property. */
- virtual void port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value) = 0;
-
- /** Return the audio buffer size in frames */
- virtual SampleCount block_length() const = 0;
-
- /** Return the event buffer size in bytes */
- virtual size_t seq_size() const = 0;
-
- /** Return the sample rate in Hz */
- virtual SampleRate sample_rate() const = 0;
-
- /** Return the current frame time (running counter) */
- virtual SampleCount frame_time() const = 0;
-
- /** Append time events for this cycle to `buffer`. */
- virtual void append_time_events(RunContext& context,
- Buffer& buffer) = 0;
-
- /** Return the real-time priority of the audio thread, or -1. */
- virtual int real_time_priority() = 0;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_DRIVER_HPP
diff --git a/src/server/DuplexPort.cpp b/src/server/DuplexPort.cpp
deleted file mode 100644
index 1b62ff38..00000000
--- a/src/server/DuplexPort.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/URIs.hpp"
-
-#include "Buffer.hpp"
-#include "Driver.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-DuplexPort::DuplexPort(BufferFactory& bufs,
- GraphImpl* parent,
- const Raul::Symbol& symbol,
- uint32_t index,
- bool polyphonic,
- PortType type,
- LV2_URID buf_type,
- size_t buf_size,
- const Atom& value,
- bool is_output)
- : InputPort(bufs, parent, symbol, index, parent->polyphony(), type, buf_type, value, buf_size)
-{
- if (polyphonic) {
- set_property(bufs.uris().ingen_polyphonic, bufs.forge().make(true));
- }
-
- if (!parent->parent() ||
- _poly != parent->parent_graph()->internal_poly()) {
- _poly = 1;
- }
-
- // Set default control range
- if (!is_output && value.type() == bufs.uris().atom_Float) {
- set_property(bufs.uris().lv2_minimum, bufs.forge().make(0.0f));
- set_property(bufs.uris().lv2_maximum, bufs.forge().make(1.0f));
- }
-
- _is_output = is_output;
- if (is_output) {
- if (parent->graph_type() != Node::GraphType::GRAPH) {
- remove_property(bufs.uris().rdf_type, bufs.uris().lv2_InputPort.urid);
- add_property(bufs.uris().rdf_type, bufs.uris().lv2_OutputPort.urid);
- }
- }
-
- get_buffers(bufs, &BufferFactory::get_buffer,
- _voices, parent->polyphony(), 0);
-}
-
-DuplexPort::~DuplexPort()
-{
- if (is_linked()) {
- parent_graph()->remove_port(*this);
- }
-}
-
-DuplexPort*
-DuplexPort::duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent)
-{
- BufferFactory& bufs = *engine.buffer_factory();
- const Atom polyphonic = get_property(bufs.uris().ingen_polyphonic);
-
- DuplexPort* dup = new DuplexPort(
- bufs, parent, symbol, _index,
- polyphonic.type() == bufs.uris().atom_Bool && polyphonic.get<int32_t>(),
- _type, _buffer_type, _buffer_size,
- _value, _is_output);
-
- dup->set_properties(properties());
-
- return dup;
-}
-
-void
-DuplexPort::inherit_neighbour(const PortImpl* port,
- Properties& remove,
- Properties& add)
-{
- const URIs& uris = _bufs.uris();
-
- /* TODO: This needs to become more sophisticated, and correct the situation
- if the port is disconnected. */
- if (_type == PortType::CONTROL || _type == PortType::CV) {
- if (port->minimum().get<float>() < _min.get<float>()) {
- _min = port->minimum();
- remove.emplace(uris.lv2_minimum, uris.patch_wildcard);
- add.emplace(uris.lv2_minimum, port->minimum());
- }
- if (port->maximum().get<float>() > _max.get<float>()) {
- _max = port->maximum();
- remove.emplace(uris.lv2_maximum, uris.patch_wildcard);
- add.emplace(uris.lv2_maximum, port->maximum());
- }
- } else if (_type == PortType::ATOM) {
- for (auto i = port->properties().find(uris.atom_supports);
- i != port->properties().end() && i->first == uris.atom_supports;
- ++i) {
- set_property(i->first, i->second);
- add.insert(*i);
- }
- }
-}
-
-void
-DuplexPort::on_property(const URI& uri, const Atom& value)
-{
- _bufs.engine().driver()->port_property(_path, uri, value);
-}
-
-bool
-DuplexPort::get_buffers(BufferFactory& bufs,
- PortImpl::GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const
-{
- if (!_is_driver_port && is_output()) {
- return InputPort::get_buffers(bufs, get, voices, poly, num_in_arcs);
- } else if (!_is_driver_port && is_input()) {
- return PortImpl::get_buffers(bufs, get, voices, poly, num_in_arcs);
- }
- return false;
-}
-
-bool
-DuplexPort::setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly)
-{
- if (!_is_driver_port && is_output()) {
- return InputPort::setup_buffers(ctx, bufs, poly);
- } else if (!_is_driver_port && is_input()) {
- return PortImpl::setup_buffers(ctx, bufs, poly);
- }
- return false;
-}
-
-void
-DuplexPort::set_is_driver_port(BufferFactory& bufs)
-{
- _voices->at(0).buffer = new Buffer(bufs, buffer_type(), _value.type(), 0, true, nullptr);
- PortImpl::set_is_driver_port(bufs);
-}
-
-void
-DuplexPort::set_driver_buffer(void* buf, uint32_t capacity)
-{
- _voices->at(0).buffer->set_buffer(buf);
- _voices->at(0).buffer->set_capacity(capacity);
-}
-
-uint32_t
-DuplexPort::max_tail_poly(RunContext& context) const
-{
- return std::max(_poly, parent_graph()->internal_poly_process());
-}
-
-bool
-DuplexPort::prepare_poly(BufferFactory& bufs, uint32_t poly)
-{
- if (!parent()->parent() ||
- poly != parent()->parent_graph()->internal_poly()) {
- return false;
- }
-
- return PortImpl::prepare_poly(bufs, poly);
-}
-
-bool
-DuplexPort::apply_poly(RunContext& context, uint32_t poly)
-{
- if (!parent()->parent() ||
- poly != parent()->parent_graph()->internal_poly()) {
- return false;
- }
-
- return PortImpl::apply_poly(context, poly);
-}
-
-void
-DuplexPort::pre_process(RunContext& context)
-{
- if (_is_output) {
- /* This is a graph output, which is an input from the internal
- perspective. Prepare buffers for write so plugins can deliver to
- them */
- for (uint32_t v = 0; v < _poly; ++v) {
- _voices->at(v).buffer->prepare_write(context);
- }
- } else {
- /* This is a a graph input, which is an output from the internal
- perspective. Do whatever a normal block's input port does to
- prepare input for reading. */
- InputPort::pre_process(context);
- InputPort::pre_run(context);
- }
-}
-
-void
-DuplexPort::post_process(RunContext& context)
-{
- if (_is_output) {
- /* This is a graph output, which is an input from the internal
- perspective. Mix down input delivered by plugins so output
- (external perspective) is ready. */
- InputPort::pre_process(context);
- InputPort::pre_run(context);
- }
- monitor(context);
-}
-
-SampleCount
-DuplexPort::next_value_offset(SampleCount offset, SampleCount end) const
-{
- return PortImpl::next_value_offset(offset, end);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/DuplexPort.hpp b/src/server/DuplexPort.hpp
deleted file mode 100644
index b0066164..00000000
--- a/src/server/DuplexPort.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_DUPLEXPORT_HPP
-#define INGEN_ENGINE_DUPLEXPORT_HPP
-
-#include <boost/intrusive/slist.hpp>
-
-#include "BufferRef.hpp"
-#include "InputPort.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-
-/** A duplex Port (both an input and output port on a Graph)
- *
- * This is used for Graph ports, since they need to appear as both an input and
- * an output port based on context. There are no actual duplex ports in Ingen,
- * a Port is either an Input or Output. This class only exists to allow Graph
- * outputs to appear as inputs from within that Graph, and vice versa.
- *
- * \ingroup engine
- */
-class DuplexPort : public InputPort
- , public boost::intrusive::slist_base_hook<> // In GraphImpl
-{
-public:
- DuplexPort(BufferFactory& bufs,
- GraphImpl* parent,
- const Raul::Symbol& symbol,
- uint32_t index,
- bool polyphonic,
- PortType type,
- LV2_URID buf_type,
- size_t buf_size,
- const Atom& value,
- bool is_output);
-
- virtual ~DuplexPort();
-
- DuplexPort* duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent);
-
- void inherit_neighbour(const PortImpl* port,
- Properties& remove,
- Properties& add);
-
- void on_property(const URI& uri, const Atom& value);
-
- uint32_t max_tail_poly(RunContext& context) const;
-
- bool prepare_poly(BufferFactory& bufs, uint32_t poly);
-
- bool apply_poly(RunContext& context, uint32_t poly);
-
- bool get_buffers(BufferFactory& bufs,
- PortImpl::GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const;
-
- virtual void set_is_driver_port(BufferFactory& bufs);
-
- /** Set the external driver-provided buffer.
- *
- * This may only be called in the process thread, after an earlier call to
- * prepare_driver_buffer().
- */
- void set_driver_buffer(void* buf, uint32_t capacity);
-
- bool setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly);
-
- void pre_process(RunContext& context);
- void post_process(RunContext& context);
-
- SampleCount next_value_offset(SampleCount offset, SampleCount end) const;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_DUPLEXPORT_HPP
diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp
deleted file mode 100644
index a7476845..00000000
--- a/src/server/Engine.cpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen_config.h"
-
-#include <sys/mman.h>
-
-#include <limits>
-#include <thread>
-
-#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-
-#include "events/CreateGraph.hpp"
-#include "ingen/AtomReader.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/StreamWriter.hpp"
-#include "ingen/Tee.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen/types.hpp"
-#include "raul/Maid.hpp"
-
-#include "BlockFactory.hpp"
-#include "Broadcaster.hpp"
-#include "BufferFactory.hpp"
-#include "ControlBindings.hpp"
-#include "DirectDriver.hpp"
-#include "Driver.hpp"
-#include "Engine.hpp"
-#include "Event.hpp"
-#include "EventWriter.hpp"
-#include "GraphImpl.hpp"
-#include "LV2Options.hpp"
-#include "PostProcessor.hpp"
-#include "PreProcessContext.hpp"
-#include "PreProcessor.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-#include "UndoStack.hpp"
-#include "Worker.hpp"
-#ifdef HAVE_SOCKET
-#include "SocketListener.hpp"
-#endif
-
-namespace Ingen {
-namespace Server {
-
-INGEN_THREAD_LOCAL unsigned ThreadManager::flags(0);
-bool ThreadManager::single_threaded(true);
-
-Engine::Engine(Ingen::World* world)
- : _world(world)
- , _options(new LV2Options(world->uris()))
- , _buffer_factory(new BufferFactory(*this, world->uris()))
- , _maid(new Raul::Maid)
- , _worker(new Worker(world->log(), event_queue_size()))
- , _sync_worker(new Worker(world->log(), event_queue_size(), true))
- , _broadcaster(new Broadcaster())
- , _control_bindings(new ControlBindings(*this))
- , _block_factory(new BlockFactory(world))
- , _undo_stack(new UndoStack(_world->uris(), _world->uri_map()))
- , _redo_stack(new UndoStack(_world->uris(), _world->uri_map()))
- , _post_processor(new PostProcessor(*this))
- , _pre_processor(new PreProcessor(*this))
- , _event_writer(new EventWriter(*this))
- , _interface(_event_writer)
- , _atom_interface(
- new AtomReader(world->uri_map(), world->uris(), world->log(), *_interface))
- , _root_graph(nullptr)
- , _cycle_start_time(0)
- , _rand_engine(0)
- , _uniform_dist(0.0f, 1.0f)
- , _quit_flag(false)
- , _reset_load_flag(false)
- , _atomic_bundles(world->conf().option("atomic-bundles").get<int32_t>())
- , _activated(false)
-{
- if (!world->store()) {
- world->set_store(SPtr<Ingen::Store>(new Store()));
- }
-
- for (int i = 0; i < world->conf().option("threads").get<int32_t>(); ++i) {
- Raul::RingBuffer* ring = new Raul::RingBuffer(24 * event_queue_size());
- _notifications.push_back(ring);
- _run_contexts.push_back(new RunContext(*this, ring, i, i > 0));
- }
-
- _world->lv2_features().add_feature(_worker->schedule_feature());
- _world->lv2_features().add_feature(_options);
- _world->lv2_features().add_feature(
- SPtr<LV2Features::Feature>(
- new LV2Features::EmptyFeature(LV2_BUF_SIZE__powerOf2BlockLength)));
- _world->lv2_features().add_feature(
- SPtr<LV2Features::Feature>(
- new LV2Features::EmptyFeature(LV2_BUF_SIZE__fixedBlockLength)));
- _world->lv2_features().add_feature(
- SPtr<LV2Features::Feature>(
- new LV2Features::EmptyFeature(LV2_BUF_SIZE__boundedBlockLength)));
- _world->lv2_features().add_feature(
- SPtr<LV2Features::Feature>(
- new LV2Features::EmptyFeature(LV2_STATE__loadDefaultState)));
-
- if (world->conf().option("dump").get<int32_t>()) {
- _interface = std::make_shared<Tee>(
- Tee::Sinks{
- _event_writer,
- std::make_shared<StreamWriter>(world->uri_map(),
- world->uris(),
- URI("ingen:/engine"),
- stderr,
- ColorContext::Color::MAGENTA)});
- }
-}
-
-Engine::~Engine()
-{
- _root_graph = nullptr;
- deactivate();
-
- // Process all pending events
- const FrameTime end = std::numeric_limits<FrameTime>::max();
- RunContext& ctx = run_context();
- locate(ctx.end(), end - ctx.end());
- _post_processor->set_end_time(end);
- _post_processor->process();
- while (!_pre_processor->empty()) {
- _pre_processor->process(ctx, *_post_processor, 1);
- _post_processor->process();
- }
-
- _atom_interface.reset();
-
- // Delete run contexts
- _quit_flag = true;
- _tasks_available.notify_all();
- for (RunContext* ctx : _run_contexts) {
- ctx->join();
- delete ctx;
- }
- for (Raul::RingBuffer* ring : _notifications) {
- delete ring;
- }
-
- const SPtr<Store> store = this->store();
- if (store) {
- for (auto& s : *store.get()) {
- if (!dynamic_ptr_cast<NodeImpl>(s.second)->parent()) {
- s.second.reset();
- }
- }
- store->clear();
- }
-
- _world->set_store(SPtr<Ingen::Store>());
-}
-
-void
-Engine::listen()
-{
-#ifdef HAVE_SOCKET
- _listener = UPtr<SocketListener>(new SocketListener(*this));
-#endif
-}
-
-void
-Engine::advance(SampleCount nframes)
-{
- for (RunContext* ctx : _run_contexts) {
- ctx->locate(ctx->start() + nframes, block_length());
- }
-}
-
-void
-Engine::locate(FrameTime s, SampleCount nframes)
-{
- for (RunContext* ctx : _run_contexts) {
- ctx->locate(s, nframes);
- }
-}
-
-void
-Engine::set_root_graph(GraphImpl* graph)
-{
- _root_graph = graph;
-}
-
-void
-Engine::flush_events(const std::chrono::milliseconds& sleep_ms)
-{
- bool finished = !pending_events();
- while (!finished) {
- // Run one audio block to execute prepared events
- run(block_length());
- advance(block_length());
-
- // Run one main iteration to post-process events
- main_iteration();
-
- // Sleep before continuing if there are still events to process
- if (!(finished = !pending_events())) {
- std::this_thread::sleep_for(sleep_ms);
- }
- }
-}
-
-void
-Engine::emit_notifications(FrameTime end)
-{
- for (RunContext* ctx : _run_contexts) {
- ctx->emit_notifications(end);
- }
-}
-
-bool
-Engine::pending_notifications()
-{
- for (const RunContext* ctx : _run_contexts) {
- if (ctx->pending_notifications()) {
- return true;
- }
- }
- return false;
-}
-
-bool
-Engine::wait_for_tasks()
-{
- if (!_quit_flag) {
- std::unique_lock<std::mutex> lock(_tasks_mutex);
- _tasks_available.wait(lock);
- }
- return !_quit_flag;
-}
-
-void
-Engine::signal_tasks_available()
-{
- _tasks_available.notify_all();
-}
-
-Task*
-Engine::steal_task(unsigned start_thread)
-{
- for (unsigned i = 0; i < _run_contexts.size(); ++i) {
- const unsigned id = (start_thread + i) % _run_contexts.size();
- RunContext* const ctx = _run_contexts[id];
- Task* par = ctx->task();
- if (par) {
- Task* t = par->steal(*ctx);
- if (t) {
- return t;
- }
- }
- }
- return nullptr;
-}
-
-SPtr<Store>
-Engine::store() const
-{
- return _world->store();
-}
-
-SampleRate
-Engine::sample_rate() const
-{
- return _driver->sample_rate();
-}
-
-SampleCount
-Engine::block_length() const
-{
- return _driver->block_length();
-}
-
-size_t
-Engine::sequence_size() const
-{
- return _driver->seq_size();
-}
-
-size_t
-Engine::event_queue_size() const
-{
- return world()->conf().option("queue-size").get<int32_t>();
-}
-
-void
-Engine::quit()
-{
- _quit_flag = true;
-}
-
-Properties
-Engine::load_properties() const
-{
- const Ingen::URIs& uris = world()->uris();
-
- return { { uris.ingen_meanRunLoad,
- uris.forge.make(floorf(_run_load.mean) / 100.0f) },
- { uris.ingen_minRunLoad,
- uris.forge.make(_run_load.min / 100.0f) },
- { uris.ingen_maxRunLoad,
- uris.forge.make(_run_load.max / 100.0f) } };
-}
-
-bool
-Engine::main_iteration()
-{
- _post_processor->process();
- _maid->cleanup();
-
- if (_run_load.changed) {
- _broadcaster->put(URI("ingen:/engine"), load_properties());
- _run_load.changed = false;
- }
-
- return !_quit_flag;
-}
-
-void
-Engine::set_driver(SPtr<Driver> driver)
-{
- _driver = driver;
- for (RunContext* ctx : _run_contexts) {
- ctx->set_priority(driver->real_time_priority());
- ctx->set_rate(driver->sample_rate());
- }
-
- _buffer_factory->set_block_length(driver->block_length());
- _options->set(sample_rate(),
- block_length(),
- buffer_factory()->default_size(_world->uris().atom_Sequence));
-}
-
-SampleCount
-Engine::event_time()
-{
- if (ThreadManager::single_threaded) {
- return 0;
- }
-
- return _driver->frame_time() + _driver->block_length();
-}
-
-uint64_t
-Engine::current_time() const
-{
- return _clock.now_microseconds();
-}
-
-void
-Engine::reset_load()
-{
- _reset_load_flag = true;
-}
-
-void
-Engine::init(double sample_rate, uint32_t block_length, size_t seq_size)
-{
- set_driver(SPtr<Driver>(new DirectDriver(*this, sample_rate, block_length, seq_size)));
-}
-
-bool
-Engine::supports_dynamic_ports() const
-{
- return !_driver || _driver->dynamic_ports();
-}
-
-bool
-Engine::activate()
-{
- if (!_driver) {
- return false;
- }
-
- ThreadManager::single_threaded = true;
-
- const Ingen::URIs& uris = world()->uris();
-
- if (!_root_graph) {
- // No root graph has been loaded, create an empty one
- const Properties properties = {
- {uris.rdf_type, uris.ingen_Graph},
- {uris.ingen_polyphony,
- Property(_world->forge().make(1),
- Resource::Graph::INTERNAL)}};
-
- enqueue_event(
- new Events::CreateGraph(
- *this, SPtr<Interface>(), -1, 0, Raul::Path("/"), properties));
-
- flush_events(std::chrono::milliseconds(10));
- if (!_root_graph) {
- return false;
- }
- }
-
- _driver->activate();
- _root_graph->enable();
-
- ThreadManager::single_threaded = false;
- _activated = true;
-
- return true;
-}
-
-void
-Engine::deactivate()
-{
- if (_driver) {
- _driver->deactivate();
- }
-
- if (_root_graph) {
- _root_graph->deactivate();
- }
-
- ThreadManager::single_threaded = true;
- _activated = false;
-}
-
-unsigned
-Engine::run(uint32_t sample_count)
-{
- RunContext& ctx = run_context();
- _cycle_start_time = current_time();
-
- post_processor()->set_end_time(ctx.end());
-
- // Process events that came in during the last cycle
- // (Aiming for jitter-free 1 block event latency, ideally)
- const unsigned n_processed_events = process_events();
-
- // Reset load if graph structure has changed
- if (_reset_load_flag) {
- _run_load = Load();
- _reset_load_flag = false;
- }
-
- // Run root graph
- if (_root_graph) {
- // Apply control bindings to input
- control_bindings()->pre_process(
- ctx, _root_graph->port_impl(0)->buffer(0).get());
-
- // Run root graph for this cycle
- _root_graph->process(ctx);
-
- // Emit control binding feedback
- control_bindings()->post_process(
- ctx, _root_graph->port_impl(1)->buffer(0).get());
- }
-
- // Update load for this cycle
- if (ctx.duration() > 0) {
- _run_load.update(current_time() - _cycle_start_time, ctx.duration());
- }
-
- return n_processed_events;
-}
-
-bool
-Engine::pending_events() const
-{
- return !_pre_processor->empty() || _post_processor->pending();
-}
-
-void
-Engine::enqueue_event(Event* ev, Event::Mode mode)
-{
- _pre_processor->event(ev, mode);
-}
-
-unsigned
-Engine::process_events()
-{
- const size_t MAX_EVENTS_PER_CYCLE = run_context().nframes() / 8;
- return _pre_processor->process(
- run_context(), *_post_processor, MAX_EVENTS_PER_CYCLE);
-}
-
-unsigned
-Engine::process_all_events()
-{
- return _pre_processor->process(run_context(), *_post_processor, 0);
-}
-
-Log&
-Engine::log() const
-{
- return _world->log();
-}
-
-void
-Engine::register_client(SPtr<Interface> client)
-{
- log().info(fmt("Registering client <%1%>\n") % client->uri().c_str());
- _broadcaster->register_client(client);
-}
-
-bool
-Engine::unregister_client(SPtr<Interface> client)
-{
- log().info(fmt("Unregistering client <%1%>\n") % client->uri().c_str());
- return _broadcaster->unregister_client(client);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/Engine.hpp b/src/server/Engine.hpp
deleted file mode 100644
index f5ba1feb..00000000
--- a/src/server/Engine.hpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- 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_ENGINE_ENGINE_HPP
-#define INGEN_ENGINE_ENGINE_HPP
-
-#include <chrono>
-#include <condition_variable>
-#include <mutex>
-#include <random>
-
-#include "ingen/Clock.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/Properties.hpp"
-#include "ingen/ingen.h"
-#include "ingen/types.hpp"
-
-#include "Event.hpp"
-#include "Load.hpp"
-
-namespace Raul {
-class Maid;
-class RingBuffer;
-}
-
-namespace Ingen {
-
-class AtomReader;
-class Interface;
-class Log;
-class Store;
-class World;
-
-namespace Server {
-
-class BlockFactory;
-class Broadcaster;
-class BufferFactory;
-class ControlBindings;
-class Driver;
-class EventWriter;
-class GraphImpl;
-class LV2Options;
-class PostProcessor;
-class PreProcessor;
-class RunContext;
-class SocketListener;
-class Task;
-class UndoStack;
-class Worker;
-
-/**
- The engine which executes the process graph.
-
- This is a simple class that provides pointers to the various components
- that make up the engine implementation. In processes with a local engine,
- it can be accessed via the Ingen::World.
-
- @ingroup engine
-*/
-class INGEN_API Engine : public EngineBase
-{
-public:
- explicit Engine(Ingen::World* world);
- virtual ~Engine();
-
- Engine(const Engine&) = delete;
- Engine& operator=(const Engine&) = delete;
-
- // EngineBase methods
- virtual void init(double sample_rate, uint32_t block_length, size_t seq_size);
- virtual bool supports_dynamic_ports() const;
- virtual bool activate();
- virtual void deactivate();
- virtual bool pending_events() const;
- virtual unsigned run(uint32_t sample_count);
- virtual void quit();
- virtual bool main_iteration();
- virtual void register_client(SPtr<Interface> client);
- virtual bool unregister_client(SPtr<Interface> client);
-
- void listen();
-
- /** Return a random [0..1] float with uniform distribution */
- float frand() { return _uniform_dist(_rand_engine); }
-
- void set_driver(SPtr<Driver> driver);
-
- /** Return the frame time to execute an event that arrived now.
- *
- * This aims to return a time one cycle from "now", so that events ideally
- * have 1 cycle of latency with no jitter.
- */
- SampleCount event_time();
-
- /** Return the time this cycle began processing in microseconds.
- *
- * This value is comparable to the value returned by current_time().
- */
- inline uint64_t cycle_start_time(const RunContext& context) const {
- return _cycle_start_time;
- }
-
- /** Return the current time in microseconds. */
- uint64_t current_time() const;
-
- /** Reset the load statistics (when the expected DSP load changes). */
- void reset_load();
-
- /** Enqueue an event to be processed (non-realtime threads only). */
- void enqueue_event(Event* ev, Event::Mode mode=Event::Mode::NORMAL);
-
- /** Process events (process thread only). */
- unsigned process_events();
-
- /** Process all events (no RT limits). */
- unsigned process_all_events();
-
- Ingen::World* world() const { return _world; }
- Log& log() const;
-
- const SPtr<Interface>& interface() const { return _interface; }
- const SPtr<EventWriter>& event_writer() const { return _event_writer; }
- const UPtr<AtomReader>& atom_interface() const { return _atom_interface; }
- const UPtr<BlockFactory>& block_factory() const { return _block_factory; }
- const UPtr<Broadcaster>& broadcaster() const { return _broadcaster; }
- const UPtr<BufferFactory>& buffer_factory() const { return _buffer_factory; }
- const UPtr<ControlBindings>& control_bindings() const { return _control_bindings; }
- const SPtr<Driver>& driver() const { return _driver; }
- const UPtr<PostProcessor>& post_processor() const { return _post_processor; }
- const UPtr<Raul::Maid>& maid() const { return _maid; }
- const UPtr<UndoStack>& undo_stack() const { return _undo_stack; }
- const UPtr<UndoStack>& redo_stack() const { return _redo_stack; }
- const UPtr<Worker>& worker() const { return _worker; }
- const UPtr<Worker>& sync_worker() const { return _sync_worker; }
-
- GraphImpl* root_graph() const { return _root_graph; }
- void set_root_graph(GraphImpl* graph);
-
- RunContext& run_context() { return *_run_contexts[0]; }
-
- void flush_events(const std::chrono::milliseconds& sleep_ms);
-
- void advance(SampleCount nframes);
- void locate(FrameTime s, SampleCount nframes);
- void emit_notifications(FrameTime end);
- bool pending_notifications();
- bool wait_for_tasks();
- void signal_tasks_available();
- Task* steal_task(unsigned start_thread);
-
- SPtr<Store> store() const;
-
- SampleRate sample_rate() const;
- SampleCount block_length() const;
- size_t sequence_size() const;
- size_t event_queue_size() const;
-
- size_t n_threads() const { return _run_contexts.size(); }
- bool atomic_bundles() const { return _atomic_bundles; }
- bool activated() const { return _activated; }
-
- Properties load_properties() const;
-
-private:
- Ingen::World* _world;
-
- SPtr<LV2Options> _options;
- UPtr<BufferFactory> _buffer_factory;
- UPtr<Raul::Maid> _maid;
- SPtr<Driver> _driver;
- UPtr<Worker> _worker;
- UPtr<Worker> _sync_worker;
- UPtr<Broadcaster> _broadcaster;
- UPtr<ControlBindings> _control_bindings;
- UPtr<BlockFactory> _block_factory;
- UPtr<UndoStack> _undo_stack;
- UPtr<UndoStack> _redo_stack;
- UPtr<PostProcessor> _post_processor;
- UPtr<PreProcessor> _pre_processor;
- UPtr<SocketListener> _listener;
- SPtr<EventWriter> _event_writer;
- SPtr<Interface> _interface;
- UPtr<AtomReader> _atom_interface;
- GraphImpl* _root_graph;
-
- std::vector<Raul::RingBuffer*> _notifications;
- std::vector<RunContext*> _run_contexts;
- uint64_t _cycle_start_time;
- Load _run_load;
- Clock _clock;
-
- std::mt19937 _rand_engine;
- std::uniform_real_distribution<float> _uniform_dist;
-
- std::condition_variable _tasks_available;
- std::mutex _tasks_mutex;
-
- bool _quit_flag;
- bool _reset_load_flag;
- bool _atomic_bundles;
- bool _activated;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_ENGINE_HPP
diff --git a/src/server/EnginePort.hpp b/src/server/EnginePort.hpp
deleted file mode 100644
index c14f363c..00000000
--- a/src/server/EnginePort.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_ENGINE_PORT_HPP
-#define INGEN_ENGINE_ENGINE_PORT_HPP
-
-#include "raul/Deletable.hpp"
-#include "raul/Noncopyable.hpp"
-
-#include <boost/intrusive/slist.hpp>
-
-#include "DuplexPort.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** A "system" port (e.g. a Jack port, an external port on Ingen).
- *
- * @ingroup engine
- */
-class EnginePort : public Raul::Noncopyable
- , public Raul::Deletable
- , public boost::intrusive::slist_base_hook<>
-{
-public:
- explicit EnginePort(DuplexPort* port)
- : _graph_port(port)
- , _buffer(nullptr)
- , _handle(nullptr)
- , _driver_index(0)
- {}
-
- void set_buffer(void* buf) { _buffer = buf; }
- void set_handle(void* buf) { _handle = buf; }
- void set_driver_index(uint32_t index) { _driver_index = index; }
-
- void* buffer() const { return _buffer; }
- void* handle() const { return _handle; }
- uint32_t driver_index() const { return _driver_index; }
- DuplexPort* graph_port() const { return _graph_port; }
- bool is_input() const { return _graph_port->is_input(); }
-
-protected:
- DuplexPort* _graph_port;
- void* _buffer;
- void* _handle;
- uint32_t _driver_index;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_ENGINE_PORT_HPP
diff --git a/src/server/Event.hpp b/src/server/Event.hpp
deleted file mode 100644
index d9095def..00000000
--- a/src/server/Event.hpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_EVENT_HPP
-#define INGEN_ENGINE_EVENT_HPP
-
-#include <atomic>
-
-#include "raul/Deletable.hpp"
-#include "raul/Noncopyable.hpp"
-#include "raul/Path.hpp"
-
-#include "ingen/Interface.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/Status.hpp"
-#include "ingen/types.hpp"
-
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-class RunContext;
-class PreProcessContext;
-
-/** An event (command) to perform some action on Ingen.
- *
- * Virtually all operations on Ingen are implemented as events. An event has
- * three distinct execution phases:
- *
- * 1) Pre-process: In a non-realtime thread, prepare event for execution
- * 2) Execute: In the audio thread, execute (apply) event
- * 3) Post-process: In a non-realtime thread, finalize event
- * (e.g. clean up and send replies)
- *
- * \ingroup engine
- */
-class Event : public Raul::Deletable, public Raul::Noncopyable
-{
-public:
- /** Event mode to distinguish normal events from undo events. */
- enum class Mode { NORMAL, UNDO, REDO };
-
- /** Execution mode for events that block and unblock preprocessing. */
- enum class Execution {
- NORMAL, ///< Normal pipelined execution
- ATOMIC, ///< Block pre-processing until this event is executed
- BLOCK, ///< Begin atomic block of events
- UNBLOCK ///< Finish atomic executed block of events
- };
-
- /** Pre-process event before execution (non-realtime). */
- virtual bool pre_process(PreProcessContext& ctx) = 0;
-
- /** Execute this event in the audio thread (realtime). */
- virtual void execute(RunContext& context) = 0;
-
- /** Post-process event after execution (non-realtime). */
- virtual void post_process() = 0;
-
- /** Write the inverse of this event to `sink`. */
- virtual void undo(Interface& target) {}
-
- /** Return true iff this event has been pre-processed. */
- inline bool is_prepared() const { return _status != Status::NOT_PREPARED; }
-
- /** Return the time stamp of this event. */
- inline SampleCount time() const { return _time; }
-
- /** Set the time stamp of this event. */
- inline void set_time(SampleCount time) { _time = time; }
-
- /** Get the next event to be processed after this one. */
- Event* next() const { return _next.load(); }
-
- /** Set the next event to be processed after this one. */
- void next(Event* ev) { _next = ev; }
-
- /** Return the status (success or error code) of this event. */
- Status status() const { return _status; }
-
- /** Return the blocking behaviour of this event (after construction). */
- virtual Execution get_execution() const { return Execution::NORMAL; }
-
- /** Return undo mode of this event. */
- Mode get_mode() const { return _mode; }
-
- /** Set the undo mode of this event. */
- void set_mode(Mode mode) { _mode = mode; }
-
- inline Engine& engine() { return _engine; }
-
-protected:
- Event(Engine& engine, SPtr<Interface> client, int32_t id, FrameTime time)
- : _engine(engine)
- , _next(nullptr)
- , _request_client(std::move(client))
- , _request_id(id)
- , _time(time)
- , _status(Status::NOT_PREPARED)
- , _mode(Mode::NORMAL)
- {}
-
- /** Constructor for internal events only */
- explicit Event(Engine& engine)
- : _engine(engine)
- , _next(nullptr)
- , _request_id(0)
- , _time(0)
- , _status(Status::NOT_PREPARED)
- , _mode(Mode::NORMAL)
- {}
-
- inline bool pre_process_done(Status st) {
- _status = st;
- return st == Status::SUCCESS;
- }
-
- inline bool pre_process_done(Status st, const URI& subject) {
- _err_subject = subject;
- return pre_process_done(st);
- }
-
- inline bool pre_process_done(Status st, const Raul::Path& subject) {
- return pre_process_done(st, path_to_uri(subject));
- }
-
- /** Respond to the originating client. */
- inline Status respond() {
- if (_request_client && _request_id) {
- _request_client->response(_request_id, _status, _err_subject);
- }
- return _status;
- }
-
- Engine& _engine;
- std::atomic<Event*> _next;
- SPtr<Interface> _request_client;
- int32_t _request_id;
- FrameTime _time;
- Status _status;
- std::string _err_subject;
- Mode _mode;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_EVENT_HPP
diff --git a/src/server/EventWriter.cpp b/src/server/EventWriter.cpp
deleted file mode 100644
index ebdf7562..00000000
--- a/src/server/EventWriter.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <boost/variant/apply_visitor.hpp>
-
-#include "ingen/URIs.hpp"
-
-#include "Engine.hpp"
-#include "EventWriter.hpp"
-#include "events.hpp"
-
-namespace Ingen {
-namespace Server {
-
-EventWriter::EventWriter(Engine& engine)
- : _engine(engine)
- , _event_mode(Event::Mode::NORMAL)
-{
-}
-
-SampleCount
-EventWriter::now() const
-{
- return _engine.event_time();
-}
-
-void
-EventWriter::message(const Message& msg)
-{
- boost::apply_visitor(*this, msg);
-}
-
-void
-EventWriter::operator()(const BundleBegin& msg)
-{
- _engine.enqueue_event(new Events::Mark(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const BundleEnd& msg)
-{
- _engine.enqueue_event(new Events::Mark(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Put& msg)
-{
- _engine.enqueue_event(new Events::Delta(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Delta& msg)
-{
- _engine.enqueue_event(new Events::Delta(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Copy& msg)
-{
- _engine.enqueue_event(new Events::Copy(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Move& msg)
-{
- _engine.enqueue_event(new Events::Move(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Del& msg)
-{
- _engine.enqueue_event(new Events::Delete(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Connect& msg)
-{
- _engine.enqueue_event(new Events::Connect(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Disconnect& msg)
-{
- _engine.enqueue_event(
- new Events::Disconnect(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const DisconnectAll& msg)
-{
- _engine.enqueue_event(
- new Events::DisconnectAll(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const SetProperty& msg)
-{
- _engine.enqueue_event(new Events::Delta(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Undo& msg)
-{
- _engine.enqueue_event(new Events::Undo(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Redo& msg)
-{
- _engine.enqueue_event(new Events::Undo(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-void
-EventWriter::operator()(const Get& msg)
-{
- _engine.enqueue_event(new Events::Get(_engine, _respondee, now(), msg),
- _event_mode);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/EventWriter.hpp b/src/server/EventWriter.hpp
deleted file mode 100644
index 2d4b9724..00000000
--- a/src/server/EventWriter.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_EVENTWRITER_HPP
-#define INGEN_ENGINE_EVENTWRITER_HPP
-
-#include <memory>
-#include <string>
-
-#include "ingen/Interface.hpp"
-#include "ingen/Resource.hpp"
-#include "ingen/types.hpp"
-
-#include "Event.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-
-/** An Interface that creates and enqueues Events for the Engine to execute.
- */
-class EventWriter : public Interface
-{
-public:
- explicit EventWriter(Engine& engine);
-
- URI uri() const override { return URI("ingen:/clients/event_writer"); }
-
- SPtr<Interface> respondee() const override {
- return _respondee;
- }
-
- void set_respondee(SPtr<Interface> respondee) override {
- _respondee = respondee;
- }
-
- void message(const Message& msg) override;
-
- void set_event_mode(Event::Mode mode) { _event_mode = mode; }
- Event::Mode get_event_mode() { return _event_mode; }
-
- 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&);
-
-protected:
- Engine& _engine;
- SPtr<Interface> _respondee;
- Event::Mode _event_mode;
-
-private:
- SampleCount now() const;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_EVENTWRITER_HPP
diff --git a/src/server/FrameTimer.hpp b/src/server/FrameTimer.hpp
deleted file mode 100644
index 367ac900..00000000
--- a/src/server/FrameTimer.hpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2017 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_FRAMETIMER_HPP
-#define INGEN_ENGINE_FRAMETIMER_HPP
-
-#include <chrono>
-#include <cmath>
-#include <cstdint>
-
-namespace Ingen {
-namespace Server {
-
-/** Delay-locked loop for monotonic sample time.
- *
- * See "Using a DLL to filter time" by Fons Adriaensen
- * http://kokkinizita.linuxaudio.org/papers/usingdll.pdf
- */
-class FrameTimer
-{
-public:
- static constexpr double PI = 3.14159265358979323846;
- static constexpr double bandwidth = 1.0 / 8.0; // Hz
- static constexpr double us_per_s = 1000000.0;
-
- FrameTimer(uint32_t period_size, uint32_t sample_rate)
- : tper(((double)period_size / (double)sample_rate) * us_per_s)
- , omega(2 * PI * bandwidth / us_per_s * tper)
- , b(sqrt(2) * omega)
- , c(omega * omega)
- , nper(period_size)
- {
- }
-
- /** Update the timer for current real time `usec` and frame `frame`. */
- void update(uint64_t usec, uint64_t frame) {
- if (!initialized || frame != n1) {
- init(usec, frame);
- return;
- }
-
- // Calculate loop error
- const double e = ((double)usec - t1);
-
- // Update loop
- t0 = t1;
- t1 += b * e + e2;
- e2 += c * e;
-
- // Update frame counts
- n0 = n1;
- n1 += nper;
- }
-
- /** Return an estimate of the frame time for current real time `usec`. */
- uint64_t frame_time(uint64_t usec) const {
- if (!initialized) {
- return 0;
- }
-
- const double delta = (double)usec - t0;
- const double period = t1 - t0;
- return n0 + std::round(delta / period * nper);
- }
-
-private:
- void init(uint64_t now, uint64_t frame) {
- // Init loop
- e2 = tper;
- t0 = now;
- t1 = t0 + e2;
-
- // Init sample counts
- n0 = frame;
- n1 = n0 + nper;
-
- initialized = true;
- }
-
- const double tper;
- const double omega;
- const double b;
- const double c;
-
- uint64_t nper;
- double e2;
- double t0;
- double t1;
- uint64_t n0;
- uint64_t n1;
- bool initialized;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_FRAMETIMER_HPP
diff --git a/src/server/GraphImpl.cpp b/src/server/GraphImpl.cpp
deleted file mode 100644
index f9c4cb54..00000000
--- a/src/server/GraphImpl.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <unordered_map>
-
-#include "ingen/Log.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "raul/Maid.hpp"
-
-#include "ArcImpl.hpp"
-#include "BlockImpl.hpp"
-#include "BufferFactory.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "GraphPlugin.hpp"
-#include "PortImpl.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-GraphImpl::GraphImpl(Engine& engine,
- const Raul::Symbol& symbol,
- uint32_t poly,
- GraphImpl* parent,
- SampleRate srate,
- uint32_t internal_poly)
- : BlockImpl(new GraphPlugin(engine.world()->uris(),
- engine.world()->uris().ingen_Graph,
- Raul::Symbol("graph"),
- "Ingen Graph"),
- symbol, poly, parent, srate)
- , _engine(engine)
- , _poly_pre(internal_poly)
- , _poly_process(internal_poly)
- , _process(false)
-{
- assert(internal_poly >= 1);
- assert(internal_poly <= 128);
-}
-
-GraphImpl::~GraphImpl()
-{
- delete _plugin;
-}
-
-BlockImpl*
-GraphImpl::duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent)
-{
- BufferFactory& bufs = *engine.buffer_factory();
- const SampleRate rate = engine.sample_rate();
-
- // Duplicate graph
- GraphImpl* dup = new GraphImpl(
- engine, symbol, _polyphony, parent, rate, _poly_process);
-
- Properties props = properties();
- props.erase(bufs.uris().lv2_symbol);
- props.insert({bufs.uris().lv2_symbol, bufs.forge().alloc(symbol.c_str())});
- dup->set_properties(props);
-
- // We need a map of port duplicates to duplicate arcs
- typedef std::unordered_map<PortImpl*, PortImpl*> PortMap;
- PortMap port_map;
-
- // Add duplicates of all ports
- dup->_ports = bufs.maid().make_managed<Ports>(num_ports(), nullptr);
- for (PortList::iterator p = _inputs.begin(); p != _inputs.end(); ++p) {
- DuplexPort* p_dup = p->duplicate(engine, p->symbol(), dup);
- dup->_inputs.push_front(*p_dup);
- (*dup->_ports)[p->index()] = p_dup;
- port_map.insert({&*p, p_dup});
- }
- for (PortList::iterator p = _outputs.begin(); p != _outputs.end(); ++p) {
- DuplexPort* p_dup = p->duplicate(engine, p->symbol(), dup);
- dup->_outputs.push_front(*p_dup);
- (*dup->_ports)[p->index()] = p_dup;
- port_map.insert({&*p, p_dup});
- }
-
- // Add duplicates of all blocks
- for (auto& b : _blocks) {
- BlockImpl* b_dup = b.duplicate(engine, b.symbol(), dup);
- dup->add_block(*b_dup);
- b_dup->activate(*engine.buffer_factory());
- for (uint32_t p = 0; p < b.num_ports(); ++p) {
- port_map.insert({b.port_impl(p), b_dup->port_impl(p)});
- }
- }
-
- // Add duplicates of all arcs
- for (const auto& a : _arcs) {
- SPtr<ArcImpl> arc = dynamic_ptr_cast<ArcImpl>(a.second);
- if (arc) {
- auto t = port_map.find(arc->tail());
- auto h = port_map.find(arc->head());
- if (t != port_map.end() && h != port_map.end()) {
- dup->add_arc(SPtr<ArcImpl>(new ArcImpl(t->second, h->second)));
- }
- }
- }
-
- return dup;
-}
-
-void
-GraphImpl::activate(BufferFactory& bufs)
-{
- BlockImpl::activate(bufs);
-
- for (auto& b : _blocks) {
- b.activate(bufs);
- }
-
- assert(_activated);
-}
-
-void
-GraphImpl::deactivate()
-{
- if (_activated) {
- BlockImpl::deactivate();
-
- for (auto& b : _blocks) {
- if (b.activated()) {
- b.deactivate();
- }
- }
- }
-}
-
-void
-GraphImpl::disable(RunContext& context)
-{
- _process = false;
- for (auto& o : _outputs) {
- o.clear_buffers(context);
- }
-}
-
-bool
-GraphImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- // TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)
-
- for (auto& b : _blocks) {
- b.prepare_poly(bufs, poly);
- }
-
- _poly_pre = poly;
- return true;
-}
-
-bool
-GraphImpl::apply_internal_poly(RunContext& context,
- BufferFactory& bufs,
- Raul::Maid& maid,
- uint32_t poly)
-{
- // TODO: Subgraph dynamic polyphony (i.e. changing port polyphony)
-
- for (auto& b : _blocks) {
- b.apply_poly(context, poly);
- }
-
- for (auto& b : _blocks) {
- for (uint32_t j = 0; j < b.num_ports(); ++j) {
- PortImpl* const port = b.port_impl(j);
- if (port->is_input() && dynamic_cast<InputPort*>(port)->direct_connect()) {
- port->setup_buffers(context, bufs, port->poly());
- }
- port->connect_buffers();
- }
- }
-
- const bool polyphonic = parent_graph() && (poly == parent_graph()->internal_poly_process());
- for (auto& o : _outputs) {
- o.setup_buffers(context, bufs, polyphonic ? poly : 1);
- }
-
- _poly_process = poly;
- return true;
-}
-
-void
-GraphImpl::pre_process(RunContext& context)
-{
- // Mix down input ports and connect buffers
- for (uint32_t i = 0; i < num_ports(); ++i) {
- PortImpl* const port = _ports->at(i);
- if (!port->is_driver_port()) {
- port->pre_process(context);
- port->pre_run(context);
- port->connect_buffers();
- }
- }
-}
-
-void
-GraphImpl::process(RunContext& context)
-{
- if (!_process) {
- return;
- }
-
- pre_process(context);
- run(context);
- post_process(context);
-}
-
-void
-GraphImpl::run(RunContext& context)
-{
- if (_compiled_graph) {
- _compiled_graph->run(context);
- }
-}
-
-void
-GraphImpl::set_buffer_size(RunContext& context,
- BufferFactory& bufs,
- LV2_URID type,
- uint32_t size)
-{
- BlockImpl::set_buffer_size(context, bufs, type, size);
-
- if (_compiled_graph) {
- // FIXME
- // for (size_t i = 0; i < _compiled_graph->size(); ++i) {
- // const CompiledBlock& block = (*_compiled_graph)[i];
- // block.block()->set_buffer_size(context, bufs, type, size);
- // }
- }
-}
-
-void
-GraphImpl::add_block(BlockImpl& block)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- _blocks.push_front(block);
-}
-
-void
-GraphImpl::remove_block(BlockImpl& block)
-{
- _blocks.erase(_blocks.iterator_to(block));
-}
-
-void
-GraphImpl::add_arc(SPtr<ArcImpl> a)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- _arcs.emplace(std::make_pair(a->tail(), a->head()), a);
-}
-
-SPtr<ArcImpl>
-GraphImpl::remove_arc(const PortImpl* tail, const PortImpl* dst_port)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- auto i = _arcs.find(std::make_pair(tail, dst_port));
- if (i != _arcs.end()) {
- SPtr<ArcImpl> arc = dynamic_ptr_cast<ArcImpl>(i->second);
- _arcs.erase(i);
- return arc;
- } else {
- return SPtr<ArcImpl>();
- }
-}
-
-bool
-GraphImpl::has_arc(const PortImpl* tail, const PortImpl* dst_port) const
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- auto i = _arcs.find(std::make_pair(tail, dst_port));
- return (i != _arcs.end());
-}
-
-void
-GraphImpl::set_compiled_graph(MPtr<CompiledGraph>&& cg)
-{
- if (_compiled_graph && _compiled_graph != cg) {
- _engine.reset_load();
- }
- _compiled_graph = std::move(cg);
-}
-
-uint32_t
-GraphImpl::num_ports_non_rt() const
-{
- ThreadManager::assert_not_thread(THREAD_PROCESS);
- return _inputs.size() + _outputs.size();
-}
-
-bool
-GraphImpl::has_port_with_index(uint32_t index) const
-{
- BufferFactory& bufs = *_engine.buffer_factory();
- const auto index_atom = bufs.forge().make(int32_t(index));
-
- for (auto p = _inputs.begin(); p != _inputs.end(); ++p) {
- if (p->has_property(bufs.uris().lv2_index, index_atom)) {
- return true;
- }
- }
-
- for (auto p = _outputs.begin(); p != _outputs.end(); ++p) {
- if (p->has_property(bufs.uris().lv2_index, index_atom)) {
- return true;
- }
- }
-
- return false;
-}
-
-void
-GraphImpl::remove_port(DuplexPort& port)
-{
- if (port.is_input()) {
- _inputs.erase(_inputs.iterator_to(port));
- } else {
- _outputs.erase(_outputs.iterator_to(port));
- }
-}
-
-void
-GraphImpl::clear_ports()
-{
- _inputs.clear();
- _outputs.clear();
-}
-
-MPtr<BlockImpl::Ports>
-GraphImpl::build_ports_array(Raul::Maid& maid)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- const size_t n = _inputs.size() + _outputs.size();
- MPtr<Ports> result = maid.make_managed<Ports>(n);
-
- std::map<size_t, DuplexPort*> ports;
- for (PortList::iterator p = _inputs.begin(); p != _inputs.end(); ++p) {
- ports.emplace(p->index(), &*p);
- }
- for (PortList::iterator p = _outputs.begin(); p != _outputs.end(); ++p) {
- ports.emplace(p->index(), &*p);
- }
-
- size_t i = 0;
- for (const auto& p : ports) {
- result->at(i++) = p.second;
- }
-
- assert(i == n);
-
- return result;
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/GraphImpl.hpp b/src/server/GraphImpl.hpp
deleted file mode 100644
index 3f11a84a..00000000
--- a/src/server/GraphImpl.hpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_GRAPHIMPL_HPP
-#define INGEN_ENGINE_GRAPHIMPL_HPP
-
-#include <cstdlib>
-
-#include "ingen/ingen.h"
-
-#include "BlockImpl.hpp"
-#include "CompiledGraph.hpp"
-#include "DuplexPort.hpp"
-#include "PluginImpl.hpp"
-#include "PortType.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-
-class Arc;
-
-namespace Server {
-
-class ArcImpl;
-class CompiledGraph;
-class Engine;
-class RunContext;
-
-/** A group of blocks in a graph, possibly polyphonic.
- *
- * Note that this is also a Block, just one which contains Blocks.
- * Therefore infinite subgraphing is possible, of polyphonic
- * graphs of polyphonic blocks etc. etc.
- *
- * \ingroup engine
- */
-class GraphImpl : public BlockImpl
-{
-public:
- GraphImpl(Engine& engine,
- const Raul::Symbol& symbol,
- uint32_t poly,
- GraphImpl* parent,
- SampleRate srate,
- uint32_t internal_poly);
-
- virtual ~GraphImpl();
-
- virtual GraphType graph_type() const { return GraphType::GRAPH; }
-
- BlockImpl* duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent);
-
- void activate(BufferFactory& bufs);
- void deactivate();
-
- void pre_process(RunContext& context);
- void process(RunContext& context);
- void run(RunContext& context);
-
- void set_buffer_size(RunContext& context,
- BufferFactory& bufs,
- LV2_URID type,
- uint32_t size);
-
- /** Prepare for a new (internal) polyphony value.
- *
- * Pre-process thread, poly is actually applied by apply_internal_poly.
- * \return true on success.
- */
- bool prepare_internal_poly(BufferFactory& bufs, uint32_t poly);
-
- /** Apply a new (internal) polyphony value.
- *
- * Audio thread.
- *
- * \param context Process context
- * \param bufs New set of buffers
- * \param poly Must be < the most recent value passed to prepare_internal_poly.
- * \param maid Any objects no longer needed will be pushed to this
- */
- bool apply_internal_poly(RunContext& context,
- BufferFactory& bufs,
- Raul::Maid& maid,
- uint32_t poly);
-
- // Graph specific stuff not inherited from Block
-
- typedef boost::intrusive::slist<
- BlockImpl, boost::intrusive::constant_time_size<true> > Blocks;
-
- /** Add a block to this graph.
- * Pre-process thread only.
- */
- void add_block(BlockImpl& block);
-
- /** Remove a block from this graph.
- * Pre-process thread only.
- */
- void remove_block(BlockImpl& block);
-
- Blocks& blocks() { return _blocks; }
- const Blocks& blocks() const { return _blocks; }
-
- uint32_t num_ports_non_rt() const;
- bool has_port_with_index(uint32_t index) const;
-
- typedef boost::intrusive::slist<
- DuplexPort, boost::intrusive::constant_time_size<true> > PortList;
-
- void add_input(DuplexPort& port) {
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- assert(port.is_input());
- _inputs.push_front(port);
- }
-
- void add_output(DuplexPort& port) {
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- assert(port.is_output());
- _outputs.push_front(port);
- }
-
- /** Remove port from ports list used in pre-processing thread.
- *
- * Port is not removed from ports array for process thread (which could be
- * simultaneously running).
- *
- * Pre-processing thread or situations that won't cause races with it only.
- */
- void remove_port(DuplexPort& port);
-
- /** Remove all ports from ports list used in pre-processing thread.
- *
- * Ports are not removed from ports array for process thread (which could be
- * simultaneously running). Returned is a (inputs, outputs) pair.
- *
- * Pre-processing thread or situations that won't cause races with it only.
- */
- void clear_ports();
-
- /** Add an arc to this graph.
- * Pre-processing thread only.
- */
- void add_arc(SPtr<ArcImpl> a);
-
- /** Remove an arc from this graph.
- * Pre-processing thread only.
- */
- SPtr<ArcImpl> remove_arc(const PortImpl* tail, const PortImpl* dst_port);
-
- bool has_arc(const PortImpl* tail, const PortImpl* dst_port) const;
-
- /** Set a new compiled graph to run, and return the old one. */
- void set_compiled_graph(MPtr<CompiledGraph>&& cg);
-
- const MPtr<Ports>& external_ports() { return _ports; }
-
- void set_external_ports(MPtr<Ports>&& pa) { _ports = std::move(pa); }
-
- MPtr<Ports> build_ports_array(Raul::Maid& maid);
-
- /** Whether to run this graph's DSP bits in the audio thread */
- bool enabled() const { return _process; }
- void enable() { _process = true; }
- void disable(RunContext& context);
-
- uint32_t internal_poly() const { return _poly_pre; }
- uint32_t internal_poly_process() const { return _poly_process; }
-
- Engine& engine() { return _engine; }
-
-private:
- Engine& _engine;
- uint32_t _poly_pre; ///< Pre-process thread only
- uint32_t _poly_process; ///< Process thread only
- MPtr<CompiledGraph> _compiled_graph; ///< Process thread only
- PortList _inputs; ///< Pre-process thread only
- PortList _outputs; ///< Pre-process thread only
- Blocks _blocks; ///< Pre-process thread only
- bool _process; ///< True iff graph is enabled
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_GRAPHIMPL_HPP
diff --git a/src/server/GraphPlugin.hpp b/src/server/GraphPlugin.hpp
deleted file mode 100644
index 308ed91a..00000000
--- a/src/server/GraphPlugin.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_GRAPHPLUGIN_HPP
-#define INGEN_ENGINE_GRAPHPLUGIN_HPP
-
-#include <string>
-#include "PluginImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-
-/** Implementation of a Graph plugin.
- *
- * Graphs don't actually work like this yet...
- */
-class GraphPlugin : public PluginImpl
-{
-public:
- GraphPlugin(URIs& uris,
- const URI& uri,
- const Raul::Symbol& symbol,
- const std::string& name)
- : PluginImpl(uris, uris.ingen_Graph.urid, uri)
- {}
-
- BlockImpl* instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state)
- {
- return nullptr;
- }
-
- const Raul::Symbol symbol() const { return Raul::Symbol("graph"); }
- const std::string name() const { return "Ingen Graph"; }
-
-private:
- const std::string _symbol;
- const std::string _name;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_GRAPHPLUGIN_HPP
diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp
deleted file mode 100644
index 2f22491f..00000000
--- a/src/server/InputPort.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-#include <cassert>
-
-#include "ingen/Log.hpp"
-#include "ingen/URIs.hpp"
-
-#include "ArcImpl.hpp"
-#include "BlockImpl.hpp"
-#include "Buffer.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "RunContext.hpp"
-#include "mix.hpp"
-
-namespace Ingen {
-namespace Server {
-
-InputPort::InputPort(BufferFactory& bufs,
- BlockImpl* parent,
- const Raul::Symbol& symbol,
- uint32_t index,
- uint32_t poly,
- PortType type,
- LV2_URID buffer_type,
- const Atom& value,
- size_t buffer_size)
- : PortImpl(bufs, parent, symbol, index, poly, type, buffer_type, value, buffer_size, false)
- , _num_arcs(0)
-{
- const Ingen::URIs& uris = bufs.uris();
-
- if (parent->graph_type() != Node::GraphType::GRAPH) {
- add_property(uris.rdf_type, uris.lv2_InputPort.urid);
- }
-}
-
-bool
-InputPort::apply_poly(RunContext& context, uint32_t poly)
-{
- bool ret = PortImpl::apply_poly(context, poly);
- if (!ret) {
- poly = 1;
- }
-
- assert(_voices->size() >= poly);
-
- return true;
-}
-
-bool
-InputPort::get_buffers(BufferFactory& bufs,
- PortImpl::GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const
-{
- if (is_a(PortType::ATOM) && !_value.is_valid()) {
- poly = 1;
- }
-
- if (is_a(PortType::AUDIO) && num_in_arcs == 0) {
- // Audio input with no arcs, use shared zero buffer
- for (uint32_t v = 0; v < poly; ++v) {
- voices->at(v).buffer = bufs.silent_buffer();
- }
- return false;
- }
-
- // Otherwise, allocate local buffers
- for (uint32_t v = 0; v < poly; ++v) {
- voices->at(v).buffer.reset();
- voices->at(v).buffer = (bufs.*get)(
- buffer_type(), _value.type(), _buffer_size);
- voices->at(v).buffer->clear();
- if (_value.is_valid()) {
- voices->at(v).buffer->set_value(_value);
- }
- }
- return true;
-}
-
-bool
-InputPort::pre_get_buffers(BufferFactory& bufs,
- MPtr<Voices>& voices,
- uint32_t poly) const
-{
- return get_buffers(bufs, &BufferFactory::get_buffer, voices, poly, _num_arcs);
-}
-
-bool
-InputPort::setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly)
-{
- if (is_a(PortType::ATOM) && !_value.is_valid()) {
- poly = 1;
- }
-
- if (_arcs.size() == 1 && !is_a(PortType::ATOM) && !_arcs.front().must_mix()) {
- // Single non-mixing connection, use buffers directly
- for (uint32_t v = 0; v < poly; ++v) {
- _voices->at(v).buffer = _arcs.front().buffer(v);
- }
- return false;
- }
-
- return get_buffers(bufs, &BufferFactory::claim_buffer, _voices, poly, _arcs.size());
-}
-
-void
-InputPort::add_arc(RunContext& context, ArcImpl& c)
-{
- _arcs.push_front(c);
-}
-
-void
-InputPort::remove_arc(ArcImpl& arc)
-{
- _arcs.erase(_arcs.iterator_to(arc));
-}
-
-uint32_t
-InputPort::max_tail_poly(RunContext& context) const
-{
- return parent_block()->parent_graph()->internal_poly_process();
-}
-
-void
-InputPort::pre_process(RunContext& context)
-{
- if (_arcs.empty()) {
- // No incoming arcs, just handle user-set value
- for (uint32_t v = 0; v < _poly; ++v) {
- // Update set state
- update_set_state(context, v);
-
- // Prepare for write in case a set event executes this cycle
- if (!_parent->is_main()) {
- buffer(v)->prepare_write(context);
- }
- }
- } else if (direct_connect()) {
- // Directly connected, use source's buffer directly
- for (uint32_t v = 0; v < _poly; ++v) {
- _voices->at(v).buffer = _arcs.front().buffer(v);
- }
- } else {
- // Mix down to local buffers in pre_run()
- for (uint32_t v = 0; v < _poly; ++v) {
- buffer(v)->prepare_write(context);
- }
- }
-}
-
-void
-InputPort::pre_run(RunContext& context)
-{
- if ((_user_buffer || !_arcs.empty()) && !direct_connect()) {
- const uint32_t src_poly = max_tail_poly(context);
- const uint32_t max_n_srcs = _arcs.size() * src_poly + 1;
-
- for (uint32_t v = 0; v < _poly; ++v) {
- if (!buffer(v)->get<void>()) {
- continue;
- }
-
- // Get all sources for this voice
- const Buffer* srcs[max_n_srcs];
- uint32_t n_srcs = 0;
-
- if (_user_buffer) {
- // Add buffer with user/UI input for this cycle
- srcs[n_srcs++] = _user_buffer.get();
- }
-
- for (const auto& arc : _arcs) {
- if (_poly == 1) {
- // P -> 1 or 1 -> 1: all tail voices => each head voice
- for (uint32_t w = 0; w < arc.tail()->poly(); ++w) {
- assert(n_srcs < max_n_srcs);
- srcs[n_srcs++] = arc.buffer(w, context.offset()).get();
- assert(srcs[n_srcs - 1]);
- }
- } else {
- // P -> P or 1 -> P: tail voice => corresponding head voice
- assert(n_srcs < max_n_srcs);
- srcs[n_srcs++] = arc.buffer(v, context.offset()).get();
- assert(srcs[n_srcs - 1]);
- }
- }
-
- // Then mix them into our buffer for this voice
- mix(context, buffer(v).get(), srcs, n_srcs);
- update_values(context.offset(), v);
- }
- } else if (is_a(PortType::CONTROL)) {
- for (uint32_t v = 0; v < _poly; ++v) {
- update_values(context.offset(), v);
- }
- }
-}
-
-SampleCount
-InputPort::next_value_offset(SampleCount offset, SampleCount end) const
-{
- SampleCount earliest = end;
-
- if (_user_buffer) {
- earliest = _user_buffer->next_value_offset(offset, end);
- }
-
- for (const auto& arc : _arcs) {
- const SampleCount o = arc.tail()->next_value_offset(offset, end);
- if (o < earliest) {
- earliest = o;
- }
- }
-
- return earliest;
-}
-
-void
-InputPort::post_process(RunContext& context)
-{
- if (!_arcs.empty() || _force_monitor_update) {
- monitor(context, _force_monitor_update);
- _force_monitor_update = false;
- }
-
- /* Finished processing any user/UI messages for this cycle, drop reference
- to user buffer. */
- _user_buffer.reset();
-}
-
-bool
-InputPort::direct_connect() const
-{
- return _arcs.size() == 1
- && !_parent->is_main()
- && !_arcs.front().must_mix()
- && buffer(0)->type() != _bufs.uris().atom_Sequence;
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/InputPort.hpp b/src/server/InputPort.hpp
deleted file mode 100644
index 708f7ea2..00000000
--- a/src/server/InputPort.hpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_INPUTPORT_HPP
-#define INGEN_ENGINE_INPUTPORT_HPP
-
-#include <cassert>
-#include <cstdlib>
-
-#include <boost/intrusive/slist.hpp>
-
-#include "ingen/types.hpp"
-
-#include "ArcImpl.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class ArcImpl;
-class BlockImpl;
-class RunContext;
-
-/** An input port on a Block or Graph.
- *
- * All ports have a Buffer, but the actual contents (data) of that buffer may be
- * set directly to the incoming arc's buffer if there's only one inbound
- * arc, to eliminate the need to copy/mix.
- *
- * If a port has multiple arcs, they will be mixed down into the local
- * buffer and it will be used.
- *
- * \ingroup engine
- */
-class InputPort : public PortImpl
-{
-public:
- InputPort(BufferFactory& bufs,
- BlockImpl* parent,
- const Raul::Symbol& symbol,
- uint32_t index,
- uint32_t poly,
- PortType type,
- LV2_URID buffer_type,
- const Atom& value,
- size_t buffer_size = 0);
-
- typedef boost::intrusive::slist<ArcImpl,
- boost::intrusive::constant_time_size<true>
- > Arcs;
-
- /** Return the maximum polyphony of an output connected to this input. */
- virtual uint32_t max_tail_poly(RunContext& context) const;
-
- bool apply_poly(RunContext& context, uint32_t poly);
-
- /** Add an arc. Realtime safe.
- *
- * The buffer of this port will be set directly to the arc's buffer
- * if there is only one arc, since no copying/mixing needs to take place.
- *
- * setup_buffers() must be called later for the change to take effect.
- */
- void add_arc(RunContext& context, ArcImpl& c);
-
- /** Remove an arc. Realtime safe.
- *
- * setup_buffers() must be called later for the change to take effect.
- */
- void remove_arc(ArcImpl& arc);
-
- /** Like `get_buffers`, but for the pre-process thread.
- *
- * This uses the "current" number of arcs fromthe perspective of the
- * pre-process thread to allocate buffers for application of a
- * connection/disconnection/etc in the next process cycle.
- */
- bool pre_get_buffers(BufferFactory& bufs,
- MPtr<Voices>& voices,
- uint32_t poly) const;
-
- bool setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly);
-
- /** Set up buffer pointers. */
- void pre_process(RunContext& context);
-
- /** Prepare buffer for access, mixing if necessary. */
- void pre_run(RunContext& context);
-
- /** Prepare buffer for next process cycle. */
- void post_process(RunContext& context);
-
- SampleCount next_value_offset(SampleCount offset, SampleCount end) const;
-
- size_t num_arcs() const { return _num_arcs; }
- void increment_num_arcs() { ++_num_arcs; }
- void decrement_num_arcs() { --_num_arcs; }
-
- bool direct_connect() const;
-
-protected:
- bool get_buffers(BufferFactory& bufs,
- PortImpl::GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const;
-
- size_t _num_arcs; ///< Pre-process thread
- Arcs _arcs; ///< Audio thread
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_INPUTPORT_HPP
diff --git a/src/server/InternalBlock.cpp b/src/server/InternalBlock.cpp
deleted file mode 100644
index 3d8f7390..00000000
--- a/src/server/InternalBlock.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "Buffer.hpp"
-#include "Engine.hpp"
-#include "InternalBlock.hpp"
-#include "InternalPlugin.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-InternalBlock::InternalBlock(PluginImpl* plugin,
- const Raul::Symbol& symbol,
- bool poly,
- GraphImpl* parent,
- SampleRate rate)
- : BlockImpl(plugin, symbol, poly, parent, rate)
-{}
-
-BlockImpl*
-InternalBlock::duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent)
-{
- BufferFactory& bufs = *engine.buffer_factory();
-
- BlockImpl* copy = reinterpret_cast<InternalPlugin*>(_plugin)->instantiate(
- bufs, symbol, _polyphonic, parent_graph(), engine, nullptr);
-
- for (size_t i = 0; i < num_ports(); ++i) {
- const Atom& value = port_impl(i)->value();
- copy->port_impl(i)->set_property(bufs.uris().ingen_value, value);
- copy->port_impl(i)->set_value(value);
- }
-
- return copy;
-}
-
-void
-InternalBlock::pre_process(RunContext& context)
-{
- for (uint32_t i = 0; i < num_ports(); ++i) {
- PortImpl* const port = _ports->at(i);
- if (port->is_input()) {
- port->pre_process(context);
- } else if (port->buffer_type() == _plugin->uris().atom_Sequence) {
- /* Output sequences are initialized in LV2 format, an atom:Chunk
- with size set to the capacity of the buffer. Internal nodes
- don't care, so clear to an empty sequences so appending events
- results in a valid output. */
- for (uint32_t v = 0; v < port->poly(); ++v) {
- port->buffer(v)->clear();
- }
- }
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/InternalBlock.hpp b/src/server/InternalBlock.hpp
deleted file mode 100644
index a57bd89f..00000000
--- a/src/server/InternalBlock.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_INTERNALBLOCK_HPP
-#define INGEN_ENGINE_INTERNALBLOCK_HPP
-
-#include "BlockImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** An internal Block implemented inside Ingen.
- *
- * \ingroup engine
- */
-class InternalBlock : public BlockImpl
-{
-public:
- InternalBlock(PluginImpl* plugin,
- const Raul::Symbol& symbol,
- bool poly,
- GraphImpl* parent,
- SampleRate rate);
-
- BlockImpl* duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent);
-
- virtual void pre_process(RunContext& context);
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_BLOCKIMPL_HPP
diff --git a/src/server/InternalPlugin.cpp b/src/server/InternalPlugin.cpp
deleted file mode 100644
index 6529b9c0..00000000
--- a/src/server/InternalPlugin.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/URIs.hpp"
-#include "internals/Controller.hpp"
-#include "internals/BlockDelay.hpp"
-#include "internals/Note.hpp"
-#include "internals/Time.hpp"
-#include "internals/Trigger.hpp"
-
-#include "Engine.hpp"
-#include "InternalPlugin.hpp"
-
-namespace Ingen {
-namespace Server {
-
-using namespace Internals;
-
-InternalPlugin::InternalPlugin(URIs& uris,
- const URI& uri,
- const Raul::Symbol& symbol)
- : PluginImpl(uris, uris.ingen_Internal.urid, uri)
- , _symbol(symbol)
-{
- set_property(uris.rdf_type, uris.ingen_Internal);
-}
-
-BlockImpl*
-InternalPlugin::instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state)
-{
- const SampleCount srate = engine.sample_rate();
-
- if (uri() == NS_INTERNALS "BlockDelay") {
- return new BlockDelayNode(this, bufs, symbol, polyphonic, parent, srate);
- } else if (uri() == NS_INTERNALS "Controller") {
- return new ControllerNode(this, bufs, symbol, polyphonic, parent, srate);
- } else if (uri() == NS_INTERNALS "Note") {
- return new NoteNode(this, bufs, symbol, polyphonic, parent, srate);
- } else if (uri() == NS_INTERNALS "Time") {
- return new TimeNode(this, bufs, symbol, polyphonic, parent, srate);
- } else if (uri() == NS_INTERNALS "Trigger") {
- return new TriggerNode(this, bufs, symbol, polyphonic, parent, srate);
- } else {
- return nullptr;
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/InternalPlugin.hpp b/src/server/InternalPlugin.hpp
deleted file mode 100644
index 79309beb..00000000
--- a/src/server/InternalPlugin.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_INTERNALPLUGIN_HPP
-#define INGEN_ENGINE_INTERNALPLUGIN_HPP
-
-#include "raul/Symbol.hpp"
-
-#include "PluginImpl.hpp"
-
-#define NS_INTERNALS "http://drobilla.net/ns/ingen-internals#"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class BufferFactory;
-
-/** Implementation of an Internal plugin.
- */
-class InternalPlugin : public PluginImpl
-{
-public:
- InternalPlugin(URIs& uris,
- const URI& uri,
- const Raul::Symbol& symbol);
-
- BlockImpl* instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state);
-
- const Raul::Symbol symbol() const { return _symbol; }
-
-private:
- const Raul::Symbol _symbol;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_INTERNALPLUGIN_HPP
diff --git a/src/server/JackDriver.cpp b/src/server/JackDriver.cpp
deleted file mode 100644
index 973e3eb7..00000000
--- a/src/server/JackDriver.cpp
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen_config.h"
-
-#include <cstdlib>
-#include <string>
-
-#include <jack/midiport.h>
-#ifdef INGEN_JACK_SESSION
-#include <jack/session.h>
-#include <boost/format.hpp>
-#include "ingen/Serialiser.hpp"
-#endif
-#ifdef HAVE_JACK_METADATA
-#include <jack/metadata.h>
-#include "jackey.h"
-#endif
-
-#include "ingen/Configuration.hpp"
-#include "ingen/LV2Features.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-
-#include "Buffer.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "JackDriver.hpp"
-#include "PortImpl.hpp"
-#include "ThreadManager.hpp"
-#include "util.hpp"
-
-typedef jack_default_audio_sample_t jack_sample_t;
-
-namespace Ingen {
-namespace Server {
-
-JackDriver::JackDriver(Engine& engine)
- : _engine(engine)
- , _sem(0)
- , _flag(false)
- , _client(nullptr)
- , _block_length(0)
- , _seq_size(0)
- , _sample_rate(0)
- , _is_activated(false)
- , _old_bpm(120.0f)
- , _old_frame(0)
- , _old_rolling(false)
-{
- _midi_event_type = _engine.world()->uris().midi_MidiEvent;
- lv2_atom_forge_init(
- &_forge, &engine.world()->uri_map().urid_map_feature()->urid_map);
-}
-
-JackDriver::~JackDriver()
-{
- deactivate();
- _ports.clear_and_dispose([](EnginePort* p) { delete p; });
-}
-
-bool
-JackDriver::attach(const std::string& server_name,
- const std::string& client_name,
- void* jack_client)
-{
- assert(!_client);
- if (!jack_client) {
-#ifdef INGEN_JACK_SESSION
- const std::string uuid = _engine.world()->jack_uuid();
- if (!uuid.empty()) {
- _client = jack_client_open(client_name.c_str(),
- JackSessionID, nullptr,
- uuid.c_str());
- _engine.log().info(fmt("Connected to Jack as `%1%' (UUID `%2%')\n")
- % client_name.c_str() % uuid);
- }
-#endif
-
- // Try supplied server name
- if (!_client && !server_name.empty()) {
- if ((_client = jack_client_open(client_name.c_str(),
- JackServerName, nullptr,
- server_name.c_str()))) {
- _engine.log().info(fmt("Connected to Jack server `%1%'\n")
- % server_name);
- }
- }
-
- // Either server name not specified, or supplied server name does not exist
- // Connect to default server
- if (!_client) {
- if ((_client = jack_client_open(client_name.c_str(), JackNullOption, nullptr))) {
- _engine.log().info("Connected to default Jack server\n");
- }
- }
-
- // Still failed
- if (!_client) {
- _engine.log().error("Unable to connect to Jack\n");
- return false;
- }
- } else {
- _client = (jack_client_t*)jack_client;
- }
-
- _sample_rate = jack_get_sample_rate(_client);
- _block_length = jack_get_buffer_size(_client);
- _seq_size = jack_port_type_get_buffer_size(_client, JACK_DEFAULT_MIDI_TYPE);
-
- _fallback_buffer = AudioBufPtr(
- static_cast<float*>(
- Buffer::aligned_alloc(sizeof(float) * _block_length)));
-
- jack_on_shutdown(_client, shutdown_cb, this);
-
- jack_set_thread_init_callback(_client, thread_init_cb, this);
- jack_set_buffer_size_callback(_client, block_length_cb, this);
-#ifdef INGEN_JACK_SESSION
- jack_set_session_callback(_client, session_cb, this);
-#endif
-
- for (auto& p : _ports) {
- register_port(p);
- }
-
- return true;
-}
-
-bool
-JackDriver::activate()
-{
- World* world = _engine.world();
-
- if (_is_activated) {
- _engine.log().warn("Jack driver already activated\n");
- return false;
- }
-
- if (!_client) {
- attach(world->conf().option("jack-server").ptr<char>(),
- world->conf().option("jack-name").ptr<char>(), nullptr);
- }
-
- if (!_client) {
- return false;
- }
-
- jack_set_process_callback(_client, process_cb, this);
-
- _is_activated = true;
-
- if (jack_activate(_client)) {
- _engine.log().error("Could not activate Jack client, aborting\n");
- return false;
- } else {
- _engine.log().info(fmt("Activated Jack client `%1%'\n") %
- world->conf().option("jack-name").ptr<char>());
- }
- return true;
-}
-
-void
-JackDriver::deactivate()
-{
- if (_is_activated) {
- _flag = true;
- _is_activated = false;
- _sem.timed_wait(std::chrono::seconds(1));
-
- for (auto& p : _ports) {
- unregister_port(p);
- }
-
- if (_client) {
- jack_deactivate(_client);
- jack_client_close(_client);
- _client = nullptr;
- }
-
- _engine.log().info("Deactivated Jack client\n");
- }
-}
-
-EnginePort*
-JackDriver::get_port(const Raul::Path& path)
-{
- for (auto& p : _ports) {
- if (p.graph_port()->path() == path) {
- return &p;
- }
- }
-
- return nullptr;
-}
-
-void
-JackDriver::add_port(RunContext& context, EnginePort* port)
-{
- _ports.push_back(*port);
-
- DuplexPort* graph_port = port->graph_port();
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- const SampleCount nframes = context.nframes();
- jack_port_t* jport = (jack_port_t*)port->handle();
- void* jbuf = jack_port_get_buffer(jport, nframes);
-
- /* Jack fails to return a buffer if this is too soon after registering
- the port, so use a silent fallback buffer if necessary. */
- graph_port->set_driver_buffer(
- jbuf ? jbuf : _fallback_buffer.get(),
- nframes * sizeof(float));
- }
-}
-
-void
-JackDriver::remove_port(RunContext& context, EnginePort* port)
-{
- _ports.erase(_ports.iterator_to(*port));
-}
-
-void
-JackDriver::register_port(EnginePort& port)
-{
- jack_port_t* jack_port = jack_port_register(
- _client,
- port.graph_port()->path().substr(1).c_str(),
- ((port.graph_port()->is_a(PortType::AUDIO) ||
- port.graph_port()->is_a(PortType::CV))
- ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE),
- (port.graph_port()->is_input()
- ? JackPortIsInput : JackPortIsOutput),
- 0);
-
- if (!jack_port) {
- throw JackDriver::PortRegistrationFailedException();
- }
-
- port.set_handle(jack_port);
-
- for (const auto& p : port.graph_port()->properties()) {
- port_property_internal(jack_port, p.first, p.second);
- }
-}
-
-void
-JackDriver::unregister_port(EnginePort& port)
-{
- if (jack_port_unregister(_client, (jack_port_t*)port.handle())) {
- _engine.log().error("Failed to unregister Jack port\n");
- }
-
- port.set_handle(nullptr);
-}
-
-void
-JackDriver::rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path)
-{
- EnginePort* eport = get_port(old_path);
- if (eport) {
-#ifdef HAVE_JACK_PORT_RENAME
- jack_port_rename(
- _client, (jack_port_t*)eport->handle(), new_path.substr(1).c_str());
-#else
- jack_port_set_name((jack_port_t*)eport->handle(),
- new_path.substr(1).c_str());
-#endif
- }
-}
-
-void
-JackDriver::port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value)
-{
-#ifdef HAVE_JACK_METADATA
- EnginePort* eport = get_port(path);
- if (eport) {
- const jack_port_t* const jport = (const jack_port_t*)eport->handle();
- port_property_internal(jport, uri, value);
- }
-#endif
-}
-
-void
-JackDriver::port_property_internal(const jack_port_t* jport,
- const URI& uri,
- const Atom& value)
-{
-#ifdef HAVE_JACK_METADATA
- if (uri == _engine.world()->uris().lv2_name) {
- jack_set_property(_client, jack_port_uuid(jport),
- JACK_METADATA_PRETTY_NAME, value.ptr<char>(), "text/plain");
- } else if (uri == _engine.world()->uris().lv2_index) {
- jack_set_property(_client, jack_port_uuid(jport),
- JACKEY_ORDER, std::to_string(value.get<int32_t>()).c_str(),
- "http://www.w3.org/2001/XMLSchema#integer");
- } else if (uri == _engine.world()->uris().rdf_type) {
- if (value == _engine.world()->uris().lv2_CVPort) {
- jack_set_property(_client, jack_port_uuid(jport),
- JACKEY_SIGNAL_TYPE, "CV", "text/plain");
- }
- }
-#endif
-}
-
-EnginePort*
-JackDriver::create_port(DuplexPort* graph_port)
-{
- EnginePort* eport = nullptr;
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- // Audio buffer port, use Jack buffer directly
- eport = new EnginePort(graph_port);
- graph_port->set_is_driver_port(*_engine.buffer_factory());
- } else if (graph_port->is_a(PortType::ATOM) &&
- graph_port->buffer_type() == _engine.world()->uris().atom_Sequence) {
- // Sequence port, make Jack port but use internal LV2 format buffer
- eport = new EnginePort(graph_port);
- }
-
- if (eport) {
- register_port(*eport);
- }
-
- return eport;
-}
-
-void
-JackDriver::pre_process_port(RunContext& context, EnginePort* port)
-{
- const URIs& uris = context.engine().world()->uris();
- const SampleCount nframes = context.nframes();
- jack_port_t* jack_port = (jack_port_t*)port->handle();
- DuplexPort* graph_port = port->graph_port();
- Buffer* graph_buf = graph_port->buffer(0).get();
- void* jack_buf = jack_port_get_buffer(jack_port, nframes);
-
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- graph_port->set_driver_buffer(jack_buf, nframes * sizeof(float));
- if (graph_port->is_input()) {
- graph_port->monitor(context);
- } else {
- graph_port->buffer(0)->clear(); // TODO: Avoid when possible
- }
- } else if (graph_port->buffer_type() == uris.atom_Sequence) {
- graph_buf->prepare_write(context);
- if (graph_port->is_input()) {
- // Copy events from Jack port buffer into graph port buffer
- const jack_nframes_t event_count = jack_midi_get_event_count(jack_buf);
- for (jack_nframes_t i = 0; i < event_count; ++i) {
- jack_midi_event_t ev;
- jack_midi_event_get(&ev, jack_buf, i);
- if (!graph_buf->append_event(
- ev.time, ev.size, _midi_event_type, ev.buffer)) {
- _engine.log().rt_error("Failed to write to MIDI buffer, events lost!\n");
- }
- }
- }
- graph_port->monitor(context);
- }
-}
-
-void
-JackDriver::post_process_port(RunContext& context, EnginePort* port)
-{
- const URIs& uris = context.engine().world()->uris();
- const SampleCount nframes = context.nframes();
- jack_port_t* jack_port = (jack_port_t*)port->handle();
- DuplexPort* graph_port = port->graph_port();
- void* jack_buf = port->buffer();
-
- if (port->graph_port()->is_output()) {
- if (!jack_buf) {
- // First cycle for a new output, so pre_process wasn't called
- jack_buf = jack_port_get_buffer(jack_port, nframes);
- port->set_buffer(jack_buf);
- }
-
- if (graph_port->buffer_type() == uris.atom_Sequence) {
- // Copy LV2 MIDI events to Jack MIDI buffer
- Buffer* const graph_buf = graph_port->buffer(0).get();
- LV2_Atom_Sequence* seq = graph_buf->get<LV2_Atom_Sequence>();
-
- jack_midi_clear_buffer(jack_buf);
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body);
- if (ev->body.type == _midi_event_type) {
- jack_midi_event_write(
- jack_buf, ev->time.frames, buf, ev->body.size);
- }
- }
- }
- }
-
- // Reset graph port buffer pointer to no longer point to the Jack buffer
- if (graph_port->is_driver_port()) {
- graph_port->set_driver_buffer(nullptr, 0);
- }
-}
-
-void
-JackDriver::append_time_events(RunContext& context,
- Buffer& buffer)
-{
- const URIs& uris = context.engine().world()->uris();
- const jack_position_t* pos = &_position;
- const bool rolling = (_transport_state == JackTransportRolling);
-
- // Do nothing if there is no unexpected time change (other than rolling)
- if (rolling == _old_rolling &&
- pos->frame == _old_frame &&
- pos->beats_per_minute == _old_bpm) {
- return;
- }
-
- // Update old time information to detect change next cycle
- _old_frame = pos->frame;
- _old_rolling = rolling;
- _old_bpm = pos->beats_per_minute;
-
- // Build an LV2 position object to append to the buffer
- LV2_Atom pos_buf[16];
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_set_buffer(&_forge, (uint8_t*)pos_buf, sizeof(pos_buf));
- lv2_atom_forge_object(&_forge, &frame, 0, uris.time_Position);
- lv2_atom_forge_key(&_forge, uris.time_frame);
- lv2_atom_forge_long(&_forge, pos->frame);
- lv2_atom_forge_key(&_forge, uris.time_speed);
- lv2_atom_forge_float(&_forge, rolling ? 1.0 : 0.0);
- if (pos->valid & JackPositionBBT) {
- lv2_atom_forge_key(&_forge, uris.time_barBeat);
- lv2_atom_forge_float(
- &_forge, pos->beat - 1 + (pos->tick / pos->ticks_per_beat));
- lv2_atom_forge_key(&_forge, uris.time_bar);
- lv2_atom_forge_long(&_forge, pos->bar - 1);
- lv2_atom_forge_key(&_forge, uris.time_beatUnit);
- lv2_atom_forge_int(&_forge, pos->beat_type);
- lv2_atom_forge_key(&_forge, uris.time_beatsPerBar);
- lv2_atom_forge_float(&_forge, pos->beats_per_bar);
- lv2_atom_forge_key(&_forge, uris.time_beatsPerMinute);
- lv2_atom_forge_float(&_forge, pos->beats_per_minute);
- }
-
- // Append position to buffer at offset 0 (start of this cycle)
- LV2_Atom* lpos = (LV2_Atom*)pos_buf;
- buffer.append_event(
- 0, lpos->size, lpos->type, (const uint8_t*)LV2_ATOM_BODY_CONST(lpos));
-}
-
-/**** Jack Callbacks ****/
-
-/** Jack process callback, drives entire audio thread.
- *
- * \callgraph
- */
-REALTIME int
-JackDriver::_process_cb(jack_nframes_t nframes)
-{
- if (nframes == 0 || ! _is_activated) {
- if (_flag) {
- _sem.post();
- }
- return 0;
- }
-
- /* Note that Jack may not call this function for a cycle, if overloaded,
- so a rolling counter here would not always be correct. */
- const jack_nframes_t start_of_current_cycle = jack_last_frame_time(_client);
-
- _transport_state = jack_transport_query(_client, &_position);
-
- _engine.locate(start_of_current_cycle, nframes);
-
- // Read input
- for (auto& p : _ports) {
- pre_process_port(_engine.run_context(), &p);
- }
-
- // Process
- _engine.run(nframes);
-
- // Write output
- for (auto& p : _ports) {
- post_process_port(_engine.run_context(), &p);
- }
-
- // Update expected transport frame for next cycle to detect changes
- if (_transport_state == JackTransportRolling) {
- _old_frame += nframes;
- }
-
- return 0;
-}
-
-void
-JackDriver::_thread_init_cb()
-{
- ThreadManager::set_flag(THREAD_PROCESS);
- ThreadManager::set_flag(THREAD_IS_REAL_TIME);
-}
-
-void
-JackDriver::_shutdown_cb()
-{
- _engine.log().info("Jack shutdown, exiting\n");
- _is_activated = false;
- _client = nullptr;
-}
-
-int
-JackDriver::_block_length_cb(jack_nframes_t nframes)
-{
- if (_engine.root_graph()) {
- _block_length = nframes;
- _seq_size = jack_port_type_get_buffer_size(_client, JACK_DEFAULT_MIDI_TYPE);
- _engine.root_graph()->set_buffer_size(
- _engine.run_context(), *_engine.buffer_factory(), PortType::AUDIO,
- _engine.buffer_factory()->audio_buffer_size(nframes));
- _engine.root_graph()->set_buffer_size(
- _engine.run_context(), *_engine.buffer_factory(), PortType::ATOM,
- _seq_size);
- }
- return 0;
-}
-
-#ifdef INGEN_JACK_SESSION
-void
-JackDriver::_session_cb(jack_session_event_t* event)
-{
- _engine.log().info(fmt("Jack session save to %1%\n") % event->session_dir);
-
- const std::string cmd = (
- boost::format("ingen -eg -n %1% -u %2% -l ${SESSION_DIR}")
- % jack_get_client_name(_client)
- % event->client_uuid).str();
-
- SPtr<Serialiser> serialiser = _engine.world()->serialiser();
- if (serialiser) {
- std::lock_guard<std::mutex> lock(_engine.world()->rdf_mutex());
-
- SPtr<Node> root(_engine.root_graph(), NullDeleter<Node>);
- serialiser->write_bundle(root,
- URI(std::string("file://") + event->session_dir));
- }
-
- event->command_line = (char*)malloc(cmd.size() + 1);
- memcpy(event->command_line, cmd.c_str(), cmd.size() + 1);
- jack_session_reply(_client, event);
-
- switch (event->type) {
- case JackSessionSave:
- break;
- case JackSessionSaveAndQuit:
- _engine.log().warn("Jack session quit\n");
- _engine.quit();
- break;
- case JackSessionSaveTemplate:
- break;
- }
-
- jack_session_event_free(event);
-}
-#endif
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/JackDriver.hpp b/src/server/JackDriver.hpp
deleted file mode 100644
index 2a21d96e..00000000
--- a/src/server/JackDriver.hpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_JACKAUDIODRIVER_HPP
-#define INGEN_ENGINE_JACKAUDIODRIVER_HPP
-
-#include "ingen_config.h"
-
-#include <string>
-#include <atomic>
-
-#include <jack/jack.h>
-#include <jack/thread.h>
-#include <jack/transport.h>
-#ifdef INGEN_JACK_SESSION
-#include <jack/session.h>
-#endif
-
-#include "ingen/types.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
-#include "raul/Semaphore.hpp"
-
-#include "Driver.hpp"
-#include "EnginePort.hpp"
-
-namespace Raul { class Path; }
-
-namespace Ingen {
-namespace Server {
-
-class DuplexPort;
-class Engine;
-class GraphImpl;
-class JackDriver;
-class PortImpl;
-
-/** The Jack Driver.
- *
- * The process callback here drives the entire audio thread by "pulling"
- * events from queues, processing them, running the graphs, and passing
- * events along to the PostProcessor.
- *
- * \ingroup engine
- */
-class JackDriver : public Driver
-{
-public:
- explicit JackDriver(Engine& engine);
- ~JackDriver();
-
- bool attach(const std::string& server_name,
- const std::string& client_name,
- void* jack_client);
-
- bool activate();
- void deactivate();
-
- bool dynamic_ports() const { return true; }
-
- EnginePort* create_port(DuplexPort* graph_port);
- EnginePort* get_port(const Raul::Path& path);
-
- void rename_port(const Raul::Path& old_path, const Raul::Path& new_path);
- void port_property(const Raul::Path& path, const URI& uri, const Atom& value);
- void add_port(RunContext& context, EnginePort* port);
- void remove_port(RunContext& context, EnginePort* port);
- void register_port(EnginePort& port);
- void unregister_port(EnginePort& port);
-
- /** Transport state for this frame.
- * Intended to only be called from the audio thread. */
- inline const jack_position_t* position() { return &_position; }
- inline jack_transport_state_t transport_state() { return _transport_state; }
-
- void append_time_events(RunContext& context,
- Buffer& buffer);
-
- int real_time_priority() { return jack_client_real_time_priority(_client); }
-
- jack_client_t* jack_client() const { return _client; }
- SampleCount block_length() const { return _block_length; }
- size_t seq_size() const { return _seq_size; }
- SampleCount sample_rate() const { return _sample_rate; }
-
- inline SampleCount frame_time() const { return _client ? jack_frame_time(_client) : 0; }
-
- class PortRegistrationFailedException : public std::exception {};
-
-private:
- friend class JackPort;
-
- // Static JACK callbacks which call the non-static callbacks (methods)
- inline static void thread_init_cb(void* const jack_driver) {
- return ((JackDriver*)jack_driver)->_thread_init_cb();
- }
- inline static void shutdown_cb(void* const jack_driver) {
- return ((JackDriver*)jack_driver)->_shutdown_cb();
- }
- inline static int process_cb(jack_nframes_t nframes, void* const jack_driver) {
- return ((JackDriver*)jack_driver)->_process_cb(nframes);
- }
- inline static int block_length_cb(jack_nframes_t nframes, void* const jack_driver) {
- return ((JackDriver*)jack_driver)->_block_length_cb(nframes);
- }
-#ifdef INGEN_JACK_SESSION
- inline static void session_cb(jack_session_event_t* event, void* jack_driver) {
- ((JackDriver*)jack_driver)->_session_cb(event);
- }
-#endif
-
- void pre_process_port(RunContext& context, EnginePort* port);
- void post_process_port(RunContext& context, EnginePort* port);
-
- void port_property_internal(const jack_port_t* jport,
- const URI& uri,
- const Atom& value);
-
- // Non static callbacks (methods)
- void _thread_init_cb();
- void _shutdown_cb();
- int _process_cb(jack_nframes_t nframes);
- int _block_length_cb(jack_nframes_t nframes);
-#ifdef INGEN_JACK_SESSION
- void _session_cb(jack_session_event_t* event);
-#endif
-
-protected:
- typedef boost::intrusive::slist<EnginePort,
- boost::intrusive::cache_last<true>
- > Ports;
-
- using AudioBufPtr = UPtr<float, FreeDeleter<float>>;
-
- Engine& _engine;
- Ports _ports;
- AudioBufPtr _fallback_buffer;
- LV2_Atom_Forge _forge;
- Raul::Semaphore _sem;
- std::atomic<bool> _flag;
- jack_client_t* _client;
- jack_nframes_t _block_length;
- size_t _seq_size;
- jack_nframes_t _sample_rate;
- uint32_t _midi_event_type;
- bool _is_activated;
- jack_position_t _position;
- jack_transport_state_t _transport_state;
- float _old_bpm;
- jack_nframes_t _old_frame;
- bool _old_rolling;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_JACKAUDIODRIVER_HPP
diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp
deleted file mode 100644
index f4792f39..00000000
--- a/src/server/LV2Block.cpp
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <cmath>
-#include <cstdint>
-
-#include "lv2/lv2plug.in/ns/ext/morph/morph.h"
-#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
-#include "lv2/lv2plug.in/ns/ext/options/options.h"
-#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-
-#include "raul/Maid.hpp"
-#include "raul/Array.hpp"
-
-#include "ingen/FilePath.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-
-#include "Buffer.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "LV2Block.hpp"
-#include "LV2Plugin.hpp"
-#include "OutputPort.hpp"
-#include "PortImpl.hpp"
-#include "RunContext.hpp"
-#include "Worker.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** Partially construct a LV2Block.
- *
- * Object is not usable until instantiate() is called with success.
- * (It _will_ crash!)
- */
-LV2Block::LV2Block(LV2Plugin* plugin,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
- : BlockImpl(plugin, symbol, polyphonic, parent, srate)
- , _lv2_plugin(plugin)
- , _worker_iface(nullptr)
-{
- assert(_lv2_plugin);
-}
-
-LV2Block::~LV2Block()
-{
- // Explicitly drop instances first to prevent reference cycles
- drop_instances(_instances);
- drop_instances(_prepared_instances);
-}
-
-SPtr<LV2Block::Instance>
-LV2Block::make_instance(URIs& uris,
- SampleRate rate,
- uint32_t voice,
- bool preparing)
-{
- const Engine& engine = parent_graph()->engine();
- const LilvPlugin* lplug = _lv2_plugin->lilv_plugin();
- LilvInstance* inst = lilv_plugin_instantiate(
- lplug, rate, _features->array());
-
- if (!inst) {
- engine.log().error(fmt("Failed to instantiate <%1%>\n")
- % _lv2_plugin->uri().c_str());
- return SPtr<Instance>();
- }
-
- const LV2_Options_Interface* options_iface = nullptr;
- if (lilv_plugin_has_extension_data(lplug, uris.opt_interface)) {
- options_iface = (const LV2_Options_Interface*)
- lilv_instance_get_extension_data(inst, LV2_OPTIONS__interface);
- }
-
- for (uint32_t p = 0; p < num_ports(); ++p) {
- PortImpl* const port = _ports->at(p);
- Buffer* const buffer = (preparing)
- ? port->prepared_buffer(voice).get()
- : port->buffer(voice).get();
- if (port->is_morph() && port->is_a(PortType::CV)) {
- if (options_iface) {
- const LV2_URID port_type = uris.lv2_CVPort;
- const LV2_Options_Option options[] = {
- { LV2_OPTIONS_PORT, p, uris.morph_currentType,
- sizeof(LV2_URID), uris.atom_URID, &port_type },
- { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, nullptr }
- };
- options_iface->set(inst->lv2_handle, options);
- }
- }
-
- if (buffer) {
- if (port->is_a(PortType::CONTROL)) {
- buffer->set_value(port->value());
- } else if (port->is_a(PortType::CV)) {
- buffer->set_block(port->value().get<float>(), 0, engine.block_length());
- } else {
- buffer->clear();
- }
- }
- }
-
- if (options_iface) {
- for (uint32_t p = 0; p < num_ports(); ++p) {
- PortImpl* const port = _ports->at(p);
- if (port->is_auto_morph()) {
- LV2_Options_Option options[] = {
- { LV2_OPTIONS_PORT, p, uris.morph_currentType, 0, 0, nullptr },
- { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, nullptr }
- };
-
- options_iface->get(inst->lv2_handle, options);
- if (options[0].value) {
- LV2_URID type = *(const LV2_URID*)options[0].value;
- if (type == _uris.lv2_ControlPort) {
- port->set_type(PortType::CONTROL, 0);
- } else if (type == _uris.lv2_CVPort) {
- port->set_type(PortType::CV, 0);
- } else {
- parent_graph()->engine().log().error(
- fmt("%1% auto-morphed to unknown type %2%\n")
- % port->path().c_str() % type);
- return SPtr<Instance>();
- }
- } else {
- parent_graph()->engine().log().error(
- fmt("Failed to get auto-morphed type of %1%\n")
- % port->path().c_str());
- }
- }
- }
- }
-
- return std::make_shared<Instance>(inst);
-}
-
-bool
-LV2Block::prepare_poly(BufferFactory& bufs, uint32_t poly)
-{
- if (!_polyphonic) {
- poly = 1;
- }
-
- BlockImpl::prepare_poly(bufs, poly);
-
- if (_polyphony == poly) {
- return true;
- }
-
- const SampleRate rate = bufs.engine().sample_rate();
- assert(!_prepared_instances);
- _prepared_instances = bufs.maid().make_managed<Instances>(
- poly, *_instances, SPtr<Instance>());
- for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) {
- SPtr<Instance> inst = make_instance(bufs.uris(), rate, i, true);
- if (!inst) {
- _prepared_instances.reset();
- return false;
- }
-
- _prepared_instances->at(i) = inst;
-
- if (_activated) {
- lilv_instance_activate(inst->instance);
- }
- }
-
- return true;
-}
-
-bool
-LV2Block::apply_poly(RunContext& context, uint32_t poly)
-{
- if (!_polyphonic) {
- poly = 1;
- }
-
- if (_prepared_instances) {
- _instances = std::move(_prepared_instances);
- }
- assert(poly <= _instances->size());
-
- return BlockImpl::apply_poly(context, poly);
-}
-
-/** Instantiate self from LV2 plugin descriptor.
- *
- * Implemented as a seperate function (rather than in the constructor) to
- * allow graceful error-catching of broken plugins.
- *
- * Returns whether or not plugin was successfully instantiated. If return
- * value is false, this object may not be used.
- */
-bool
-LV2Block::instantiate(BufferFactory& bufs, const LilvState* state)
-{
- const Ingen::URIs& uris = bufs.uris();
- Ingen::World* world = bufs.engine().world();
- const LilvPlugin* plug = _lv2_plugin->lilv_plugin();
- Ingen::Forge& forge = bufs.forge();
- const uint32_t num_ports = lilv_plugin_get_num_ports(plug);
-
- LilvNode* lv2_connectionOptional = lilv_new_uri(
- bufs.engine().world()->lilv_world(), LV2_CORE__connectionOptional);
-
- _ports = bufs.maid().make_managed<BlockImpl::Ports>(num_ports, nullptr);
-
- bool ret = true;
-
- float* min_values = new float[num_ports];
- float* max_values = new float[num_ports];
- float* def_values = new float[num_ports];
- lilv_plugin_get_port_ranges_float(plug, min_values, max_values, def_values);
- uint32_t max_sequence_size = 0;
-
- // Get all the necessary information about ports
- for (uint32_t j = 0; j < num_ports; ++j) {
- const LilvPort* id = lilv_plugin_get_port_by_index(plug, j);
-
- /* LV2 port symbols are guaranteed to be unique, valid C identifiers,
- and Lilv guarantees that lilv_port_get_symbol() is valid. */
- const Raul::Symbol port_sym(
- lilv_node_as_string(lilv_port_get_symbol(plug, id)));
-
- // Get port type
- Atom val;
- PortType port_type = PortType::UNKNOWN;
- LV2_URID buffer_type = 0;
- bool is_morph = false;
- bool is_auto_morph = false;
- if (lilv_port_is_a(plug, id, uris.lv2_ControlPort)) {
- if (lilv_port_is_a(plug, id, uris.morph_MorphPort)) {
- is_morph = true;
- LilvNodes* types = lilv_port_get_value(
- plug, id, uris.morph_supportsType);
- LILV_FOREACH(nodes, i, types) {
- const LilvNode* type = lilv_nodes_get(types, i);
- if (lilv_node_equals(type, uris.lv2_CVPort)) {
- port_type = PortType::CV;
- buffer_type = uris.atom_Sound;
- }
- }
- lilv_nodes_free(types);
- }
- if (port_type == PortType::UNKNOWN) {
- port_type = PortType::CONTROL;
- buffer_type = uris.atom_Sequence;
- val = forge.make(def_values[j]);
- }
- } else if (lilv_port_is_a(plug, id, uris.lv2_CVPort)) {
- port_type = PortType::CV;
- buffer_type = uris.atom_Sound;
- } else if (lilv_port_is_a(plug, id, uris.lv2_AudioPort)) {
- port_type = PortType::AUDIO;
- buffer_type = uris.atom_Sound;
- } else if (lilv_port_is_a(plug, id, uris.atom_AtomPort)) {
- port_type = PortType::ATOM;
- }
-
- if (lilv_port_is_a(plug, id, uris.morph_AutoMorphPort)) {
- is_auto_morph = true;
- }
-
- // Get buffer type if necessary (atom ports)
- if (!buffer_type) {
- LilvNodes* types = lilv_port_get_value(
- plug, id, uris.atom_bufferType);
- LILV_FOREACH(nodes, i, types) {
- const LilvNode* type = lilv_nodes_get(types, i);
- if (lilv_node_is_uri(type)) {
- buffer_type = bufs.engine().world()->uri_map().map_uri(
- lilv_node_as_uri(type));
- }
- }
- lilv_nodes_free(types);
- }
-
- const bool optional = lilv_port_has_property(
- plug, id, lv2_connectionOptional);
-
- uint32_t port_buffer_size = bufs.default_size(buffer_type);
- if (port_buffer_size == 0 && !optional) {
- parent_graph()->engine().log().error(
- fmt("<%1%> port `%2%' has unknown buffer type\n")
- % _lv2_plugin->uri().c_str() % port_sym.c_str());
- ret = false;
- break;
- }
-
- if (port_type == PortType::ATOM) {
- // Get default value, and its length
- LilvNodes* defaults = lilv_port_get_value(plug, id, uris.lv2_default);
- LILV_FOREACH(nodes, i, defaults) {
- const LilvNode* d = lilv_nodes_get(defaults, i);
- if (lilv_node_is_string(d)) {
- const char* str_val = lilv_node_as_string(d);
- const uint32_t str_val_len = strlen(str_val);
- val = forge.alloc(str_val);
- port_buffer_size = std::max(port_buffer_size, str_val_len);
- } else if (lilv_node_is_uri(d)) {
- const char* uri_val = lilv_node_as_uri(d);
- val = forge.make_urid(
- bufs.engine().world()->uri_map().map_uri(uri_val));
- }
- }
- lilv_nodes_free(defaults);
-
- if (!val.type() && buffer_type == _uris.atom_URID) {
- val = forge.make_urid(0);
- }
-
- // Get minimum size, if set in data
- LilvNodes* sizes = lilv_port_get_value(plug, id, uris.rsz_minimumSize);
- LILV_FOREACH(nodes, i, sizes) {
- const LilvNode* d = lilv_nodes_get(sizes, i);
- if (lilv_node_is_int(d)) {
- uint32_t size_val = lilv_node_as_int(d);
- port_buffer_size = std::max(port_buffer_size, size_val);
- }
- }
- lilv_nodes_free(sizes);
- max_sequence_size = std::max(port_buffer_size, max_sequence_size);
- bufs.set_seq_size(max_sequence_size);
- }
-
- enum { UNKNOWN, INPUT, OUTPUT } direction = UNKNOWN;
- if (lilv_port_is_a(plug, id, uris.lv2_InputPort)) {
- direction = INPUT;
- } else if (lilv_port_is_a(plug, id, uris.lv2_OutputPort)) {
- direction = OUTPUT;
- }
-
- if ((port_type == PortType::UNKNOWN && !optional) ||
- direction == UNKNOWN) {
- parent_graph()->engine().log().error(
- fmt("<%1%> port `%2%' has unknown type or direction\n")
- % _lv2_plugin->uri().c_str() % port_sym.c_str());
- ret = false;
- break;
- }
-
- if (!val.type() && (port_type != PortType::ATOM)) {
- // Ensure numeric ports have a value, use 0 by default
- val = forge.make(std::isnan(def_values[j]) ? 0.0f : def_values[j]);
- }
-
- PortImpl* port = (direction == INPUT)
- ? static_cast<PortImpl*>(
- new InputPort(bufs, this, port_sym, j, _polyphony,
- port_type, buffer_type, val))
- : static_cast<PortImpl*>(
- new OutputPort(bufs, this, port_sym, j, _polyphony,
- port_type, buffer_type, val));
-
- port->set_morphable(is_morph, is_auto_morph);
- if (direction == INPUT && (port_type == PortType::CONTROL
- || port_type == PortType::CV)) {
- port->set_value(val);
- if (!std::isnan(min_values[j])) {
- port->set_minimum(forge.make(min_values[j]));
- }
- if (!std::isnan(max_values[j])) {
- port->set_maximum(forge.make(max_values[j]));
- }
- }
-
- // Inherit certain properties from plugin port
- const LilvNode* preds[] = { uris.lv2_designation,
- uris.lv2_portProperty,
- uris.atom_supports,
- nullptr };
- for (int p = 0; preds[p]; ++p) {
- LilvNodes* values = lilv_port_get_value(plug, id, preds[p]);
- LILV_FOREACH(nodes, v, values) {
- const LilvNode* val = lilv_nodes_get(values, v);
- if (lilv_node_is_uri(val)) {
- port->add_property(URI(lilv_node_as_uri(preds[p])),
- forge.make_urid(URI(lilv_node_as_uri(val))));
- }
- }
- lilv_nodes_free(values);
- }
-
- port->cache_properties();
-
- _ports->at(j) = port;
- }
-
- delete[] min_values;
- delete[] max_values;
- delete[] def_values;
-
- lilv_node_free(lv2_connectionOptional);
-
- if (!ret) {
- _ports.reset();
- return ret;
- }
-
- _features = world->lv2_features().lv2_features(world, this);
-
- // Actually create plugin instances and port buffers.
- const SampleRate rate = bufs.engine().sample_rate();
- _instances = bufs.maid().make_managed<Instances>(
- _polyphony, SPtr<Instance>());
- for (uint32_t i = 0; i < _polyphony; ++i) {
- _instances->at(i) = make_instance(bufs.uris(), rate, i, false);
- if (!_instances->at(i)) {
- return false;
- }
- }
-
- // Load initial state if no state is explicitly given
- LilvState* default_state = nullptr;
- if (!state) {
- state = default_state = load_preset(_lv2_plugin->uri());
- }
-
- // Apply state
- if (state) {
- apply_state(nullptr, state);
- }
-
- if (default_state) {
- lilv_state_free(default_state);
- }
-
- // FIXME: Polyphony + worker?
- if (lilv_plugin_has_feature(plug, uris.work_schedule)) {
- _worker_iface = (const LV2_Worker_Interface*)
- lilv_instance_get_extension_data(instance(0),
- LV2_WORKER__interface);
- }
-
- return ret;
-}
-
-bool
-LV2Block::save_state(const FilePath& dir) const
-{
- World* world = _lv2_plugin->world();
- LilvWorld* lworld = world->lilv_world();
-
- LilvState* state = lilv_state_new_from_instance(
- _lv2_plugin->lilv_plugin(), const_cast<LV2Block*>(this)->instance(0),
- &world->uri_map().urid_map_feature()->urid_map,
- nullptr, dir.c_str(), dir.c_str(), dir.c_str(), nullptr, nullptr,
- LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, nullptr);
-
- if (!state) {
- return false;
- } else if (lilv_state_get_num_properties(state) == 0) {
- lilv_state_free(state);
- return false;
- }
-
- lilv_state_save(lworld,
- &world->uri_map().urid_map_feature()->urid_map,
- &world->uri_map().urid_unmap_feature()->urid_unmap,
- state,
- nullptr,
- dir.c_str(),
- "state.ttl");
-
- lilv_state_free(state);
-
- return true;
-}
-
-BlockImpl*
-LV2Block::duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent)
-{
- const SampleRate rate = engine.sample_rate();
-
- // Get current state
- LilvState* state = lilv_state_new_from_instance(
- _lv2_plugin->lilv_plugin(), instance(0),
- &engine.world()->uri_map().urid_map_feature()->urid_map,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, LV2_STATE_IS_NATIVE, nullptr);
-
- // Duplicate and instantiate block
- LV2Block* dup = new LV2Block(_lv2_plugin, symbol, _polyphonic, parent, rate);
- if (!dup->instantiate(*engine.buffer_factory(), state)) {
- delete dup;
- return nullptr;
- }
- dup->set_properties(properties());
-
- // Set duplicate port values and properties to the same as ours
- for (uint32_t p = 0; p < num_ports(); ++p) {
- const Atom& val = port_impl(p)->value();
- if (val.is_valid()) {
- dup->port_impl(p)->set_value(val);
- }
- dup->port_impl(p)->set_properties(port_impl(p)->properties());
- }
-
- return dup;
-}
-
-void
-LV2Block::activate(BufferFactory& bufs)
-{
- BlockImpl::activate(bufs);
-
- for (uint32_t i = 0; i < _polyphony; ++i) {
- lilv_instance_activate(instance(i));
- }
-}
-
-void
-LV2Block::deactivate()
-{
- BlockImpl::deactivate();
-
- for (uint32_t i = 0; i < _polyphony; ++i) {
- lilv_instance_deactivate(instance(i));
- }
-}
-
-LV2_Worker_Status
-LV2Block::work_respond(LV2_Worker_Respond_Handle handle,
- uint32_t size,
- const void* data)
-{
- LV2Block* block = (LV2Block*)handle;
- LV2Block::Response* r = new LV2Block::Response(size, data);
- block->_responses.push_back(*r);
- return LV2_WORKER_SUCCESS;
-}
-
-LV2_Worker_Status
-LV2Block::work(uint32_t size, const void* data)
-{
- if (_worker_iface) {
- std::lock_guard<std::mutex> lock(_work_mutex);
-
- LV2_Handle inst = lilv_instance_get_handle(instance(0));
- LV2_Worker_Status st = _worker_iface->work(inst, work_respond, this, size, data);
- if (st) {
- parent_graph()->engine().log().error(
- fmt("Error calling %1% work method\n") % _path);
- }
- return st;
- }
- return LV2_WORKER_ERR_UNKNOWN;
-}
-
-void
-LV2Block::run(RunContext& context)
-{
- for (uint32_t i = 0; i < _polyphony; ++i) {
- lilv_instance_run(instance(i), context.nframes());
- }
-}
-
-void
-LV2Block::post_process(RunContext& context)
-{
- /* Handle any worker responses. Note that this may write to output ports,
- so must be done first to prevent clobbering worker responses and
- monitored notification ports. */
- if (_worker_iface) {
- LV2_Handle inst = lilv_instance_get_handle(instance(0));
- while (!_responses.empty()) {
- Response& r = _responses.front();
- _worker_iface->work_response(inst, r.size, r.data);
- _responses.pop_front();
- context.engine().maid()->dispose(&r);
- }
-
- if (_worker_iface->end_run) {
- _worker_iface->end_run(inst);
- }
- }
-
- /* Run cycle truly finished, finalise output ports. */
- BlockImpl::post_process(context);
-}
-
-LilvState*
-LV2Block::load_preset(const URI& uri)
-{
- World* world = _lv2_plugin->world();
- LilvWorld* lworld = world->lilv_world();
- LilvNode* preset = lilv_new_uri(lworld, uri.c_str());
-
- // Load preset into world if necessary
- lilv_world_load_resource(lworld, preset);
-
- // Load preset from world
- LV2_URID_Map* map = &world->uri_map().urid_map_feature()->urid_map;
- LilvState* state = lilv_state_new_from_world(lworld, map, preset);
-
- lilv_node_free(preset);
- return state;
-}
-
-LilvState*
-LV2Block::load_state(World* world, const FilePath& path)
-{
- LilvWorld* lworld = world->lilv_world();
- const URI uri = URI(path);
- LilvNode* subject = lilv_new_uri(lworld, uri.c_str());
-
- LilvState* state = lilv_state_new_from_file(
- lworld,
- &world->uri_map().urid_map_feature()->urid_map,
- subject,
- path.c_str());
-
- lilv_node_free(subject);
- return state;
-}
-
-void
-LV2Block::apply_state(const UPtr<Worker>& worker, const LilvState* state)
-{
- World* world = parent_graph()->engine().world();
- SPtr<LV2_Feature> sched;
- if (worker) {
- sched = worker->schedule_feature()->feature(world, this);
- }
-
- const LV2_Feature* state_features[2] = { nullptr, nullptr };
- if (sched) {
- state_features[0] = sched.get();
- }
-
- for (uint32_t v = 0; v < _polyphony; ++v) {
- lilv_state_restore(state, instance(v), nullptr, nullptr, 0, state_features);
- }
-}
-
-static const void*
-get_port_value(const char* port_symbol,
- void* user_data,
- uint32_t* size,
- uint32_t* type)
-{
- LV2Block* const block = (LV2Block*)user_data;
- PortImpl* const port = block->port_by_symbol(port_symbol);
-
- if (port && port->is_input() && port->value().is_valid()) {
- *size = port->value().size();
- *type = port->value().type();
- return port->value().get_body();
- }
-
- return nullptr;
-}
-
-boost::optional<Resource>
-LV2Block::save_preset(const URI& uri,
- const Properties& props)
-{
- World* world = parent_graph()->engine().world();
- LilvWorld* lworld = _lv2_plugin->world()->lilv_world();
- LV2_URID_Map* lmap = &world->uri_map().urid_map_feature()->urid_map;
- LV2_URID_Unmap* lunmap = &world->uri_map().urid_unmap_feature()->urid_unmap;
-
- const FilePath path = FilePath(uri.path());
- const FilePath dirname = path.parent_path();
- const FilePath basename = path.stem();
-
- LilvState* state = lilv_state_new_from_instance(
- _lv2_plugin->lilv_plugin(), instance(0), lmap,
- nullptr, nullptr, nullptr, path.c_str(),
- get_port_value, this, LV2_STATE_IS_NATIVE, nullptr);
-
- if (state) {
- const Properties::const_iterator l = props.find(_uris.rdfs_label);
- if (l != props.end() && l->second.type() == _uris.atom_String) {
- lilv_state_set_label(state, l->second.ptr<char>());
- }
-
- lilv_state_save(lworld, lmap, lunmap, state, nullptr,
- dirname.c_str(), basename.c_str());
-
- const URI uri(lilv_node_as_uri(lilv_state_get_uri(state)));
- const std::string label(lilv_state_get_label(state)
- ? lilv_state_get_label(state)
- : basename);
- lilv_state_free(state);
-
- Resource preset(_uris, uri);
- preset.set_property(_uris.rdf_type, _uris.pset_Preset);
- preset.set_property(_uris.rdfs_label, world->forge().alloc(label));
- preset.set_property(_uris.lv2_appliesTo,
- world->forge().make_urid(_lv2_plugin->uri()));
-
- const std::string bundle_uri = URI(dirname).string() + '/';
- LilvNode* lbundle = lilv_new_uri(lworld, bundle_uri.c_str());
- lilv_world_load_bundle(lworld, lbundle);
- lilv_node_free(lbundle);
-
- return preset;
- }
-
- return boost::optional<Resource>();
-}
-
-void
-LV2Block::set_port_buffer(uint32_t voice,
- uint32_t port_num,
- BufferRef buf,
- SampleCount offset)
-{
- BlockImpl::set_port_buffer(voice, port_num, buf, offset);
- lilv_instance_connect_port(
- instance(voice),
- port_num,
- buf ? buf->port_data(_ports->at(port_num)->type(), offset) : nullptr);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/LV2Block.hpp b/src/server/LV2Block.hpp
deleted file mode 100644
index f3a59550..00000000
--- a/src/server/LV2Block.hpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_LV2BLOCK_HPP
-#define INGEN_ENGINE_LV2BLOCK_HPP
-
-#include <mutex>
-
-#include "lilv/lilv.h"
-#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
-#include "raul/Maid.hpp"
-
-#include "BufferRef.hpp"
-#include "BlockImpl.hpp"
-#include "ingen/LV2Features.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class LV2Plugin;
-
-/** An instance of a LV2 plugin.
- *
- * \ingroup engine
- */
-class LV2Block : public BlockImpl
-{
-public:
- LV2Block(LV2Plugin* plugin,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate);
-
- ~LV2Block();
-
- bool instantiate(BufferFactory& bufs, const LilvState* state);
-
- LilvInstance* instance() { return instance(0); }
- bool save_state(const FilePath& dir) const;
-
- BlockImpl* duplicate(Engine& engine,
- const Raul::Symbol& symbol,
- GraphImpl* parent);
-
- bool prepare_poly(BufferFactory& bufs, uint32_t poly);
- bool apply_poly(RunContext& context, uint32_t poly);
-
- void activate(BufferFactory& bufs);
- void deactivate();
-
- LV2_Worker_Status work(uint32_t size, const void* data);
-
- void run(RunContext& context);
- void post_process(RunContext& context);
-
- LilvState* load_preset(const URI& uri);
-
- void apply_state(const UPtr<Worker>& worker, const LilvState* state);
-
- boost::optional<Resource> save_preset(const URI& uri,
- const Properties& props);
-
- void set_port_buffer(uint32_t voice,
- uint32_t port_num,
- BufferRef buf,
- SampleCount offset);
-
- static LilvState* load_state(World* world, const FilePath& path);
-
-protected:
- struct Instance : public Raul::Noncopyable {
- explicit Instance(LilvInstance* i) : instance(i) {}
-
- ~Instance() { lilv_instance_free(instance); }
-
- LilvInstance* const instance;
- };
-
- SPtr<Instance> make_instance(URIs& uris,
- SampleRate rate,
- uint32_t voice,
- bool preparing);
-
- inline LilvInstance* instance(uint32_t voice) {
- return (LilvInstance*)(*_instances)[voice]->instance;
- }
-
- typedef Raul::Array< SPtr<Instance> > Instances;
-
- void drop_instances(const MPtr<Instances>& instances) {
- if (instances) {
- for (size_t i = 0; i < instances->size(); ++i) {
- (*instances)[i].reset();
- }
- }
- }
-
- struct Response : public Raul::Maid::Disposable
- , public Raul::Noncopyable
- , public boost::intrusive::slist_base_hook<>
- {
- inline Response(uint32_t s, const void* d)
- : size(s)
- , data(malloc(s))
- {
- memcpy(data, d, s);
- }
-
- ~Response() {
- free(data);
- }
-
- const uint32_t size;
- void* const data;
- };
-
- typedef boost::intrusive::slist<Response,
- boost::intrusive::cache_last<true>,
- boost::intrusive::constant_time_size<false>
- > Responses;
-
- static LV2_Worker_Status work_respond(
- LV2_Worker_Respond_Handle handle, uint32_t size, const void* data);
-
- LV2Plugin* _lv2_plugin;
- MPtr<Instances> _instances;
- MPtr<Instances> _prepared_instances;
- const LV2_Worker_Interface* _worker_iface;
- std::mutex _work_mutex;
- Responses _responses;
- SPtr<LV2Features::FeatureArray> _features;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_LV2BLOCK_HPP
diff --git a/src/server/LV2Options.hpp b/src/server/LV2Options.hpp
deleted file mode 100644
index ef7c5ec9..00000000
--- a/src/server/LV2Options.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_LV2OPTIONS_HPP
-#define INGEN_ENGINE_LV2OPTIONS_HPP
-
-#include "ingen/LV2Features.hpp"
-#include "ingen/URIs.hpp"
-#include "lv2/lv2plug.in/ns/ext/options/options.h"
-
-namespace Ingen {
-namespace Server {
-
-class LV2Options : public Ingen::LV2Features::Feature {
-public:
- explicit LV2Options(const URIs& uris)
- : _uris(uris)
- {}
-
- void set(int32_t sample_rate, int32_t block_length, int32_t seq_size) {
- _sample_rate = sample_rate;
- _block_length = block_length;
- _seq_size = seq_size;
- }
-
- const char* uri() const { return LV2_OPTIONS__options; }
-
- SPtr<LV2_Feature> feature(World* w, Node* n) {
- const LV2_Options_Option options[] = {
- { LV2_OPTIONS_INSTANCE, 0, _uris.bufsz_minBlockLength,
- sizeof(int32_t), _uris.atom_Int, &_block_length },
- { LV2_OPTIONS_INSTANCE, 0, _uris.bufsz_maxBlockLength,
- sizeof(int32_t), _uris.atom_Int, &_block_length },
- { LV2_OPTIONS_INSTANCE, 0, _uris.bufsz_sequenceSize,
- sizeof(int32_t), _uris.atom_Int, &_seq_size },
- { LV2_OPTIONS_INSTANCE, 0, _uris.param_sampleRate,
- sizeof(int32_t), _uris.atom_Int, &_sample_rate },
- { LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, nullptr }
- };
-
- LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature));
- f->URI = LV2_OPTIONS__options;
- f->data = malloc(sizeof(options));
- memcpy(f->data, options, sizeof(options));
- return SPtr<LV2_Feature>(f, &free_feature);
- }
-
-private:
- const URIs& _uris;
- int32_t _sample_rate;
- int32_t _block_length;
- int32_t _seq_size;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_LV2OPTIONS_HPP
diff --git a/src/server/LV2Plugin.cpp b/src/server/LV2Plugin.cpp
deleted file mode 100644
index f56fd4d7..00000000
--- a/src/server/LV2Plugin.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <string>
-
-#include "ingen/Forge.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
-
-#include "Engine.hpp"
-#include "LV2Block.hpp"
-#include "LV2Plugin.hpp"
-
-namespace Ingen {
-namespace Server {
-
-LV2Plugin::LV2Plugin(World* world, const LilvPlugin* lplugin)
- : PluginImpl(world->uris(),
- world->uris().lv2_Plugin.urid,
- URI(lilv_node_as_uri(lilv_plugin_get_uri(lplugin))))
- , _world(world)
- , _lilv_plugin(lplugin)
-{
- set_property(_uris.rdf_type, _uris.lv2_Plugin);
-
- update_properties();
-}
-
-void
-LV2Plugin::update_properties()
-{
- LilvNode* minor = lilv_world_get(_world->lilv_world(),
- lilv_plugin_get_uri(_lilv_plugin),
- _uris.lv2_minorVersion,
- nullptr);
- LilvNode* micro = lilv_world_get(_world->lilv_world(),
- lilv_plugin_get_uri(_lilv_plugin),
- _uris.lv2_microVersion,
- nullptr);
-
- if (lilv_node_is_int(minor) && lilv_node_is_int(micro)) {
- set_property(_uris.lv2_minorVersion,
- _world->forge().make(lilv_node_as_int(minor)));
- set_property(_uris.lv2_microVersion,
- _world->forge().make(lilv_node_as_int(micro)));
- }
-
- lilv_node_free(minor);
- lilv_node_free(micro);
-}
-
-const Raul::Symbol
-LV2Plugin::symbol() const
-{
- std::string working = uri();
- if (working.back() == '/') {
- working = working.substr(0, working.length() - 1);
- }
-
- while (working.length() > 0) {
- size_t last_slash = working.find_last_of("/");
- const std::string symbol = working.substr(last_slash+1);
- if ( (symbol[0] >= 'a' && symbol[0] <= 'z')
- || (symbol[0] >= 'A' && symbol[0] <= 'Z') ) {
- return Raul::Symbol::symbolify(symbol);
- } else {
- working = working.substr(0, last_slash);
- }
- }
-
- return Raul::Symbol("lv2_symbol");
-}
-
-BlockImpl*
-LV2Plugin::instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state)
-{
- LV2Block* b = new LV2Block(
- this, symbol, polyphonic, parent, engine.sample_rate());
-
- if (!b->instantiate(bufs, state)) {
- delete b;
- return nullptr;
- } else {
- return b;
- }
-}
-
-void
-LV2Plugin::load_presets()
-{
- const URIs& uris = _world->uris();
- LilvWorld* lworld = _world->lilv_world();
- LilvNodes* presets = lilv_plugin_get_related(_lilv_plugin, uris.pset_Preset);
-
- if (presets) {
- LILV_FOREACH(nodes, i, presets) {
- const LilvNode* preset = lilv_nodes_get(presets, i);
- lilv_world_load_resource(lworld, preset);
-
- LilvNodes* labels = lilv_world_find_nodes(
- lworld, preset, uris.rdfs_label, nullptr);
- if (labels) {
- const LilvNode* label = lilv_nodes_get_first(labels);
-
- _presets.emplace(URI(lilv_node_as_uri(preset)),
- lilv_node_as_string(label));
-
- lilv_nodes_free(labels);
- } else {
- _world->log().error(
- fmt("Preset <%1%> has no rdfs:label\n")
- % lilv_node_as_string(lilv_nodes_get(presets, i)));
- }
- }
-
- lilv_nodes_free(presets);
- }
-
- PluginImpl::load_presets();
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/LV2Plugin.hpp b/src/server/LV2Plugin.hpp
deleted file mode 100644
index 43d0fba9..00000000
--- a/src/server/LV2Plugin.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_LV2PLUGIN_HPP
-#define INGEN_ENGINE_LV2PLUGIN_HPP
-
-#include <cstdlib>
-
-#include "ingen/types.hpp"
-#include "lilv/lilv.h"
-
-#include "PluginImpl.hpp"
-
-namespace Ingen {
-
-class World;
-
-namespace Server {
-
-class GraphImpl;
-class BlockImpl;
-
-/** Implementation of an LV2 plugin (loaded shared library).
- */
-class LV2Plugin : public PluginImpl
-{
-public:
- LV2Plugin(World* world, const LilvPlugin* lplugin);
-
- BlockImpl* instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state);
-
- const Raul::Symbol symbol() const;
-
- World* world() const { return _world; }
- const LilvPlugin* lilv_plugin() const { return _lilv_plugin; }
-
- void update_properties();
-
- void load_presets();
-
- URI bundle_uri() const {
- const LilvNode* bundle = lilv_plugin_get_bundle_uri(_lilv_plugin);
- return URI(lilv_node_as_uri(bundle));
- }
-
-private:
- World* _world;
- const LilvPlugin* _lilv_plugin;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_LV2PLUGIN_HPP
diff --git a/src/server/LV2ResizeFeature.hpp b/src/server/LV2ResizeFeature.hpp
deleted file mode 100644
index f61165ee..00000000
--- a/src/server/LV2ResizeFeature.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_LV2RESIZEFEATURE_HPP
-#define INGEN_ENGINE_LV2RESIZEFEATURE_HPP
-
-#include "ingen/LV2Features.hpp"
-#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
-
-#include "BlockImpl.hpp"
-#include "Buffer.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-struct ResizeFeature : public Ingen::LV2Features::Feature {
- static LV2_Resize_Port_Status resize_port(
- LV2_Resize_Port_Feature_Data data,
- uint32_t index,
- size_t size) {
- BlockImpl* block = (BlockImpl*)data;
- PortImpl* port = block->port_impl(index);
- if (block->context() == Context::ID::MESSAGE) {
- port->buffer(0)->resize(size);
- port->connect_buffers();
- return LV2_RESIZE_PORT_SUCCESS;
- }
- return LV2_RESIZE_PORT_ERR_UNKNOWN;
- }
-
- const char* uri() const { return LV2_RESIZE_PORT_URI; }
-
- SPtr<LV2_Feature> feature(World* w, Node* n) {
- BlockImpl* block = dynamic_cast<BlockImpl*>(n);
- if (!block)
- return SPtr<LV2_Feature>();
- LV2_Resize_Port_Resize* data
- = (LV2_Resize_Port_Resize*)malloc(sizeof(LV2_Resize_Port_Resize));
- data->data = block;
- data->resize = &resize_port;
- LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature));
- f->URI = LV2_RESIZE_PORT_URI;
- f->data = data;
- return SPtr<LV2_Feature>(f, &free_feature);
- }
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_LV2RESIZEFEATURE_HPP
diff --git a/src/server/Load.hpp b/src/server/Load.hpp
deleted file mode 100644
index ed9ee406..00000000
--- a/src/server/Load.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- 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_ENGINE_LOAD_HPP
-#define INGEN_ENGINE_LOAD_HPP
-
-namespace Ingen {
-namespace Server {
-
-struct Load
-{
- void update(uint64_t time, uint64_t available) {
- const uint64_t load = time * 100 / available;
- if (load < min) {
- min = load;
- changed = true;
- }
- if (load > max) {
- max = load;
- changed = true;
- }
- if (++n == 1) {
- mean = load;
- changed = true;
- } else {
- const float a = mean + ((float)load - mean) / (float)++n;
- if (a != mean) {
- changed = floorf(a) != floorf(mean);
- mean = a;
- }
- }
- }
-
- uint64_t min = std::numeric_limits<uint64_t>::max();
- uint64_t max = 0;
- float mean = 0.0f;
- uint64_t n = 0;
- bool changed = false;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_LOAD_HPP
diff --git a/src/server/NodeImpl.cpp b/src/server/NodeImpl.cpp
deleted file mode 100644
index 778ba15a..00000000
--- a/src/server/NodeImpl.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "GraphImpl.hpp"
-#include "NodeImpl.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-NodeImpl::NodeImpl(const Ingen::URIs& uris,
- NodeImpl* parent,
- const Raul::Symbol& symbol)
- : Node(uris, parent ? parent->path().child(symbol) : Raul::Path("/"))
- , _parent(parent)
- , _path(parent ? parent->path().child(symbol) : Raul::Path("/"))
- , _symbol(symbol)
-{
-}
-
-const Atom&
-NodeImpl::get_property(const URI& key) const
-{
- ThreadManager::assert_not_thread(THREAD_PROCESS);
- static const Atom null_atom;
- auto i = properties().find(key);
- return (i != properties().end()) ? i->second : null_atom;
-}
-
-GraphImpl*
-NodeImpl::parent_graph() const
-{
- return dynamic_cast<GraphImpl*>((BlockImpl*)_parent);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/NodeImpl.hpp b/src/server/NodeImpl.hpp
deleted file mode 100644
index 614801eb..00000000
--- a/src/server/NodeImpl.hpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_NODEIMPL_HPP
-#define INGEN_ENGINE_NODEIMPL_HPP
-
-#include <cassert>
-#include <cstddef>
-#include <map>
-
-#include "ingen/Node.hpp"
-#include "ingen/Resource.hpp"
-#include "raul/Deletable.hpp"
-#include "raul/Path.hpp"
-
-namespace Raul { class Maid; }
-
-namespace Ingen {
-
-namespace Shared { class URIs; }
-
-namespace Server {
-
-class BufferFactory;
-class GraphImpl;
-class RunContext;
-
-/** An object on the audio graph (a Graph, Block, or Port).
- *
- * Each of these is a Raul::Deletable and so can be deleted in a realtime safe
- * way from anywhere, and they all have a map of variable for clients to store
- * arbitrary values in (which the engine puts no significance to whatsoever).
- *
- * \ingroup engine
- */
-class NodeImpl : public Node
-{
-public:
- const Raul::Symbol& symbol() const { return _symbol; }
-
- Node* graph_parent() const { return _parent; }
- NodeImpl* parent() const { return _parent; }
-
- /** Rename */
- virtual void set_path(const Raul::Path& new_path) {
- _path = new_path;
- const char* const new_sym = new_path.symbol();
- if (new_sym[0] != '\0') {
- _symbol = Raul::Symbol(new_sym);
- }
- set_uri(path_to_uri(new_path));
- }
-
- const Atom& get_property(const URI& key) const;
-
- /** The Graph this object is a child of. */
- virtual GraphImpl* parent_graph() const;
-
- const Raul::Path& path() const { return _path; }
-
- /** Prepare for a new (external) polyphony value.
- *
- * Preprocessor thread, poly is actually applied by apply_poly.
- * \return true on success.
- */
- virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly) = 0;
-
- /** Apply a new (external) polyphony value.
- *
- * \param context Process context (process thread only).
- * \param poly Must be <= the most recent value passed to prepare_poly.
- */
- virtual bool apply_poly(RunContext& context, uint32_t poly) = 0;
-
- /** Return true iff this is main (the top level Node).
- *
- * This is sometimes called "the root graph", but the term "main" is used
- * to avoid ambiguity with the root path, since main does not have the path
- * "/", but usually "/main" to leave namespace for non-node things.
- */
- bool is_main() const { return !_parent; }
-
-protected:
- NodeImpl(const Ingen::URIs& uris,
- NodeImpl* parent,
- const Raul::Symbol& symbol);
-
- NodeImpl* _parent;
- Raul::Path _path;
- Raul::Symbol _symbol;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_NODEIMPL_HPP
diff --git a/src/server/OutputPort.hpp b/src/server/OutputPort.hpp
deleted file mode 100644
index 1058defb..00000000
--- a/src/server/OutputPort.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_OUTPUTPORT_HPP
-#define INGEN_ENGINE_OUTPUTPORT_HPP
-
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** An output port.
- *
- * Output ports always have a locally allocated buffer, and buffer() will
- * always return that buffer.
- *
- * \ingroup engine
- */
-class OutputPort : public PortImpl
-{
-public:
- OutputPort(BufferFactory& bufs,
- BlockImpl* parent,
- const Raul::Symbol& symbol,
- uint32_t index,
- uint32_t poly,
- PortType type,
- LV2_URID buffer_type,
- const Atom& value,
- size_t buffer_size = 0)
- : PortImpl(bufs, parent, symbol, index,poly, type, buffer_type, value, buffer_size, true)
- {}
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_OUTPUTPORT_HPP
diff --git a/src/server/PluginImpl.hpp b/src/server/PluginImpl.hpp
deleted file mode 100644
index ebd4b3e5..00000000
--- a/src/server/PluginImpl.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_PLUGINIMPL_HPP
-#define INGEN_ENGINE_PLUGINIMPL_HPP
-
-#include <cstdlib>
-
-#include "ingen/Resource.hpp"
-#include "raul/Symbol.hpp"
-
-namespace Ingen {
-
-class URIs;
-
-namespace Server {
-
-class BlockImpl;
-class BufferFactory;
-class Engine;
-class GraphImpl;
-
-/** Implementation of a plugin (internal code, or a loaded shared library).
- *
- * Conceptually, a Block is an instance of this.
- */
-class PluginImpl : public Resource
-{
-public:
- PluginImpl(Ingen::URIs& uris, const Atom& type, const URI& uri)
- : Resource(uris, uri)
- , _type(type)
- , _presets_loaded(false)
- , _is_zombie(false)
- {
- }
-
- virtual BlockImpl* instantiate(BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- Engine& engine,
- const LilvState* state) = 0;
-
- virtual const Raul::Symbol symbol() const = 0;
-
- const Atom& type() const { return _type; }
- void set_type(const Atom& t) { _type = t; }
- bool is_zombie() const { return _is_zombie; }
- void set_is_zombie(bool t) { _is_zombie = t; }
-
- typedef std::pair<URI, std::string> Preset;
- typedef std::map<URI, std::string> Presets;
-
- const Presets& presets(bool force_reload=false) {
- if (!_presets_loaded || force_reload) {
- load_presets();
- }
-
- return _presets;
- }
-
- virtual void update_properties() {}
-
- virtual void load_presets() { _presets_loaded = true; }
-
- virtual URI bundle_uri() const { return URI("ingen:/"); }
-
-protected:
- Atom _type;
- Presets _presets;
- bool _presets_loaded;
- bool _is_zombie;
-
-private:
- PluginImpl(const PluginImpl&) = delete;
- PluginImpl& operator=(const PluginImpl&) = delete;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_PLUGINIMPL_HPP
diff --git a/src/server/PortAudioDriver.cpp b/src/server/PortAudioDriver.cpp
deleted file mode 100644
index f892c99f..00000000
--- a/src/server/PortAudioDriver.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen_config.h"
-
-#include <cstdlib>
-#include <string>
-
-#include <portaudio.h>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/LV2Features.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-
-#include "Buffer.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "PortAudioDriver.hpp"
-#include "PortImpl.hpp"
-#include "FrameTimer.hpp"
-#include "ThreadManager.hpp"
-#include "util.hpp"
-
-namespace Ingen {
-namespace Server {
-
-static bool
-pa_error(const char* msg, PaError err)
-{
- fprintf(stderr, "error: %s (%s)\n", msg, Pa_GetErrorText(err));
- Pa_Terminate();
- return false;
-}
-
-PortAudioDriver::PortAudioDriver(Engine& engine)
- : _engine(engine)
- , _sem(0)
- , _stream(nullptr)
- , _seq_size(4096)
- , _block_length(engine.world()->conf().option("buffer-size").get<int32_t>())
- , _sample_rate(48000)
- , _n_inputs(0)
- , _n_outputs(0)
- , _flag(false)
- , _is_activated(false)
-{
-}
-
-PortAudioDriver::~PortAudioDriver()
-{
- deactivate();
- _ports.clear_and_dispose([](EnginePort* p) { delete p; });
-}
-
-bool
-PortAudioDriver::attach()
-{
- PaError st = paNoError;
- if ((st = Pa_Initialize())) {
- return pa_error("Failed to initialize audio system", st);
- }
-
- // Get default input and output devices
- _inputParameters.device = Pa_GetDefaultInputDevice();
- _outputParameters.device = Pa_GetDefaultOutputDevice();
- if (_inputParameters.device == paNoDevice) {
- return pa_error("No default input device", paDeviceUnavailable);
- } else if (_outputParameters.device == paNoDevice) {
- return pa_error("No default output device", paDeviceUnavailable);
- }
-
- const PaDeviceInfo* in_dev = Pa_GetDeviceInfo(_inputParameters.device);
-
- /* TODO: It looks like it is somehow actually impossible to request the
- best/native buffer size then retrieve what it actually is with
- PortAudio. How such a glaring useless flaw exists in such a widespread
- library is beyond me... */
-
- _sample_rate = in_dev->defaultSampleRate;
-
- _timer = std::unique_ptr<FrameTimer>(
- new FrameTimer(_block_length, _sample_rate));
-
- return true;
-}
-
-bool
-PortAudioDriver::activate()
-{
- const PaDeviceInfo* in_dev = Pa_GetDeviceInfo(_inputParameters.device);
- const PaDeviceInfo* out_dev = Pa_GetDeviceInfo(_outputParameters.device);
-
- // Count number of input and output audio ports/channels
- _inputParameters.channelCount = 0;
- _outputParameters.channelCount = 0;
- for (const auto& port : _ports) {
- if (port.graph_port()->is_a(PortType::AUDIO)) {
- if (port.graph_port()->is_input()) {
- ++_inputParameters.channelCount;
- } else if (port.graph_port()->is_output()) {
- ++_outputParameters.channelCount;
- }
- }
- }
-
- // Configure audio format
- _inputParameters.sampleFormat = paFloat32|paNonInterleaved;
- _inputParameters.suggestedLatency = in_dev->defaultLowInputLatency;
- _inputParameters.hostApiSpecificStreamInfo = nullptr;
- _outputParameters.sampleFormat = paFloat32|paNonInterleaved;
- _outputParameters.suggestedLatency = out_dev->defaultLowOutputLatency;
- _outputParameters.hostApiSpecificStreamInfo = nullptr;
-
- // Open stream
- PaError st = paNoError;
- if ((st = Pa_OpenStream(
- &_stream,
- _inputParameters.channelCount ? &_inputParameters : nullptr,
- _outputParameters.channelCount ? &_outputParameters : nullptr,
- in_dev->defaultSampleRate,
- _block_length, // paFramesPerBufferUnspecified, // FIXME: ?
- 0,
- pa_process_cb,
- this))) {
- return pa_error("Failed to open audio stream", st);
- }
-
- _is_activated = true;
- if ((st = Pa_StartStream(_stream))) {
- return pa_error("Error starting audio stream", st);
- }
-
- return true;
-}
-
-void
-PortAudioDriver::deactivate()
-{
- Pa_Terminate();
-}
-
-SampleCount
-PortAudioDriver::frame_time() const
-{
- return _timer->frame_time(_engine.current_time()) + _engine.block_length();
-}
-
-EnginePort*
-PortAudioDriver::get_port(const Raul::Path& path)
-{
- for (auto& p : _ports) {
- if (p.graph_port()->path() == path) {
- return &p;
- }
- }
-
- return nullptr;
-}
-
-void
-PortAudioDriver::add_port(RunContext& context, EnginePort* port)
-{
- _ports.push_back(*port);
-}
-
-void
-PortAudioDriver::remove_port(RunContext& context, EnginePort* port)
-{
- _ports.erase(_ports.iterator_to(*port));
-}
-
-void
-PortAudioDriver::register_port(EnginePort& port)
-{
-}
-
-void
-PortAudioDriver::unregister_port(EnginePort& port)
-{
-}
-
-void
-PortAudioDriver::rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path)
-{
-}
-
-void
-PortAudioDriver::port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value)
-{
-}
-
-EnginePort*
-PortAudioDriver::create_port(DuplexPort* graph_port)
-{
- EnginePort* eport = nullptr;
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- // Audio buffer port, use Jack buffer directly
- eport = new EnginePort(graph_port);
- graph_port->set_is_driver_port(*_engine.buffer_factory());
- } else if (graph_port->is_a(PortType::ATOM) &&
- graph_port->buffer_type() == _engine.world()->uris().atom_Sequence) {
- // Sequence port, make Jack port but use internal LV2 format buffer
- eport = new EnginePort(graph_port);
- }
-
- if (graph_port->is_a(PortType::AUDIO)) {
- if (graph_port->is_input()) {
- eport->set_driver_index(_n_inputs++);
- } else {
- eport->set_driver_index(_n_outputs++);
- }
- }
-
- if (eport) {
- register_port(*eport);
- }
-
- return eport;
-}
-
-void
-PortAudioDriver::pre_process_port(RunContext& context,
- EnginePort* port,
- const void* inputs,
- void* outputs)
-{
- if (!port->graph_port()->is_a(PortType::AUDIO)) {
- return;
- }
-
- if (port->is_input()) {
- port->set_buffer(((float**)inputs)[port->driver_index()]);
- } else {
- port->set_buffer(((float**)outputs)[port->driver_index()]);
- memset(port->buffer(), 0, _block_length * sizeof(float));
- }
-
- port->graph_port()->set_driver_buffer(
- port->buffer(), _block_length * sizeof(float));
-}
-
-void
-PortAudioDriver::post_process_port(RunContext& context,
- EnginePort* port,
- const void* inputs,
- void* outputs)
-{
-}
-
-int
-PortAudioDriver::process_cb(const void* inputs,
- void* outputs,
- unsigned long nframes,
- const PaStreamCallbackTimeInfo* time,
- PaStreamCallbackFlags flags)
-{
- _engine.advance(nframes);
- _timer->update(_engine.current_time(), _engine.run_context().start());
-
- // Read input
- for (auto& p : _ports) {
- pre_process_port(_engine.run_context(), &p, inputs, outputs);
- }
-
- // Process
- _engine.run(nframes);
-
- // Write output
- for (auto& p : _ports) {
- post_process_port(_engine.run_context(), &p, inputs, outputs);
- }
-
- return 0;
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/PortAudioDriver.hpp b/src/server/PortAudioDriver.hpp
deleted file mode 100644
index b1545f64..00000000
--- a/src/server/PortAudioDriver.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- 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_ENGINE_PORTAUDIODRIVER_HPP
-#define INGEN_ENGINE_PORTAUDIODRIVER_HPP
-
-#include "ingen_config.h"
-
-#include <atomic>
-#include <memory>
-#include <string>
-
-#include <portaudio.h>
-
-#include "raul/Semaphore.hpp"
-
-#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
-
-#include "Driver.hpp"
-#include "EnginePort.hpp"
-
-namespace Raul { class Path; }
-
-namespace Ingen {
-namespace Server {
-
-class DuplexPort;
-class Engine;
-class GraphImpl;
-class PortAudioDriver;
-class PortImpl;
-class FrameTimer;
-
-class PortAudioDriver : public Driver
-{
-public:
- explicit PortAudioDriver(Engine& engine);
- ~PortAudioDriver();
-
- bool attach();
-
- bool activate();
- void deactivate();
-
- EnginePort* create_port(DuplexPort* graph_port);
- EnginePort* get_port(const Raul::Path& path);
-
- void rename_port(const Raul::Path& old_path, const Raul::Path& new_path);
- void port_property(const Raul::Path& path, const URI& uri, const Atom& value);
- void add_port(RunContext& context, EnginePort* port);
- void remove_port(RunContext& context, EnginePort* port);
- void register_port(EnginePort& port);
- void unregister_port(EnginePort& port);
-
- void append_time_events(RunContext& context, Buffer& buffer) {}
-
- SampleCount frame_time() const;
-
- int real_time_priority() { return 80; }
-
- SampleCount block_length() const { return _block_length; }
- size_t seq_size() const { return _seq_size; }
- SampleCount sample_rate() const { return _sample_rate; }
-
-private:
- friend class PortAudioPort;
-
- inline static int
- pa_process_cb(const void* inputs,
- void* outputs,
- unsigned long nframes,
- const PaStreamCallbackTimeInfo* time,
- PaStreamCallbackFlags flags,
- void* handle) {
- return ((PortAudioDriver*)handle)->process_cb(
- inputs, outputs, nframes, time, flags);
- }
-
- int process_cb(const void* inputs,
- void* outputs,
- unsigned long nframes,
- const PaStreamCallbackTimeInfo* time,
- PaStreamCallbackFlags flags);
-
- void pre_process_port(RunContext& context,
- EnginePort* port,
- const void* inputs,
- void* outputs);
-
- void post_process_port(RunContext& context,
- EnginePort* port,
- const void* inputs,
- void* outputs);
-
-protected:
- typedef boost::intrusive::slist<EnginePort,
- boost::intrusive::cache_last<true>
- > Ports;
-
- Engine& _engine;
- Ports _ports;
- PaStreamParameters _inputParameters;
- PaStreamParameters _outputParameters;
- Raul::Semaphore _sem;
- std::unique_ptr<FrameTimer> _timer;
- PaStream* _stream;
- size_t _seq_size;
- uint32_t _block_length;
- uint32_t _sample_rate;
- uint32_t _n_inputs;
- uint32_t _n_outputs;
- std::atomic<bool> _flag;
- bool _is_activated;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_PORTAUDIODRIVER_HPP
diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp
deleted file mode 100644
index b0ef3c85..00000000
--- a/src/server/PortImpl.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "raul/Array.hpp"
-#include "raul/Maid.hpp"
-
-#include "BlockImpl.hpp"
-#include "Buffer.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "PortImpl.hpp"
-#include "PortType.hpp"
-#include "ThreadManager.hpp"
-
-namespace Ingen {
-namespace Server {
-
-static const uint32_t monitor_rate = 25.0; // Hz
-
-/** The length of time between monitor updates in frames */
-static inline uint32_t
-monitor_period(const Engine& engine)
-{
- return std::max(engine.block_length(),
- engine.sample_rate() / monitor_rate);
-}
-
-PortImpl::PortImpl(BufferFactory& bufs,
- BlockImpl* const block,
- const Raul::Symbol& name,
- uint32_t index,
- uint32_t poly,
- PortType type,
- LV2_URID buffer_type,
- const Atom& value,
- size_t buffer_size,
- bool is_output)
- : NodeImpl(bufs.uris(), block, name)
- , _bufs(bufs)
- , _index(index)
- , _poly(poly)
- , _buffer_size(buffer_size)
- , _frames_since_monitor(0)
- , _monitor_value(0.0f)
- , _peak(0.0f)
- , _type(type)
- , _buffer_type(buffer_type)
- , _value(value)
- , _min(bufs.forge().make(0.0f))
- , _max(bufs.forge().make(1.0f))
- , _voices(bufs.maid().make_managed<Voices>(poly))
- , _connected_flag(false)
- , _monitored(false)
- , _force_monitor_update(false)
- , _is_morph(false)
- , _is_auto_morph(false)
- , _is_logarithmic(false)
- , _is_sample_rate(false)
- , _is_toggled(false)
- , _is_driver_port(false)
- , _is_output(is_output)
-{
- assert(block != nullptr);
- assert(_poly > 0);
-
- const Ingen::URIs& uris = bufs.uris();
-
- set_type(type, buffer_type);
-
- remove_property(uris.lv2_index, uris.patch_wildcard);
- set_property(uris.lv2_index, bufs.forge().make((int32_t)index));
-
- if (has_value()) {
- set_property(uris.ingen_value, value);
- }
- if (type == PortType::ATOM) {
- set_property(uris.atom_bufferType,
- bufs.forge().make_urid(buffer_type));
- }
-
- if (is_output) {
- if (_parent->graph_type() != Node::GraphType::GRAPH) {
- add_property(bufs.uris().rdf_type, bufs.uris().lv2_OutputPort.urid);
- }
- }
-
- get_buffers(bufs, &BufferFactory::get_buffer, _voices, poly, 0);
-}
-
-bool
-PortImpl::get_buffers(BufferFactory& bufs,
- GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const
-{
- for (uint32_t v = 0; v < poly; ++v) {
- voices->at(v).buffer.reset();
- voices->at(v).buffer = (bufs.*get)(
- buffer_type(), _value.type(), _buffer_size);
- }
-
- return true;
-}
-
-bool
-PortImpl::setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly)
-{
- return get_buffers(bufs, &BufferFactory::claim_buffer, _voices, poly, 0);
-}
-
-void
-PortImpl::set_type(PortType port_type, LV2_URID buffer_type)
-{
- const Ingen::URIs& uris = _bufs.uris();
- Ingen::World* world = _bufs.engine().world();
-
- // Update type properties so clients are aware of current type
- remove_property(uris.rdf_type, uris.lv2_AudioPort);
- remove_property(uris.rdf_type, uris.lv2_CVPort);
- remove_property(uris.rdf_type, uris.lv2_ControlPort);
- remove_property(uris.rdf_type, uris.atom_AtomPort);
- add_property(uris.rdf_type, world->forge().make_urid(port_type.uri()));
-
- // Update audio thread types
- _type = port_type;
- _buffer_type = buffer_type;
- if (!_buffer_type) {
- switch (_type.id()) {
- case PortType::CONTROL:
- _buffer_type = uris.atom_Float;
- break;
- case PortType::AUDIO:
- case PortType::CV:
- _buffer_type = uris.atom_Sound;
- break;
- default:
- break;
- }
- }
- _buffer_size = std::max(_buffer_size, _bufs.default_size(_buffer_type));
-}
-
-bool
-PortImpl::has_value() const
-{
- return (_type == PortType::CONTROL ||
- _type == PortType::CV ||
- (_type == PortType::ATOM &&
- _value.type() == _bufs.uris().atom_Float));
-}
-
-bool
-PortImpl::supports(const URIs::Quark& value_type) const
-{
- return has_property(_bufs.uris().atom_supports, value_type);
-}
-
-void
-PortImpl::activate(BufferFactory& bufs)
-{
- /* Set the time since the last monitor update to a random value within the
- monitor period, to spread the load out over time. Otherwise, every
- port would try to send an update at exactly the same time, every time.
- */
- const double srate = bufs.engine().sample_rate();
- const uint32_t period = srate / monitor_rate;
- _frames_since_monitor = bufs.engine().frand() * period;
- _monitor_value = 0.0f;
- _peak = 0.0f;
-
- // Trigger buffer re-connect next cycle
- _connected_flag.clear(std::memory_order_release);
-}
-
-void
-PortImpl::deactivate()
-{
- if (is_output() && !_is_driver_port) {
- for (uint32_t v = 0; v < _poly; ++v) {
- if (_voices->at(v).buffer) {
- _voices->at(v).buffer->clear();
- }
- }
- }
- _monitor_value = 0.0f;
- _peak = 0.0f;
-}
-
-void
-PortImpl::set_voices(RunContext& context, MPtr<Voices>&& voices)
-{
- _voices = std::move(voices);
- connect_buffers();
-}
-
-void
-PortImpl::cache_properties()
-{
- _is_logarithmic = has_property(_bufs.uris().lv2_portProperty,
- _bufs.uris().pprops_logarithmic);
- _is_sample_rate = has_property(_bufs.uris().lv2_portProperty,
- _bufs.uris().lv2_sampleRate);
- _is_toggled = has_property(_bufs.uris().lv2_portProperty,
- _bufs.uris().lv2_toggled);
-}
-
-void
-PortImpl::set_control_value(const RunContext& context,
- FrameTime time,
- Sample value)
-{
- for (uint32_t v = 0; v < _poly; ++v) {
- update_set_state(context, v);
- set_voice_value(context, v, time, value);
- }
-}
-
-void
-PortImpl::set_voice_value(const RunContext& context,
- uint32_t voice,
- FrameTime time,
- Sample value)
-{
- switch (_type.id()) {
- case PortType::CONTROL:
- if (buffer(voice)->value()) {
- ((LV2_Atom_Float*)buffer(voice)->value())->body = value;
- }
- _voices->at(voice).set_state.set(context, context.start(), value);
- break;
- case PortType::AUDIO:
- case PortType::CV: {
- // Time may be at end so internal blocks can set triggers
- assert(time >= context.start());
- assert(time <= context.start() + context.nframes());
-
- const FrameTime offset = time - context.start();
- if (offset < context.nframes()) {
- buffer(voice)->set_block(value, offset, context.nframes());
- }
- /* else, this is a set at context.nframes(), used to reset a CV port's
- value for the next block, particularly for triggers on the last
- frame of a block (set nframes-1 to 1, then nframes to 0). */
-
- _voices->at(voice).set_state.set(context, time, value);
- } break;
- case PortType::ATOM:
- if (buffer(voice)->is_sequence()) {
- const FrameTime offset = time - context.start();
- // Same deal as above
- if (offset < context.nframes()) {
- buffer(voice)->append_event(offset,
- sizeof(value),
- _bufs.uris().atom_Float,
- (const uint8_t*)&value);
- }
- _voices->at(voice).set_state.set(context, time, value);
- } else {
-#ifndef NDEBUG
- fprintf(stderr,
- "error: %s set non-sequence atom port value (buffer type %u)\n",
- path().c_str(), buffer(voice)->type());
-#endif
- }
- default:
- break;
- }
-}
-
-void
-PortImpl::update_set_state(const RunContext& context, uint32_t v)
-{
- Voice& voice = _voices->at(v);
- SetState& state = voice.set_state;
- BufferRef buf = voice.buffer;
- switch (state.state) {
- case SetState::State::SET:
- break;
- case SetState::State::SET_CYCLE_1:
- if (state.time < context.start() &&
- buf->is_sequence() &&
- buf->value_type() == _bufs.uris().atom_Float &&
- !_parent->is_main()) {
- buf->clear();
- state.time = context.start();
- }
- state.state = SetState::State::SET;
- break;
- case SetState::State::HALF_SET_CYCLE_1:
- state.state = SetState::State::HALF_SET_CYCLE_2;
- break;
- case SetState::State::HALF_SET_CYCLE_2:
- if (buf->is_sequence()) {
- buf->clear();
- buf->append_event(
- 0, sizeof(float), _bufs.uris().atom_Float,
- (const uint8_t*)&state.value);
- } else {
- buf->set_block(state.value, 0, context.nframes());
- }
- state.state = SetState::State::SET_CYCLE_1;
- break;
- }
-}
-
-bool
-PortImpl::prepare_poly(BufferFactory& bufs, uint32_t poly)
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
- if (_is_driver_port || _parent->is_main() ||
- (_type == PortType::ATOM && !_value.is_valid())) {
- return false;
- } else if (_poly == poly) {
- return true;
- } else if (_prepared_voices && _prepared_voices->size() != poly) {
- _prepared_voices.reset();
- }
-
- if (!_prepared_voices) {
- _prepared_voices = bufs.maid().make_managed<Voices>(
- poly, *_voices, Voice());
- }
-
- get_buffers(bufs, &BufferFactory::get_buffer,
- _prepared_voices, _prepared_voices->size(), num_arcs());
-
- return true;
-}
-
-bool
-PortImpl::apply_poly(RunContext& context, uint32_t poly)
-{
- if (_parent->is_main() ||
- (_type == PortType::ATOM && !_value.is_valid())) {
- return false;
- } else if (!_prepared_voices) {
- return true;
- }
-
- assert(poly == _prepared_voices->size());
-
- _poly = poly;
-
- // Apply a new set of voices from a preceding call to prepare_poly
- _voices = std::move(_prepared_voices);
-
- if (is_a(PortType::CONTROL) || is_a(PortType::CV)) {
- set_control_value(context, context.start(), _value.get<float>());
- }
-
- assert(_voices->size() >= poly);
- assert(this->poly() == poly);
- assert(!_prepared_voices);
-
- connect_buffers();
-
- return true;
-}
-
-void
-PortImpl::set_buffer_size(RunContext& context, BufferFactory& bufs, size_t size)
-{
- _buffer_size = size;
-
- for (uint32_t v = 0; v < _poly; ++v) {
- _voices->at(v).buffer->resize(size);
- }
-
- connect_buffers();
-}
-
-void
-PortImpl::connect_buffers(SampleCount offset)
-{
- for (uint32_t v = 0; v < _poly; ++v) {
- PortImpl::parent_block()->set_port_buffer(v, _index, buffer(v), offset);
- }
-}
-
-void
-PortImpl::recycle_buffers()
-{
- for (uint32_t v = 0; v < _poly; ++v) {
- _voices->at(v).buffer = nullptr;
- }
-}
-
-void
-PortImpl::set_is_driver_port(BufferFactory& bufs)
-{
- _is_driver_port = true;
-}
-
-void
-PortImpl::clear_buffers(const RunContext& ctx)
-{
- switch (_type.id()) {
- case PortType::AUDIO:
- default:
- for (uint32_t v = 0; v < _poly; ++v) {
- buffer(v)->clear();
- }
- break;
- case PortType::CONTROL:
- for (uint32_t v = 0; v < _poly; ++v) {
- buffer(v)->clear();
- _voices->at(v).set_state.set(ctx, ctx.start(), _value.get<float>());
- }
- break;
- case PortType::CV:
- for (uint32_t v = 0; v < _poly; ++v) {
- buffer(v)->set_block(_value.get<float>(), 0, ctx.nframes());
- _voices->at(v).set_state.set(ctx, ctx.start(), _value.get<float>());
- }
- break;
- }
-}
-
-void
-PortImpl::monitor(RunContext& context, bool send_now)
-{
- if (!context.must_notify(this)) {
- return;
- }
-
- const uint32_t period = monitor_period(context.engine());
- _frames_since_monitor += context.nframes();
-
- const bool time_to_send = send_now || _frames_since_monitor >= period;
- const bool is_sequence = (_type.id() == PortType::ATOM &&
- _buffer_type == _bufs.uris().atom_Sequence);
- if (!time_to_send && !(is_sequence && _monitored) && (!is_sequence && buffer(0)->value())) {
- return;
- }
-
- Forge& forge = context.engine().world()->forge();
- URIs& uris = context.engine().world()->uris();
- LV2_URID key = 0;
- float val = 0.0f;
- switch (_type.id()) {
- case PortType::UNKNOWN:
- break;
- case PortType::AUDIO:
- key = uris.ingen_activity;
- val = _peak = std::max(_peak, buffer(0)->peak(context));
- break;
- case PortType::CONTROL:
- case PortType::CV:
- key = uris.ingen_value;
- val = buffer(0)->value_at(0);
- break;
- case PortType::ATOM:
- if (_buffer_type == _bufs.uris().atom_Sequence) {
- const LV2_Atom* atom = buffer(0)->get<const LV2_Atom>();
- const LV2_Atom* value = buffer(0)->value();
- if (atom->type != _bufs.uris().atom_Sequence) {
- /* Buffer contents are not actually a Sequence. Probably an
- uninitialized Chunk, so do nothing. */
- } else if (_monitored) {
- /* Sequence explicitly monitored, send everything. */
- const LV2_Atom_Sequence* seq = (const LV2_Atom_Sequence*)atom;
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- context.notify(uris.ingen_activity,
- context.start() + ev->time.frames,
- this,
- ev->body.size,
- ev->body.type,
- LV2_ATOM_BODY(&ev->body));
- }
- } else if (value && value->type == _bufs.uris().atom_Float) {
- /* Float sequence, monitor as a control. */
- key = uris.ingen_value;
- val = ((LV2_Atom_Float*)buffer(0)->value())->body;
- } else if (atom->size > sizeof(LV2_Atom_Sequence_Body)) {
- /* General sequence, send activity for blinkenlights. */
- const int32_t one = 1;
- context.notify(uris.ingen_activity,
- context.start(),
- this,
- sizeof(int32_t),
- (LV2_URID)uris.atom_Bool,
- &one);
- _force_monitor_update = false;
- }
- }
- }
-
- _frames_since_monitor = _frames_since_monitor % period;
- if (key && val != _monitor_value) {
- if (context.notify(key, context.start(), this,
- sizeof(float), forge.Float, &val)) {
- /* Update frames since last update to conceptually zero, but keep
- the remainder to preserve load balancing. */
- _frames_since_monitor = _frames_since_monitor % period;
- _peak = 0.0f;
- _monitor_value = val;
- }
- // Otherwise failure, leave old value and try again next time
- }
-}
-
-BufferRef
-PortImpl::value_buffer(uint32_t voice)
-{
- return buffer(voice)->value_buffer();
-}
-
-SampleCount
-PortImpl::next_value_offset(SampleCount offset, SampleCount end) const
-{
- SampleCount earliest = end;
- for (uint32_t v = 0; v < _poly; ++v) {
- const SampleCount o = _voices->at(v).buffer->next_value_offset(offset, end);
- if (o < earliest) {
- earliest = o;
- }
- }
- return earliest;
-}
-
-void
-PortImpl::update_values(SampleCount offset, uint32_t voice)
-{
- buffer(voice)->update_value_buffer(offset);
-}
-
-void
-PortImpl::pre_process(RunContext& context)
-{
- if (!_connected_flag.test_and_set(std::memory_order_acquire)) {
- connect_buffers();
- clear_buffers(context);
- }
-
- for (uint32_t v = 0; v < _poly; ++v) {
- _voices->at(v).buffer->prepare_output_write(context);
- }
-}
-
-void
-PortImpl::post_process(RunContext& context)
-{
- for (uint32_t v = 0; v < _poly; ++v) {
- update_set_state(context, v);
- update_values(0, v);
- }
-
- monitor(context);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp
deleted file mode 100644
index 70d90d0a..00000000
--- a/src/server/PortImpl.hpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_PORTIMPL_HPP
-#define INGEN_ENGINE_PORTIMPL_HPP
-
-#include <cstdlib>
-
-#include "ingen/Atom.hpp"
-#include "raul/Array.hpp"
-
-#include "BufferRef.hpp"
-#include "NodeImpl.hpp"
-#include "PortType.hpp"
-#include "RunContext.hpp"
-#include "types.hpp"
-
-namespace Raul { class Maid; }
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class BufferFactory;
-class RunContext;
-
-/** A port (input or output) on a Block.
- *
- * The base implementation here is general and/or for output ports (which are
- * simplest), InputPort and DuplexPort override functions to provide
- * specialized behaviour where necessary.
- *
- * \ingroup engine
- */
-class PortImpl : public NodeImpl
-{
-public:
- struct SetState {
- enum class State {
- /// Partially set, first cycle: AAAAA => AAABB.
- HALF_SET_CYCLE_1,
-
- /// Partially set, second cycle: AAABB => BBBBB.
- HALF_SET_CYCLE_2,
-
- /// Fully set, first cycle (clear events if necessary).
- SET_CYCLE_1,
-
- /// Fully set, second cycle and onwards (done).
- SET
- };
-
- SetState() : state(State::SET), value(0), time(0) {}
-
- void set(const RunContext& context, FrameTime t, Sample v) {
- time = t;
- value = v;
- state = (time == context.start()
- ? State::SET
- : State::HALF_SET_CYCLE_1);
- }
-
- State state; ///< State of buffer for setting control value
- Sample value; ///< Value currently being set
- FrameTime time; ///< Time value was set
- };
-
- struct Voice {
- Voice() : buffer(nullptr) {}
-
- SetState set_state;
- BufferRef buffer;
- };
-
- typedef Raul::Array<Voice> Voices;
-
- PortImpl(BufferFactory& bufs,
- BlockImpl* block,
- const Raul::Symbol& name,
- uint32_t index,
- uint32_t poly,
- PortType type,
- LV2_URID buffer_type,
- const Atom& value,
- size_t buffer_size = 0,
- bool is_output = true);
-
- virtual GraphType graph_type() const { return GraphType::PORT; }
-
- /** A port's parent is always a block, so static cast should be safe */
- BlockImpl* parent_block() const { return (BlockImpl*)_parent; }
-
- /** Set the the voices (buffers) for this port in the audio thread. */
- void set_voices(RunContext& context, MPtr<Voices>&& voices);
-
- /** Prepare for a new (external) polyphony value.
- *
- * Preprocessor thread, poly is actually applied by apply_poly.
- */
- virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly);
-
- /** Apply a new polyphony value.
- *
- * Audio thread.
- * \a poly Must be < the most recent value passed to prepare_poly.
- */
- virtual bool apply_poly(RunContext& context, uint32_t poly);
-
- /** Return the number of arcs (pre-process thraed). */
- virtual size_t num_arcs() const { return 0; }
-
- const Atom& value() const { return _value; }
- void set_value(const Atom& v) { _value = v; }
-
- const Atom& minimum() const { return _min; }
- const Atom& maximum() const { return _max; }
-
- /* The following two methods store the range in variables so it can be
- accessed in the process thread, which is required for applying control
- bindings from incoming MIDI data.
- */
- void set_minimum(const Atom& min) { _min.set_rt(min); }
- void set_maximum(const Atom& max) { _max.set_rt(max); }
-
- inline BufferRef buffer(uint32_t voice) const {
- return _voices->at((_poly == 1) ? 0 : voice).buffer;
- }
- inline BufferRef prepared_buffer(uint32_t voice) const {
- return _prepared_voices->at(voice).buffer;
- }
-
- void update_set_state(const RunContext& context, uint32_t v);
-
- void set_voice_value(const RunContext& context,
- uint32_t voice,
- FrameTime time,
- Sample value);
-
- void set_control_value(const RunContext& context,
- FrameTime time,
- Sample value);
-
- /** Prepare this port to use an external driver-provided buffer.
- *
- * This will avoid allocating a buffer for the port, instead the driver
- * buffer is used directly. This only makes sense for ports on the
- * top-level graph, which are monophonic. Non-real-time, must be called
- * before using the port, followed by a call to set_driver_buffer() in the
- * processing thread.
- */
- virtual void set_is_driver_port(BufferFactory& bufs);
-
- bool is_driver_port() const { return _is_driver_port; }
-
- /** Called once per process cycle */
- virtual void pre_process(RunContext& context);
- virtual void pre_run(RunContext& context) {}
- virtual void post_process(RunContext& context);
-
- /** Clear/silence all buffers */
- virtual void clear_buffers(const RunContext& ctx);
-
- /** Claim and apply buffers in the real-time thread. */
- virtual bool setup_buffers(RunContext& ctx, BufferFactory& bufs, uint32_t poly);
-
- void activate(BufferFactory& bufs);
- void deactivate();
-
- /**
- Inherit any properties from a connected neighbour.
-
- This is used for Graph ports, so e.g. a control input has the range of
- all the ports it is connected to.
- */
- virtual void inherit_neighbour(const PortImpl* port,
- Properties& remove,
- Properties& add) {}
-
- virtual void connect_buffers(SampleCount offset=0);
- virtual void recycle_buffers();
-
- uint32_t index() const { return _index; }
- void set_index(RunContext&, uint32_t index) { _index = index; }
-
- inline bool is_a(PortType type) const { return _type == type; }
-
- bool has_value() const;
-
- PortType type() const { return _type; }
- LV2_URID value_type() const { return _value.is_valid() ? _value.type() : 0; }
- LV2_URID buffer_type() const { return _buffer_type; }
-
- bool supports(const URIs::Quark& value_type) const;
-
- size_t buffer_size() const { return _buffer_size; }
-
- uint32_t poly() const {
- return _poly;
- }
- uint32_t prepared_poly() const {
- return (_prepared_voices) ? _prepared_voices->size() : 1;
- }
-
- void set_buffer_size(RunContext& context, BufferFactory& bufs, size_t size);
-
- /** Return true iff this port is explicitly monitored.
- *
- * This is used for plugin UIs which require monitoring for particular
- * ports, even if the Ingen client has not requested broadcasting in
- * general (e.g. for canvas animation).
- */
- bool is_monitored() const { return _monitored; }
-
- /** Explicitly turn on monitoring for this port. */
- void enable_monitoring(bool monitored) { _monitored = monitored; }
-
- /** Monitor port value and broadcast to clients periodically. */
- void monitor(RunContext& context, bool send_now=false);
-
- BufferFactory& bufs() const { return _bufs; }
-
- BufferRef value_buffer(uint32_t voice);
-
- BufferRef user_buffer(RunContext&) const { return _user_buffer; }
- void set_user_buffer(RunContext&, BufferRef b) { _user_buffer = b; }
-
- /** Return offset of the first value change after `offset`. */
- virtual SampleCount next_value_offset(SampleCount offset,
- SampleCount end) const;
-
- /** Update value buffer for `voice` to be current as of `offset`. */
- void update_values(SampleCount offset, uint32_t voice);
-
- void force_monitor_update() { _force_monitor_update = true; }
-
- void set_morphable(bool is_morph, bool is_auto_morph) {
- _is_morph = is_morph;
- _is_auto_morph = is_auto_morph;
- }
-
- void set_type(PortType port_type, LV2_URID buffer_type);
-
- void cache_properties();
-
- bool is_input() const { return !_is_output; }
- bool is_output() const { return _is_output; }
- bool is_morph() const { return _is_morph; }
- bool is_auto_morph() const { return _is_auto_morph; }
- bool is_logarithmic() const { return _is_logarithmic; }
- bool is_sample_rate() const { return _is_sample_rate; }
- bool is_toggled() const { return _is_toggled; }
-
-protected:
- typedef BufferRef (BufferFactory::*GetFn)(LV2_URID, LV2_URID, uint32_t);
-
- /** Set `voices` as the buffers to be used for this port.
- *
- * This is real-time safe only if `get` is as well, use in the real-time
- * thread should pass &BufferFactory::claim_buffer.
- *
- * @return true iff buffers are locally owned by the port
- */
- virtual bool get_buffers(BufferFactory& bufs,
- GetFn get,
- const MPtr<Voices>& voices,
- uint32_t poly,
- size_t num_in_arcs) const;
-
- BufferFactory& _bufs;
- uint32_t _index;
- uint32_t _poly;
- uint32_t _buffer_size;
- uint32_t _frames_since_monitor;
- float _monitor_value;
- float _peak;
- PortType _type;
- LV2_URID _buffer_type;
- Atom _value;
- Atom _min;
- Atom _max;
- MPtr<Voices> _voices;
- MPtr<Voices> _prepared_voices;
- BufferRef _user_buffer;
- std::atomic_flag _connected_flag;
- bool _monitored;
- bool _force_monitor_update;
- bool _is_morph;
- bool _is_auto_morph;
- bool _is_logarithmic;
- bool _is_sample_rate;
- bool _is_toggled;
- bool _is_driver_port;
- bool _is_output;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_PORTIMPL_HPP
diff --git a/src/server/PortType.hpp b/src/server/PortType.hpp
deleted file mode 100644
index 0b62c5ab..00000000
--- a/src/server/PortType.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- 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_INTERFACE_PORTTYPE_HPP
-#define INGEN_INTERFACE_PORTTYPE_HPP
-
-#include <cassert>
-
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-namespace Ingen {
-
-/** The type of a port.
- *
- * This type refers to the type of the port itself (not necessarily the type
- * of its contents). Ports with different types can contain the same type of
- * data, but may e.g. have different access semantics.
- */
-class PortType {
-public:
- enum ID {
- UNKNOWN = 0,
- AUDIO = 1,
- CONTROL = 2,
- CV = 3,
- ATOM = 4
- };
-
- explicit PortType(const URI& uri)
- : _id(UNKNOWN)
- {
- if (uri == type_uri(AUDIO)) {
- _id = AUDIO;
- } else if (uri == type_uri(CONTROL)) {
- _id = CONTROL;
- } else if (uri == type_uri(CV)) {
- _id = CV;
- } else if (uri == type_uri(ATOM)) {
- _id = ATOM;
- }
- }
-
- PortType(ID id) : _id(id) {}
-
- inline const URI& uri() const { return type_uri(_id); }
- inline ID id() const { return _id; }
-
- inline bool operator==(const ID& id) const { return (_id == id); }
- inline bool operator!=(const ID& id) const { return (_id != id); }
- inline bool operator==(const PortType& type) const { return (_id == type._id); }
- inline bool operator!=(const PortType& type) const { return (_id != type._id); }
- inline bool operator<(const PortType& type) const { return (_id < type._id); }
-
- inline bool is_audio() { return _id == AUDIO; }
- inline bool is_control() { return _id == CONTROL; }
- inline bool is_cv() { return _id == CV; }
- inline bool is_atom() { return _id == ATOM; }
-
-private:
- static inline const URI& type_uri(unsigned id_num) {
- assert(id_num <= ATOM);
- static const URI uris[] = {
- URI("http://www.w3.org/2002/07/owl#Nothing"),
- URI(LV2_CORE__AudioPort),
- URI(LV2_CORE__ControlPort),
- URI(LV2_CORE__CVPort),
- URI(LV2_ATOM__AtomPort)
- };
- return uris[id_num];
- }
-
- ID _id;
-};
-
-} // namespace Ingen
-
-#endif // INGEN_INTERFACE_PORTTYPE_HPP
diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp
deleted file mode 100644
index b275c36a..00000000
--- a/src/server/PostProcessor.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-
-#include "Engine.hpp"
-#include "Event.hpp"
-#include "PostProcessor.hpp"
-#include "RunContext.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Sentinel : public Event {
-public:
- Sentinel(Engine& engine) : Event(engine) {}
-
- bool pre_process(PreProcessContext& ctx) { return false; }
- void execute(RunContext& context) {}
- void post_process() {}
-};
-
-PostProcessor::PostProcessor(Engine& engine)
- : _engine(engine)
- , _head(new Sentinel(engine))
- , _tail(_head.load())
- , _max_time(0)
-{
-}
-
-PostProcessor::~PostProcessor()
-{
- /* Delete any straggler events (usually at least one since the event list
- is never completely emptied by process()). */
- Event* e = _head;
- while (e) {
- Event* const next = e->next();
- delete e;
- e = next;
- }
-}
-
-void
-PostProcessor::append(RunContext& context, Event* first, Event* last)
-{
- assert(first);
- assert(last);
- assert(!last->next());
-
- // The only place where _tail is written or next links are changed
- _tail.load()->next(first);
- _tail.store(last);
-}
-
-bool
-PostProcessor::pending() const
-{
- return _head.load()->next() || _engine.pending_notifications();
-}
-
-void
-PostProcessor::process()
-{
- const FrameTime end_time = _max_time;
-
- /* We can never empty the list and set _head = _tail = NULL since this
- would cause a race with append. Instead, head is an already
- post-processed node, or initially a sentinel. */
- Event* ev = _head.load();
- Event* next = ev->next();
- if (!next || next->time() >= end_time) {
- // Process audio thread notifications until end
- _engine.emit_notifications(end_time);
- return;
- }
-
- do {
- // Delete previously post-processed ev and move to next
- delete ev;
- ev = next;
-
- // Process audio thread notifications up until this event's time
- _engine.emit_notifications(ev->time());
-
- // Post-process event
- ev->post_process();
- next = ev->next(); // [1] (see below)
- } while (next && next->time() < end_time);
-
- /* Reached the tail (as far as we're concerned). There may be successors
- by now if append() has been called since [1], but that's fine. Now, ev
- points to the last post-processed event, which will be the new head. */
- assert(ev);
- _head = ev;
-
- // Process remaining audio thread notifications until end
- _engine.emit_notifications(end_time);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/PostProcessor.hpp b/src/server/PostProcessor.hpp
deleted file mode 100644
index 5a3ffa62..00000000
--- a/src/server/PostProcessor.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_POSTPROCESSOR_HPP
-#define INGEN_ENGINE_POSTPROCESSOR_HPP
-
-#include <atomic>
-
-#include "ingen/ingen.h"
-
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-class Event;
-class RunContext;
-
-/** Processor for Events after leaving the audio thread.
- *
- * The audio thread pushes events to this when it is done with them (which
- * is realtime-safe), which signals the processing thread through a semaphore
- * to handle the event and pass it on to the Maid.
- *
- * Update: This is all run from main_iteration now to solve scripting
- * thread issues. Not sure if this is permanent/ideal or not...
- *
- * \ingroup engine
- */
-class INGEN_API PostProcessor
-{
-public:
- explicit PostProcessor(Engine& engine);
- ~PostProcessor();
-
- /** Push a list of events on to the process queue.
- realtime-safe, not thread-safe.
- */
- void append(RunContext& context, Event* first, Event* last);
-
- /** Post-process and delete all pending events */
- void process();
-
- /** Return true iff any events are pending */
- bool pending() const;
-
- /** Set the latest event time that should be post-processed */
- void set_end_time(FrameTime time) { _max_time = time; }
-
-private:
- Engine& _engine;
- std::atomic<Event*> _head;
- std::atomic<Event*> _tail;
- std::atomic<FrameTime> _max_time;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_POSTPROCESSOR_HPP
diff --git a/src/server/PreProcessContext.hpp b/src/server/PreProcessContext.hpp
deleted file mode 100644
index 1b57c013..00000000
--- a/src/server/PreProcessContext.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_PREPROCESSCONTEXT_HPP
-#define INGEN_ENGINE_PREPROCESSCONTEXT_HPP
-
-#include <unordered_set>
-
-#include "GraphImpl.hpp"
-
-namespace Raul { class Maid; }
-
-namespace Ingen {
-namespace Server {
-
-/** Event pre-processing context.
- *
- * \ingroup engine
- */
-class PreProcessContext
-{
-public:
- typedef std::unordered_set<GraphImpl*> DirtyGraphs;
-
- /** Return true iff an atomic bundle is currently being pre-processed. */
- bool in_bundle() const { return _in_bundle; }
-
- /** Set/unset atomic bundle flag. */
- void set_in_bundle(bool b) { _in_bundle = b; }
-
- /** Return true iff graph should be compiled now (after a change).
- *
- * This may return false when an atomic bundle is deferring compilation, in
- * which case the graph is flagged as dirty for later compilation.
- */
- bool must_compile(GraphImpl& graph) {
- if (!graph.enabled()) {
- return false;
- } else if (_in_bundle) {
- _dirty_graphs.insert(&graph);
- return false;
- } else {
- return true;
- }
- }
-
- /** Compile graph and return the result if necessary.
- *
- * This may return null when an atomic bundle is deferring compilation, in
- * which case the graph is flagged as dirty for later compilation.
- */
- MPtr<CompiledGraph> maybe_compile(Raul::Maid& maid, GraphImpl& graph) {
- if (must_compile(graph)) {
- return compile(maid, graph);
- }
- return MPtr<CompiledGraph>();
- }
-
- /** Return all graphs that require compilation after an atomic bundle. */
- const DirtyGraphs& dirty_graphs() const { return _dirty_graphs; }
- DirtyGraphs& dirty_graphs() { return _dirty_graphs; }
-
-private:
- DirtyGraphs _dirty_graphs;
- bool _in_bundle = false;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_PREPROCESSCONTEXT_HPP
diff --git a/src/server/PreProcessor.cpp b/src/server/PreProcessor.cpp
deleted file mode 100644
index f674284e..00000000
--- a/src/server/PreProcessor.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <stdexcept>
-
-#include "ingen/AtomSink.hpp"
-#include "ingen/AtomWriter.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/World.hpp"
-
-#include "Engine.hpp"
-#include "Event.hpp"
-#include "PostProcessor.hpp"
-#include "PreProcessContext.hpp"
-#include "PreProcessor.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-#include "UndoStack.hpp"
-
-namespace Ingen {
-namespace Server {
-
-PreProcessor::PreProcessor(Engine& engine)
- : _engine(engine)
- , _sem(0)
- , _head(nullptr)
- , _tail(nullptr)
- , _block_state(BlockState::UNBLOCKED)
- , _exit_flag(false)
- , _thread(&PreProcessor::run, this)
-{}
-
-PreProcessor::~PreProcessor()
-{
- if (_thread.joinable()) {
- _exit_flag = true;
- _sem.post();
- _thread.join();
- }
-}
-
-void
-PreProcessor::event(Event* const ev, Event::Mode mode)
-{
- // TODO: Probably possible to make this lock-free with CAS
- ThreadManager::assert_not_thread(THREAD_IS_REAL_TIME);
- std::lock_guard<std::mutex> lock(_mutex);
-
- assert(!ev->is_prepared());
- assert(!ev->next());
- ev->set_mode(mode);
-
- /* Note that tail is only used here, not in process(). The head must be
- checked first here, since if it is NULL the tail pointer is junk. */
- Event* const head = _head.load();
- if (!head) {
- _head = ev;
- _tail = ev;
- } else {
- _tail.load()->next(ev);
- _tail = ev;
- }
-
- _sem.post();
-}
-
-unsigned
-PreProcessor::process(RunContext& context, PostProcessor& dest, size_t limit)
-{
- Event* const head = _head.load();
- size_t n_processed = 0;
- Event* ev = head;
- Event* last = ev;
- while (ev && ev->is_prepared()) {
- switch (_block_state.load()) {
- case BlockState::UNBLOCKED:
- break;
- case BlockState::PRE_BLOCKED:
- if (ev->get_execution() == Event::Execution::BLOCK) {
- _block_state = BlockState::BLOCKED;
- } else if (ev->get_execution() == Event::Execution::ATOMIC) {
- _block_state = BlockState::PROCESSING;
- }
- break;
- case BlockState::BLOCKED:
- break;
- case BlockState::PRE_UNBLOCKED:
- assert(ev->get_execution() == Event::Execution::BLOCK);
- if (ev->get_execution() == Event::Execution::BLOCK) {
- _block_state = BlockState::PROCESSING;
- }
- break;
- case BlockState::PROCESSING:
- if (ev->get_execution() == Event::Execution::UNBLOCK) {
- _block_state = BlockState::UNBLOCKED;
- }
- }
-
- if (_block_state == BlockState::BLOCKED) {
- break; // Waiting for PRE_UNBLOCKED
- } else if (ev->time() < context.start()) {
- ev->set_time(context.start()); // Too late, nudge to context start
- } else if (_block_state != BlockState::PROCESSING &&
- ev->time() >= context.end()) {
- break; // Event is for a future cycle
- }
-
- // Execute event
- ev->execute(context);
- ++n_processed;
-
- // Unblock pre-processing if this is a non-bundled atomic event
- if (ev->get_execution() == Event::Execution::ATOMIC) {
- assert(_block_state.load() == BlockState::PROCESSING);
- _block_state = BlockState::UNBLOCKED;
- }
-
- // Move to next event
- last = ev;
- ev = ev->next();
-
- if (_block_state != BlockState::PROCESSING &&
- limit && n_processed >= limit) {
- break;
- }
- }
-
- if (n_processed > 0) {
-#ifndef NDEBUG
- Engine& engine = context.engine();
- if (engine.world()->conf().option("trace").get<int32_t>()) {
- const uint64_t start = engine.cycle_start_time(context);
- const uint64_t end = engine.current_time();
- fprintf(stderr, "Processed %zu events in %u us\n",
- n_processed, (unsigned)(end - start));
- }
-#endif
-
- Event* next = (Event*)last->next();
- last->next(nullptr);
- dest.append(context, head, last);
-
- // Since _head was not NULL, we know it hasn't been changed since
- _head = next;
-
- /* If next is NULL, then _tail may now be invalid. However, it would cause
- a race to reset _tail here. Instead, append() checks only _head for
- emptiness, and resets the tail appropriately. */
- }
-
- return n_processed;
-}
-
-void
-PreProcessor::run()
-{
- PreProcessContext ctx;
-
- UndoStack& undo_stack = *_engine.undo_stack();
- UndoStack& redo_stack = *_engine.redo_stack();
- AtomWriter undo_writer(
- _engine.world()->uri_map(), _engine.world()->uris(), undo_stack);
- AtomWriter redo_writer(
- _engine.world()->uri_map(), _engine.world()->uris(), redo_stack);
-
- ThreadManager::set_flag(THREAD_PRE_PROCESS);
-
- Event* back = nullptr;
- while (!_exit_flag) {
- if (!_sem.timed_wait(std::chrono::seconds(1))) {
- continue;
- }
-
- if (!back) {
- // Ran off end, find new unprepared back
- back = _head;
- while (back && back->is_prepared()) {
- back = back->next();
- }
- }
-
- Event* const ev = back;
- if (!ev) {
- continue;
- }
-
- // Set block state before enqueueing event
- switch (ev->get_execution()) {
- case Event::Execution::NORMAL:
- break;
- case Event::Execution::ATOMIC:
- assert(_block_state == BlockState::UNBLOCKED);
- _block_state = BlockState::PRE_BLOCKED;
- break;
- case Event::Execution::BLOCK:
- assert(_block_state == BlockState::UNBLOCKED);
- _block_state = BlockState::PRE_BLOCKED;
- break;
- case Event::Execution::UNBLOCK:
- wait_for_block_state(BlockState::BLOCKED);
- _block_state = BlockState::PRE_UNBLOCKED;
- }
-
- // Prepare event, allowing it to be processed
- assert(!ev->is_prepared());
- if (ev->pre_process(ctx)) {
- switch (ev->get_mode()) {
- case Event::Mode::NORMAL:
- case Event::Mode::REDO:
- undo_stack.start_entry();
- ev->undo(undo_writer);
- undo_stack.finish_entry();
- // undo_stack.save(stderr);
- break;
- case Event::Mode::UNDO:
- redo_stack.start_entry();
- ev->undo(redo_writer);
- redo_stack.finish_entry();
- // redo_stack.save(stderr, "redo");
- break;
- }
- }
- assert(ev->is_prepared());
-
- // Wait for process() if necessary
- if (ev->get_execution() == Event::Execution::ATOMIC) {
- wait_for_block_state(BlockState::UNBLOCKED);
- }
-
- back = (Event*)ev->next();
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/PreProcessor.hpp b/src/server/PreProcessor.hpp
deleted file mode 100644
index eb72328e..00000000
--- a/src/server/PreProcessor.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_PREPROCESSOR_HPP
-#define INGEN_ENGINE_PREPROCESSOR_HPP
-
-#include <atomic>
-#include <thread>
-#include <mutex>
-
-#include "raul/Semaphore.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-class Event;
-class PostProcessor;
-class RunContext;
-
-class PreProcessor
-{
-public:
- explicit PreProcessor(Engine& engine);
-
- ~PreProcessor();
-
- /** Return true iff no events are enqueued. */
- inline bool empty() const { return !_head.load(); }
-
- /** Enqueue an event.
- * This is safe to call from any non-realtime thread (it locks).
- */
- void event(Event* ev, Event::Mode mode);
-
- /** Process events for a cycle.
- * @return The number of events processed.
- */
- unsigned process(RunContext& context,
- PostProcessor& dest,
- size_t limit = 0);
-
-protected:
- void run();
-
-private:
- enum class BlockState {
- UNBLOCKED, ///< Normal, unblocked execution
- PRE_BLOCKED, ///< Preprocess thread has enqueued blocking event
- BLOCKED, ///< Process thread has reached blocking event
- PRE_UNBLOCKED, ///< Preprocess thread has enqueued unblocking event
- PROCESSING ///< Process thread is executing all events in-between
- };
-
- void wait_for_block_state(const BlockState state) {
- while (_block_state != state) {
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
-
- Engine& _engine;
- std::mutex _mutex;
- Raul::Semaphore _sem;
- std::atomic<Event*> _head;
- std::atomic<Event*> _tail;
- std::atomic<BlockState> _block_state;
- bool _exit_flag;
- std::thread _thread;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_PREPROCESSOR_HPP
diff --git a/src/server/RunContext.cpp b/src/server/RunContext.cpp
deleted file mode 100644
index 3ab9d15c..00000000
--- a/src/server/RunContext.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Forge.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-
-#include "Broadcaster.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "PortImpl.hpp"
-#include "RunContext.hpp"
-#include "Task.hpp"
-
-namespace Ingen {
-namespace Server {
-
-struct Notification
-{
- inline Notification(PortImpl* p = nullptr,
- FrameTime f = 0,
- LV2_URID k = 0,
- uint32_t s = 0,
- LV2_URID t = 0)
- : port(p), time(f), key(k), size(s), type(t)
- {}
-
- PortImpl* port;
- FrameTime time;
- LV2_URID key;
- uint32_t size;
- LV2_URID type;
-};
-
-RunContext::RunContext(Engine& engine,
- Raul::RingBuffer* event_sink,
- unsigned id,
- bool threaded)
- : _engine(engine)
- , _event_sink(event_sink)
- , _task(nullptr)
- , _thread(threaded ? new std::thread(&RunContext::run, this) : nullptr)
- , _id(id)
- , _start(0)
- , _end(0)
- , _offset(0)
- , _nframes(0)
- , _realtime(true)
-{}
-
-RunContext::RunContext(const RunContext& copy)
- : _engine(copy._engine)
- , _event_sink(copy._event_sink)
- , _task(nullptr)
- , _thread(nullptr)
- , _id(copy._id)
- , _start(copy._start)
- , _end(copy._end)
- , _offset(copy._offset)
- , _nframes(copy._nframes)
- , _realtime(copy._realtime)
-{}
-
-bool
-RunContext::must_notify(const PortImpl* port) const
-{
- return (port->is_monitored() || _engine.broadcaster()->must_broadcast());
-}
-
-bool
-RunContext::notify(LV2_URID key,
- FrameTime time,
- PortImpl* port,
- uint32_t size,
- LV2_URID type,
- const void* body)
-{
- const Notification n(port, time, key, size, type);
- if (_event_sink->write_space() < sizeof(n) + size) {
- return false;
- }
- if (_event_sink->write(sizeof(n), &n) != sizeof(n)) {
- _engine.log().rt_error("Error writing header to notification ring\n");
- } else if (_event_sink->write(size, body) != size) {
- _engine.log().rt_error("Error writing body to notification ring\n");
- } else {
- return true;
- }
- return false;
-}
-
-void
-RunContext::emit_notifications(FrameTime end)
-{
- const URIs& uris = _engine.buffer_factory()->uris();
- const uint32_t read_space = _event_sink->read_space();
- Notification note;
- for (uint32_t i = 0; i < read_space; i += sizeof(note)) {
- if (_event_sink->peek(sizeof(note), &note) != sizeof(note) ||
- note.time >= end) {
- return;
- }
- if (_event_sink->read(sizeof(note), &note) == sizeof(note)) {
- Atom value = _engine.world()->forge().alloc(
- note.size, note.type, nullptr);
- if (_event_sink->read(note.size, value.get_body()) == note.size) {
- i += note.size;
- const char* key = _engine.world()->uri_map().unmap_uri(note.key);
- if (key) {
- _engine.broadcaster()->set_property(
- note.port->uri(), URI(key), value);
- if (note.port->is_input() &&
- (note.key == uris.ingen_value ||
- note.key == uris.midi_binding)) {
- // FIXME: not thread safe
- note.port->set_property(URI(key), value);
- }
- } else {
- _engine.log().rt_error("Error unmapping notification key URI\n");
- }
- } else {
- _engine.log().rt_error("Error reading body from notification ring\n");
- }
- } else {
- _engine.log().rt_error("Error reading header from notification ring\n");
- }
- }
-}
-
-void
-RunContext::claim_task(Task* task)
-{
- if ((_task = task)) {
- _engine.signal_tasks_available();
- }
-}
-
-Task*
-RunContext::steal_task() const
-{
- return _engine.steal_task(_id + 1);
-}
-
-void
-RunContext::set_priority(int priority)
-{
- if (_thread) {
- pthread_t pthread = _thread->native_handle();
- const int policy = (priority > 0) ? SCHED_FIFO : SCHED_OTHER;
- sched_param sp;
- sp.sched_priority = (priority > 0) ? priority : 0;
- if (pthread_setschedparam(pthread, policy, &sp)) {
- _engine.log().error(
- fmt("Failed to set real-time priority of run thread (%s)\n")
- % strerror(errno));
- }
- }
-}
-
-void
-RunContext::join()
-{
- if (_thread) {
- if (_thread->joinable()) {
- _thread->join();
- }
- delete _thread;
- }
-}
-
-void
-RunContext::run()
-{
- while (_engine.wait_for_tasks()) {
- for (Task* t; (t = _engine.steal_task(0));) {
- t->run(*this);
- }
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/RunContext.hpp b/src/server/RunContext.hpp
deleted file mode 100644
index bb64a250..00000000
--- a/src/server/RunContext.hpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_RUNCONTEXT_HPP
-#define INGEN_ENGINE_RUNCONTEXT_HPP
-
-#include <cstdint>
-#include <thread>
-
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "raul/RingBuffer.hpp"
-
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-class PortImpl;
-class Task;
-
-/** Graph execution context.
- *
- * This is used to pass whatever information a Node might need to process; such
- * as the current time, a sink for generated events, etc.
- *
- * Note the logical distinction between nframes (jack relative) and start/end
- * (timeline relative). If transport speed != 1.0, then end-start != nframes
- * (though currently this is never the case, it may be if ingen incorporates
- * tempo and varispeed).
- *
- * \ingroup engine
- */
-class RunContext
-{
-public:
- /** Create a new run context.
- *
- * @param engine The engine this context is running within.
- * @param event_sink Sink for notification events (peaks etc)
- * @param id The ID of this context.
- * @param threaded If true, then this context is a worker which will launch
- * a thread and execute tasks as they become available.
- */
- RunContext(Engine& engine,
- Raul::RingBuffer* event_sink,
- unsigned id,
- bool threaded);
-
- /** Create a sub-context of `parent`.
- *
- * This is used to subdivide process cycles, the sub-context is
- * lightweight and only serves to pass different time attributes.
- */
- RunContext(const RunContext& copy);
-
- /** Return true iff the given port should broadcast its value.
- *
- * Whether or not broadcasting is actually done is a per-client property,
- * this is for use in the audio thread to quickly determine if the
- * necessary calculations need to be done at all.
- */
- bool must_notify(const PortImpl* port) const;
-
- /** Send a notification from this run context.
- * @return false on failure (ring is full)
- */
- bool notify(LV2_URID key = 0,
- FrameTime time = 0,
- PortImpl* port = nullptr,
- uint32_t size = 0,
- LV2_URID type = 0,
- const void* body = nullptr);
-
- /** Emit pending notifications in some other non-realtime thread. */
- void emit_notifications(FrameTime end);
-
- /** Return true iff any notifications are pending. */
- bool pending_notifications() const { return _event_sink->read_space(); }
-
- /** Return the duration of this cycle in microseconds.
- *
- * This is the cycle length in frames (nframes) converted to microseconds,
- * that is, the amount of real time that this cycle's audio represents.
- * Note that this is unrelated to the amount of time available to execute a
- * cycle (other than the fact that it must be processed in significantly
- * less time to avoid a dropout when running in real time).
- */
- inline uint64_t duration() const {
- return (uint64_t)_nframes * 1e6 / _rate;
- }
-
- inline void locate(FrameTime s, SampleCount nframes) {
- _start = s;
- _end = s + nframes;
- _nframes = nframes;
- }
-
- inline void slice(SampleCount offset, SampleCount nframes) {
- _offset = offset;
- _nframes = nframes;
- }
-
- /** Claim a parallel task, and signal others that work is available. */
- void claim_task(Task* task);
-
- /** Steal a task from some other context if possible. */
- Task* steal_task() const;
-
- void set_priority(int priority);
- void set_rate(SampleCount rate) { _rate = rate; }
-
- void join();
-
- inline Engine& engine() const { return _engine; }
- inline Task* task() const { return _task; }
- inline unsigned id() const { return _id; }
- inline FrameTime start() const { return _start; }
- inline FrameTime time() const { return _start + _offset; }
- inline FrameTime end() const { return _end; }
- inline SampleCount offset() const { return _offset; }
- inline SampleCount nframes() const { return _nframes; }
- inline SampleCount rate() const { return _rate; }
- inline bool realtime() const { return _realtime; }
-
-protected:
- const RunContext& operator=(const RunContext& copy) = delete;
-
- void run();
-
- Engine& _engine; ///< Engine we're running in
- Raul::RingBuffer* _event_sink; ///< Port updates from process context
- Task* _task; ///< Currently executing task
- std::thread* _thread; ///< Thread (NULL for main run context)
- unsigned _id; ///< Context ID
-
- FrameTime _start; ///< Start frame of this cycle, timeline relative
- FrameTime _end; ///< End frame of this cycle, timeline relative
- SampleCount _offset; ///< Offset into data buffers
- SampleCount _nframes; ///< Number of frames past offset to process
- SampleCount _rate; ///< Sample rate in Hz
- bool _realtime; ///< True iff context is hard realtime
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_RUNCONTEXT_HPP
diff --git a/src/server/SocketListener.cpp b/src/server/SocketListener.cpp
deleted file mode 100644
index a6faa863..00000000
--- a/src/server/SocketListener.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <poll.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <cerrno>
-#include <sstream>
-#include <string>
-#include <thread>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/World.hpp"
-#include "raul/Socket.hpp"
-
-#include "../server/Engine.hpp"
-#include "../server/EventWriter.hpp"
-
-#include "SocketListener.hpp"
-#include "SocketServer.hpp"
-
-namespace Ingen {
-namespace Server {
-
-static constexpr const char* const unix_scheme = "unix://";
-
-static std::string
-get_link_target(const char* link_path)
-{
- // Stat the link to get the required size for the target path
- struct stat link_stat;
- if (lstat(link_path, &link_stat)) {
- return std::string();
- }
-
- // Allocate buffer and read link target
- char* target = (char*)calloc(1, link_stat.st_size + 1);
- if (readlink(link_path, target, link_stat.st_size) != -1) {
- const std::string result(target);
- free(target);
- return result;
- }
-
- return std::string();
-}
-
-static void ingen_listen(Engine* engine,
- Raul::Socket* unix_sock,
- Raul::Socket* net_sock);
-
-
-SocketListener::SocketListener(Engine& engine)
- : unix_sock(Raul::Socket::Type::UNIX)
- , net_sock(Raul::Socket::Type::TCP)
- , thread(new std::thread(ingen_listen, &engine, &unix_sock, &net_sock))
-{}
-
-SocketListener::~SocketListener() {
- unix_sock.shutdown();
- net_sock.shutdown();
- thread->join();
- unlink(unix_sock.uri().substr(strlen(unix_scheme)).c_str());
-}
-
-static void
-ingen_listen(Engine* engine, Raul::Socket* unix_sock, Raul::Socket* net_sock)
-{
- Ingen::World* world = engine->world();
-
- const std::string link_path(world->conf().option("socket").ptr<char>());
- const std::string unix_path(link_path + "." + std::to_string(getpid()));
-
- // Bind UNIX socket and create PID-less symbolic link
- const URI unix_uri(unix_scheme + unix_path);
- bool make_link = true;
- if (!unix_sock->bind(unix_uri) || !unix_sock->listen()) {
- world->log().error("Failed to create UNIX socket\n");
- unix_sock->close();
- make_link = false;
- } else {
- const std::string old_path = get_link_target(link_path.c_str());
- if (!old_path.empty()) {
- const std::string suffix = old_path.substr(old_path.find_last_of(".") + 1);
- const pid_t pid = std::stoi(suffix);
- if (!kill(pid, 0)) {
- make_link = false;
- world->log().warn(fmt("Another Ingen instance is running at %1% => %2%\n")
- % link_path % old_path);
- } else {
- world->log().warn(fmt("Replacing old link %1% => %2%\n")
- % link_path % old_path);
- unlink(link_path.c_str());
- }
- }
-
- if (make_link) {
- if (!symlink(unix_path.c_str(), link_path.c_str())) {
- world->log().info(fmt("Listening on %1%\n") %
- (unix_scheme + link_path));
- } else {
- world->log().error(fmt("Failed to link %1% => %2% (%3%)\n")
- % link_path % unix_path % strerror(errno));
- }
- } else {
- world->log().info(fmt("Listening on %1%\n") % unix_uri);
- }
- }
-
- // Bind TCP socket
- const int port = world->conf().option("engine-port").get<int32_t>();
- std::ostringstream ss;
- ss << "tcp://*:" << port;
- if (!net_sock->bind(URI(ss.str())) || !net_sock->listen()) {
- world->log().error("Failed to create TCP socket\n");
- net_sock->close();
- } else {
- world->log().info(fmt("Listening on TCP port %1%\n") % port);
- }
-
- if (unix_sock->fd() == -1 && net_sock->fd() == -1) {
- return; // No sockets to listen to, exit thread
- }
-
- struct pollfd pfds[2];
- int nfds = 0;
- if (unix_sock->fd() != -1) {
- pfds[nfds].fd = unix_sock->fd();
- pfds[nfds].events = POLLIN;
- pfds[nfds].revents = 0;
- ++nfds;
- }
- if (net_sock->fd() != -1) {
- pfds[nfds].fd = net_sock->fd();
- pfds[nfds].events = POLLIN;
- pfds[nfds].revents = 0;
- ++nfds;
- }
-
- while (true) {
- // Wait for input to arrive at a socket
- const int ret = poll(pfds, nfds, -1);
- if (ret == -1) {
- world->log().error(fmt("Poll error: %1%\n") % strerror(errno));
- break;
- } else if (ret == 0) {
- world->log().warn("Poll returned with no data\n");
- continue;
- } else if ((pfds[0].revents & POLLHUP) || pfds[1].revents & POLLHUP) {
- break;
- }
-
- if (pfds[0].revents & POLLIN) {
- SPtr<Raul::Socket> conn = unix_sock->accept();
- if (conn) {
- new SocketServer(*world, *engine, conn);
- }
- }
-
- if (pfds[1].revents & POLLIN) {
- SPtr<Raul::Socket> conn = net_sock->accept();
- if (conn) {
- new SocketServer(*world, *engine, conn);
- }
- }
- }
-
- if (make_link) {
- unlink(link_path.c_str());
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/SocketListener.hpp b/src/server/SocketListener.hpp
deleted file mode 100644
index e74629ad..00000000
--- a/src/server/SocketListener.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <memory>
-#include <thread>
-
-#include "raul/Socket.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-
-/** Listens on main sockets and spawns socket servers for new connections. */
-class SocketListener
-{
-public:
- SocketListener(Engine& engine);
- ~SocketListener();
-
-private:
- Raul::Socket unix_sock;
- Raul::Socket net_sock;
- std::unique_ptr<std::thread> thread;
-};
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/SocketServer.hpp b/src/server/SocketServer.hpp
deleted file mode 100644
index dbeb76ea..00000000
--- a/src/server/SocketServer.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- 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_SERVER_SOCKET_SERVER_HPP
-#define INGEN_SERVER_SOCKET_SERVER_HPP
-
-#include "ingen/SocketReader.hpp"
-#include "ingen/SocketWriter.hpp"
-#include "ingen/StreamWriter.hpp"
-#include "ingen/Tee.hpp"
-#include "raul/Socket.hpp"
-
-#include "EventWriter.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/** The server side of an Ingen socket connection. */
-class SocketServer
-{
-public:
- SocketServer(World& world,
- Server::Engine& engine,
- SPtr<Raul::Socket> sock)
- : _engine(engine)
- , _sink(world.conf().option("dump").get<int32_t>()
- ? SPtr<Interface>(
- new Tee({SPtr<Interface>(new EventWriter(engine)),
- SPtr<Interface>(new StreamWriter(world.uri_map(),
- world.uris(),
- URI("ingen:/engine"),
- stderr,
- ColorContext::Color::CYAN))}))
- : SPtr<Interface>(new EventWriter(engine)))
- , _reader(new SocketReader(world, *_sink.get(), sock))
- , _writer(new SocketWriter(world.uri_map(),
- world.uris(),
- URI(sock->uri()),
- sock))
- {
- _sink->set_respondee(_writer);
- engine.register_client(_writer);
- }
-
- ~SocketServer() {
- if (_writer) {
- _engine.unregister_client(_writer);
- }
- }
-
-protected:
- void on_hangup() {
- _engine.unregister_client(_writer);
- _writer.reset();
- }
-
-private:
- Server::Engine& _engine;
- SPtr<Interface> _sink;
- SPtr<SocketReader> _reader;
- SPtr<SocketWriter> _writer;
-};
-
-} // namespace Ingen
-} // namespace Socket
-
-#endif // INGEN_SERVER_SOCKET_SERVER_HPP
diff --git a/src/server/Task.cpp b/src/server/Task.cpp
deleted file mode 100644
index d2cb2683..00000000
--- a/src/server/Task.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2015-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/>.
-*/
-
-#include "BlockImpl.hpp"
-#include "Task.hpp"
-
-namespace Ingen {
-namespace Server {
-
-void
-Task::run(RunContext& context)
-{
- switch (_mode) {
- case Mode::SINGLE:
- // fprintf(stderr, "%u run %s\n", context.id(), _block->path().c_str());
- _block->process(context);
- break;
- case Mode::SEQUENTIAL:
- for (const auto& task : _children) {
- task->run(context);
- }
- break;
- case Mode::PARALLEL:
- // Initialize (not) done state of sub-tasks
- for (const auto& task : _children) {
- task->set_done(false);
- }
-
- // Grab the first sub-task
- _next = 0;
- _done_end = 0;
- Task* t = steal(context);
-
- // Allow other threads to steal sub-tasks
- context.claim_task(this);
-
- // Run available tasks until this task is finished
- for (; t; t = get_task(context)) {
- t->run(context);
- }
- context.claim_task(nullptr);
- break;
- }
-
- set_done(true);
-}
-
-Task*
-Task::steal(RunContext& context)
-{
- if (_mode == Mode::PARALLEL) {
- const unsigned i = _next++;
- if (i < _children.size()) {
- return _children[i].get();
- }
- }
-
- return nullptr;
-}
-
-Task*
-Task::get_task(RunContext& context)
-{
- // Attempt to "steal" a task from ourselves
- Task* t = steal(context);
- if (t) {
- return t;
- }
-
- while (true) {
- // Push done end index as forward as possible
- while (_done_end < _children.size() && _children[_done_end]->done()) {
- ++_done_end;
- }
-
- if (_done_end >= _children.size()) {
- return nullptr; // All child tasks are finished
- }
-
- // All child tasks claimed, but some are unfinished, steal a task
- if ((t = context.steal_task())) {
- return t;
- }
-
- /* All child tasks are claimed, and we failed to steal any tasks. Spin
- to prevent blocking, though it would probably be wiser to wait for a
- signal in non-main threads, and maybe even in the main thread
- depending on your real-time safe philosophy... more experimentation
- here is needed. */
- }
-}
-
-std::unique_ptr<Task>
-Task::simplify(std::unique_ptr<Task>&& task)
-{
- if (task->mode() == Mode::SINGLE) {
- return std::move(task);
- }
-
- std::unique_ptr<Task> ret = std::unique_ptr<Task>(new Task(task->mode()));
- for (auto&& c : task->_children) {
- auto child = simplify(std::move(c));
- if (!child->empty()) {
- if (child->mode() == task->mode()) {
- // Merge child into parent
- for (auto&& grandchild : child->_children) {
- ret->append(std::move(grandchild));
- }
- } else {
- // Add child task
- ret->append(std::move(child));
- }
- }
- }
-
- if (ret->_children.size() == 1) {
- return std::move(ret->_children.front());
- }
-
- return ret;
-}
-
-void
-Task::dump(std::function<void (const std::string&)> sink, unsigned indent, bool first) const
-{
- if (!first) {
- sink("\n");
- for (unsigned i = 0; i < indent; ++i) {
- sink(" ");
- }
- }
-
- if (_mode == Mode::SINGLE) {
- sink(_block->path());
- } else {
- sink(((_mode == Mode::SEQUENTIAL) ? "(seq " : "(par "));
- for (size_t i = 0; i < _children.size(); ++i) {
- _children[i]->dump(sink, indent + 5, i == 0);
- }
- sink(")");
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/Task.hpp b/src/server/Task.hpp
deleted file mode 100644
index 2cdad71b..00000000
--- a/src/server/Task.hpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- 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_ENGINE_TASK_HPP
-#define INGEN_ENGINE_TASK_HPP
-
-#include <atomic>
-#include <cassert>
-#include <deque>
-#include <functional>
-#include <memory>
-#include <ostream>
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class RunContext;
-
-class Task {
-public:
- enum class Mode {
- SINGLE, ///< Single block to run
- SEQUENTIAL, ///< Elements must be run sequentially in order
- PARALLEL ///< Elements may be run in any order in parallel
- };
-
- Task(Mode mode, BlockImpl* block = nullptr)
- : _block(block)
- , _mode(mode)
- , _done_end(0)
- , _next(0)
- , _done(false)
- {
- assert(!(mode == Mode::SINGLE && !block));
- }
-
- Task(Task&& task)
- : _children(std::move(task._children))
- , _block(task._block)
- , _mode(task._mode)
- , _done_end(task._done_end)
- , _next(task._next.load())
- , _done(task._done.load())
- {}
-
- Task& operator=(Task&& task)
- {
- _children = std::move(task._children);
- _block = task._block;
- _mode = task._mode;
- _done_end = task._done_end;
- _next = task._next.load();
- _done = task._done.load();
- return *this;
- }
-
- /** Run task in the given context. */
- void run(RunContext& context);
-
- /** Pretty print task to the given stream (recursively). */
- void dump(std::function<void (const std::string&)> sink, unsigned indent, bool first) const;
-
- /** Return true iff this is an empty task. */
- bool empty() const { return _mode != Mode::SINGLE && _children.empty(); }
-
- /** Simplify task expression. */
- static std::unique_ptr<Task> simplify(std::unique_ptr<Task>&& task);
-
- /** Steal a child task from this task (succeeds for PARALLEL only). */
- Task* steal(RunContext& context);
-
- /** Prepend a child to this task. */
- void push_front(Task&& task) {
- _children.emplace_front(std::unique_ptr<Task>(new Task(std::move(task))));
- }
-
- Mode mode() const { return _mode; }
- BlockImpl* block() const { return _block; }
- bool done() const { return _done; }
-
- void set_done(bool done) { _done = done; }
-
-private:
- typedef std::deque<std::unique_ptr<Task>> Children;
-
- Task(const Task&) = delete;
- Task& operator=(const Task&) = delete;
-
- Task* get_task(RunContext& context);
-
- void append(std::unique_ptr<Task>&& t) {
- _children.emplace_back(std::move(t));
- }
-
- Children _children; ///< Vector of child tasks
- BlockImpl* _block; ///< Used for SINGLE only
- Mode _mode; ///< Execution mode
- unsigned _done_end; ///< Index of rightmost done sub-task
- std::atomic<unsigned> _next; ///< Index of next sub-task
- std::atomic<bool> _done; ///< Completion phase
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_TASK_HPP
diff --git a/src/server/ThreadManager.hpp b/src/server/ThreadManager.hpp
deleted file mode 100644
index 3bcedf30..00000000
--- a/src/server/ThreadManager.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_THREADMANAGER_HPP
-#define INGEN_ENGINE_THREADMANAGER_HPP
-
-#include <cassert>
-
-#include "ingen/ingen.h"
-
-#include "util.hpp"
-
-namespace Ingen {
-namespace Server {
-
-enum ThreadFlag {
- THREAD_IS_REAL_TIME = 1,
- THREAD_PRE_PROCESS = 1 << 1,
- THREAD_PROCESS = 1 << 2,
- THREAD_MESSAGE = 1 << 3,
-};
-
-class INGEN_API ThreadManager {
-public:
- static inline void set_flag(ThreadFlag f) {
-#ifndef NDEBUG
- flags = ((unsigned)flags | f);
-#endif
- }
-
- static inline void unset_flag(ThreadFlag f) {
-#ifndef NDEBUG
- flags = ((unsigned)flags & (~f));
-#endif
- }
-
- static inline void assert_thread(ThreadFlag f) {
- assert(single_threaded || (flags & f));
- }
-
- static inline void assert_not_thread(ThreadFlag f) {
- assert(single_threaded || !(flags & f));
- }
-
- /** Set to true during initialisation so ensure_thread doesn't fail.
- * Defined in Engine.cpp
- */
- static bool single_threaded;
- static INGEN_THREAD_LOCAL unsigned flags;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_THREADMANAGER_HPP
diff --git a/src/server/UndoStack.cpp b/src/server/UndoStack.cpp
deleted file mode 100644
index dad211ad..00000000
--- a/src/server/UndoStack.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 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/>.
-*/
-
-#include <ctime>
-
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
-#include "serd/serd.h"
-#include "sratom/sratom.h"
-
-#include "UndoStack.hpp"
-
-#define NS_RDF (const uint8_t*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-
-#define USTR(s) ((const uint8_t*)(s))
-
-namespace Ingen {
-namespace Server {
-
-int
-UndoStack::start_entry()
-{
- if (_depth == 0) {
- time_t now;
- time(&now);
- _stack.push_back(Entry(now));
- }
- return ++_depth;
-}
-
-bool
-UndoStack::write(const LV2_Atom* msg, int32_t default_id)
-{
- _stack.back().push_event(msg);
- return true;
-}
-
-bool
-UndoStack::ignore_later_event(const LV2_Atom* first,
- const LV2_Atom* second) const
-{
- if (first->type != _uris.atom_Object || first->type != second->type) {
- return false;
- }
-
- const LV2_Atom_Object* f = (const LV2_Atom_Object*)first;
- const LV2_Atom_Object* s = (const LV2_Atom_Object*)second;
- if (f->body.otype == _uris.patch_Set && f->body.otype == s->body.otype) {
- const LV2_Atom* f_subject = nullptr;
- const LV2_Atom* f_property = nullptr;
- const LV2_Atom* s_subject = nullptr;
- const LV2_Atom* s_property = nullptr;
- lv2_atom_object_get(f,
- (LV2_URID)_uris.patch_subject, &f_subject,
- (LV2_URID)_uris.patch_property, &f_property,
- 0);
- lv2_atom_object_get(s,
- (LV2_URID)_uris.patch_subject, &s_subject,
- (LV2_URID)_uris.patch_property, &s_property,
- 0);
- return (lv2_atom_equals(f_subject, s_subject) &&
- lv2_atom_equals(f_property, s_property));
- }
-
- return false;
-}
-
-int
-UndoStack::finish_entry()
-{
- if (--_depth > 0) {
- return _depth;
- } else if (_stack.back().events.empty()) {
- // Disregard empty entry
- _stack.pop_back();
- } else if (_stack.size() > 1 && _stack.back().events.size() == 1) {
- // This entry and the previous one have one event, attempt to merge
- auto i = _stack.rbegin();
- ++i;
- if (i->events.size() == 1) {
- if (ignore_later_event(i->events[0], _stack.back().events[0])) {
- _stack.pop_back();
- }
- }
- }
-
- return _depth;
-}
-
-UndoStack::Entry
-UndoStack::pop()
-{
- Entry top;
- if (!_stack.empty()) {
- top = _stack.back();
- _stack.pop_back();
- }
- return top;
-}
-
-struct BlankIDs {
- BlankIDs(char c='b') : n(0), c(c) {}
-
- SerdNode get() {
- snprintf(buf, sizeof(buf), "%c%u", c, n++);
- return serd_node_from_string(SERD_BLANK, USTR(buf));
- }
-
- char buf[16];
- unsigned n;
- const char c;
-};
-
-struct ListContext {
- explicit ListContext(BlankIDs& ids, unsigned flags, const SerdNode* s, const SerdNode* p)
- : ids(ids)
- , s(*s)
- , p(*p)
- , flags(flags | SERD_LIST_O_BEGIN)
- {}
-
- SerdNode start_node(SerdWriter* writer) {
- const SerdNode node = ids.get();
- serd_writer_write_statement(writer, flags, nullptr, &s, &p, &node, nullptr, nullptr);
- return node;
- }
-
- void append(SerdWriter* writer, unsigned oflags, const SerdNode* value) {
- // s p node
- const SerdNode node = start_node(writer);
-
- // node rdf:first value
- p = serd_node_from_string(SERD_URI, NS_RDF "first");
- flags = SERD_LIST_CONT;
- serd_writer_write_statement(writer, flags|oflags, nullptr, &node, &p, value, nullptr, nullptr);
-
- end_node(writer, &node);
- }
-
- void end_node(SerdWriter* writer, const SerdNode* node) {
- // Prepare for next call: node rdf:rest ...
- s = *node;
- p = serd_node_from_string(SERD_URI, NS_RDF "rest");
- }
-
- void end(SerdWriter* writer) {
- const SerdNode nil = serd_node_from_string(SERD_URI, NS_RDF "nil");
- serd_writer_write_statement(writer, flags, nullptr, &s, &p, &nil, nullptr, nullptr);
- }
-
- BlankIDs& ids;
- SerdNode s;
- SerdNode p;
- unsigned flags;
-};
-
-void
-UndoStack::write_entry(Sratom* sratom,
- SerdWriter* writer,
- const SerdNode* const subject,
- const UndoStack::Entry& entry)
-{
- char time_str[24];
- strftime(time_str, sizeof(time_str), "%FT%T", gmtime(&entry.time));
-
- // entry rdf:type ingen:UndoEntry
- SerdNode p = serd_node_from_string(SERD_URI, USTR(INGEN_NS "time"));
- SerdNode o = serd_node_from_string(SERD_LITERAL, USTR(time_str));
- serd_writer_write_statement(writer, SERD_ANON_CONT, nullptr, subject, &p, &o, nullptr, nullptr);
-
- p = serd_node_from_string(SERD_URI, USTR(INGEN_NS "events"));
-
- BlankIDs ids('e');
- ListContext ctx(ids, SERD_ANON_CONT, subject, &p);
-
- for (const LV2_Atom* atom : entry.events) {
- const SerdNode node = ctx.start_node(writer);
-
- p = serd_node_from_string(SERD_URI, NS_RDF "first");
- ctx.flags = SERD_LIST_CONT;
- sratom_write(sratom, &_map.urid_unmap_feature()->urid_unmap, SERD_LIST_CONT,
- &node, &p,
- atom->type, atom->size, LV2_ATOM_BODY_CONST(atom));
-
- ctx.end_node(writer, &node);
- }
-
- ctx.end(writer);
-}
-
-void
-UndoStack::save(FILE* stream, const char* name)
-{
- SerdEnv* env = serd_env_new(nullptr);
- serd_env_set_prefix_from_strings(env, USTR("atom"), USTR(LV2_ATOM_PREFIX));
- serd_env_set_prefix_from_strings(env, USTR("ingen"), USTR(INGEN_NS));
- serd_env_set_prefix_from_strings(env, USTR("patch"), USTR(LV2_PATCH_PREFIX));
-
- const SerdNode base = serd_node_from_string(SERD_URI, USTR("ingen:/"));
- SerdURI base_uri;
- serd_uri_parse(base.buf, &base_uri);
-
- SerdWriter* writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
- env,
- &base_uri,
- serd_file_sink,
- stream);
-
- // Configure sratom to write directly to the writer (and thus the socket)
- Sratom* sratom = sratom_new(&_map.urid_map_feature()->urid_map);
- sratom_set_sink(sratom,
- (const char*)base.buf,
- (SerdStatementSink)serd_writer_write_statement,
- (SerdEndSink)serd_writer_end_anon,
- writer);
-
- SerdNode s = serd_node_from_string(SERD_BLANK, (const uint8_t*)name);
- SerdNode p = serd_node_from_string(SERD_URI, USTR(INGEN_NS "entries"));
-
- BlankIDs ids('u');
- ListContext ctx(ids, 0, &s, &p);
- for (const Entry& e : _stack) {
- const SerdNode entry = ids.get();
- ctx.append(writer, SERD_ANON_O_BEGIN, &entry);
- write_entry(sratom, writer, &entry, e);
- serd_writer_end_anon(writer, &entry);
- }
- ctx.end(writer);
-
- sratom_free(sratom);
- serd_writer_finish(writer);
- serd_writer_free(writer);
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/UndoStack.hpp b/src/server/UndoStack.hpp
deleted file mode 100644
index 6ce6475f..00000000
--- a/src/server/UndoStack.hpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_UNDOSTACK_HPP
-#define INGEN_ENGINE_UNDOSTACK_HPP
-
-#include <ctime>
-#include <deque>
-
-#include "ingen/AtomSink.hpp"
-#include "ingen/ingen.h"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "serd/serd.h"
-#include "sratom/sratom.h"
-
-namespace Ingen {
-
-class URIMap;
-class URIs;
-
-namespace Server {
-
-class INGEN_API UndoStack : public AtomSink {
-public:
- struct Entry {
- Entry(time_t time=0) : time(time) {}
-
- Entry(const Entry& copy)
- : time(copy.time)
- {
- for (const LV2_Atom* ev : copy.events) {
- push_event(ev);
- }
- }
-
- ~Entry() { clear(); }
-
- Entry& operator=(const Entry& rhs) {
- clear();
- time = rhs.time;
- for (const LV2_Atom* ev : rhs.events) {
- push_event(ev);
- }
- return *this;
- }
-
- void clear() {
- for (LV2_Atom* ev : events) {
- free(ev);
- }
- events.clear();
- }
-
- void push_event(const LV2_Atom* ev) {
- const uint32_t size = lv2_atom_total_size(ev);
- LV2_Atom* copy = (LV2_Atom*)malloc(size);
- memcpy(copy, ev, size);
- events.push_front(copy);
- }
-
- time_t time;
- std::deque<LV2_Atom*> events;
- };
-
- UndoStack(URIs& uris, URIMap& map) : _uris(uris), _map(map), _depth(0) {}
-
- int start_entry();
- bool write(const LV2_Atom* msg, int32_t default_id=0);
- int finish_entry();
-
- bool empty() const { return _stack.empty(); }
- Entry pop();
-
- void save(FILE* stream, const char* name="undo");
-
-private:
- bool ignore_later_event(const LV2_Atom* first,
- const LV2_Atom* second) const;
-
- void write_entry(Sratom* sratom,
- SerdWriter* writer,
- const SerdNode* subject,
- const Entry& entry);
-
- URIs& _uris;
- URIMap& _map;
- std::deque<Entry> _stack;
- int _depth;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_UNDOSTACK_HPP
diff --git a/src/server/Worker.cpp b/src/server/Worker.cpp
deleted file mode 100644
index 6f60250c..00000000
--- a/src/server/Worker.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/LV2Features.hpp"
-#include "ingen/Log.hpp"
-#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
-
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "LV2Block.hpp"
-#include "Worker.hpp"
-
-namespace Ingen {
-namespace Server {
-
-/// A message in the Worker::_requests ring
-struct MessageHeader {
- LV2Block* block; ///< Node this message is from
- uint32_t size; ///< Size of following data
- // `size' bytes of data follow here
-};
-
-static LV2_Worker_Status
-schedule(LV2_Worker_Schedule_Handle handle,
- uint32_t size,
- const void* data)
-{
- LV2Block* block = (LV2Block*)handle;
- Engine& engine = block->parent_graph()->engine();
-
- return engine.worker()->request(block, size, data);
-}
-
-static LV2_Worker_Status
-schedule_sync(LV2_Worker_Schedule_Handle handle,
- uint32_t size,
- const void* data)
-{
- LV2Block* block = (LV2Block*)handle;
- Engine& engine = block->parent_graph()->engine();
-
- return engine.sync_worker()->request(block, size, data);
-}
-
-LV2_Worker_Status
-Worker::request(LV2Block* block,
- uint32_t size,
- const void* data)
-{
- if (_synchronous) {
- return block->work(size, data);
- }
-
- Engine& engine = block->parent_graph()->engine();
- if (_requests.write_space() < sizeof(MessageHeader) + size) {
- engine.log().error("Work request ring overflow\n");
- return LV2_WORKER_ERR_NO_SPACE;
- }
-
- const MessageHeader msg = { block, size };
- if (_requests.write(sizeof(msg), &msg) != sizeof(msg)) {
- engine.log().error("Error writing header to work request ring\n");
- return LV2_WORKER_ERR_UNKNOWN;
- }
- if (_requests.write(size, data) != size) {
- engine.log().error("Error writing body to work request ring\n");
- return LV2_WORKER_ERR_UNKNOWN;
- }
-
- _sem.post();
-
- return LV2_WORKER_SUCCESS;
-}
-
-SPtr<LV2_Feature>
-Worker::Schedule::feature(World* world, Node* n)
-{
- LV2Block* block = dynamic_cast<LV2Block*>(n);
- if (!block) {
- return SPtr<LV2_Feature>();
- }
-
- LV2_Worker_Schedule* data = (LV2_Worker_Schedule*)malloc(
- sizeof(LV2_Worker_Schedule));
- data->handle = block;
- data->schedule_work = synchronous ? schedule_sync : schedule;
-
- LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature));
- f->URI = LV2_WORKER__schedule;
- f->data = data;
-
- return SPtr<LV2_Feature>(f, &free_feature);
-}
-
-Worker::Worker(Log& log, uint32_t buffer_size, bool synchronous)
- : _schedule(new Schedule(synchronous))
- , _log(log)
- , _sem(0)
- , _requests(buffer_size)
- , _responses(buffer_size)
- , _buffer((uint8_t*)malloc(buffer_size))
- , _buffer_size(buffer_size)
- , _thread(nullptr)
- , _exit_flag(false)
- , _synchronous(synchronous)
-{
- if (!synchronous) {
- _thread = new std::thread(&Worker::run, this);
- }
-}
-
-Worker::~Worker()
-{
- _exit_flag = true;
- _sem.post();
- if (_thread) {
- _thread->join();
- delete _thread;
- }
- free(_buffer);
-}
-
-void
-Worker::run()
-{
- while (_sem.wait() && !_exit_flag) {
- MessageHeader msg;
- if (_requests.read_space() > sizeof(msg)) {
- if (_requests.read(sizeof(msg), &msg) != sizeof(msg)) {
- _log.error("Error reading header from work request ring\n");
- continue;
- }
-
- if (msg.size >= _buffer_size - sizeof(msg)) {
- _log.error("Corrupt work request ring\n");
- return;
- }
-
- if (_requests.read(msg.size, _buffer) != msg.size) {
- _log.error("Error reading body from work request ring\n");
- continue;
- }
-
- msg.block->work(msg.size, _buffer);
- }
- }
-}
-
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/Worker.hpp b/src/server/Worker.hpp
deleted file mode 100644
index 0a3fdeaf..00000000
--- a/src/server/Worker.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_WORKER_HPP
-#define INGEN_ENGINE_WORKER_HPP
-
-#include <thread>
-
-#include "ingen/LV2Features.hpp"
-#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
-#include "raul/RingBuffer.hpp"
-#include "raul/Semaphore.hpp"
-
-namespace Ingen {
-
-class Log;
-
-namespace Server {
-
-class LV2Block;
-
-class Worker
-{
-public:
- Worker(Log& log, uint32_t buffer_size, bool synchronous=false);
- ~Worker();
-
- struct Schedule : public LV2Features::Feature {
- Schedule(bool sync) : synchronous(sync) {}
-
- const char* uri() const { return LV2_WORKER__schedule; }
-
- SPtr<LV2_Feature> feature(World* world, Node* n);
-
- const bool synchronous;
- };
-
- LV2_Worker_Status request(LV2Block* block,
- uint32_t size,
- const void* data);
-
- SPtr<Schedule> schedule_feature() { return _schedule; }
-
-private:
- SPtr<Schedule> _schedule;
-
- Log& _log;
- Raul::Semaphore _sem;
- Raul::RingBuffer _requests;
- Raul::RingBuffer _responses;
- uint8_t* const _buffer;
- const uint32_t _buffer_size;
- std::thread* _thread;
- bool _exit_flag;
- bool _synchronous;
-
- void run();
-};
-
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_ENGINE_WORKER_HPP
diff --git a/src/server/events.hpp b/src/server/events.hpp
deleted file mode 100644
index 5f77b431..00000000
--- a/src/server/events.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2016 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef INGEN_ENGINE_EVENTS_HPP
-#define INGEN_ENGINE_EVENTS_HPP
-
-#include "events/Connect.hpp"
-#include "events/Copy.hpp"
-#include "events/CreateBlock.hpp"
-#include "events/CreateGraph.hpp"
-#include "events/CreatePort.hpp"
-#include "events/Delete.hpp"
-#include "events/Delta.hpp"
-#include "events/Disconnect.hpp"
-#include "events/DisconnectAll.hpp"
-#include "events/Get.hpp"
-#include "events/Mark.hpp"
-#include "events/Move.hpp"
-#include "events/SetPortValue.hpp"
-#include "events/Undo.hpp"
-
-#endif // INGEN_ENGINE_EVENTS_HPP
diff --git a/src/server/events/Connect.cpp b/src/server/events/Connect.cpp
deleted file mode 100644
index 8937b327..00000000
--- a/src/server/events/Connect.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Store.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "ArcImpl.hpp"
-#include "Broadcaster.hpp"
-#include "BufferFactory.hpp"
-#include "Connect.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "PortImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "internals/BlockDelay.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Connect::Connect(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Connect& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _graph(nullptr)
- , _head(nullptr)
-{}
-
-bool
-Connect::pre_process(PreProcessContext& ctx)
-{
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- Node* tail = _engine.store()->get(_msg.tail);
- if (!tail) {
- return Event::pre_process_done(Status::NOT_FOUND, _msg.tail);
- }
-
- Node* head = _engine.store()->get(_msg.head);
- if (!head) {
- return Event::pre_process_done(Status::NOT_FOUND, _msg.head);
- }
-
- PortImpl* tail_output = dynamic_cast<PortImpl*>(tail);
- _head = dynamic_cast<InputPort*>(head);
- if (!tail_output || !_head) {
- return Event::pre_process_done(Status::BAD_REQUEST, _msg.head);
- }
-
- BlockImpl* const tail_block = tail_output->parent_block();
- BlockImpl* const head_block = _head->parent_block();
- if (!tail_block || !head_block) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND, _msg.head);
- }
-
- if (tail_block->parent() != head_block->parent()
- && tail_block != head_block->parent()
- && tail_block->parent() != head_block) {
- return Event::pre_process_done(Status::PARENT_DIFFERS, _msg.head);
- }
-
- if (!ArcImpl::can_connect(tail_output, _head)) {
- return Event::pre_process_done(Status::TYPE_MISMATCH, _msg.head);
- }
-
- if (tail_block->parent_graph() != head_block->parent_graph()) {
- // Arc to a graph port from inside the graph
- assert(tail_block->parent() == head_block || head_block->parent() == tail_block);
- if (tail_block->parent() == head_block) {
- _graph = dynamic_cast<GraphImpl*>(head_block);
- } else {
- _graph = dynamic_cast<GraphImpl*>(tail_block);
- }
- } else if (tail_block == head_block && dynamic_cast<GraphImpl*>(tail_block)) {
- // Arc from a graph input to a graph output (pass through)
- _graph = dynamic_cast<GraphImpl*>(tail_block);
- } else {
- // Normal arc between blocks with the same parent
- _graph = tail_block->parent_graph();
- }
-
- if (_graph->has_arc(tail_output, _head)) {
- return Event::pre_process_done(Status::EXISTS, _msg.head);
- }
-
- _arc = SPtr<ArcImpl>(new ArcImpl(tail_output, _head));
-
- /* Need to be careful about graph port arcs here and adding a
- block's parent as a dependant/provider, or adding a graph as its own
- provider...
- */
- if (tail_block != head_block && tail_block->parent() == head_block->parent()) {
- // Connection is between blocks inside a graph, compile graph
-
- // The tail block is now a dependency (provider) of the head block
- head_block->providers().insert(tail_block);
-
- if (!dynamic_cast<Internals::BlockDelayNode*>(tail_block)) {
- /* Arcs leaving a delay node are ignored for the purposes of
- compilation, since the output is from the previous cycle and
- does not affect execution order. Otherwise, the head block is
- now a dependant of the head block. */
- tail_block->dependants().insert(head_block);
- }
-
- if (ctx.must_compile(*_graph)) {
- if (!(_compiled_graph = compile(*_engine.maid(), *_graph))) {
- head_block->providers().erase(tail_block);
- tail_block->dependants().erase(head_block);
- return Event::pre_process_done(Status::COMPILATION_FAILED);
- }
- }
- }
-
- _graph->add_arc(_arc);
- _head->increment_num_arcs();
-
- if (!_head->is_driver_port()) {
- BufferFactory& bufs = *_engine.buffer_factory();
- _voices = bufs.maid().make_managed<PortImpl::Voices>(_head->poly());
- _head->pre_get_buffers(bufs, _voices, _head->poly());
- }
-
- tail_output->inherit_neighbour(_head, _tail_remove, _tail_add);
- _head->inherit_neighbour(tail_output, _head_remove, _head_add);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Connect::execute(RunContext& context)
-{
- if (_status == Status::SUCCESS) {
- _head->add_arc(context, *_arc.get());
- if (!_head->is_driver_port()) {
- _head->set_voices(context, std::move(_voices));
- }
- _head->connect_buffers();
- if (_compiled_graph) {
- _graph->set_compiled_graph(std::move(_compiled_graph));
- }
- }
-}
-
-void
-Connect::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->message(_msg);
- if (!_tail_remove.empty() || !_tail_add.empty()) {
- _engine.broadcaster()->delta(
- path_to_uri(_msg.tail), _tail_remove, _tail_add);
- }
- if (!_tail_remove.empty() || !_tail_add.empty()) {
- _engine.broadcaster()->delta(
- path_to_uri(_msg.tail), _tail_remove, _tail_add);
- }
- }
-}
-
-void
-Connect::undo(Interface& target)
-{
- target.disconnect(_msg.tail, _msg.head);
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Connect.hpp b/src/server/events/Connect.hpp
deleted file mode 100644
index 8a42b984..00000000
--- a/src/server/events/Connect.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- 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_EVENTS_CONNECT_HPP
-#define INGEN_EVENTS_CONNECT_HPP
-
-#include "raul/Path.hpp"
-
-#include "CompiledGraph.hpp"
-#include "Event.hpp"
-#include "PortImpl.hpp"
-#include "types.hpp"
-
-namespace Raul {
-template <typename T> class Array;
-}
-
-namespace Ingen {
-namespace Server {
-
-class ArcImpl;
-class GraphImpl;
-class InputPort;
-
-namespace Events {
-
-/** Make an Arc between two Ports.
- *
- * \ingroup engine
- */
-class Connect : public Event
-{
-public:
- Connect(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Connect& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- const Ingen::Connect _msg;
- GraphImpl* _graph;
- InputPort* _head;
- MPtr<CompiledGraph> _compiled_graph;
- SPtr<ArcImpl> _arc;
- MPtr<PortImpl::Voices> _voices;
- Properties _tail_remove;
- Properties _tail_add;
- Properties _head_remove;
- Properties _head_add;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_CONNECT_HPP
diff --git a/src/server/events/Copy.cpp b/src/server/events/Copy.cpp
deleted file mode 100644
index fc9d40f7..00000000
--- a/src/server/events/Copy.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Parser.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/Store.hpp"
-#include "raul/Path.hpp"
-
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "Engine.hpp"
-#include "EnginePort.hpp"
-#include "GraphImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "events/Copy.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Copy::Copy(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Copy& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _old_block(nullptr)
- , _parent(nullptr)
- , _block(nullptr)
-{}
-
-bool
-Copy::pre_process(PreProcessContext& ctx)
-{
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- if (uri_is_path(_msg.old_uri)) {
- // Old URI is a path within the engine
- const Raul::Path old_path = uri_to_path(_msg.old_uri);
-
- // Find the old node
- const Store::iterator i = _engine.store()->find(old_path);
- if (i == _engine.store()->end()) {
- return Event::pre_process_done(Status::NOT_FOUND, old_path);
- }
-
- // Ensure it is a block (ports are not supported for now)
- if (!(_old_block = dynamic_ptr_cast<BlockImpl>(i->second))) {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, old_path);
- }
-
- if (uri_is_path(_msg.new_uri)) {
- // Copy to path within the engine
- return engine_to_engine(ctx);
- } else if (_msg.new_uri.scheme() == "file") {
- // Copy to filesystem path (i.e. save)
- return engine_to_filesystem(ctx);
- } else {
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
- } else if (_msg.old_uri.scheme() == "file") {
- if (uri_is_path(_msg.new_uri)) {
- return filesystem_to_engine(ctx);
- } else {
- // Ingen is not your file manager
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
- }
-
- return Event::pre_process_done(Status::BAD_URI);
-}
-
-bool
-Copy::engine_to_engine(PreProcessContext& ctx)
-{
- // Only support a single source for now
- const Raul::Path new_path = uri_to_path(_msg.new_uri);
- if (!Raul::Symbol::is_valid(new_path.symbol())) {
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
-
- // Ensure the new node doesn't already exist
- if (_engine.store()->find(new_path) != _engine.store()->end()) {
- return Event::pre_process_done(Status::EXISTS, new_path);
- }
-
- // Find new parent graph
- const Raul::Path parent_path = new_path.parent();
- const Store::iterator p = _engine.store()->find(parent_path);
- if (p == _engine.store()->end()) {
- return Event::pre_process_done(Status::NOT_FOUND, parent_path);
- }
- if (!(_parent = dynamic_cast<GraphImpl*>(p->second.get()))) {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, parent_path);
- }
-
- // Create new block
- if (!(_block = dynamic_cast<BlockImpl*>(
- _old_block->duplicate(_engine, Raul::Symbol(new_path.symbol()), _parent)))) {
- return Event::pre_process_done(Status::INTERNAL_ERROR);
- }
-
- _block->activate(*_engine.buffer_factory());
-
- // Add block to the store and the graph's pre-processor only block list
- _parent->add_block(*_block);
- _engine.store()->add(_block);
-
- // Compile graph with new block added for insertion in audio thread
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *_parent);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-static bool
-ends_with(const std::string& str, const std::string& end)
-{
- if (str.length() >= end.length()) {
- return !str.compare(str.length() - end.length(), end.length(), end);
- }
- return false;
-}
-
-bool
-Copy::engine_to_filesystem(PreProcessContext& ctx)
-{
- // Ensure source is a graph
- SPtr<GraphImpl> graph = dynamic_ptr_cast<GraphImpl>(_old_block);
- if (!graph) {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _msg.old_uri);
- }
-
- if (!_engine.world()->serialiser()) {
- return Event::pre_process_done(Status::INTERNAL_ERROR);
- }
-
- std::lock_guard<std::mutex> lock(_engine.world()->rdf_mutex());
-
- if (ends_with(_msg.new_uri, ".ingen") || ends_with(_msg.new_uri, ".ingen/")) {
- _engine.world()->serialiser()->write_bundle(graph, URI(_msg.new_uri));
- } else {
- _engine.world()->serialiser()->start_to_file(graph->path(), _msg.new_uri);
- _engine.world()->serialiser()->serialise(graph);
- _engine.world()->serialiser()->finish();
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-bool
-Copy::filesystem_to_engine(PreProcessContext& ctx)
-{
- if (!_engine.world()->parser()) {
- return Event::pre_process_done(Status::INTERNAL_ERROR);
- }
-
- std::lock_guard<std::mutex> lock(_engine.world()->rdf_mutex());
-
- // Old URI is a filesystem path and new URI is a path within the engine
- const std::string src_path(_msg.old_uri.path());
- const Raul::Path dst_path = uri_to_path(_msg.new_uri);
- boost::optional<Raul::Path> dst_parent;
- boost::optional<Raul::Symbol> dst_symbol;
- if (!dst_path.is_root()) {
- dst_parent = dst_path.parent();
- dst_symbol = Raul::Symbol(dst_path.symbol());
- }
-
- _engine.world()->parser()->parse_file(
- _engine.world(), _engine.world()->interface().get(), src_path,
- dst_parent, dst_symbol);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Copy::execute(RunContext& context)
-{
- if (_block && _compiled_graph) {
- _parent->set_compiled_graph(std::move(_compiled_graph));
- }
-}
-
-void
-Copy::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->message(_msg);
- }
-}
-
-void
-Copy::undo(Interface& target)
-{
- if (uri_is_path(_msg.new_uri)) {
- target.del(_msg.new_uri);
- }
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Copy.hpp b/src/server/events/Copy.hpp
deleted file mode 100644
index 5216b56e..00000000
--- a/src/server/events/Copy.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- 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_EVENTS_COPY_HPP
-#define INGEN_EVENTS_COPY_HPP
-
-#include <list>
-
-#include "ingen/Store.hpp"
-#include "raul/Path.hpp"
-
-#include "CompiledGraph.hpp"
-#include "Event.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class GraphImpl;
-
-namespace Events {
-
-/** Copy a graph object to a new path.
- * \ingroup engine
- */
-class Copy : public Event
-{
-public:
- Copy(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Copy& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- bool engine_to_engine(PreProcessContext& ctx);
- bool engine_to_filesystem(PreProcessContext& ctx);
- bool filesystem_to_engine(PreProcessContext& ctx);
-
- const Ingen::Copy _msg;
- SPtr<BlockImpl> _old_block;
- GraphImpl* _parent;
- BlockImpl* _block;
- MPtr<CompiledGraph> _compiled_graph;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_COPY_HPP
diff --git a/src/server/events/CreateBlock.cpp b/src/server/events/CreateBlock.cpp
deleted file mode 100644
index d678bea3..00000000
--- a/src/server/events/CreateBlock.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Forge.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URIs.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "BlockFactory.hpp"
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "CreateBlock.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "LV2Block.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-CreateBlock::CreateBlock(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- Properties& properties)
- : Event(engine, client, id, timestamp)
- , _path(path)
- , _properties(properties)
- , _graph(nullptr)
- , _block(nullptr)
-{}
-
-bool
-CreateBlock::pre_process(PreProcessContext& ctx)
-{
- typedef Properties::const_iterator iterator;
-
- const Ingen::URIs& uris = _engine.world()->uris();
- const SPtr<Store> store = _engine.store();
-
- // Check sanity of target path
- if (_path.is_root()) {
- return Event::pre_process_done(Status::BAD_URI, _path);
- } else if (store->get(_path)) {
- return Event::pre_process_done(Status::EXISTS, _path);
- } else if (!(_graph = dynamic_cast<GraphImpl*>(store->get(_path.parent())))) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND, _path.parent());
- }
-
- // Map old ingen:prototype to new lv2:prototype
- auto range = _properties.equal_range(uris.ingen_prototype);
- for (auto i = range.first; i != range.second;) {
- const auto value = i->second;
- auto next = i;
- next = _properties.erase(i);
- _properties.emplace(uris.lv2_prototype, value);
- i = next;
- }
-
- // Get prototype
- iterator t = _properties.find(uris.lv2_prototype);
- if (t == _properties.end() || !uris.forge.is_uri(t->second)) {
- // Missing/invalid prototype
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
-
- const URI prototype(uris.forge.str(t->second, false));
-
- // Find polyphony
- const iterator p = _properties.find(uris.ingen_polyphonic);
- const bool polyphonic = (p != _properties.end() &&
- p->second.type() == uris.forge.Bool &&
- p->second.get<int32_t>());
-
- // Find and instantiate/duplicate prototype (plugin/existing node)
- if (uri_is_path(prototype)) {
- // Prototype is an existing block
- BlockImpl* const ancestor = dynamic_cast<BlockImpl*>(
- store->get(uri_to_path(prototype)));
- if (!ancestor) {
- return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype);
- } else if (!(_block = ancestor->duplicate(
- _engine, Raul::Symbol(_path.symbol()), _graph))) {
- return Event::pre_process_done(Status::CREATION_FAILED, _path);
- }
-
- /* Replace prototype with the ancestor's. This is less informative,
- but the client expects an actual LV2 plugin as prototype. */
- _properties.erase(uris.ingen_prototype);
- _properties.erase(uris.lv2_prototype);
- _properties.emplace(uris.lv2_prototype,
- uris.forge.make_urid(ancestor->plugin()->uri()));
- } else {
- // Prototype is a plugin
- PluginImpl* const plugin = _engine.block_factory()->plugin(prototype);
- if (!plugin) {
- return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype);
- }
-
- // Load state from directory if given in properties
- LilvState* state = nullptr;
- auto s = _properties.find(uris.state_state);
- if (s != _properties.end() && s->second.type() == uris.forge.Path) {
- state = LV2Block::load_state(
- _engine.world(), FilePath(s->second.ptr<char>()));
- }
-
- // Instantiate plugin
- if (!(_block = plugin->instantiate(*_engine.buffer_factory(),
- Raul::Symbol(_path.symbol()),
- polyphonic,
- _graph,
- _engine,
- state))) {
- return Event::pre_process_done(Status::CREATION_FAILED, _path);
- }
- }
-
- // Activate block
- _block->properties().insert(_properties.begin(), _properties.end());
- _block->activate(*_engine.buffer_factory());
-
- // Add block to the store and the graph's pre-processor only block list
- _graph->add_block(*_block);
- store->add(_block);
-
- /* Compile graph with new block added for insertion in audio thread
- TODO: Since the block is not connected at this point, a full compilation
- could be avoided and the block simply appended. */
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *_graph);
-
- _update.put_block(_block);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-CreateBlock::execute(RunContext& context)
-{
- if (_status == Status::SUCCESS && _compiled_graph) {
- _graph->set_compiled_graph(std::move(_compiled_graph));
- }
-}
-
-void
-CreateBlock::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _update.send(*_engine.broadcaster());
- }
-}
-
-void
-CreateBlock::undo(Interface& target)
-{
- target.del(_block->uri());
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/CreateBlock.hpp b/src/server/events/CreateBlock.hpp
deleted file mode 100644
index 0a29e68c..00000000
--- a/src/server/events/CreateBlock.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- 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_EVENTS_CREATEBLOCK_HPP
-#define INGEN_EVENTS_CREATEBLOCK_HPP
-
-#include "ingen/Resource.hpp"
-
-#include "ClientUpdate.hpp"
-#include "CompiledGraph.hpp"
-#include "Event.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class GraphImpl;
-
-namespace Events {
-
-/** An event to load a Block and insert it into a Graph.
- *
- * \ingroup engine
- */
-class CreateBlock : public Event
-{
-public:
- CreateBlock(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- Properties& properties);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- Raul::Path _path;
- Properties& _properties;
- ClientUpdate _update;
- GraphImpl* _graph;
- BlockImpl* _block;
- MPtr<CompiledGraph> _compiled_graph;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_CREATEBLOCK_HPP
diff --git a/src/server/events/CreateGraph.cpp b/src/server/events/CreateGraph.cpp
deleted file mode 100644
index 390fdd9a..00000000
--- a/src/server/events/CreateGraph.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Forge.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URIs.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "Broadcaster.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "events/CreateGraph.hpp"
-#include "events/CreatePort.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-CreateGraph::CreateGraph(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- const Properties& properties)
- : Event(engine, client, id, timestamp)
- , _path(path)
- , _properties(properties)
- , _graph(nullptr)
- , _parent(nullptr)
-{}
-
-CreateGraph::~CreateGraph()
-{
- for (Event* ev : _child_events) {
- delete ev;
- }
-}
-
-void
-CreateGraph::build_child_events()
-{
- const Ingen::URIs& uris = _engine.world()->uris();
-
- // Properties common to both ports
- Properties control_properties;
- control_properties.put(uris.atom_bufferType, uris.atom_Sequence);
- control_properties.put(uris.atom_supports, uris.patch_Message);
- control_properties.put(uris.lv2_designation, uris.lv2_control);
- control_properties.put(uris.lv2_portProperty, uris.lv2_connectionOptional);
- control_properties.put(uris.rdf_type, uris.atom_AtomPort);
- control_properties.put(uris.rsz_minimumSize, uris.forge.make(4096));
-
- // Add control port (message receive)
- Properties in_properties(control_properties);
- in_properties.put(uris.lv2_index, uris.forge.make(0));
- in_properties.put(uris.lv2_name, uris.forge.alloc("Control"));
- in_properties.put(uris.rdf_type, uris.lv2_InputPort);
- in_properties.put(uris.ingen_canvasX, uris.forge.make(32.0f),
- Resource::Graph::EXTERNAL);
- in_properties.put(uris.ingen_canvasY, uris.forge.make(32.0f),
- Resource::Graph::EXTERNAL);
-
- _child_events.push_back(
- new Events::CreatePort(
- _engine, _request_client, -1, _time,
- _path.child(Raul::Symbol("control")),
- in_properties));
-
- // Add notify port (message respond)
- Properties out_properties(control_properties);
- out_properties.put(uris.lv2_index, uris.forge.make(1));
- out_properties.put(uris.lv2_name, uris.forge.alloc("Notify"));
- out_properties.put(uris.rdf_type, uris.lv2_OutputPort);
- out_properties.put(uris.ingen_canvasX, uris.forge.make(128.0f),
- Resource::Graph::EXTERNAL);
- out_properties.put(uris.ingen_canvasY, uris.forge.make(32.0f),
- Resource::Graph::EXTERNAL);
-
- _child_events.push_back(
- new Events::CreatePort(_engine, _request_client, -1, _time,
- _path.child(Raul::Symbol("notify")),
- out_properties));
-}
-
-bool
-CreateGraph::pre_process(PreProcessContext& ctx)
-{
- if (_engine.store()->get(_path)) {
- return Event::pre_process_done(Status::EXISTS, _path);
- }
-
- if (!_path.is_root()) {
- const Raul::Path up(_path.parent());
- if (!(_parent = dynamic_cast<GraphImpl*>(_engine.store()->get(up)))) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND, up);
- }
- }
-
- const Ingen::URIs& uris = _engine.world()->uris();
-
- typedef Properties::const_iterator iterator;
-
- uint32_t ext_poly = 1;
- uint32_t int_poly = 1;
- iterator p = _properties.find(uris.ingen_polyphony);
- if (p != _properties.end() && p->second.type() == uris.forge.Int) {
- int_poly = p->second.get<int32_t>();
- }
-
- if (int_poly < 1 || int_poly > 128) {
- return Event::pre_process_done(Status::INVALID_POLY, _path);
- }
-
- if (!_parent || int_poly == _parent->internal_poly()) {
- ext_poly = int_poly;
- }
-
- const Raul::Symbol symbol(_path.is_root() ? "graph" : _path.symbol());
-
- // Get graph prototype
- iterator t = _properties.find(uris.lv2_prototype);
- if (t == _properties.end()) {
- t = _properties.find(uris.lv2_prototype);
- }
-
- if (t != _properties.end() &&
- uris.forge.is_uri(t->second) &&
- URI::is_valid(uris.forge.str(t->second, false)) &&
- uri_is_path(URI(uris.forge.str(t->second, false)))) {
- // Create a duplicate of an existing graph
- const URI prototype(uris.forge.str(t->second, false));
- GraphImpl* ancestor = dynamic_cast<GraphImpl*>(
- _engine.store()->get(uri_to_path(prototype)));
- if (!ancestor) {
- return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype);
- } else if (!(_graph = dynamic_cast<GraphImpl*>(
- ancestor->duplicate(_engine, symbol, _parent)))) {
- return Event::pre_process_done(Status::CREATION_FAILED, _path);
- }
- } else {
- // Create a new graph
- _graph = new GraphImpl(_engine, symbol, ext_poly, _parent,
- _engine.sample_rate(), int_poly);
- _graph->add_property(uris.rdf_type, uris.ingen_Graph.urid);
- _graph->add_property(uris.rdf_type,
- Property(uris.ingen_Block,
- Resource::Graph::EXTERNAL));
- }
-
- _graph->set_properties(_properties);
-
- if (_parent) {
- // Add graph to parent
- _parent->add_block(*_graph);
- if (_parent->enabled()) {
- _graph->enable();
- }
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *_parent);
- }
-
- _graph->activate(*_engine.buffer_factory());
-
- // Insert into store and build update to send to clients
- _engine.store()->add(_graph);
- _update.put_graph(_graph);
- for (BlockImpl& block : _graph->blocks()) {
- _engine.store()->add(&block);
- }
-
- // Build and pre-process child events to create standard ports
- build_child_events();
- for (Event* ev : _child_events) {
- ev->pre_process(ctx);
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-CreateGraph::execute(RunContext& context)
-{
- if (_graph) {
- if (_parent) {
- if (_compiled_graph) {
- _parent->set_compiled_graph(std::move(_compiled_graph));
- }
- } else {
- _engine.set_root_graph(_graph);
- _graph->enable();
- }
-
- for (Event* ev : _child_events) {
- ev->execute(context);
- }
- }
-}
-
-void
-CreateGraph::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _update.send(*_engine.broadcaster());
- }
-
- if (_graph) {
- for (Event* ev : _child_events) {
- ev->post_process();
- }
- }
-}
-
-void
-CreateGraph::undo(Interface& target)
-{
- target.del(_graph->uri());
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/CreateGraph.hpp b/src/server/events/CreateGraph.hpp
deleted file mode 100644
index 564d553b..00000000
--- a/src/server/events/CreateGraph.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- 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_EVENTS_CREATEGRAPH_HPP
-#define INGEN_EVENTS_CREATEGRAPH_HPP
-
-#include <list>
-
-#include "ingen/Resource.hpp"
-
-#include "CompiledGraph.hpp"
-#include "Event.hpp"
-#include "events/Get.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class GraphImpl;
-
-namespace Events {
-
-/** Creates a new Graph.
- *
- * \ingroup engine
- */
-class CreateGraph : public Event
-{
-public:
- CreateGraph(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- const Properties& properties);
-
- ~CreateGraph();
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
- GraphImpl* graph() { return _graph; }
-
-private:
- void build_child_events();
-
- const Raul::Path _path;
- Properties _properties;
- ClientUpdate _update;
- GraphImpl* _graph;
- GraphImpl* _parent;
- MPtr<CompiledGraph> _compiled_graph;
- std::list<Event*> _child_events;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_CREATEGRAPH_HPP
diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp
deleted file mode 100644
index e17b8b01..00000000
--- a/src/server/events/CreatePort.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <utility>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "raul/Array.hpp"
-#include "raul/Path.hpp"
-
-#include "Broadcaster.hpp"
-#include "BufferFactory.hpp"
-#include "CreatePort.hpp"
-#include "Driver.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-CreatePort::CreatePort(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- const Properties& properties)
- : Event(engine, client, id, timestamp)
- , _path(path)
- , _port_type(PortType::UNKNOWN)
- , _buf_type(0)
- , _graph(nullptr)
- , _graph_port(nullptr)
- , _engine_port(nullptr)
- , _properties(properties)
-{
- const Ingen::URIs& uris = _engine.world()->uris();
-
- typedef Properties::const_iterator Iterator;
- typedef std::pair<Iterator, Iterator> Range;
-
- const Range types = properties.equal_range(uris.rdf_type);
- for (Iterator i = types.first; i != types.second; ++i) {
- const Atom& type = i->second;
- if (type == uris.lv2_AudioPort) {
- _port_type = PortType::AUDIO;
- } else if (type == uris.lv2_ControlPort) {
- _port_type = PortType::CONTROL;
- } else if (type == uris.lv2_CVPort) {
- _port_type = PortType::CV;
- } else if (type == uris.atom_AtomPort) {
- _port_type = PortType::ATOM;
- } else if (type == uris.lv2_InputPort) {
- _flow = Flow::INPUT;
- } else if (type == uris.lv2_OutputPort) {
- _flow = Flow::OUTPUT;
- }
- }
-
- const Range buffer_types = properties.equal_range(uris.atom_bufferType);
- for (Iterator i = buffer_types.first; i != buffer_types.second; ++i) {
- if (uris.forge.is_uri(i->second)) {
- _buf_type = _engine.world()->uri_map().map_uri(
- uris.forge.str(i->second, false));
- }
- }
-}
-
-bool
-CreatePort::pre_process(PreProcessContext& ctx)
-{
- if (_port_type == PortType::UNKNOWN) {
- return Event::pre_process_done(Status::UNKNOWN_TYPE, _path);
- } else if (!_flow) {
- return Event::pre_process_done(Status::UNKNOWN_TYPE, _path);
- } else if (_path.is_root()) {
- return Event::pre_process_done(Status::BAD_URI, _path);
- } else if (_engine.store()->get(_path)) {
- return Event::pre_process_done(Status::EXISTS, _path);
- }
-
- const Raul::Path parent_path = _path.parent();
- Node* const parent = _engine.store()->get(parent_path);
- if (!parent) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND, parent_path);
- } else if (!(_graph = dynamic_cast<GraphImpl*>(parent))) {
- return Event::pre_process_done(Status::INVALID_PARENT, parent_path);
- } else if (!_graph->parent() && _engine.activated() &&
- !_engine.driver()->dynamic_ports()) {
- return Event::pre_process_done(Status::CREATION_FAILED, _path);
- }
-
- const URIs& uris = _engine.world()->uris();
- BufferFactory& bufs = *_engine.buffer_factory();
- const uint32_t buf_size = bufs.default_size(_buf_type);
- const int32_t old_n_ports = _graph->num_ports_non_rt();
-
- typedef Properties::const_iterator PropIter;
-
- PropIter index_i = _properties.find(uris.lv2_index);
- int32_t index = 0;
- if (index_i != _properties.end()) {
- // Ensure given index is sane and not taken
- if (index_i->second.type() != uris.forge.Int) {
- return Event::pre_process_done(Status::BAD_REQUEST);
- }
-
- index = index_i->second.get<int32_t>();
- if (_graph->has_port_with_index(index)) {
- return Event::pre_process_done(Status::BAD_INDEX);
- }
- } else {
- // No index given, append
- index = old_n_ports;
- index_i = _properties.emplace(uris.lv2_index,
- _engine.world()->forge().make(index));
- }
-
- const PropIter poly_i = _properties.find(uris.ingen_polyphonic);
- const bool polyphonic = (poly_i != _properties.end() &&
- poly_i->second.type() == uris.forge.Bool &&
- poly_i->second.get<int32_t>());
-
- // Create 0 value if the port requires one
- Atom value;
- if (_port_type == PortType::CONTROL || _port_type == PortType::CV) {
- value = bufs.forge().make(0.0f);
- }
-
- // Create port
- _graph_port = new DuplexPort(bufs, _graph, Raul::Symbol(_path.symbol()),
- index,
- polyphonic,
- _port_type, _buf_type, buf_size,
- value, _flow == Flow::OUTPUT);
- assert((_flow == Flow::OUTPUT && _graph_port->is_output()) ||
- (_flow == Flow::INPUT && _graph_port->is_input()));
- _graph_port->properties().insert(_properties.begin(), _properties.end());
-
- _engine.store()->add(_graph_port);
- if (_flow == Flow::OUTPUT) {
- _graph->add_output(*_graph_port);
- } else {
- _graph->add_input(*_graph_port);
- }
-
- if (!_graph->parent()) {
- _engine_port = _engine.driver()->create_port(_graph_port);
- }
-
- _ports_array = bufs.maid().make_managed<GraphImpl::Ports>(
- old_n_ports + 1, nullptr);
-
- _update = _graph_port->properties();
-
- assert(_graph_port->index() == (uint32_t)index_i->second.get<int32_t>());
- assert(_graph->num_ports_non_rt() == (uint32_t)old_n_ports + 1);
- assert(_ports_array->size() == _graph->num_ports_non_rt());
- assert(_graph_port->index() < _ports_array->size());
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-CreatePort::execute(RunContext& context)
-{
- if (_status == Status::SUCCESS) {
- const MPtr<GraphImpl::Ports>& old_ports = _graph->external_ports();
- if (old_ports) {
- for (uint32_t i = 0; i < old_ports->size(); ++i) {
- const auto* const old_port = (*old_ports)[i];
- assert(old_port->index() < _ports_array->size());
- (*_ports_array)[old_port->index()] = (*old_ports)[i];
- }
- }
- assert(!(*_ports_array)[_graph_port->index()]);
- (*_ports_array)[_graph_port->index()] = _graph_port;
- _graph->set_external_ports(std::move(_ports_array));
-
- if (_engine_port) {
- _engine.driver()->add_port(context, _engine_port);
- }
- }
-}
-
-void
-CreatePort::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->put(path_to_uri(_path), _update);
- }
-}
-
-void
-CreatePort::undo(Interface& target)
-{
- target.del(_graph_port->uri());
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/CreatePort.hpp b/src/server/events/CreatePort.hpp
deleted file mode 100644
index a2ea7682..00000000
--- a/src/server/events/CreatePort.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- 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_EVENTS_CREATEPORT_HPP
-#define INGEN_EVENTS_CREATEPORT_HPP
-
-#include <boost/optional.hpp>
-
-#include "ingen/Resource.hpp"
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "raul/Array.hpp"
-#include "raul/Path.hpp"
-
-#include "BlockImpl.hpp"
-#include "Event.hpp"
-#include "PortType.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class DuplexPort;
-class EnginePort;
-class GraphImpl;
-class PortImpl;
-
-namespace Events {
-
-/** An event to add a Port to a Graph.
- *
- * \ingroup engine
- */
-class CreatePort : public Event
-{
-public:
- CreatePort(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- const Raul::Path& path,
- const Properties& properties);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- enum class Flow {
- INPUT,
- OUTPUT
- };
-
- Raul::Path _path;
- PortType _port_type;
- LV2_URID _buf_type;
- GraphImpl* _graph;
- DuplexPort* _graph_port;
- MPtr<BlockImpl::Ports> _ports_array; ///< New external port array for Graph
- EnginePort* _engine_port; ///< Driver port if on the root
- Properties _properties;
- Properties _update;
- boost::optional<Flow> _flow;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_CREATEPORT_HPP
diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp
deleted file mode 100644
index e8f9582c..00000000
--- a/src/server/events/Delete.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Store.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "ControlBindings.hpp"
-#include "Delete.hpp"
-#include "DisconnectAll.hpp"
-#include "Driver.hpp"
-#include "Engine.hpp"
-#include "EnginePort.hpp"
-#include "GraphImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortImpl.hpp"
-#include "PreProcessContext.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Delete::Delete(Engine& engine,
- SPtr<Interface> client,
- FrameTime timestamp,
- const Ingen::Del& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _engine_port(nullptr)
- , _disconnect_event(nullptr)
-{
- if (uri_is_path(msg.uri)) {
- _path = uri_to_path(msg.uri);
- }
-}
-
-Delete::~Delete()
-{
- delete _disconnect_event;
- for (ControlBindings::Binding* b : _removed_bindings) {
- delete b;
- }
-}
-
-bool
-Delete::pre_process(PreProcessContext& ctx)
-{
- const Ingen::URIs& uris = _engine.world()->uris();
- if (_path.is_root() || _path == "/control" || _path == "/notify") {
- return Event::pre_process_done(Status::NOT_DELETABLE, _path);
- }
-
- _engine.control_bindings()->get_all(_path, _removed_bindings);
-
- auto iter = _engine.store()->find(_path);
- if (iter == _engine.store()->end()) {
- return Event::pre_process_done(Status::NOT_FOUND, _path);
- }
-
- if (!(_block = dynamic_ptr_cast<BlockImpl>(iter->second))) {
- _port = dynamic_ptr_cast<DuplexPort>(iter->second);
- }
-
- if ((!_block && !_port) || (_port && !_engine.driver()->dynamic_ports())) {
- return Event::pre_process_done(Status::NOT_DELETABLE, _path);
- }
-
- GraphImpl* parent = _block ? _block->parent_graph() : _port->parent_graph();
- if (!parent) {
- return Event::pre_process_done(Status::INTERNAL_ERROR, _path);
- }
-
- // Take a writer lock while we modify the store
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- _engine.store()->remove(iter, _removed_objects);
-
- if (_block) {
- parent->remove_block(*_block);
- _disconnect_event = new DisconnectAll(_engine, parent, _block.get());
- _disconnect_event->pre_process(ctx);
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *parent);
- } else if (_port) {
- parent->remove_port(*_port);
- _disconnect_event = new DisconnectAll(_engine, parent, _port.get());
- _disconnect_event->pre_process(ctx);
-
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *parent);
- if (parent->enabled()) {
- _ports_array = parent->build_ports_array(*_engine.maid());
- assert(_ports_array->size() == parent->num_ports_non_rt());
-
- // Adjust port indices if necessary and record changes for later
- for (size_t i = 0; i < _ports_array->size(); ++i) {
- PortImpl* const port = _ports_array->at(i);
- if (port->index() != i) {
- _port_index_changes.emplace(
- port->path(), std::make_pair(port->index(), i));
- port->remove_property(uris.lv2_index, uris.patch_wildcard);
- port->set_property(
- uris.lv2_index,
- _engine.buffer_factory()->forge().make((int32_t)i));
- }
- }
- }
-
- if (!parent->parent()) {
- _engine_port = _engine.driver()->get_port(_port->path());
- }
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Delete::execute(RunContext& context)
-{
- if (_status != Status::SUCCESS) {
- return;
- }
-
- if (_disconnect_event) {
- _disconnect_event->execute(context);
- }
-
- if (!_removed_bindings.empty()) {
- _engine.control_bindings()->remove(context, _removed_bindings);
- }
-
- GraphImpl* parent = _block ? _block->parent_graph() : nullptr;
- if (_port) {
- // Adjust port indices if necessary
- for (size_t i = 0; i < _ports_array->size(); ++i) {
- PortImpl* const port = _ports_array->at(i);
- if (port->index() != i) {
- port->set_index(context, i);
- }
- }
-
- // Replace ports array in graph
- parent = _port->parent_graph();
- parent->set_external_ports(std::move(_ports_array));
-
- if (_engine_port) {
- _engine.driver()->remove_port(context, _engine_port);
- }
- }
-
- if (parent && _compiled_graph) {
- parent->set_compiled_graph(std::move(_compiled_graph));
- }
-}
-
-void
-Delete::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS && (_block || _port)) {
- if (_block) {
- _block->deactivate();
- }
-
- _engine.broadcaster()->message(_msg);
- }
-
- if (_engine_port) {
- _engine.driver()->unregister_port(*_engine_port);
- delete _engine_port;
- }
-}
-
-void
-Delete::undo(Interface& target)
-{
- const Ingen::URIs& uris = _engine.world()->uris();
- Ingen::Forge& forge = _engine.buffer_factory()->forge();
-
- auto i = _removed_objects.find(_path);
- if (i != _removed_objects.end()) {
- // Undo disconnect
- if (_disconnect_event) {
- _disconnect_event->undo(target);
- }
-
- // Put deleted item back
- target.put(_msg.uri, i->second->properties());
-
- // Adjust port indices
- for (const auto& c : _port_index_changes) {
- if (c.first != _msg.uri.path()) {
- target.set_property(path_to_uri(c.first),
- uris.lv2_index,
- forge.make(int32_t(c.second.first)));
- }
- }
- }
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp
deleted file mode 100644
index 8b2a0a91..00000000
--- a/src/server/events/Delete.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- 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_EVENTS_DELETE_HPP
-#define INGEN_EVENTS_DELETE_HPP
-
-#include <map>
-#include <vector>
-
-#include "ingen/Store.hpp"
-
-#include "CompiledGraph.hpp"
-#include "ControlBindings.hpp"
-#include "Event.hpp"
-#include "GraphImpl.hpp"
-
-namespace Raul {
-template<typename T> class Array;
-}
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class DuplexPort;
-class EnginePort;
-class PortImpl;
-
-namespace Events {
-
-class DisconnectAll;
-
-/** Delete a graph object.
- * \ingroup engine
- */
-class Delete : public Event
-{
-public:
- Delete(Engine& engine,
- SPtr<Interface> client,
- FrameTime timestamp,
- const Ingen::Del& msg);
-
- ~Delete();
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- using IndexChange = std::pair<uint32_t, uint32_t>;
- using IndexChanges = std::map<Raul::Path, IndexChange>;
-
- const Ingen::Del _msg;
- Raul::Path _path;
- SPtr<BlockImpl> _block; ///< Non-NULL iff a block
- SPtr<DuplexPort> _port; ///< Non-NULL iff a port
- EnginePort* _engine_port;
- MPtr<GraphImpl::Ports> _ports_array; ///< New (external) ports for Graph
- MPtr<CompiledGraph> _compiled_graph; ///< Graph's new process order
- DisconnectAll* _disconnect_event;
- Store::Objects _removed_objects;
- IndexChanges _port_index_changes;
-
- std::vector<ControlBindings::Binding*> _removed_bindings;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_DELETE_HPP
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
deleted file mode 100644
index b23ae884..00000000
--- a/src/server/events/Delta.cpp
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <vector>
-#include <thread>
-
-#include "ingen/Log.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URIs.hpp"
-#include "raul/Maid.hpp"
-
-#include "Broadcaster.hpp"
-#include "ControlBindings.hpp"
-#include "CreateBlock.hpp"
-#include "CreateGraph.hpp"
-#include "CreatePort.hpp"
-#include "Delta.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortImpl.hpp"
-#include "PortType.hpp"
-#include "SetPortValue.hpp"
-#include "events/Get.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Delta::Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Put& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _create_event(nullptr)
- , _subject(msg.uri)
- , _properties(msg.properties)
- , _object(nullptr)
- , _graph(nullptr)
- , _binding(nullptr)
- , _state(nullptr)
- , _context(msg.ctx)
- , _type(Type::PUT)
- , _block(false)
-{
- init();
-}
-
-Delta::Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Delta& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _create_event(nullptr)
- , _subject(msg.uri)
- , _properties(msg.add)
- , _remove(msg.remove)
- , _object(nullptr)
- , _graph(nullptr)
- , _binding(nullptr)
- , _state(nullptr)
- , _context(msg.ctx)
- , _type(Type::PATCH)
- , _block(false)
-{
- init();
-}
-
-Delta::Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::SetProperty& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _create_event(nullptr)
- , _subject(msg.subject)
- , _properties{{msg.predicate, msg.value}}
- , _object(nullptr)
- , _graph(nullptr)
- , _binding(nullptr)
- , _state(nullptr)
- , _context(msg.ctx)
- , _type(Type::SET)
- , _block(false)
-{
- init();
-}
-
-Delta::~Delta()
-{
- for (auto& s : _set_events) {
- delete s;
- }
-
- delete _create_event;
-}
-
-void
-Delta::init()
-{
- if (_context != Resource::Graph::DEFAULT) {
- for (auto& p : _properties) {
- p.second.set_context(_context);
- }
- }
-
- // Set atomic execution if polyphony is to be changed
- const Ingen::URIs& uris = _engine.world()->uris();
- if (_properties.count(uris.ingen_polyphonic) ||
- _properties.count(uris.ingen_polyphony)) {
- _block = true;
- }
-}
-
-void
-Delta::add_set_event(const char* port_symbol,
- const void* value,
- uint32_t size,
- uint32_t type)
-{
- BlockImpl* block = dynamic_cast<BlockImpl*>(_object);
- PortImpl* port = block->port_by_symbol(port_symbol);
- if (!port) {
- _engine.log().warn(fmt("Unknown port `%1%' in state") % port_symbol);
- return;
- }
-
- SetPortValue* ev = new SetPortValue(
- _engine, _request_client, _request_id, _time,
- port, Atom(size, type, value), false, true);
-
- _set_events.push_back(ev);
-}
-
-static void
-s_add_set_event(const char* port_symbol,
- void* user_data,
- const void* value,
- uint32_t size,
- uint32_t type)
-{
- ((Delta*)user_data)->add_set_event(port_symbol, value, size, type);
-}
-
-static LilvNode*
-get_file_node(LilvWorld* lworld, const URIs& uris, const Atom& value)
-{
- if (value.type() == uris.atom_Path) {
- return lilv_new_file_uri(lworld, nullptr, value.ptr<char>());
- } else if (uris.forge.is_uri(value)) {
- const std::string str = uris.forge.str(value, false);
- if (str.substr(0, 5) == "file:") {
- return lilv_new_uri(lworld, value.ptr<char>());
- }
- }
- return nullptr;
-}
-
-bool
-Delta::pre_process(PreProcessContext& ctx)
-{
- const Ingen::URIs& uris = _engine.world()->uris();
-
- const bool is_graph_object = uri_is_path(_subject);
- const bool is_client = (_subject == "ingen:/clients/this");
- const bool is_engine = (_subject == "ingen:/");
- const bool is_file = (_subject.scheme() == "file");
-
- if (_type == Type::PUT && is_file) {
- // Ensure type is Preset, the only supported file put
- const auto t = _properties.find(uris.rdf_type);
- if (t == _properties.end() || t->second != uris.pset_Preset) {
- return Event::pre_process_done(Status::BAD_REQUEST, _subject);
- }
-
- // Get "prototype" for preset (node to save state for)
- const auto p = _properties.find(uris.lv2_prototype);
- if (p == _properties.end()) {
- return Event::pre_process_done(Status::BAD_REQUEST, _subject);
- } else if (!_engine.world()->forge().is_uri(p->second)) {
- return Event::pre_process_done(Status::BAD_REQUEST, _subject);
- }
-
- const URI prot(_engine.world()->forge().str(p->second, false));
- if (!uri_is_path(prot)) {
- return Event::pre_process_done(Status::BAD_URI, _subject);
- }
-
- Node* node = _engine.store()->get(uri_to_path(prot));
- if (!node) {
- return Event::pre_process_done(Status::NOT_FOUND, prot);
- }
-
- BlockImpl* block = dynamic_cast<BlockImpl*>(node);
- if (!block) {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, prot);
- }
-
- if ((_preset = block->save_preset(_subject, _properties))) {
- return Event::pre_process_done(Status::SUCCESS);
- } else {
- return Event::pre_process_done(Status::FAILURE);
- }
- }
-
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- _object = is_graph_object
- ? static_cast<Ingen::Resource*>(_engine.store()->get(uri_to_path(_subject)))
- : static_cast<Ingen::Resource*>(_engine.block_factory()->plugin(_subject));
-
- if (!_object && !is_client && !is_engine &&
- (!is_graph_object || _type != Type::PUT)) {
- return Event::pre_process_done(Status::NOT_FOUND, _subject);
- }
-
- if (is_graph_object && !_object) {
- Raul::Path path(uri_to_path(_subject));
- bool is_graph = false, is_block = false, is_port = false, is_output = false;
- Ingen::Resource::type(uris, _properties, is_graph, is_block, is_port, is_output);
-
- if (is_graph) {
- _create_event = new CreateGraph(
- _engine, _request_client, _request_id, _time, path, _properties);
- } else if (is_block) {
- _create_event = new CreateBlock(
- _engine, _request_client, _request_id, _time, path, _properties);
- } else if (is_port) {
- _create_event = new CreatePort(
- _engine, _request_client, _request_id, _time,
- path, _properties);
- }
- if (_create_event) {
- if (_create_event->pre_process(ctx)) {
- _object = _engine.store()->get(path); // Get object for setting
- } else {
- return Event::pre_process_done(Status::CREATION_FAILED, _subject);
- }
- } else {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _subject);
- }
- }
-
- _types.reserve(_properties.size());
-
- NodeImpl* obj = dynamic_cast<NodeImpl*>(_object);
-
- // Remove any properties removed in delta
- for (const auto& r : _remove) {
- const URI& key = r.first;
- const Atom& value = r.second;
- if (key == uris.midi_binding && value == uris.patch_wildcard) {
- PortImpl* port = dynamic_cast<PortImpl*>(_object);
- if (port) {
- _engine.control_bindings()->get_all(port->path(), _removed_bindings);
- }
- }
- if (_object) {
- _removed.emplace(key, value);
- _object->remove_property(key, value);
- } else if (is_engine && key == uris.ingen_loadedBundle) {
- LilvWorld* lworld = _engine.world()->lilv_world();
- LilvNode* bundle = get_file_node(lworld, uris, value);
- if (bundle) {
- for (const auto& p : _engine.block_factory()->plugins()) {
- if (p.second->bundle_uri() == lilv_node_as_string(bundle)) {
- p.second->set_is_zombie(true);
- _update.del(p.second->uri());
- }
- }
- lilv_world_unload_bundle(lworld, bundle);
- _engine.block_factory()->refresh();
- lilv_node_free(bundle);
- } else {
- _status = Status::BAD_VALUE;
- }
- }
- }
-
- // Remove all added properties if this is a put or set
- if (_object && (_type == Type::PUT || _type == Type::SET)) {
- for (auto p = _properties.begin();
- p != _properties.end();
- p = _properties.upper_bound(p->first)) {
- for (auto q = _object->properties().find(p->first);
- q != _object->properties().end() && q->first == p->first;) {
- auto next = q;
- ++next;
-
- if (!_properties.contains(q->first, q->second)) {
- const auto r = std::make_pair(q->first, q->second);
- _object->properties().erase(q);
- _object->on_property_removed(r.first, r.second);
- _removed.insert(r);
- }
-
- q = next;
- }
- }
- }
-
- for (const auto& p : _properties) {
- const URI& key = p.first;
- const Property& value = p.second;
- SpecialType op = SpecialType::NONE;
- if (obj) {
- Resource& resource = *obj;
- if (value != uris.patch_wildcard) {
- if (resource.add_property(key, value, value.context())) {
- _added.emplace(key, value);
- }
- }
-
- BlockImpl* block = nullptr;
- PortImpl* port = dynamic_cast<PortImpl*>(_object);
- if (port) {
- if (key == uris.ingen_broadcast) {
- if (value.type() == uris.forge.Bool) {
- op = SpecialType::ENABLE_BROADCAST;
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
- } else if (key == uris.ingen_value || key == uris.ingen_activity) {
- SetPortValue* ev = new SetPortValue(
- _engine, _request_client, _request_id, _time, port, value,
- key == uris.ingen_activity);
- _set_events.push_back(ev);
- } else if (key == uris.midi_binding) {
- if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) {
- if (value == uris.patch_wildcard) {
- _engine.control_bindings()->start_learn(port);
- } else if (value.type() == uris.atom_Object) {
- op = SpecialType::CONTROL_BINDING;
- _binding = new ControlBindings::Binding();
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
- } else {
- _status = Status::BAD_OBJECT_TYPE;
- }
- } else if (key == uris.lv2_index) {
- op = SpecialType::PORT_INDEX;
- port->set_property(key, value);
- }
- } else if ((block = dynamic_cast<BlockImpl*>(_object))) {
- if (key == uris.midi_binding && value == uris.patch_wildcard) {
- op = SpecialType::CONTROL_BINDING; // Internal block learn
- } else if (key == uris.ingen_enabled) {
- if (value.type() == uris.forge.Bool) {
- op = SpecialType::ENABLE;
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
- } else if (key == uris.pset_preset) {
- URI uri;
- if (uris.forge.is_uri(value)) {
- const std::string uri_str = uris.forge.str(value, false);
- if (URI::is_valid(uri_str)) {
- uri = URI(uri_str);
- }
- } else if (value.type() == uris.forge.Path) {
- uri = URI(FilePath(value.ptr<char>()));
- }
-
- if (!uri.empty()) {
- op = SpecialType::PRESET;
- if ((_state = block->load_preset(uri))) {
- lilv_state_emit_port_values(
- _state, s_add_set_event, this);
- } else {
- _engine.log().warn(fmt("Failed to load preset <%1%>\n") % uri);
- }
- } else {
- _status = Status::BAD_VALUE;
- }
- }
- }
-
- if ((_graph = dynamic_cast<GraphImpl*>(_object))) {
- if (key == uris.ingen_enabled) {
- if (value.type() == uris.forge.Bool) {
- op = SpecialType::ENABLE;
- // FIXME: defer this until all other metadata has been processed
- if (value.get<int32_t>() && !_graph->enabled()) {
- if (!(_compiled_graph = compile(*_engine.maid(), *_graph))) {
- _status = Status::COMPILATION_FAILED;
- }
- }
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
- } else if (key == uris.ingen_polyphony) {
- if (value.type() == uris.forge.Int) {
- if (value.get<int32_t>() < 1 || value.get<int32_t>() > 128) {
- _status = Status::INVALID_POLY;
- } else {
- op = SpecialType::POLYPHONY;
- _graph->prepare_internal_poly(
- *_engine.buffer_factory(), value.get<int32_t>());
- }
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
- }
- }
-
- if (!_create_event && key == uris.ingen_polyphonic) {
- GraphImpl* parent = dynamic_cast<GraphImpl*>(obj->parent());
- if (!parent) {
- _status = Status::BAD_OBJECT_TYPE;
- } else if (value.type() != uris.forge.Bool) {
- _status = Status::BAD_VALUE_TYPE;
- } else {
- op = SpecialType::POLYPHONIC;
- obj->set_property(key, value, value.context());
- BlockImpl* block = dynamic_cast<BlockImpl*>(obj);
- if (block) {
- block->set_polyphonic(value.get<int32_t>());
- }
- if (value.get<int32_t>()) {
- obj->prepare_poly(*_engine.buffer_factory(), parent->internal_poly());
- } else {
- obj->prepare_poly(*_engine.buffer_factory(), 1);
- }
- }
- }
- } else if (is_client && key == uris.ingen_broadcast) {
- _engine.broadcaster()->set_broadcast(
- _request_client, value.get<int32_t>());
- } else if (is_engine && key == uris.ingen_loadedBundle) {
- LilvWorld* lworld = _engine.world()->lilv_world();
- LilvNode* bundle = get_file_node(lworld, uris, value);
- if (bundle) {
- lilv_world_load_bundle(lworld, bundle);
- const std::set<PluginImpl*> new_plugins =
- _engine.block_factory()->refresh();
-
- for (PluginImpl* p : new_plugins) {
- if (p->bundle_uri() == lilv_node_as_string(bundle)) {
- _update.put_plugin(p);
- }
- }
- lilv_node_free(bundle);
- } else {
- _status = Status::BAD_VALUE;
- }
- }
-
- if (_status != Status::NOT_PREPARED) {
- break;
- }
-
- _types.push_back(op);
- }
-
- for (auto& s : _set_events) {
- s->pre_process(ctx);
- }
-
- return Event::pre_process_done(
- _status == Status::NOT_PREPARED ? Status::SUCCESS : _status,
- _subject);
-}
-
-void
-Delta::execute(RunContext& context)
-{
- if (_status != Status::SUCCESS || _preset) {
- return;
- }
-
- const Ingen::URIs& uris = _engine.world()->uris();
-
- if (_create_event) {
- _create_event->set_time(_time);
- _create_event->execute(context);
- }
-
- for (auto& s : _set_events) {
- s->set_time(_time);
- s->execute(context);
- }
-
- if (!_removed_bindings.empty()) {
- _engine.control_bindings()->remove(context, _removed_bindings);
- }
-
- NodeImpl* const object = dynamic_cast<NodeImpl*>(_object);
- BlockImpl* const block = dynamic_cast<BlockImpl*>(_object);
- PortImpl* const port = dynamic_cast<PortImpl*>(_object);
-
- std::vector<SpecialType>::const_iterator t = _types.begin();
- for (const auto& p : _properties) {
- const URI& key = p.first;
- const Atom& value = p.second;
- switch (*t++) {
- case SpecialType::ENABLE_BROADCAST:
- if (port) {
- port->enable_monitoring(value.get<int32_t>());
- }
- break;
- case SpecialType::ENABLE:
- if (_graph) {
- if (value.get<int32_t>()) {
- if (_compiled_graph) {
- _graph->set_compiled_graph(std::move(_compiled_graph));
- }
- _graph->enable();
- } else {
- _graph->disable(context);
- }
- } else if (block) {
- block->set_enabled(value.get<int32_t>());
- }
- break;
- case SpecialType::POLYPHONIC: {
- GraphImpl* parent = reinterpret_cast<GraphImpl*>(object->parent());
- if (value.get<int32_t>()) {
- object->apply_poly(context, parent->internal_poly_process());
- } else {
- object->apply_poly(context, 1);
- }
- } break;
- case SpecialType::POLYPHONY:
- if (!_graph->apply_internal_poly(context,
- *_engine.buffer_factory(),
- *_engine.maid(),
- value.get<int32_t>())) {
- _status = Status::INTERNAL_ERROR;
- }
- break;
- case SpecialType::PORT_INDEX:
- if (port) {
- port->set_index(context, value.get<int32_t>());
- }
- break;
- case SpecialType::CONTROL_BINDING:
- if (port) {
- if (!_engine.control_bindings()->set_port_binding(context, port, _binding, value)) {
- _status = Status::BAD_VALUE;
- }
- } else if (block) {
- if (uris.ingen_Internal == block->plugin_impl()->type()) {
- block->learn();
- }
- }
- break;
- case SpecialType::PRESET:
- block->set_enabled(false);
- break;
- case SpecialType::NONE:
- if (port) {
- if (key == uris.lv2_minimum) {
- port->set_minimum(value);
- } else if (key == uris.lv2_maximum) {
- port->set_maximum(value);
- }
- }
- case SpecialType::LOADED_BUNDLE:
- break;
- }
- }
-}
-
-void
-Delta::post_process()
-{
- if (_state) {
- BlockImpl* block = dynamic_cast<BlockImpl*>(_object);
- if (block) {
- block->apply_state(_engine.sync_worker(), _state);
- block->set_enabled(true);
- }
- lilv_state_free(_state);
- }
-
- Broadcaster::Transfer t(*_engine.broadcaster());
-
- if (_create_event) {
- _create_event->post_process();
- if (_create_event->status() != Status::SUCCESS) {
- return; // Creation failed, nothing else to do
- }
- }
-
- for (auto& s : _set_events) {
- if (s->synthetic() || s->status() != Status::SUCCESS) {
- s->post_process(); // Set failed, report error
- }
- }
-
- if (respond() == Status::SUCCESS) {
- _update.send(*_engine.broadcaster());
-
- switch (_type) {
- case Type::SET:
- /* Kludge to avoid feedback for set events only. The GUI
- depends on put responses to e.g. initially place blocks.
- Some more sensible way of controlling this is needed. */
- if (_mode == Mode::NORMAL) {
- _engine.broadcaster()->set_ignore_client(_request_client);
- }
- _engine.broadcaster()->set_property(
- _subject,
- _properties.begin()->first,
- _properties.begin()->second);
- if (_mode == Mode::NORMAL) {
- _engine.broadcaster()->clear_ignore_client();
- }
- break;
- case Type::PUT:
- if (_type == Type::PUT && _subject.scheme() == "file") {
- // Preset save
- ClientUpdate response;
- response.put(_preset->uri(), _preset->properties());
- response.send(*_engine.broadcaster());
- } else {
- // Graph object put
- _engine.broadcaster()->put(_subject, _properties, _context);
- }
- break;
- case Type::PATCH:
- _engine.broadcaster()->delta(_subject, _remove, _properties, _context);
- break;
- }
- }
-}
-
-void
-Delta::undo(Interface& target)
-{
- if (_create_event) {
- _create_event->undo(target);
- } else if (_type == Type::PATCH) {
- target.delta(_subject, _added, _removed, _context);
- } else if (_type == Type::SET || _type == Type::PUT) {
- if (_removed.size() == 1) {
- target.set_property(_subject,
- _removed.begin()->first,
- _removed.begin()->second,
- _context);
- } else if (_removed.empty()) {
- target.delta(_subject, _added, {}, _context);
- } else {
- target.put(_subject, _removed, _context);
- }
- }
-}
-
-Event::Execution
-Delta::get_execution() const
-{
- return _block ? Execution::ATOMIC : Execution::NORMAL;
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp
deleted file mode 100644
index af337b57..00000000
--- a/src/server/events/Delta.hpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- 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_EVENTS_DELTA_HPP
-#define INGEN_EVENTS_DELTA_HPP
-
-#include <vector>
-
-#include <boost/optional.hpp>
-
-#include "lilv/lilv.h"
-
-#include "CompiledGraph.hpp"
-#include "ControlBindings.hpp"
-#include "Event.hpp"
-#include "PluginImpl.hpp"
-
-namespace Ingen {
-
-class Resource;
-
-namespace Server {
-
-class Engine;
-class GraphImpl;
-class RunContext;
-
-namespace Events {
-
-class SetPortValue;
-
-/** Set properties of a graph object.
- * \ingroup engine
- */
-class Delta : public Event
-{
-public:
- Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Put& msg);
-
- Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Delta& msg);
-
- Delta(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::SetProperty& msg);
-
- ~Delta();
-
- void add_set_event(const char* port_symbol,
- const void* value,
- uint32_t size,
- uint32_t type);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
- Execution get_execution() const;
-
-private:
- enum class Type {
- SET,
- PUT,
- PATCH
- };
-
- enum class SpecialType {
- NONE,
- ENABLE,
- ENABLE_BROADCAST,
- POLYPHONY,
- POLYPHONIC,
- PORT_INDEX,
- CONTROL_BINDING,
- PRESET,
- LOADED_BUNDLE
- };
-
- typedef std::vector<SetPortValue*> SetEvents;
-
- void init();
-
- Event* _create_event;
- SetEvents _set_events;
- std::vector<SpecialType> _types;
- std::vector<SpecialType> _remove_types;
- URI _subject;
- Properties _properties;
- Properties _remove;
- ClientUpdate _update;
- Ingen::Resource* _object;
- GraphImpl* _graph;
- MPtr<CompiledGraph> _compiled_graph;
- ControlBindings::Binding* _binding;
- LilvState* _state;
- Resource::Graph _context;
- Type _type;
-
- Properties _added;
- Properties _removed;
-
- std::vector<ControlBindings::Binding*> _removed_bindings;
-
- boost::optional<Resource> _preset;
-
- bool _block;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_DELTA_HPP
diff --git a/src/server/events/Disconnect.cpp b/src/server/events/Disconnect.cpp
deleted file mode 100644
index 4553c8a2..00000000
--- a/src/server/events/Disconnect.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <set>
-
-#include "ingen/Store.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "ArcImpl.hpp"
-#include "Broadcaster.hpp"
-#include "Buffer.hpp"
-#include "DuplexPort.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "PortImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-#include "events/Disconnect.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Disconnect::Disconnect(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Disconnect& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _graph(nullptr)
- , _impl(nullptr)
-{
-}
-
-Disconnect::~Disconnect()
-{
- delete _impl;
-}
-
-Disconnect::Impl::Impl(Engine& e,
- GraphImpl* graph,
- PortImpl* t,
- InputPort* h)
- : _engine(e)
- , _tail(t)
- , _head(h)
- , _arc(graph->remove_arc(_tail, _head))
-{
- ThreadManager::assert_thread(THREAD_PRE_PROCESS);
-
- BlockImpl* const tail_block = _tail->parent_block();
- BlockImpl* const head_block = _head->parent_block();
-
- // Remove tail from head's providers
- auto hp = head_block->providers().find(tail_block);
- if (hp != head_block->providers().end()) {
- head_block->providers().erase(hp);
- }
-
- // Remove head from tail's providers
- auto td = tail_block->dependants().find(head_block);
- if (td != tail_block->dependants().end()) {
- tail_block->dependants().erase(td);
- }
-
- _head->decrement_num_arcs();
-
- if (_head->num_arcs() == 0) {
- if (!_head->is_driver_port()) {
- BufferFactory& bufs = *_engine.buffer_factory();
- _voices = bufs.maid().make_managed<PortImpl::Voices>(_head->poly());
- _head->pre_get_buffers(bufs, _voices, _head->poly());
-
- if (_head->is_a(PortType::CONTROL) ||
- _head->is_a(PortType::CV)) {
- // Reset buffer to control value
- const float value = _head->value().get<float>();
- for (uint32_t i = 0; i < _voices->size(); ++i) {
- Buffer* buf = _voices->at(i).buffer.get();
- buf->set_block(value, 0, e.block_length());
- }
- } else {
- for (uint32_t i = 0; i < _voices->size(); ++i) {
- _voices->at(i).buffer->clear();
- }
- }
- }
- }
-}
-
-bool
-Disconnect::pre_process(PreProcessContext& ctx)
-{
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- if (_msg.tail.parent().parent() != _msg.head.parent().parent()
- && _msg.tail.parent() != _msg.head.parent().parent()
- && _msg.tail.parent().parent() != _msg.head.parent()) {
- return Event::pre_process_done(Status::PARENT_DIFFERS, _msg.head);
- }
-
- PortImpl* tail = dynamic_cast<PortImpl*>(_engine.store()->get(_msg.tail));
- if (!tail) {
- return Event::pre_process_done(Status::PORT_NOT_FOUND, _msg.tail);
- }
-
- PortImpl* head = dynamic_cast<PortImpl*>(_engine.store()->get(_msg.head));
- if (!head) {
- return Event::pre_process_done(Status::PORT_NOT_FOUND, _msg.head);
- }
-
- BlockImpl* const tail_block = tail->parent_block();
- BlockImpl* const head_block = head->parent_block();
-
- if (tail_block->parent_graph() != head_block->parent_graph()) {
- // Arc to a graph port from inside the graph
- assert(tail_block->parent() == head_block || head_block->parent() == tail_block);
- if (tail_block->parent() == head_block) {
- _graph = dynamic_cast<GraphImpl*>(head_block);
- } else {
- _graph = dynamic_cast<GraphImpl*>(tail_block);
- }
- } else if (tail_block == head_block && dynamic_cast<GraphImpl*>(tail_block)) {
- // Arc from a graph input to a graph output (pass through)
- _graph = dynamic_cast<GraphImpl*>(tail_block);
- } else {
- // Normal arc between blocks with the same parent
- _graph = tail_block->parent_graph();
- }
-
- if (!_graph) {
- return Event::pre_process_done(Status::INTERNAL_ERROR, _msg.head);
- } else if (!_graph->has_arc(tail, head)) {
- return Event::pre_process_done(Status::NOT_FOUND, _msg.head);
- }
-
- if (tail_block == nullptr || head_block == nullptr) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND, _msg.head);
- }
-
- _impl = new Impl(_engine,
- _graph,
- dynamic_cast<PortImpl*>(tail),
- dynamic_cast<InputPort*>(head));
-
- _compiled_graph = ctx.maybe_compile(*_engine.maid(), *_graph);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-bool
-Disconnect::Impl::execute(RunContext& context, bool set_head_buffers)
-{
- if (!_arc) {
- return false;
- }
-
- _head->remove_arc(*_arc.get());
- if (_head->is_driver_port()) {
- return true;
- }
-
- if (set_head_buffers) {
- if (_voices) {
- _head->set_voices(context, std::move(_voices));
- } else {
- _head->setup_buffers(context, *_engine.buffer_factory(), _head->poly());
- }
- _head->connect_buffers();
- } else {
- _head->recycle_buffers();
- }
-
- return true;
-}
-
-void
-Disconnect::execute(RunContext& context)
-{
- if (_status == Status::SUCCESS) {
- if (_impl->execute(context, true)) {
- if (_compiled_graph) {
- _graph->set_compiled_graph(std::move(_compiled_graph));
- }
- } else {
- _status = Status::NOT_FOUND;
- }
- }
-}
-
-void
-Disconnect::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->message(_msg);
- }
-}
-
-void
-Disconnect::undo(Interface& target)
-{
- target.connect(_msg.tail, _msg.head);
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Disconnect.hpp b/src/server/events/Disconnect.hpp
deleted file mode 100644
index 44290d7c..00000000
--- a/src/server/events/Disconnect.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- 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_EVENTS_DISCONNECT_HPP
-#define INGEN_EVENTS_DISCONNECT_HPP
-
-#include "raul/Path.hpp"
-
-#include "BufferFactory.hpp"
-#include "CompiledGraph.hpp"
-#include "Event.hpp"
-#include "GraphImpl.hpp"
-#include "types.hpp"
-
-namespace Raul {
-template <typename T> class Array;
-}
-
-namespace Ingen {
-namespace Server {
-
-class InputPort;
-class PortImpl;
-
-namespace Events {
-
-/** Remove an Arc between two Ports.
- *
- * \ingroup engine
- */
-class Disconnect : public Event
-{
-public:
- Disconnect(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Disconnect& msg);
-
- ~Disconnect();
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
- class Impl {
- public:
- Impl(Engine& e, GraphImpl* graph, PortImpl* t, InputPort* h);
-
- bool execute(RunContext& context, bool set_head_buffers);
-
- inline PortImpl* tail() { return _tail; }
- inline InputPort* head() { return _head; }
-
- private:
- Engine& _engine;
- PortImpl* _tail;
- InputPort* _head;
- SPtr<ArcImpl> _arc;
- MPtr<PortImpl::Voices> _voices;
- };
-
-private:
- const Ingen::Disconnect _msg;
- GraphImpl* _graph;
- Impl* _impl;
- MPtr<CompiledGraph> _compiled_graph;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_DISCONNECT_HPP
diff --git a/src/server/events/DisconnectAll.cpp b/src/server/events/DisconnectAll.cpp
deleted file mode 100644
index 11311d12..00000000
--- a/src/server/events/DisconnectAll.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <set>
-
-#include "ingen/Store.hpp"
-#include "raul/Array.hpp"
-#include "raul/Maid.hpp"
-#include "raul/Path.hpp"
-
-#include "ArcImpl.hpp"
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "Engine.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "PortImpl.hpp"
-#include "PreProcessContext.hpp"
-#include "events/Disconnect.hpp"
-#include "events/DisconnectAll.hpp"
-#include "util.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-DisconnectAll::DisconnectAll(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::DisconnectAll& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _parent(nullptr)
- , _block(nullptr)
- , _port(nullptr)
- , _deleting(false)
-{
-}
-
-/** Internal version for use by other events.
- */
-DisconnectAll::DisconnectAll(Engine& engine,
- GraphImpl* parent,
- Node* object)
- : Event(engine)
- , _msg{0, parent->path(), object->path()}
- , _parent(parent)
- , _block(dynamic_cast<BlockImpl*>(object))
- , _port(dynamic_cast<PortImpl*>(object))
- , _deleting(true)
-{
-}
-
-DisconnectAll::~DisconnectAll()
-{
- for (auto& i : _impls) {
- delete i;
- }
-}
-
-bool
-DisconnectAll::pre_process(PreProcessContext& ctx)
-{
- std::unique_lock<Store::Mutex> lock(_engine.store()->mutex(),
- std::defer_lock);
-
- if (!_deleting) {
- lock.lock();
-
- _parent = dynamic_cast<GraphImpl*>(_engine.store()->get(_msg.graph));
- if (!_parent) {
- return Event::pre_process_done(Status::PARENT_NOT_FOUND,
- _msg.graph);
- }
-
- NodeImpl* const object = dynamic_cast<NodeImpl*>(
- _engine.store()->get(_msg.path));
- if (!object) {
- return Event::pre_process_done(Status::NOT_FOUND, _msg.path);
- }
-
- if (object->parent_graph() != _parent
- && object->parent()->parent_graph() != _parent) {
- return Event::pre_process_done(Status::INVALID_PARENT, _msg.graph);
- }
-
- // Only one of these will succeed
- _block = dynamic_cast<BlockImpl*>(object);
- _port = dynamic_cast<PortImpl*>(object);
-
- if (!_block && !_port) {
- return Event::pre_process_done(Status::INTERNAL_ERROR, _msg.path);
- }
- }
-
- // Find set of arcs to remove
- std::set<ArcImpl*> to_remove;
- for (const auto& a : _parent->arcs()) {
- ArcImpl* const arc = (ArcImpl*)a.second.get();
- if (_block) {
- if (arc->tail()->parent_block() == _block
- || arc->head()->parent_block() == _block) {
- to_remove.insert(arc);
- }
- } else if (_port) {
- if (arc->tail() == _port || arc->head() == _port) {
- to_remove.insert(arc);
- }
- }
- }
-
- // Create disconnect events (which erases from _parent->arcs())
- for (const auto& a : to_remove) {
- _impls.push_back(new Disconnect::Impl(
- _engine, _parent,
- dynamic_cast<PortImpl*>(a->tail()),
- dynamic_cast<InputPort*>(a->head())));
- }
-
- if (!_deleting && ctx.must_compile(*_parent)) {
- if (!(_compiled_graph = compile(*_engine.maid(), *_parent))) {
- return Event::pre_process_done(Status::COMPILATION_FAILED);
- }
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-DisconnectAll::execute(RunContext& context)
-{
- if (_status == Status::SUCCESS) {
- for (auto& i : _impls) {
- i->execute(context,
- !_deleting || (i->head()->parent_block() != _block));
- }
- }
-
- if (_compiled_graph) {
- _parent->set_compiled_graph(std::move(_compiled_graph));
- }
-}
-
-void
-DisconnectAll::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->message(_msg);
- }
-}
-
-void
-DisconnectAll::undo(Interface& target)
-{
- for (auto& i : _impls) {
- target.connect(i->tail()->path(), i->head()->path());
- }
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/DisconnectAll.hpp b/src/server/events/DisconnectAll.hpp
deleted file mode 100644
index 947e538f..00000000
--- a/src/server/events/DisconnectAll.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- 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_EVENTS_DISCONNECTALL_HPP
-#define INGEN_EVENTS_DISCONNECTALL_HPP
-
-#include <list>
-
-#include "raul/Path.hpp"
-
-#include "CompiledGraph.hpp"
-#include "Disconnect.hpp"
-#include "Event.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class GraphImpl;
-class PortImpl;
-
-namespace Events {
-
-class Disconnect;
-
-/** An event to disconnect all connections to a Block.
- *
- * \ingroup engine
- */
-class DisconnectAll : public Event
-{
-public:
- DisconnectAll(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::DisconnectAll& msg);
-
- DisconnectAll(Engine& engine,
- GraphImpl* parent,
- Node* object);
-
- ~DisconnectAll();
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- typedef std::list<Disconnect::Impl*> Impls;
-
- const Ingen::DisconnectAll _msg;
- GraphImpl* _parent;
- BlockImpl* _block;
- PortImpl* _port;
- Impls _impls;
- MPtr<CompiledGraph> _compiled_graph;
- bool _deleting;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_DISCONNECTALL_HPP
diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp
deleted file mode 100644
index e53e8c41..00000000
--- a/src/server/events/Get.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <utility>
-
-#include "ingen/Interface.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/Store.hpp"
-
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "BufferFactory.hpp"
-#include "Engine.hpp"
-#include "Get.hpp"
-#include "GraphImpl.hpp"
-#include "PluginImpl.hpp"
-#include "PortImpl.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Get::Get(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Get& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
- , _object(nullptr)
- , _plugin(nullptr)
-{}
-
-bool
-Get::pre_process(PreProcessContext& ctx)
-{
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- const auto& uri = _msg.subject;
- if (uri == "ingen:/plugins") {
- _plugins = _engine.block_factory()->plugins();
- return Event::pre_process_done(Status::SUCCESS);
- } else if (uri == "ingen:/engine") {
- return Event::pre_process_done(Status::SUCCESS);
- } else if (uri_is_path(uri)) {
- if ((_object = _engine.store()->get(uri_to_path(uri)))) {
- const BlockImpl* block = nullptr;
- const GraphImpl* graph = nullptr;
- const PortImpl* port = nullptr;
- if ((graph = dynamic_cast<const GraphImpl*>(_object))) {
- _response.put_graph(graph);
- } else if ((block = dynamic_cast<const BlockImpl*>(_object))) {
- _response.put_block(block);
- } else if ((port = dynamic_cast<const PortImpl*>(_object))) {
- _response.put_port(port);
- } else {
- return Event::pre_process_done(Status::BAD_OBJECT_TYPE, uri);
- }
- return Event::pre_process_done(Status::SUCCESS);
- }
- return Event::pre_process_done(Status::NOT_FOUND, uri);
- } else if ((_plugin = _engine.block_factory()->plugin(uri))) {
- _response.put_plugin(_plugin);
- return Event::pre_process_done(Status::SUCCESS);
- } else {
- return Event::pre_process_done(Status::NOT_FOUND, uri);
- }
-}
-
-void
-Get::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS && _request_client) {
- if (_msg.subject == "ingen:/plugins") {
- _engine.broadcaster()->send_plugins_to(_request_client.get(), _plugins);
- } else if (_msg.subject == "ingen:/engine") {
- // TODO: Keep a proper RDF model of the engine
- URIs& uris = _engine.world()->uris();
- Properties props = {
- { uris.param_sampleRate,
- uris.forge.make(int32_t(_engine.sample_rate())) },
- { uris.bufsz_maxBlockLength,
- uris.forge.make(int32_t(_engine.block_length())) },
- { uris.ingen_numThreads,
- uris.forge.make(int32_t(_engine.n_threads())) } };
-
- const Properties load_props = _engine.load_properties();
- props.insert(load_props.begin(), load_props.end());
- _request_client->put(URI("ingen:/engine"), props);
- } else {
- _response.send(*_request_client);
- }
- }
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Get.hpp b/src/server/events/Get.hpp
deleted file mode 100644
index 7392550f..00000000
--- a/src/server/events/Get.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- 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_EVENTS_GET_HPP
-#define INGEN_EVENTS_GET_HPP
-
-#include <vector>
-
-#include "BlockFactory.hpp"
-#include "ClientUpdate.hpp"
-#include "Event.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class BlockImpl;
-class GraphImpl;
-class PluginImpl;
-class PortImpl;
-
-namespace Events {
-
-/** A request from a client to send an object.
- *
- * \ingroup engine
- */
-class Get : public Event
-{
-public:
- Get(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Get& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context) {}
- void post_process();
-
-private:
- const Ingen::Get _msg;
- const Node* _object;
- PluginImpl* _plugin;
- BlockFactory::Plugins _plugins;
- ClientUpdate _response;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_GET_HPP
diff --git a/src/server/events/Mark.cpp b/src/server/events/Mark.cpp
deleted file mode 100644
index 3c0dfaaf..00000000
--- a/src/server/events/Mark.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 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/>.
-*/
-
-#include "Engine.hpp"
-#include "PreProcessContext.hpp"
-#include "UndoStack.hpp"
-#include "events/Mark.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Mark::Mark(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::BundleBegin& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _type(Type::BUNDLE_BEGIN)
- , _depth(0)
-{}
-
-Mark::Mark(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::BundleEnd& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _type(Type::BUNDLE_END)
- , _depth(0)
-{}
-
-bool
-Mark::pre_process(PreProcessContext& ctx)
-{
- const UPtr<UndoStack>& stack = ((_mode == Mode::UNDO)
- ? _engine.redo_stack()
- : _engine.undo_stack());
-
- switch (_type) {
- case Type::BUNDLE_BEGIN:
- ctx.set_in_bundle(true);
- _depth = stack->start_entry();
- break;
- case Type::BUNDLE_END:
- _depth = stack->finish_entry();
- ctx.set_in_bundle(false);
- if (!ctx.dirty_graphs().empty()) {
- for (GraphImpl* g : ctx.dirty_graphs()) {
- MPtr<CompiledGraph> cg = compile(*_engine.maid(), *g);
- if (cg) {
- _compiled_graphs.emplace(g, std::move(cg));
- }
- }
- ctx.dirty_graphs().clear();
- }
- break;
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Mark::execute(RunContext& context)
-{
- for (auto& g : _compiled_graphs) {
- g.first->set_compiled_graph(std::move(g.second));
- }
-}
-
-void
-Mark::post_process()
-{
- respond();
-}
-
-Event::Execution
-Mark::get_execution() const
-{
- if (!_engine.atomic_bundles()) {
- return Execution::NORMAL;
- }
-
- switch (_type) {
- case Type::BUNDLE_BEGIN:
- if (_depth == 1) {
- return Execution::BLOCK;
- }
- break;
- case Type::BUNDLE_END:
- if (_depth == 0) {
- return Execution::UNBLOCK;
- }
- break;
- }
- return Execution::NORMAL;
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Mark.hpp b/src/server/events/Mark.hpp
deleted file mode 100644
index eaeb9332..00000000
--- a/src/server/events/Mark.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- 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_EVENTS_MARK_HPP
-#define INGEN_EVENTS_MARK_HPP
-
-#include "Event.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class Engine;
-
-namespace Events {
-
-/** Delineate the start or end of a bundle of events.
- *
- * This is used to mark the ends of an undo transaction, so a single undo can
- * undo the effects of many events (such as a paste or a graph load).
- *
- * \ingroup engine
- */
-class Mark : public Event
-{
-public:
- Mark(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::BundleBegin& msg);
-
- Mark(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::BundleEnd& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
-
- Execution get_execution() const;
-
-private:
- enum class Type { BUNDLE_BEGIN, BUNDLE_END };
-
- typedef std::map<GraphImpl*, MPtr<CompiledGraph>> CompiledGraphs;
-
- CompiledGraphs _compiled_graphs;
- Type _type;
- int _depth;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_MARK_HPP
diff --git a/src/server/events/Move.cpp b/src/server/events/Move.cpp
deleted file mode 100644
index b0935675..00000000
--- a/src/server/events/Move.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Store.hpp"
-#include "raul/Path.hpp"
-
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "Driver.hpp"
-#include "Engine.hpp"
-#include "EnginePort.hpp"
-#include "GraphImpl.hpp"
-#include "events/Move.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Move::Move(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Move& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _msg(msg)
-{
-}
-
-bool
-Move::pre_process(PreProcessContext& ctx)
-{
- std::lock_guard<Store::Mutex> lock(_engine.store()->mutex());
-
- if (!_msg.old_path.parent().is_parent_of(_msg.new_path)) {
- return Event::pre_process_done(Status::PARENT_DIFFERS, _msg.new_path);
- }
-
- const Store::iterator i = _engine.store()->find(_msg.old_path);
- if (i == _engine.store()->end()) {
- return Event::pre_process_done(Status::NOT_FOUND, _msg.old_path);
- }
-
- if (_engine.store()->find(_msg.new_path) != _engine.store()->end()) {
- return Event::pre_process_done(Status::EXISTS, _msg.new_path);
- }
-
- EnginePort* eport = _engine.driver()->get_port(_msg.old_path);
- if (eport) {
- _engine.driver()->rename_port(_msg.old_path, _msg.new_path);
- }
-
- _engine.store()->rename(i, _msg.new_path);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Move::execute(RunContext& context)
-{
-}
-
-void
-Move::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS) {
- _engine.broadcaster()->message(_msg);
- }
-}
-
-void
-Move::undo(Interface& target)
-{
- target.move(_msg.new_path, _msg.old_path);
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Move.hpp b/src/server/events/Move.hpp
deleted file mode 100644
index 459d2709..00000000
--- a/src/server/events/Move.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- 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_EVENTS_MOVE_HPP
-#define INGEN_EVENTS_MOVE_HPP
-
-#include "ingen/Store.hpp"
-#include "raul/Path.hpp"
-
-#include "Event.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class GraphImpl;
-class PortImpl;
-
-namespace Events {
-
-/** Move a graph object to a new path.
- * \ingroup engine
- */
-class Move : public Event
-{
-public:
- Move(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Move& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
- void undo(Interface& target);
-
-private:
- const Ingen::Move _msg;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_MOVE_HPP
diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp
deleted file mode 100644
index 62f2def6..00000000
--- a/src/server/events/SetPortValue.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/LV2Features.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-
-#include "BlockImpl.hpp"
-#include "Broadcaster.hpp"
-#include "Buffer.hpp"
-#include "ControlBindings.hpp"
-#include "Engine.hpp"
-#include "PortImpl.hpp"
-#include "RunContext.hpp"
-#include "SetPortValue.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-/** Internal */
-SetPortValue::SetPortValue(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- PortImpl* port,
- const Atom& value,
- bool activity,
- bool synthetic)
- : Event(engine, client, id, timestamp)
- , _port(port)
- , _value(value)
- , _activity(activity)
- , _synthetic(synthetic)
-{
-}
-
-bool
-SetPortValue::pre_process(PreProcessContext& ctx)
-{
- Ingen::URIs& uris = _engine.world()->uris();
- if (_port->is_output()) {
- return Event::pre_process_done(Status::DIRECTION_MISMATCH, _port->path());
- }
-
- if (!_activity) {
- // Set value metadata (does not affect buffers)
- _port->set_value(_value);
- _port->set_property(_engine.world()->uris().ingen_value, _value);
- }
-
- _binding = _engine.control_bindings()->port_binding(_port);
-
- if (_port->buffer_type() == uris.atom_Sequence) {
- _buffer = _engine.buffer_factory()->get_buffer(
- _port->buffer_type(),
- _value.type() == uris.atom_Float ? _value.type() : 0,
- _engine.buffer_factory()->default_size(_port->buffer_type()));
- }
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-SetPortValue::execute(RunContext& context)
-{
- assert(_time >= context.start() && _time <= context.end());
- apply(context);
- _engine.control_bindings()->port_value_changed(context, _port, _binding, _value);
-}
-
-void
-SetPortValue::apply(RunContext& context)
-{
- if (_status != Status::SUCCESS) {
- return;
- }
-
- Ingen::URIs& uris = _engine.world()->uris();
- Buffer* buf = _port->buffer(0).get();
-
- if (_buffer) {
- if (_port->user_buffer(context)) {
- buf = _port->user_buffer(context).get();
- } else {
- _port->set_user_buffer(context, _buffer);
- buf = _buffer.get();
- }
- }
-
- if (buf->type() == uris.atom_Sound || buf->type() == uris.atom_Float) {
- if (_value.type() == uris.forge.Float) {
- _port->set_control_value(context, _time, _value.get<float>());
- } else {
- _status = Status::TYPE_MISMATCH;
- }
- } else if (buf->type() == uris.atom_Sequence) {
- if (!buf->append_event(_time - context.start(),
- _value.size(),
- _value.type(),
- (const uint8_t*)_value.get_body())) {
- _status = Status::NO_SPACE;
- }
- } else if (buf->type() == uris.atom_URID) {
- buf->get<LV2_Atom_URID>()->body = _value.get<int32_t>();
- } else {
- _status = Status::BAD_VALUE_TYPE;
- }
-}
-
-void
-SetPortValue::post_process()
-{
- Broadcaster::Transfer t(*_engine.broadcaster());
- if (respond() == Status::SUCCESS && !_activity) {
- _engine.broadcaster()->set_property(
- _port->uri(),
- _engine.world()->uris().ingen_value,
- _value);
- }
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp
deleted file mode 100644
index 4df60019..00000000
--- a/src/server/events/SetPortValue.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- 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_EVENTS_SETPORTVALUE_HPP
-#define INGEN_EVENTS_SETPORTVALUE_HPP
-
-#include "ingen/Atom.hpp"
-
-#include "BufferRef.hpp"
-#include "ControlBindings.hpp"
-#include "Event.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class PortImpl;
-
-namespace Events {
-
-/** An event to change the value of a port.
- *
- * \ingroup engine
- */
-class SetPortValue : public Event
-{
-public:
- SetPortValue(Engine& engine,
- SPtr<Interface> client,
- int32_t id,
- SampleCount timestamp,
- PortImpl* port,
- const Atom& value,
- bool activity,
- bool synthetic = false);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
-
- bool synthetic() const { return _synthetic; }
-
-private:
- void apply(RunContext& context);
-
- PortImpl* _port;
- const Atom _value;
- BufferRef _buffer;
- ControlBindings::Key _binding;
- bool _activity;
- bool _synthetic;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_SETPORTVALUE_HPP
diff --git a/src/server/events/Undo.cpp b/src/server/events/Undo.cpp
deleted file mode 100644
index e06a5951..00000000
--- a/src/server/events/Undo.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 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/>.
-*/
-
-#include "ingen/AtomReader.hpp"
-
-#include "Engine.hpp"
-#include "EventWriter.hpp"
-#include "Undo.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-Undo::Undo(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Undo& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _is_redo(false)
-{}
-
-Undo::Undo(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Redo& msg)
- : Event(engine, client, msg.seq, timestamp)
- , _is_redo(true)
-{}
-
-bool
-Undo::pre_process(PreProcessContext& ctx)
-{
- const UPtr<UndoStack>& stack = _is_redo ? _engine.redo_stack() : _engine.undo_stack();
- const Event::Mode mode = _is_redo ? Event::Mode::REDO : Event::Mode::UNDO;
-
- if (stack->empty()) {
- return Event::pre_process_done(Status::NOT_FOUND);
- }
-
- const Event::Mode orig_mode = _engine.event_writer()->get_event_mode();
- _entry = stack->pop();
- _engine.event_writer()->set_event_mode(mode);
- if (_entry.events.size() > 1) {
- _engine.interface()->bundle_begin();
- }
-
- for (const LV2_Atom* ev : _entry.events) {
- _engine.atom_interface()->write(ev);
- }
-
- if (_entry.events.size() > 1) {
- _engine.interface()->bundle_end();
- }
- _engine.event_writer()->set_event_mode(orig_mode);
-
- return Event::pre_process_done(Status::SUCCESS);
-}
-
-void
-Undo::execute(RunContext& context)
-{
-}
-
-void
-Undo::post_process()
-{
- respond();
-}
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/events/Undo.hpp b/src/server/events/Undo.hpp
deleted file mode 100644
index af4b0d65..00000000
--- a/src/server/events/Undo.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 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_EVENTS_UNDO_HPP
-#define INGEN_EVENTS_UNDO_HPP
-
-#include "Event.hpp"
-#include "UndoStack.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Events {
-
-/** A request to undo the last change to the engine.
- *
- * \ingroup engine
- */
-class Undo : public Event
-{
-public:
- Undo(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Undo& msg);
-
- Undo(Engine& engine,
- SPtr<Interface> client,
- SampleCount timestamp,
- const Ingen::Redo& msg);
-
- bool pre_process(PreProcessContext& ctx);
- void execute(RunContext& context);
- void post_process();
-
-private:
- UndoStack::Entry _entry;
- bool _is_redo;
-};
-
-} // namespace Events
-} // namespace Server
-} // namespace Ingen
-
-#endif // INGEN_EVENTS_UNDO_HPP
diff --git a/src/server/ingen_engine.cpp b/src/server/ingen_engine.cpp
deleted file mode 100644
index 3409f1bf..00000000
--- a/src/server/ingen_engine.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Module.hpp"
-#include "ingen/World.hpp"
-#include "Engine.hpp"
-#include "EventWriter.hpp"
-#include "util.hpp"
-
-using namespace Ingen;
-
-struct IngenEngineModule : public Ingen::Module {
- virtual void load(Ingen::World* world) {
- Server::set_denormal_flags(world->log());
- SPtr<Server::Engine> engine(new Server::Engine(world));
- world->set_engine(engine);
- if (!world->interface()) {
- world->set_interface(engine->interface());
- }
- }
-};
-
-extern "C" {
-
-Ingen::Module*
-ingen_module_load()
-{
- return new IngenEngineModule();
-}
-
-} // extern "C"
diff --git a/src/server/ingen_jack.cpp b/src/server/ingen_jack.cpp
deleted file mode 100644
index a897f130..00000000
--- a/src/server/ingen_jack.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <string>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/World.hpp"
-
-#include "JackDriver.hpp"
-#include "Engine.hpp"
-
-using namespace Ingen;
-
-struct IngenJackModule : public Ingen::Module {
- void load(Ingen::World* world) {
- if (((Server::Engine*)world->engine().get())->driver()) {
- world->log().warn("Engine already has a driver\n");
- return;
- }
-
- Server::JackDriver* driver = new Server::JackDriver(
- *(Server::Engine*)world->engine().get());
- const Atom& s = world->conf().option("jack-server");
- const std::string server_name = s.is_valid() ? s.ptr<char>() : "";
- driver->attach(server_name,
- world->conf().option("jack-name").ptr<char>(),
- nullptr);
- ((Server::Engine*)world->engine().get())->set_driver(
- SPtr<Server::Driver>(driver));
- }
-};
-
-extern "C" {
-
-Ingen::Module*
-ingen_module_load()
-{
- return new IngenJackModule();
-}
-
-} // extern "C"
diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp
deleted file mode 100644
index b2806ab6..00000000
--- a/src/server/ingen_lv2.cpp
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
-#include "lv2/lv2plug.in/ns/ext/log/log.h"
-#include "lv2/lv2plug.in/ns/ext/log/logger.h"
-#include "lv2/lv2plug.in/ns/ext/options/options.h"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-#include "ingen/AtomReader.hpp"
-#include "ingen/AtomWriter.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/World.hpp"
-#include "ingen/ingen.h"
-#include "ingen/runtime_paths.hpp"
-#include "ingen/types.hpp"
-#include "raul/Semaphore.hpp"
-
-#include "Buffer.hpp"
-#include "Driver.hpp"
-#include "Engine.hpp"
-#include "EnginePort.hpp"
-#include "EventWriter.hpp"
-#include "GraphImpl.hpp"
-#include "PostProcessor.hpp"
-#include "RunContext.hpp"
-#include "ThreadManager.hpp"
-
-#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#"
-
-namespace Ingen {
-
-/** Record of a graph in this bundle. */
-struct LV2Graph : public Parser::ResourceRecord {
- LV2Graph(Parser::ResourceRecord record);
-
- LV2_Descriptor descriptor;
-};
-
-/** Ingen LV2 library. */
-class Lib {
-public:
- explicit Lib(const char* bundle_path);
-
- typedef std::vector< SPtr<const LV2Graph> > Graphs;
-
- Graphs graphs;
-};
-
-namespace Server {
-
-class LV2Driver;
-
-void signal_main(RunContext& context, LV2Driver* driver);
-
-inline size_t
-ui_ring_size(SampleCount block_length)
-{
- return std::max((size_t)8192, (size_t)block_length * 16);
-}
-
-class LV2Driver : public Ingen::Server::Driver
- , public Ingen::AtomSink
-{
-public:
- LV2Driver(Engine& engine,
- SampleCount block_length,
- size_t seq_size,
- SampleCount sample_rate)
- : _engine(engine)
- , _main_sem(0)
- , _reader(engine.world()->uri_map(),
- engine.world()->uris(),
- engine.world()->log(),
- *engine.world()->interface().get())
- , _writer(engine.world()->uri_map(),
- engine.world()->uris(),
- *this)
- , _from_ui(ui_ring_size(block_length))
- , _to_ui(ui_ring_size(block_length))
- , _root_graph(nullptr)
- , _notify_capacity(0)
- , _block_length(block_length)
- , _seq_size(seq_size)
- , _sample_rate(sample_rate)
- , _frame_time(0)
- , _to_ui_overflow_sem(0)
- , _to_ui_overflow(false)
- , _instantiated(false)
- {}
-
- virtual bool dynamic_ports() const { return !_instantiated; }
-
- void pre_process_port(RunContext& context, EnginePort* port) {
- const URIs& uris = _engine.world()->uris();
- const SampleCount nframes = context.nframes();
- DuplexPort* graph_port = port->graph_port();
- Buffer* graph_buf = graph_port->buffer(0).get();
- void* lv2_buf = port->buffer();
-
- if (graph_port->is_a(PortType::AUDIO) || graph_port->is_a(PortType::CV)) {
- graph_port->set_driver_buffer(lv2_buf, nframes * sizeof(float));
- } else if (graph_port->buffer_type() == uris.atom_Sequence) {
- graph_port->set_driver_buffer(lv2_buf, lv2_atom_total_size((LV2_Atom*)lv2_buf));
- if (graph_port->symbol() == "control") { // TODO: Safe to use index?
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_buf;
- bool enqueued = false;
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (AtomReader::is_message(uris, &ev->body)) {
- enqueued = enqueue_message(&ev->body) || enqueued;
- }
- }
-
- if (enqueued) {
- // Enqueued a message for processing, raise semaphore
- _main_sem.post();
- }
- }
- }
-
- if (graph_port->is_input()) {
- graph_port->monitor(context);
- } else {
- graph_buf->prepare_write(context);
- }
- }
-
- void post_process_port(RunContext& context, EnginePort* port) {
- DuplexPort* graph_port = port->graph_port();
-
- // No copying necessary, host buffers are used directly
- // Reset graph port buffer pointer to no longer point to the Jack buffer
- if (graph_port->is_driver_port()) {
- graph_port->set_driver_buffer(nullptr, 0);
- }
- }
-
- void run(uint32_t nframes) {
- _engine.locate(_frame_time, nframes);
-
- // Notify buffer is a Chunk with size set to the available space
- _notify_capacity = ((LV2_Atom_Sequence*)_ports[1]->buffer())->atom.size;
-
- for (auto& p : _ports) {
- pre_process_port(_engine.run_context(), p);
- }
-
- _engine.run(nframes);
- if (_engine.post_processor()->pending()) {
- _main_sem.post();
- }
-
- flush_to_ui(_engine.run_context());
-
- for (auto& p : _ports) {
- post_process_port(_engine.run_context(), p);
- }
-
- _frame_time += nframes;
- }
-
- virtual void deactivate() {
- _engine.quit();
- _main_sem.post();
- }
-
- virtual void set_root_graph(GraphImpl* graph) { _root_graph = graph; }
- virtual GraphImpl* root_graph() { return _root_graph; }
-
- virtual EnginePort* get_port(const Raul::Path& path) {
- for (auto& p : _ports) {
- if (p->graph_port()->path() == path) {
- return p;
- }
- }
-
- return nullptr;
- }
-
- /** Add a port. Called only during init or restore. */
- virtual void add_port(RunContext& context, EnginePort* port) {
- const uint32_t index = port->graph_port()->index();
- if (_ports.size() <= index) {
- _ports.resize(index + 1);
- }
- _ports[index] = port;
- }
-
- /** Remove a port. Called only during init or restore. */
- virtual void remove_port(RunContext& context, EnginePort* port) {
- const uint32_t index = port->graph_port()->index();
- _ports[index] = nullptr;
- }
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void register_port(EnginePort& port) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void unregister_port(EnginePort& port) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void rename_port(const Raul::Path& old_path,
- const Raul::Path& new_path) {}
-
- /** Unused since LV2 has no dynamic ports. */
- virtual void port_property(const Raul::Path& path,
- const URI& uri,
- const Atom& value) {}
-
- virtual EnginePort* create_port(DuplexPort* graph_port) {
- graph_port->set_is_driver_port(*_engine.buffer_factory());
- return new EnginePort(graph_port);
- }
-
- virtual void append_time_events(RunContext& context,
- Buffer& buffer)
- {
- const URIs& uris = _engine.world()->uris();
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)_ports[0]->buffer();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- if (ev->body.type == uris.atom_Object) {
- const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == uris.time_Position) {
- buffer.append_event(ev->time.frames,
- ev->body.size,
- ev->body.type,
- (const uint8_t*)(&ev->body + 1));
- }
- }
- }
- }
-
- virtual int real_time_priority() { return 60; }
-
- /** Called in run thread for events received at control input port. */
- bool enqueue_message(const LV2_Atom* atom) {
- if (_from_ui.write(lv2_atom_total_size(atom), atom) == 0) {
-#ifndef NDEBUG
- _engine.log().error("Control input buffer overflow\n");
-#endif
- return false;
- }
- return true;
- }
-
- Raul::Semaphore& main_sem() { return _main_sem; }
-
- /** AtomSink::write implementation called by the PostProcessor in the main
- * thread to write responses to the UI.
- */
- bool write(const LV2_Atom* atom, int32_t default_id) {
- // Called from post-processor in main thread
- while (_to_ui.write(lv2_atom_total_size(atom), atom) == 0) {
- // Overflow, wait until ring is drained next cycle
- _to_ui_overflow = true;
- _to_ui_overflow_sem.wait();
- _to_ui_overflow = false;
- }
- return true;
- }
-
- void consume_from_ui() {
- const uint32_t read_space = _from_ui.read_space();
- void* buf = nullptr;
- for (uint32_t read = 0; read < read_space;) {
- LV2_Atom atom;
- if (!_from_ui.read(sizeof(LV2_Atom), &atom)) {
- _engine.log().rt_error("Error reading head from from-UI ring\n");
- break;
- }
-
- buf = realloc(buf, sizeof(LV2_Atom) + atom.size);
- memcpy(buf, &atom, sizeof(LV2_Atom));
-
- if (!_from_ui.read(atom.size, (char*)buf + sizeof(LV2_Atom))) {
- _engine.log().rt_error("Error reading body from from-UI ring\n");
- break;
- }
-
- _reader.write((LV2_Atom*)buf);
- read += sizeof(LV2_Atom) + atom.size;
- }
- free(buf);
- }
-
- void flush_to_ui(RunContext& context) {
- if (_ports.size() < 2) {
- _engine.log().rt_error("Standard control ports are not present\n");
- return;
- }
-
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)_ports[1]->buffer();
- if (!seq) {
- _engine.log().rt_error("Notify output not connected\n");
- return;
- }
-
- // Initialise output port buffer to an empty Sequence
- seq->atom.type = _engine.world()->uris().atom_Sequence;
- seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
-
- const uint32_t read_space = _to_ui.read_space();
- for (uint32_t read = 0; read < read_space;) {
- LV2_Atom atom;
- if (!_to_ui.peek(sizeof(LV2_Atom), &atom)) {
- _engine.log().rt_error("Error reading head from to-UI ring\n");
- break;
- }
-
- if (seq->atom.size + lv2_atom_pad_size(
- sizeof(LV2_Atom_Event) + atom.size)
- > _notify_capacity) {
- break; // Output port buffer full, resume next time
- }
-
- LV2_Atom_Event* ev = (LV2_Atom_Event*)(
- (uint8_t*)seq + lv2_atom_total_size(&seq->atom));
-
- ev->time.frames = 0; // TODO: Time?
- ev->body = atom;
-
- _to_ui.skip(sizeof(LV2_Atom));
- if (!_to_ui.read(ev->body.size, LV2_ATOM_BODY(&ev->body))) {
- _engine.log().rt_error("Error reading body from to-UI ring\n");
- break;
- }
-
- read += lv2_atom_total_size(&ev->body);
- seq->atom.size += lv2_atom_pad_size(
- sizeof(LV2_Atom_Event) + ev->body.size);
- }
-
- if (_to_ui_overflow) {
- _to_ui_overflow_sem.post();
- }
- }
-
- virtual SampleCount block_length() const { return _block_length; }
- virtual size_t seq_size() const { return _seq_size; }
- virtual SampleCount sample_rate() const { return _sample_rate; }
- virtual SampleCount frame_time() const { return _frame_time; }
-
- AtomReader& reader() { return _reader; }
- AtomWriter& writer() { return _writer; }
-
- typedef std::vector<EnginePort*> Ports;
-
- Ports& ports() { return _ports; }
-
- void set_instantiated(bool instantiated) { _instantiated = instantiated; }
-
-private:
- Engine& _engine;
- Ports _ports;
- Raul::Semaphore _main_sem;
- AtomReader _reader;
- AtomWriter _writer;
- Raul::RingBuffer _from_ui;
- Raul::RingBuffer _to_ui;
- GraphImpl* _root_graph;
- uint32_t _notify_capacity;
- SampleCount _block_length;
- size_t _seq_size;
- SampleCount _sample_rate;
- SampleCount _frame_time;
- Raul::Semaphore _to_ui_overflow_sem;
- bool _to_ui_overflow;
- bool _instantiated;
-};
-
-} // namespace Server
-} // namespace Ingen
-
-extern "C" {
-
-using namespace Ingen;
-using namespace Ingen::Server;
-
-static void
-ingen_lv2_main(SPtr<Engine> engine, const SPtr<LV2Driver>& driver)
-{
- while (true) {
- // Wait until there is work to be done
- driver->main_sem().wait();
-
- // Convert pending messages to events and push to pre processor
- driver->consume_from_ui();
-
- // Run post processor and maid to finalise events from last time
- if (!engine->main_iteration()) {
- return;
- }
- }
-}
-
-struct IngenPlugin {
- IngenPlugin()
- : world(nullptr)
- , main(nullptr)
- , map(nullptr)
- , argc(0)
- , argv(nullptr)
- {}
-
- Ingen::World* world;
- SPtr<Engine> engine;
- std::thread* main;
- LV2_URID_Map* map;
- int argc;
- char** argv;
-};
-
-static Lib::Graphs
-find_graphs(const URI& manifest_uri)
-{
- Sord::World world;
- Parser parser;
-
- const std::set<Parser::ResourceRecord> resources = parser.find_resources(
- world,
- manifest_uri,
- URI(INGEN__Graph));
-
- Lib::Graphs graphs;
- for (const auto& r : resources) {
- graphs.push_back(SPtr<const LV2Graph>(new LV2Graph(r)));
- }
-
- return graphs;
-}
-
-static LV2_Handle
-ingen_instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature*const* features)
-{
- // Get features from features array
- LV2_URID_Map* map = nullptr;
- LV2_URID_Unmap* unmap = nullptr;
- LV2_Log_Log* log = nullptr;
- const LV2_Options_Option* options = nullptr;
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID__map)) {
- map = (LV2_URID_Map*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_URID__unmap)) {
- unmap = (LV2_URID_Unmap*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_LOG__log)) {
- log = (LV2_Log_Log*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_OPTIONS__options)) {
- options = (const LV2_Options_Option*)features[i]->data;
- }
- }
-
- LV2_Log_Logger logger;
- lv2_log_logger_init(&logger, map, log);
-
- if (!map) {
- lv2_log_error(&logger, "host did not provide URI map feature\n");
- return nullptr;
- } else if (!unmap) {
- lv2_log_error(&logger, "host did not provide URI unmap feature\n");
- return nullptr;
- }
-
- set_bundle_path(bundle_path);
- const std::string manifest_path = Ingen::bundle_file_path("manifest.ttl");
- SerdNode manifest_node = serd_node_new_file_uri(
- (const uint8_t*)manifest_path.c_str(), nullptr, nullptr, true);
-
- Lib::Graphs graphs = find_graphs(URI((const char*)manifest_node.buf));
- serd_node_free(&manifest_node);
-
- const LV2Graph* graph = nullptr;
- for (const auto& g : graphs) {
- if (g->uri == descriptor->URI) {
- graph = g.get();
- break;
- }
- }
-
- if (!graph) {
- lv2_log_error(&logger, "could not find graph <%s>\n", descriptor->URI);
- return nullptr;
- }
-
- IngenPlugin* plugin = new IngenPlugin();
- plugin->map = map;
- plugin->world = new Ingen::World(map, unmap, log);
- plugin->world->load_configuration(plugin->argc, plugin->argv);
-
- LV2_URID bufsz_max = map->map(map->handle, LV2_BUF_SIZE__maxBlockLength);
- LV2_URID bufsz_seq = map->map(map->handle, LV2_BUF_SIZE__sequenceSize);
- LV2_URID atom_Int = map->map(map->handle, LV2_ATOM__Int);
- int32_t block_length = 0;
- int32_t seq_size = 0;
- if (options) {
- for (const LV2_Options_Option* o = options; o->key; ++o) {
- if (o->key == bufsz_max && o->type == atom_Int) {
- block_length = *(const int32_t*)o->value;
- } else if (o->key == bufsz_seq && o->type == atom_Int) {
- seq_size = *(const int32_t*)o->value;
- }
- }
- }
- if (block_length == 0) {
- block_length = 4096;
- plugin->world->log().warn("No maximum block length given\n");
- }
- if (seq_size == 0) {
- seq_size = 16384;
- plugin->world->log().warn("No maximum sequence size given\n");
- }
-
- plugin->world->log().info(
- fmt("Block: %1% frames, Sequence: %2% bytes\n")
- % block_length % seq_size);
- plugin->world->conf().set(
- "queue-size",
- plugin->world->forge().make(std::max(block_length, seq_size) * 4));
-
- SPtr<Server::Engine> engine(new Server::Engine(plugin->world));
- plugin->engine = engine;
- plugin->world->set_engine(engine);
-
- SPtr<Interface> interface = engine->interface();
-
- plugin->world->set_interface(interface);
-
- Server::ThreadManager::set_flag(Server::THREAD_PRE_PROCESS);
- Server::ThreadManager::single_threaded = true;
-
- LV2Driver* driver = new LV2Driver(*engine.get(), block_length, seq_size, rate);
- engine->set_driver(SPtr<Ingen::Server::Driver>(driver));
-
- engine->activate();
- Server::ThreadManager::single_threaded = true;
-
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
-
- // Locate to time 0 to process initialization events
- engine->locate(0, block_length);
- engine->post_processor()->set_end_time(block_length);
-
- // Parse graph, filling the queue with events to create it
- plugin->world->interface()->bundle_begin();
- plugin->world->parser()->parse_file(plugin->world,
- plugin->world->interface().get(),
- graph->filename);
- plugin->world->interface()->bundle_end();
-
- // Drain event queue
- while (engine->pending_events()) {
- engine->process_all_events();
- engine->post_processor()->process();
- engine->maid()->cleanup();
- }
-
- /* Register client after loading graph so the to-ui ring does not overflow.
- Since we are not yet rolling, it won't be drained, causing a deadlock. */
- SPtr<Interface> client(&driver->writer(), NullDeleter<Interface>);
- interface->set_respondee(client);
- engine->register_client(client);
-
- driver->set_instantiated(true);
- return (LV2_Handle)plugin;
-}
-
-static void
-ingen_connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- using namespace Ingen::Server;
-
- IngenPlugin* me = (IngenPlugin*)instance;
- Server::Engine* engine = (Server::Engine*)me->world->engine().get();
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
- if (port < driver->ports().size()) {
- driver->ports().at(port)->set_buffer(data);
- } else {
- engine->log().rt_error("Connect to non-existent port\n");
- }
-}
-
-static void
-ingen_activate(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- SPtr<Server::Engine> engine = static_ptr_cast<Server::Engine>(me->world->engine());
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
- engine->activate();
- me->main = new std::thread(ingen_lv2_main, engine, driver);
-}
-
-static void
-ingen_run(LV2_Handle instance, uint32_t sample_count)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- SPtr<Server::Engine> engine = static_ptr_cast<Server::Engine>(me->world->engine());
- const SPtr<LV2Driver>& driver = static_ptr_cast<LV2Driver>(engine->driver());
-
- Server::ThreadManager::set_flag(Ingen::Server::THREAD_PROCESS);
- Server::ThreadManager::set_flag(Ingen::Server::THREAD_IS_REAL_TIME);
-
- driver->run(sample_count);
-}
-
-static void
-ingen_deactivate(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- me->world->engine()->deactivate();
- if (me->main) {
- me->main->join();
- delete me->main;
- me->main = nullptr;
- }
-}
-
-static void
-ingen_cleanup(LV2_Handle instance)
-{
- IngenPlugin* me = (IngenPlugin*)instance;
- me->world->set_engine(SPtr<Ingen::Server::Engine>());
- me->world->set_interface(SPtr<Ingen::Interface>());
- if (me->main) {
- me->main->join();
- delete me->main;
- }
-
- World* world = me->world;
- delete me;
- delete world;
-}
-
-static void
-get_state_features(const LV2_Feature* const* features,
- LV2_State_Map_Path** map,
- LV2_State_Make_Path** make)
-{
- for (int i = 0; features[i]; ++i) {
- if (map && !strcmp(features[i]->URI, LV2_STATE__mapPath)) {
- *map = (LV2_State_Map_Path*)features[i]->data;
- } else if (make && !strcmp(features[i]->URI, LV2_STATE__makePath)) {
- *make = (LV2_State_Make_Path*)features[i]->data;
- }
- }
-}
-
-static LV2_State_Status
-ingen_save(LV2_Handle instance,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- IngenPlugin* plugin = (IngenPlugin*)instance;
-
- LV2_State_Map_Path* map_path = nullptr;
- LV2_State_Make_Path* make_path = nullptr;
- get_state_features(features, &map_path, &make_path);
- if (!map_path || !make_path || !plugin->map) {
- plugin->world->log().error("Missing state:mapPath, state:makePath, or urid:Map\n");
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- LV2_URID ingen_file = plugin->map->map(plugin->map->handle, INGEN__file);
- LV2_URID atom_Path = plugin->map->map(plugin->map->handle,
- LV2_ATOM__Path);
-
- char* real_path = make_path->path(make_path->handle, "main.ttl");
- char* state_path = map_path->abstract_path(map_path->handle, real_path);
-
- auto root = plugin->world->store()->find(Raul::Path("/"));
-
- {
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
-
- plugin->world->serialiser()->start_to_file(root->second->path(), real_path);
- plugin->world->serialiser()->serialise(root->second);
- plugin->world->serialiser()->finish();
- }
-
- store(handle,
- ingen_file,
- state_path,
- strlen(state_path) + 1,
- atom_Path,
- LV2_STATE_IS_POD);
-
- free(state_path);
- free(real_path);
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-ingen_restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- IngenPlugin* plugin = (IngenPlugin*)instance;
-
- LV2_State_Map_Path* map_path = nullptr;
- get_state_features(features, &map_path, nullptr);
- if (!map_path) {
- plugin->world->log().error("Missing state:mapPath\n");
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- LV2_URID ingen_file = plugin->map->map(plugin->map->handle, INGEN__file);
- size_t size;
- uint32_t type;
- uint32_t valflags;
-
- // Get abstract path to graph file
- const char* path = (const char*)retrieve(
- handle, ingen_file, &size, &type, &valflags);
- if (!path) {
- return LV2_STATE_ERR_NO_PROPERTY;
- }
-
- // Convert to absolute path
- char* real_path = map_path->absolute_path(map_path->handle, path);
- if (!real_path) {
- return LV2_STATE_ERR_UNKNOWN;
- }
-
-#if 0
- // Remove existing root graph contents
- SPtr<Engine> engine = plugin->engine;
- for (const auto& b : engine->root_graph()->blocks()) {
- plugin->world->interface()->del(b.uri());
- }
-
- const uint32_t n_ports = engine->root_graph()->num_ports_non_rt();
- for (int32_t i = n_ports - 1; i >= 0; --i) {
- PortImpl* port = engine->root_graph()->port_impl(i);
- if (port->symbol() != "control" && port->symbol() != "notify") {
- plugin->world->interface()->del(port->uri());
- }
- }
-#endif
-
- // Load new graph
- std::lock_guard<std::mutex> lock(plugin->world->rdf_mutex());
- plugin->world->parser()->parse_file(
- plugin->world, plugin->world->interface().get(), real_path);
-
- free(real_path);
- return LV2_STATE_SUCCESS;
-}
-
-static const void*
-ingen_extension_data(const char* uri)
-{
- static const LV2_State_Interface state = { ingen_save, ingen_restore };
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return nullptr;
-}
-
-LV2Graph::LV2Graph(Parser::ResourceRecord record)
- : Parser::ResourceRecord(std::move(record))
-{
- descriptor.URI = uri.c_str();
- descriptor.instantiate = ingen_instantiate;
- descriptor.connect_port = ingen_connect_port;
- descriptor.activate = ingen_activate;
- descriptor.run = ingen_run;
- descriptor.deactivate = ingen_deactivate;
- descriptor.cleanup = ingen_cleanup;
- descriptor.extension_data = ingen_extension_data;
-}
-
-Lib::Lib(const char* bundle_path)
-{
- Ingen::set_bundle_path(bundle_path);
- const std::string manifest_path = Ingen::bundle_file_path("manifest.ttl");
- SerdNode manifest_node = serd_node_new_file_uri(
- (const uint8_t*)manifest_path.c_str(), nullptr, nullptr, true);
-
- graphs = find_graphs(URI((const char*)manifest_node.buf));
-
- serd_node_free(&manifest_node);
-}
-
-static void
-lib_cleanup(LV2_Lib_Handle handle)
-{
- Lib* lib = (Lib*)handle;
- delete lib;
-}
-
-static const LV2_Descriptor*
-lib_get_plugin(LV2_Lib_Handle handle, uint32_t index)
-{
- Lib* lib = (Lib*)handle;
- return index < lib->graphs.size() ? &lib->graphs[index]->descriptor : nullptr;
-}
-
-/** LV2 plugin library entry point */
-LV2_SYMBOL_EXPORT
-const LV2_Lib_Descriptor*
-lv2_lib_descriptor(const char* bundle_path,
- const LV2_Feature*const* features)
-{
- static const uint32_t desc_size = sizeof(LV2_Lib_Descriptor);
- Lib* lib = new Lib(bundle_path);
-
- // FIXME: memory leak. I think the LV2_Lib_Descriptor API is botched :(
- LV2_Lib_Descriptor* desc = (LV2_Lib_Descriptor*)malloc(desc_size);
- desc->handle = lib;
- desc->size = desc_size;
- desc->cleanup = lib_cleanup;
- desc->get_plugin = lib_get_plugin;
-
- return desc;
-}
-
-} // extern "C"
diff --git a/src/server/ingen_portaudio.cpp b/src/server/ingen_portaudio.cpp
deleted file mode 100644
index e4065342..00000000
--- a/src/server/ingen_portaudio.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <string>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/World.hpp"
-
-#include "PortAudioDriver.hpp"
-#include "Engine.hpp"
-
-using namespace Ingen;
-
-struct IngenPortAudioModule : public Ingen::Module {
- void load(Ingen::World* world) {
- if (((Server::Engine*)world->engine().get())->driver()) {
- world->log().warn("Engine already has a driver\n");
- return;
- }
-
- Server::PortAudioDriver* driver = new Server::PortAudioDriver(
- *(Server::Engine*)world->engine().get());
- driver->attach();
- ((Server::Engine*)world->engine().get())->set_driver(
- SPtr<Server::Driver>(driver));
- }
-};
-
-extern "C" {
-
-Ingen::Module*
-ingen_module_load()
-{
- return new IngenPortAudioModule();
-}
-
-} // extern "C"
diff --git a/src/server/internals/BlockDelay.cpp b/src/server/internals/BlockDelay.cpp
deleted file mode 100644
index 6b27ed83..00000000
--- a/src/server/internals/BlockDelay.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <climits>
-
-#include <cmath>
-
-#include "ingen/URIs.hpp"
-#include "raul/Array.hpp"
-#include "raul/Maid.hpp"
-
-#include "Buffer.hpp"
-#include "InputPort.hpp"
-#include "InternalPlugin.hpp"
-#include "OutputPort.hpp"
-#include "RunContext.hpp"
-#include "internals/BlockDelay.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Internals {
-
-InternalPlugin* BlockDelayNode::internal_plugin(URIs& uris) {
- return new InternalPlugin(
- uris, URI(NS_INTERNALS "BlockDelay"), Raul::Symbol("blockDelay"));
-}
-
-BlockDelayNode::BlockDelayNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
- : InternalBlock(plugin, symbol, polyphonic, parent, srate)
-{
- const Ingen::URIs& uris = bufs.uris();
- _ports = bufs.maid().make_managed<Ports>(2);
-
- _in_port = new InputPort(bufs, this, Raul::Symbol("in"), 0, 1,
- PortType::AUDIO, 0, bufs.forge().make(0.0f));
- _in_port->set_property(uris.lv2_name, bufs.forge().alloc("In"));
- _ports->at(0) = _in_port;
-
- _out_port = new OutputPort(bufs, this, Raul::Symbol("out"), 0, 1,
- PortType::AUDIO, 0, bufs.forge().make(0.0f));
- _out_port->set_property(uris.lv2_name, bufs.forge().alloc("Out"));
- _ports->at(1) = _out_port;
-}
-
-BlockDelayNode::~BlockDelayNode()
-{
- _buffer.reset();
-}
-
-void
-BlockDelayNode::activate(BufferFactory& bufs)
-{
- _buffer = bufs.create(
- bufs.uris().atom_Sound, 0, bufs.audio_buffer_size());
-
- BlockImpl::activate(bufs);
-}
-
-void
-BlockDelayNode::run(RunContext& context)
-{
- // Copy buffer from last cycle to output
- _out_port->buffer(0)->copy(context, _buffer.get());
-
- // Copy input from this cycle to buffer
- _buffer->copy(context, _in_port->buffer(0).get());
-}
-
-} // namespace Internals
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/internals/BlockDelay.hpp b/src/server/internals/BlockDelay.hpp
deleted file mode 100644
index e1ef5311..00000000
--- a/src/server/internals/BlockDelay.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- 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_INTERNALS_BLOCKDELAY_HPP
-#define INGEN_INTERNALS_BLOCKDELAY_HPP
-
-#include "BufferRef.hpp"
-#include "InternalBlock.hpp"
-#include "types.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class InputPort;
-class OutputPort;
-class InternalPlugin;
-class BufferFactory;
-
-namespace Internals {
-
-class BlockDelayNode : public InternalBlock
-{
-public:
- BlockDelayNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate);
-
- ~BlockDelayNode();
-
- void activate(BufferFactory& bufs);
-
- void run(RunContext& context);
-
- static InternalPlugin* internal_plugin(URIs& uris);
-
-private:
- InputPort* _in_port;
- OutputPort* _out_port;
- BufferRef _buffer;
-};
-
-} // namespace Server
-} // namespace Ingen
-} // namespace Internals
-
-#endif // INGEN_INTERNALS_BLOCKDELAY_HPP
diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp
deleted file mode 100644
index 4c1cf45a..00000000
--- a/src/server/internals/Controller.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cmath>
-
-#include "ingen/URIs.hpp"
-#include "internals/Controller.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
-
-#include "Buffer.hpp"
-#include "Engine.hpp"
-#include "InputPort.hpp"
-#include "InternalPlugin.hpp"
-#include "OutputPort.hpp"
-#include "PostProcessor.hpp"
-#include "RunContext.hpp"
-#include "util.hpp"
-
-namespace Ingen {
-namespace Server {
-namespace Internals {
-
-InternalPlugin* ControllerNode::internal_plugin(URIs& uris) {
- return new InternalPlugin(
- uris, URI(NS_INTERNALS "Controller"), Raul::Symbol("controller"));
-}
-
-ControllerNode::ControllerNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
- : InternalBlock(plugin, symbol, false, parent, srate)
- , _learning(false)
-{
- const Ingen::URIs& uris = bufs.uris();
- _ports = bufs.maid().make_managed<Ports>(7);
-
- const Atom zero = bufs.forge().make(0.0f);
- const Atom one = bufs.forge().make(1.0f);
- const Atom atom_Float = bufs.forge().make_urid(URI(LV2_ATOM__Float));
-
- _midi_in_port = new InputPort(bufs, this, Raul::Symbol("input"), 0, 1,
- PortType::ATOM, uris.atom_Sequence, Atom());
- _midi_in_port->set_property(uris.lv2_name, bufs.forge().alloc("Input"));
- _midi_in_port->set_property(uris.atom_supports,
- bufs.forge().make_urid(uris.midi_MidiEvent));
- _ports->at(0) = _midi_in_port;
-
- _midi_out_port = new OutputPort(bufs, this, Raul::Symbol("event"), 1, 1,
- PortType::ATOM, uris.atom_Sequence, Atom());
- _midi_out_port->set_property(uris.lv2_name, bufs.forge().alloc("Event"));
- _midi_out_port->set_property(uris.atom_supports,
- bufs.forge().make_urid(uris.midi_MidiEvent));
- _ports->at(1) = _midi_out_port;
-
- _param_port = new InputPort(bufs, this, Raul::Symbol("controller"), 2, 1,
- PortType::ATOM, uris.atom_Sequence, zero);
- _param_port->set_property(uris.atom_supports, atom_Float);
- _param_port->set_property(uris.lv2_minimum, zero);
- _param_port->set_property(uris.lv2_maximum, bufs.forge().make(127.0f));
- _param_port->set_property(uris.lv2_portProperty, uris.lv2_integer);
- _param_port->set_property(uris.lv2_name, bufs.forge().alloc("Controller"));
- _ports->at(2) = _param_port;
-
- _log_port = new InputPort(bufs, this, Raul::Symbol("logarithmic"), 3, 1,
- PortType::ATOM, uris.atom_Sequence, zero);
- _log_port->set_property(uris.atom_supports, atom_Float);
- _log_port->set_property(uris.lv2_portProperty, uris.lv2_toggled);
- _log_port->set_property(uris.lv2_name, bufs.forge().alloc("Logarithmic"));
- _ports->at(3) = _log_port;
-
- _min_port = new InputPort(bufs, this, Raul::Symbol("minimum"), 4, 1,
- PortType::ATOM, uris.atom_Sequence, zero);
- _min_port->set_property(uris.atom_supports, atom_Float);
- _min_port->set_property(uris.lv2_name, bufs.forge().alloc("Minimum"));
- _ports->at(4) = _min_port;
-
- _max_port = new InputPort(bufs, this, Raul::Symbol("maximum"), 5, 1,
- PortType::ATOM, uris.atom_Sequence, one);
- _max_port->set_property(uris.atom_supports, atom_Float);
- _max_port->set_property(uris.lv2_name, bufs.forge().alloc("Maximum"));
- _ports->at(5) = _max_port;
-
- _audio_port = new OutputPort(bufs, this, Raul::Symbol("output"), 6, 1,
- PortType::ATOM, uris.atom_Sequence, zero);
- _audio_port->set_property(uris.atom_supports, atom_Float);
- _audio_port->set_property(uris.lv2_name, bufs.forge().alloc("Output"));
- _ports->at(6) = _audio_port;
-}
-
-void
-ControllerNode::run(RunContext& context)
-{
- const BufferRef midi_in = _midi_in_port->buffer(0);
- LV2_Atom_Sequence* seq = midi_in->get<LV2_Atom_Sequence>();
- const BufferRef midi_out = _midi_out_port->buffer(0);
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body);
- if (ev->body.type == _midi_in_port->bufs().uris().midi_MidiEvent &&
- ev->body.size >= 3 &&
- lv2_midi_message_type(buf) == LV2_MIDI_MSG_CONTROLLER) {
- if (control(context, buf[1], buf[2], ev->time.frames + context.start())) {
- midi_out->append_event(ev->time.frames, &ev->body);
- }
- }
- }
-}
-
-bool
-ControllerNode::control(RunContext& context, uint8_t control_num, uint8_t val, FrameTime time)
-{
- assert(time >= context.start() && time <= context.end());
- const uint32_t offset = time - context.start();
-
- const Sample nval = (val / 127.0f); // normalized [0, 1]
-
- if (_learning) {
- _param_port->set_control_value(context, time, control_num);
- _param_port->force_monitor_update();
- _learning = false;
- } else {
- _param_port->update_values(offset, 0);
- }
-
- if (control_num != _param_port->buffer(0)->value_at(offset)) {
- return false;
- }
-
- for (const auto& port : { _min_port, _max_port, _log_port }) {
- port->update_values(offset, 0);
- }
-
- const Sample min_port_val = _min_port->buffer(0)->value_at(offset);
- const Sample max_port_val = _max_port->buffer(0)->value_at(offset);
- const Sample log_port_val = _log_port->buffer(0)->value_at(offset);
-
- Sample scaled_value;
- if (log_port_val > 0.0f) {
- // haaaaack, stupid negatives and logarithms
- Sample log_offset = 0;
- if (min_port_val < 0) {
- log_offset = fabs(min_port_val);
- }
- const Sample min = log(min_port_val + 1 + log_offset);
- const Sample max = log(max_port_val + 1 + log_offset);
- scaled_value = expf(nval * (max - min) + min) - 1 - log_offset;
- } else {
- scaled_value = ((nval) * (max_port_val - min_port_val)) + min_port_val;
- }
-
- _audio_port->set_control_value(context, time, scaled_value);
-
- return true;
-}
-
-} // namespace Internals
-} // namespace Server
-} // namespace Ingen
diff --git a/src/server/internals/Controller.hpp b/src/server/internals/Controller.hpp
deleted file mode 100644
index 720f78c0..00000000
--- a/src/server/internals/Controller.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- 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_INTERNALS_CONTROLLER_HPP
-#define INGEN_INTERNALS_CONTROLLER_HPP
-
-#include "InternalBlock.hpp"
-
-namespace Ingen {
-namespace Server {
-
-class InputPort;
-class OutputPort;
-class InternalPlugin;
-
-namespace Internals {
-
-/** MIDI control input block.
- *
- * Creating one of these nodes is how a user makes "MIDI Bindings". Note that
- * this node will always be monophonic, the poly parameter is ignored.
- *
- * \ingroup engine
- */
-class ControllerNode : public InternalBlock
-{
-public:
- ControllerNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate);
-
- void run(RunContext& context);
-
- bool control(RunContext& context, uint8_t control_num, uint8_t val, FrameTime time);
-
- void learn() { _learning = true; }
-
- static InternalPlugin* internal_plugin(URIs& uris);
-
-private:
- InputPort* _midi_in_port;
- OutputPort* _midi_out_port;
- InputPort* _param_port;
- InputPort* _log_port;
- InputPort* _min_port;
- InputPort* _max_port;
- OutputPort* _audio_port;
- bool _learning;
-};
-
-} // namespace Server
-} // namespace Ingen
-} // namespace Internals
-
-#endif // INGEN_INTERNALS_CONTROLLER_HPP
diff --git a/src/server/internals/Note.cpp b/src/server/internals/Note.cpp
deleted file mode 100644
index b39dd1d4..00000000
--- a/src/server/internals/Note.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cmath>
-
-#include "ingen/URIs.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
-#include "raul/Array.hpp"
-#include "raul/Maid.hpp"
-
-#include "Buffer.hpp"
-#include "GraphImpl.hpp"
-#include "InputPort.hpp"
-#include "InternalPlugin.hpp"
-#include "OutputPort.hpp"
-#include "RunContext.hpp"
-#include "ingen_config.h"
-#include "internals/Note.hpp"
-#include "util.hpp"
-
-// #define NOTE_DEBUG 1
-
-namespace Ingen {
-namespace Server {
-namespace Internals {
-
-InternalPlugin* NoteNode::internal_plugin(URIs& uris) {
- return new InternalPlugin(
- uris, URI(NS_INTERNALS "Note"), Raul::Symbol("note"));
-}
-
-NoteNode::NoteNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
- : InternalBlock(plugin, symbol, polyphonic, parent, srate)
- , _voices(bufs.maid().make_managed<Voices>(_polyphony))
- , _sustain(false)
-{
- const Ingen::URIs& uris = bufs.uris();
- _ports = bufs.maid().make_managed<Ports>(8);
-
- const Atom zero = bufs.forge().make(0.0f);
- const Atom one = bufs.forge().make(1.0f);
-
- _midi_in_port = new InputPort(bufs, this, Raul::Symbol("input"), 0, 1,
- PortType::ATOM, uris.atom_Sequence, Atom());
- _midi_in_port->set_property(uris.lv2_name, bufs.forge().alloc("Input"));
- _midi_in_port->set_property(uris.atom_supports,
- bufs.forge().make_urid(uris.midi_MidiEvent));
- _ports->at(0) = _midi_in_port;
-
- _freq_port = new OutputPort(bufs, this, Raul::Symbol("frequency"), 1, _polyphony,
- PortType::ATOM, uris.atom_Sequence,
- bufs.forge().make(440.0f));
- _freq_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _freq_port->set_property(uris.lv2_name, bufs.forge().alloc("Frequency"));
- _freq_port->set_property(uris.lv2_minimum, bufs.forge().make(16.0f));
- _freq_port->set_property(uris.lv2_maximum, bufs.forge().make(25088.0f));
- _ports->at(1) = _freq_port;
-
- _num_port = new OutputPort(bufs, this, Raul::Symbol("number"), 1, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _num_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _num_port->set_property(uris.lv2_minimum, zero);
- _num_port->set_property(uris.lv2_maximum, bufs.forge().make(127.0f));
- _num_port->set_property(uris.lv2_portProperty, uris.lv2_integer);
- _num_port->set_property(uris.lv2_name, bufs.forge().alloc("Number"));
- _ports->at(2) = _num_port;
-
- _vel_port = new OutputPort(bufs, this, Raul::Symbol("velocity"), 2, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _vel_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _vel_port->set_property(uris.lv2_minimum, zero);
- _vel_port->set_property(uris.lv2_maximum, one);
- _vel_port->set_property(uris.lv2_name, bufs.forge().alloc("Velocity"));
- _ports->at(3) = _vel_port;
-
- _gate_port = new OutputPort(bufs, this, Raul::Symbol("gate"), 3, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _gate_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled);
- _gate_port->set_property(uris.lv2_name, bufs.forge().alloc("Gate"));
- _ports->at(4) = _gate_port;
-
- _trig_port = new OutputPort(bufs, this, Raul::Symbol("trigger"), 4, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _trig_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled);
- _trig_port->set_property(uris.lv2_name, bufs.forge().alloc("Trigger"));
- _ports->at(5) = _trig_port;
-
- _bend_port = new OutputPort(bufs, this, Raul::Symbol("bend"), 5, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _bend_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _bend_port->set_property(uris.lv2_name, bufs.forge().alloc("Bender"));
- _bend_port->set_property(uris.lv2_default, zero);
- _bend_port->set_property(uris.lv2_minimum, bufs.forge().make(-1.0f));
- _bend_port->set_property(uris.lv2_maximum, one);
- _ports->at(6) = _bend_port;
-
- _pressure_port = new OutputPort(bufs, this, Raul::Symbol("pressure"), 6, _polyphony,
- PortType::ATOM, uris.atom_Sequence, zero);
- _pressure_port->set_property(uris.atom_supports, bufs.uris().atom_Float);
- _pressure_port->set_property(uris.lv2_name, bufs.forge().alloc("Pressure"));
- _pressure_port->set_property(uris.lv2_default, zero);
- _pressure_port->set_property(uris.lv2_minimum, zero);
- _pressure_port->set_property(uris.lv2_maximum, one);
- _ports->at(7) = _pressure_port;
-}
-
-bool
-NoteNode::prepare_poly(BufferFactory& bufs, uint32_t poly)
-{
- if (!_polyphonic) {
- return true;
- }
-
- BlockImpl::prepare_poly(bufs, poly);
-
- if (_prepared_voices && poly <= _prepared_voices->size()) {
- return true;
- }
-
- _prepared_voices = bufs.maid().make_managed<Voices>(
- poly, *_voices, Voice());
-
- return true;
-}
-
-bool
-NoteNode::apply_poly(RunContext& context, uint32_t poly)
-{
- if (!BlockImpl::apply_poly(context, poly)) {
- return false;
- }
-
- if (_prepared_voices) {
- assert(_polyphony <= _prepared_voices->size());
- _voices = std::move(_prepared_voices);
- }
- assert(_polyphony <= _voices->size());
-
- return true;
-}
-
-void
-NoteNode::run(RunContext& context)
-{
- Buffer* const midi_in = _midi_in_port->buffer(0).get();
- LV2_Atom_Sequence* seq = midi_in->get<LV2_Atom_Sequence>();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY_CONST(&ev->body);
- const FrameTime time = context.start() + (FrameTime)ev->time.frames;
- if (ev->body.type == _midi_in_port->bufs().uris().midi_MidiEvent &&
- ev->body.size >= 3) {
- switch (lv2_midi_message_type(buf)) {
- case LV2_MIDI_MSG_NOTE_ON:
- if (buf[2] == 0) {
- note_off(context, buf[1], time);
- } else {
- note_on(context, buf[1], buf[2], time);
- }
- break;
- case LV2_MIDI_MSG_NOTE_OFF:
- note_off(context, buf[1], time);
- break;
- case LV2_MIDI_MSG_CONTROLLER:
- switch (buf[1]) {
- case LV2_MIDI_CTL_ALL_NOTES_OFF:
- case LV2_MIDI_CTL_ALL_SOUNDS_OFF:
- all_notes_off(context, time);
- break;
- case LV2_MIDI_CTL_SUSTAIN:
- if (buf[2] > 63) {
- sustain_on(context, time);
- } else {
- sustain_off(context, time);
- }
- break;
- }
- break;
- case LV2_MIDI_MSG_BENDER:
- bend(context, time, (((((uint16_t)buf[2] << 7) | buf[1]) - 8192.0f)
- / 8192.0f));
- break;
- case LV2_MIDI_MSG_CHANNEL_PRESSURE:
- channel_pressure(context, time, buf[1] / 127.0f);
- break;
- case LV2_MIDI_MSG_NOTE_PRESSURE:
- note_pressure(context, time, buf[1], buf[2] / 127.0f);
- break;
- default:
- break;
- }
- }
- }
-}
-
-static inline float
-note_to_freq(uint8_t num)
-{
- static const float A4 = 440.0f;
- return A4 * powf(2.0f, (float)(num - 57.0f) / 12.0f);
-}
-
-void
-NoteNode::note_on(RunContext& context, uint8_t note_num, uint8_t velocity, FrameTime time)
-{
- assert(time >= context.start() && time <= context.end());
- assert(note_num <= 127);
-
- Key* key = &_keys[note_num];
- Voice* voice = nullptr;
- uint32_t voice_num = 0;
-
- if (key->state != Key::State::OFF) {
- return;
- }
-
- // Look for free voices
- for (uint32_t i=0; i < _polyphony; ++i) {
- if ((*_voices)[i].state == Voice::State::FREE) {
- voice = &(*_voices)[i];
- voice_num = i;
- break;
- }
- }
-
- // If we didn't find a free one, steal the oldest
- if (voice == nullptr) {
- voice_num = 0;
- voice = &(*_voices)[0];
- FrameTime oldest_time = (*_voices)[0].time;
- for (uint32_t i=1; i < _polyphony; ++i) {
- if ((*_voices)[i].time < oldest_time) {
- voice = &(*_voices)[i];
- voice_num = i;
- oldest_time = voice->time;
- }
- }
- }
- assert(voice != nullptr);
- assert(voice == &(*_voices)[voice_num]);
-
- // Update stolen key, if applicable
- if (voice->state == Voice::State::ACTIVE) {
- assert(_keys[voice->note].state == Key::State::ON_ASSIGNED);
- assert(_keys[voice->note].voice == voice_num);
- _keys[voice->note].state = Key::State::ON_UNASSIGNED;
- }
-
- // Store key information for later reallocation on note off
- key->state = Key::State::ON_ASSIGNED;
- key->voice = voice_num;
- key->time = time;
-
- // Check if we just triggered this voice at the same time
- // (Double note-on at the same sample on the same voice)
- const bool double_trigger = (voice->state == Voice::State::ACTIVE &&
- voice->time == time);
-
- // Trigger voice
- voice->state = Voice::State::ACTIVE;
- voice->note = note_num;
- voice->time = time;
-
- assert(_keys[voice->note].state == Key::State::ON_ASSIGNED);
- assert(_keys[voice->note].voice == voice_num);
-
- _freq_port->set_voice_value(context, voice_num, time, note_to_freq(note_num));
- _num_port->set_voice_value(context, voice_num, time, (float)note_num);
- _vel_port->set_voice_value(context, voice_num, time, velocity / 127.0f);
- _gate_port->set_voice_value(context, voice_num, time, 1.0f);
- if (!double_trigger) {
- _trig_port->set_voice_value(context, voice_num, time, 1.0f);
- _trig_port->set_voice_value(context, voice_num, time + 1, 0.0f);
- }
-
- assert(key->state == Key::State::ON_ASSIGNED);
- assert(voice->state == Voice::State::ACTIVE);
- assert(key->voice == voice_num);
- assert((*_voices)[key->voice].note == note_num);
-}
-
-void
-NoteNode::note_off(RunContext& context, uint8_t note_num, FrameTime time)
-{
- assert(time >= context.start() && time <= context.end());
-
- Key* key = &_keys[note_num];
-
- if (key->state == Key::State::ON_ASSIGNED) {
- // Assigned key, turn off voice and key
- if ((*_voices)[key->voice].state == Voice::State::ACTIVE) {
- assert((*_voices)[key->voice].note == note_num);
- if ( ! _sustain) {
- free_voice(context, key->voice, time);
- } else {
- (*_voices)[key->voice].state = Voice::State::HOLDING;
- }
- }
- }
-
- key->state = Key::State::OFF;