c411c2b22c3acc490cc8ea5ae1c9406eb6d5871a
[ardour.git] / gtk2_ardour / export_channel_selector.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
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.
9
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.
14
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.
18
19 */
20
21 #include "export_channel_selector.h"
22
23 #include <algorithm>
24
25 #include "pbd/convert.h"
26
27 #include "ardour/audio_track.h"
28 #include "ardour/audioregion.h"
29 #include "ardour/export_channel_configuration.h"
30 #include "ardour/io.h"
31 #include "ardour/route.h"
32 #include "ardour/session.h"
33
34 #include <sstream>
35
36 #include "i18n.h"
37
38 using namespace std;
39 using namespace Glib;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 struct EditorOrderRouteSorter {
44     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
45             return a->order_key () < b->order_key ();
46     }
47 };
48
49 PortExportChannelSelector::PortExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager) :
50   ExportChannelSelector (session, manager),
51   channels_label (_("Channels:"), Gtk::ALIGN_LEFT),
52   split_checkbox (_("Split to mono files")),
53   max_channels (20),
54   channel_view (max_channels)
55 {
56         channels_hbox.pack_start (channels_label, false, false, 0);
57         channels_hbox.pack_end (channels_spinbutton, false, false, 0);
58
59         channels_vbox.pack_start (channels_hbox, false, false, 0);
60         channels_vbox.pack_start (split_checkbox, false, false, 6);
61
62         channel_alignment.add (channel_scroller);
63         channel_alignment.set_padding (0, 0, 12, 0);
64         channel_scroller.add (channel_view);
65         channel_scroller.set_size_request (-1, 130);
66         channel_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
67
68         pack_start (channels_vbox, false, false, 0);
69         pack_start (channel_alignment, true, true, 0);
70
71         /* Channels spinbutton */
72
73         channels_spinbutton.set_digits (0);
74         channels_spinbutton.set_increments (1, 2);
75         channels_spinbutton.set_range (1, max_channels);
76         channels_spinbutton.set_value (2);
77
78         channels_spinbutton.signal_value_changed().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_channel_count));
79
80         /* Other signals */
81
82         split_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_split_state));
83         channel_view.CriticalSelectionChanged.connect (CriticalSelectionChanged.make_slot());
84
85         /* Finalize */
86
87         sync_with_manager();
88         show_all_children ();
89
90 }
91
92 PortExportChannelSelector::~PortExportChannelSelector ()
93 {
94 //      if (session) {
95 //              session->add_instant_xml (get_state(), false);
96 //      }
97 }
98
99 void
100 PortExportChannelSelector::sync_with_manager ()
101 {
102         state = manager->get_channel_configs().front();
103
104         split_checkbox.set_active (state->config->get_split());
105         channels_spinbutton.set_value (state->config->get_n_chans());
106
107         /* when loading presets, config is ready set here (shared ptr)
108          * fill_route_list () -> update_channel_count () -> set_channel_count () -> update_config()
109          * will call config->clear_channels(); and clear the config
110          */
111         channel_view.set_config (ChannelConfigPtr ());
112         fill_route_list ();
113         channel_view.set_config (state->config);
114 }
115
116 void
117 PortExportChannelSelector::fill_route_list ()
118 {
119         channel_view.clear_routes ();
120         RouteList routes = *_session->get_routes();
121
122         /* Add master bus and then everything else */
123
124         if (_session->master_out()) {
125                 ARDOUR::IO* master = _session->master_out()->output().get();
126                 channel_view.add_route (master);
127         }
128
129         routes.sort (EditorOrderRouteSorter ());
130
131         for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
132                 if ((*it)->is_master () || (*it)->is_monitor ()) {
133                         continue;
134                 }
135                 channel_view.add_route ((*it)->output().get());
136         }
137
138         update_channel_count ();
139 }
140
141 void
142 PortExportChannelSelector::update_channel_count ()
143 {
144         uint32_t chans = static_cast<uint32_t> (channels_spinbutton.get_value());
145         channel_view.set_channel_count (chans);
146         CriticalSelectionChanged();
147 }
148
149 void
150 PortExportChannelSelector::update_split_state ()
151 {
152         state->config->set_split (split_checkbox.get_active());
153         CriticalSelectionChanged();
154 }
155
156 void
157 PortExportChannelSelector::RouteCols::add_channels (uint32_t chans)
158 {
159         while (chans > 0) {
160                 channels.push_back (Channel (*this));
161                 ++n_channels;
162                 --chans;
163         }
164 }
165
166 PortExportChannelSelector::RouteCols::Channel &
167 PortExportChannelSelector::RouteCols::get_channel (uint32_t channel)
168 {
169         if (channel > n_channels) {
170                 std::cout << "Invalid channel count for get_channel!" << std::endl;
171         }
172
173         std::list<Channel>::iterator it = channels.begin();
174
175         while (channel > 1) { // Channel count starts from one!
176                 ++it;
177                 --channel;
178         }
179
180         return *it;
181 }
182
183 PortExportChannelSelector::ChannelTreeView::ChannelTreeView (uint32_t max_channels) :
184   n_channels (0)
185 {
186         /* Main columns */
187
188         route_cols.add_channels (max_channels);
189
190         route_list = Gtk::ListStore::create(route_cols);
191         set_model (route_list);
192
193         /* Add column with toggle and text */
194
195         append_column_editable (_("Export"), route_cols.selected);
196
197         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
198         text_renderer->property_editable() = false;
199         text_renderer->set_alignment (0.0, 0.5);
200
201         Gtk::TreeView::Column* column = Gtk::manage (new Gtk::TreeView::Column);
202         column->set_title (_("Bus or Track"));
203         column->pack_start (*text_renderer);
204         column->set_expand (true);
205         column->add_attribute (text_renderer->property_text(), route_cols.name);
206         append_column  (*column);
207
208         Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *>(get_column_cell_renderer (0));
209         toggle->set_alignment (0.0, 0.5);
210         toggle->signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_toggle_selection));
211
212         static_columns = get_columns().size();
213 }
214
215 void
216 PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c)
217 {
218         /* TODO Without the following line, the state might get reset.
219          * Pointing to the same address does not mean the state of the configuration hasn't changed.
220          * In the current code this is safe, but the actual cause of the problem would be good to fix
221          */
222
223         if (config == c) { return; }
224         config = c;
225         if (!config) { return; }
226
227         uint32_t i = 1;
228         ExportChannelConfiguration::ChannelList chan_list = config->get_channels();
229         for (ExportChannelConfiguration::ChannelList::iterator c_it = chan_list.begin(); c_it != chan_list.end(); ++c_it) {
230
231                 for (Gtk::ListStore::Children::iterator r_it = route_list->children().begin(); r_it != route_list->children().end(); ++r_it) {
232
233                         ARDOUR::PortExportChannel * pec;
234                         if (!(pec = dynamic_cast<ARDOUR::PortExportChannel *> (c_it->get()))) {
235                                 continue;
236                         }
237
238                         Glib::RefPtr<Gtk::ListStore> port_list = r_it->get_value (route_cols.port_list_col);
239                         std::set<boost::weak_ptr<AudioPort> > route_ports;
240                         std::set<boost::weak_ptr<AudioPort> > intersection;
241                         std::map<boost::weak_ptr<AudioPort>, string> port_labels;
242
243                         for (Gtk::ListStore::Children::const_iterator p_it = port_list->children().begin(); p_it != port_list->children().end(); ++p_it) {
244                                 route_ports.insert ((*p_it)->get_value (route_cols.port_cols.port));
245                                 port_labels.insert (make_pair ((*p_it)->get_value (route_cols.port_cols.port),
246                                                                (*p_it)->get_value (route_cols.port_cols.label)));
247                         }
248
249                         std::set_intersection (pec->get_ports().begin(), pec->get_ports().end(),
250                                                route_ports.begin(), route_ports.end(),
251                                                std::insert_iterator<std::set<boost::weak_ptr<AudioPort> > > (intersection, intersection.begin()));
252
253                         intersection.erase (boost::weak_ptr<AudioPort> ()); // Remove "none" selection
254
255                         if (intersection.empty()) {
256                                 continue;
257                         }
258
259                         if (!r_it->get_value (route_cols.selected)) {
260                                 r_it->set_value (route_cols.selected, true);
261
262                                 /* Set previous channels (if any) to none */
263
264                                 for (uint32_t chn = 1; chn < i; ++chn) {
265                                         r_it->set_value (route_cols.get_channel (chn).port, boost::weak_ptr<AudioPort> ());
266                                         r_it->set_value (route_cols.get_channel (chn).label, string ("(none)"));
267                                 }
268                         }
269
270                         boost::weak_ptr<AudioPort> port = *intersection.begin();
271                         std::map<boost::weak_ptr<AudioPort>, string>::iterator label_it = port_labels.find (port);
272                         string label = label_it != port_labels.end() ? label_it->second : "error";
273
274                         r_it->set_value (route_cols.get_channel (i).port, port);
275                         r_it->set_value (route_cols.get_channel (i).label, label);
276                 }
277
278                 ++i;
279         }
280 }
281
282 void
283 PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * io)
284 {
285         Gtk::TreeModel::iterator iter = route_list->append();
286         Gtk::TreeModel::Row row = *iter;
287
288         row[route_cols.selected] = false;
289         row[route_cols.name] = io->name();
290         row[route_cols.io] = io;
291
292         /* Initialize port list */
293
294         Glib::RefPtr<Gtk::ListStore> port_list = Gtk::ListStore::create (route_cols.port_cols);
295         row[route_cols.port_list_col] = port_list;
296
297         uint32_t outs = io->n_ports().n_audio();
298         for (uint32_t i = 0; i < outs; ++i) {
299                 iter = port_list->append();
300                 row = *iter;
301
302                 row[route_cols.port_cols.selected] = false;
303                 row[route_cols.port_cols.port] = io->audio (i);
304
305                 std::ostringstream oss;
306                 oss << "Out-" << (i + 1);
307
308                 row[route_cols.port_cols.label] = oss.str();
309         }
310
311         iter = port_list->append();
312         row = *iter;
313
314         row[route_cols.port_cols.selected] = false;
315         row[route_cols.port_cols.port] = boost::weak_ptr<AudioPort> ();
316         row[route_cols.port_cols.label] = "(none)";
317
318 }
319
320 void
321 PortExportChannelSelector::ChannelTreeView::set_channel_count (uint32_t channels)
322 {
323         int offset = channels - n_channels;
324
325         while (offset > 0) {
326                 ++n_channels;
327
328                 std::ostringstream oss;
329                 oss << n_channels;
330
331                 /* New column */
332
333                 Gtk::TreeView::Column* column = Gtk::manage (new Gtk::TreeView::Column (oss.str()));
334
335                 Gtk::CellRendererCombo* combo_renderer = Gtk::manage (new Gtk::CellRendererCombo);
336                 combo_renderer->property_text_column() = 2;
337                 combo_renderer->property_has_entry() = false;
338                 column->pack_start (*combo_renderer);
339
340                 append_column (*column);
341
342                 column->add_attribute (combo_renderer->property_text(), route_cols.get_channel(n_channels).label);
343                 column->add_attribute (combo_renderer->property_model(), route_cols.port_list_col);
344                 column->add_attribute (combo_renderer->property_editable(), route_cols.selected);
345
346                 combo_renderer->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_selection_text), n_channels));
347
348                 /* put data into view */
349
350                 for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) {
351                         std::string label = it->get_value(route_cols.selected) ? "(none)" : "";
352                         it->set_value (route_cols.get_channel (n_channels).label, label);
353                         it->set_value (route_cols.get_channel (n_channels).port, boost::weak_ptr<AudioPort> ());
354                 }
355
356                 /* set column width */
357
358                 get_column (static_columns + n_channels - 1)->set_min_width (80);
359
360                 --offset;
361         }
362
363         while (offset < 0) {
364                 --n_channels;
365
366                 remove_column (*get_column (n_channels + static_columns));
367
368                 ++offset;
369         }
370
371         update_config ();
372 }
373
374 void
375 PortExportChannelSelector::ChannelTreeView::update_config ()
376 {
377         if (!config) { return; }
378
379         config->clear_channels();
380
381         for (uint32_t i = 1; i <= n_channels; ++i) {
382
383                 ExportChannelPtr channel (new PortExportChannel ());
384                 PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
385
386                 for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) {
387                         Gtk::TreeModel::Row row = *it;
388
389                         if (!row[route_cols.selected]) {
390                                 continue;
391                         }
392
393                         boost::weak_ptr<AudioPort> weak_port = row[route_cols.get_channel (i).port];
394                         boost::shared_ptr<AudioPort> port = weak_port.lock ();
395                         if (port) {
396                                 pec->add_port (port);
397                         }
398                 }
399
400                 config->register_channel (channel);
401         }
402
403         CriticalSelectionChanged ();
404 }
405
406 void
407 PortExportChannelSelector::ChannelTreeView::update_toggle_selection (std::string const & path)
408 {
409         Gtk::TreeModel::iterator iter = get_model ()->get_iter (path);
410         bool selected = iter->get_value (route_cols.selected);
411
412         for (uint32_t i = 1; i <= n_channels; ++i) {
413
414                 if (!selected) {
415                         iter->set_value (route_cols.get_channel (i).label, std::string (""));
416                         continue;
417                 }
418
419                 iter->set_value (route_cols.get_channel (i).label, std::string("(none)"));
420                 iter->set_value (route_cols.get_channel (i).port, boost::weak_ptr<AudioPort> ());
421
422                 Glib::RefPtr<Gtk::ListStore> port_list = iter->get_value (route_cols.port_list_col);
423                 Gtk::ListStore::Children::iterator port_it;
424                 uint32_t port_number = 1;
425
426                 for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) {
427                         if (port_number == i) {
428                                 iter->set_value (route_cols.get_channel (i).label, (std::string) (*port_it)->get_value (route_cols.port_cols.label));
429                                 iter->set_value (route_cols.get_channel (i).port, (*port_it)->get_value (route_cols.port_cols.port));
430                         }
431
432                         ++port_number;
433                 }
434         }
435
436         update_config ();
437 }
438
439 void
440 PortExportChannelSelector::ChannelTreeView::update_selection_text (std::string const & path, std::string const & new_text, uint32_t channel)
441 {
442         Gtk::TreeModel::iterator iter = get_model ()->get_iter (path);
443         iter->set_value (route_cols.get_channel (channel).label, new_text);
444
445         Glib::RefPtr<Gtk::ListStore> port_list = iter->get_value (route_cols.port_list_col);
446         Gtk::ListStore::Children::iterator port_it;
447
448         for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) {
449                 std::string label = port_it->get_value (route_cols.port_cols.label);
450                 if (label == new_text) {
451                         boost::weak_ptr<AudioPort> w = (*port_it)[route_cols.port_cols.port];
452                         iter->set_value (route_cols.get_channel (channel).port, w);
453                 }
454         }
455
456         update_config ();
457 }
458
459 RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session * _session,
460                                                           ProfileManagerPtr manager,
461                                                           ARDOUR::AudioRegion const & region,
462                                                           ARDOUR::AudioTrack & track) :
463   ExportChannelSelector (_session, manager),
464   region (region),
465   track (track),
466   region_chans (region.n_channels()),
467   track_chans (track.n_outputs().n_audio()),
468
469   raw_button (type_group),
470   fades_button (type_group),
471   processed_button (type_group)
472 {
473         pack_start (vbox);
474
475         /* make fades+region gain be the default */
476
477         fades_button.set_active ();
478
479         raw_button.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans));
480         raw_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
481         vbox.pack_start (raw_button, false, false);
482
483         fades_button.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans));
484         fades_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
485         vbox.pack_start (fades_button, false, false);
486
487         processed_button.set_label (string_compose (_("Track output (channels: %1)"), track_chans));
488         processed_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
489         vbox.pack_start (processed_button, false, false);
490
491         sync_with_manager();
492         vbox.show_all_children ();
493         show_all_children ();
494 }
495
496 void
497 RegionExportChannelSelector::sync_with_manager ()
498 {
499         state = manager->get_channel_configs().front();
500
501         if (!state) { return; }
502
503         switch (state->config->region_processing_type()) {
504         case RegionExportChannelFactory::None:
505                 // Do nothing
506                 break;
507         case RegionExportChannelFactory::Raw:
508                 raw_button.set_active (true);
509                 break;
510         case RegionExportChannelFactory::Fades:
511                 fades_button.set_active (true);
512                 break;
513         case RegionExportChannelFactory::Processed:
514                 processed_button.set_active (true);
515                 break;
516         }
517
518         handle_selection ();
519 }
520
521 void
522 RegionExportChannelSelector::handle_selection ()
523 {
524         if (!state) {
525                 return;
526         }
527
528         state->config->clear_channels ();
529
530         RegionExportChannelFactory::Type type = RegionExportChannelFactory::None;
531         if (raw_button.get_active ()) {
532                 type = RegionExportChannelFactory::Raw;
533         } else if (fades_button.get_active ()) {
534                 type = RegionExportChannelFactory::Fades;
535         } else if (processed_button.get_active ()) {
536                 type = RegionExportChannelFactory::Processed;
537         } else {
538                 CriticalSelectionChanged ();
539                 return;
540         }
541
542         factory.reset (new RegionExportChannelFactory (_session, region, track, type));
543         state->config->set_region_processing_type (type);
544
545         const size_t cc = type == RegionExportChannelFactory::Processed ? track_chans : region_chans;
546         for (size_t chan = 0; chan < cc; ++chan) {
547                 state->config->register_channel (factory->create (chan));
548         }
549
550         CriticalSelectionChanged ();
551 }
552
553 /* Track export channel selector */
554
555 TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager)
556   : ExportChannelSelector(session, manager)
557   , track_output_button(_("Apply track/bus processing"))
558   , select_tracks_button (_("Select all tracks"))
559   , select_busses_button (_("Select all busses"))
560   , select_none_button (_("Deselect all"))
561 {
562         pack_start(main_layout);
563
564         // Options
565         options_box.pack_start(track_output_button);
566         options_box.pack_start (select_tracks_button);
567         options_box.pack_start (select_busses_button);
568         options_box.pack_start (select_none_button);
569         main_layout.pack_start(options_box, false, false);
570
571         // Track scroller
572         track_scroller.add (track_view);
573         track_scroller.set_size_request (-1, 130);
574         track_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
575         main_layout.pack_start(track_scroller);
576
577         // Track list
578         track_list = Gtk::ListStore::create (track_cols);
579         track_list->set_sort_column (track_cols.order_key, Gtk::SORT_ASCENDING);
580         track_view.set_model (track_list);
581         track_view.set_headers_visible (true);
582
583         track_view.append_column_editable (_("Export"), track_cols.selected);
584         Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *>(track_view.get_column_cell_renderer (0));
585         toggle->set_alignment (0.0, 0.5);
586
587         toggle->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &TrackExportChannelSelector::update_config)));
588
589         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
590         text_renderer->property_editable() = false;
591         text_renderer->set_alignment (0.0, 0.5);
592
593         Gtk::TreeView::Column* column = Gtk::manage (new Gtk::TreeView::Column);
594         column->set_title (_("Track name"));
595
596         track_view.append_column  (*column);
597         column->pack_start (*text_renderer, false);
598         column->add_attribute (text_renderer->property_text(), track_cols.label);
599
600         select_tracks_button.signal_clicked().connect (sigc::mem_fun (*this, &TrackExportChannelSelector::select_tracks));
601         select_busses_button.signal_clicked().connect (sigc::mem_fun (*this, &TrackExportChannelSelector::select_busses));
602         select_none_button.signal_clicked().connect (sigc::mem_fun (*this, &TrackExportChannelSelector::select_none));
603
604         track_output_button.signal_clicked().connect (sigc::mem_fun (*this, &TrackExportChannelSelector::track_outputs_selected));
605
606         fill_list();
607
608         show_all_children ();
609 }
610
611 void
612 TrackExportChannelSelector::sync_with_manager ()
613 {
614         // TODO implement properly
615         update_config();
616 }
617
618 void
619 TrackExportChannelSelector::select_tracks ()
620 {
621         for (Gtk::ListStore::Children::iterator it = track_list->children().begin(); it != track_list->children().end(); ++it) {
622                 Gtk::TreeModel::Row row = *it;
623                 boost::shared_ptr<Route> route = row[track_cols.route];
624                 if (boost::dynamic_pointer_cast<Track> (route)) {
625                         // it's a track
626                         row[track_cols.selected] = true;
627                 }
628         }
629         update_config();
630 }
631
632 void
633 TrackExportChannelSelector::select_busses ()
634 {
635         for (Gtk::ListStore::Children::iterator it = track_list->children().begin(); it != track_list->children().end(); ++it) {
636                 Gtk::TreeModel::Row row = *it;
637                 boost::shared_ptr<Route> route = row[track_cols.route];
638                 if (!boost::dynamic_pointer_cast<Track> (route)) {
639                         // it's not a track, must be a bus
640                         row[track_cols.selected] = true;
641                 }
642         }
643         update_config();
644 }
645
646 void
647 TrackExportChannelSelector::select_none ()
648 {
649         for (Gtk::ListStore::Children::iterator it = track_list->children().begin(); it != track_list->children().end(); ++it) {
650                 Gtk::TreeModel::Row row = *it;
651                 row[track_cols.selected] = false;
652         }
653         update_config();
654 }
655
656 void
657 TrackExportChannelSelector::track_outputs_selected ()
658 {
659         update_config();
660 }
661
662 void
663 TrackExportChannelSelector::fill_list()
664 {
665         track_list->clear();
666         RouteList routes = *_session->get_routes();
667
668         for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
669                 if (!boost::dynamic_pointer_cast<Track>(*it)) {
670                         // not a track, must be a bus
671                         if ((*it)->is_master () || (*it)->is_monitor ()) {
672                                 continue;
673                         }
674                         if (!(*it)->active ()) {
675                                 // don't include inactive busses
676                                 continue;
677                         }
678
679                         // not monitor or master bus
680                         add_track (*it);
681                 }
682         }
683         for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
684                 if (boost::dynamic_pointer_cast<AudioTrack>(*it)) {
685                         if (!(*it)->active ()) {
686                                 // don't include inactive tracks
687                                 continue;
688                         }
689                         add_track (*it);
690                 }
691         }
692 }
693
694 void
695 TrackExportChannelSelector::add_track (boost::shared_ptr<Route> route)
696 {
697         Gtk::TreeModel::iterator iter = track_list->append();
698         Gtk::TreeModel::Row row = *iter;
699
700         row[track_cols.selected] = false;
701         row[track_cols.label] = route->name();
702         row[track_cols.route] = route;
703         row[track_cols.order_key] = route->order_key();
704 }
705
706 void
707 TrackExportChannelSelector::update_config()
708 {
709         manager->clear_channel_configs();
710
711         for (Gtk::ListStore::Children::iterator it = track_list->children().begin(); it != track_list->children().end(); ++it) {
712                 Gtk::TreeModel::Row row = *it;
713
714                 if (!row[track_cols.selected]) {
715                         continue;
716                 }
717
718                 ExportProfileManager::ChannelConfigStatePtr state = manager->add_channel_config();
719
720                 boost::shared_ptr<Route> route = row[track_cols.route];
721
722                 if (track_output_button.get_active()) {
723                         uint32_t outs = route->n_outputs().n_audio();
724                         for (uint32_t i = 0; i < outs; ++i) {
725                                 boost::shared_ptr<AudioPort> port = route->output()->audio (i);
726                                 if (port) {
727                                         ExportChannelPtr channel (new PortExportChannel ());
728                                         PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
729                                         pec->add_port(port);
730                                         state->config->register_channel(channel);
731                                 }
732                         }
733                 } else {
734                         std::list<ExportChannelPtr> list;
735                         RouteExportChannel::create_from_route (list, route);
736                         state->config->register_channels (list);
737                 }
738
739                 state->config->set_name (route->name());
740
741         }
742
743         CriticalSelectionChanged ();
744 }