From 2db1897709eba0e80677bd09e8444e7320e15120 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 19 Jun 2006 06:17:49 +0000 Subject: Connecting of patch ports internally (seemingly anyway, data not flowing yet) git-svn-id: http://svn.drobilla.net/lad/grauph@61 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/client/ConnectionModel.cpp | 24 +++++- src/libs/client/ConnectionModel.h | 2 +- src/libs/client/PatchModel.cpp | 12 ++- src/libs/client/Store.cpp | 16 ++-- src/libs/client/Store.h | 6 +- src/libs/engine/Buffer.cpp | 1 + src/libs/engine/ConnectionBase.cpp | 96 ---------------------- src/libs/engine/ConnectionBase.h | 105 ------------------------- src/libs/engine/Driver.h | 4 +- src/libs/engine/InputPort.cpp | 101 ++++++++++++------------ src/libs/engine/InputPort.h | 16 ++-- src/libs/engine/JackAudioDriver.cpp | 14 ++-- src/libs/engine/JackAudioDriver.h | 10 +-- src/libs/engine/JackMidiDriver.cpp | 6 +- src/libs/engine/JackMidiDriver.h | 14 ++-- src/libs/engine/Makefile.am | 6 +- src/libs/engine/MidiDriver.h | 2 +- src/libs/engine/ObjectSender.cpp | 2 +- src/libs/engine/OutputPort.cpp | 12 +-- src/libs/engine/OutputPort.h | 6 +- src/libs/engine/Patch.cpp | 41 ++++++---- src/libs/engine/Patch.h | 12 +-- src/libs/engine/TypedConnection.cpp | 96 ++++++++++++++++++++++ src/libs/engine/TypedConnection.h | 105 +++++++++++++++++++++++++ src/libs/engine/TypedPort.cpp | 8 +- src/libs/engine/TypedPort.h | 16 ++-- src/libs/engine/events/ConnectionEvent.cpp | 48 +++++++---- src/libs/engine/events/ConnectionEvent.h | 6 +- src/libs/engine/events/DisconnectNodeEvent.cpp | 2 +- src/libs/engine/events/DisconnectNodeEvent.h | 2 +- src/libs/engine/events/DisconnectionEvent.cpp | 8 +- src/libs/engine/events/DisconnectionEvent.h | 2 +- src/progs/gtk/PatchController.cpp | 13 ++- 33 files changed, 435 insertions(+), 379 deletions(-) delete mode 100644 src/libs/engine/ConnectionBase.cpp delete mode 100644 src/libs/engine/ConnectionBase.h create mode 100644 src/libs/engine/TypedConnection.cpp create mode 100644 src/libs/engine/TypedConnection.h diff --git a/src/libs/client/ConnectionModel.cpp b/src/libs/client/ConnectionModel.cpp index 1c7541b9..18b6fbd7 100644 --- a/src/libs/client/ConnectionModel.cpp +++ b/src/libs/client/ConnectionModel.cpp @@ -27,8 +27,8 @@ ConnectionModel::ConnectionModel(const Path& src_port, const Path& dst_port) m_dst_port(NULL) { // Be sure connection is within one patch - assert(m_src_port_path.parent().parent() - == m_dst_port_path.parent().parent()); + //assert(m_src_port_path.parent().parent() + // == m_dst_port_path.parent().parent()); } @@ -51,4 +51,24 @@ ConnectionModel::dst_port_path() const return m_dst_port->path(); } +const Path +ConnectionModel::patch_path() const +{ + const Path& src_node = m_src_port_path.parent(); + const Path& dst_node = m_dst_port_path.parent(); + Path patch_path = src_node.parent(); + + if (src_node.parent() != dst_node.parent()) { + // 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) + patch_path = dst_node; + else + patch_path = src_node; + } + + return patch_path; +} + + } // namespace LibOmClient diff --git a/src/libs/client/ConnectionModel.h b/src/libs/client/ConnectionModel.h index ef909850..427c5858 100644 --- a/src/libs/client/ConnectionModel.h +++ b/src/libs/client/ConnectionModel.h @@ -55,7 +55,7 @@ public: const Path& src_port_path() const; const Path& dst_port_path() const; - const Path patch_path() const { return src_port_path().parent().parent(); } + const Path patch_path() const; private: Path m_src_port_path; ///< Only used if m_src_port == NULL diff --git a/src/libs/client/PatchModel.cpp b/src/libs/client/PatchModel.cpp index 7d786301..265a17d8 100644 --- a/src/libs/client/PatchModel.cpp +++ b/src/libs/client/PatchModel.cpp @@ -163,19 +163,23 @@ void PatchModel::add_connection(CountedPtr cm) { assert(cm); - assert(cm->src_port_path().parent().parent() == m_path); - assert(cm->dst_port_path().parent().parent() == m_path); + //assert(cm->src_port_path().parent().parent() == m_path); + //assert(cm->dst_port_path().parent().parent() == m_path); assert(cm->patch_path() == path()); + cerr << "PatchModel::add_connection: " << cm->src_port_path() << " -> " << cm->dst_port_path() << endl; + CountedPtr existing = get_connection(cm->src_port_path(), cm->dst_port_path()); if (existing) { return; } - NodeModel* src_node = get_node(cm->src_port_path().parent().name()).get(); + NodeModel* src_node = (cm->src_port_path().parent() == path()) + ? this : get_node(cm->src_port_path().parent().name()).get(); PortModel* src_port = (src_node == NULL) ? NULL : src_node->get_port(cm->src_port_path().name()).get(); - NodeModel* dst_node = get_node(cm->dst_port_path().parent().name()).get(); + NodeModel* dst_node = (cm->dst_port_path().parent() == path()) + ? this : get_node(cm->dst_port_path().parent().name()).get(); PortModel* dst_port = (dst_node == NULL) ? NULL : dst_node->get_port(cm->dst_port_path().name()).get(); assert(src_port != NULL); diff --git a/src/libs/client/Store.cpp b/src/libs/client/Store.cpp index 542c1bc5..15f91786 100644 --- a/src/libs/client/Store.cpp +++ b/src/libs/client/Store.cpp @@ -311,24 +311,22 @@ Store::metadata_update_event(const string& subject_path, const string& predicate void -Store::connection_event(const string& src_port_path, const string& dst_port_path) +Store::connection_event(const Path& src_port_path, const Path& dst_port_path) { - const Path& src = src_port_path; - const Path& dst = dst_port_path; - - assert(src.parent().parent() == dst.parent().parent()); - const Path& patch_path = src.parent().parent(); + // ConnectionModel has the clever patch-path-figuring-out stuff in it, so + // just make one right away to get at that + ConnectionModel* cm = new ConnectionModel(src_port_path, dst_port_path); - CountedPtr patch = this->patch(patch_path); + CountedPtr patch = this->patch(cm->patch_path()); if (patch) - patch->add_connection(new ConnectionModel(src, dst)); + patch->add_connection(cm); else cerr << "ERROR: connection in nonexistant patch" << endl; } void -Store::disconnection_event(const string& src_port_path, const string& dst_port_path) +Store::disconnection_event(const Path& src_port_path, const Path& dst_port_path) { const Path& src = src_port_path; const Path& dst = dst_port_path; diff --git a/src/libs/client/Store.h b/src/libs/client/Store.h index 0b84d418..0e47168d 100644 --- a/src/libs/client/Store.h +++ b/src/libs/client/Store.h @@ -22,7 +22,9 @@ #include #include "util/CountedPtr.h" #include +#include "util/Path.h" using std::string; using std::map; +using Om::Path; namespace LibOmClient { @@ -71,8 +73,8 @@ private: void new_node_event(const string& plugin_type, const string& plugin_uri, const string& node_path, bool is_polyphonic, uint32_t num_ports); void new_port_event(const string& path, const string& data_type, bool is_output); void metadata_update_event(const string& subject_path, const string& predicate, const string& value); - void connection_event(const string& src_port_path, const string& dst_port_path); - void disconnection_event(const string& src_port_path, const string& dst_port_path); + void connection_event(const Path& src_port_path, const Path& dst_port_path); + void disconnection_event(const Path& src_port_path, const Path& dst_port_path); map > m_objects; ///< Keyed by Om path map > m_plugins; ///< Keyed by URI diff --git a/src/libs/engine/Buffer.cpp b/src/libs/engine/Buffer.cpp index 963b14a5..4e94a943 100644 --- a/src/libs/engine/Buffer.cpp +++ b/src/libs/engine/Buffer.cpp @@ -39,6 +39,7 @@ Buffer::Buffer(size_t size) { assert(m_size > 0); allocate(); + assert(m_data); } template Buffer::Buffer(size_t size); template Buffer::Buffer(size_t size); diff --git a/src/libs/engine/ConnectionBase.cpp b/src/libs/engine/ConnectionBase.cpp deleted file mode 100644 index c8936818..00000000 --- a/src/libs/engine/ConnectionBase.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* This file is part of Om. 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., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ConnectionBase.h" -#include "util.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Node.h" -#include "Om.h" -#include "Port.h" - -namespace Om { - - -/** Constructor for a connection from a node's output port. - * - * This handles both polyphonic and monophonic nodes, transparently to the - * user (InputPort). - */ -template -ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port) -: Connection(src_port, dst_port), - m_local_buffer(NULL), - m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), - m_buffer_size(src_port->buffer_size()), - m_pending_disconnection(false) -{ - assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) - || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); - - if (m_is_poly_to_mono) // Poly -> Mono connection, need a buffer to mix in to - m_local_buffer = new Buffer(m_buffer_size); -} -template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); -template ConnectionBase::ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); - - -template -ConnectionBase::~ConnectionBase() -{ - delete m_local_buffer; -} -template ConnectionBase::~ConnectionBase(); -template ConnectionBase::~ConnectionBase(); - - -template -void -ConnectionBase::prepare_buffers() -{ - /* Thought: A poly output port can be connected to multiple mono input - * ports, which means this mix down would have to happen many times. - * Adding a method to OutputPort that mixes down all it's outputs into - * a buffer (if it hasn't been done already this cycle) and returns that - * would avoid having to mix multiple times. Probably not a very common - * case, but it would be faster anyway. */ - - if (m_is_poly_to_mono) { - m_local_buffer->copy(src_port()->buffer(0), 0, m_buffer_size-1); - - // Mix all the source's voices down into local buffer starting at the second - // voice (buffer is already set to first voice above) - for (size_t j=1; j < src_port()->poly(); ++j) - m_local_buffer->accumulate(src_port()->buffer(j), 0, m_buffer_size-1); - - // Scale the buffer down. - if (src_port()->poly() > 1) - m_local_buffer->scale(1.0f/(float)src_port()->poly(), 0, m_buffer_size-1); - } -} -template void ConnectionBase::prepare_buffers(); - - -// FIXME: MIDI mixing not implemented -template <> -void -ConnectionBase::prepare_buffers() -{ -} - - -} // namespace Om - diff --git a/src/libs/engine/ConnectionBase.h b/src/libs/engine/ConnectionBase.h deleted file mode 100644 index 80d7bd84..00000000 --- a/src/libs/engine/ConnectionBase.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Om. 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., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef CONNECTIONBASE_H -#define CONNECTIONBASE_H - -#include "types.h" -#include "OutputPort.h" -#include "Connection.h" - -namespace Om { - -class MidiMessage; -class Port; -template class InputPort; - - -/** A Connection with a type. - * - * \ingroup engine - */ -template -class ConnectionBase : public Connection -{ -public: - ConnectionBase(OutputPort* const src_port, InputPort* const dst_port); - virtual ~ConnectionBase(); - - void prepare_buffers(); - - inline OutputPort* src_port() const { return (OutputPort*)m_src_port; } - inline InputPort* dst_port() const { return (InputPort*)m_dst_port; } - - /** Used by some (recursive) events to prevent double disconnections */ - bool pending_disconnection() { return m_pending_disconnection; } - void pending_disconnection(bool b) { m_pending_disconnection = b; } - - /** Get the buffer for a particular voice. - * A ConnectionBase is smart - it knows the destination port respondering the - * buffer, and will return accordingly (ie the same buffer for every voice - * in a mono->poly connection). - */ - inline Buffer* buffer(size_t voice) const; - -private: - // Disallow copies (undefined) - ConnectionBase(const ConnectionBase& copy); - ConnectionBase& operator=(const ConnectionBase&); - - Buffer* m_local_buffer; ///< Only used for poly->mono connections - bool m_is_poly_to_mono; - size_t m_buffer_size; - bool m_pending_disconnection; -}; - - -template <> -inline Buffer* -ConnectionBase::buffer(size_t voice) const -{ - TypedPort* const src_port = (TypedPort*)m_src_port; - - if (m_is_poly_to_mono) { - return m_local_buffer; - } else { - if (src_port->poly() == 1) - return src_port->buffer(0); - else - return src_port->buffer(voice); - } -} - - -template <> -inline Buffer* -ConnectionBase::buffer(size_t voice) const -{ - // No such thing as polyphonic MIDI ports - assert(m_src_port->poly() == 1); - assert(m_dst_port->poly() == 1); - - TypedPort* const src_port = (TypedPort*)m_src_port; - return src_port->buffer(0); -} - - -template class ConnectionBase; -template class ConnectionBase; - -} // namespace Om - -#endif // CONNECTIONBASE_H diff --git a/src/libs/engine/Driver.h b/src/libs/engine/Driver.h index ade50a71..11060c04 100644 --- a/src/libs/engine/Driver.h +++ b/src/libs/engine/Driver.h @@ -22,7 +22,7 @@ using std::string; namespace Om { -template class TypedPort; +template class DuplexPort; /** Representation of a system (outside Om, ie hardware) audio port. @@ -77,7 +77,7 @@ public: * * May return NULL if the Driver can not drive the port for some reason. */ - virtual DriverPort* create_port(TypedPort* patch_port) = 0; + virtual DriverPort* create_port(DuplexPort* patch_port) = 0; }; diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp index 0e7a349d..752efde4 100644 --- a/src/libs/engine/InputPort.cpp +++ b/src/libs/engine/InputPort.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "ConnectionBase.h" +#include "TypedConnection.h" #include "OutputPort.h" #include "Node.h" #include "Om.h" @@ -46,21 +46,21 @@ template InputPort::InputPort(Node* parent, const string& name, siz */ template void -InputPort::add_connection(ListNode*>* const c) +InputPort::add_connection(ListNode*>* const c) { m_connections.push_back(c); bool modify_buffers = !m_fixed_buffers; - if (modify_buffers && m_is_tied) - modify_buffers = !m_tied_port->fixed_buffers(); + //if (modify_buffers && m_is_tied) + // modify_buffers = !m_tied_port->fixed_buffers(); if (modify_buffers) { if (m_connections.size() == 1) { // Use buffer directly to avoid copying for (size_t i=0; i < _poly; ++i) { m_buffers.at(i)->join(c->elem()->buffer(i)); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); + //if (m_is_tied) + // m_tied_port->buffer(i)->join(m_buffers.at(i)); assert(m_buffers.at(i)->data() == c->elem()->buffer(i)->data()); } } else if (m_connections.size() == 2) { @@ -68,34 +68,34 @@ InputPort::add_connection(ListNode*>* const c) // so have to use local ones again and mix down for (size_t i=0; i < _poly; ++i) { m_buffers.at(i)->unjoin(); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); + //if (m_is_tied) + // m_tied_port->buffer(i)->join(m_buffers.at(i)); } } update_buffers(); } - assert( ! m_is_tied || m_tied_port != NULL); - assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + //assert( ! m_is_tied || m_tied_port != NULL); + //assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); } -template void InputPort::add_connection(ListNode*>* const c); -template void InputPort::add_connection(ListNode*>* const c); +template void InputPort::add_connection(ListNode*>* const c); +template void InputPort::add_connection(ListNode*>* const c); /** Remove a connection. Realtime safe. */ template -ListNode*>* +ListNode*>* InputPort::remove_connection(const OutputPort* const src_port) { bool modify_buffers = !m_fixed_buffers; - if (modify_buffers && m_is_tied) - modify_buffers = !m_tied_port->fixed_buffers(); + //if (modify_buffers && m_is_tied) + // modify_buffers = !m_tied_port->fixed_buffers(); - typedef typename List*>::iterator ConnectionBaseListIterator; + typedef typename List*>::iterator TypedConnectionListIterator; bool found = false; - ListNode*>* connection = NULL; - for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) { + ListNode*>* connection = NULL; + for (TypedConnectionListIterator i = m_connections.begin(); i != m_connections.end(); ++i) { if ((*i)->src_port()->path() == src_port->path()) { connection = m_connections.remove(i); found = true; @@ -112,15 +112,15 @@ InputPort::remove_connection(const OutputPort* const src_port) if (modify_buffers && m_buffers.at(i)->is_joined()) m_buffers.at(i)->unjoin(); m_buffers.at(i)->clear(); // Write silence - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); + //if (m_is_tied) + //m_tied_port->buffer(i)->join(m_buffers.at(i)); } } else if (modify_buffers && m_connections.size() == 1) { // Share a buffer for (size_t i=0; i < _poly; ++i) { m_buffers.at(i)->join((*m_connections.begin())->buffer(i)); - if (m_is_tied) - m_tied_port->buffer(i)->join(m_buffers.at(i)); + //if (m_is_tied) + // m_tied_port->buffer(i)->join(m_buffers.at(i)); } } } @@ -128,14 +128,14 @@ InputPort::remove_connection(const OutputPort* const src_port) if (modify_buffers) update_buffers(); - assert( ! m_is_tied || m_tied_port != NULL); - assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + //assert( ! m_is_tied || m_tied_port != NULL); + //assert( ! m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); return connection; } -template ListNode*>* +template ListNode*>* InputPort::remove_connection(const OutputPort* const src_port); -template ListNode*>* +template ListNode*>* InputPort::remove_connection(const OutputPort* const src_port); @@ -161,8 +161,8 @@ template bool InputPort::is_connected_to(const OutputPort* const port) const { - typedef typename List*>::const_iterator ConnectionBaseListIterator; - for (ConnectionBaseListIterator i = m_connections.begin(); i != m_connections.end(); ++i) + typedef typename List*>::const_iterator TypedConnectionListIterator; + for (TypedConnectionListIterator i = m_connections.begin(); i != m_connections.end(); ++i) if ((*i)->src_port() == port) return true; @@ -177,6 +177,7 @@ template bool InputPort::is_connected_to(const OutputPort void InputPort::tie(OutputPort* const port) @@ -202,7 +203,7 @@ InputPort::tie(OutputPort* const port) } template void InputPort::tie(OutputPort* const port); template void InputPort::tie(OutputPort* const port); - +*/ /** Prepare buffer for access, mixing if necessary. Realtime safe. * FIXME: nframes parameter not used, @@ -211,21 +212,21 @@ template<> void InputPort::prepare_buffers(size_t nframes) { - assert(!m_is_tied || m_tied_port != NULL); + //assert(!m_is_tied || m_tied_port != NULL); - typedef List*>::iterator ConnectionBaseListIterator; + typedef List*>::iterator TypedConnectionListIterator; bool do_mixdown = true; if (m_connections.size() == 0) return; - for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) + for (TypedConnectionListIterator c = m_connections.begin(); c != m_connections.end(); ++c) (*c)->prepare_buffers(); // If only one connection, buffer is (maybe) used directly (no copying) if (m_connections.size() == 1) { // Buffer changed since connection if (m_buffers.at(0)->data() != (*m_connections.begin())->buffer(0)->data()) { - if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { + if (m_fixed_buffers) { // || (m_is_tied && m_tied_port->fixed_buffers())) { // can't change buffer, must copy do_mixdown = true; } else { @@ -245,15 +246,15 @@ InputPort::prepare_buffers(size_t nframes) return; } - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + /*assert(!m_is_tied || m_tied_port != NULL); + assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data());*/ for (size_t voice=0; voice < _poly; ++voice) { m_buffers.at(voice)->copy((*m_connections.begin())->buffer(voice), 0, _buffer_size-1); if (m_connections.size() > 1) { // Copy first connection - ConnectionBaseListIterator c = m_connections.begin(); + TypedConnectionListIterator c = m_connections.begin(); // Add all other connections for (++c; c != m_connections.end(); ++c) @@ -271,17 +272,17 @@ template <> void InputPort::prepare_buffers(size_t nframes) { - assert(!m_is_tied || m_tied_port != NULL); + //assert(!m_is_tied || m_tied_port != NULL); const size_t num_ins = m_connections.size(); bool do_mixdown = true; assert(num_ins == 0 || num_ins == 1); - typedef List*>::iterator ConnectionBaseListIterator; + typedef List*>::iterator TypedConnectionListIterator; assert(_poly == 1); - for (ConnectionBaseListIterator c = m_connections.begin(); c != m_connections.end(); ++c) + for (TypedConnectionListIterator c = m_connections.begin(); c != m_connections.end(); ++c) (*c)->prepare_buffers(); @@ -289,24 +290,24 @@ InputPort::prepare_buffers(size_t nframes) if (num_ins == 1) { // Buffer changed since connection if (m_buffers.at(0) != (*m_connections.begin())->buffer(0)) { - if (m_fixed_buffers || (m_is_tied && m_tied_port->fixed_buffers())) { + if (m_fixed_buffers) { // || (m_is_tied && m_tied_port->fixed_buffers())) { // can't change buffer, must copy do_mixdown = true; } else { // zero-copy assert(m_buffers.at(0)->is_joined()); m_buffers.at(0)->join((*m_connections.begin())->buffer(0)); - if (m_is_tied) - m_tied_port->buffer(0)->join(m_buffers.at(0)); + //if (m_is_tied) + // m_tied_port->buffer(0)->join(m_buffers.at(0)); do_mixdown = false; } update_buffers(); } else { do_mixdown = false; } - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); - assert(!m_is_tied || m_buffers.at(0)->filled_size() == m_tied_port->buffer(0)->filled_size()); + //assert(!m_is_tied || m_tied_port != NULL); + //assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + //assert(!m_is_tied || m_buffers.at(0)->filled_size() == m_tied_port->buffer(0)->filled_size()); assert(do_mixdown || m_buffers.at(0)->filled_size() == (*m_connections.begin())->src_port()->buffer(0)->filled_size()); } @@ -318,8 +319,8 @@ InputPort::prepare_buffers(size_t nframes) m_buffers.at(0)->filled_size( (*m_connections.begin())->src_port()->buffer(0)->filled_size()); - if (m_is_tied) - m_tied_port->buffer(0)->filled_size(m_buffers.at(0)->filled_size()); + //if (m_is_tied) + // m_tied_port->buffer(0)->filled_size(m_buffers.at(0)->filled_size()); assert(m_buffers.at(0)->filled_size() == (*m_connections.begin())->src_port()->buffer(0)->filled_size()); @@ -329,7 +330,7 @@ InputPort::prepare_buffers(size_t nframes) } } - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + //assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); if (!do_mixdown || m_buffers.at(0)->filled_size() == 0 || num_ins == 0) return; @@ -337,8 +338,8 @@ InputPort::prepare_buffers(size_t nframes) //cerr << path() << " - Copying MIDI buffer" << endl; // Be sure buffers are the same as tied port's, if joined - assert(!m_is_tied || m_tied_port != NULL); - assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); + //assert(!m_is_tied || m_tied_port != NULL); + //assert(!m_is_tied || m_buffers.at(0)->data() == m_tied_port->buffer(0)->data()); if (num_ins > 0) for (size_t i=0; i < m_buffers.at(0)->filled_size(); ++i) diff --git a/src/libs/engine/InputPort.h b/src/libs/engine/InputPort.h index 8c677b26..60e96167 100644 --- a/src/libs/engine/InputPort.h +++ b/src/libs/engine/InputPort.h @@ -27,7 +27,7 @@ using std::string; namespace Om { -template class ConnectionBase; +template class TypedConnection; template class OutputPort; class Node; @@ -44,16 +44,16 @@ class Node; * \ingroup engine */ template -class InputPort : public TypedPort +class InputPort : virtual public TypedPort { public: InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); virtual ~InputPort() {} - void add_connection(ListNode*>* const c); - ListNode*>* remove_connection(const OutputPort* const src_port); + void add_connection(ListNode*>* const c); + ListNode*>* remove_connection(const OutputPort* const src_port); - const List*>& connections() { return m_connections; } + const List*>& connections() { return m_connections; } void prepare_buffers(size_t nframes); @@ -72,11 +72,11 @@ private: void update_buffers(); - List*> m_connections; + List*> m_connections; // This is just stupid... - using TypedPort::m_is_tied; - using TypedPort::m_tied_port; + //using TypedPort::m_is_tied; + //using TypedPort::m_tied_port; using TypedPort::m_buffers; using TypedPort::_poly; using TypedPort::_index; diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp index e6ef502e..5fc786f2 100644 --- a/src/libs/engine/JackAudioDriver.cpp +++ b/src/libs/engine/JackAudioDriver.cpp @@ -32,7 +32,7 @@ #include "Port.h" #include "MidiDriver.h" #include "List.h" -#include "TypedPort.h" +#include "DuplexPort.h" #ifdef HAVE_LASH #include "LashDriver.h" #endif @@ -45,7 +45,7 @@ namespace Om { //// JackAudioPort //// -JackAudioPort::JackAudioPort(JackAudioDriver* driver, TypedPort* patch_port) +JackAudioPort::JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port) : DriverPort(), ListNode(this), m_driver(driver), @@ -53,7 +53,7 @@ JackAudioPort::JackAudioPort(JackAudioDriver* driver, TypedPort* patch_p m_jack_buffer(NULL), m_patch_port(patch_port) { - assert(patch_port->tied_port() != NULL); + //assert(patch_port->tied_port() != NULL); assert(patch_port->poly() == 1); m_jack_port = jack_port_register(m_driver->jack_client(), @@ -93,17 +93,17 @@ JackAudioPort::prepare_buffer(jack_nframes_t nframes) m_jack_buffer->set_data((jack_default_audio_sample_t*) jack_port_get_buffer(m_jack_port, nframes)); - assert(m_patch_port->tied_port() != NULL); + //assert(m_patch_port->tied_port() != NULL); // FIXME: fixed_buffers switch on/off thing can be removed once this shit // gets figured out and assertions can go away m_patch_port->fixed_buffers(false); m_patch_port->buffer(0)->join(m_jack_buffer); - m_patch_port->tied_port()->buffer(0)->join(m_jack_buffer); + //m_patch_port->tied_port()->buffer(0)->join(m_jack_buffer); m_patch_port->fixed_buffers(true); - assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data()); + //assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data()); assert(m_patch_port->buffer(0)->data() == m_jack_buffer->data()); } @@ -241,7 +241,7 @@ JackAudioDriver::remove_port(JackAudioPort* port) DriverPort* -JackAudioDriver::create_port(TypedPort* patch_port) +JackAudioDriver::create_port(DuplexPort* patch_port) { if (patch_port->buffer_size() == m_buffer_size) return new JackAudioPort(this, patch_port); diff --git a/src/libs/engine/JackAudioDriver.h b/src/libs/engine/JackAudioDriver.h index a01624ed..abb74825 100644 --- a/src/libs/engine/JackAudioDriver.h +++ b/src/libs/engine/JackAudioDriver.h @@ -27,7 +27,7 @@ namespace Om { class Patch; class Port; -template class TypedPort; +template class DuplexPort; class JackAudioDriver; typedef jack_default_audio_sample_t jack_sample_t; @@ -39,7 +39,7 @@ typedef jack_default_audio_sample_t jack_sample_t; class JackAudioPort : public DriverPort, public ListNode { public: - JackAudioPort(JackAudioDriver* driver, TypedPort* patch_port); + JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port); ~JackAudioPort(); void add_to_driver(); @@ -51,7 +51,7 @@ public: jack_port_t* jack_port() const { return m_jack_port; } DriverBuffer* buffer() const { return m_jack_buffer; } void jack_buffer(jack_sample_t* s) { m_jack_buffer->set_data(s); } - TypedPort* patch_port() const { return m_patch_port; } + DuplexPort* patch_port() const { return m_patch_port; } private: // Prevent copies (undefined) @@ -61,7 +61,7 @@ private: JackAudioDriver* m_driver; jack_port_t* m_jack_port; DriverBuffer* m_jack_buffer; - TypedPort* m_patch_port; + DuplexPort* m_patch_port; }; @@ -88,7 +88,7 @@ public: void process_events(jack_nframes_t block_start, jack_nframes_t block_end); - DriverPort* create_port(TypedPort* patch_port); + DriverPort* create_port(DuplexPort* patch_port); Patch* root_patch() { return m_root_patch; } void set_root_patch(Patch* patch) { m_root_patch = patch; } diff --git a/src/libs/engine/JackMidiDriver.cpp b/src/libs/engine/JackMidiDriver.cpp index f55f0422..7c9ca9f4 100644 --- a/src/libs/engine/JackMidiDriver.cpp +++ b/src/libs/engine/JackMidiDriver.cpp @@ -26,7 +26,7 @@ #include "Maid.h" #include "AudioDriver.h" #include "MidiMessage.h" -#include "TypedPort.h" +#include "DuplexPort.h" #ifdef HAVE_LASH #include "LashDriver.h" #endif @@ -37,7 +37,7 @@ namespace Om { //// JackMidiPort //// -JackMidiPort::JackMidiPort(JackMidiDriver* driver, TypedPort* patch_port) +JackMidiPort::JackMidiPort(JackMidiDriver* driver, DuplexPort* patch_port) : DriverPort(), ListNode(this), m_driver(driver), @@ -115,7 +115,7 @@ JackMidiPort::prepare_block(const samplecount block_start, const samplecount blo //cerr << "Jack MIDI got " << event_count << " events." << endl; m_patch_port->buffer(0)->filled_size(event_count); - m_patch_port->tied_port()->buffer(0)->filled_size(event_count); + //m_patch_port->tied_port()->buffer(0)->filled_size(event_count); } diff --git a/src/libs/engine/JackMidiDriver.h b/src/libs/engine/JackMidiDriver.h index 33b4a0e1..f080833c 100644 --- a/src/libs/engine/JackMidiDriver.h +++ b/src/libs/engine/JackMidiDriver.h @@ -29,7 +29,7 @@ namespace Om { class Node; class SetPortValueEvent; class JackMidiDriver; -template class TypedPort; +template class DuplexPort; /** Representation of an JACK MIDI port. @@ -39,7 +39,7 @@ template class TypedPort; class JackMidiPort : public DriverPort, public ListNode { public: - JackMidiPort(JackMidiDriver* driver, TypedPort* port); + JackMidiPort(JackMidiDriver* driver, DuplexPort* port); virtual ~JackMidiPort(); void prepare_block(const samplecount block_start, const samplecount block_end); @@ -48,16 +48,16 @@ public: void remove_from_driver(); void set_name(const string& name) { jack_port_set_name(m_jack_port, name.c_str()); }; - TypedPort* patch_port() const { return m_patch_port; } + DuplexPort* patch_port() const { return m_patch_port; } private: // Prevent copies (undefined) JackMidiPort(const JackMidiPort&); JackMidiPort& operator=(const JackMidiPort&); - JackMidiDriver* m_driver; - jack_port_t* m_jack_port; - TypedPort* m_patch_port; + JackMidiDriver* m_driver; + jack_port_t* m_jack_port; + DuplexPort* m_patch_port; }; @@ -84,7 +84,7 @@ public: void prepare_block(const samplecount block_start, const samplecount block_end); - JackMidiPort* create_port(TypedPort* patch_port) + JackMidiPort* create_port(DuplexPort* patch_port) { return new JackMidiPort(this, patch_port); } jack_client_t* jack_client() { return m_client; } diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am index 09098e10..56b7724c 100644 --- a/src/libs/engine/Makefile.am +++ b/src/libs/engine/Makefile.am @@ -47,6 +47,8 @@ libom_la_SOURCES = \ InputPort.cpp \ OutputPort.h \ OutputPort.cpp \ + DuplexPort.h \ + DuplexPort.cpp \ MidiMessage.h \ MidiNoteNode.h \ MidiNoteNode.cpp \ @@ -76,8 +78,8 @@ libom_la_SOURCES = \ PostProcessor.cpp \ Connection.h \ Connection.cpp \ - ConnectionBase.h \ - ConnectionBase.cpp \ + TypedConnection.h \ + TypedConnection.cpp \ ObjectStore.h \ ObjectStore.cpp \ TransportNode.h \ diff --git a/src/libs/engine/MidiDriver.h b/src/libs/engine/MidiDriver.h index ed9d6e18..b037d52b 100644 --- a/src/libs/engine/MidiDriver.h +++ b/src/libs/engine/MidiDriver.h @@ -66,7 +66,7 @@ public: void enable() {} void disable() {} - DriverPort* create_port(TypedPort* patch_port) { return NULL; } + DriverPort* create_port(DuplexPort* patch_port) { return NULL; } void prepare_block(const samplecount block_start, const samplecount block_end) {} }; diff --git a/src/libs/engine/ObjectSender.cpp b/src/libs/engine/ObjectSender.cpp index 567beabe..354820f7 100644 --- a/src/libs/engine/ObjectSender.cpp +++ b/src/libs/engine/ObjectSender.cpp @@ -72,7 +72,7 @@ ObjectSender::send_patch(ClientInterface* client, const Patch* patch) // Control port, send value if (port->type() == DataType::FLOAT && port->buffer_size() == 1) - client->control_change(port->path(), ((TypedPort*)port)->buffer(0)->value_at(0)); + client->control_change(port->path(), dynamic_cast*>(port)->buffer(0)->value_at(0)); } // Send metadata diff --git a/src/libs/engine/OutputPort.cpp b/src/libs/engine/OutputPort.cpp index 35cb84b4..d713726a 100644 --- a/src/libs/engine/OutputPort.cpp +++ b/src/libs/engine/OutputPort.cpp @@ -28,22 +28,22 @@ OutputPort::OutputPort(Node* parent, const string& name, size_t index, size_t template OutputPort::OutputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); template OutputPort::OutputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); - +#if 0 template void OutputPort::set_tied_port(InputPort* port) { - assert(!m_is_tied); - assert(m_tied_port == NULL); + //assert(!m_is_tied); + //assert(m_tied_port == NULL); assert(static_cast*>(port) != static_cast*>(this)); assert(port != NULL); - m_is_tied = true; - m_tied_port = (TypedPort*)port; + //m_is_tied = true; + //m_tied_port = (TypedPort*)port; } template void OutputPort::set_tied_port(InputPort* port); template void OutputPort::set_tied_port(InputPort* port); - +#endif } // namespace Om diff --git a/src/libs/engine/OutputPort.h b/src/libs/engine/OutputPort.h index 269a4524..25a03325 100644 --- a/src/libs/engine/OutputPort.h +++ b/src/libs/engine/OutputPort.h @@ -39,7 +39,7 @@ template class InputPort; * \ingroup engine */ template -class OutputPort : public TypedPort +class OutputPort : virtual public TypedPort { public: OutputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); @@ -55,8 +55,8 @@ private: OutputPort(const OutputPort& copy); OutputPort& operator=(const OutputPort&); - using TypedPort::m_is_tied; - using TypedPort::m_tied_port; + //using TypedPort::m_is_tied; + //using TypedPort::m_tied_port; }; diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp index b24377e0..7d22c673 100644 --- a/src/libs/engine/Patch.cpp +++ b/src/libs/engine/Patch.cpp @@ -30,6 +30,7 @@ #include "ObjectStore.h" #include "InputPort.h" #include "OutputPort.h" +#include "DuplexPort.h" #include "interface/ClientInterface.h" using std::cerr; using std::cout; using std::endl; @@ -45,8 +46,8 @@ Patch::Patch(const string& path, size_t poly, Patch* parent, samplerate srate, s { assert(internal_poly >= 1); - _plugin.plug_label("om_patch"); - _plugin.name("Om Patch"); + //_plugin->plug_label("om_patch"); + //_plugin->name("Om Patch"); //std::cerr << "Creating patch " << _name << ", poly = " << poly // << ", internal poly = " << internal_poly << std::endl; @@ -110,10 +111,8 @@ Patch::process(bool p) assert((*i)->as_port() != NULL); if ((*i)->as_port()->port_info()->is_output()) (*i)->as_port()->clear_buffers();*/ - for (List::iterator i = _patch_ports.begin(); i != _patch_ports.end(); ++i) { - if ((*i)->is_output()) - (*i)->clear_buffers(); - } + for (List::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) + (*i)->clear_buffers(); } _process = p; } @@ -132,9 +131,8 @@ Patch::run(size_t nframes) // FIXME: This is far too slow, too much checking every cycle // Prepare input ports for nodes to consume - for (List::iterator i = _patch_ports.begin(); i != _patch_ports.end(); ++i) - if ((*i)->is_input()) - (*i)->prepare_buffers(nframes); + for (List::iterator i = _input_ports.begin(); i != _input_ports.end(); ++i) + (*i)->prepare_buffers(nframes); // Run all nodes (consume input ports) for (size_t i=0; i < _process_order->size(); ++i) { @@ -145,7 +143,7 @@ Patch::run(size_t nframes) } // Prepare output ports (for caller to consume) - for (List::iterator i = _patch_ports.begin(); i != _patch_ports.end(); ++i) + for (List::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) if ((*i)->is_output()) (*i)->prepare_buffers(nframes); } @@ -299,10 +297,11 @@ Patch::create_port(const string& name, DataType type, size_t buffer_size, bool i assert( !(type == DataType::UNKNOWN) ); - if (is_output) - return new OutputPort(this, name, 0, _poly, type, buffer_size); - else - return new InputPort(this, name, 0, _poly, type, buffer_size); + // FIXME: is it possible to just "pass" the type directly as the template parameter somehow? + if (type == DataType::FLOAT) + return new DuplexPort(this, name, 0, _poly, type, buffer_size, is_output); + else if (type == DataType::MIDI) + return new DuplexPort(this, name, 0, _poly, type, buffer_size, is_output); } @@ -313,9 +312,17 @@ Patch::remove_port(const Port* port) { bool found = false; ListNode* ret = NULL; - for (List::iterator i = _patch_ports.begin(); i != _patch_ports.end(); ++i) { + for (List::iterator i = _input_ports.begin(); i != _input_ports.end(); ++i) { + if ((*i) == port) { + ret = _input_ports.remove(i); + found = true; + } + } + + if (!found) + for (List::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) { if ((*i) == port) { - ret = _patch_ports.remove(i); + ret = _output_ports.remove(i); found = true; } } @@ -347,7 +354,7 @@ Patch::build_process_order() const (*i)->traversed(false); // Traverse backwards starting at outputs - for (List::const_iterator p = _patch_ports.begin(); p != _patch_ports.end(); ++p) { + for (List::const_iterator p = _output_ports.begin(); p != _output_ports.end(); ++p) { /*const Port* const port = (*p); if (port->port_info()->is_output()) { for (List::const_iterator c = port->connections().begin(); diff --git a/src/libs/engine/Patch.h b/src/libs/engine/Patch.h index edde636e..f0e06368 100644 --- a/src/libs/engine/Patch.h +++ b/src/libs/engine/Patch.h @@ -74,10 +74,9 @@ public: const List& nodes() const { return _nodes; } const List& connections() const { return _connections; } - //void add_bridge_node(ListNode* n) { _bridge_nodes.push_back(n); } - //ListNode* remove_bridge_node(const InternalNode* n); Port* create_port(const string& name, DataType type, size_t buffer_size, bool is_output); - void add_port(ListNode* port) { _patch_ports.push_back(port); } + void add_input(ListNode* port) { _input_ports.push_back(port); } ///< Preprocesser thread + void add_output(ListNode* port) { _output_ports.push_back(port); } ///< Preprocessor thread ListNode* remove_port(const Port* p); void add_connection(ListNode* c) { _connections.push_back(c); } @@ -96,8 +95,6 @@ public: void process(bool p); size_t internal_poly() const { return _internal_poly; } - - const Plugin* plugin() const { return &_plugin; } private: // Prevent copies (undefined) @@ -109,11 +106,10 @@ private: size_t _internal_poly; Array* _process_order; ///< Accessed in audio thread only List _connections; ///< Accessed in audio thread only - List _patch_ports; ///< Accessed in preprocessing thread only + List _input_ports; ///< Accessed in preprocessing thread only + List _output_ports; ///< Accessed in preprocessing thread only List _nodes; ///< Accessed in preprocessing thread only bool _process; - - Plugin _plugin; }; diff --git a/src/libs/engine/TypedConnection.cpp b/src/libs/engine/TypedConnection.cpp new file mode 100644 index 00000000..ccfd36a1 --- /dev/null +++ b/src/libs/engine/TypedConnection.cpp @@ -0,0 +1,96 @@ +/* This file is part of Om. 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "TypedConnection.h" +#include "util.h" +#include "InputPort.h" +#include "OutputPort.h" +#include "Node.h" +#include "Om.h" +#include "Port.h" + +namespace Om { + + +/** Constructor for a connection from a node's output port. + * + * This handles both polyphonic and monophonic nodes, transparently to the + * user (InputPort). + */ +template +TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port) +: Connection(src_port, dst_port), + m_local_buffer(NULL), + m_is_poly_to_mono( (src_port->parent_node()->poly() > dst_port->parent_node()->poly()) ), + m_buffer_size(src_port->buffer_size()), + m_pending_disconnection(false) +{ + assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) + || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); + + if (m_is_poly_to_mono) // Poly -> Mono connection, need a buffer to mix in to + m_local_buffer = new Buffer(m_buffer_size); +} +template TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port); +template TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port); + + +template +TypedConnection::~TypedConnection() +{ + delete m_local_buffer; +} +template TypedConnection::~TypedConnection(); +template TypedConnection::~TypedConnection(); + + +template +void +TypedConnection::prepare_buffers() +{ + /* Thought: A poly output port can be connected to multiple mono input + * ports, which means this mix down would have to happen many times. + * Adding a method to OutputPort that mixes down all it's outputs into + * a buffer (if it hasn't been done already this cycle) and returns that + * would avoid having to mix multiple times. Probably not a very common + * case, but it would be faster anyway. */ + + if (m_is_poly_to_mono) { + m_local_buffer->copy(src_port()->buffer(0), 0, m_buffer_size-1); + + // Mix all the source's voices down into local buffer starting at the second + // voice (buffer is already set to first voice above) + for (size_t j=1; j < src_port()->poly(); ++j) + m_local_buffer->accumulate(src_port()->buffer(j), 0, m_buffer_size-1); + + // Scale the buffer down. + if (src_port()->poly() > 1) + m_local_buffer->scale(1.0f/(float)src_port()->poly(), 0, m_buffer_size-1); + } +} +template void TypedConnection::prepare_buffers(); + + +// FIXME: MIDI mixing not implemented +template <> +void +TypedConnection::prepare_buffers() +{ +} + + +} // namespace Om + diff --git a/src/libs/engine/TypedConnection.h b/src/libs/engine/TypedConnection.h new file mode 100644 index 00000000..953c77e9 --- /dev/null +++ b/src/libs/engine/TypedConnection.h @@ -0,0 +1,105 @@ +/* This file is part of Om. 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TYPEDCONNECTION_H +#define TYPEDCONNECTION_H + +#include "types.h" +#include "OutputPort.h" +#include "Connection.h" + +namespace Om { + +class MidiMessage; +class Port; +template class InputPort; + + +/** A Connection with a type. + * + * \ingroup engine + */ +template +class TypedConnection : public Connection +{ +public: + TypedConnection(OutputPort* const src_port, InputPort* const dst_port); + virtual ~TypedConnection(); + + void prepare_buffers(); + + inline OutputPort* src_port() const { return dynamic_cast*>(m_src_port); } + inline InputPort* dst_port() const { return dynamic_cast*>(m_dst_port); } + + /** Used by some (recursive) events to prevent double disconnections */ + bool pending_disconnection() { return m_pending_disconnection; } + void pending_disconnection(bool b) { m_pending_disconnection = b; } + + /** Get the buffer for a particular voice. + * A TypedConnection is smart - it knows the destination port respondering the + * buffer, and will return accordingly (ie the same buffer for every voice + * in a mono->poly connection). + */ + inline Buffer* buffer(size_t voice) const; + +private: + // Disallow copies (undefined) + TypedConnection(const TypedConnection& copy); + TypedConnection& operator=(const TypedConnection&); + + Buffer* m_local_buffer; ///< Only used for poly->mono connections + bool m_is_poly_to_mono; + size_t m_buffer_size; + bool m_pending_disconnection; +}; + + +template <> +inline Buffer* +TypedConnection::buffer(size_t voice) const +{ + TypedPort* const src_port = (TypedPort*)m_src_port; + + if (m_is_poly_to_mono) { + return m_local_buffer; + } else { + if (src_port->poly() == 1) + return src_port->buffer(0); + else + return src_port->buffer(voice); + } +} + + +template <> +inline Buffer* +TypedConnection::buffer(size_t voice) const +{ + // No such thing as polyphonic MIDI ports + assert(m_src_port->poly() == 1); + assert(m_dst_port->poly() == 1); + + TypedPort* const src_port = (TypedPort*)m_src_port; + return src_port->buffer(0); +} + + +template class TypedConnection; +template class TypedConnection; + +} // namespace Om + +#endif // TYPEDCONNECTION_H diff --git a/src/libs/engine/TypedPort.cpp b/src/libs/engine/TypedPort.cpp index 0ebb05eb..4fb1dfa7 100644 --- a/src/libs/engine/TypedPort.cpp +++ b/src/libs/engine/TypedPort.cpp @@ -31,10 +31,10 @@ namespace Om { */ template TypedPort::TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size) -: Port(parent, name, index, poly, type, buffer_size), - m_fixed_buffers(false), - m_is_tied(false), - m_tied_port(NULL) +: Port(parent, name, index, poly, type, buffer_size) +, m_fixed_buffers(false) +/*, m_is_tied(false) +, m_tied_port(NULL)*/ { allocate_buffers(); clear_buffers(); diff --git a/src/libs/engine/TypedPort.h b/src/libs/engine/TypedPort.h index e2ccaff4..332741a6 100644 --- a/src/libs/engine/TypedPort.h +++ b/src/libs/engine/TypedPort.h @@ -14,8 +14,8 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PORTBASE_H -#define PORTBASE_H +#ifndef TYPEDPORT_H +#define TYPEDPORT_H #include #include "types.h" @@ -52,8 +52,8 @@ public: virtual void prepare_buffers(size_t nframes); virtual void clear_buffers(); - TypedPort* tied_port() const { return m_tied_port; } - void untie() { m_is_tied = false; m_tied_port = NULL; } + //TypedPort* tied_port() const { return m_tied_port; } + //void untie() { m_is_tied = false; m_tied_port = NULL; } /** Used by drivers to prevent port from changing buffers */ void fixed_buffers(bool b) { m_fixed_buffers = b; } @@ -68,9 +68,9 @@ protected: void allocate_buffers(); - bool m_fixed_buffers; - bool m_is_tied; - TypedPort* m_tied_port; + bool m_fixed_buffers; + //bool m_is_tied; + //TypedPort* m_tied_port; Array*> m_buffers; }; @@ -81,4 +81,4 @@ template class TypedPort; } // namespace Om -#endif // PORTBASE_H +#endif // TYPEDPORT_H diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp index fcfa3bbc..1d5b3ba1 100644 --- a/src/libs/engine/events/ConnectionEvent.cpp +++ b/src/libs/engine/events/ConnectionEvent.cpp @@ -19,7 +19,7 @@ #include "Responder.h" #include "Om.h" #include "OmApp.h" -#include "ConnectionBase.h" +#include "TypedConnection.h" #include "InputPort.h" #include "OutputPort.h" #include "Patch.h" @@ -58,7 +58,9 @@ ConnectionEvent::~ConnectionEvent() void ConnectionEvent::pre_process() { - if (m_src_port_path.parent().parent() != m_dst_port_path.parent().parent()) { + 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; @@ -72,22 +74,22 @@ ConnectionEvent::pre_process() return; }*/ - Port* port1 = om->object_store()->find_port(m_src_port_path); - Port* port2 = om->object_store()->find_port(m_dst_port_path); + 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 (port1 == NULL || port2 == NULL) { + if (m_src_port == NULL || m_dst_port == NULL) { m_error = PORT_NOT_FOUND; QueuedEvent::pre_process(); return; } - if (port1->type() != port2->type()) { + 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()) { + /*if (port1->is_output() && port2->is_input()) { m_src_port = port1; m_dst_port = port2; } else if (port2->is_output() && port1->is_input()) { @@ -97,16 +99,16 @@ ConnectionEvent::pre_process() m_error = TYPE_MISMATCH; QueuedEvent::pre_process(); return; - } + }*/ // Create the typed event to actually do the work - const DataType type = port1->type(); + const DataType type = m_src_port->type(); if (type == DataType::FLOAT) { m_typed_event = new TypedConnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); + dynamic_cast*>(m_src_port), dynamic_cast*>(m_dst_port)); } else if (type == DataType::MIDI) { m_typed_event = new TypedConnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); + dynamic_cast*>(m_src_port), dynamic_cast*>(m_dst_port)); } else { m_error = TYPE_MISMATCH; QueuedEvent::pre_process(); @@ -177,23 +179,37 @@ TypedConnectionEvent::pre_process() { Node* const src_node = m_src_port->parent_node(); Node* const dst_node = m_dst_port->parent_node(); - - m_patch = src_node->parent_patch(); + + 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(dst_node); + else + m_patch = dynamic_cast(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) { + 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 ConnectionBase(m_src_port, m_dst_port); - m_port_listnode = new ListNode*>(m_connection); + m_connection = new TypedConnection(m_src_port, m_dst_port); + m_port_listnode = new ListNode*>(m_connection); m_patch_listnode = new ListNode(m_connection); dst_node->providers()->push_back(new ListNode(src_node)); diff --git a/src/libs/engine/events/ConnectionEvent.h b/src/libs/engine/events/ConnectionEvent.h index 369a3903..e2a50d53 100644 --- a/src/libs/engine/events/ConnectionEvent.h +++ b/src/libs/engine/events/ConnectionEvent.h @@ -33,7 +33,7 @@ class Node; class Connection; class MidiMessage; class Port; -template class ConnectionBase; +template class TypedConnection; template class InputPort; template class OutputPort; template class TypedConnectionEvent; // helper, defined below @@ -93,9 +93,9 @@ private: Patch* m_patch; Array* m_process_order; ///< New process order for Patch - ConnectionBase* m_connection; + TypedConnection* m_connection; ListNode* m_patch_listnode; - ListNode*>* m_port_listnode; + ListNode*>* m_port_listnode; bool m_succeeded; }; diff --git a/src/libs/engine/events/DisconnectNodeEvent.cpp b/src/libs/engine/events/DisconnectNodeEvent.cpp index 4c4e19a7..e430acc5 100644 --- a/src/libs/engine/events/DisconnectNodeEvent.cpp +++ b/src/libs/engine/events/DisconnectNodeEvent.cpp @@ -22,7 +22,7 @@ #include "Maid.h" #include "List.h" #include "Node.h" -#include "ConnectionBase.h" +#include "TypedConnection.h" #include "DisconnectionEvent.h" #include "Port.h" #include "Array.h" diff --git a/src/libs/engine/events/DisconnectNodeEvent.h b/src/libs/engine/events/DisconnectNodeEvent.h index a82fbaec..4bcbdf94 100644 --- a/src/libs/engine/events/DisconnectNodeEvent.h +++ b/src/libs/engine/events/DisconnectNodeEvent.h @@ -29,7 +29,7 @@ class DisconnectionEvent; class Patch; class Node; class Connection; -template class ConnectionBase; +template class TypedConnection; class Port; template class InputPort; template class OutputPort; diff --git a/src/libs/engine/events/DisconnectionEvent.cpp b/src/libs/engine/events/DisconnectionEvent.cpp index 0a3a4f7b..34570537 100644 --- a/src/libs/engine/events/DisconnectionEvent.cpp +++ b/src/libs/engine/events/DisconnectionEvent.cpp @@ -19,7 +19,7 @@ #include "Responder.h" #include "Om.h" #include "OmApp.h" -#include "ConnectionBase.h" +#include "TypedConnection.h" #include "InputPort.h" #include "OutputPort.h" #include "Patch.h" @@ -124,10 +124,10 @@ DisconnectionEvent::pre_process() const DataType type = m_src_port->type(); if (type == DataType::FLOAT) { m_typed_event = new TypedDisconnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); + dynamic_cast*>(m_src_port), dynamic_cast*>(m_dst_port)); } else if (type == DataType::MIDI) { m_typed_event = new TypedDisconnectionEvent(m_responder, - (OutputPort*)m_src_port, (InputPort*)m_dst_port); + dynamic_cast*>(m_src_port), dynamic_cast*>(m_dst_port)); } else { m_error = TYPE_MISMATCH; QueuedEvent::pre_process(); @@ -250,7 +250,7 @@ TypedDisconnectionEvent::execute(samplecount offset) { if (m_succeeded) { - ListNode*>* const port_connection + ListNode*>* const port_connection = m_dst_port->remove_connection(m_src_port); if (port_connection != NULL) { diff --git a/src/libs/engine/events/DisconnectionEvent.h b/src/libs/engine/events/DisconnectionEvent.h index 77d4aabe..445815dd 100644 --- a/src/libs/engine/events/DisconnectionEvent.h +++ b/src/libs/engine/events/DisconnectionEvent.h @@ -33,7 +33,7 @@ class Node; class Connection; class MidiMessage; class Port; -template class ConnectionBase; +template class TypedConnection; template class InputPort; template class OutputPort; template class TypedDisconnectionEvent; // helper, defined below diff --git a/src/progs/gtk/PatchController.cpp b/src/progs/gtk/PatchController.cpp index d9b22e35..ae604bae 100644 --- a/src/progs/gtk/PatchController.cpp +++ b/src/progs/gtk/PatchController.cpp @@ -390,10 +390,19 @@ PatchController::show_properties_window() void PatchController::create_connection(CountedPtr cm) { + // Deal with messy anonymous nodes for this patch's own ports... + const Path& src_parent_path = cm->src_port_path().parent(); + const Path& dst_parent_path = cm->dst_port_path().parent(); + + const string& src_parent_name = + (src_parent_path == path()) ? "" : src_parent_path.name(); + const string& dst_parent_name = + (dst_parent_path == path()) ? "" : dst_parent_path.name(); + m_patch_view->canvas()->add_connection( - cm->src_port_path().parent().name(), + src_parent_name, cm->src_port_path().name(), - cm->dst_port_path().parent().name(), + dst_parent_name, cm->dst_port_path().name()); // Disable control slider from destination node control window -- cgit v1.2.1