2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "ardour/bundle.h"
23 #include "ardour/audioengine.h"
24 #include "ardour/port.h"
29 using namespace ARDOUR;
32 /** Construct an audio bundle.
33 * @param i true if ports are inputs, otherwise false.
35 Bundle::Bundle (bool i)
36 : _ports_are_inputs (i),
37 _signals_suspended (false),
38 _pending_change (Change (0))
44 /** Construct an audio bundle.
46 * @param i true if ports are inputs, otherwise false.
48 Bundle::Bundle (std::string const & n, bool i)
50 _ports_are_inputs (i),
51 _signals_suspended (false),
52 _pending_change (Change (0))
57 Bundle::Bundle (boost::shared_ptr<Bundle> other)
58 : _channel (other->_channel),
60 _ports_are_inputs (other->_ports_are_inputs),
61 _signals_suspended (other->_signals_suspended),
62 _pending_change (other->_pending_change)
68 Bundle::nchannels () const
70 Glib::Threads::Mutex::Lock lm (_channel_mutex);
73 for (vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
74 c.set (i->type, c.get (i->type) + 1);
81 Bundle::n_total () const
83 /* Simpler and far more efficient than nchannels.n_total() */
84 return _channel.size();
87 Bundle::PortList const &
88 Bundle::channel_ports (uint32_t c) const
90 assert (c < n_total());
92 Glib::Threads::Mutex::Lock lm (_channel_mutex);
93 return _channel[c].ports;
96 /** Add an association between one of our channels and a port.
97 * @param ch Channel index.
98 * @param portname full port name to associate with (including prefix).
101 Bundle::add_port_to_channel (uint32_t ch, string portname)
103 assert (ch < n_total());
104 assert (portname.find_first_of (':') != string::npos);
107 Glib::Threads::Mutex::Lock lm (_channel_mutex);
108 _channel[ch].ports.push_back (portname);
111 emit_changed (PortsChanged);
114 /** Disassociate a port from one of our channels.
115 * @param ch Channel index.
116 * @param portname port name to disassociate from.
119 Bundle::remove_port_from_channel (uint32_t ch, string portname)
121 assert (ch < n_total());
123 bool changed = false;
126 Glib::Threads::Mutex::Lock lm (_channel_mutex);
127 PortList& pl = _channel[ch].ports;
128 PortList::iterator i = find (pl.begin(), pl.end(), portname);
137 emit_changed (PortsChanged);
141 /** Set a single port to be associated with a channel, removing any others.
143 * @param portname Full port name, including prefix.
146 Bundle::set_port (uint32_t ch, string portname)
148 assert (ch < n_total());
149 assert (portname.find_first_of (':') != string::npos);
152 Glib::Threads::Mutex::Lock lm (_channel_mutex);
153 _channel[ch].ports.clear ();
154 _channel[ch].ports.push_back (portname);
157 emit_changed (PortsChanged);
160 /** @param n Channel name */
162 Bundle::add_channel (std::string const & n, DataType t)
165 Glib::Threads::Mutex::Lock lm (_channel_mutex);
166 _channel.push_back (Channel (n, t));
169 emit_changed (ConfigurationChanged);
172 /** @param n Channel name */
174 Bundle::add_channel (std::string const & n, DataType t, PortList p)
177 Glib::Threads::Mutex::Lock lm (_channel_mutex);
178 _channel.push_back (Channel (n, t, p));
181 emit_changed (ConfigurationChanged);
184 /** @param n Channel name */
186 Bundle::add_channel (std::string const & n, DataType t, std::string const & p)
189 Glib::Threads::Mutex::Lock lm (_channel_mutex);
190 _channel.push_back (Channel (n, t, p));
193 emit_changed (ConfigurationChanged);
197 Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
199 assert (ch < n_total());
201 Glib::Threads::Mutex::Lock lm (_channel_mutex);
202 return (std::find (_channel[ch].ports.begin (), _channel[ch].ports.end (), portname) != _channel[ch].ports.end ());
205 /** Remove a channel.
209 Bundle::remove_channel (uint32_t ch)
211 assert (ch < n_total());
213 Glib::Threads::Mutex::Lock lm (_channel_mutex);
214 _channel.erase (_channel.begin () + ch);
217 emit_changed (ConfigurationChanged);
220 /** Remove all channels */
222 Bundle::remove_channels ()
224 Glib::Threads::Mutex::Lock lm (_channel_mutex);
229 emit_changed (ConfigurationChanged);
232 /** @param p Port name.
233 * @return true if any channel is associated with p.
236 Bundle::offers_port (std::string p) const
238 Glib::Threads::Mutex::Lock lm (_channel_mutex);
240 for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
241 for (PortList::const_iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
251 /** @param p Port name.
252 * @return true if this bundle offers this port on its own on a channel.
255 Bundle::offers_port_alone (std::string p) const
257 Glib::Threads::Mutex::Lock lm (_channel_mutex);
259 for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
260 if (i->ports.size() == 1 && i->ports[0] == p) {
269 /** @param ch Channel.
270 * @return Channel name.
273 Bundle::channel_name (uint32_t ch) const
275 assert (ch < n_total());
277 Glib::Threads::Mutex::Lock lm (_channel_mutex);
278 return _channel[ch].name;
281 /** Set the name of a channel.
286 Bundle::set_channel_name (uint32_t ch, std::string const & n)
288 assert (ch < n_total());
291 Glib::Threads::Mutex::Lock lm (_channel_mutex);
292 _channel[ch].name = n;
295 emit_changed (NameChanged);
298 /** Take the channels from another bundle and add them to this bundle,
299 * so that channels from other are added to this (with their ports)
300 * and are named "<other_bundle_name> <other_channel_name>".
303 Bundle::add_channels_from_bundle (boost::shared_ptr<Bundle> other)
305 uint32_t const ch = n_total();
307 for (uint32_t i = 0; i < other->n_total(); ++i) {
310 s << other->name() << " " << other->channel_name(i);
312 add_channel (s.str(), other->channel_type(i));
314 PortList const& pl = other->channel_ports (i);
315 for (uint32_t j = 0; j < pl.size(); ++j) {
316 add_port_to_channel (ch + i, pl[j]);
321 /** Connect the ports associated with our channels to the ports associated
322 * with another bundle's channels.
323 * @param other Other bundle.
324 * @param engine AudioEngine to use to make the connections.
325 * @param allow_partial whether to allow leaving unconnected channels types,
326 * or require that the ChanCounts match exactly (default false).
329 Bundle::connect (boost::shared_ptr<Bundle> other, AudioEngine & engine,
332 ChanCount our_count = nchannels();
333 ChanCount other_count = other->nchannels();
335 if (!allow_partial && our_count != other_count) {
336 assert (our_count == other_count);
340 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
341 uint32_t N = our_count.n(*t);
342 if (N != other_count.n(*t))
344 for (uint32_t i = 0; i < N; ++i) {
345 Bundle::PortList const & our_ports =
346 channel_ports (type_channel_to_overall(*t, i));
347 Bundle::PortList const & other_ports =
348 other->channel_ports (other->type_channel_to_overall(*t, i));
350 for (Bundle::PortList::const_iterator j = our_ports.begin();
351 j != our_ports.end(); ++j) {
352 for (Bundle::PortList::const_iterator k = other_ports.begin();
353 k != other_ports.end(); ++k) {
354 engine.connect (*j, *k);
362 Bundle::disconnect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
364 ChanCount our_count = nchannels();
365 ChanCount other_count = other->nchannels();
367 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
368 uint32_t N = min(our_count.n(*t), other_count.n(*t));
369 for (uint32_t i = 0; i < N; ++i) {
370 Bundle::PortList const & our_ports =
371 channel_ports (type_channel_to_overall(*t, i));
372 Bundle::PortList const & other_ports =
373 other->channel_ports (other->type_channel_to_overall(*t, i));
375 for (Bundle::PortList::const_iterator j = our_ports.begin();
376 j != our_ports.end(); ++j) {
377 for (Bundle::PortList::const_iterator k = other_ports.begin();
378 k != other_ports.end(); ++k) {
379 engine.disconnect (*j, *k);
386 /** Remove all ports from all channels */
388 Bundle::remove_ports_from_channels ()
391 Glib::Threads::Mutex::Lock lm (_channel_mutex);
392 for (uint32_t c = 0; c < n_total(); ++c) {
393 _channel[c].ports.clear ();
398 emit_changed (PortsChanged);
401 /** Remove all ports from a given channel.
405 Bundle::remove_ports_from_channel (uint32_t ch)
407 assert (ch < n_total());
410 Glib::Threads::Mutex::Lock lm (_channel_mutex);
411 _channel[ch].ports.clear ();
414 emit_changed (PortsChanged);
418 Bundle::suspend_signals ()
420 _signals_suspended = true;
424 Bundle::resume_signals ()
426 if (_pending_change) {
427 Changed (_pending_change);
428 _pending_change = Change (0);
431 _signals_suspended = false;
435 Bundle::emit_changed (Change c)
437 if (_signals_suspended) {
438 _pending_change = Change (int (_pending_change) | int (c));
444 /** This must not be called in code executed as a response to a backend event,
445 * as it may query the backend in the same thread where it's waiting for us.
446 * @return true if a Bundle is connected to another.
447 * @param type: if not NIL, restrict the check to channels of that type.
448 * @param exclusive: if true, additionally check if the bundle is connected
449 * only to |other|, and return false if not. */
451 Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine,
452 DataType type, bool exclusive)
454 if (_ports_are_inputs == other->_ports_are_inputs)
457 if (type == DataType::NIL) {
458 for (DataType::iterator t = DataType::begin();
459 t != DataType::end(); ++t) {
460 if (!connected_to(other, engine, *t, exclusive))
466 uint32_t N = nchannels().n(type);
467 if (other->nchannels().n(type) != N)
470 vector<string> port_connections;
472 for (uint32_t i = 0; i < N; ++i) {
473 Bundle::PortList const & our_ports =
474 channel_ports (type_channel_to_overall(type, i));
475 Bundle::PortList const & other_ports =
476 other->channel_ports (other->type_channel_to_overall(type, i));
478 for (Bundle::PortList::const_iterator j = our_ports.begin();
479 j != our_ports.end(); ++j) {
480 boost::shared_ptr<Port> p = engine.get_port_by_name(*j);
482 for (Bundle::PortList::const_iterator k = other_ports.begin();
483 k != other_ports.end(); ++k) {
484 boost::shared_ptr<Port> q = engine.get_port_by_name(*k);
490 if (p && !p->connected_to (*k)) {
492 } else if (q && !q->connected_to (*j)) {
497 if (exclusive && p) {
498 port_connections.clear();
499 p->get_connections(port_connections);
500 if (port_connections.size() != other_ports.size())
509 /** This must not be called in code executed as a response to a backend event,
510 * as it uses the backend port_get_all_connections().
511 * @return true if any of this bundle's channels are connected to anything.
514 Bundle::connected_to_anything (AudioEngine& engine)
516 PortManager& pm (engine);
518 for (uint32_t i = 0; i < n_total(); ++i) {
519 Bundle::PortList const & ports = channel_ports (i);
521 for (uint32_t j = 0; j < ports.size(); ++j) {
523 /* ports[j] may not be an Ardour port, so use the port manager directly
524 rather than doing it with Port.
527 if (pm.connected (ports[j])) {
537 Bundle::set_ports_are_inputs ()
539 _ports_are_inputs = true;
540 emit_changed (DirectionChanged);
544 Bundle::set_ports_are_outputs ()
546 _ports_are_inputs = false;
547 emit_changed (DirectionChanged);
554 Bundle::set_name (string const & n)
557 emit_changed (NameChanged);
560 /** @param b Other bundle.
561 * @return true if b has the same number of channels as this bundle, and those channels have corresponding ports.
564 Bundle::has_same_ports (boost::shared_ptr<Bundle> b) const
566 ChanCount our_count = nchannels();
567 ChanCount other_count = b->nchannels();
569 if (our_count != other_count)
572 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
573 uint32_t N = our_count.n(*t);
574 for (uint32_t i = 0; i < N; ++i) {
575 Bundle::PortList const & our_ports =
576 channel_ports (type_channel_to_overall(*t, i));
577 Bundle::PortList const & other_ports =
578 b->channel_ports (b->type_channel_to_overall(*t, i));
580 if (our_ports != other_ports)
589 Bundle::channel_type (uint32_t c) const
591 assert (c < n_total());
593 Glib::Threads::Mutex::Lock lm (_channel_mutex);
594 return _channel[c].type;
598 operator<< (ostream& os, Bundle const & b)
600 os << "BUNDLE " << b.nchannels() << " channels: ";
601 for (uint32_t i = 0; i < b.n_total(); ++i) {
603 Bundle::PortList const & pl = b.channel_ports (i);
604 for (Bundle::PortList::const_iterator j = pl.begin(); j != pl.end(); ++j) {
614 Bundle::operator== (Bundle const & other)
616 return _channel == other._channel;
619 /** Given an index of a channel as the nth channel of a particular type,
620 * return an index of that channel when considering channels of all types.
622 * e.g. given a bundle with channels:
627 * If t == MIDI and c == 0, then we would return 2, as 2 is the index of the
630 * If t == NIL, we just return c.
634 Bundle::type_channel_to_overall (DataType t, uint32_t c) const
636 if (t == DataType::NIL) {
640 Glib::Threads::Mutex::Lock lm (_channel_mutex);
642 vector<Channel>::const_iterator i = _channel.begin ();
648 assert (i != _channel.end ());
662 abort(); /* NOTREACHED */
666 /** Perform the reverse of type_channel_to_overall */
668 Bundle::overall_channel_to_type (DataType t, uint32_t c) const
670 if (t == DataType::NIL) {
674 Glib::Threads::Mutex::Lock lm (_channel_mutex);
678 vector<Channel>::const_iterator i = _channel.begin ();
679 for (uint32_t j = 0; j < c; ++j) {