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