2 Copyright (C) 2008 Paul Davis
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 "export_channel_selector.h"
25 #include "pbd/convert.h"
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"
43 using namespace ARDOUR
;
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")),
51 channel_view (max_channels
)
53 channels_hbox
.pack_start (channels_label
, false, false, 0);
54 channels_hbox
.pack_end (channels_spinbutton
, false, false, 0);
56 channels_vbox
.pack_start (channels_hbox
, false, false, 0);
57 channels_vbox
.pack_start (split_checkbox
, false, false, 6);
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
);
65 pack_start (channels_vbox
, false, false, 0);
66 pack_start (channel_alignment
, true, true, 0);
68 /* Channels spinbutton */
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);
75 channels_spinbutton
.signal_value_changed().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_channel_count
));
79 split_checkbox
.signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_split_state
));
80 channel_view
.CriticalSelectionChanged
.connect (CriticalSelectionChanged
.make_slot());
89 PortExportChannelSelector::~PortExportChannelSelector ()
92 // session->add_instant_xml (get_state(), false);
97 PortExportChannelSelector::sync_with_manager ()
99 state
= manager
->get_channel_configs().front();
101 split_checkbox
.set_active (state
->config
->get_split());
102 channels_spinbutton
.set_value (state
->config
->get_n_chans());
105 channel_view
.set_config (state
->config
);
109 PortExportChannelSelector::fill_route_list ()
111 channel_view
.clear_routes ();
112 RouteList routes
= *_session
->get_routes();
114 /* Add master bus and then everything else */
116 ARDOUR::IO
* master
= _session
->master_out()->output().get();
117 channel_view
.add_route (master
);
119 for (RouteList::iterator it
= routes
.begin(); it
!= routes
.end(); ++it
) {
120 if ((*it
)->output().get() == master
) {
123 channel_view
.add_route ((*it
)->output().get());
126 update_channel_count ();
130 PortExportChannelSelector::update_channel_count ()
132 uint32_t chans
= static_cast<uint32_t> (channels_spinbutton
.get_value());
133 channel_view
.set_channel_count (chans
);
134 CriticalSelectionChanged();
138 PortExportChannelSelector::update_split_state ()
140 state
->config
->set_split (split_checkbox
.get_active());
141 CriticalSelectionChanged();
145 PortExportChannelSelector::RouteCols::add_channels (uint32_t chans
)
148 channels
.push_back (Channel (*this));
154 PortExportChannelSelector::RouteCols::Channel
&
155 PortExportChannelSelector::RouteCols::get_channel (uint32_t channel
)
157 if (channel
> n_channels
) {
158 std::cout
<< "Invalid channel cout for get_channel!" << std::endl
;
161 std::list
<Channel
>::iterator it
= channels
.begin();
163 while (channel
> 1) { // Channel count starts from one!
171 PortExportChannelSelector::ChannelTreeView::ChannelTreeView (uint32_t max_channels
) :
176 route_cols
.add_channels (max_channels
);
178 route_list
= Gtk::ListStore::create(route_cols
);
179 set_model (route_list
);
181 /* Add column with toggle and text */
183 append_column_editable (_("Bus or Track"), route_cols
.selected
);
185 Gtk::CellRendererText
* text_renderer
= Gtk::manage (new Gtk::CellRendererText
);
186 text_renderer
->property_editable() = false;
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
);
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
));
195 static_columns
= get_columns().size();
199 PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c
)
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
206 if (config
== c
) { return; }
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
) {
213 for (Gtk::ListStore::Children::iterator r_it
= route_list
->children().begin(); r_it
!= route_list
->children().end(); ++r_it
) {
215 ARDOUR::PortExportChannel
* pec
;
216 if (!(pec
= dynamic_cast<ARDOUR::PortExportChannel
*> (c_it
->get()))) {
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
;
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
)));
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()));
235 intersection
.erase (0); // Remove "none" selection
237 if (intersection
.empty()) {
241 if (!r_it
->get_value (route_cols
.selected
)) {
242 r_it
->set_value (route_cols
.selected
, true);
244 /* Set previous channels (if any) to none */
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)"));
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";
256 r_it
->set_value (route_cols
.get_channel (i
).port
, port
);
257 r_it
->set_value (route_cols
.get_channel (i
).label
, label
);
265 PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO
* io
)
267 Gtk::TreeModel::iterator iter
= route_list
->append();
268 Gtk::TreeModel::Row row
= *iter
;
270 row
[route_cols
.selected
] = false;
271 row
[route_cols
.name
] = io
->name();
272 row
[route_cols
.io
] = io
;
274 /* Initialize port list */
276 Glib::RefPtr
<Gtk::ListStore
> port_list
= Gtk::ListStore::create (route_cols
.port_cols
);
277 row
[route_cols
.port_list_col
] = port_list
;
279 uint32_t outs
= io
->n_ports().n_audio();
280 for (uint32_t i
= 0; i
< outs
; ++i
) {
281 iter
= port_list
->append();
284 row
[route_cols
.port_cols
.selected
] = false;
285 row
[route_cols
.port_cols
.port
] = io
->audio (i
);
287 std::ostringstream oss
;
288 oss
<< "Out-" << (i
+ 1);
290 row
[route_cols
.port_cols
.label
] = oss
.str();
293 iter
= port_list
->append();
296 row
[route_cols
.port_cols
.selected
] = false;
297 row
[route_cols
.port_cols
.port
] = 0;
298 row
[route_cols
.port_cols
.label
] = "(none)";
303 PortExportChannelSelector::ChannelTreeView::set_channel_count (uint32_t channels
)
305 int offset
= channels
- n_channels
;
310 std::ostringstream oss
;
315 Gtk::TreeView::Column
* column
= Gtk::manage (new Gtk::TreeView::Column (oss
.str()));
317 Gtk::CellRendererCombo
* combo_renderer
= Gtk::manage (new Gtk::CellRendererCombo
);
318 combo_renderer
->property_text_column() = 2;
319 column
->pack_start (*combo_renderer
);
321 append_column (*column
);
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
);
327 combo_renderer
->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_selection_text
), n_channels
));
329 /* put data into view */
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);
337 /* set column width */
339 get_column (static_columns
+ n_channels
- 1)->set_min_width (80);
347 remove_column (*get_column (n_channels
+ static_columns
));
356 PortExportChannelSelector::ChannelTreeView::update_config ()
359 if (!config
) { return; }
361 config
->clear_channels();
363 for (uint32_t i
= 1; i
<= n_channels
; ++i
) {
365 ExportChannelPtr
channel (new PortExportChannel ());
366 PortExportChannel
* pec
= static_cast<PortExportChannel
*> (channel
.get());
368 for (Gtk::ListStore::Children::iterator it
= route_list
->children().begin(); it
!= route_list
->children().end(); ++it
) {
369 Gtk::TreeModel::Row row
= *it
;
371 if (!row
[route_cols
.selected
]) {
375 AudioPort
* port
= row
[route_cols
.get_channel (i
).port
];
377 pec
->add_port (port
);
381 config
->register_channel (channel
);
384 CriticalSelectionChanged ();
388 PortExportChannelSelector::ChannelTreeView::update_toggle_selection (std::string
const & path
)
390 Gtk::TreeModel::iterator iter
= get_model ()->get_iter (path
);
391 bool selected
= iter
->get_value (route_cols
.selected
);
393 for (uint32_t i
= 1; i
<= n_channels
; ++i
) {
396 iter
->set_value (route_cols
.get_channel (i
).label
, std::string (""));
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);
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;
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
));
421 PortExportChannelSelector::ChannelTreeView::update_selection_text (std::string
const & path
, std::string
const & new_text
, uint32_t channel
)
423 Gtk::TreeModel::iterator iter
= get_model ()->get_iter (path
);
424 iter
->set_value (route_cols
.get_channel (channel
).label
, new_text
);
426 Glib::RefPtr
<Gtk::ListStore
> port_list
= iter
->get_value (route_cols
.port_list_col
);
427 Gtk::ListStore::Children::iterator port_it
;
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
]);
439 RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session
* _session
,
440 ProfileManagerPtr manager
,
441 ARDOUR::AudioRegion
const & region
,
442 ARDOUR::AudioTrack
& track
) :
443 ExportChannelSelector (_session
, manager
),
446 region_chans (region
.n_channels()),
447 track_chans (track
.n_outputs().n_audio()),
449 raw_button (type_group
),
450 fades_button (type_group
),
451 processed_button (type_group
)
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
);
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
);
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
);
468 vbox
.show_all_children ();
469 show_all_children ();
473 RegionExportChannelSelector::sync_with_manager ()
475 state
= manager
->get_channel_configs().front();
480 RegionExportChannelSelector::handle_selection ()
486 state
->config
->clear_channels ();
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
));
495 CriticalSelectionChanged ();
499 for (size_t chan
= 0; chan
< region_chans
; ++chan
) {
500 state
->config
->register_channel (factory
->create (chan
));
503 CriticalSelectionChanged ();
506 TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session
* session
, ProfileManagerPtr manager
)
507 : ExportChannelSelector(session
, manager
)
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
);
515 track_list
= Gtk::ListStore::create (track_cols
);
516 track_view
.set_model (track_list
);
517 track_view
.set_headers_visible (true);
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
)));
523 Gtk::CellRendererText
* text_renderer
= Gtk::manage (new Gtk::CellRendererText
);
524 text_renderer
->property_editable() = false;
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
);
532 show_all_children ();
536 TrackExportChannelSelector::sync_with_manager ()
538 // TODO implement properly
543 TrackExportChannelSelector::fill_list()
546 RouteList routes
= *_session
->get_routes();
548 for (RouteList::iterator it
= routes
.begin(); it
!= routes
.end(); ++it
) {
549 Route
* route
= it
->get();
550 if(dynamic_cast<AudioTrack
*>(route
)) {
557 TrackExportChannelSelector::add_track(Route
* route
)
559 Gtk::TreeModel::iterator iter
= track_list
->append();
560 Gtk::TreeModel::Row row
= *iter
;
562 row
[track_cols
.selected
] = true;
563 row
[track_cols
.label
] = route
->name();
564 row
[track_cols
.track
] = route
;
568 TrackExportChannelSelector::update_config()
570 manager
->clear_channel_configs();
572 for (Gtk::ListStore::Children::iterator it
= track_list
->children().begin(); it
!= track_list
->children().end(); ++it
) {
573 Gtk::TreeModel::Row row
= *it
;
575 if (!row
[track_cols
.selected
]) {
579 ExportProfileManager::ChannelConfigStatePtr state
= manager
->add_channel_config();
581 Route
* track
= row
[track_cols
.track
];
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);
588 ExportChannelPtr channel (new PortExportChannel ());
589 PortExportChannel * pec = static_cast<PortExportChannel *> (channel.get());
591 state->config->register_channel(channel);
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());
602 CriticalSelectionChanged ();