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