make BusProfile argument to new Session constructor be const (and in associated call...
[ardour.git] / libs / ardour / io.cc
1 /*
2  * Copyright (C) 2000-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
4  * Copyright (C) 2006 Jesse Chappell <jesse@essej.net>
5  * Copyright (C) 2007-2011 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2013-2015 John Emmas <john@creativepost.co.uk>
7  * Copyright (C) 2013-2016 Tim Mayberry <mojofunk@gmail.com>
8  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
9  * Copyright (C) 2015 GZharun <grygoriiz@wavesglobal.com>
10  * Copyright (C) 2016-2017 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27 #include <algorithm>
28 #include <cmath>
29 #include <vector>
30
31 #include <unistd.h>
32 #include <locale.h>
33 #include <errno.h>
34
35 #include <glibmm.h>
36 #include <glibmm/threads.h>
37
38 #include "pbd/xml++.h"
39 #include "pbd/replace_all.h"
40 #include "pbd/unknown_type.h"
41 #include "pbd/enumwriter.h"
42 #include "pbd/locale_guard.h"
43 #include "pbd/types_convert.h"
44
45 #include "ardour/audioengine.h"
46 #include "ardour/buffer.h"
47 #include "ardour/buffer_set.h"
48 #include "ardour/debug.h"
49 #include "ardour/io.h"
50 #include "ardour/port.h"
51 #include "ardour/profile.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/types_convert.h"
55 #include "ardour/user_bundle.h"
56
57 #include "pbd/i18n.h"
58
59 #define BLOCK_PROCESS_CALLBACK() Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock())
60
61 using namespace std;
62 using namespace ARDOUR;
63 using namespace PBD;
64
65 const string                 IO::state_node_name = "IO";
66 bool                         IO::connecting_legal = false;
67 PBD::Signal0<int>            IO::ConnectingLegal;
68 PBD::Signal1<void,ChanCount> IO::PortCountChanged;
69
70 /** @param default_type The type of port that will be created by ensure_io
71  * and friends if no type is explicitly requested (to avoid breakage).
72  */
73 IO::IO (Session& s, const string& name, Direction dir, DataType default_type, bool sendish)
74         : SessionObject (s, name)
75         , _direction (dir)
76         , _default_type (default_type)
77         , _sendish (sendish)
78 {
79         _active = true;
80         Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
81         pending_state_node = 0;
82         setup_bundle ();
83 }
84
85 IO::IO (Session& s, const XMLNode& node, DataType dt, bool sendish)
86         : SessionObject(s, "unnamed io")
87         , _direction (Input)
88         , _default_type (dt)
89         , _sendish (sendish)
90 {
91         _active = true;
92         pending_state_node = 0;
93         Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
94
95         set_state (node, Stateful::loading_state_version);
96         setup_bundle ();
97 }
98
99 IO::~IO ()
100 {
101         Glib::Threads::Mutex::Lock lm (io_lock);
102
103         DEBUG_TRACE (DEBUG::Ports, string_compose ("IO %1 unregisters %2 ports\n", name(), _ports.num_ports()));
104
105         BLOCK_PROCESS_CALLBACK ();
106
107         for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
108                 _session.engine().unregister_port (*i);
109         }
110         delete pending_state_node; pending_state_node = 0;
111 }
112
113 void
114 IO::disconnect_check (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
115 {
116         if (_session.deletion_in_progress ()) {
117                 return;
118         }
119         /* this could be called from within our own ::disconnect() method(s)
120            or from somewhere that operates directly on a port. so, we don't
121            know for sure if we can take this lock or not. if we fail,
122            we assume that its safely locked by our own ::disconnect().
123         */
124
125         Glib::Threads::Mutex::Lock tm (io_lock, Glib::Threads::TRY_LOCK);
126
127         if (tm.locked()) {
128                 /* we took the lock, so we cannot be here from inside
129                  * ::disconnect()
130                  */
131                 if (_ports.contains (a) || _ports.contains (b)) {
132                         changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */
133                 }
134         } else {
135                 /* we didn't get the lock, so assume that we're inside
136                  * ::disconnect(), and it will call changed() appropriately.
137                  */
138         }
139 }
140
141 void
142 IO::silence (samplecnt_t nframes)
143 {
144         /* io_lock, not taken: function must be called from Session::process() calltree */
145
146         for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
147                 if (i->port_handle ()) {
148                         i->get_buffer(nframes).silence (nframes);
149                 }
150         }
151 }
152
153 int
154 IO::disconnect (boost::shared_ptr<Port> our_port, string other_port, void* src)
155 {
156         if (other_port.length() == 0 || our_port == 0) {
157                 return 0;
158         }
159
160         {
161                 Glib::Threads::Mutex::Lock lm (io_lock);
162
163                 /* check that our_port is really one of ours */
164
165                 if ( ! _ports.contains(our_port)) {
166                         return -1;
167                 }
168
169                 /* disconnect it from the source */
170
171                 if (our_port->disconnect (other_port)) {
172                         error << string_compose(_("IO: cannot disconnect port %1 from %2"), our_port->name(), other_port) << endmsg;
173                         return -1;
174                 }
175         }
176
177         changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
178
179         _session.set_dirty ();
180
181         return 0;
182 }
183
184 int
185 IO::connect (boost::shared_ptr<Port> our_port, string other_port, void* src)
186 {
187         if (other_port.length() == 0 || our_port == 0) {
188                 return 0;
189         }
190
191         {
192                 Glib::Threads::Mutex::Lock lm (io_lock);
193
194                 /* check that our_port is really one of ours */
195
196                 if ( ! _ports.contains(our_port) ) {
197                         return -1;
198                 }
199
200                 /* connect it to the source */
201
202                 if (our_port->connect (other_port)) {
203                         return -1;
204                 }
205         }
206         changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
207         _session.set_dirty ();
208         return 0;
209 }
210
211 bool
212 IO::can_add_port (DataType type) const
213 {
214         switch (type) {
215                 case DataType::NIL:
216                         return false;
217                 case DataType::AUDIO:
218                         return true;
219                 case DataType::MIDI:
220                         return _ports.count ().n_midi() < 1;
221         }
222         abort(); /*NOTREACHED*/
223         return false;
224 }
225
226 int
227 IO::remove_port (boost::shared_ptr<Port> port, void* src)
228 {
229         ChanCount before = _ports.count ();
230         ChanCount after = before;
231         after.set (port->type(), after.get (port->type()) - 1);
232
233         boost::optional<bool> const r = PortCountChanging (after); /* EMIT SIGNAL */
234         if (r.get_value_or (false)) {
235                 return -1;
236         }
237
238         IOChange change;
239
240         {
241                 BLOCK_PROCESS_CALLBACK ();
242
243                 {
244                         Glib::Threads::Mutex::Lock lm (io_lock);
245
246                         if (_ports.remove(port)) {
247                                 change.type = IOChange::Type (change.type | IOChange::ConfigurationChanged);
248                                 change.before = before;
249                                 change.after = _ports.count ();
250
251                                 if (port->connected()) {
252                                         change.type = IOChange::Type (change.type | IOChange::ConnectionsChanged);
253                                 }
254
255                                 _session.engine().unregister_port (port);
256                         }
257                 }
258
259                 PortCountChanged (n_ports()); /* EMIT SIGNAL */
260
261                 if (change.type != IOChange::NoChange) {
262                         changed (change, src);
263                         _buffers.attach_buffers (_ports);
264                 }
265         }
266
267         if (change.type & IOChange::ConfigurationChanged) {
268                 setup_bundle ();
269         }
270
271         if (change.type == IOChange::NoChange) {
272                 return -1;
273         }
274
275         _session.set_dirty ();
276
277         return 0;
278 }
279
280 /** Add a port.
281  *
282  * @param destination Name of port to connect new port to.
283  * @param src Source for emitted ConfigurationChanged signal.
284  * @param type Data type of port.  Default value (NIL) will use this IO's default type.
285  */
286 int
287 IO::add_port (string destination, void* src, DataType type)
288 {
289         boost::shared_ptr<Port> our_port;
290
291         if (type == DataType::NIL) {
292                 type = _default_type;
293         }
294
295         if (!can_add_port (type)) {
296                 return -1;
297         }
298
299         ChanCount before = _ports.count ();
300         ChanCount after = before;
301         after.set (type, after.get (type) + 1);
302
303         bool const r = PortCountChanging (after); /* EMIT SIGNAL */
304         if (r) {
305                 return -1;
306         }
307
308         IOChange change;
309
310         {
311                 BLOCK_PROCESS_CALLBACK ();
312
313
314                 {
315                         Glib::Threads::Mutex::Lock lm (io_lock);
316
317                         /* Create a new port */
318
319                         string portname = build_legal_port_name (type);
320
321                         if (_direction == Input) {
322                                 if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
323                                         error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
324                                         return -1;
325                                 }
326                         } else {
327                                 if ((our_port = _session.engine().register_output_port (type, portname)) == 0) {
328                                         error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
329                                         return -1;
330                                 }
331                         }
332
333                         change.before = _ports.count ();
334                         _ports.add (our_port);
335                 }
336
337                 PortCountChanged (n_ports()); /* EMIT SIGNAL */
338                 change.type = IOChange::ConfigurationChanged;
339                 change.after = _ports.count ();
340                 changed (change, src); /* EMIT SIGNAL */
341                 _buffers.attach_buffers (_ports);
342         }
343
344         if (!destination.empty()) {
345                 if (our_port->connect (destination)) {
346                         return -1;
347                 }
348         }
349
350         apply_pretty_name ();
351         setup_bundle ();
352         _session.set_dirty ();
353
354         return 0;
355 }
356
357 int
358 IO::disconnect (void* src)
359 {
360         {
361                 Glib::Threads::Mutex::Lock lm (io_lock);
362
363                 for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
364                         i->disconnect_all ();
365                 }
366         }
367
368         changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
369
370         return 0;
371 }
372
373 /** Caller must hold process lock */
374 int
375 IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed)
376 {
377 #ifndef PLATFORM_WINDOWS
378         assert (!AudioEngine::instance()->process_lock().trylock());
379 #endif
380
381         boost::shared_ptr<Port> port;
382         vector<boost::shared_ptr<Port> > deleted_ports;
383
384         changed    = false;
385
386         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
387
388                 const size_t n = count.get(*t);
389
390                 /* remove unused ports */
391                 for (size_t i = n_ports().get(*t); i > n; --i) {
392                         port = _ports.port(*t, i-1);
393
394                         assert(port);
395                         _ports.remove(port);
396
397                         /* hold a reference to the port so that we can ensure
398                          * that this thread, and not a JACK notification thread,
399                          * holds the final reference.
400                          */
401
402                         deleted_ports.push_back (port);
403                         _session.engine().unregister_port (port);
404
405                         changed = true;
406                 }
407
408                 /* this will drop the final reference to the deleted ports,
409                  * which will in turn call their destructors, which will in
410                  * turn call the backend to unregister them.
411                  *
412                  * There will no connect/disconnect or register/unregister
413                  * callbacks from the backend until we get here, because
414                  * they are driven by the Port destructor. The destructor
415                  * will not execute until we drop the final reference,
416                  * which all happens right .... here.
417                  */
418                 deleted_ports.clear ();
419
420                 /* create any necessary new ports */
421                 while (n_ports().get(*t) < n) {
422
423                         string portname = build_legal_port_name (*t);
424
425                         try {
426
427                                 if (_direction == Input) {
428                                         if ((port = _session.engine().register_input_port (*t, portname)) == 0) {
429                                                 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
430                                                 return -1;
431                                         }
432                                 } else {
433                                         if ((port = _session.engine().register_output_port (*t, portname)) == 0) {
434                                                 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
435                                                 return -1;
436                                         }
437                                 }
438                         }
439
440                         catch (AudioEngine::PortRegistrationFailure& err) {
441                                 /* pass it on */
442                                 throw;
443                         }
444
445                         _ports.add (port);
446                         changed = true;
447                 }
448         }
449
450         if (changed) {
451                 PortCountChanged (n_ports()); /* EMIT SIGNAL */
452                 _session.set_dirty ();
453         }
454
455         if (clear) {
456                 /* disconnect all existing ports so that we get a fresh start */
457                 for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
458                         i->disconnect_all ();
459                 }
460         }
461
462         return 0;
463 }
464
465 /** Caller must hold process lock */
466 int
467 IO::ensure_ports (ChanCount count, bool clear, void* src)
468 {
469 #ifndef PLATFORM_WINDOWS
470         assert (!AudioEngine::instance()->process_lock().trylock());
471 #endif
472
473         bool changed = false;
474
475         if (count == n_ports() && !clear) {
476                 return 0;
477         }
478
479         IOChange change;
480
481         change.before = _ports.count ();
482
483         {
484                 Glib::Threads::Mutex::Lock im (io_lock);
485                 if (ensure_ports_locked (count, clear, changed)) {
486                         return -1;
487                 }
488         }
489
490         if (changed) {
491                 change.after = _ports.count ();
492                 change.type = IOChange::ConfigurationChanged;
493                 this->changed (change, src); /* EMIT SIGNAL */
494                 _buffers.attach_buffers (_ports);
495                 setup_bundle ();
496                 _session.set_dirty ();
497         }
498
499         return 0;
500 }
501
502 /** Caller must hold process lock */
503 int
504 IO::ensure_io (ChanCount count, bool clear, void* src)
505 {
506 #ifndef PLATFORM_WINDOWS
507         assert (!AudioEngine::instance()->process_lock().trylock());
508 #endif
509
510         return ensure_ports (count, clear, src);
511 }
512
513 XMLNode&
514 IO::get_state ()
515 {
516         return state ();
517 }
518
519 XMLNode&
520 IO::state ()
521 {
522         XMLNode* node = new XMLNode (state_node_name);
523         int n;
524         Glib::Threads::Mutex::Lock lm (io_lock);
525
526         node->set_property ("name", name());
527         node->set_property ("id", id ());
528         node->set_property ("direction", _direction);
529         node->set_property ("default-type", _default_type);
530
531         if (!_pretty_name_prefix.empty ()) {
532                 node->set_property("pretty-name", _pretty_name_prefix);
533         }
534
535         for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
536
537                 vector<string> connections;
538
539                 XMLNode* pnode = new XMLNode (X_("Port"));
540                 pnode->set_property (X_("type"), i->type());
541                 pnode->set_property (X_("name"), i->name());
542
543                 if (i->get_connections (connections)) {
544                         vector<string>::const_iterator ci;
545                         std::sort (connections.begin(), connections.end());
546
547                         for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) {
548
549                                 /* if its a connection to our own port,
550                                    return only the port name, not the
551                                    whole thing. this allows connections
552                                    to be re-established even when our
553                                    client name is different.
554                                 */
555
556                                 XMLNode* cnode = new XMLNode (X_("Connection"));
557
558                                 cnode->set_property (X_("other"), _session.engine().make_port_name_relative (*ci));
559                                 pnode->add_child_nocopy (*cnode);
560                         }
561                 }
562
563                 node->add_child_nocopy (*pnode);
564         }
565
566         return *node;
567 }
568
569 int
570 IO::set_state (const XMLNode& node, int version)
571 {
572         /* callers for version < 3000 need to call set_state_2X directly, as A3 IOs
573          * are input OR output, not both, so the direction needs to be specified
574          * by the caller.
575          */
576         assert (version >= 3000);
577
578         /* force use of non-localized representation of decimal point,
579            since we use it a lot in XML files and so forth.
580         */
581
582         if (node.name() != state_node_name) {
583                 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
584                 return -1;
585         }
586
587         bool ignore_name = node.property ("ignore-name");
588         std::string name;
589         if (node.get_property ("name", name) && !ignore_name) {
590                 set_name (name);
591         }
592
593         if (node.get_property (X_("default-type"), _default_type)) {
594                 assert(_default_type != DataType::NIL);
595         }
596
597         set_id (node);
598
599         node.get_property ("direction", _direction);
600
601         if (create_ports (node, version)) {
602                 return -1;
603         }
604         if (_sendish && _direction == Output) {
605                 /* ignore <Port name="...">  from XML for sends, but use the names
606                  * ::ensure_ports_locked() creates port using ::build_legal_port_name()
607                  * This is needed to properly restore connections when creating
608                  * external sends from templates because the IO name changes.
609                  */
610                 PortSet::iterator i = _ports.begin();
611                 XMLNodeConstIterator x = node.children().begin();
612                 for (; i != _ports.end(), x != node.children().end(); ++i, ++x) {
613                         if ((*x)->name() == "Port") {
614                                 (*x)->remove_property (X_("name"));
615                                 (*x)->set_property (X_("name"), i->name());
616                         }
617                 }
618         }
619
620         // after create_ports, updates names
621         if (node.get_property ("pretty-name", name)) {
622                 set_pretty_name (name);
623         }
624
625         if (connecting_legal) {
626
627                 if (make_connections (node, version, false)) {
628                         return -1;
629                 }
630
631         } else {
632
633                 delete pending_state_node;
634                 pending_state_node = new XMLNode (node);
635                 pending_state_node_version = version;
636                 pending_state_node_in = false;
637                 ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this));
638         }
639
640         return 0;
641 }
642
643 int
644 IO::set_state_2X (const XMLNode& node, int version, bool in)
645 {
646         XMLProperty const * prop;
647         XMLNodeConstIterator iter;
648         LocaleGuard lg;
649
650         /* force use of non-localized representation of decimal point,
651            since we use it a lot in XML files and so forth.
652         */
653
654         if (node.name() != state_node_name) {
655                 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
656                 return -1;
657         }
658
659         if ((prop = node.property ("name")) != 0) {
660                 set_name (prop->value());
661         }
662
663         if ((prop = node.property (X_("default-type"))) != 0) {
664                 _default_type = DataType(prop->value());
665                 assert(_default_type != DataType::NIL);
666         }
667
668         set_id (node);
669
670         _direction = in ? Input : Output;
671
672         if (create_ports (node, version)) {
673                 return -1;
674         }
675
676         if (connecting_legal) {
677
678                 if (make_connections_2X (node, version, in)) {
679                         return -1;
680                 }
681
682         } else {
683
684                 delete pending_state_node;
685                 pending_state_node = new XMLNode (node);
686                 pending_state_node_version = version;
687                 pending_state_node_in = in;
688                 ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this));
689         }
690
691         return 0;
692 }
693
694 int
695 IO::connecting_became_legal ()
696 {
697         int ret = 0;
698
699         assert (pending_state_node);
700
701         connection_legal_c.disconnect ();
702
703         ret = make_connections (*pending_state_node, pending_state_node_version, pending_state_node_in);
704
705         delete pending_state_node;
706         pending_state_node = 0;
707
708         return ret;
709 }
710
711 boost::shared_ptr<Bundle>
712 IO::find_possible_bundle (const string &desired_name)
713 {
714         static const string digits = "0123456789";
715         const string &default_name = (_direction == Input ? _("in") : _("out"));
716         const string &bundle_type_name = (_direction == Input ? _("input") : _("output"));
717
718         boost::shared_ptr<Bundle> c = _session.bundle_by_name (desired_name);
719
720         if (!c) {
721                 int bundle_number, mask;
722                 string possible_name;
723                 bool stereo = false;
724                 string::size_type last_non_digit_pos;
725                 std::string bundle_number_str;
726
727                 error << string_compose(_("Unknown bundle \"%1\" listed for %2 of %3"), desired_name, bundle_type_name, _name)
728                       << endmsg;
729
730                 // find numeric suffix of desired name
731                 bundle_number = 0;
732
733                 last_non_digit_pos = desired_name.find_last_not_of(digits);
734
735                 if (last_non_digit_pos != string::npos) {
736                         bundle_number_str = desired_name.substr(last_non_digit_pos);
737                         bundle_number = string_to<int32_t>(bundle_number_str);
738                 }
739
740                 // see if it's a stereo connection e.g. "in 3+4"
741
742                 if (last_non_digit_pos > 1 && desired_name[last_non_digit_pos] == '+') {
743                         string::size_type left_last_non_digit_pos;
744
745                         left_last_non_digit_pos = desired_name.find_last_not_of(digits, last_non_digit_pos-1);
746
747                         if (left_last_non_digit_pos != string::npos) {
748                                 int left_bundle_number = 0;
749                                 bundle_number_str = desired_name.substr(left_last_non_digit_pos, last_non_digit_pos-1);
750                                 left_bundle_number = string_to<int32_t>(bundle_number_str);
751
752                                 if (left_bundle_number > 0 && left_bundle_number + 1 == bundle_number) {
753                                         bundle_number--;
754                                         stereo = true;
755                                 }
756                         }
757                 }
758
759                 // make 0-based
760                 if (bundle_number)
761                         bundle_number--;
762
763                 // find highest set bit
764                 mask = 1;
765                 while ((mask <= bundle_number) && (mask <<= 1)) {}
766
767                 // "wrap" bundle number into largest possible power of 2
768                 // that works...
769
770                 while (mask) {
771
772                         if (bundle_number & mask) {
773                                 bundle_number &= ~mask;
774
775                                 std::string possible_name = default_name + " " + to_string(bundle_number + 1);
776
777                                 if (stereo) {
778                                         possible_name += "+" + to_string(bundle_number + 2);
779                                 }
780
781                                 if ((c = _session.bundle_by_name (possible_name)) != 0) {
782                                         break;
783                                 }
784                         }
785                         mask >>= 1;
786                 }
787                 if (c) {
788                         info << string_compose (_("Bundle %1 was not available - \"%2\" used instead"), desired_name, possible_name)
789                              << endmsg;
790                 } else {
791                         error << string_compose(_("No %1 bundles available as a replacement"), bundle_type_name)
792                               << endmsg;
793                 }
794
795         }
796
797         return c;
798
799 }
800
801 int
802 IO::get_port_counts_2X (XMLNode const & node, int /*version*/, ChanCount& n, boost::shared_ptr<Bundle>& /*c*/)
803 {
804         XMLProperty const * prop;
805         XMLNodeList children = node.children ();
806
807         uint32_t n_audio = 0;
808
809         for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
810
811                 if ((prop = node.property ("inputs")) != 0 && _direction == Input) {
812                         n_audio = count (prop->value().begin(), prop->value().end(), '{');
813                 } else if ((prop = node.property ("input-connection")) != 0 && _direction == Input) {
814                         n_audio = 1;
815                 } else if ((prop = node.property ("outputs")) != 0 && _direction == Output) {
816                         n_audio = count (prop->value().begin(), prop->value().end(), '{');
817                 } else if ((prop = node.property ("output-connection")) != 0 && _direction == Output) {
818                         n_audio = 2;
819                 }
820         }
821
822         ChanCount cnt;
823         cnt.set_audio (n_audio);
824         n = ChanCount::max (n, cnt);
825
826         return 0;
827 }
828
829 int
830 IO::get_port_counts (const XMLNode& node, int version, ChanCount& n, boost::shared_ptr<Bundle>& c)
831 {
832         if (version < 3000) {
833                 return get_port_counts_2X (node, version, n, c);
834         }
835
836         XMLProperty const * prop;
837         XMLNodeConstIterator iter;
838         uint32_t n_audio = 0;
839         uint32_t n_midi = 0;
840         ChanCount cnt;
841
842         n = n_ports();
843
844         if ((prop = node.property ("connection")) != 0) {
845
846                 if ((c = find_possible_bundle (prop->value())) != 0) {
847                         n = ChanCount::max (n, c->nchannels());
848                 }
849                 return 0;
850         }
851
852         for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
853
854                 if ((*iter)->name() == X_("Bundle")) {
855                         prop = (*iter)->property ("name");
856                         if ((c = find_possible_bundle (prop->value())) != 0) {
857                                 n = ChanCount::max (n, c->nchannels());
858                                 return 0;
859                         } else {
860                                 return -1;
861                         }
862                 }
863
864                 if ((*iter)->name() == X_("Port")) {
865                         prop = (*iter)->property (X_("type"));
866
867                         if (!prop) {
868                                 continue;
869                         }
870
871                         if (prop->value() == X_("audio")) {
872                                 cnt.set_audio (++n_audio);
873                         } else if (prop->value() == X_("midi")) {
874                                 cnt.set_midi (++n_midi);
875                         }
876                 }
877         }
878
879         n = ChanCount::max (n, cnt);
880         return 0;
881 }
882
883 int
884 IO::create_ports (const XMLNode& node, int version)
885 {
886         ChanCount n;
887         boost::shared_ptr<Bundle> c;
888
889         get_port_counts (node, version, n, c);
890
891         {
892                 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
893
894                 if (ensure_ports (n, true, this)) {
895                         error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
896                         return -1;
897                 }
898         }
899
900         /* XXX use c */
901
902         return 0;
903 }
904
905 int
906 IO::make_connections (const XMLNode& node, int version, bool in)
907 {
908         if (version < 3000) {
909                 return make_connections_2X (node, version, in);
910         }
911
912         XMLProperty const * prop;
913
914         for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) {
915
916                 if ((*i)->name() == "Bundle") {
917                         XMLProperty const * prop = (*i)->property ("name");
918                         if (prop) {
919                                 boost::shared_ptr<Bundle> b = find_possible_bundle (prop->value());
920                                 if (b) {
921                                         connect_ports_to_bundle (b, true, this);
922                                 }
923                         }
924
925                         return 0;
926                 }
927
928                 if ((*i)->name() == "Port") {
929
930                         prop = (*i)->property (X_("name"));
931
932                         if (!prop) {
933                                 continue;
934                         }
935
936                         boost::shared_ptr<Port> p = port_by_name (prop->value());
937
938                         if (p) {
939                                 for (XMLNodeConstIterator c = (*i)->children().begin(); c != (*i)->children().end(); ++c) {
940
941                                         XMLNode* cnode = (*c);
942
943                                         if (cnode->name() != X_("Connection")) {
944                                                 continue;
945                                         }
946
947                                         if ((prop = cnode->property (X_("other"))) == 0) {
948                                                 continue;
949                                         }
950
951                                         if (prop) {
952                                                 connect (p, prop->value(), this);
953                                         }
954                                 }
955                         }
956                 }
957         }
958
959         return 0;
960 }
961
962 void
963 IO::prepare_for_reset (XMLNode& node, const std::string& name)
964 {
965         /* reset name */
966         node.set_property ("name", name);
967
968         /* now find connections and reset the name of the port
969            in one so that when we re-use it it will match
970            the name of the thing we're applying it to.
971         */
972
973         XMLProperty * prop;
974         XMLNodeList children = node.children();
975
976         for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
977
978                 if ((*i)->name() == "Port") {
979
980                         prop = (*i)->property (X_("name"));
981
982                         if (prop) {
983                                 string new_name;
984                                 string old = prop->value();
985                                 string::size_type slash = old.find ('/');
986
987                                 if (slash != string::npos) {
988                                         /* port name is of form: <IO-name>/<port-name> */
989
990                                         new_name = name;
991                                         new_name += old.substr (old.find ('/'));
992
993                                         prop->set_value (new_name);
994                                 }
995                         }
996                 }
997         }
998 }
999
1000
1001 int
1002 IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
1003 {
1004         XMLProperty const * prop;
1005
1006         /* XXX: bundles ("connections" as was) */
1007
1008         if ((prop = node.property ("inputs")) != 0 && in) {
1009
1010                 string::size_type ostart = 0;
1011                 string::size_type start = 0;
1012                 string::size_type end = 0;
1013                 int i = 0;
1014                 int n;
1015                 vector<string> ports;
1016
1017                 string const str = prop->value ();
1018
1019                 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1020                         start += 1;
1021
1022                         if ((end = str.find_first_of ('}', start)) == string::npos) {
1023                                 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1024                                 return -1;
1025                         }
1026
1027                         if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1028                                 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1029
1030                                 return -1;
1031
1032                         } else if (n > 0) {
1033
1034
1035                                 for (int x = 0; x < n; ++x) {
1036                                         /* XXX: this is a bit of a hack; need to check if it's always valid */
1037                                         string::size_type const p = ports[x].find ("/out");
1038                                         if (p != string::npos) {
1039                                                 ports[x].replace (p, 4, "/audio_out");
1040                                         }
1041                                         if (NULL != nth(i).get())
1042                                                 nth(i)->connect (ports[x]);
1043                                 }
1044                         }
1045
1046                         ostart = end+1;
1047                         i++;
1048                 }
1049
1050         }
1051
1052         if ((prop = node.property ("outputs")) != 0 && !in) {
1053
1054                 string::size_type ostart = 0;
1055                 string::size_type start = 0;
1056                 string::size_type end = 0;
1057                 int i = 0;
1058                 int n;
1059                 vector<string> ports;
1060
1061                 string const str = prop->value ();
1062
1063                 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1064                         start += 1;
1065
1066                         if ((end = str.find_first_of ('}', start)) == string::npos) {
1067                                 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1068                                 return -1;
1069                         }
1070
1071                         if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1072                                 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1073
1074                                 return -1;
1075
1076                         } else if (n > 0) {
1077
1078                                 for (int x = 0; x < n; ++x) {
1079                                         /* XXX: this is a bit of a hack; need to check if it's always valid */
1080                                         string::size_type const p = ports[x].find ("/in");
1081                                         if (p != string::npos) {
1082                                                 ports[x].replace (p, 3, "/audio_in");
1083                                         }
1084                                         if (NULL != nth(i).get())
1085                                                 nth(i)->connect (ports[x]);
1086                                 }
1087                         }
1088
1089                         ostart = end+1;
1090                         i++;
1091                 }
1092         }
1093
1094         return 0;
1095 }
1096
1097 int
1098 IO::set_ports (const string& str)
1099 {
1100         vector<string> ports;
1101         int n;
1102         uint32_t nports;
1103
1104         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1105                 return 0;
1106         }
1107
1108         {
1109                 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
1110
1111                 // FIXME: audio-only
1112                 if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
1113                         return -1;
1114                 }
1115         }
1116
1117         string::size_type start  = 0;
1118         string::size_type end    = 0;
1119         string::size_type ostart = 0;
1120         for (int i = 0; (start = str.find_first_of ('{', ostart)) != string::npos; ++i) {
1121                 start += 1;
1122
1123                 if ((end = str.find_first_of ('}', start)) == string::npos) {
1124                         error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1125                         return -1;
1126                 }
1127
1128                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1129                         error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1130
1131                         return -1;
1132
1133                 } else if (n > 0) {
1134
1135                         for (int x = 0; x < n; ++x) {
1136                                 connect (nth (i), ports[x], this);
1137                         }
1138                 }
1139
1140                 ostart = end+1;
1141         }
1142
1143         return 0;
1144 }
1145
1146 int
1147 IO::parse_io_string (const string& str, vector<string>& ports)
1148 {
1149         string::size_type pos, opos;
1150
1151         if (str.length() == 0) {
1152                 return 0;
1153         }
1154
1155         opos = 0;
1156
1157         ports.clear ();
1158
1159         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1160                 ports.push_back (str.substr (opos, pos - opos));
1161                 opos = pos + 1;
1162         }
1163
1164         if (opos < str.length()) {
1165                 ports.push_back (str.substr(opos));
1166         }
1167
1168         return ports.size();
1169 }
1170
1171 int
1172 IO::parse_gain_string (const string& str, vector<string>& ports)
1173 {
1174         string::size_type pos, opos;
1175
1176         opos = 0;
1177         ports.clear ();
1178
1179         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1180                 ports.push_back (str.substr (opos, pos - opos));
1181                 opos = pos + 1;
1182         }
1183
1184         if (opos < str.length()) {
1185                 ports.push_back (str.substr(opos));
1186         }
1187
1188         return ports.size();
1189 }
1190
1191 bool
1192 IO::set_name (const string& requested_name)
1193 {
1194         string name = requested_name;
1195
1196         if (_name == name) {
1197                 return true;
1198         }
1199
1200         /* replace all colons in the name. i wish we didn't have to do this */
1201
1202         replace_all (name, ":", "-");
1203
1204         for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
1205                 string current_name = i->name();
1206                 current_name.replace (current_name.find (_name), _name.val().length(), name);
1207                 i->set_name (current_name);
1208         }
1209
1210         bool const r = SessionObject::set_name (name);
1211
1212         setup_bundle ();
1213
1214         return r;
1215 }
1216
1217 void
1218 IO::set_pretty_name (const std::string& str)
1219 {
1220         if (_pretty_name_prefix == str) {
1221                 return;
1222         }
1223         _pretty_name_prefix = str;
1224         apply_pretty_name ();
1225 }
1226
1227 void
1228 IO::apply_pretty_name ()
1229 {
1230         uint32_t pn = 1;
1231         if (_pretty_name_prefix.empty ()) {
1232                 return;
1233         }
1234         for (PortSet::iterator i = _ports.begin (); i != _ports.end(); ++i, ++pn) {
1235                 (*i)->set_pretty_name (string_compose (("%1/%2 %3"),
1236                                         _pretty_name_prefix,
1237                                         _direction == Output ? _("Out") : _("In"),
1238                                         pn));
1239         }
1240 }
1241
1242 void
1243 IO::set_private_port_latencies (samplecnt_t value, bool playback)
1244 {
1245         LatencyRange lat;
1246         lat.min = lat.max = value;
1247         for (PortSet::iterator i = _ports.begin (); i != _ports.end(); ++i) {
1248                  i->set_private_latency_range (lat, playback);
1249         }
1250 }
1251
1252 void
1253 IO::set_public_port_latencies (samplecnt_t value, bool playback) const
1254 {
1255         LatencyRange lat;
1256         lat.min = lat.max = value;
1257         for (PortSet::const_iterator i = _ports.begin (); i != _ports.end(); ++i) {
1258                  i->set_public_latency_range (lat, playback);
1259         }
1260 }
1261
1262 samplecnt_t
1263 IO::latency () const
1264 {
1265         samplecnt_t max_latency = 0;
1266
1267         /* io lock not taken - must be protected by other means */
1268
1269         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1270                 samplecnt_t latency;
1271                 if ((latency = i->private_latency_range (_direction == Output).max) > max_latency) {
1272                         DEBUG_TRACE (DEBUG::Latency, string_compose ("port %1 has %2 latency of %3 - use\n",
1273                                                                      name(),
1274                                                                      ((_direction == Output) ? "PLAYBACK" : "CAPTURE"),
1275                                                                      latency));
1276                         max_latency = latency;
1277                 }
1278         }
1279
1280         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: max %4 latency from %2 ports = %3\n",
1281                                                      name(), _ports.num_ports(), max_latency,
1282                                                      ((_direction == Output) ? "PLAYBACK" : "CAPTURE")));
1283         return max_latency;
1284 }
1285
1286 samplecnt_t
1287 IO::public_latency () const
1288 {
1289         samplecnt_t max_latency = 0;
1290
1291         /* io lock not taken - must be protected by other means */
1292
1293         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1294                 samplecnt_t latency;
1295                 if ((latency = i->public_latency_range (_direction == Output).max) > max_latency) {
1296                         DEBUG_TRACE (DEBUG::Latency, string_compose ("port %1 has %2 latency of %3 - use\n",
1297                                                                      name(),
1298                                                                      ((_direction == Output) ? "PLAYBACK" : "CAPTURE"),
1299                                                                      latency));
1300                         max_latency = latency;
1301                 }
1302         }
1303
1304         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: max %4 public latency from %2 ports = %3\n",
1305                                                      name(), _ports.num_ports(), max_latency,
1306                                                      ((_direction == Output) ? "PLAYBACK" : "CAPTURE")));
1307         return max_latency;
1308 }
1309
1310 samplecnt_t
1311 IO::connected_latency (bool for_playback) const
1312 {
1313         /* io lock not taken - must be protected by other means */
1314         samplecnt_t max_latency = 0;
1315         bool connected = false;
1316
1317         /* if output is not connected to anything, use private latency */
1318         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1319                 if (i->connected()) {
1320                         connected = true;
1321                         max_latency = 0;
1322                         break;
1323                 }
1324                 samplecnt_t latency;
1325                 if ((latency = i->private_latency_range (for_playback).max) > max_latency) {
1326                         max_latency = latency;
1327                 }
1328         }
1329         if (connected) {
1330                 for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1331                         LatencyRange lr;
1332                         i->get_connected_latency_range (lr, for_playback);
1333                         if (lr.max > max_latency) {
1334                                 max_latency = lr.max;
1335                         }
1336                 }
1337         }
1338         return max_latency;
1339 }
1340
1341 int
1342 IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, bool exclusive, void* src) {
1343         return connect_ports_to_bundle(c, exclusive, false, src);
1344 }
1345
1346 int
1347 IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, bool exclusive,
1348                              bool allow_partial, void* src)
1349 {
1350         BLOCK_PROCESS_CALLBACK ();
1351
1352         {
1353                 Glib::Threads::Mutex::Lock lm2 (io_lock);
1354
1355                 if (exclusive) {
1356                         for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
1357                                 i->disconnect_all ();
1358                         }
1359                 }
1360
1361                 c->connect (_bundle, _session.engine(), allow_partial);
1362
1363         }
1364
1365         changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
1366         return 0;
1367 }
1368
1369 int
1370 IO::disconnect_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
1371 {
1372         BLOCK_PROCESS_CALLBACK ();
1373
1374         {
1375                 Glib::Threads::Mutex::Lock lm2 (io_lock);
1376
1377                 c->disconnect (_bundle, _session.engine());
1378
1379                 /* If this is a UserBundle, make a note of what we've done */
1380
1381         }
1382
1383         changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
1384         return 0;
1385 }
1386
1387
1388 int
1389 IO::disable_connecting ()
1390 {
1391         connecting_legal = false;
1392         return 0;
1393 }
1394
1395 int
1396 IO::enable_connecting ()
1397 {
1398         Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
1399         connecting_legal = true;
1400         boost::optional<int> r = ConnectingLegal ();
1401         return r.get_value_or (0);
1402 }
1403
1404 void
1405 IO::bundle_changed (Bundle::Change /*c*/)
1406 {
1407 }
1408
1409
1410 string
1411 IO::build_legal_port_name (DataType type)
1412 {
1413         const int name_size = AudioEngine::instance()->port_name_size();
1414         int limit;
1415         string suffix;
1416
1417         if (type == DataType::AUDIO) {
1418                 suffix = X_("audio");
1419         } else if (type == DataType::MIDI) {
1420                 suffix = X_("midi");
1421         } else {
1422                 throw unknown_type();
1423         }
1424
1425         /* note that if "in" or "out" are translated it will break a session
1426            across locale switches because a port's connection list will
1427            show (old) translated names, but the current port name will
1428            use the (new) translated name.
1429         */
1430
1431         if (_sendish) {
1432                 if (_direction == Input) {
1433                         suffix += X_("_return");
1434                 } else {
1435                         suffix += X_("_send");
1436                 }
1437         } else {
1438                 if (_direction == Input) {
1439                         suffix += X_("_in");
1440                 } else {
1441                         suffix += X_("_out");
1442                 }
1443         }
1444
1445         // allow up to 4 digits for the output port number, plus the slash, suffix and extra space
1446
1447         limit = name_size - AudioEngine::instance()->my_name().length() - (suffix.length() + 5);
1448
1449         std::vector<char> buf1(name_size+1);
1450         std::vector<char> buf2(name_size+1);
1451
1452         /* colons are illegal in port names, so fix that */
1453
1454         string nom = _name.val();
1455         replace_all (nom, ":", ";");
1456
1457         snprintf (&buf1[0], name_size+1, ("%.*s/%s"), limit, nom.c_str(), suffix.c_str());
1458
1459         int port_number = find_port_hole (&buf1[0]);
1460         snprintf (&buf2[0], name_size+1, "%s %d", &buf1[0], port_number);
1461
1462         return string (&buf2[0]);
1463 }
1464
1465 int32_t
1466 IO::find_port_hole (const char* base)
1467 {
1468         /* CALLER MUST HOLD IO LOCK */
1469
1470         uint32_t n;
1471
1472         if (_ports.empty()) {
1473                 return 1;
1474         }
1475
1476         /* we only allow up to 4 characters for the port number
1477          */
1478
1479         for (n = 1; n < 9999; ++n) {
1480                 std::vector<char> buf (AudioEngine::instance()->port_name_size());
1481                 PortSet::iterator i = _ports.begin();
1482
1483                 snprintf (&buf[0], buf.size()+1, _("%s %u"), base, n);
1484
1485                 for ( ; i != _ports.end(); ++i) {
1486                         if (string(i->name()) == string(&buf[0])) {
1487                                 break;
1488                         }
1489                 }
1490
1491                 if (i == _ports.end()) {
1492                         break;
1493                 }
1494         }
1495         return n;
1496 }
1497
1498
1499 boost::shared_ptr<AudioPort>
1500 IO::audio(uint32_t n) const
1501 {
1502         return _ports.nth_audio_port (n);
1503
1504 }
1505
1506 boost::shared_ptr<MidiPort>
1507 IO::midi(uint32_t n) const
1508 {
1509         return _ports.nth_midi_port (n);
1510 }
1511
1512 /**
1513  *  Setup a bundle that describe our inputs or outputs. Also creates the bundle if necessary.
1514  */
1515 void
1516 IO::setup_bundle ()
1517 {
1518         char buf[32];
1519
1520         if (!_bundle) {
1521                 _bundle.reset (new Bundle (_direction == Input));
1522         }
1523
1524         _bundle->suspend_signals ();
1525
1526         _bundle->remove_channels ();
1527
1528         if (_direction == Input) {
1529                 snprintf(buf, sizeof (buf), _("%s in"), _name.val().c_str());
1530         } else {
1531                 snprintf(buf, sizeof (buf), _("%s out"), _name.val().c_str());
1532         }
1533         _bundle->set_name (buf);
1534
1535         int c = 0;
1536         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1537
1538                 uint32_t const N = _ports.count().get (*i);
1539                 for (uint32_t j = 0; j < N; ++j) {
1540                         _bundle->add_channel (bundle_channel_name (j, N, *i), *i);
1541                         _bundle->set_port (c, _session.engine().make_port_name_non_relative (_ports.port(*i, j)->name()));
1542                         ++c;
1543                 }
1544
1545         }
1546
1547         _bundle->resume_signals ();
1548 }
1549
1550 /** @return Bundles connected to our ports */
1551 BundleList
1552 IO::bundles_connected ()
1553 {
1554         BundleList bundles;
1555
1556         /* Session bundles */
1557         boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
1558         for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1559                 if ((*i)->connected_to (_bundle, _session.engine())) {
1560                         bundles.push_back (*i);
1561                 }
1562         }
1563
1564         /* Route bundles */
1565
1566         boost::shared_ptr<ARDOUR::RouteList> r = _session.get_routes ();
1567
1568         if (_direction == Input) {
1569                 for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1570                         if ((*i)->output()->bundle()->connected_to (_bundle, _session.engine())) {
1571                                 bundles.push_back ((*i)->output()->bundle());
1572                         }
1573                 }
1574         } else {
1575                 for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
1576                         if ((*i)->input()->bundle()->connected_to (_bundle, _session.engine())) {
1577                                 bundles.push_back ((*i)->input()->bundle());
1578                         }
1579                 }
1580         }
1581
1582         return bundles;
1583 }
1584
1585
1586 IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr<UserBundle> b)
1587 {
1588         bundle = b;
1589         b->Changed.connect_same_thread (changed, boost::bind (&IO::bundle_changed, io, _1));
1590 }
1591
1592 std::string
1593 IO::bundle_channel_name (uint32_t c, uint32_t n, DataType t) const
1594 {
1595         char buf[32];
1596
1597         if (t == DataType::AUDIO) {
1598
1599                 switch (n) {
1600                 case 1:
1601                         return _("mono");
1602                 case 2:
1603                         return c == 0 ? _("L") : _("R");
1604                 default:
1605                         snprintf (buf, sizeof(buf), "%d", (c + 1));
1606                         return buf;
1607                 }
1608
1609         } else {
1610
1611                 snprintf (buf, sizeof(buf), "%d", (c + 1));
1612                 return buf;
1613
1614         }
1615
1616         return "";
1617 }
1618
1619 string
1620 IO::name_from_state (const XMLNode& node)
1621 {
1622         XMLProperty const * prop;
1623
1624         if ((prop = node.property ("name")) != 0) {
1625                 return prop->value();
1626         }
1627
1628         return string();
1629 }
1630
1631 void
1632 IO::set_name_in_state (XMLNode& node, const string& new_name)
1633 {
1634         node.set_property (X_("name"), new_name);
1635         XMLNodeList children = node.children ();
1636         for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
1637                 if ((*i)->name() == X_("Port")) {
1638                         string const old_name = (*i)->property(X_("name"))->value();
1639                         string const old_name_second_part = old_name.substr (old_name.find_first_of ("/") + 1);
1640                         (*i)->set_property (X_("name"), string_compose ("%1/%2", new_name, old_name_second_part));
1641                 }
1642         }
1643 }
1644
1645 bool
1646 IO::connected () const
1647 {
1648         /* do we have any connections at all? */
1649
1650         for (PortSet::const_iterator p = _ports.begin(); p != _ports.end(); ++p) {
1651                 if (p->connected()) {
1652                         return true;
1653                 }
1654         }
1655
1656         return false;
1657 }
1658
1659 bool
1660 IO::connected_to (boost::shared_ptr<const IO> other) const
1661 {
1662         if (!other) {
1663                 return connected ();
1664         }
1665
1666         assert (_direction != other->direction());
1667
1668         uint32_t i, j;
1669         uint32_t no = n_ports().n_total();
1670         uint32_t ni = other->n_ports ().n_total();
1671
1672         for (i = 0; i < no; ++i) {
1673                 for (j = 0; j < ni; ++j) {
1674                         if ((NULL != nth(i).get()) && (NULL != other->nth(j).get())) {
1675                                 if (nth(i)->connected_to (other->nth(j)->name())) {
1676                                         return true;
1677                                 }
1678                         }
1679                 }
1680         }
1681
1682         return false;
1683 }
1684
1685 bool
1686 IO::connected_to (const string& str) const
1687 {
1688         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1689                 if (i->connected_to (str)) {
1690                         return true;
1691                 }
1692         }
1693
1694         return false;
1695 }
1696
1697 void
1698 IO::collect_input (BufferSet& bufs, pframes_t nframes, ChanCount offset)
1699 {
1700         assert(bufs.available() >= _ports.count());
1701
1702         if (_ports.count() == ChanCount::ZERO) {
1703                 return;
1704         }
1705
1706         bufs.set_count (_ports.count());
1707
1708         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1709                 PortSet::iterator   i = _ports.begin(*t);
1710                 BufferSet::iterator b = bufs.begin(*t);
1711
1712                 for (uint32_t off = 0; off < offset.get(*t); ++off, ++b) {
1713                         if (b == bufs.end(*t)) {
1714                                 continue;
1715                         }
1716                 }
1717
1718                 for ( ; i != _ports.end(*t); ++i, ++b) {
1719                         const Buffer& bb (i->get_buffer (nframes));
1720                         b->read_from (bb, nframes);
1721                 }
1722         }
1723 }
1724
1725 void
1726 IO::copy_to_outputs (BufferSet& bufs, DataType type, pframes_t nframes, samplecnt_t offset)
1727 {
1728         PortSet::iterator o = _ports.begin(type);
1729         BufferSet::iterator i = bufs.begin(type);
1730         BufferSet::iterator prev = i;
1731
1732         assert(i != bufs.end(type)); // or second loop will crash
1733
1734         // Copy any buffers 1:1 to outputs
1735
1736         while (i != bufs.end(type) && o != _ports.end (type)) {
1737                 Buffer& port_buffer (o->get_buffer (nframes));
1738                 port_buffer.read_from (*i, nframes, offset);
1739                 prev = i;
1740                 ++i;
1741                 ++o;
1742         }
1743
1744         // Copy last buffer to any extra outputs
1745
1746         while (o != _ports.end(type)) {
1747                 Buffer& port_buffer (o->get_buffer (nframes));
1748                 port_buffer.read_from (*prev, nframes, offset);
1749                 ++o;
1750         }
1751 }
1752
1753 boost::shared_ptr<Port>
1754 IO::port_by_name (const std::string& str) const
1755 {
1756         /* to be called only from ::set_state() - no locking */
1757
1758         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1759
1760                 if (i->name() == str) {
1761                         return boost::const_pointer_cast<Port> (*i);
1762                 }
1763         }
1764
1765         return boost::shared_ptr<Port> ();
1766 }
1767
1768 bool
1769 IO::physically_connected () const
1770 {
1771         for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
1772                 if (i->physically_connected()) {
1773                         return true;
1774                 }
1775         }
1776
1777         return false;
1778 }
1779
1780 bool
1781 IO::has_port (boost::shared_ptr<Port> p) const
1782 {
1783         Glib::Threads::Mutex::Lock lm (io_lock);
1784         return _ports.contains (p);
1785 }