remove a bunch of uses of long (mostly replaced by int32_t)
[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 "pbd/failed_constructor.h"
23 #include "ardour/ardour.h"
24 #include "ardour/bundle.h"
25 #include "ardour/audioengine.h"
26 #include "ardour/port.h"
27 #include "pbd/xml++.h"
28
29 #include "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  */
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  */
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
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
71 Bundle::nchannels () const
72 {
73         Glib::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 Bundle::PortList const &
84 Bundle::channel_ports (uint32_t c) const
85 {
86         assert (c < nchannels().n_total());
87
88         Glib::Mutex::Lock lm (_channel_mutex);
89         return _channel[c].ports;
90 }
91
92 /** Add an association between one of our channels and a port.
93  *  @param ch Channel index.
94  *  @param portname full port name to associate with (including prefix).
95  */
96 void
97 Bundle::add_port_to_channel (uint32_t ch, string portname)
98 {
99         assert (ch < nchannels().n_total());
100         assert (portname.find_first_of (':') != string::npos);
101
102         {
103                 Glib::Mutex::Lock lm (_channel_mutex);
104                 _channel[ch].ports.push_back (portname);
105         }
106
107         emit_changed (PortsChanged);
108 }
109
110 /** Disassociate a port from one of our channels.
111  *  @param ch Channel index.
112  *  @param portname port name to disassociate from.
113  */
114 void
115 Bundle::remove_port_from_channel (uint32_t ch, string portname)
116 {
117         assert (ch < nchannels().n_total());
118
119         bool changed = false;
120
121         {
122                 Glib::Mutex::Lock lm (_channel_mutex);
123                 PortList& pl = _channel[ch].ports;
124                 PortList::iterator i = find (pl.begin(), pl.end(), portname);
125
126                 if (i != pl.end()) {
127                         pl.erase (i);
128                         changed = true;
129                 }
130         }
131
132         if (changed) {
133                 emit_changed (PortsChanged);
134         }
135 }
136
137 /** Set a single port to be associated with a channel, removing any others.
138  *  @param ch Channel.
139  *  @param portname Full port name, including prefix.
140  */
141 void
142 Bundle::set_port (uint32_t ch, string portname)
143 {
144         assert (ch < nchannels().n_total());
145         assert (portname.find_first_of (':') != string::npos);
146
147         {
148                 Glib::Mutex::Lock lm (_channel_mutex);
149                 _channel[ch].ports.clear ();
150                 _channel[ch].ports.push_back (portname);
151         }
152
153         emit_changed (PortsChanged);
154 }
155
156 /** @param n Channel name */
157 void
158 Bundle::add_channel (std::string const & n, DataType t)
159 {
160         {
161                 Glib::Mutex::Lock lm (_channel_mutex);
162                 _channel.push_back (Channel (n, t));
163         }
164
165         emit_changed (ConfigurationChanged);
166 }
167
168 bool
169 Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
170 {
171         assert (ch < nchannels().n_total());
172
173         Glib::Mutex::Lock lm (_channel_mutex);
174         return (std::find (_channel[ch].ports.begin (), _channel[ch].ports.end (), portname) != _channel[ch].ports.end ());
175 }
176
177 /** Remove a channel.
178  *  @param ch Channel.
179  */
180 void
181 Bundle::remove_channel (uint32_t ch)
182 {
183         assert (ch < nchannels().n_total());
184
185         Glib::Mutex::Lock lm (_channel_mutex);
186         _channel.erase (_channel.begin () + ch);
187 }
188
189 /** Remove all channels */
190 void
191 Bundle::remove_channels ()
192 {
193         Glib::Mutex::Lock lm (_channel_mutex);
194
195         _channel.clear ();
196 }
197
198 /** @param p Port name.
199  *  @return true if any channel is associated with p.
200  */
201 bool
202 Bundle::uses_port (std::string p) const
203 {
204         Glib::Mutex::Lock lm (_channel_mutex);
205
206         for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
207                 for (PortList::const_iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
208                         if (*j == p) {
209                                 return true;
210                         }
211                 }
212         }
213
214         return false;
215 }
216
217 /** @param p Port name.
218  *  @return true if this bundle offers this port on its own on a channel.
219  */
220 bool
221 Bundle::offers_port_alone (std::string p) const
222 {
223         Glib::Mutex::Lock lm (_channel_mutex);
224
225         for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
226                 if (i->ports.size() == 1 && i->ports[0] == p) {
227                         return true;
228                 }
229         }
230
231         return false;
232 }
233
234
235 /** @param ch Channel.
236  *  @return Channel name.
237  */
238 std::string
239 Bundle::channel_name (uint32_t ch) const
240 {
241         assert (ch < nchannels().n_total());
242
243         Glib::Mutex::Lock lm (_channel_mutex);
244         return _channel[ch].name;
245 }
246
247 /** Set the name of a channel.
248  *  @param ch Channel.
249  *  @param n New name.
250  */
251 void
252 Bundle::set_channel_name (uint32_t ch, std::string const & n)
253 {
254         assert (ch < nchannels().n_total());
255
256         {
257                 Glib::Mutex::Lock lm (_channel_mutex);
258                 _channel[ch].name = n;
259         }
260
261         emit_changed (NameChanged);
262 }
263
264 /** Take the channels from another bundle and add them to this bundle,
265  *  so that channels from other are added to this (with their ports)
266  *  and are named "<other_bundle_name> <other_channel_name>".
267  */
268 void
269 Bundle::add_channels_from_bundle (boost::shared_ptr<Bundle> other)
270 {
271         uint32_t const ch = nchannels().n_total();
272
273         for (uint32_t i = 0; i < other->nchannels().n_total(); ++i) {
274
275                 std::stringstream s;
276                 s << other->name() << " " << other->channel_name(i);
277
278                 add_channel (s.str(), other->channel_type(i));
279
280                 PortList const& pl = other->channel_ports (i);
281                 for (uint32_t j = 0; j < pl.size(); ++j) {
282                         add_port_to_channel (ch + i, pl[j]);
283                 }
284         }
285 }
286
287 /** Connect the ports associated with our channels to the ports associated
288  *  with another bundle's channels.
289  *  @param other Other bundle.
290  *  @param engine AudioEngine to use to make the connections.
291  */
292 void
293 Bundle::connect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
294 {
295         uint32_t const N = nchannels().n_total();
296         assert (N == other->nchannels().n_total());
297
298         for (uint32_t i = 0; i < N; ++i) {
299                 Bundle::PortList const & our_ports = channel_ports (i);
300                 Bundle::PortList const & other_ports = other->channel_ports (i);
301
302                 for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
303                         for (Bundle::PortList::const_iterator k = other_ports.begin(); k != other_ports.end(); ++k) {
304                                 engine.connect (*j, *k);
305                         }
306                 }
307         }
308 }
309
310 void
311 Bundle::disconnect (boost::shared_ptr<Bundle> other, AudioEngine & engine)
312 {
313         uint32_t const N = nchannels().n_total();
314         assert (N == other->nchannels().n_total());
315
316         for (uint32_t i = 0; i < N; ++i) {
317                 Bundle::PortList const & our_ports = channel_ports (i);
318                 Bundle::PortList const & other_ports = other->channel_ports (i);
319
320                 for (Bundle::PortList::const_iterator j = our_ports.begin(); j != our_ports.end(); ++j) {
321                         for (Bundle::PortList::const_iterator k = other_ports.begin(); k != other_ports.end(); ++k) {
322                                 engine.disconnect (*j, *k);
323                         }
324                 }
325         }
326 }
327
328 /** Remove all ports from all channels */
329 void
330 Bundle::remove_ports_from_channels ()
331 {
332         {
333                 Glib::Mutex::Lock lm (_channel_mutex);
334                 for (uint32_t c = 0; c < _channel.size(); ++c) {
335                         _channel[c].ports.clear ();
336                 }
337
338         }
339
340         emit_changed (PortsChanged);
341 }
342
343 /** Remove all ports from a given channel.
344  *  @param ch Channel.
345  */
346 void
347 Bundle::remove_ports_from_channel (uint32_t ch)
348 {
349         assert (ch < nchannels().n_total());
350
351         {
352                 Glib::Mutex::Lock lm (_channel_mutex);
353                 _channel[ch].ports.clear ();
354         }
355
356         emit_changed (PortsChanged);
357 }
358
359 void
360 Bundle::suspend_signals ()
361 {
362         _signals_suspended = true;
363 }
364
365 void
366 Bundle::resume_signals ()
367 {
368         if (_pending_change) {
369                 Changed (_pending_change);
370                 _pending_change = Change (0);
371         }
372
373         _signals_suspended = false;
374 }
375
376 void
377 Bundle::emit_changed (Change c)
378 {
379         if (_signals_suspended) {
380                 _pending_change = Change (int (_pending_change) | int (c));
381         } else {
382                 Changed (c);
383         }
384 }
385
386 bool
387 Bundle::connected_to (boost::shared_ptr<Bundle> other, AudioEngine & engine)
388 {
389         if (_ports_are_inputs == other->_ports_are_inputs || nchannels() != other->nchannels()) {
390                 return false;
391         }
392
393         for (uint32_t i = 0; i < nchannels().n_total(); ++i) {
394                 Bundle::PortList const & A = channel_ports (i);
395                 Bundle::PortList const & B = other->channel_ports (i);
396
397                 for (uint32_t j = 0; j < A.size(); ++j) {
398                         for (uint32_t k = 0; k < B.size(); ++k) {
399
400                                 Port* p = engine.get_port_by_name (A[j]);
401                                 Port* q = engine.get_port_by_name (B[k]);
402
403                                 if (!p && !q) {
404                                         return false;
405                                 }
406
407                                 if (p && !p->connected_to (B[k])) {
408                                         return false;
409                                 } else if (q && !q->connected_to (A[j])) {
410                                         return false;
411                                 }
412                         }
413                 }
414         }
415
416         return true;
417 }
418
419 void
420 Bundle::set_ports_are_inputs ()
421 {
422         _ports_are_inputs = true;
423         emit_changed (DirectionChanged);
424 }
425
426 void
427 Bundle::set_ports_are_outputs ()
428 {
429         _ports_are_inputs = false;
430         emit_changed (DirectionChanged);
431 }
432
433 /** Set the name.
434  *  @param n New name.
435  */
436 void
437 Bundle::set_name (string const & n)
438 {
439         _name = n;
440         emit_changed (NameChanged);
441 }
442
443 /** @param b Other bundle.
444  *  @return true if b has the same number of channels as this bundle, and those channels have corresponding ports.
445  */
446 bool
447 Bundle::has_same_ports (boost::shared_ptr<Bundle> b) const
448 {
449         uint32_t const N = nchannels().n_total();
450
451         if (b->nchannels().n_total() != N) {
452                 return false;
453         }
454
455         /* XXX: probably should sort channel port lists before comparing them */
456
457         for (uint32_t i = 0; i < N; ++i) {
458                 if (channel_ports (i) != b->channel_ports (i)) {
459                         return false;
460                 }
461         }
462
463         return true;
464 }
465
466 DataType
467 Bundle::channel_type (uint32_t c) const
468 {
469         assert (c < nchannels().n_total());
470
471         Glib::Mutex::Lock lm (_channel_mutex);
472         return _channel[c].type;
473 }