2 Copyright (C) 2011 Paul Davis
3 Author: Carl Hetherington <cth@carlh.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "ardour/route.h"
22 #include "ardour/route_dag.h"
27 using namespace ARDOUR;
30 DAGEdges::add (boost::shared_ptr<Route> from, boost::shared_ptr<Route> to)
32 insert (_from_to, from, to);
33 insert (_to_from, to, from);
35 EdgeMap::iterator i = _from_to.find (from);
36 if (i != _from_to.end ()) {
37 i->second.insert (to);
39 set<boost::shared_ptr<Route> > v;
41 _from_to.insert (make_pair (from, v));
46 set<boost::shared_ptr<Route> >
47 DAGEdges::from (boost::shared_ptr<Route> r) const
49 EdgeMap::const_iterator i = _from_to.find (r);
50 if (i == _from_to.end ()) {
51 return set<boost::shared_ptr<Route> > ();
58 DAGEdges::remove (boost::shared_ptr<Route> from, boost::shared_ptr<Route> to)
60 EdgeMap::iterator i = _from_to.find (from);
61 assert (i != _from_to.end ());
63 if (i->second.empty ()) {
67 EdgeMap::iterator j = _to_from.find (to);
68 assert (j != _to_from.end ());
69 j->second.erase (from);
70 if (j->second.empty ()) {
75 /** @param to `To' route.
76 * @return true if there are no edges going to `to'.
80 DAGEdges::has_none_to (boost::shared_ptr<Route> to) const
82 return _to_from.find (to) == _to_from.end ();
86 DAGEdges::empty () const
88 assert (_from_to.empty () == _to_from.empty ());
89 return _from_to.empty ();
93 DAGEdges::dump () const
95 for (EdgeMap::const_iterator i = _from_to.begin(); i != _from_to.end(); ++i) {
96 cout << "FROM: " << i->first->name() << " ";
97 for (set<boost::shared_ptr<Route> >::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
98 cout << (*j)->name() << " ";
103 for (EdgeMap::const_iterator i = _to_from.begin(); i != _to_from.end(); ++i) {
104 cout << "TO: " << i->first->name() << " ";
105 for (set<boost::shared_ptr<Route> >::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
106 cout << (*j)->name() << " ";
113 DAGEdges::insert (EdgeMap& e, boost::shared_ptr<Route> a, boost::shared_ptr<Route> b)
115 EdgeMap::iterator i = e.find (a);
117 i->second.insert (b);
119 set<boost::shared_ptr<Route> > v;
121 e.insert (make_pair (a, v));
125 struct RouteRecEnabledComparator
127 bool operator () (boost::shared_ptr<Route> r1, boost::shared_ptr<Route> r2) const
129 if (r1->record_enabled()) {
130 if (r2->record_enabled()) {
131 /* both rec-enabled, just use signal order */
132 return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
134 /* r1 rec-enabled, r2 not rec-enabled, run r2 early */
138 if (r2->record_enabled()) {
139 /* r2 rec-enabled, r1 not rec-enabled, run r1 early */
142 /* neither rec-enabled, use signal order */
143 return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
150 boost::shared_ptr<RouteList>
151 ARDOUR::topological_sort (
152 boost::shared_ptr<RouteList> routes,
156 boost::shared_ptr<RouteList> sorted_routes (new RouteList);
158 /* queue of routes to process */
161 /* initial queue has routes that are not fed by anything */
162 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
163 if ((*i)->not_fed ()) {
164 queue.push_back (*i);
168 /* Sort the initial queue so that non-rec-enabled routes are run first.
169 This is so that routes can record things coming from other routes
170 via external connections.
172 queue.sort (RouteRecEnabledComparator ());
174 /* Do the sort: algorithm is Kahn's from Wikipedia.
175 `Topological sorting of large networks', Communications of the ACM 5(11):558-562.
178 while (!queue.empty ()) {
179 boost::shared_ptr<Route> r = queue.front ();
181 sorted_routes->push_back (r);
182 set<boost::shared_ptr<Route> > e = edges.from (r);
183 for (set<boost::shared_ptr<Route> >::iterator i = e.begin(); i != e.end(); ++i) {
184 edges.remove (r, *i);
185 if (edges.has_none_to (*i)) {
186 queue.push_back (*i);
191 if (!edges.empty ()) {
192 cout << "Feedback detected.\n";
195 return sorted_routes;