258 lines
6.4 KiB
C++
258 lines
6.4 KiB
C++
/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
|
|
*
|
|
* Om is free software; you can redistribute it and/or modify it under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option) any later
|
|
* version.
|
|
*
|
|
* Om 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 General Public License for details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "ConnectionEvent.h"
|
|
#include <string>
|
|
#include "Responder.h"
|
|
#include "Om.h"
|
|
#include "OmApp.h"
|
|
#include "TypedConnection.h"
|
|
#include "InputPort.h"
|
|
#include "OutputPort.h"
|
|
#include "Patch.h"
|
|
#include "ClientBroadcaster.h"
|
|
#include "Port.h"
|
|
#include "Maid.h"
|
|
#include "ObjectStore.h"
|
|
#include "util/Path.h"
|
|
|
|
using std::string;
|
|
namespace Om {
|
|
|
|
|
|
//// ConnectionEvent ////
|
|
|
|
|
|
ConnectionEvent::ConnectionEvent(CountedPtr<Responder> responder, const string& src_port_path, const string& dst_port_path)
|
|
: QueuedEvent(responder),
|
|
m_src_port_path(src_port_path),
|
|
m_dst_port_path(dst_port_path),
|
|
m_patch(NULL),
|
|
m_src_port(NULL),
|
|
m_dst_port(NULL),
|
|
m_typed_event(NULL),
|
|
m_error(NO_ERROR)
|
|
{
|
|
}
|
|
|
|
|
|
ConnectionEvent::~ConnectionEvent()
|
|
{
|
|
delete m_typed_event;
|
|
}
|
|
|
|
|
|
void
|
|
ConnectionEvent::pre_process()
|
|
{
|
|
if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()
|
|
&& m_src_port_path.parent() != m_dst_port_path.parent().parent()
|
|
&& m_src_port_path.parent().parent() != m_dst_port_path.parent()) {
|
|
m_error = PARENT_PATCH_DIFFERENT;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
/*m_patch = om->object_store()->find_patch(m_src_port_path.parent().parent());
|
|
|
|
if (m_patch == NULL) {
|
|
m_error = PORT_NOT_FOUND;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}*/
|
|
|
|
m_src_port = om->object_store()->find_port(m_src_port_path);
|
|
m_dst_port = om->object_store()->find_port(m_dst_port_path);
|
|
|
|
if (m_src_port == NULL || m_dst_port == NULL) {
|
|
m_error = PORT_NOT_FOUND;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
if (m_src_port->type() != m_dst_port->type() || m_src_port->buffer_size() != m_dst_port->buffer_size()) {
|
|
m_error = TYPE_MISMATCH;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
/*if (port1->is_output() && port2->is_input()) {
|
|
m_src_port = port1;
|
|
m_dst_port = port2;
|
|
} else if (port2->is_output() && port1->is_input()) {
|
|
m_src_port = port2;
|
|
m_dst_port = port1;
|
|
} else {
|
|
m_error = TYPE_MISMATCH;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}*/
|
|
|
|
// Create the typed event to actually do the work
|
|
const DataType type = m_src_port->type();
|
|
if (type == DataType::FLOAT) {
|
|
m_typed_event = new TypedConnectionEvent<sample>(m_responder,
|
|
dynamic_cast<OutputPort<sample>*>(m_src_port), dynamic_cast<InputPort<sample>*>(m_dst_port));
|
|
} else if (type == DataType::MIDI) {
|
|
m_typed_event = new TypedConnectionEvent<MidiMessage>(m_responder,
|
|
dynamic_cast<OutputPort<MidiMessage>*>(m_src_port), dynamic_cast<InputPort<MidiMessage>*>(m_dst_port));
|
|
} else {
|
|
m_error = TYPE_MISMATCH;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
m_typed_event->pre_process();
|
|
|
|
QueuedEvent::pre_process();
|
|
}
|
|
|
|
|
|
void
|
|
ConnectionEvent::execute(samplecount offset)
|
|
{
|
|
QueuedEvent::execute(offset);
|
|
|
|
if (m_error == NO_ERROR)
|
|
m_typed_event->execute(offset);
|
|
}
|
|
|
|
|
|
void
|
|
ConnectionEvent::post_process()
|
|
{
|
|
if (m_error == NO_ERROR) {
|
|
m_typed_event->post_process();
|
|
} else {
|
|
// FIXME: better error messages
|
|
string msg = "Unable to make connection ";
|
|
msg.append(m_src_port_path + " -> " + m_dst_port_path);
|
|
m_responder->respond_error(msg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//// TypedConnectionEvent ////
|
|
|
|
|
|
template <typename T>
|
|
TypedConnectionEvent<T>::TypedConnectionEvent(CountedPtr<Responder> responder, OutputPort<T>* src_port, InputPort<T>* dst_port)
|
|
: QueuedEvent(responder),
|
|
m_src_port(src_port),
|
|
m_dst_port(dst_port),
|
|
m_patch(NULL),
|
|
m_process_order(NULL),
|
|
m_connection(NULL),
|
|
m_port_listnode(NULL),
|
|
m_succeeded(true)
|
|
{
|
|
assert(src_port != NULL);
|
|
assert(dst_port != NULL);
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
void
|
|
TypedConnectionEvent<T>::pre_process()
|
|
{
|
|
if (m_dst_port->is_connected_to(m_src_port)) {
|
|
m_succeeded = false;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
Node* const src_node = m_src_port->parent_node();
|
|
Node* const dst_node = m_dst_port->parent_node();
|
|
|
|
if (src_node->parent_patch() != dst_node->parent_patch()) {
|
|
// Connection to a patch port from inside the patch
|
|
assert(src_node->parent() == dst_node || dst_node->parent() == src_node);
|
|
if (src_node->parent() == dst_node)
|
|
m_patch = dynamic_cast<Patch*>(dst_node);
|
|
else
|
|
m_patch = dynamic_cast<Patch*>(src_node);
|
|
} else {
|
|
// Normal connection between nodes with the same parent
|
|
m_patch = src_node->parent_patch();
|
|
}
|
|
|
|
assert(m_patch);
|
|
|
|
if (src_node == NULL || dst_node == NULL) {
|
|
cerr << "ERR 1\n";
|
|
m_succeeded = false;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
if (src_node->parent() != m_patch && dst_node->parent() != m_patch) {
|
|
cerr << "ERR 2\n";
|
|
m_succeeded = false;
|
|
QueuedEvent::pre_process();
|
|
return;
|
|
}
|
|
|
|
m_connection = new TypedConnection<T>(m_src_port, m_dst_port);
|
|
m_port_listnode = new ListNode<TypedConnection<T>*>(m_connection);
|
|
m_patch_listnode = new ListNode<Connection*>(m_connection);
|
|
|
|
// Need to be careful about patch port connections here and adding a node's
|
|
// parent as a dependant/provider...
|
|
if (src_node->parent() == dst_node->parent()) {
|
|
dst_node->providers()->push_back(new ListNode<Node*>(src_node));
|
|
src_node->dependants()->push_back(new ListNode<Node*>(dst_node));
|
|
}
|
|
|
|
if (m_patch->process())
|
|
m_process_order = m_patch->build_process_order();
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
void
|
|
TypedConnectionEvent<T>::execute(samplecount offset)
|
|
{
|
|
if (m_succeeded) {
|
|
// These must be inserted here, since they're actually used by the audio thread
|
|
m_dst_port->add_connection(m_port_listnode);
|
|
m_patch->add_connection(m_patch_listnode);
|
|
if (m_patch->process_order() != NULL)
|
|
om->maid()->push(m_patch->process_order());
|
|
m_patch->process_order(m_process_order);
|
|
}
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
void
|
|
TypedConnectionEvent<T>::post_process()
|
|
{
|
|
if (m_succeeded) {
|
|
assert(m_connection != NULL);
|
|
|
|
m_responder->respond_ok();
|
|
|
|
om->client_broadcaster()->send_connection(m_connection);
|
|
} else {
|
|
m_responder->respond_error("Unable to make connection.");
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace Om
|
|
|