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