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