2 Copyright (C) 2002-2009 Paul Davis
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.
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.
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.
21 #include <boost/shared_ptr.hpp>
22 #include <boost/algorithm/string.hpp>
24 #include "midi++/manager.h"
25 #include "midi++/mmc.h"
27 #include "ardour/audio_track.h"
28 #include "ardour/audioengine.h"
29 #include "ardour/bundle.h"
30 #include "ardour/user_bundle.h"
31 #include "ardour/io_processor.h"
32 #include "ardour/midi_track.h"
33 #include "ardour/port.h"
34 #include "ardour/session.h"
35 #include "ardour/auditioner.h"
36 #include "ardour/control_protocol_manager.h"
37 #include "control_protocol/control_protocol.h"
39 #include "gui_thread.h"
40 #include "port_group.h"
41 #include "port_matrix.h"
42 #include "time_axis_view.h"
43 #include "public_editor.h"
49 using namespace ARDOUR
;
51 /** PortGroup constructor.
54 PortGroup::PortGroup (std::string
const & n
)
60 PortGroup::~PortGroup()
62 for (BundleList::iterator i
= _bundles
.begin(); i
!= _bundles
.end(); ++i
) {
68 /** Add a bundle to a group.
70 * @param allow_dups true to allow the group to contain more than one bundle with the same port, otherwise false.
73 PortGroup::add_bundle (boost::shared_ptr
<Bundle
> b
, bool allow_dups
)
75 add_bundle_internal (b
, boost::shared_ptr
<IO
> (), false, Gdk::Color (), allow_dups
);
78 /** Add a bundle to a group.
80 * @param io IO whose ports are in the bundle.
83 PortGroup::add_bundle (boost::shared_ptr
<Bundle
> b
, boost::shared_ptr
<IO
> io
)
85 add_bundle_internal (b
, io
, false, Gdk::Color (), false);
88 /** Add a bundle to a group.
90 * @param c Colour to represent the bundle with.
93 PortGroup::add_bundle (boost::shared_ptr
<Bundle
> b
, boost::shared_ptr
<IO
> io
, Gdk::Color c
)
95 add_bundle_internal (b
, io
, true, c
, false);
98 PortGroup::BundleRecord::BundleRecord (boost::shared_ptr
<ARDOUR::Bundle
> b
, boost::shared_ptr
<ARDOUR::IO
> iop
, Gdk::Color c
, bool has_c
)
107 PortGroup::add_bundle_internal (boost::shared_ptr
<Bundle
> b
, boost::shared_ptr
<IO
> io
, bool has_colour
, Gdk::Color colour
, bool allow_dups
)
113 /* don't add this bundle if we already have one with the same ports */
115 BundleList::iterator i
= _bundles
.begin ();
116 while (i
!= _bundles
.end() && b
->has_same_ports ((*i
)->bundle
) == false) {
120 if (i
!= _bundles
.end ()) {
125 BundleRecord
* br
= new BundleRecord (b
, io
, colour
, has_colour
);
126 b
->Changed
.connect (br
->changed_connection
, invalidator (*this), ui_bind (&PortGroup::bundle_changed
, this, _1
), gui_context());
127 _bundles
.push_back (br
);
133 PortGroup::remove_bundle (boost::shared_ptr
<Bundle
> b
)
137 BundleList::iterator i
= _bundles
.begin ();
138 while (i
!= _bundles
.end() && (*i
)->bundle
!= b
) {
142 if (i
== _bundles
.end()) {
153 PortGroup::bundle_changed (Bundle::Change c
)
162 for (BundleList::iterator i
= _bundles
.begin(); i
!= _bundles
.end(); ++i
) {
171 PortGroup::has_port (std::string
const& p
) const
173 for (BundleList::const_iterator i
= _bundles
.begin(); i
!= _bundles
.end(); ++i
) {
174 if ((*i
)->bundle
->offers_port_alone (p
)) {
182 boost::shared_ptr
<Bundle
>
183 PortGroup::only_bundle ()
185 assert (_bundles
.size() == 1);
186 return _bundles
.front()->bundle
;
191 PortGroup::total_channels () const
194 for (BundleList::const_iterator i
= _bundles
.begin(); i
!= _bundles
.end(); ++i
) {
195 n
+= (*i
)->bundle
->nchannels ();
201 boost::shared_ptr
<IO
>
202 PortGroup::io_from_bundle (boost::shared_ptr
<ARDOUR::Bundle
> b
) const
204 BundleList::const_iterator i
= _bundles
.begin ();
205 while (i
!= _bundles
.end() && (*i
)->bundle
!= b
) {
209 if (i
== _bundles
.end()) {
210 return boost::shared_ptr
<IO
> ();
213 boost::shared_ptr
<IO
> io ((*i
)->io
.lock ());
217 /** Remove bundles whose channels are already represented by other, larger bundles */
219 PortGroup::remove_duplicates ()
221 BundleList::iterator i
= _bundles
.begin();
222 while (i
!= _bundles
.end()) {
224 BundleList::iterator tmp
= i
;
229 for (BundleList::iterator j
= _bundles
.begin(); j
!= _bundles
.end(); ++j
) {
231 if ((*j
)->bundle
->nchannels() > (*i
)->bundle
->nchannels()) {
232 /* this bundle is larger */
235 while (k
< (*i
)->bundle
->nchannels().n_total()) {
236 /* see if this channel on *i has an equivalent on *j */
238 while (l
< (*j
)->bundle
->nchannels().n_total() && (*i
)->bundle
->channel_ports (k
) != (*j
)->bundle
->channel_ports (l
)) {
242 if (l
== (*j
)->bundle
->nchannels().n_total()) {
250 if (k
== (*i
)->bundle
->nchannels().n_total()) {
251 /* all channels on *i are represented by the larger bundle *j, so remove *i */
267 /** PortGroupList constructor.
269 PortGroupList::PortGroupList ()
270 : _signals_suspended (false), _pending_change (false), _pending_bundle_change ((Bundle::Change
) 0)
275 PortGroupList::~PortGroupList()
277 /* XXX need to clean up bundles, but ownership shared with PortGroups */
281 PortGroupList::maybe_add_processor_to_list (
282 boost::weak_ptr
<Processor
> wp
, list
<boost::shared_ptr
<IO
> >* route_ios
, bool inputs
, set
<boost::shared_ptr
<IO
> >& used_io
285 boost::shared_ptr
<Processor
> p (wp
.lock());
291 boost::shared_ptr
<IOProcessor
> iop
= boost::dynamic_pointer_cast
<IOProcessor
> (p
);
295 boost::shared_ptr
<IO
> io
= inputs
? iop
->input() : iop
->output();
297 if (io
&& used_io
.find (io
) == used_io
.end()) {
298 route_ios
->push_back (io
);
305 RouteIOs (boost::shared_ptr
<Route
> r
, boost::shared_ptr
<IO
> i
) {
310 boost::shared_ptr
<Route
> route
;
311 /* it's ok to use a shared_ptr here as RouteIOs structs are only used during ::gather () */
312 std::list
<boost::shared_ptr
<IO
> > ios
;
315 class RouteIOsComparator
{
317 bool operator() (RouteIOs
const & a
, RouteIOs
const & b
) {
318 return a
.route
->order_key (X_("editor")) < b
.route
->order_key (X_("editor"));
322 /** Gather ports from around the system and put them in this PortGroupList.
323 * @param type Type of ports to collect, or NIL for all types.
326 PortGroupList::gather (ARDOUR::Session
* session
, ARDOUR::DataType type
, bool inputs
, bool allow_dups
)
334 boost::shared_ptr
<PortGroup
> bus (new PortGroup (string_compose (_("%1 Busses"), PROGRAM_NAME
)));
335 boost::shared_ptr
<PortGroup
> track (new PortGroup (string_compose (_("%1 Tracks"), PROGRAM_NAME
)));
336 boost::shared_ptr
<PortGroup
> system (new PortGroup (_("Hardware")));
337 boost::shared_ptr
<PortGroup
> ardour (new PortGroup (string_compose (_("%1 Misc"), PROGRAM_NAME
)));
338 boost::shared_ptr
<PortGroup
> other (new PortGroup (_("Other")));
340 /* Find the IOs which have bundles for routes and their processors. We store
341 these IOs in a RouteIOs class so that we can then sort the results by route
345 boost::shared_ptr
<RouteList
> routes
= session
->get_routes ();
346 list
<RouteIOs
> route_ios
;
348 for (RouteList::const_iterator i
= routes
->begin(); i
!= routes
->end(); ++i
) {
350 /* we never show the monitor bus inputs */
352 if (inputs
&& (*i
)->is_monitor()) {
356 /* keep track of IOs that we have taken bundles from,
357 so that we can avoid taking the same IO from both
358 Route::output() and the main_outs Delivery
361 set
<boost::shared_ptr
<IO
> > used_io
;
362 boost::shared_ptr
<IO
> io
= inputs
? (*i
)->input() : (*i
)->output();
365 RouteIOs
rb (*i
, io
);
366 (*i
)->foreach_processor (boost::bind (&PortGroupList::maybe_add_processor_to_list
, this, _1
, &rb
.ios
, inputs
, used_io
));
368 route_ios
.push_back (rb
);
371 /* Sort RouteIOs by the routes' editor order keys */
372 route_ios
.sort (RouteIOsComparator ());
374 /* Now put the bundles that belong to these sorted RouteIOs into the PortGroup.
375 Note that if the RouteIO's bundles are multi-type, we may make new Bundles
376 with only the ports of one type.
379 for (list
<RouteIOs
>::iterator i
= route_ios
.begin(); i
!= route_ios
.end(); ++i
) {
380 TimeAxisView
* tv
= PublicEditor::instance().axis_view_from_route (i
->route
);
382 /* Work out which group to put these IOs' bundles in */
383 boost::shared_ptr
<PortGroup
> g
;
384 if (boost::dynamic_pointer_cast
<Track
> (i
->route
)) {
390 for (list
<boost::shared_ptr
<IO
> >::iterator j
= i
->ios
.begin(); j
!= i
->ios
.end(); ++j
) {
391 boost::shared_ptr
<Bundle
> b
= bundle_for_type ((*j
)->bundle(), type
);
392 if (b
->nchannels() != ChanCount::ZERO
) {
394 g
->add_bundle (b
, *j
, tv
->color ());
396 g
->add_bundle (b
, *j
);
402 /* Bundles owned by the session; add user bundles first, then normal ones, so
403 that UserBundles that offer the same ports as a normal bundle get priority
406 boost::shared_ptr
<BundleList
> b
= session
->bundles ();
408 for (BundleList::iterator i
= b
->begin(); i
!= b
->end(); ++i
) {
409 if (boost::dynamic_pointer_cast
<UserBundle
> (*i
) && (*i
)->ports_are_inputs() == inputs
) {
410 boost::shared_ptr
<Bundle
> b
= bundle_for_type (*i
, type
);
411 if (b
->nchannels() != ChanCount::ZERO
) {
412 system
->add_bundle (b
, allow_dups
);
417 for (BundleList::iterator i
= b
->begin(); i
!= b
->end(); ++i
) {
418 if (boost::dynamic_pointer_cast
<UserBundle
> (*i
) == 0 && (*i
)->ports_are_inputs() == inputs
) {
419 boost::shared_ptr
<Bundle
> b
= bundle_for_type (*i
, type
);
420 if (b
->nchannels() != ChanCount::ZERO
) {
421 system
->add_bundle (b
, allow_dups
);
429 boost::shared_ptr
<Bundle
> b
= bundle_for_type (session
->the_auditioner()->output()->bundle(), type
);
430 if (b
->nchannels() != ChanCount::ZERO
) {
431 ardour
->add_bundle (b
);
434 b
= bundle_for_type (session
->click_io()->bundle(), type
);
435 if (b
->nchannels() != ChanCount::ZERO
) {
436 ardour
->add_bundle (b
);
440 /* Ardour's surfaces */
442 ControlProtocolManager
& m
= ControlProtocolManager::instance ();
443 for (list
<ControlProtocolInfo
*>::iterator i
= m
.control_protocol_info
.begin(); i
!= m
.control_protocol_info
.end(); ++i
) {
444 if ((*i
)->protocol
) {
445 list
<boost::shared_ptr
<Bundle
> > b
= (*i
)->protocol
->bundles ();
446 for (list
<boost::shared_ptr
<Bundle
> >::iterator j
= b
.begin(); j
!= b
.end(); ++j
) {
447 if ((*j
)->ports_are_inputs() == inputs
) {
448 ardour
->add_bundle (*j
);
454 /* Ardour's sync ports */
456 MIDI::Manager
* midi_manager
= MIDI::Manager::instance ();
457 if (midi_manager
&& (type
== DataType::MIDI
|| type
== DataType::NIL
)) {
458 boost::shared_ptr
<Bundle
> sync (new Bundle (_("Sync"), inputs
));
459 MIDI::MachineControl
* mmc
= midi_manager
->mmc ();
460 AudioEngine
& ae
= session
->engine ();
463 _("MTC in"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->mtc_input_port()->name())
466 _("MIDI control in"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->midi_input_port()->name())
469 _("MIDI clock in"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->midi_clock_input_port()->name())
472 _("MMC in"), DataType::MIDI
, ae
.make_port_name_non_relative (mmc
->input_port()->name())
476 _("MTC out"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->mtc_output_port()->name())
479 _("MIDI control out"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->midi_output_port()->name())
482 _("MIDI clock out"), DataType::MIDI
, ae
.make_port_name_non_relative (midi_manager
->midi_clock_output_port()->name())
485 _("MMC out"), DataType::MIDI
, ae
.make_port_name_non_relative (mmc
->output_port()->name())
489 ardour
->add_bundle (sync
);
492 /* Now find all other ports that we haven't thought of yet */
494 std::vector
<std::string
> extra_system
[DataType::num_types
];
495 std::vector
<std::string
> extra_other
[DataType::num_types
];
497 string
lpn (PROGRAM_NAME
);
498 boost::to_lower (lpn
);
502 const char ** ports
= 0;
503 if (type
== DataType::NIL
) {
504 ports
= session
->engine().get_ports ("", "", inputs
? JackPortIsInput
: JackPortIsOutput
);
506 ports
= session
->engine().get_ports ("", type
.to_jack_type(), inputs
? JackPortIsInput
: JackPortIsOutput
);
515 std::string
const p
= ports
[n
];
517 if (!system
->has_port(p
) &&
519 !track
->has_port(p
) &&
520 !ardour
->has_port(p
) &&
521 !other
->has_port(p
)) {
523 /* special hack: ignore MIDI ports labelled Midi-Through. these
524 are basically useless and mess things up for default
528 if (p
.find ("Midi-Through") != string::npos
) {
533 /* special hack: ignore our monitor inputs (which show up here because
534 we excluded them earlier.
538 boost::to_lower (lp
);
540 if ((lp
.find (N_(":monitor")) != string::npos
) &&
541 (lp
.find (lpn
) != string::npos
)) {
546 /* can't use the audio engine for this as we are looking at non-Ardour ports */
548 jack_port_t
* jp
= jack_port_by_name (session
->engine().jack(), p
.c_str());
550 DataType
t (jack_port_type (jp
));
551 if (t
!= DataType::NIL
) {
552 if (port_has_prefix (p
, N_("system:")) ||
553 port_has_prefix (p
, N_("alsa_pcm")) ||
554 port_has_prefix (p
, lpnc
)) {
555 extra_system
[t
].push_back (p
);
557 extra_other
[t
].push_back (p
);
569 for (DataType::iterator i
= DataType::begin(); i
!= DataType::end(); ++i
) {
570 if (!extra_system
[*i
].empty()) {
571 boost::shared_ptr
<Bundle
> b
= make_bundle_from_ports (extra_system
[*i
], *i
, inputs
);
572 boost::shared_ptr
<Bundle
> bt
= bundle_for_type (b
, type
);
573 if (bt
->nchannels() != ChanCount::ZERO
) {
574 system
->add_bundle (bt
);
579 for (DataType::iterator i
= DataType::begin(); i
!= DataType::end(); ++i
) {
580 if (!extra_other
[*i
].empty()) {
581 boost::shared_ptr
<Bundle
> b
= make_bundle_from_ports (extra_other
[*i
], *i
, inputs
);
582 boost::shared_ptr
<Bundle
> bt
= bundle_for_type (b
, type
);
583 if (bt
->nchannels() != ChanCount::ZERO
) {
584 other
->add_bundle (bt
);
590 system
->remove_duplicates ();
593 add_group_if_not_empty (other
);
594 add_group_if_not_empty (bus
);
595 add_group_if_not_empty (track
);
596 add_group_if_not_empty (ardour
);
597 add_group_if_not_empty (system
);
602 boost::shared_ptr
<Bundle
>
603 PortGroupList::make_bundle_from_ports (std::vector
<std::string
> const & p
, ARDOUR::DataType type
, bool inputs
) const
605 boost::shared_ptr
<Bundle
> b (new Bundle ("", inputs
));
607 std::string
const pre
= common_prefix (p
);
609 b
->set_name (pre
.substr (0, pre
.length() - 1));
612 for (uint32_t j
= 0; j
< p
.size(); ++j
) {
613 b
->add_channel (p
[j
].substr (pre
.length()), type
);
614 b
->set_port (j
, p
[j
]);
621 PortGroupList::port_has_prefix (const std::string
& n
, const std::string
& p
) const
623 return n
.substr (0, p
.length()) == p
;
627 PortGroupList::common_prefix_before (std::vector
<std::string
> const & p
, std::string
const & s
) const
629 /* we must have some strings and the first must contain the separator string */
630 if (p
.empty() || p
[0].find_first_of (s
) == std::string::npos
) {
634 /* prefix of the first string */
635 std::string
const fp
= p
[0].substr (0, p
[0].find_first_of (s
) + 1);
637 /* see if the other strings also start with fp */
639 while (j
< p
.size()) {
640 if (p
[j
].substr (0, fp
.length()) != fp
) {
655 PortGroupList::common_prefix (std::vector
<std::string
> const & p
) const
657 /* common prefix before '/' ? */
658 std::string cp
= common_prefix_before (p
, "/");
663 cp
= common_prefix_before (p
, ":");
672 PortGroupList::clear ()
675 _bundle_changed_connections
.drop_connections ();
680 PortGroup::BundleList
const &
681 PortGroupList::bundles () const
685 for (PortGroupList::List::const_iterator i
= begin (); i
!= end (); ++i
) {
686 std::copy ((*i
)->bundles().begin(), (*i
)->bundles().end(), std::back_inserter (_bundles
));
693 PortGroupList::total_channels () const
697 for (PortGroupList::List::const_iterator i
= begin(); i
!= end(); ++i
) {
698 n
+= (*i
)->total_channels ();
705 PortGroupList::add_group_if_not_empty (boost::shared_ptr
<PortGroup
> g
)
707 if (!g
->bundles().empty ()) {
713 PortGroupList::add_group (boost::shared_ptr
<PortGroup
> g
)
715 _groups
.push_back (g
);
717 g
->Changed
.connect (_changed_connections
, invalidator (*this), boost::bind (&PortGroupList::emit_changed
, this), gui_context());
718 g
->BundleChanged
.connect (_bundle_changed_connections
, invalidator (*this), ui_bind (&PortGroupList::emit_bundle_changed
, this, _1
), gui_context());
724 PortGroupList::remove_bundle (boost::shared_ptr
<Bundle
> b
)
726 for (List::iterator i
= _groups
.begin(); i
!= _groups
.end(); ++i
) {
727 (*i
)->remove_bundle (b
);
734 PortGroupList::emit_changed ()
736 if (_signals_suspended
) {
737 _pending_change
= true;
744 PortGroupList::emit_bundle_changed (Bundle::Change c
)
746 if (_signals_suspended
) {
747 _pending_bundle_change
= c
;
753 PortGroupList::suspend_signals ()
755 _signals_suspended
= true;
759 PortGroupList::resume_signals ()
761 if (_pending_change
) {
763 _pending_change
= false;
766 if (_pending_bundle_change
!= 0) {
767 BundleChanged (_pending_bundle_change
);
768 _pending_bundle_change
= (ARDOUR::Bundle::Change
) 0;
771 _signals_suspended
= false;
774 boost::shared_ptr
<IO
>
775 PortGroupList::io_from_bundle (boost::shared_ptr
<ARDOUR::Bundle
> b
) const
777 List::const_iterator i
= _groups
.begin ();
778 while (i
!= _groups
.end()) {
779 boost::shared_ptr
<IO
> io
= (*i
)->io_from_bundle (b
);
786 return boost::shared_ptr
<IO
> ();
790 PortGroupList::empty () const
792 List::const_iterator i
= _groups
.begin ();
793 while (i
!= _groups
.end() && (*i
)->total_channels() == ChanCount::ZERO
) {
797 return (i
== _groups
.end());
800 /** Take a bundle, and either return it, if it contains only ports of type \a t,
801 * or return a new bundle with those ports from \a b which are of type \a t.
802 * Note that t == NIL is taken to mean "all types".
804 boost::shared_ptr
<Bundle
>
805 PortGroupList::bundle_for_type (boost::shared_ptr
<Bundle
> b
, DataType t
) const
807 /* We are asked for a bundle with all types, so that's easy */
808 if (t
== DataType::NIL
) {
812 if (b
->nchannels().get(t
) == b
->nchannels().n_total()) {
813 /* All channels on b are of the correct type, so just return b */
817 /* We must build a new bundle */
818 boost::shared_ptr
<Bundle
> n (new ARDOUR::Bundle (b
->name(), b
->ports_are_inputs()));
819 for (uint32_t i
= 0; i
< b
->nchannels().n_total(); ++i
) {
820 if (b
->channel_type(i
) == t
) {
821 n
->add_channel (b
->channel_name (i
), t
, b
->channel_ports (i
));