1 /*
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>
7  *
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.
12  *
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.
17  *
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.
21  */
22 
23 #include <algorithm>
24 
25 #include "ardour/bundle.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/port.h"
28 
29 #include "pbd/i18n.h"
30 
31 using namespace std;
32 using namespace ARDOUR;
33 using namespace PBD;
34 
35 /** Construct an audio bundle.
36  *  @param i true if ports are inputs, otherwise false.
37  */
Bundle(bool i)38 Bundle::Bundle (bool i)
39 	: _ports_are_inputs (i),
40 	  _signals_suspended (false),
41 	  _pending_change (Change (0))
42 {
43 
44 }
45 
46 
47 /** Construct an audio bundle.
48  *  @param n Name.
49  *  @param i true if ports are inputs, otherwise false.
50  */
Bundle(std::string const & n,bool i)51 Bundle::Bundle (std::string const & n, bool i)
52 	: _name (n),
53 	  _ports_are_inputs (i),
54 	  _signals_suspended (false),
55 	  _pending_change (Change (0))
56 {
57 
58 }
59 
Bundle(boost::shared_ptr<Bundle> other)60 Bundle::Bundle (boost::shared_ptr<Bundle> other)
61 	: _channel (other->_channel),
62 	  _name (other->_name),
63 	  _ports_are_inputs (other->_ports_are_inputs),
64 	  _signals_suspended (other->_signals_suspended),
65 	  _pending_change (other->_pending_change)
66 {
67 
68 }
69 
70 ChanCount
nchannels() const71 Bundle::nchannels () const
72 {
73 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
74 
75 	ChanCount c;
76 	for (vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
77 		c.set (i->type, c.get (i->type) + 1);
78 	}
79 
80 	return c;
81 }
82 
83 uint32_t
n_total() const84 Bundle::n_total () const
85 {
86     /* Simpler and far more efficient than nchannels.n_total() */
87     return _channel.size();
88 }
89 
90 Bundle::PortList const &
channel_ports(uint32_t c) const91 Bundle::channel_ports (uint32_t c) const
92 {
93 	assert (c < n_total());
94 
95 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
96 	return _channel[c].ports;
97 }
98 
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).
102  */
103 void
add_port_to_channel(uint32_t ch,string portname)104 Bundle::add_port_to_channel (uint32_t ch, string portname)
105 {
106 	assert (ch < n_total());
107 	assert (portname.find_first_of (':') != string::npos);
108 
109 	{
110 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
111 		_channel[ch].ports.push_back (portname);
112 	}
113 
114 	emit_changed (PortsChanged);
115 }
116 
117 /** Disassociate a port from one of our channels.
118  *  @param ch Channel index.
119  *  @param portname port name to disassociate from.
120  */
121 void
remove_port_from_channel(uint32_t ch,string portname)122 Bundle::remove_port_from_channel (uint32_t ch, string portname)
123 {
124 	assert (ch < n_total());
125 
126 	bool changed = false;
127 
128 	{
129 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
130 		PortList& pl = _channel[ch].ports;
131 		PortList::iterator i = find (pl.begin(), pl.end(), portname);
132 
133 		if (i != pl.end()) {
134 			pl.erase (i);
135 			changed = true;
136 		}
137 	}
138 
139 	if (changed) {
140 		emit_changed (PortsChanged);
141 	}
142 }
143 
144 /** Set a single port to be associated with a channel, removing any others.
145  *  @param ch Channel.
146  *  @param portname Full port name, including prefix.
147  */
148 void
set_port(uint32_t ch,string portname)149 Bundle::set_port (uint32_t ch, string portname)
150 {
151 	assert (ch < n_total());
152 	assert (portname.find_first_of (':') != string::npos);
153 
154 	{
155 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
156 		_channel[ch].ports.clear ();
157 		_channel[ch].ports.push_back (portname);
158 	}
159 
160 	emit_changed (PortsChanged);
161 }
162 
163 /** @param n Channel name */
164 void
add_channel(std::string const & n,DataType t)165 Bundle::add_channel (std::string const & n, DataType t)
166 {
167 	{
168 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
169 		_channel.push_back (Channel (n, t));
170 	}
171 
172 	emit_changed (ConfigurationChanged);
173 }
174 
175 /** @param n Channel name */
176 void
add_channel(std::string const & n,DataType t,PortList p)177 Bundle::add_channel (std::string const & n, DataType t, PortList p)
178 {
179 	{
180 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
181 		_channel.push_back (Channel (n, t, p));
182 	}
183 
184 	emit_changed (ConfigurationChanged);
185 }
186 
187 /** @param n Channel name */
188 void
add_channel(std::string const & n,DataType t,std::string const & p)189 Bundle::add_channel (std::string const & n, DataType t, std::string const & p)
190 {
191 	{
192 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
193 		_channel.push_back (Channel (n, t, p));
194 	}
195 
196 	emit_changed (ConfigurationChanged);
197 }
198 
199 bool
port_attached_to_channel(uint32_t ch,std::string portname)200 Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
201 {
202 	assert (ch < n_total());
203 
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 ());
206 }
207 
208 /** Remove a channel.
209  *  @param ch Channel.
210  */
211 void
remove_channel(uint32_t ch)212 Bundle::remove_channel (uint32_t ch)
213 {
214 	assert (ch < n_total());
215 
216 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
217 	_channel.erase (_channel.begin () + ch);
218 
219 	lm.release();
220 	emit_changed (ConfigurationChanged);
221 }
222 
223 /** Remove all channels */
224 void
remove_channels()225 Bundle::remove_channels ()
226 {
227 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
228 
229 	_channel.clear ();
230 
231 	lm.release();
232 	emit_changed (ConfigurationChanged);
233 }
234 
235 /** @param p Port name.
236  *  @return true if any channel is associated with p.
237  */
238 bool
offers_port(std::string p) const239 Bundle::offers_port (std::string p) const
240 {
241 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
242 
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) {
245 			if (*j == p) {
246 				return true;
247 			}
248 		}
249 	}
250 
251 	return false;
252 }
253 
254 /** @param p Port name.
255  *  @return true if this bundle offers this port on its own on a channel.
256  */
257 bool
offers_port_alone(std::string p) const258 Bundle::offers_port_alone (std::string p) const
259 {
260 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
261 
262 	for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
263 		if (i->ports.size() == 1 && i->ports[0] == p) {
264 			return true;
265 		}
266 	}
267 
268 	return false;
269 }
270 
271 
272 /** @param ch Channel.
273  *  @return Channel name.
274  */
275 std::string
channel_name(uint32_t ch) const276 Bundle::channel_name (uint32_t ch) const
277 {
278 	assert (ch < n_total());
279 
280 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
281 	return _channel[ch].name;
282 }
283 
284 /** Set the name of a channel.
285  *  @param ch Channel.
286  *  @param n New name.
287  */
288 void
set_channel_name(uint32_t ch,std::string const & n)289 Bundle::set_channel_name (uint32_t ch, std::string const & n)
290 {
291 	assert (ch < n_total());
292 
293 	{
294 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
295 		_channel[ch].name = n;
296 	}
297 
298 	emit_changed (NameChanged);
299 }
300 
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>".
304  */
305 void
add_channels_from_bundle(boost::shared_ptr<Bundle> other)306 Bundle::add_channels_from_bundle (boost::shared_ptr<Bundle> other)
307 {
308 	uint32_t const ch = n_total();
309 
310 	for (uint32_t i = 0; i < other->n_total(); ++i) {
311 
312 		std::stringstream s;
313 		s << other->name() << " " << other->channel_name(i);
314 
315 		add_channel (s.str(), other->channel_type(i));
316 
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]);
320 		}
321 	}
322 }
323 
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).
330  */
331 void
connect(boost::shared_ptr<Bundle> other,AudioEngine & engine,bool allow_partial)332 Bundle::connect (boost::shared_ptr<Bundle> other, AudioEngine & engine,
333                  bool allow_partial)
334 {
335 	ChanCount our_count = nchannels();
336 	ChanCount other_count = other->nchannels();
337 
338 	if (!allow_partial && our_count != other_count) {
339 		assert (our_count == other_count);
340 		return;
341 	}
342 
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))
346 			continue;
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));
352 
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);
358 				}
359 			}
360 		}
361 	}
362 }
363 
364 void
disconnect(boost::shared_ptr<Bundle> other,AudioEngine & engine)365 Bundle::disconnect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
366 {
367 	ChanCount our_count = nchannels();
368 	ChanCount other_count = other->nchannels();
369 
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));
377 
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);
383 				}
384 			}
385 		}
386 	}
387 }
388 
389 /** Remove all ports from all channels */
390 void
remove_ports_from_channels()391 Bundle::remove_ports_from_channels ()
392 {
393 	{
394 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
395 		for (uint32_t c = 0; c < n_total(); ++c) {
396 			_channel[c].ports.clear ();
397 		}
398 
399 	}
400 
401 	emit_changed (PortsChanged);
402 }
403 
404 /** Remove all ports from a given channel.
405  *  @param ch Channel.
406  */
407 void
remove_ports_from_channel(uint32_t ch)408 Bundle::remove_ports_from_channel (uint32_t ch)
409 {
410 	assert (ch < n_total());
411 
412 	{
413 		Glib::Threads::Mutex::Lock lm (_channel_mutex);
414 		_channel[ch].ports.clear ();
415 	}
416 
417 	emit_changed (PortsChanged);
418 }
419 
420 void
suspend_signals()421 Bundle::suspend_signals ()
422 {
423 	_signals_suspended = true;
424 }
425 
426 void
resume_signals()427 Bundle::resume_signals ()
428 {
429 	if (_pending_change) {
430 		Changed (_pending_change);
431 		_pending_change = Change (0);
432 	}
433 
434 	_signals_suspended = false;
435 }
436 
437 void
emit_changed(Change c)438 Bundle::emit_changed (Change c)
439 {
440 	if (_signals_suspended) {
441 		_pending_change = Change (int (_pending_change) | int (c));
442 	} else {
443 		Changed (c);
444 	}
445 }
446 
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. */
453 bool
connected_to(boost::shared_ptr<Bundle> other,AudioEngine & engine,DataType type,bool exclusive)454 Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine,
455                       DataType type, bool exclusive)
456 {
457 	if (_ports_are_inputs == other->_ports_are_inputs)
458 		return false;
459 
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))
464 				return false;
465 		}
466 		return true;
467 	}
468 
469 	uint32_t N = nchannels().n(type);
470 	if (other->nchannels().n(type) != N)
471 		return false;
472 
473 	vector<string> port_connections;
474 
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));
480 
481 		for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
482 
483 			boost::shared_ptr<Port> p = engine.get_port_by_name(*j);
484 
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);
488 
489 				if (!p && !q) {
490 					return false;
491 				}
492 
493 				if (p && !p->connected_to (*k)) {
494 					return false;
495 				} else if (q && !q->connected_to (*j)) {
496 					return false;
497 				}
498 			}
499 
500 			if (exclusive && p) {
501 				port_connections.clear();
502 				p->get_connections(port_connections);
503 				if (port_connections.size() != other_ports.size())
504 					return false;
505 			}
506 		}
507 	}
508 
509 	return true;
510 }
511 
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.
515  */
516 bool
connected_to_anything(AudioEngine & engine)517 Bundle::connected_to_anything (AudioEngine& engine)
518 {
519 	PortManager& pm (engine);
520 
521 	for (uint32_t i = 0; i < n_total(); ++i) {
522 		Bundle::PortList const & ports = channel_ports (i);
523 
524 		for (uint32_t j = 0; j < ports.size(); ++j) {
525 
526 			/* ports[j] may not be an Ardour port, so use the port manager directly
527 			   rather than doing it with Port.
528 			*/
529 
530 			if (pm.connected (ports[j])) {
531 				return true;
532 			}
533 		}
534 	}
535 
536 	return false;
537 }
538 
539 void
set_ports_are_inputs()540 Bundle::set_ports_are_inputs ()
541 {
542 	_ports_are_inputs = true;
543 	emit_changed (DirectionChanged);
544 }
545 
546 void
set_ports_are_outputs()547 Bundle::set_ports_are_outputs ()
548 {
549 	_ports_are_inputs = false;
550 	emit_changed (DirectionChanged);
551 }
552 
553 /** Set the name.
554  *  @param n New name.
555  */
556 void
set_name(string const & n)557 Bundle::set_name (string const & n)
558 {
559 	_name = n;
560 	emit_changed (NameChanged);
561 }
562 
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.
565  */
566 bool
has_same_ports(boost::shared_ptr<Bundle> b) const567 Bundle::has_same_ports (boost::shared_ptr<Bundle> b) const
568 {
569 	ChanCount our_count = nchannels();
570 	ChanCount other_count = b->nchannels();
571 
572 	if (our_count != other_count)
573 		return false;
574 
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));
582 
583 			if (our_ports != other_ports)
584 				return false;
585 		}
586 	}
587 
588 	return true;
589 }
590 
591 DataType
channel_type(uint32_t c) const592 Bundle::channel_type (uint32_t c) const
593 {
594 	assert (c < n_total());
595 
596 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
597 	return _channel[c].type;
598 }
599 
600 ostream &
operator <<(ostream & os,Bundle const & b)601 operator<< (ostream& os, Bundle const & b)
602 {
603 	os << "BUNDLE " << b.nchannels() << " channels: ";
604 	for (uint32_t i = 0; i < b.n_total(); ++i) {
605 		os << "( ";
606 		Bundle::PortList const & pl = b.channel_ports (i);
607 		for (Bundle::PortList::const_iterator j = pl.begin(); j != pl.end(); ++j) {
608 			os << *j << " ";
609 		}
610 		os << ") ";
611 	}
612 
613 	return os;
614 }
615 
616 bool
operator ==(Bundle const & other)617 Bundle::operator== (Bundle const & other)
618 {
619 	return _channel == other._channel;
620 }
621 
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.
624  *
625  *  e.g. given a bundle with channels:
626  *          fred   [audio]
627  *          jim    [audio]
628  *          sheila [midi]
629  *
630  * If t == MIDI and c == 0, then we would return 2, as 2 is the index of the
631  * 0th MIDI channel.
632  *
633  * If t == NIL, we just return c.
634  */
635 
636 uint32_t
type_channel_to_overall(DataType t,uint32_t c) const637 Bundle::type_channel_to_overall (DataType t, uint32_t c) const
638 {
639 	if (t == DataType::NIL) {
640 		return c;
641 	}
642 
643 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
644 
645 	vector<Channel>::const_iterator i = _channel.begin ();
646 
647 	uint32_t o = 0;
648 
649 	while (1) {
650 
651 		assert (i != _channel.end ());
652 
653 		if (i->type != t) {
654 			++i;
655 		} else {
656 			if (c == 0) {
657 				return o;
658 			}
659 			--c;
660 		}
661 
662 		++o;
663 	}
664 
665 	abort(); /* NOTREACHED */
666 	return -1;
667 }
668 
669 /** Perform the reverse of type_channel_to_overall */
670 uint32_t
overall_channel_to_type(DataType t,uint32_t c) const671 Bundle::overall_channel_to_type (DataType t, uint32_t c) const
672 {
673 	if (t == DataType::NIL) {
674 		return c;
675 	}
676 
677 	Glib::Threads::Mutex::Lock lm (_channel_mutex);
678 
679 	uint32_t s = 0;
680 
681 	vector<Channel>::const_iterator i = _channel.begin ();
682 	for (uint32_t j = 0; j < c; ++j) {
683 		if (i->type == t) {
684 			++s;
685 		}
686 		++i;
687 	}
688 
689 	return s;
690 }
691