use filechooser widget in export dialog, selected files set format combos, hide progr...
[ardour.git] / gtk2_ardour / export_dialog.cc
1 /*
2     Copyright (C) 1999-2005 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18
19 */
20
21 #include <unistd.h>
22 #include <utility>
23 #include <sys/stat.h>
24 #include <fstream>
25
26 #include <samplerate.h>
27
28 #include <pbd/convert.h>
29 #include <pbd/xml++.h>
30
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/window_title.h>
33
34 #include <ardour/export.h>
35 #include <ardour/session_directory.h>
36 #include <ardour/sndfile_helpers.h>
37 #include <ardour/audio_track.h>
38 #include <ardour/audioregion.h>
39 #include <ardour/audioengine.h>
40 #include <ardour/audiofilesource.h>
41 #include <ardour/gdither.h>
42 #include <ardour/utils.h>
43
44 #include "export_dialog.h"
45 #include "ardour_ui.h"
46 #include "public_editor.h"
47 #include "keyboard.h"
48
49 #include "i18n.h"
50
51 #define FRAME_NAME "BaseFrame"
52
53 using namespace std;
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace sigc;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59
60 using PBD::internationalize;
61
62 static const gchar *sample_rates[] = {
63         N_("22.05kHz"),
64         N_("44.1kHz"),
65         N_("48kHz"),
66         N_("88.2kHz"),
67         N_("96kHz"),
68         N_("192kHz"),
69         0
70 };
71
72 static const gchar *src_quality[] = {
73         N_("best"),
74         N_("fastest"),
75         N_("linear"),
76         N_("better"),
77         N_("intermediate"),
78         0
79 };
80
81 static const gchar *dither_types[] = {
82         N_("None"),
83         N_("Rectangular"),
84         N_("Shaped Noise"),
85         N_("Triangular"),
86         0
87 };
88
89 static const gchar* channel_strings[] = {
90         N_("Stereo"), 
91         N_("Mono"), 
92         0
93 };
94
95 static const gchar* cue_file_types[] = {
96         N_("None"), 
97         N_("CUE"),
98         N_("TOC"),
99         0
100 };
101
102 ExportDialog::ExportDialog(PublicEditor& e)
103         : ArdourDialog ("export dialog"),
104           editor (e),
105           format_table (9, 2),
106           format_frame (_("Format")),
107           cue_file_label (_("CD Marker File Type"), 1.0, 0.5),
108           channel_count_label (_("Channels"), 1.0, 0.5),
109           header_format_label (_("File Type"), 1.0, 0.5),
110           bitdepth_format_label (_("Sample Format"), 1.0, 0.5),
111           endian_format_label (_("Sample Endianness"), 1.0, 0.5),
112           sample_rate_label (_("Sample Rate"), 1.0, 0.5),
113           src_quality_label (_("Conversion Quality"), 1.0, 0.5),
114           dither_type_label (_("Dither Type"), 1.0, 0.5),
115           cuefile_only_checkbox (_("Export CD Marker File Only")),
116           file_chooser (FILE_CHOOSER_ACTION_SAVE),
117           track_selector_button (_("Specific tracks ..."))
118 {
119         guint32 n;
120         guint32 len;
121         guint32 maxlen;
122
123         session = 0;
124         track_and_master_selection_allowed = true;
125         channel_count_selection_allowed = true;
126         export_cd_markers_allowed = true;
127         set_resizable (false);  
128
129         WindowTitle title(Glib::get_application_name());
130         title += _("Export");
131         
132         set_title (title.get_string());
133         set_wmclass (X_("ardour_export"), "Ardour");
134         set_name ("ExportWindow");
135         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
136
137         spec.running = false;
138
139         master_list = ListStore::create (exp_cols);
140         master_selector.set_model (master_list);
141
142         master_selector.set_name ("ExportTrackSelector");
143         master_selector.set_size_request (-1, 100);
144         master_selector.append_column(_("Output"), exp_cols.output);
145         master_selector.append_column_editable(_("Left"), exp_cols.left);
146         master_selector.append_column_editable(_("Right"), exp_cols.right);
147         master_selector.get_column(0)->set_min_width(100);
148         
149         master_selector.get_column(1)->set_min_width(40);
150         master_selector.get_column(1)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
151         master_selector.get_column(2)->set_min_width(40);
152         master_selector.get_column(2)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
153         master_selector.get_selection()->set_mode (Gtk::SELECTION_NONE);
154
155         track_list = ListStore::create (exp_cols);
156         track_selector.set_model (track_list);
157
158         track_selector.set_name ("ExportTrackSelector");
159         track_selector.set_size_request (-1, 130);
160         track_selector.append_column(_("Output"), exp_cols.output);
161         track_selector.append_column_editable(_("Left"), exp_cols.left);
162         track_selector.append_column_editable(_("Right"), exp_cols.right);
163
164         track_selector.get_column(0)->set_min_width(100);
165         track_selector.get_column(1)->set_min_width(40);
166         track_selector.get_column(1)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
167         track_selector.get_column(2)->set_min_width(40);
168         track_selector.get_column(2)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
169         track_selector.get_selection()->set_mode (Gtk::SELECTION_NONE);
170
171         progress_bar.set_name ("ExportProgress");
172
173         format_frame.add (format_table);
174         format_frame.set_name (FRAME_NAME);
175
176         track_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
177         master_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
178
179         get_vbox()->pack_start (file_frame, PACK_EXPAND_WIDGET);
180
181         hpacker.set_spacing (5);
182         hpacker.set_border_width (5);
183         hpacker.pack_start (format_frame, PACK_SHRINK );
184
185         master_scroll.add (master_selector);
186         track_scroll.add (track_selector);
187
188         master_scroll.set_size_request (220, 100);
189         track_scroll.set_size_request (220, 100);
190                 
191         /* we may hide some of these later */
192         track_vpacker.pack_start (master_scroll);
193         track_vpacker.pack_start (track_scroll);
194         track_vpacker.pack_start (track_selector_button, Gtk::PACK_EXPAND_PADDING);
195
196         hpacker.pack_start (track_vpacker);
197
198         get_vbox()->pack_start (hpacker, PACK_SHRINK);
199         
200         track_selector_button.set_name ("EditorGTKButton");
201         track_selector_button.signal_clicked().connect (mem_fun(*this, &ExportDialog::track_selector_button_click));
202
203         Gtk::FileFilter filter_wav;
204         filter_wav.set_name("Wav files");
205         filter_wav.add_mime_type("audio/wav");
206         file_chooser.add_filter(filter_wav);
207         
208         Gtk::FileFilter filter_aiff;
209         filter_aiff.set_name("Aiff files");
210         filter_aiff.add_mime_type("audio/aiff");
211         filter_aiff.add_pattern("*.aif");
212         filter_aiff.add_pattern("*.aiff");
213         file_chooser.add_filter(filter_aiff);
214         
215         Gtk::FileFilter filter_any;
216         filter_any.set_name("All files");
217         filter_any.add_pattern("*");
218         file_chooser.add_filter(filter_any);
219         file_chooser.set_no_show_all();
220
221         get_vbox()->pack_start (progress_bar, false, false, 5);
222         progress_bar.set_no_show_all();
223         progress_bar.hide();
224
225         file_hbox.set_spacing (5);
226         file_hbox.set_border_width (5);
227         file_hbox.pack_start (file_chooser, PACK_EXPAND_WIDGET);
228
229         file_frame.add (file_hbox);
230         file_frame.set_border_width (5);
231         file_frame.set_name (FRAME_NAME);
232
233         /* pop_strings needs to be created on the stack because set_popdown_strings()
234            takes a reference. 
235         */
236
237         vector<string> pop_strings = I18N(sample_rates);
238         Gtkmm2ext::set_popdown_strings (sample_rate_combo, pop_strings);
239         sample_rate_combo.set_active_text (pop_strings.front());
240         pop_strings = I18N(src_quality);
241         Gtkmm2ext::set_popdown_strings (src_quality_combo, pop_strings);
242         src_quality_combo.set_active_text (pop_strings.front());
243         pop_strings = I18N(dither_types);
244         Gtkmm2ext::set_popdown_strings (dither_type_combo, pop_strings);
245         dither_type_combo.set_active_text (pop_strings.front());
246         pop_strings = I18N(channel_strings);
247         Gtkmm2ext::set_popdown_strings (channel_count_combo, pop_strings);
248         channel_count_combo.set_active_text (pop_strings.front());
249         pop_strings = I18N((const char **) sndfile_header_formats_strings);
250         Gtkmm2ext::set_popdown_strings (header_format_combo, pop_strings);
251         header_format_combo.set_active_text (pop_strings.front());
252         pop_strings = I18N((const char **) sndfile_bitdepth_formats_strings);
253         Gtkmm2ext::set_popdown_strings (bitdepth_format_combo, pop_strings);
254         bitdepth_format_combo.set_active_text (pop_strings.front());
255         pop_strings = I18N((const char **) sndfile_endian_formats_strings);
256         Gtkmm2ext::set_popdown_strings (endian_format_combo, pop_strings);
257         endian_format_combo.set_active_text (pop_strings.front());
258         pop_strings = I18N(cue_file_types);
259         Gtkmm2ext::set_popdown_strings (cue_file_combo, pop_strings);
260         cue_file_combo.set_active_text (pop_strings.front());
261
262         /* this will re-sensitized as soon as a non RIFF/WAV
263            header format is chosen.
264         */
265
266         endian_format_combo.set_sensitive (false);
267
268         /* determine longest strings at runtime */
269
270         maxlen = 0;
271         const char *longest = X_("gl"); /* translators: one ascender, one descender */
272         string longest_str;
273
274         for (n = 0; n < SNDFILE_HEADER_FORMATS; ++n) {
275                 if ((len = strlen (sndfile_header_formats_strings[n])) > maxlen) {
276                         maxlen = len;
277                         longest = sndfile_header_formats_strings[n];
278                 }
279         }
280
281         for (n = 0; n < SNDFILE_BITDEPTH_FORMATS; ++n) {
282                 if ((len = strlen (sndfile_bitdepth_formats_strings[n])) > maxlen) {
283                         maxlen = len;
284                         longest = sndfile_bitdepth_formats_strings[n];
285                 }
286         }
287
288         for (n = 0; n < SNDFILE_ENDIAN_FORMATS; ++n) {
289                 if ((len = strlen (sndfile_endian_formats_strings[n])) > maxlen) {
290                         maxlen = len;
291                         longest = sndfile_endian_formats_strings[n];
292                 }
293         }
294
295         longest_str = longest;
296
297         /* force ascender + descender */
298
299         longest_str[0] = 'g';
300         longest_str[1] = 'l';
301
302         //Gtkmm2ext::set_size_request_to_display_given_text (header_format_combo, longest_str.c_str(), 5+FUDGE, 5);
303
304         // TRANSLATORS: "slereg" is "stereo" with ascender and descender substituted
305         //Gtkmm2ext::set_size_request_to_display_given_text (channel_count_combo, _("slereg"), 5+FUDGE, 5);
306
307 /*      header_format_combo.set_focus_on_click (true);
308         bitdepth_format_combo.set_focus_on_click (true);
309         endian_format_combo.set_focus_on_click (true);
310         channel_count_combo.set_focus_on_click (true);
311         src_quality_combo.set_focus_on_click (true);
312         dither_type_combo.set_focus_on_click (true);
313         sample_rate_combo.set_focus_on_click (true);
314         cue_file_combo.set_focus_on_click (true);
315 */
316         dither_type_label.set_name ("ExportFormatLabel");
317         sample_rate_label.set_name ("ExportFormatLabel");
318         src_quality_label.set_name ("ExportFormatLabel");
319         channel_count_label.set_name ("ExportFormatLabel");
320         header_format_label.set_name ("ExportFormatLabel");
321         bitdepth_format_label.set_name ("ExportFormatLabel");
322         endian_format_label.set_name ("ExportFormatLabel");
323         cue_file_label.set_name ("ExportFormatLabel");
324
325         header_format_combo.set_name ("ExportFormatDisplay");
326         bitdepth_format_combo.set_name ("ExportFormatDisplay");
327         endian_format_combo.set_name ("ExportFormatDisplay");
328         channel_count_combo.set_name ("ExportFormatDisplay");
329         dither_type_combo.set_name ("ExportFormatDisplay");
330         src_quality_combo.set_name ("ExportFormatDisplay");
331         sample_rate_combo.set_name ("ExportFormatDisplay");
332         cue_file_combo.set_name ("ExportFormatDisplay");
333
334         cuefile_only_checkbox.set_name ("ExportCheckbox");
335
336         format_table.set_homogeneous (true);
337         format_table.set_border_width (5);
338         format_table.set_col_spacings (5);
339         format_table.set_row_spacings (5);
340
341         format_table.attach (channel_count_label, 0, 1, 0, 1, FILL, FILL);
342         format_table.attach (channel_count_combo, 1, 2, 0, 1, FILL, FILL);
343         
344         format_table.attach (header_format_label, 0, 1, 1, 2, FILL, FILL);
345         format_table.attach (header_format_combo, 1, 2, 1, 2, FILL, FILL);
346
347         format_table.attach (bitdepth_format_label, 0, 1, 2, 3, FILL, FILL);
348         format_table.attach (bitdepth_format_combo, 1, 2, 2, 3, FILL, FILL);
349
350         format_table.attach (endian_format_label, 0, 1, 3, 4, FILL, FILL);
351         format_table.attach (endian_format_combo, 1, 2, 3, 4, FILL, FILL);
352
353         format_table.attach (sample_rate_label, 0, 1, 4, 5, FILL, FILL);
354         format_table.attach (sample_rate_combo, 1, 2, 4, 5, FILL, FILL);
355
356         format_table.attach (src_quality_label, 0, 1, 5, 6, FILL, FILL);
357         format_table.attach (src_quality_combo, 1, 2, 5, 6, FILL, FILL);
358
359         format_table.attach (dither_type_label, 0, 1, 6, 7, FILL, FILL);
360         format_table.attach (dither_type_combo, 1, 2, 6, 7, FILL, FILL);
361
362         format_table.attach (cue_file_label, 0, 1, 7, 8, FILL, FILL);
363         format_table.attach (cue_file_combo, 1, 2, 7, 8, FILL, FILL);
364         format_table.attach (cuefile_only_checkbox, 0, 2, 8, 9, FILL, FILL);
365
366         signal_delete_event().connect (mem_fun(*this, &ExportDialog::window_closed));
367
368         cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
369         cancel_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::end_dialog));
370         ok_button = add_button (_("Export"), RESPONSE_ACCEPT);
371         ok_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::do_export));
372         channel_count_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::channels_chosen));
373         bitdepth_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::bitdepth_chosen));
374         header_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::header_chosen));
375         sample_rate_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::sample_rate_chosen));
376         cue_file_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::cue_file_type_chosen));
377
378         file_chooser.signal_update_preview().connect (mem_fun(*this, &ExportDialog::file_chooser_selection_changed));
379
380 }
381
382 ExportDialog::~ExportDialog()
383 {
384 }
385
386 void
387 ExportDialog::do_not_allow_track_and_master_selection()
388 {
389         track_and_master_selection_allowed = false;
390 }
391
392 void
393 ExportDialog::do_not_allow_channel_count_selection()
394 {
395         channel_count_selection_allowed = false;
396 }
397
398 void
399 ExportDialog::do_not_allow_export_cd_markers()
400 {
401         export_cd_markers_allowed = false;
402 }
403
404 void
405 ExportDialog::connect_to_session (Session *s)
406 {
407         session = s;
408         session->GoingAway.connect (mem_fun(*this, &Window::hide_all));
409
410         switch (session->frame_rate()) {
411         case 22050:
412                 sample_rate_combo.set_active_text (_("22.05kHz"));
413                 break;
414         case 44100:
415                 sample_rate_combo.set_active_text (_("44.1kHz"));
416                 break;
417         case 48000:
418                 sample_rate_combo.set_active_text (_("48kHz"));
419                 break;
420         case 88200:
421                 sample_rate_combo.set_active_text (_("88.2kHz"));
422                 break;
423         case 96000:
424                 sample_rate_combo.set_active_text (_("96kHz"));
425                 break;
426         case 192000:
427                 sample_rate_combo.set_active_text (_("192kHz"));
428                 break;
429         default:
430                 sample_rate_combo.set_active_text (_("44.1kHz"));
431                 break;
432         }
433
434         src_quality_combo.set_sensitive (false);
435
436         set_state();
437 }
438
439 void
440 ExportDialog::set_state()
441 {
442         XMLNode* node = session->instant_xml(X_("ExportDialog"));
443         XMLProperty* prop;
444         bool fc_location_requested = false;
445         if (node) {
446
447                 if ((prop = node->property (X_("sample_rate"))) != 0) {
448                         sample_rate_combo.set_active_text(prop->value());
449                 }
450                 if ((prop = node->property (X_("src_quality"))) != 0) {
451                         src_quality_combo.set_active_text(prop->value());
452                 }
453                 if ((prop = node->property (X_("dither_type"))) != 0) {
454                         dither_type_combo.set_active_text(prop->value());
455                 }
456                 if ((prop = node->property (X_("channel_count"))) != 0) {
457                         channel_count_combo.set_active_text(prop->value());
458                 }
459                 if ((prop = node->property (X_("header_format"))) != 0) {
460                         header_format_combo.set_active_text(prop->value());
461                 }
462                 if ((prop = node->property (X_("bitdepth_format"))) != 0) {
463                         bitdepth_format_combo.set_active_text(prop->value());
464                 }
465                 if ((prop = node->property (X_("endian_format"))) != 0) {
466                         endian_format_combo.set_active_text(prop->value());
467                 }
468                 if ((prop = node->property (X_("filename"))) != 0) {
469                         file_chooser.set_filename(prop->value());
470                         fc_location_requested = true;
471                         file_chooser.set_current_folder(Glib::path_get_basename(prop->value()));
472                 }
473                   
474                 if ((prop = node->property (X_("cue_file_type"))) != 0) {
475                         cue_file_combo.set_active_text(prop->value());
476                 }
477         }
478
479         if (!fc_location_requested) {
480
481                 /*
482                   If the filename hasn't been set before, use the
483                   current session's export directory as a default
484                   location for the export.  
485                 */
486
487                 file_chooser.set_current_folder (session->session_directory().export_path().to_string());
488                 file_chooser.set_current_name (_("export.wav"));
489         }
490
491         header_chosen ();
492         bitdepth_chosen();
493         channels_chosen();
494         sample_rate_chosen();
495
496         if (session->master_out()) {
497                 track_scroll.hide ();
498         } else {
499                 master_scroll.hide ();
500                 track_selector_button.hide ();
501         }
502
503         if (!node) {
504                 return;
505         }
506
507         if (session->master_out()) {
508                 XMLNode* master = find_named_node(*node, (X_("Master")));
509                 int nchns;
510
511                 if (!master) {
512                         
513                         /* default is to use all */
514                         if (channel_count_combo.get_active_text() == _("Mono")) {
515                                 nchns = 1;
516                         } else {
517                                 nchns = 2;
518                         }
519
520                         TreeModel::Children rows = master_selector.get_model()->children();
521                         for (uint32_t r = 0; r < session->master_out()->n_outputs().n_audio(); ++r) {
522                                 if (nchns == 2) {
523                                         if (r % 2) {
524                                                 rows[r][exp_cols.right] = true;
525                                         } else {
526                                                 rows[r][exp_cols.left] = true;
527                                         }
528                                 } else {
529                                         rows[r][exp_cols.left] = true;
530                                 }
531                         }
532
533                 } else {
534                         /* XXX use XML state */
535                 }
536         }
537
538         XMLNode* tracks = find_named_node(*node, (X_("Tracks")));
539         if (!tracks) {
540                 return;
541         }
542         
543         XMLNodeList track_list = tracks->children(X_("Track"));
544         TreeModel::Children rows = track_selector.get_model()->children();
545         TreeModel::Children::iterator ri = rows.begin();
546         TreeModel::Row row;
547
548         for (XMLNodeIterator it = track_list.begin(); it != track_list.end(); ++it, ++ri) {
549                 if (ri == rows.end()){
550                         break;
551                 }
552
553                 XMLNode* track = *it;
554                 row = *ri;
555
556                 if ((prop = track->property(X_("channel1"))) != 0) {
557                         if (prop->value() == X_("on")) {
558                                 row[exp_cols.left] = true;
559                         } else {
560                                 row[exp_cols.left] = false;
561                         }
562                 }
563
564                 if ((prop = track->property(X_("channel2"))) != 0) {
565                         if (prop->value() == X_("on")) {
566                                 row[exp_cols.right] = true;
567                         } else {
568                                 row[exp_cols.right] = false;
569                         }
570                 }
571         }
572 }
573
574 void
575 ExportDialog::save_state()
576 {
577         if (!session) {
578                 return;
579         }
580
581         XMLNode* node = new XMLNode(X_("ExportDialog"));
582
583         node->add_property(X_("sample_rate"), sample_rate_combo.get_active_text());
584         node->add_property(X_("src_quality"), src_quality_combo.get_active_text());
585         node->add_property(X_("dither_type"), dither_type_combo.get_active_text());
586         node->add_property(X_("channel_count"), channel_count_combo.get_active_text());
587         node->add_property(X_("header_format"), header_format_combo.get_active_text());
588         node->add_property(X_("bitdepth_format"), bitdepth_format_combo.get_active_text());
589         node->add_property(X_("endian_format"), endian_format_combo.get_active_text());
590         node->add_property(X_("filename"), file_chooser.get_filename());
591         node->add_property(X_("cue_file_type"), cue_file_combo.get_active_text());
592
593         XMLNode* tracks = new XMLNode(X_("Tracks"));
594
595         TreeModel::Children rows = track_selector.get_model()->children();
596         TreeModel::Row row;
597         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
598                 XMLNode* track = new XMLNode(X_("Track"));
599
600                 row = *ri;
601                 track->add_property(X_("channel1"), row[exp_cols.left] ? X_("on") : X_("off"));
602                 track->add_property(X_("channel2"), row[exp_cols.right] ? X_("on") : X_("off"));
603
604                 tracks->add_child_nocopy(*track);
605         }
606         node->add_child_nocopy(*tracks);
607         
608         session->add_instant_xml(*node);
609 }
610
611 void
612 ExportDialog::set_range (nframes_t start, nframes_t end)
613 {
614         spec.start_frame = start;
615         spec.end_frame = end;
616 }
617
618 gint
619 ExportDialog::progress_timeout ()
620 {
621         progress_bar.set_fraction (spec.progress);
622         return TRUE;
623 }
624
625 void
626 frames_to_cd_frames_string (char* buf, nframes_t when, nframes_t fr)
627 {
628
629   long unsigned int remainder;
630   int mins, secs, frames;
631
632         mins = when / (60 * fr);
633         remainder = when - (mins * 60 * fr);
634         secs = remainder / fr;
635         remainder -= secs * fr;
636         frames = remainder / (fr / 75);
637         sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
638
639 }
640
641 struct LocationSortByStart {
642     bool operator() (Location *a, Location *b) {
643             return a->start() < b->start();
644     }
645 };
646
647 void
648 ExportDialog::export_toc_file (Locations::LocationList& locations, const string& path)
649 {
650         if(!export_cd_markers_allowed){
651                 return;
652         }
653         
654     string filepath = path + ".toc";
655         ofstream out (filepath.c_str());
656         long unsigned int last_end_time = spec.start_frame, last_start_time = spec.start_frame;
657         int numtracks = 0;
658         gchar buf[18];
659
660         if (!out) {
661                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD toc file"), filepath) << endmsg;
662                 return;
663         }
664         out << "CD_DA" << endl;
665         out << "CD_TEXT {" << endl << "  LANGUAGE_MAP {" << endl << "    0 : EN" << endl << "  }" << endl;
666         out << "  LANGUAGE 0 {" << endl << "    TITLE \"" << session->name() << "\"" << endl << "  }" << endl << "}" << endl;
667
668         Locations::LocationList::iterator i;
669         Locations::LocationList temp;
670
671         for (i = locations.begin(); i != locations.end(); ++i) {
672           if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
673             temp.push_back (*i);
674             if (!(*i)->is_mark()) {
675               numtracks ++;
676             }
677           }
678         }
679
680         if (numtracks == 0 ) {
681                     /* the user supplied no track markers.
682                        we now treat the session as one track.*/
683
684                     out << endl << "TRACK AUDIO" << endl;
685                    
686                     out << "COPY" << endl;
687
688                     out << "NO PRE_EMPHASIS" << endl;
689    
690                     /* XXX add session properties for catalog etc.
691                        (so far only the session name is used) */
692                     
693                     out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE \"" << session->name() << "\"" << endl;
694                     out << "  }" << endl << "}" << endl;
695
696                     out << "FILE \"" << path << "\" ";
697                     out << "00:00:00 " ;
698                     frames_to_cd_frames_string (buf, spec.end_frame - spec.start_frame, session->frame_rate());
699                     out << buf << endl;
700                     out << "START 00:00:00" << endl;
701
702                     last_start_time = spec.start_frame;
703                     last_end_time = spec.end_frame;
704         } 
705
706         if (temp.size()) {
707                 LocationSortByStart cmp;
708                 temp.sort (cmp);
709
710                 for (i = temp.begin(); i != temp.end(); ++i) {
711         
712                       if (!(*i)->is_mark()) {
713                         /*this is a track */
714                         out << endl << "TRACK AUDIO" << endl;
715
716                         if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
717                           out << "NO ";
718                         }
719                         out << "COPY" << endl;
720
721                         if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
722                           out << "PRE_EMPHASIS" << endl;
723                         } else {
724                           out << "NO PRE_EMPHASIS" << endl;
725                         }
726
727                         if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
728                           out << "ISRC \"" << (*i)->cd_info["isrc"] << "\"" << endl;
729                         }
730
731                         out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE \"" << (*i)->name() << "\"" << endl;
732                         if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
733                           out << "     PERFORMER \"" << (*i)->cd_info["performer"]  << "\"" << endl;
734                         }
735                         if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
736                           out  << "     COMPOSER \"" << (*i)->cd_info["string_composer"] << "\"" << endl;
737                         }
738
739                         if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end()) {                          
740                           out  << "     ISRC \"";
741                           out << (*i)->cd_info["isrc"].substr(0,2) << "-";
742                           out << (*i)->cd_info["isrc"].substr(2,3) << "-";
743                           out << (*i)->cd_info["isrc"].substr(5,2) << "-";
744                           out << (*i)->cd_info["isrc"].substr(7,5) << "\"" << endl;
745                         }
746
747                         out << "  }" << endl << "}" << endl;
748
749                         frames_to_cd_frames_string (buf, last_end_time - spec.start_frame, session->frame_rate());
750                         out << "FILE \"" << path << "\" " << buf;
751
752                         frames_to_cd_frames_string (buf, (*i)->end() - last_end_time, session->frame_rate());
753                         out << buf << endl;
754
755                         frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
756                         out << "START" << buf << endl;
757                         
758                         last_start_time = (*i)->start();
759                         last_end_time = (*i)->end();
760                  
761
762                       } else  if ((*i)->start() < last_end_time) {
763                         /* this is an index within a track */
764                         
765                         frames_to_cd_frames_string (buf, (*i)->start() - last_start_time, session->frame_rate());
766                         out << "INDEX" << buf << endl;
767                       }
768                 }
769         }
770         
771 }
772
773 void
774 ExportDialog::export_cue_file (Locations::LocationList& locations, const string& path)
775 {
776         if(!export_cd_markers_allowed){
777                 return;
778         }
779         
780     string filepath = path + ".cue";
781         ofstream out (filepath.c_str());
782         gchar buf[18];
783         long unsigned int last_track_end = spec.start_frame;
784         int numtracks = 0, tracknum = 0, indexnum = 0;
785
786         if (!out) {
787                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD cue file"), filepath) << endmsg;
788                 return;
789         }
790
791         Locations::LocationList::iterator i;
792         Locations::LocationList temp;
793
794         for (i = locations.begin(); i != locations.end(); ++i) {
795                 if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
796                         temp.push_back (*i);
797                         if (!(*i)->is_mark()) {
798                                 numtracks++;
799                         }
800                 }
801         }
802         
803         out << "REM Cue file generated by Ardour" << endl;
804         out << "TITLE \"" << session->name() << "\"" << endl;
805
806         if ((header_format_combo.get_active_text() == N_("WAV"))) {
807                   out << "FILE " << path  << " WAVE" << endl;
808         } else {
809                   out << "FILE " << path  << ' ' << (header_format_combo.get_active_text()) << endl;
810         }
811
812         if (numtracks == 0) {
813                     /* the user has supplied no track markers.
814                        the entire export is treated as one track. 
815                     */
816
817                   numtracks++;
818                   tracknum++;
819                   indexnum = 0;
820                   out << endl << "TRACK " << tracknum << " AUDIO" << endl;
821                   out << "FLAGS " ;
822                   
823                   out << "DCP " << endl;                   
824                   
825                   /* use the session name*/
826                   
827                   if (session->name() != "") {
828                     out << "TITLE \"" << session->name() << "\"" << endl;
829                   }           
830                   
831                   /* no pregap in this case */
832
833                   out << "INDEX 00 00:00:00" << endl;
834                   indexnum++;
835                   out << "INDEX 01 00:00:00" << endl;
836                   indexnum++;
837                   last_track_end = spec.end_frame;
838         }
839
840         if (temp.size()) {
841                 LocationSortByStart cmp;
842                 temp.sort (cmp);
843
844                 for ( i = temp.begin(); i != temp.end(); ++i) {
845
846                     if (!(*i)->is_mark() && ((*i)->start() >= last_track_end)) {
847                       /* this is a track and it doesn't start inside another one*/
848                       
849                       tracknum++;
850                       indexnum = 0;
851                       out << endl << "TRACK " << tracknum << " AUDIO" << endl;
852                       out << "FLAGS " ;
853                       
854                       if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
855                         out << "SCMS ";
856                       } else {
857                         out << "DCP ";
858                       }
859                       
860                       if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
861                         out << "PRE";
862                       }
863                       out << endl;
864                       
865                       if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
866                         out << "ISRC " << (*i)->cd_info["isrc"] << endl;
867                         
868                       }
869                       if ((*i)->name() != "") {
870                         out << "TITLE \"" << (*i)->name() << "\"" << endl;
871                       }       
872                       
873                       if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
874                         out << "PERFORMER \"" <<  (*i)->cd_info["performer"] << "\"" << endl;
875                       }
876                       
877                       if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
878                         out << "SONGWRITER \"" << (*i)->cd_info["string_composer"]  << "\"" << endl;
879                       }
880                         snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
881                         out << buf;
882                         frames_to_cd_frames_string (buf, last_track_end - spec.start_frame, session->frame_rate());
883                         out << buf << endl;
884                         indexnum++;
885                         last_track_end = (*i)->end();
886                     } 
887                     if ((tracknum > 0) && ((*i)->start() < last_track_end)) {
888                       /*this is an index and it lies within a track*/
889                       snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
890                       out << buf;
891                       frames_to_cd_frames_string (buf,(*i)->start() - spec.start_frame, session->frame_rate());
892                       out << buf << endl;
893                       indexnum++;
894                     }
895                 }
896         }
897         
898 }
899         
900 void
901 ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_type)
902 {
903         if (cuefile_type == _("TOC")) {
904                 session->locations()->apply (*this, &ExportDialog::export_toc_file, path);      
905         } else {
906                 session->locations()->apply (*this, &ExportDialog::export_cue_file, path);
907         }
908 }
909
910
911 void
912 ExportDialog::do_export ()
913 {
914         string filepath = file_chooser.get_filename();
915         
916         if(!is_filepath_valid(filepath)){
917                 return;
918         }
919
920         if (export_cd_markers_allowed) {
921                 if (cue_file_combo.get_active_text () != _("None")) {
922                         do_export_cd_markers (file_chooser.get_filename(), cue_file_combo.get_active_text ());
923                 }
924
925                 if (cuefile_only_checkbox.get_active()) {
926                         end_dialog ();
927                         return;
928                 }
929         }
930
931         ok_button->set_sensitive(false);
932         save_state();
933
934         set_modal (true);
935         
936         // read user input into spec
937         initSpec(filepath);
938         
939         progress_bar.show();
940         progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportDialog::progress_timeout), 100);
941         cancel_label.set_text (_("Stop Export"));
942
943         export_audio_data();
944         
945         progress_connection.disconnect ();
946         session->engine().freewheel (false);
947         progress_bar.hide();
948         end_dialog ();
949 }
950         
951 void
952 ExportDialog::end_dialog ()
953 {
954         if (spec.running) {
955                 spec.stop = true;
956
957                 while (spec.running) {
958                         if (gtk_events_pending()) {
959                                 gtk_main_iteration ();
960                         } else {
961                                 usleep (10000);
962                         }
963                 }
964         }
965
966         hide ();
967
968         session->finalize_audio_export ();
969
970         set_modal (false);
971         ok_button->set_sensitive(true);
972 }
973
974 void
975 ExportDialog::start_export ()
976 {
977         if (session == 0) {
978                 return;
979         }
980
981         /* If the filename hasn't been set before, use the
982            current session's export directory as a default
983            location for the export.  
984         */
985         
986         if (file_entry.get_text().length() == 0) {
987
988                 sys::path export_file_path = session->session_directory().export_path();
989
990                 if (!wants_dir()) {
991                         export_file_path /= "export.wav";
992                 }
993                 
994                 file_entry.set_text (export_file_path.to_string());
995         }
996
997         progress_bar.set_fraction (0);
998         progress_bar.hide();
999         progress_bar.set_no_show_all();
1000         cancel_label.set_text (_("Cancel"));
1001
1002         show_all();
1003
1004         if (track_and_master_selection_allowed) {
1005                 track_vpacker.show();
1006         } else {
1007                 track_vpacker.hide();
1008         }
1009
1010         file_chooser.show();
1011
1012         if (channel_count_selection_allowed) {
1013                 channel_count_combo.show();
1014                 channel_count_label.show();
1015         } else {
1016                 channel_count_combo.hide();
1017                 channel_count_label.hide();
1018         }
1019
1020         if (export_cd_markers_allowed) {
1021                 cue_file_label.show();
1022                 cue_file_combo.show();
1023                 cuefile_only_checkbox.show();
1024         } else {
1025                 cue_file_label.hide();
1026                 cue_file_combo.hide();
1027                 cuefile_only_checkbox.hide();
1028         }
1029
1030         if (session->master_out()) {
1031                 track_scroll.hide ();
1032         } else {
1033                 master_scroll.hide ();
1034                 track_selector_button.hide ();
1035         }
1036
1037         track_and_master_selection_allowed = true;
1038         channel_count_selection_allowed =  true;
1039         export_cd_markers_allowed = true;
1040 }
1041
1042 void
1043 ExportDialog::header_chosen ()
1044 {
1045         if (sndfile_header_format_from_string (header_format_combo.get_active_text ()) == SF_FORMAT_WAV) {
1046                 endian_format_combo.set_active_text (N_("Little-endian (Intel)"));
1047                 endian_format_combo.set_sensitive (false);
1048         } else {
1049                 endian_format_combo.set_sensitive (true);
1050                 endian_format_combo.set_active_text (N_("Big-endian (Mac)"));
1051         }
1052 }
1053
1054 void
1055 ExportDialog::bitdepth_chosen ()
1056 {
1057         int format = sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());    
1058         switch (format) {
1059         case SF_FORMAT_PCM_24:
1060         case SF_FORMAT_PCM_32:
1061         case SF_FORMAT_FLOAT:
1062                 dither_type_combo.set_sensitive (false);
1063                 break;
1064
1065         default:
1066                 dither_type_combo.set_sensitive (true);
1067                 break;
1068         }
1069 }
1070
1071 void
1072 ExportDialog::cue_file_type_chosen ()
1073 {
1074         if (cue_file_combo.get_active_text () != "None") {
1075                 cuefile_only_checkbox.set_sensitive (true);
1076         } else {
1077                 cuefile_only_checkbox.set_active (false);
1078                 cuefile_only_checkbox.set_sensitive (false);
1079         }
1080 }
1081
1082 void
1083 ExportDialog::file_chooser_selection_changed ()
1084 {
1085
1086   /*
1087     if the user selects an existing file from the 'browse for other folders' tab,
1088     change the format settings to match the file.
1089   */
1090         if (file_chooser.get_filename().length() == 0) {
1091                 return;
1092         }
1093         if (Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_IS_DIR)){
1094                 file_chooser.set_current_name (_(""));
1095                 return;
1096         }
1097         if (!Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_EXISTS)) {
1098                 return;
1099         }
1100
1101         SoundFileInfo finfo;
1102         string error_msg, format_str;
1103         
1104         if (!AudioFileSource::get_soundfile_info (file_chooser.get_preview_filename(), finfo, error_msg)) {
1105                 error << string_compose(_("Export: cannot open file \"%1\"."), error_msg ) << endmsg;
1106                 return;
1107         }
1108
1109         if (finfo.samplerate == 22050) {
1110                 sample_rate_combo.set_active_text (N_("22.05kHz"));
1111         } else if (finfo.samplerate == 44100) {
1112                 sample_rate_combo.set_active_text (N_("44.1kHz"));
1113         } else if (finfo.samplerate == 48000) {
1114                 sample_rate_combo.set_active_text (N_("48kHz"));
1115         } else if (finfo.samplerate == 88200) {
1116                 sample_rate_combo.set_active_text (N_("88.2kHz"));
1117         } else if (finfo.samplerate == 96000) {
1118                 sample_rate_combo.set_active_text (N_("96kHz"));
1119         } else if (finfo.samplerate == 192000) {
1120                 sample_rate_combo.set_active_text (N_("192kHz"));
1121         } 
1122
1123         if (finfo.channels == 1) {
1124                 channel_count_combo.set_active_text(N_("Mono"));
1125         } else {
1126                 channel_count_combo.set_active_text(N_("Stereo"));
1127         }
1128
1129         string::size_type pos;
1130
1131         pos = finfo.format_name.find_first_of (" ");
1132         format_str = finfo.format_name.substr(pos + 1, 255);
1133         pos = format_str.find_first_of (" ");
1134         header_format_combo.set_active_text(format_str.substr(0, pos));
1135
1136         format_str = finfo.format_name;
1137         pos = format_str.find_first_of (",");
1138         bitdepth_format_combo.set_active_text(format_str.substr(pos + 2, 255));
1139 }
1140
1141 void
1142 ExportDialog::sample_rate_chosen ()
1143 {
1144         string sr_str = sample_rate_combo.get_active_text();
1145         nframes_t rate;
1146
1147         if (sr_str == N_("22.05kHz")) {
1148                 rate = 22050;
1149         } else if (sr_str == _("44.1kHz")) {
1150                 rate = 44100;
1151         } else if (sr_str == _("48kHz")) {
1152                 rate = 48000;
1153         } else if (sr_str == _("88.2kHz")) {
1154                 rate = 88200;
1155         } else if (sr_str == _("96kHz")) {
1156                 rate = 96000;
1157         } else if (sr_str == _("192kHz")) {
1158                 rate = 192000;
1159         } else {
1160                 rate = session->frame_rate();
1161         }
1162                 
1163         if (rate != session->frame_rate()) {
1164                 src_quality_combo.set_sensitive (true);
1165         } else {
1166                 src_quality_combo.set_sensitive (false);
1167         }
1168 }
1169
1170 void
1171 ExportDialog::channels_chosen ()
1172 {
1173         bool mono;
1174
1175         mono = (channel_count_combo.get_active_text() == _("Mono"));
1176
1177         if (mono) {
1178                 track_selector.get_column(2)->set_visible(false);
1179                 track_selector.get_column(1)->set_title(_("Export"));
1180
1181                 if (session->master_out()) {
1182                         master_selector.get_column(2)->set_visible(false);
1183                         master_selector.get_column(1)->set_title(_("Export"));
1184                 }
1185
1186         } else {
1187                 track_selector.get_column(2)->set_visible(true);
1188                 track_selector.get_column(1)->set_title(_("Left"));
1189
1190                 if (session->master_out()) {
1191                         master_selector.get_column(2)->set_visible(true);
1192                         master_selector.get_column(1)->set_title(_("Left"));
1193                 }
1194         }
1195
1196         fill_lists();
1197 }
1198
1199 void
1200 ExportDialog::fill_lists ()
1201 {
1202         track_list->clear();
1203         master_list->clear();
1204         
1205         boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
1206
1207         for (Session::RouteList::iterator ri = routes->begin(); ri != routes->end(); ++ri) {
1208                 
1209                 boost::shared_ptr<Route> route = (*ri);
1210                 
1211                 if (route->is_hidden()) {
1212                         continue;
1213                 }
1214
1215                 for (uint32_t i=0; i < route->n_outputs().n_audio(); ++i) {
1216                         string name;
1217                         if (route->n_outputs().n_audio() == 1) {
1218                                 name = route->name();
1219                         } else {
1220                                 name = string_compose("%1: out-%2", route->name(), i+1);
1221                         }
1222
1223                         if (route == session->master_out()) {
1224                                 TreeModel::iterator iter = master_list->append();
1225                                 TreeModel::Row row = *iter;
1226                                 row[exp_cols.output] = name;
1227                                 row[exp_cols.left] = false;
1228                                 row[exp_cols.right] = false;
1229                                 row[exp_cols.port] = route->output (i);
1230                         } else {
1231                                 TreeModel::iterator iter = track_list->append();
1232                                 TreeModel::Row row = *iter;
1233                                 row[exp_cols.output] = name;
1234                                 row[exp_cols.left] = false;
1235                                 row[exp_cols.right] = false;
1236                                 row[exp_cols.port] = route->output (i);
1237                         }
1238                 }
1239         }
1240 }
1241
1242
1243 bool
1244 ExportDialog::is_filepath_valid(string &filepath)
1245 {
1246         // sanity check file name first
1247
1248         struct stat statbuf;
1249   
1250         if (filepath.empty()) {
1251                 string txt = _("Please enter a valid filename.");
1252                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1253                 msg.run();
1254                 return false;
1255         }
1256         
1257         // check if file exists already and warn
1258
1259         if (stat (filepath.c_str(), &statbuf) == 0) {
1260                 if (S_ISDIR (statbuf.st_mode)) {
1261                         string txt = _("Please specify a complete filename for the audio file.");
1262                         MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1263                         msg.run();
1264                         return false;
1265                 }
1266                 else {
1267                         string txt = _("File ") + filepath + _(" already exists, do you want to overwrite it?");
1268                         MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true);
1269                         if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) {
1270                                 return false;
1271                         }
1272                 }
1273         }
1274         
1275         // directory needs to exist and be writable
1276
1277         string dirpath = Glib::path_get_dirname (filepath);
1278         if (::access (dirpath.c_str(), W_OK) != 0) {
1279                 string txt = _("Cannot write file in: ") + dirpath;
1280                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1281                 msg.run();
1282                 return false;
1283         }
1284         
1285         return true;
1286 }
1287
1288 void
1289 ExportDialog::initSpec(string &filepath)
1290 {
1291         spec.path = filepath;
1292         spec.progress = 0;
1293         spec.running = true;
1294         spec.stop = false;
1295         spec.port_map.clear();
1296         
1297         if (channel_count_combo.get_active_text() == _("Mono")) {
1298                 spec.channels = 1;
1299         } else {
1300                 spec.channels = 2;
1301         }
1302
1303         spec.format = 0;
1304
1305         spec.format |= sndfile_header_format_from_string (header_format_combo.get_active_text ());
1306         
1307         if ((spec.format & SF_FORMAT_WAV) == 0) {
1308                 /* RIFF/WAV specifies endianess */
1309                 spec.format |= sndfile_endian_format_from_string (endian_format_combo.get_active_text ());
1310         }
1311
1312         spec.format |= sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());
1313
1314         string sr_str = sample_rate_combo.get_active_text();
1315         if (sr_str == N_("22.05kHz")) {
1316                 spec.sample_rate = 22050;
1317         } else if (sr_str == _("44.1kHz")) {
1318                 spec.sample_rate = 44100;
1319         } else if (sr_str == _("48kHz")) {
1320                 spec.sample_rate = 48000;
1321         } else if (sr_str == _("88.2kHz")) {
1322                 spec.sample_rate = 88200;
1323         } else if (sr_str == _("96kHz")) {
1324                 spec.sample_rate = 96000;
1325         } else if (sr_str == _("192kHz")) {
1326                 spec.sample_rate = 192000;
1327         } else {
1328                 spec.sample_rate = session->frame_rate();
1329         }
1330         
1331         string src_str = src_quality_combo.get_active_text();
1332         if (src_str == _("fastest")) {
1333                 spec.src_quality = SRC_ZERO_ORDER_HOLD;
1334         } else if (src_str == _("linear")) {
1335                 spec.src_quality = SRC_LINEAR;
1336         } else if (src_str == _("better")) {
1337                 spec.src_quality = SRC_SINC_FASTEST;
1338         } else if (src_str == _("intermediate")) {
1339                 spec.src_quality = SRC_SINC_MEDIUM_QUALITY;
1340         } else {
1341                 spec.src_quality = SRC_SINC_BEST_QUALITY;
1342         }
1343
1344         string dither_str = dither_type_combo.get_active_text();
1345         if (dither_str == _("None")) {
1346                 spec.dither_type = GDitherNone;
1347         } else if (dither_str == _("Rectangular")) {
1348                 spec.dither_type = GDitherRect;
1349         } else if (dither_str == _("Triangular")) {
1350                 spec.dither_type = GDitherTri;
1351         } else {
1352                 spec.dither_type = GDitherShaped;
1353         } 
1354
1355         write_track_and_master_selection_to_spec();
1356 }
1357
1358
1359 void
1360 ExportDialog::write_track_and_master_selection_to_spec()
1361 {
1362         if(!track_and_master_selection_allowed){
1363                 return;
1364         }
1365
1366         uint32_t chan=0;
1367         Port *last_port = 0;
1368                 
1369         TreeModel::Children rows = master_selector.get_model()->children();
1370         TreeModel::Children::iterator ri;
1371         TreeModel::Row row;
1372         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1373                 row = *ri;
1374                 Port* port = row[exp_cols.port];
1375                 
1376                 if (last_port != port) {
1377                         chan = 0;
1378                 }
1379                 
1380                 if (row[exp_cols.left]) {
1381                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1382                 } 
1383                 
1384                 if (spec.channels == 2) {
1385                         if (row[exp_cols.right]) {
1386                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1387                         }
1388                 }
1389         }
1390         
1391         chan = 0;
1392         rows = track_selector.get_model()->children();
1393
1394         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1395                 row = *ri;
1396                 
1397                 Port* port = row[exp_cols.port];
1398                 
1399                 if (last_port != port) {
1400                         chan = 0;
1401                 }
1402                 
1403                 if (row[exp_cols.left]) {
1404                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1405                 } 
1406                 
1407                 if (spec.channels == 2) {
1408                         if (row[exp_cols.right]) {
1409                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1410                         }
1411                         
1412                 }
1413                 
1414                 last_port = port;
1415                 ++chan;
1416         }
1417 }
1418
1419
1420 gint
1421 ExportDialog::window_closed (GdkEventAny *ignored)
1422 {
1423         end_dialog ();
1424         return TRUE;
1425 }
1426
1427 void
1428 ExportDialog::track_selector_button_click ()
1429 {
1430         if (track_scroll.is_visible ()) {
1431                 track_scroll.hide ();
1432         } else {
1433                 track_scroll.show_all ();
1434         }
1435 }