xybrid/xybrid/data/node.cpp

97 lines
3.3 KiB
C++

#include "node.h"
using namespace Xybrid::Data;
#include "data/graph.h"
#include "data/porttypes.h"
#include "config/pluginregistry.h"
#include <algorithm>
#include <QDebug>
Port::~Port() {
// clean up others' connection lists
while (connections.size() > 0) {
if (auto cc = connections.back().lock(); cc) cc->cleanConnections();
connections.pop_back();
}
}
bool Port::canConnectTo(DataType d) const {
return d == dataType();
}
bool Port::connect(std::shared_ptr<Port> p) {
if (!p) return false; // no blank pointers pls
// actual processing is always done on the input port, since that's where any limits are
if (type == Output) return p->type == Input && p->connect(shared_from_this());
if (!canConnectTo(p->dataType())) return false; // can't hook up to an incompatible data type
for (auto c : connections) if (c.lock() == p) return true; // I guess report success if already connected?
if (singleInput() && connections.size() > 0) return false; // reject multiple connections on single-input ports
// actually hook up
connections.emplace_back(p);
p->connections.emplace_back(shared_from_this());
return true;
}
void Port::disconnect(std::shared_ptr<Port> p) {
if (!p) return;
auto t = shared_from_this();
connections.erase(std::remove_if(connections.begin(), connections.end(), [p](auto w) { return w.lock() == p; }), connections.end());
p->connections.erase(std::remove_if(p->connections.begin(), p->connections.end(), [t](auto w) { return w.lock() == t; }), p->connections.end());
}
void Port::cleanConnections() {
connections.erase(std::remove_if(connections.begin(), connections.end(), [](auto w) { return !w.lock(); }), connections.end());
}
std::shared_ptr<Port> Port::makePort(DataType dt) {
if (dt == Audio) return std::make_shared<AudioPort>();
if (dt == Command) return std::make_shared<CommandPort>();
// fallback
return std::make_shared<Port>();
}
void Node::parentTo(std::shared_ptr<Graph> graph) {
auto t = shared_from_this(); // keep alive during reparenting
if (auto p = parent.lock(); p) {
p->children.erase(std::remove(p->children.begin(), p->children.end(), t), p->children.end());
}
parent = graph;
if (graph) {
graph->children.push_back(t);
}
}
std::shared_ptr<Port> Node::port(Port::Type t, Port::DataType dt, uint8_t idx, bool addIfNeeded) {
auto& m = t == Port::Input ? inputs : outputs;
if (auto mdt = m.find(dt); mdt != m.end()) {
if (auto it = mdt->second.find(idx); it != mdt->second.end()) return it->second;
}
return addIfNeeded ? addPort(t, dt, idx) : nullptr;
}
std::shared_ptr<Port> Node::addPort(Port::Type t, Port::DataType dt, uint8_t idx) {
auto& m = t == Port::Input ? inputs : outputs;
m.try_emplace(dt);
auto mdt = m.find(dt);
if (mdt->second.find(idx) == mdt->second.end()) {
auto p = Port::makePort(dt);
p->type = t;
mdt->second.insert({idx, p});
p->index = idx;
return p;
}
return nullptr;
}
void Node::removePort(Port::Type t, Port::DataType dt, uint8_t idx) {
auto& m = t == Port::Input ? inputs : outputs;
if (auto mdt = m.find(dt); mdt != m.end()) {
mdt->second.erase(idx);
}
}
std::string Node::pluginName() const { if (!plugin) return "(unknown plugin)"; return plugin->displayName; }