2 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2009-2012 David Robillard <d@drobilla.net>
5 * Copyright (C) 2013-2015 Robin Gareus <robin@gareus.org>
6 * Copyright (C) 2017 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "ardour/bundle.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/port.h"
32 using namespace ARDOUR;
35 /** Construct an audio bundle.
36 * @param i true if ports are inputs, otherwise false.
38 Bundle::Bundle (bool i)
39 : _ports_are_inputs (i),
40 _signals_suspended (false),
41 _pending_change (Change (0))
47 /** Construct an audio bundle.
49 * @param i true if ports are inputs, otherwise false.
51 Bundle::Bundle (std::string const & n, bool i)
53 _ports_are_inputs (i),
54 _signals_suspended (false),
55 _pending_change (Change (0))
60 Bundle::Bundle (boost::shared_ptr<Bundle> other)
61 : _channel (other->_channel),
63 _ports_are_inputs (other->_ports_are_inputs),
64 _signals_suspended (other->_signals_suspended),
65 _pending_change (other->_pending_change)
71 Bundle::nchannels () const
73 Glib::Threads::Mutex::Lock lm (_channel_mutex);
76 for (vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
77 c.set (i->type, c.get (i->type) + 1);
84 Bundle::n_total () const
86 /* Simpler and far more efficient than nchannels.n_total() */
87 return _channel.size();
90 Bundle::PortList const &
91 Bundle::channel_ports (uint32_t c) const
93 assert (c < n_total());
95 Glib::Threads::Mutex::Lock lm (_channel_mutex);
96 return _channel[c].ports;
99 /** Add an association between one of our channels and a port.
100 * @param ch Channel index.
101 * @param portname full port name to associate with (including prefix).
104 Bundle::add_port_to_channel (uint32_t ch, string portname)
106 assert (ch < n_total());
107 assert (portname.find_first_of (':') != string::npos);
110 Glib::Threads::Mutex::Lock lm (_channel_mutex);
111 _channel[ch].ports.push_back (portname);
114 emit_changed (PortsChanged);
117 /** Disassociate a port from one of our channels.
118 * @param ch Channel index.
119 * @param portname port name to disassociate from.
122 Bundle::remove_port_from_channel (uint32_t ch, string portname)
124 assert (ch < n_total());
126 bool changed = false;
129 Glib::Threads::Mutex::Lock lm (_channel_mutex);
130 PortList& pl = _channel[ch].ports;
131 PortList::iterator i = find (pl.begin(), pl.end(), portname);
140 emit_changed (PortsChanged);
144 /** Set a single port to be associated with a channel, removing any others.
146 * @param portname Full port name, including prefix.
149 Bundle::set_port (uint32_t ch, string portname)
151 assert (ch < n_total());
152 assert (portname.find_first_of (':') != string::npos);
155 Glib::Threads::Mutex::Lock lm (_channel_mutex);
156 _channel[ch].ports.clear ();
157 _channel[ch].ports.push_back (portname);
160 emit_changed (PortsChanged);
163 /** @param n Channel name */
165 Bundle::add_channel (std::string const & n, DataType t)
168 Glib::Threads::Mutex::Lock lm (_channel_mutex);
169 _channel.push_back (Channel (n, t));
172 emit_changed (ConfigurationChanged);
175 /** @param n Channel name */
177 Bundle::add_channel (std::string const & n, DataType t, PortList p)
180 Glib::Threads::Mutex::Lock lm (_channel_mutex);
181 _channel.push_back (Channel (n, t, p));
184 emit_changed (ConfigurationChanged);
187 /** @param n Channel name */
189 Bundle::add_channel (std::string const & n, DataType t, std::string const & p)
192 Glib::Threads::Mutex::Lock lm (_channel_mutex);
193 _channel.push_back (Channel (n, t, p));
196 emit_changed (ConfigurationChanged);
200 Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
202 assert (ch < n_total());
204 Glib::Threads::Mutex::Lock lm (_channel_mutex);
205 return (std::find (_channel[ch].ports.begin (), _channel[ch].ports.end (), portname) != _channel[ch].ports.end ());
208 /** Remove a channel.
212 Bundle::remove_channel (uint32_t ch)
214 assert (ch < n_total());
216 Glib::Threads::Mutex::Lock lm (_channel_mutex);
217 _channel.erase (_channel.begin () + ch);
220 emit_changed (ConfigurationChanged);
223 /** Remove all channels */
225 Bundle::remove_channels ()
227 Glib::Threads::Mutex::Lock lm (_channel_mutex);
232 emit_changed (ConfigurationChanged);
235 /** @param p Port name.
236 * @return true if any channel is associated with p.
239 Bundle::offers_port (std::string p) const
241 Glib::Threads::Mutex::Lock lm (_channel_mutex);
243 for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
244 for (PortList::const_iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
254 /** @param p Port name.
255 * @return true if this bundle offers this port on its own on a channel.
258 Bundle::offers_port_alone (std::string p) const
260 Glib::Threads::Mutex::Lock lm (_channel_mutex);
262 for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
263 if (i->ports.size() == 1 && i->ports[0] == p) {
272 /** @param ch Channel.
273 * @return Channel name.
276 Bundle::channel_name (uint32_t ch) const
278 assert (ch < n_total());
280 Glib::Threads::Mutex::Lock lm (_channel_mutex);
281 return _channel[ch].name;
284 /** Set the name of a channel.
289 Bundle::set_channel_name (uint32_t ch, std::string const & n)
291 assert (ch < n_total());
294 Glib::Threads::Mutex::Lock lm (_channel_mutex);
295 _channel[ch].name = n;
298 emit_changed (NameChanged);
301 /** Take the channels from another bundle and add them to this bundle,
302 * so that channels from other are added to this (with their ports)
303 * and are named "<other_bundle_name> <other_channel_name>".
306 Bundle::add_channels_from_bundle (boost::shared_ptr<Bundle> other)
308 uint32_t const ch = n_total();
310 for (uint32_t i = 0; i < other->n_total(); ++i) {
313 s << other->name() << " " << other->channel_name(i);
315 add_channel (s.str(), other->channel_type(i));
317 PortList const& pl = other->channel_ports (i);
318 for (uint32_t j = 0; j < pl.size(); ++j) {
319 add_port_to_channel (ch + i, pl[j]);
324 /** Connect the ports associated with our channels to the ports associated
325 * with another bundle's channels.
326 * @param other Other bundle.
327 * @param engine AudioEngine to use to make the connections.
328 * @param allow_partial whether to allow leaving unconnected channels types,
329 * or require that the ChanCounts match exactly (default false).
332 Bundle::connect (boost::shared_ptr<Bundle> other, AudioEngine & engine,
335 ChanCount our_count = nchannels();
336 ChanCount other_count = other->nchannels();
338 if (!allow_partial && our_count != other_count) {
339 assert (our_count == other_count);
343 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
344 uint32_t N = our_count.n(*t);
345 if (N != other_count.n(*t))
347 for (uint32_t i = 0; i < N; ++i) {
348 Bundle::PortList const & our_ports =
349 channel_ports (type_channel_to_overall(*t, i));
350 Bundle::PortList const & other_ports =
351 other->channel_ports (other->type_channel_to_overall(*t, i));
353 for (Bundle::PortList::const_iterator j = our_ports.begin();
354 j != our_ports.end(); ++j) {
355 for (Bundle::PortList::const_iterator k = other_ports.begin();
356 k != other_ports.end(); ++k) {
357 engine.connect (*j, *k);
365 Bundle::disconnect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
367 ChanCount our_count = nchannels();
368 ChanCount other_count = other->nchannels();
370 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
371 uint32_t N = min(our_count.n(*t), other_count.n(*t));
372 for (uint32_t i = 0; i < N; ++i) {
373 Bundle::PortList const & our_ports =
374 channel_ports (type_channel_to_overall(*t, i));
375 Bundle::PortList const & other_ports =
376 other->channel_ports (other->type_channel_to_overall(*t, i));
378 for (Bundle::PortList::const_iterator j = our_ports.begin();
379 j != our_ports.end(); ++j) {
380 for (Bundle::PortList::const_iterator k = other_ports.begin();
381 k != other_ports.end(); ++k) {
382 engine.disconnect (*j, *k);
389 /** Remove all ports from all channels */
391 Bundle::remove_ports_from_channels ()
394 Glib::Threads::Mutex::Lock lm (_channel_mutex);
395 for (uint32_t c = 0; c < n_total(); ++c) {
396 _channel[c].ports.clear ();
401 emit_changed (PortsChanged);
404 /** Remove all ports from a given channel.
408 Bundle::remove_ports_from_channel (uint32_t ch)
410 assert (ch < n_total());
413 Glib::Threads::Mutex::Lock lm (_channel_mutex);
414 _channel[ch].ports.clear ();
417 emit_changed (PortsChanged);
421 Bundle::suspend_signals ()
423 _signals_suspended = true;
427 Bundle::resume_signals ()
429 if (_pending_change) {
430 Changed (_pending_change);
431 _pending_change = Change (0);
434 _signals_suspended = false;
438 Bundle::emit_changed (Change c)
440 if (_signals_suspended) {
441 _pending_change = Change (int (_pending_change) | int (c));
447 /** This must not be called in code executed as a response to a backend event,
448 * as it may query the backend in the same thread where it's waiting for us.
449 * @return true if a Bundle is connected to another.
450 * @param type: if not NIL, restrict the check to channels of that type.
451 * @param exclusive: if true, additionally check if the bundle is connected
452 * only to |other|, and return false if not. */
454 Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine,
455 DataType type, bool exclusive)
457 if (_ports_are_inputs == other->_ports_are_inputs)
460 if (type == DataType::NIL) {
461 for (DataType::iterator t = DataType::begin();
462 t != DataType::end(); ++t) {
463 if (!connected_to(other, engine, *t, exclusive))
469 uint32_t N = nchannels().n(type);
470 if (other->nchannels().n(type) != N)
473 vector<string> port_connections;
475 for (uint32_t i = 0; i < N; ++i) {
476 Bundle::PortList const & our_ports =
477 channel_ports (type_channel_to_overall(type, i));
478 Bundle::PortList const & other_ports =
479 other->channel_ports (other->type_channel_to_overall(type, i));
481 for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
483 boost::shared_ptr<Port> p = engine.get_port_by_name(*j);
485 for (Bundle::PortList::const_iterator k = other_ports.begin();
486 k != other_ports.end(); ++k) {
487 boost::shared_ptr<Port> q = engine.get_port_by_name(*k);
493 if (p && !p->connected_to (*k)) {
495 } else if (q && !q->connected_to (*j)) {
500 if (exclusive && p) {
501 port_connections.clear();
502 p->get_connections(port_connections);
503 if (port_connections.size() != other_ports.size())
512 /** This must not be called in code executed as a response to a backend event,
513 * as it uses the backend port_get_all_connections().
514 * @return true if any of this bundle's channels are connected to anything.
517 Bundle::connected_to_anything (AudioEngine& engine)
519 PortManager& pm (engine);
521 for (uint32_t i = 0; i < n_total(); ++i) {
522 Bundle::PortList const & ports = channel_ports (i);
524 for (uint32_t j = 0; j < ports.size(); ++j) {
526 /* ports[j] may not be an Ardour port, so use the port manager directly
527 rather than doing it with Port.
530 if (pm.connected (ports[j])) {
540 Bundle::set_ports_are_inputs ()
542 _ports_are_inputs = true;
543 emit_changed (DirectionChanged);
547 Bundle::set_ports_are_outputs ()
549 _ports_are_inputs = false;
550 emit_changed (DirectionChanged);
557 Bundle::set_name (string const & n)
560 emit_changed (NameChanged);
563 /** @param b Other bundle.
564 * @return true if b has the same number of channels as this bundle, and those channels have corresponding ports.
567 Bundle::has_same_ports (boost::shared_ptr<Bundle> b) const
569 ChanCount our_count = nchannels();
570 ChanCount other_count = b->nchannels();
572 if (our_count != other_count)
575 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
576 uint32_t N = our_count.n(*t);
577 for (uint32_t i = 0; i < N; ++i) {
578 Bundle::PortList const & our_ports =
579 channel_ports (type_channel_to_overall(*t, i));
580 Bundle::PortList const & other_ports =
581 b->channel_ports (b->type_channel_to_overall(*t, i));
583 if (our_ports != other_ports)
592 Bundle::channel_type (uint32_t c) const
594 assert (c < n_total());
596 Glib::Threads::Mutex::Lock lm (_channel_mutex);
597 return _channel[c].type;
601 operator<< (ostream& os, Bundle const & b)
603 os << "BUNDLE " << b.nchannels() << " channels: ";
604 for (uint32_t i = 0; i < b.n_total(); ++i) {
606 Bundle::PortList const & pl = b.channel_ports (i);
607 for (Bundle::PortList::const_iterator j = pl.begin(); j != pl.end(); ++j) {
617 Bundle::operator== (Bundle const & other)
619 return _channel == other._channel;
622 /** Given an index of a channel as the nth channel of a particular type,
623 * return an index of that channel when considering channels of all types.
625 * e.g. given a bundle with channels:
630 * If t == MIDI and c == 0, then we would return 2, as 2 is the index of the
633 * If t == NIL, we just return c.
637 Bundle::type_channel_to_overall (DataType t, uint32_t c) const
639 if (t == DataType::NIL) {
643 Glib::Threads::Mutex::Lock lm (_channel_mutex);
645 vector<Channel>::const_iterator i = _channel.begin ();
651 assert (i != _channel.end ());
665 abort(); /* NOTREACHED */
669 /** Perform the reverse of type_channel_to_overall */
671 Bundle::overall_channel_to_type (DataType t, uint32_t c) const
673 if (t == DataType::NIL) {
677 Glib::Threads::Mutex::Lock lm (_channel_mutex);
681 vector<Channel>::const_iterator i = _channel.begin ();
682 for (uint32_t j = 0; j < c; ++j) {