+ emit_changed (NameChanged);
+}
+
+/** Take the channels from another bundle and add them to this bundle,
+ * so that channels from other are added to this (with their ports)
+ * and are named "<other_bundle_name> <other_channel_name>".
+ */
+void
+Bundle::add_channels_from_bundle (boost::shared_ptr<Bundle> other)
+{
+ uint32_t const ch = nchannels ();
+
+ for (uint32_t i = 0; i < other->nchannels(); ++i) {
+
+ std::stringstream s;
+ s << other->name() << " " << other->channel_name(i);
+
+ add_channel (s.str());
+
+ PortList const& pl = other->channel_ports (i);
+ for (uint32_t j = 0; j < pl.size(); ++j) {
+ add_port_to_channel (ch + i, pl[j]);
+ }
+ }
+}
+
+/** Connect the ports associated with our channels to the ports associated
+ * with another bundle's channels.
+ * @param other Other bundle.
+ * @param engine AudioEngine to use to make the connections.
+ */
+void
+Bundle::connect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
+{
+ uint32_t const N = nchannels ();
+ assert (N == other->nchannels ());
+
+ for (uint32_t i = 0; i < N; ++i) {
+ Bundle::PortList const & our_ports = channel_ports (i);
+ Bundle::PortList const & other_ports = other->channel_ports (i);
+
+ for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
+ for (Bundle::PortList::const_iterator k = other_ports.begin(); k != other_ports.end(); ++k) {
+ engine.connect (*j, *k);
+ }
+ }
+ }
+}
+
+void
+Bundle::disconnect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
+{
+ uint32_t const N = nchannels ();
+ assert (N == other->nchannels ());
+
+ for (uint32_t i = 0; i < N; ++i) {
+ Bundle::PortList const & our_ports = channel_ports (i);
+ Bundle::PortList const & other_ports = other->channel_ports (i);
+
+ for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
+ for (Bundle::PortList::const_iterator k = other_ports.begin(); k != other_ports.end(); ++k) {
+ engine.disconnect (*j, *k);
+ }
+ }
+ }
+}
+
+/** Remove all ports from all channels */
+void
+Bundle::remove_ports_from_channels ()
+{
+ {
+ Glib::Mutex::Lock lm (_channel_mutex);
+ for (uint32_t c = 0; c < _channel.size(); ++c) {
+ _channel[c].ports.clear ();
+ }
+
+ }
+
+ emit_changed (PortsChanged);
+}
+
+/** Remove all ports from a given channel.
+ * @param ch Channel.
+ */
+void
+Bundle::remove_ports_from_channel (uint32_t ch)
+{
+ assert (ch < nchannels ());
+
+ {
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel[ch].ports.clear ();
+ }
+
+ emit_changed (PortsChanged);
+}
+
+void
+Bundle::suspend_signals ()
+{
+ _signals_suspended = true;
+}
+
+void
+Bundle::resume_signals ()
+{
+ if (_pending_change) {
+ Changed (_pending_change);
+ _pending_change = Change (0);
+ }
+
+ _signals_suspended = false;
+}
+
+void
+Bundle::emit_changed (Change c)
+{
+ if (_signals_suspended) {
+ _pending_change = Change (int (_pending_change) | int (c));
+ } else {
+ Changed (c);
+ }
+}
+
+bool
+Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine)
+{
+ if (_ports_are_inputs == other->_ports_are_inputs ||
+ _type != other->_type ||
+ nchannels() != other->nchannels ()) {
+
+ return false;
+ }
+
+ for (uint32_t i = 0; i < nchannels(); ++i) {
+ Bundle::PortList const & A = channel_ports (i);
+ Bundle::PortList const & B = other->channel_ports (i);
+
+ for (uint32_t j = 0; j < A.size(); ++j) {
+ for (uint32_t k = 0; k < B.size(); ++k) {
+
+ Port* p = engine.get_port_by_name (A[j]);
+ Port* q = engine.get_port_by_name (B[k]);
+
+ if (!p && !q) {
+ return false;
+ }
+
+ if (p && !p->connected_to (B[k])) {
+ return false;
+ } else if (q && !q->connected_to (A[j])) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/** Set the type of the ports in this Bundle.
+ * @param t New type.
+ */
+void
+Bundle::set_type (DataType t)
+{
+ _type = t;
+ emit_changed (TypeChanged);
+}
+
+void
+Bundle::set_ports_are_inputs ()
+{
+ _ports_are_inputs = true;
+ emit_changed (DirectionChanged);
+}
+
+void
+Bundle::set_ports_are_outputs ()
+{
+ _ports_are_inputs = false;
+ emit_changed (DirectionChanged);
+}
+
+/** Set the name.
+ * @param n New name.
+ */
+void
+Bundle::set_name (string const & n)
+{
+ _name = n;
+ emit_changed (NameChanged);
+}
+
+/** @param b Other bundle.
+ * @return true if b has the same number of channels as this bundle, and those channels have corresponding ports.
+ */
+bool
+Bundle::has_same_ports (boost::shared_ptr<Bundle> b) const
+{
+ uint32_t const N = nchannels ();
+
+ if (b->nchannels() != N) {
+ return false;
+ }
+
+ /* XXX: probably should sort channel port lists before comparing them */
+
+ for (uint32_t i = 0; i < N; ++i) {
+ if (channel_ports (i) != b->channel_ports (i)) {
+ return false;
+ }
+ }
+
+ return true;