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