summaryrefslogtreecommitdiffstats
path: root/src/server/events/CreatePort.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/events/CreatePort.cpp')
-rw-r--r--src/server/events/CreatePort.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp
new file mode 100644
index 00000000..a79c85ef
--- /dev/null
+++ b/src/server/events/CreatePort.cpp
@@ -0,0 +1,219 @@
+/*
+ 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