Delete trailing whitespace
[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_port.h"
28 #include "ardour/audio_track.h"
29 #include "ardour/audioengine.h"
30 #include "ardour/audioregion.h"
31 #include "ardour/export_channel_configuration.h"
32 #include "ardour/export_handler.h"
33 #include "ardour/io.h"
34 #include "ardour/route.h"
35 #include "ardour/session.h"
36
37 #include <sstream>
38
39 #include "i18n.h"
40
41 using namespace std;
42 using namespace Glib;
43 using namespace ARDOUR;
44 using namespace PBD;
45
46 PortExportChannelSelector::PortExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager) :
47   ExportChannelSelector (session, manager),
48   channels_label (_("Channels:"), Gtk::ALIGN_LEFT),
49   split_checkbox (_("Split to mono files")),
50   max_channels (20),
51   channel_view (max_channels)
52 {
53         channels_hbox.pack_start (channels_label, false, false, 0);
54         channels_hbox.pack_end (channels_spinbutton, false, false, 0);
55
56         channels_vbox.pack_start (channels_hbox, false, false, 0);
57         channels_vbox.pack_start (split_checkbox, false, false, 6);
58
59         channel_alignment.add (channel_scroller);
60         channel_alignment.set_padding (0, 0, 12, 0);
61         channel_scroller.add (channel_view);
62         channel_scroller.set_size_request (-1, 130);
63         channel_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
64
65         pack_start (channels_vbox, false, false, 0);
66         pack_start (channel_alignment, true, true, 0);
67
68         /* Channels spinbutton */
69
70         channels_spinbutton.set_digits (0);
71         channels_spinbutton.set_increments (1, 2);
72         channels_spinbutton.set_range (1, max_channels);
73         channels_spinbutton.set_value (2);
74
75         channels_spinbutton.signal_value_changed().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_channel_count));
76
77         /* Other signals */
78
79         split_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_split_state));
80         channel_view.CriticalSelectionChanged.connect (CriticalSelectionChanged.make_slot());
81
82         /* Finalize */
83
84         sync_with_manager();
85         show_all_children ();
86
87 }
88
89 PortExportChannelSelector::~PortExportChannelSelector ()
90 {
91 //      if (session) {
92 //              session->add_instant_xml (get_state(), false);
93 //      }
94 }
95
96 void
97 PortExportChannelSelector::sync_with_manager ()
98 {
99         state = manager->get_channel_configs().front();
100
101         split_checkbox.set_active (state->config->get_split());
102         channels_spinbutton.set_value (state->config->get_n_chans());
103
104         fill_route_list ();
105         channel_view.set_config (state->config);
106 }
107
108 void
109 PortExportChannelSelector::fill_route_list ()
110 {
111         channel_view.clear_routes ();
112         RouteList routes = *_session->get_routes();
113
114         /* Add master bus and then everything else */
115
116         ARDOUR::IO* master = _session->master_out()->output().get();
117         channel_view.add_route (master);
118
119         for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
120                 if ((*it)->output().get() == master) {
121                         continue;
122                 }
123                 channel_view.add_route ((*it)->output().get());
124         }
125
126         update_channel_count ();
127 }
128
129 void
130 PortExportChannelSelector::update_channel_count ()
131 {
132         uint32_t chans = static_cast<uint32_t> (channels_spinbutton.get_value());
133         channel_view.set_channel_count (chans);
134         CriticalSelectionChanged();
135 }
136
137 void
138 PortExportChannelSelector::update_split_state ()
139 {
140         state->config->set_split (split_checkbox.get_active());
141         CriticalSelectionChanged();
142 }
143
144 void
145 PortExportChannelSelector::RouteCols::add_channels (uint32_t chans)
146 {
147         while (chans > 0) {
148                 channels.push_back (Channel (*this));
149                 ++n_channels;
150                 --chans;
151         }
152 }
153
154 PortExportChannelSelector::RouteCols::Channel &
155 PortExportChannelSelector::RouteCols::get_channel (uint32_t channel)
156 {
157         if (channel > n_channels) {
158                 std::cout << "Invalid channel cout for get_channel!" << std::endl;
159         }
160
161         std::list<Channel>::iterator it = channels.begin();
162
163         while (channel > 1) { // Channel count starts from one!
164                 ++it;
165                 --channel;
166         }
167
168         return *it;
169 }
170
171 PortExportChannelSelector::ChannelTreeView::ChannelTreeView (uint32_t max_channels) :
172   n_channels (0)
173 {
174         /* Main columns */
175
176         route_cols.add_channels (max_channels);
177
178         route_list = Gtk::ListStore::create(route_cols);
179         set_model (route_list);
180
181         /* Add column with toggle and text */
182
183         append_column_editable (_("Bus or Track"), route_cols.selected);
184
185         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
186         text_renderer->property_editable() = false;
187
188         Gtk::TreeView::Column* column = get_column (0);
189         column->pack_start (*text_renderer);
190         column->add_attribute (text_renderer->property_text(), route_cols.name);
191
192         Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *>(get_column_cell_renderer (0));
193         toggle->signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_toggle_selection));
194
195         static_columns = get_columns().size();
196 }
197
198 void
199 PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c)
200 {
201         /* TODO Without the following line, the state might get reset.
202          * Pointing to the same address does not mean the state of the configuration hasn't changed.
203          * In the current code this is safe, but the actual cause of the problem would be good to fix
204          */
205
206         if (config == c) { return; }
207         config = c;
208
209         uint32_t i = 1;
210         ExportChannelConfiguration::ChannelList chan_list = config->get_channels();
211         for (ExportChannelConfiguration::ChannelList::iterator c_it = chan_list.begin(); c_it != chan_list.end(); ++c_it) {
212
213                 for (Gtk::ListStore::Children::iterator r_it = route_list->children().begin(); r_it != route_list->children().end(); ++r_it) {
214
215                         ARDOUR::PortExportChannel * pec;
216                         if (!(pec = dynamic_cast<ARDOUR::PortExportChannel *> (c_it->get()))) {
217                                 continue;
218                         }
219
220                         Glib::RefPtr<Gtk::ListStore> port_list = r_it->get_value (route_cols.port_list_col);
221                         std::set<AudioPort *> route_ports;
222                         std::set<AudioPort *> intersection;
223                         std::map<AudioPort *, string> port_labels;
224
225                         for (Gtk::ListStore::Children::const_iterator p_it = port_list->children().begin(); p_it != port_list->children().end(); ++p_it) {
226                                 route_ports.insert ((*p_it)->get_value (route_cols.port_cols.port));
227                                 port_labels.insert (std::pair<AudioPort*, string> ((*p_it)->get_value (route_cols.port_cols.port),
228                                                                                     (*p_it)->get_value (route_cols.port_cols.label)));
229                         }
230
231                         std::set_intersection (pec->get_ports().begin(), pec->get_ports().end(),
232                                                route_ports.begin(), route_ports.end(),
233                                                std::insert_iterator<std::set<AudioPort *> > (intersection, intersection.begin()));
234
235                         intersection.erase (0); // Remove "none" selection
236
237                         if (intersection.empty()) {
238                                 continue;
239                         }
240
241                         if (!r_it->get_value (route_cols.selected)) {
242                                 r_it->set_value (route_cols.selected, true);
243
244                                 /* Set previous channels (if any) to none */
245
246                                 for (uint32_t chn = 1; chn < i; ++chn) {
247                                         r_it->set_value (route_cols.get_channel (chn).port, (AudioPort *) 0);
248                                         r_it->set_value (route_cols.get_channel (chn).label, string ("(none)"));
249                                 }
250                         }
251
252                         AudioPort * port = *intersection.begin();
253                         std::map<AudioPort *, string>::iterator label_it = port_labels.find (port);
254                         string label = label_it != port_labels.end() ? label_it->second : "error";
255
256                         r_it->set_value (route_cols.get_channel (i).port, port);
257                         r_it->set_value (route_cols.get_channel (i).label, label);
258                 }
259
260                 ++i;
261         }
262 }
263
264 void
265 PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * io)
266 {
267         Gtk::TreeModel::iterator iter = route_list->append();
268         Gtk::TreeModel::Row row = *iter;
269
270         row[route_cols.selected] = false;
271         row[route_cols.name] = io->name();
272         row[route_cols.io] = io;
273
274         /* Initialize port list */
275
276         Glib::RefPtr<Gtk::ListStore> port_list = Gtk::ListStore::create (route_cols.port_cols);
277         row[route_cols.port_list_col] = port_list;
278
279         uint32_t outs = io->n_ports().n_audio();
280         for (uint32_t i = 0; i < outs; ++i) {
281                 iter = port_list->append();
282                 row = *iter;
283
284                 row[route_cols.port_cols.selected] = false;
285                 row[route_cols.port_cols.port] = io->audio (i);
286
287                 std::ostringstream oss;
288                 oss << "Out-" << (i + 1);
289
290                 row[route_cols.port_cols.label] = oss.str();
291         }
292
293         iter = port_list->append();
294         row = *iter;
295
296         row[route_cols.port_cols.selected] = false;
297         row[route_cols.port_cols.port] = 0;
298         row[route_cols.port_cols.label] = "(none)";
299
300 }
301
302 void
303 PortExportChannelSelector::ChannelTreeView::set_channel_count (uint32_t channels)
304 {
305         int offset = channels - n_channels;
306
307         while (offset > 0) {
308                 ++n_channels;
309
310                 std::ostringstream oss;
311                 oss << n_channels;
312
313                 /* New column */
314
315                 Gtk::TreeView::Column* column = Gtk::manage (new Gtk::TreeView::Column (oss.str()));
316
317                 Gtk::CellRendererCombo* combo_renderer = Gtk::manage (new Gtk::CellRendererCombo);
318                 combo_renderer->property_text_column() = 2;
319                 column->pack_start (*combo_renderer);
320
321                 append_column (*column);
322
323                 column->add_attribute (combo_renderer->property_text(), route_cols.get_channel(n_channels).label);
324                 column->add_attribute (combo_renderer->property_model(), route_cols.port_list_col);
325                 column->add_attribute (combo_renderer->property_editable(), route_cols.selected);
326
327                 combo_renderer->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_selection_text), n_channels));
328
329                 /* put data into view */
330
331                 for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) {
332                         std::string label = it->get_value(route_cols.selected) ? "(none)" : "";
333                         it->set_value (route_cols.get_channel (n_channels).label, label);
334                         it->set_value (route_cols.get_channel (n_channels).port, (AudioPort *) 0);
335                 }
336
337                 /* set column width */
338
339                 get_column (static_columns + n_channels - 1)->set_min_width (80);
340
341                 --offset;
342         }
343
344         while (offset < 0) {
345                 --n_channels;
346
347                 remove_column (*get_column (n_channels + static_columns));
348
349                 ++offset;
350         }
351
352         update_config ();
353 }
354
355 void
356 PortExportChannelSelector::ChannelTreeView::update_config ()
357 {
358
359         if (!config) { return; }
360
361         config->clear_channels();
362
363         for (uint32_t i = 1; i <= n_channels; ++i) {
364
365                 ExportChannelPtr channel (new PortExportChannel ());
366                 PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
367
368                 for (Gtk::ListStore::Children::iterator it = route_list->children().begin(); it != route_list->children().end(); ++it) {
369                         Gtk::TreeModel::Row row = *it;
370
371                         if (!row[route_cols.selected]) {
372                                 continue;
373                         }
374
375                         AudioPort * port = row[route_cols.get_channel (i).port];
376                         if (port) {
377                                 pec->add_port (port);
378                         }
379                 }
380
381                 config->register_channel (channel);
382         }
383
384         CriticalSelectionChanged ();
385 }
386
387 void
388 PortExportChannelSelector::ChannelTreeView::update_toggle_selection (std::string const & path)
389 {
390         Gtk::TreeModel::iterator iter = get_model ()->get_iter (path);
391         bool selected = iter->get_value (route_cols.selected);
392
393         for (uint32_t i = 1; i <= n_channels; ++i) {
394
395                 if (!selected) {
396                         iter->set_value (route_cols.get_channel (i).label, std::string (""));
397                         continue;
398                 }
399
400                 iter->set_value (route_cols.get_channel (i).label, std::string("(none)"));
401                 iter->set_value (route_cols.get_channel (i).port, (AudioPort *) 0);
402
403                 Glib::RefPtr<Gtk::ListStore> port_list = iter->get_value (route_cols.port_list_col);
404                 Gtk::ListStore::Children::iterator port_it;
405                 uint32_t port_number = 1;
406
407                 for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) {
408                         if (port_number == i) {
409                                 iter->set_value (route_cols.get_channel (i).label, (std::string) (*port_it)->get_value (route_cols.port_cols.label));
410                                 iter->set_value (route_cols.get_channel (i).port, (AudioPort *) (*port_it)->get_value (route_cols.port_cols.port));
411                         }
412
413                         ++port_number;
414                 }
415         }
416
417         update_config ();
418 }
419
420 void
421 PortExportChannelSelector::ChannelTreeView::update_selection_text (std::string const & path, std::string const & new_text, uint32_t channel)
422 {
423         Gtk::TreeModel::iterator iter = get_model ()->get_iter (path);
424         iter->set_value (route_cols.get_channel (channel).label, new_text);
425
426         Glib::RefPtr<Gtk::ListStore> port_list = iter->get_value (route_cols.port_list_col);
427         Gtk::ListStore::Children::iterator port_it;
428
429         for (port_it = port_list->children().begin(); port_it != port_list->children().end(); ++port_it) {
430                 std::string label = port_it->get_value (route_cols.port_cols.label);
431                 if (label == new_text) {
432                         iter->set_value (route_cols.get_channel (channel).port, (AudioPort *) (*port_it)[route_cols.port_cols.port]);
433                 }
434         }
435
436         update_config ();
437 }
438
439 RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session * _session,
440                                                           ProfileManagerPtr manager,
441                                                           ARDOUR::AudioRegion const & region,
442                                                           ARDOUR::AudioTrack & track) :
443   ExportChannelSelector (_session, manager),
444   region (region),
445   track (track),
446   region_chans (region.n_channels()),
447   track_chans (track.n_outputs().n_audio()),
448
449   raw_button (type_group),
450   fades_button (type_group),
451   processed_button (type_group)
452 {
453         pack_start (vbox);
454
455         raw_button.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans));
456         raw_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
457         vbox.pack_start (raw_button);
458
459         fades_button.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans));
460         fades_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
461         vbox.pack_start (fades_button);
462
463         processed_button.set_label (string_compose (_("Track output (channels: %1)"), track_chans));
464         processed_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection));
465         vbox.pack_start (processed_button);
466
467         sync_with_manager();
468         vbox.show_all_children ();
469         show_all_children ();
470 }
471
472 void
473 RegionExportChannelSelector::sync_with_manager ()
474 {
475         state = manager->get_channel_configs().front();
476         handle_selection ();
477 }
478
479 void
480 RegionExportChannelSelector::handle_selection ()
481 {
482         if (!state) {
483                 return;
484         }
485
486         state->config->clear_channels ();
487
488         if (raw_button.get_active ()) {
489                 factory.reset (new RegionExportChannelFactory (_session, region, track, RegionExportChannelFactory::Raw));
490         } else if (fades_button.get_active ()) {
491                 factory.reset (new RegionExportChannelFactory (_session, region, track, RegionExportChannelFactory::Fades));
492         } else if (processed_button.get_active ()) {
493                 factory.reset (new RegionExportChannelFactory(_session, region, track, RegionExportChannelFactory::Processed));
494         } else {
495                 CriticalSelectionChanged ();
496                 return;
497         }
498
499         for (size_t chan = 0; chan < region_chans; ++chan) {
500                 state->config->register_channel (factory->create (chan));
501         }
502
503         CriticalSelectionChanged ();
504 }
505
506 TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session * session, ProfileManagerPtr manager)
507   : ExportChannelSelector(session, manager)
508 {
509         track_scroller.add (track_view);
510         track_scroller.set_size_request (-1, 130);
511         track_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
512         pack_start(track_scroller);
513
514         // Track list
515         track_list = Gtk::ListStore::create (track_cols);
516         track_view.set_model (track_list);
517         track_view.set_headers_visible (true);
518
519         track_view.append_column_editable (_("Track"), track_cols.selected);
520         Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *>(track_view.get_column_cell_renderer (0));
521         toggle->signal_toggled().connect (sigc::hide (sigc::mem_fun (*this, &TrackExportChannelSelector::update_config)));
522
523         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
524         text_renderer->property_editable() = false;
525
526         Gtk::TreeView::Column* column = track_view.get_column (0);
527         column->pack_start (*text_renderer);
528         column->add_attribute (text_renderer->property_text(), track_cols.label);
529
530         fill_list();
531
532         show_all_children ();
533 }
534
535 void
536 TrackExportChannelSelector::sync_with_manager ()
537 {
538         // TODO implement properly
539         update_config();
540 }
541
542 void
543 TrackExportChannelSelector::fill_list()
544 {
545         track_list->clear();
546         RouteList routes = *_session->get_routes();
547
548         for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
549                 Route * route = it->get();
550                 if(dynamic_cast<AudioTrack *>(route)) {
551                         add_track(route);
552                 }
553         }
554 }
555
556 void
557 TrackExportChannelSelector::add_track(Route * route)
558 {
559         Gtk::TreeModel::iterator iter = track_list->append();
560         Gtk::TreeModel::Row row = *iter;
561
562         row[track_cols.selected] = true;
563         row[track_cols.label] = route->name();
564         row[track_cols.track] = route;
565 }
566
567 void
568 TrackExportChannelSelector::update_config()
569 {
570         manager->clear_channel_configs();
571
572         for (Gtk::ListStore::Children::iterator it = track_list->children().begin(); it != track_list->children().end(); ++it) {
573                 Gtk::TreeModel::Row row = *it;
574
575                 if (!row[track_cols.selected]) {
576                         continue;
577                 }
578
579                 ExportProfileManager::ChannelConfigStatePtr state = manager->add_channel_config();
580
581                 Route * track = row[track_cols.track];
582
583                 /* Output of track code. TODO make this an option also
584                 uint32_t outs = track->n_ports().n_audio();
585                 for (uint32_t i = 0; i < outs; ++i) {
586                         AudioPort * port = track->audio (i);
587                         if(port) {
588                                 ExportChannelPtr channel (new PortExportChannel ());
589                                 PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
590                                 pec->add_port(port);
591                                 state->config->register_channel(channel);
592                         }
593                 }
594                 */
595
596                 std::list<ExportChannelPtr> list;
597                 RouteExportChannel::create_from_route (list, *track);
598                 state->config->register_channels (list);
599                 state->config->set_name(track->name());
600         }
601
602         CriticalSelectionChanged ();
603 }