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/export_channel_configuration.h"
31 #include "ardour/export_handler.h"
32 #include "ardour/io.h"
33 #include "ardour/route.h"
34 #include "ardour/session.h"
42 using namespace ARDOUR
;
45 PortExportChannelSelector::PortExportChannelSelector (ARDOUR::Session
* session
, ProfileManagerPtr manager
) :
46 ExportChannelSelector (session
, manager
),
47 channels_label (_("Channels:"), Gtk::ALIGN_LEFT
),
48 split_checkbox (_("Split to mono files")),
50 channel_view (max_channels
)
52 channels_hbox
.pack_start (channels_label
, false, false, 0);
53 channels_hbox
.pack_end (channels_spinbutton
, false, false, 0);
55 channels_vbox
.pack_start (channels_hbox
, false, false, 0);
56 channels_vbox
.pack_start (split_checkbox
, false, false, 6);
58 channel_alignment
.add (channel_scroller
);
59 channel_alignment
.set_padding (0, 0, 12, 0);
60 channel_scroller
.add (channel_view
);
61 channel_scroller
.set_size_request (-1, 130);
62 channel_scroller
.set_policy (Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
64 pack_start (channels_vbox
, false, false, 0);
65 pack_start (channel_alignment
, true, true, 0);
67 /* Channels spinbutton */
69 channels_spinbutton
.set_digits (0);
70 channels_spinbutton
.set_increments (1, 2);
71 channels_spinbutton
.set_range (1, max_channels
);
72 channels_spinbutton
.set_value (2);
74 channels_spinbutton
.signal_value_changed().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_channel_count
));
78 split_checkbox
.signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::update_split_state
));
79 channel_view
.CriticalSelectionChanged
.connect (CriticalSelectionChanged
.make_slot());
88 PortExportChannelSelector::~PortExportChannelSelector ()
91 // session->add_instant_xml (get_state(), false);
96 PortExportChannelSelector::sync_with_manager ()
98 state
= manager
->get_channel_configs().front();
100 split_checkbox
.set_active (state
->config
->get_split());
101 channels_spinbutton
.set_value (state
->config
->get_n_chans());
104 channel_view
.set_config (state
->config
);
108 PortExportChannelSelector::fill_route_list ()
110 channel_view
.clear_routes ();
111 RouteList routes
= *_session
->get_routes();
113 /* Add master bus and then everything else */
115 ARDOUR::IO
* master
= _session
->master_out()->output().get();
116 channel_view
.add_route (master
);
118 for (RouteList::iterator it
= routes
.begin(); it
!= routes
.end(); ++it
) {
119 if ((*it
)->output().get() == master
) {
122 channel_view
.add_route ((*it
)->output().get());
125 update_channel_count ();
129 PortExportChannelSelector::update_channel_count ()
131 uint32_t chans
= static_cast<uint32_t> (channels_spinbutton
.get_value());
132 channel_view
.set_channel_count (chans
);
133 CriticalSelectionChanged();
137 PortExportChannelSelector::update_split_state ()
139 state
->config
->set_split (split_checkbox
.get_active());
140 CriticalSelectionChanged();
144 PortExportChannelSelector::RouteCols::add_channels (uint32_t chans
)
147 channels
.push_back (Channel (*this));
153 PortExportChannelSelector::RouteCols::Channel
&
154 PortExportChannelSelector::RouteCols::get_channel (uint32_t channel
)
156 if (channel
> n_channels
) {
157 std::cout
<< "Invalid channel cout for get_channel!" << std::endl
;
160 std::list
<Channel
>::iterator it
= channels
.begin();
162 while (channel
> 1) { // Channel count starts from one!
170 PortExportChannelSelector::ChannelTreeView::ChannelTreeView (uint32_t max_channels
) :
175 route_cols
.add_channels (max_channels
);
177 route_list
= Gtk::ListStore::create(route_cols
);
178 set_model (route_list
);
180 /* Add column with toggle and text */
182 append_column_editable (_("Bus or Track"), route_cols
.selected
);
184 Gtk::CellRendererText
* text_renderer
= Gtk::manage (new Gtk::CellRendererText
);
185 text_renderer
->property_editable() = false;
187 Gtk::TreeView::Column
* column
= get_column (0);
188 column
->pack_start (*text_renderer
);
189 column
->add_attribute (text_renderer
->property_text(), route_cols
.name
);
191 Gtk::CellRendererToggle
*toggle
= dynamic_cast<Gtk::CellRendererToggle
*>(get_column_cell_renderer (0));
192 toggle
->signal_toggled().connect (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_toggle_selection
));
194 static_columns
= get_columns().size();
198 PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c
)
200 /* TODO Without the following line, the state might get reset.
201 * Pointing to the same address does not mean the state of the configuration hasn't changed.
202 * In the current code this is safe, but the actual cause of the problem would be good to fix
205 if (config
== c
) { return; }
209 ExportChannelConfiguration::ChannelList chan_list
= config
->get_channels();
210 for (ExportChannelConfiguration::ChannelList::iterator c_it
= chan_list
.begin(); c_it
!= chan_list
.end(); ++c_it
) {
212 for (Gtk::ListStore::Children::iterator r_it
= route_list
->children().begin(); r_it
!= route_list
->children().end(); ++r_it
) {
214 ARDOUR::PortExportChannel
* pec
;
215 if (!(pec
= dynamic_cast<ARDOUR::PortExportChannel
*> (c_it
->get()))) {
219 Glib::RefPtr
<Gtk::ListStore
> port_list
= r_it
->get_value (route_cols
.port_list_col
);
220 std::set
<AudioPort
*> route_ports
;
221 std::set
<AudioPort
*> intersection
;
222 std::map
<AudioPort
*, ustring
> port_labels
;
224 for (Gtk::ListStore::Children::const_iterator p_it
= port_list
->children().begin(); p_it
!= port_list
->children().end(); ++p_it
) {
225 route_ports
.insert ((*p_it
)->get_value (route_cols
.port_cols
.port
));
226 port_labels
.insert (std::pair
<AudioPort
*, ustring
> ((*p_it
)->get_value (route_cols
.port_cols
.port
),
227 (*p_it
)->get_value (route_cols
.port_cols
.label
)));
230 std::set_intersection (pec
->get_ports().begin(), pec
->get_ports().end(),
231 route_ports
.begin(), route_ports
.end(),
232 std::insert_iterator
<std::set
<AudioPort
*> > (intersection
, intersection
.begin()));
234 intersection
.erase (0); // Remove "none" selection
236 if (intersection
.empty()) {
240 if (!r_it
->get_value (route_cols
.selected
)) {
241 r_it
->set_value (route_cols
.selected
, true);
243 /* Set previous channels (if any) to none */
245 for (uint32_t chn
= 1; chn
< i
; ++chn
) {
246 r_it
->set_value (route_cols
.get_channel (chn
).port
, (AudioPort
*) 0);
247 r_it
->set_value (route_cols
.get_channel (chn
).label
, ustring ("(none)"));
251 AudioPort
* port
= *intersection
.begin();
252 std::map
<AudioPort
*, ustring
>::iterator label_it
= port_labels
.find (port
);
253 ustring label
= label_it
!= port_labels
.end() ? label_it
->second
: "error";
255 r_it
->set_value (route_cols
.get_channel (i
).port
, port
);
256 r_it
->set_value (route_cols
.get_channel (i
).label
, label
);
264 PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO
* io
)
266 Gtk::TreeModel::iterator iter
= route_list
->append();
267 Gtk::TreeModel::Row row
= *iter
;
269 row
[route_cols
.selected
] = false;
270 row
[route_cols
.name
] = io
->name();
271 row
[route_cols
.io
] = io
;
273 /* Initialize port list */
275 Glib::RefPtr
<Gtk::ListStore
> port_list
= Gtk::ListStore::create (route_cols
.port_cols
);
276 row
[route_cols
.port_list_col
] = port_list
;
278 uint32_t outs
= io
->n_ports().n_audio();
279 for (uint32_t i
= 0; i
< outs
; ++i
) {
280 iter
= port_list
->append();
283 row
[route_cols
.port_cols
.selected
] = false;
284 row
[route_cols
.port_cols
.port
] = io
->audio (i
);
286 std::ostringstream oss
;
287 oss
<< "Out-" << (i
+ 1);
289 row
[route_cols
.port_cols
.label
] = oss
.str();
292 iter
= port_list
->append();
295 row
[route_cols
.port_cols
.selected
] = false;
296 row
[route_cols
.port_cols
.port
] = 0;
297 row
[route_cols
.port_cols
.label
] = "(none)";
302 PortExportChannelSelector::ChannelTreeView::set_channel_count (uint32_t channels
)
304 int offset
= channels
- n_channels
;
309 std::ostringstream oss
;
314 Gtk::TreeView::Column
* column
= Gtk::manage (new Gtk::TreeView::Column (oss
.str()));
316 Gtk::CellRendererCombo
* combo_renderer
= Gtk::manage (new Gtk::CellRendererCombo
);
317 combo_renderer
->property_text_column() = 2;
318 column
->pack_start (*combo_renderer
);
320 append_column (*column
);
322 column
->add_attribute (combo_renderer
->property_text(), route_cols
.get_channel(n_channels
).label
);
323 column
->add_attribute (combo_renderer
->property_model(), route_cols
.port_list_col
);
324 column
->add_attribute (combo_renderer
->property_editable(), route_cols
.selected
);
326 combo_renderer
->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &PortExportChannelSelector::ChannelTreeView::update_selection_text
), n_channels
));
328 /* put data into view */
330 for (Gtk::ListStore::Children::iterator it
= route_list
->children().begin(); it
!= route_list
->children().end(); ++it
) {
331 Glib::ustring label
= it
->get_value(route_cols
.selected
) ? "(none)" : "";
332 it
->set_value (route_cols
.get_channel (n_channels
).label
, label
);
333 it
->set_value (route_cols
.get_channel (n_channels
).port
, (AudioPort
*) 0);
336 /* set column width */
338 get_column (static_columns
+ n_channels
- 1)->set_min_width (80);
346 remove_column (*get_column (n_channels
+ static_columns
));
355 PortExportChannelSelector::ChannelTreeView::update_config ()
358 if (!config
) { return; }
360 config
->clear_channels();
362 for (uint32_t i
= 1; i
<= n_channels
; ++i
) {
364 ExportChannelPtr
channel (new PortExportChannel ());
365 PortExportChannel
* pec
= static_cast<PortExportChannel
*> (channel
.get());
367 for (Gtk::ListStore::Children::iterator it
= route_list
->children().begin(); it
!= route_list
->children().end(); ++it
) {
368 Gtk::TreeModel::Row row
= *it
;
370 if (!row
[route_cols
.selected
]) {
374 AudioPort
* port
= row
[route_cols
.get_channel (i
).port
];
376 pec
->add_port (port
);
380 config
->register_channel (channel
);
383 CriticalSelectionChanged ();
387 PortExportChannelSelector::ChannelTreeView::update_toggle_selection (Glib::ustring
const & path
)
389 Gtk::TreeModel::iterator iter
= get_model ()->get_iter (path
);
390 bool selected
= iter
->get_value (route_cols
.selected
);
392 for (uint32_t i
= 1; i
<= n_channels
; ++i
) {
395 iter
->set_value (route_cols
.get_channel (i
).label
, Glib::ustring (""));
399 iter
->set_value (route_cols
.get_channel (i
).label
, Glib::ustring("(none)"));
400 iter
->set_value (route_cols
.get_channel (i
).port
, (AudioPort
*) 0);
402 Glib::RefPtr
<Gtk::ListStore
> port_list
= iter
->get_value (route_cols
.port_list_col
);
403 Gtk::ListStore::Children::iterator port_it
;
404 uint32_t port_number
= 1;
406 for (port_it
= port_list
->children().begin(); port_it
!= port_list
->children().end(); ++port_it
) {
407 if (port_number
== i
) {
408 iter
->set_value (route_cols
.get_channel (i
).label
, (Glib::ustring
) (*port_it
)->get_value (route_cols
.port_cols
.label
));
409 iter
->set_value (route_cols
.get_channel (i
).port
, (AudioPort
*) (*port_it
)->get_value (route_cols
.port_cols
.port
));
420 PortExportChannelSelector::ChannelTreeView::update_selection_text (Glib::ustring
const & path
, Glib::ustring
const & new_text
, uint32_t channel
)
422 Gtk::TreeModel::iterator iter
= get_model ()->get_iter (path
);
423 iter
->set_value (route_cols
.get_channel (channel
).label
, new_text
);
425 Glib::RefPtr
<Gtk::ListStore
> port_list
= iter
->get_value (route_cols
.port_list_col
);
426 Gtk::ListStore::Children::iterator port_it
;
428 for (port_it
= port_list
->children().begin(); port_it
!= port_list
->children().end(); ++port_it
) {
429 Glib::ustring label
= port_it
->get_value (route_cols
.port_cols
.label
);
430 if (label
== new_text
) {
431 iter
->set_value (route_cols
.get_channel (channel
).port
, (AudioPort
*) (*port_it
)[route_cols
.port_cols
.port
]);
438 RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session
* _session
,
439 ProfileManagerPtr manager
,
440 ARDOUR::AudioRegion
const & region
,
441 ARDOUR::AudioTrack
& track
) :
442 ExportChannelSelector (_session
, manager
),
445 region_chans (region
.n_channels()),
446 track_chans (track
.n_outputs().n_audio()),
448 raw_button (type_group
),
449 fades_button (type_group
),
450 processed_button (type_group
)
454 raw_button
.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans
));
455 raw_button
.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection
));
456 vbox
.pack_start (raw_button
);
458 fades_button
.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans
));
459 fades_button
.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection
));
460 vbox
.pack_start (fades_button
);
462 processed_button
.set_label (string_compose (_("Track output (channels: %1)"), track_chans
));
463 processed_button
.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection
));
464 vbox
.pack_start (processed_button
);
467 vbox
.show_all_children ();
468 show_all_children ();
472 RegionExportChannelSelector::sync_with_manager ()
474 state
= manager
->get_channel_configs().front();
479 RegionExportChannelSelector::handle_selection ()
485 state
->config
->clear_channels ();
487 if (raw_button
.get_active ()) {
488 factory
.reset (new RegionExportChannelFactory (_session
, region
, track
, RegionExportChannelFactory::Raw
));
489 } else if (fades_button
.get_active ()) {
490 factory
.reset (new RegionExportChannelFactory (_session
, region
, track
, RegionExportChannelFactory::Fades
));
491 } else if (processed_button
.get_active ()) {
492 factory
.reset (new RegionExportChannelFactory(_session
, region
, track
, RegionExportChannelFactory::Processed
));
494 CriticalSelectionChanged ();
498 for (size_t chan
= 0; chan
< region_chans
; ++chan
) {
499 state
->config
->register_channel (factory
->create (chan
));
502 CriticalSelectionChanged ();