f547bc3e3fead6c646b834ff96f619c897f0882c
[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 #include <pbd/convert.h>
28 #include <pbd/xml++.h>
29
30 #include <gtkmm2ext/utils.h>
31 #include <gtkmm2ext/window_title.h>
32
33 #include <ardour/export.h>
34 #include <ardour/session_directory.h>
35 #include <ardour/sndfile_helpers.h>
36 #include <ardour/audio_track.h>
37 #include <ardour/audioregion.h>
38 #include <ardour/audioengine.h>
39 #include <ardour/audiofilesource.h>
40 #include <ardour/gdither.h>
41 #include <ardour/utils.h>
42 #include <ardour/profile.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
220         get_vbox()->pack_start (progress_bar, false, false, 5);
221
222         file_hbox.set_spacing (5);
223         file_hbox.set_border_width (5);
224         file_hbox.pack_start (file_chooser, PACK_EXPAND_WIDGET);
225
226         file_frame.add (file_hbox);
227         file_frame.set_border_width (5);
228         file_frame.set_name (FRAME_NAME);
229
230         /* pop_strings needs to be created on the stack because set_popdown_strings()
231            takes a reference. 
232         */
233
234         vector<string> pop_strings = I18N(sample_rates);
235         Gtkmm2ext::set_popdown_strings (sample_rate_combo, pop_strings);
236         sample_rate_combo.set_active_text (pop_strings.front());
237         pop_strings = I18N(src_quality);
238         Gtkmm2ext::set_popdown_strings (src_quality_combo, pop_strings);
239         src_quality_combo.set_active_text (pop_strings.front());
240         pop_strings = I18N(dither_types);
241         Gtkmm2ext::set_popdown_strings (dither_type_combo, pop_strings);
242         dither_type_combo.set_active_text (pop_strings.front());
243         pop_strings = I18N(channel_strings);
244         Gtkmm2ext::set_popdown_strings (channel_count_combo, pop_strings);
245         channel_count_combo.set_active_text (pop_strings.front());
246         pop_strings = I18N((const char **) sndfile_header_formats_strings);
247         Gtkmm2ext::set_popdown_strings (header_format_combo, pop_strings);
248         header_format_combo.set_active_text (pop_strings.front());
249         pop_strings = I18N((const char **) sndfile_bitdepth_formats_strings);
250         Gtkmm2ext::set_popdown_strings (bitdepth_format_combo, pop_strings);
251         bitdepth_format_combo.set_active_text (pop_strings.front());
252         pop_strings = I18N((const char **) sndfile_endian_formats_strings);
253         Gtkmm2ext::set_popdown_strings (endian_format_combo, pop_strings);
254         endian_format_combo.set_active_text (pop_strings.front());
255         pop_strings = I18N(cue_file_types);
256         Gtkmm2ext::set_popdown_strings (cue_file_combo, pop_strings);
257         cue_file_combo.set_active_text (pop_strings.front());
258
259         /* this will re-sensitized as soon as a non RIFF/WAV
260            header format is chosen.
261         */
262
263         endian_format_combo.set_sensitive (false);
264
265         /* determine longest strings at runtime */
266
267         maxlen = 0;
268         const char *longest = X_("gl"); /* translators: one ascender, one descender */
269         string longest_str;
270
271         for (n = 0; n < SNDFILE_HEADER_FORMATS; ++n) {
272                 if ((len = strlen (sndfile_header_formats_strings[n])) > maxlen) {
273                         maxlen = len;
274                         longest = sndfile_header_formats_strings[n];
275                 }
276         }
277
278         for (n = 0; n < SNDFILE_BITDEPTH_FORMATS; ++n) {
279                 if ((len = strlen (sndfile_bitdepth_formats_strings[n])) > maxlen) {
280                         maxlen = len;
281                         longest = sndfile_bitdepth_formats_strings[n];
282                 }
283         }
284
285         for (n = 0; n < SNDFILE_ENDIAN_FORMATS; ++n) {
286                 if ((len = strlen (sndfile_endian_formats_strings[n])) > maxlen) {
287                         maxlen = len;
288                         longest = sndfile_endian_formats_strings[n];
289                 }
290         }
291
292         longest_str = longest;
293
294         /* force ascender + descender */
295
296         longest_str[0] = 'g';
297         longest_str[1] = 'l';
298
299         //Gtkmm2ext::set_size_request_to_display_given_text (header_format_combo, longest_str.c_str(), 5+FUDGE, 5);
300
301         // TRANSLATORS: "slereg" is "stereo" with ascender and descender substituted
302         //Gtkmm2ext::set_size_request_to_display_given_text (channel_count_combo, _("slereg"), 5+FUDGE, 5);
303
304 /*      header_format_combo.set_focus_on_click (true);
305         bitdepth_format_combo.set_focus_on_click (true);
306         endian_format_combo.set_focus_on_click (true);
307         channel_count_combo.set_focus_on_click (true);
308         src_quality_combo.set_focus_on_click (true);
309         dither_type_combo.set_focus_on_click (true);
310         sample_rate_combo.set_focus_on_click (true);
311         cue_file_combo.set_focus_on_click (true);
312 */
313         dither_type_label.set_name ("ExportFormatLabel");
314         sample_rate_label.set_name ("ExportFormatLabel");
315         src_quality_label.set_name ("ExportFormatLabel");
316         channel_count_label.set_name ("ExportFormatLabel");
317         header_format_label.set_name ("ExportFormatLabel");
318         bitdepth_format_label.set_name ("ExportFormatLabel");
319         endian_format_label.set_name ("ExportFormatLabel");
320         cue_file_label.set_name ("ExportFormatLabel");
321
322         header_format_combo.set_name ("ExportFormatDisplay");
323         bitdepth_format_combo.set_name ("ExportFormatDisplay");
324         endian_format_combo.set_name ("ExportFormatDisplay");
325         channel_count_combo.set_name ("ExportFormatDisplay");
326         dither_type_combo.set_name ("ExportFormatDisplay");
327         src_quality_combo.set_name ("ExportFormatDisplay");
328         sample_rate_combo.set_name ("ExportFormatDisplay");
329         cue_file_combo.set_name ("ExportFormatDisplay");
330
331         cuefile_only_checkbox.set_name ("ExportCheckbox");
332
333         format_table.set_homogeneous (true);
334         format_table.set_border_width (5);
335         format_table.set_col_spacings (5);
336         format_table.set_row_spacings (5);
337
338         int row = 0;
339
340         format_table.attach (channel_count_label, 0, 1, row, row+1);
341         format_table.attach (channel_count_combo, 1, 2, row, row+1);
342
343         row++;
344         
345         format_table.attach (header_format_label, 0, 1, 1, 2, FILL, FILL);
346         format_table.attach (header_format_combo, 1, 2, 1, 2, FILL, FILL);
347
348         format_table.attach (bitdepth_format_label, 0, 1, 2, 3, FILL, FILL);
349         format_table.attach (bitdepth_format_combo, 1, 2, 2, 3, FILL, FILL);
350
351         format_table.attach (bitdepth_format_label, 0, 1, row, row+1);
352         format_table.attach (bitdepth_format_combo, 1, 2, row, row+1);
353         
354         row++;
355         
356         if (!Profile->get_sae()) {
357                 format_table.attach (endian_format_label, 0, 1, row, row+1);
358                 format_table.attach (endian_format_combo, 1, 2, row, row+1);
359                 row++;
360         }
361
362         format_table.attach (sample_rate_label, 0, 1, row, row+1);
363         format_table.attach (sample_rate_combo, 1, 2, row, row+1);
364
365         row++;
366
367         if (!Profile->get_sae()) {
368                 format_table.attach (src_quality_label, 0, 1, row, row+1);
369                 format_table.attach (src_quality_combo, 1, 2, row, row+1);
370                 row++;
371         }
372
373         format_table.attach (dither_type_label, 0, 1, row, row+1);
374         format_table.attach (dither_type_combo, 1, 2, row, row+1);
375
376         row++;
377
378         if (!Profile->get_sae()) {
379                 format_table.attach (cue_file_label, 0, 1, row, row+1);
380                 format_table.attach (cue_file_combo, 1, 2, row, row+1);
381                 row++;
382         
383                 format_table.attach (cuefile_only_checkbox, 0, 2, row, row+1);
384         }
385
386         file_entry.set_name ("ExportFileDisplay");
387
388         signal_delete_event().connect (mem_fun(*this, &ExportDialog::window_closed));
389
390         cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
391         cancel_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::end_dialog));
392         ok_button = add_button (_("Export"), RESPONSE_ACCEPT);
393         ok_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::do_export));
394         channel_count_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::channels_chosen));
395         bitdepth_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::bitdepth_chosen));
396         header_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::header_chosen));
397         sample_rate_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::sample_rate_chosen));
398         cue_file_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::cue_file_type_chosen));
399
400         file_chooser.signal_update_preview().connect (mem_fun(*this, &ExportDialog::file_chooser_selection_changed));
401
402 }
403
404 ExportDialog::~ExportDialog()
405 {
406 }
407
408 void
409 ExportDialog::do_not_allow_track_and_master_selection()
410 {
411         track_and_master_selection_allowed = false;
412 }
413
414 void
415 ExportDialog::do_not_allow_channel_count_selection()
416 {
417         channel_count_selection_allowed = false;
418 }
419
420 void
421 ExportDialog::do_not_allow_export_cd_markers()
422 {
423         export_cd_markers_allowed = false;
424 }
425
426 void
427 ExportDialog::connect_to_session (Session *s)
428 {
429         session = s;
430         session->GoingAway.connect (mem_fun(*this, &Window::hide_all));
431
432         switch (session->frame_rate()) {
433         case 22050:
434                 sample_rate_combo.set_active_text (_("22.05kHz"));
435                 break;
436         case 44100:
437                 sample_rate_combo.set_active_text (_("44.1kHz"));
438                 break;
439         case 48000:
440                 sample_rate_combo.set_active_text (_("48kHz"));
441                 break;
442         case 88200:
443                 sample_rate_combo.set_active_text (_("88.2kHz"));
444                 break;
445         case 96000:
446                 sample_rate_combo.set_active_text (_("96kHz"));
447                 break;
448         case 192000:
449                 sample_rate_combo.set_active_text (_("192kHz"));
450                 break;
451         default:
452                 sample_rate_combo.set_active_text (_("44.1kHz"));
453                 break;
454         }
455
456         src_quality_combo.set_sensitive (false);
457
458         set_state();
459 }
460
461 void
462 ExportDialog::set_state()
463 {
464         XMLNode* node = session->instant_xml(X_("ExportDialog"));
465         XMLProperty* prop;
466         bool fc_location_requested = false;
467         if (node) {
468
469                 if ((prop = node->property (X_("sample_rate"))) != 0) {
470                         sample_rate_combo.set_active_text(prop->value());
471                 }
472                 if ((prop = node->property (X_("src_quality"))) != 0) {
473                         src_quality_combo.set_active_text(prop->value());
474                 }
475                 if ((prop = node->property (X_("dither_type"))) != 0) {
476                         dither_type_combo.set_active_text(prop->value());
477                 }
478                 if ((prop = node->property (X_("channel_count"))) != 0) {
479                         channel_count_combo.set_active_text(prop->value());
480                 }
481                 if ((prop = node->property (X_("header_format"))) != 0) {
482                         header_format_combo.set_active_text(prop->value());
483                 }
484                 if ((prop = node->property (X_("bitdepth_format"))) != 0) {
485                         bitdepth_format_combo.set_active_text(prop->value());
486                 }
487                 if ((prop = node->property (X_("endian_format"))) != 0) {
488                         endian_format_combo.set_active_text(prop->value());
489                 }
490                 if ((prop = node->property (X_("filename"))) != 0) {
491                         file_chooser.set_filename(prop->value());
492                         fc_location_requested = true;
493                         file_chooser.set_current_folder(Glib::path_get_basename(prop->value()));
494                 }
495                   
496                 if ((prop = node->property (X_("cue_file_type"))) != 0) {
497                         cue_file_combo.set_active_text(prop->value());
498                 }
499         }
500
501         if (!fc_location_requested) {
502
503                 /*
504                   If the filename hasn't been set before, use the
505                   current session's export directory as a default
506                   location for the export.  
507                 */
508
509                 file_chooser.set_current_folder (session->session_directory().export_path().to_string());
510                 file_chooser.set_current_name (_("export.wav"));
511         }
512
513         header_chosen ();
514         bitdepth_chosen();
515         channels_chosen();
516         sample_rate_chosen();
517
518         if (session->master_out()) {
519                 track_scroll.hide ();
520         } else {
521                 master_scroll.hide ();
522                 track_selector_button.hide ();
523         }
524
525         if (!node) {
526                 return;
527         }
528
529         if (session->master_out()) {
530                 XMLNode* master = find_named_node(*node, (X_("Master")));
531                 int nchns;
532
533                 if (!master) {
534                         
535                         /* default is to use all */
536                         if (channel_count_combo.get_active_text() == _("Mono")) {
537                                 nchns = 1;
538                         } else {
539                                 nchns = 2;
540                         }
541
542                         TreeModel::Children rows = master_selector.get_model()->children();
543                         for (uint32_t r = 0; r < session->master_out()->n_outputs().n_audio(); ++r) {
544                                 if (nchns == 2) {
545                                         if (r % 2) {
546                                                 rows[r][exp_cols.right] = true;
547                                         } else {
548                                                 rows[r][exp_cols.left] = true;
549                                         }
550                                 } else {
551                                         rows[r][exp_cols.left] = true;
552                                 }
553                         }
554
555                 } else {
556                         /* XXX use XML state */
557                 }
558         }
559
560         XMLNode* tracks = find_named_node(*node, (X_("Tracks")));
561         if (!tracks) {
562                 return;
563         }
564         
565         XMLNodeList track_list = tracks->children(X_("Track"));
566         TreeModel::Children rows = track_selector.get_model()->children();
567         TreeModel::Children::iterator ri = rows.begin();
568         TreeModel::Row row;
569
570         for (XMLNodeIterator it = track_list.begin(); it != track_list.end(); ++it, ++ri) {
571                 if (ri == rows.end()){
572                         break;
573                 }
574
575                 XMLNode* track = *it;
576                 row = *ri;
577
578                 if ((prop = track->property(X_("channel1"))) != 0) {
579                         if (prop->value() == X_("on")) {
580                                 row[exp_cols.left] = true;
581                         } else {
582                                 row[exp_cols.left] = false;
583                         }
584                 }
585
586                 if ((prop = track->property(X_("channel2"))) != 0) {
587                         if (prop->value() == X_("on")) {
588                                 row[exp_cols.right] = true;
589                         } else {
590                                 row[exp_cols.right] = false;
591                         }
592                 }
593         }
594 }
595
596 void
597 ExportDialog::save_state()
598 {
599         if (!session) {
600                 return;
601         }
602
603         XMLNode* node = new XMLNode(X_("ExportDialog"));
604
605         node->add_property(X_("sample_rate"), sample_rate_combo.get_active_text());
606         node->add_property(X_("src_quality"), src_quality_combo.get_active_text());
607         node->add_property(X_("dither_type"), dither_type_combo.get_active_text());
608         node->add_property(X_("channel_count"), channel_count_combo.get_active_text());
609         node->add_property(X_("header_format"), header_format_combo.get_active_text());
610         node->add_property(X_("bitdepth_format"), bitdepth_format_combo.get_active_text());
611         node->add_property(X_("endian_format"), endian_format_combo.get_active_text());
612         node->add_property(X_("filename"), file_chooser.get_filename());
613         node->add_property(X_("cue_file_type"), cue_file_combo.get_active_text());
614
615         XMLNode* tracks = new XMLNode(X_("Tracks"));
616
617         TreeModel::Children rows = track_selector.get_model()->children();
618         TreeModel::Row row;
619         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
620                 XMLNode* track = new XMLNode(X_("Track"));
621
622                 row = *ri;
623                 track->add_property(X_("channel1"), row[exp_cols.left] ? X_("on") : X_("off"));
624                 track->add_property(X_("channel2"), row[exp_cols.right] ? X_("on") : X_("off"));
625
626                 tracks->add_child_nocopy(*track);
627         }
628         node->add_child_nocopy(*tracks);
629         
630         session->add_instant_xml(*node);
631 }
632
633 void
634 ExportDialog::set_range (nframes_t start, nframes_t end)
635 {
636         spec.start_frame = start;
637         spec.end_frame = end;
638 }
639
640 gint
641 ExportDialog::progress_timeout ()
642 {
643         progress_bar.set_fraction (spec.progress);
644         return TRUE;
645 }
646
647 void
648 frames_to_cd_frames_string (char* buf, nframes_t when, nframes_t fr)
649 {
650
651   long unsigned int remainder;
652   int mins, secs, frames;
653
654         mins = when / (60 * fr);
655         remainder = when - (mins * 60 * fr);
656         secs = remainder / fr;
657         remainder -= secs * fr;
658         frames = remainder / (fr / 75);
659         sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
660
661 }
662
663 struct LocationSortByStart {
664     bool operator() (Location *a, Location *b) {
665             return a->start() < b->start();
666     }
667 };
668
669 void
670 ExportDialog::export_toc_file (Locations::LocationList& locations, const string& path)
671 {
672         if(!export_cd_markers_allowed){
673                 return;
674         }
675         
676         string filepath = path + ".toc";
677         ofstream out (filepath.c_str());
678         long unsigned int last_end_time = spec.start_frame, last_start_time = spec.start_frame;
679         gchar buf[18];
680
681         if (!out) {
682                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD toc file"), filepath) << endmsg;
683                 return;
684         }
685         out << "CD_DA" << endl;
686         out << "CD_TEXT {" << endl << "  LANGUAGE_MAP {" << endl << "    0 : EN" << endl << "  }" << endl;
687         out << "  LANGUAGE 0 {" << endl << "    TITLE \"" << session->name() << "\"" << endl << "  }" << endl << "}" << endl;
688
689         Locations::LocationList::iterator i;
690         Locations::LocationList temp;
691
692         for (i = locations.begin(); i != locations.end(); ++i) {
693                 if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
694                         temp.push_back (*i);
695                 }
696         }
697
698         if (temp.size() > 0) {
699                 LocationSortByStart cmp;
700                 temp.sort (cmp);
701                 Location * curr_range = 0;
702                 Locations::LocationList::iterator nexti;
703
704                 for (i = temp.begin(); i != temp.end(); ++i) {
705
706                         if ((*i)->start() >= last_end_time)
707                         {
708                                 /* this is a track, defined by a cd range marker or a cd location marker outside of a cd range */
709                                 out << endl << "TRACK AUDIO" << endl;
710                                 
711                                 if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
712                                         out << "NO ";
713                                 }
714                                 out << "COPY" << endl;
715                                 
716                                 if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
717                                         out << "PRE_EMPHASIS" << endl;
718                                 } else {
719                                         out << "NO PRE_EMPHASIS" << endl;
720                                 }
721                                 
722                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
723                                         out << "ISRC \"" << (*i)->cd_info["isrc"] << "\"" << endl;
724                                 }
725                                 
726                                 out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE \"" << (*i)->name() << "\"" << endl;
727                                 if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
728                                         out << "     PERFORMER \"" << (*i)->cd_info["performer"]  << "\"" << endl;
729                                 }
730                                 if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
731                                         out  << "     COMPOSER \"" << (*i)->cd_info["string_composer"] << "\"" << endl;
732                                 }
733                                 
734                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end()) {                          
735                                         out  << "     ISRC \"";
736                                         out << (*i)->cd_info["isrc"].substr(0,2) << "-";
737                                         out << (*i)->cd_info["isrc"].substr(2,3) << "-";
738                                         out << (*i)->cd_info["isrc"].substr(5,2) << "-";
739                                         out << (*i)->cd_info["isrc"].substr(7,5) << "\"" << endl;
740                                 }
741                                 
742                                 out << "  }" << endl << "}" << endl;
743                                 
744                                 frames_to_cd_frames_string (buf, last_end_time - spec.start_frame, session->frame_rate());
745                                 out << "FILE \"" << path << "\" " << buf;
746                                 
747                                 if ((*i)->is_mark()) {
748                                         // a mark track location needs to look ahead to the next marker's start to determine length
749                                         nexti = i;
750                                         ++nexti;
751                                         if (nexti != temp.end()) {
752                                                 frames_to_cd_frames_string (buf, (*nexti)->start() - 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 = (*nexti)->start();
760                                         }
761                                         else {
762                                                 // this was the last marker, use session end
763                                                 frames_to_cd_frames_string (buf, spec.end_frame - last_end_time, session->frame_rate());
764                                                 out << buf << endl;
765                                                 
766                                                 frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
767                                                 out << "START" << buf << endl;
768                                                 
769                                                 last_start_time = (*i)->start();
770                                                 last_end_time = spec.end_frame;
771                                         }
772
773                                         curr_range = 0;
774                                 }
775                                 else {
776                                         // range
777                                         frames_to_cd_frames_string (buf, (*i)->end() - last_end_time, session->frame_rate());
778                                         out << buf << endl;
779                                         
780                                         frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
781                                         out << "START" << buf << endl;
782                                         
783                                         last_start_time = (*i)->start();
784                                         last_end_time = (*i)->end();
785
786                                         curr_range = (*i);
787                                 }
788                                 
789                         }
790                         else if ((*i)->is_mark()) 
791                         {
792                                 /* this is an index within a track */
793                                 
794                                 frames_to_cd_frames_string (buf, (*i)->start() - last_start_time, session->frame_rate());
795                                 out << "INDEX" << buf << endl;
796                         }
797                 }
798         }
799         
800 }
801
802 void
803 ExportDialog::export_cue_file (Locations::LocationList& locations, const string& path)
804 {
805         if(!export_cd_markers_allowed){
806                 return;
807         }
808         
809     string filepath = path + ".cue";
810         ofstream out (filepath.c_str());
811         gchar buf[18];
812         long unsigned int last_track_end = spec.start_frame;
813         int numtracks = 0, tracknum = 0, indexnum = 0;
814
815         if (!out) {
816                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD cue file"), filepath) << endmsg;
817                 return;
818         }
819
820         Locations::LocationList::iterator i;
821         Locations::LocationList temp;
822
823         for (i = locations.begin(); i != locations.end(); ++i) {
824                 if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
825                         temp.push_back (*i);
826                         if (!(*i)->is_mark()) {
827                                 numtracks++;
828                         }
829                 }
830         }
831         
832         out << "REM Cue file generated by Ardour" << endl;
833         out << "TITLE \"" << session->name() << "\"" << endl;
834
835         if ((header_format_combo.get_active_text() == N_("WAV"))) {
836                   out << "FILE " << path  << " WAVE" << endl;
837         } else {
838                   out << "FILE " << path  << ' ' << (header_format_combo.get_active_text()) << endl;
839         }
840
841         if (false && numtracks == 0) {
842                     /* the user has supplied no track markers.
843                        the entire export is treated as one track. 
844                     */
845
846                   numtracks++;
847                   tracknum++;
848                   indexnum = 0;
849                   out << endl << "TRACK " << tracknum << " AUDIO" << endl;
850                   out << "FLAGS " ;
851                   
852                   out << "DCP " << endl;                   
853                   
854                   /* use the session name*/
855                   
856                   if (session->name() != "") {
857                     out << "TITLE \"" << session->name() << "\"" << endl;
858                   }           
859                   
860                   /* no pregap in this case */
861
862                   out << "INDEX 00 00:00:00" << endl;
863                   indexnum++;
864                   out << "INDEX 01 00:00:00" << endl;
865                   indexnum++;
866                   last_track_end = spec.end_frame;
867         }
868
869         if (temp.size()) {
870                 LocationSortByStart cmp;
871                 temp.sort (cmp);
872                 Location * curr_range = 0;
873                 Locations::LocationList::iterator nexti;
874
875                 for ( i = temp.begin(); i != temp.end(); ++i) {
876
877                         if ((*i)->start() >= last_track_end)
878                         {
879                                 /* this is a track and it doesn't start inside another one*/
880                                 
881                                 tracknum++;
882                                 indexnum = 0;
883                                 out << endl << "TRACK " << tracknum << " AUDIO" << endl;
884                                 out << "FLAGS " ;
885                                 
886                                 if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
887                                         out << "SCMS ";
888                                 } else {
889                                         out << "DCP ";
890                                 }
891                                 
892                                 if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
893                                         out << "PRE";
894                                 }
895                                 out << endl;
896                                 
897                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
898                                         out << "ISRC " << (*i)->cd_info["isrc"] << endl;
899                                         
900                                 }
901                                 if ((*i)->name() != "") {
902                                         out << "TITLE \"" << (*i)->name() << "\"" << endl;
903                                 }             
904                                 
905                                 if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
906                                         out << "PERFORMER \"" <<  (*i)->cd_info["performer"] << "\"" << endl;
907                                 }
908                                 
909                                 if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
910                                         out << "SONGWRITER \"" << (*i)->cd_info["string_composer"]  << "\"" << endl;
911                                 }
912                                 snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
913                                 out << buf;
914                                 frames_to_cd_frames_string (buf, last_track_end - spec.start_frame, session->frame_rate());
915                                 out << buf << endl;
916                                 indexnum++;
917
918                                 if ((*i)->is_mark()) {
919                                         // need to find the next start to define the end
920                                         nexti = i;
921                                         ++nexti;
922                                         if (nexti != temp.end()) {
923                                                 last_track_end = (*nexti)->start();
924                                         }
925                                         else {
926                                                 last_track_end = spec.end_frame;
927                                         }
928                                         curr_range = 0;
929                                 }
930                                 else {
931                                         last_track_end = (*i)->end();
932                                         curr_range = (*i);
933                                 }
934                         } 
935         
936                         if ((tracknum > 0) && ((*i)->start() < last_track_end)) {
937                                 /*this is an index and it lies within a track*/
938                                 snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
939                                 out << buf;
940                                 frames_to_cd_frames_string (buf,(*i)->start() - spec.start_frame, session->frame_rate());
941                                 out << buf << endl;
942                                 indexnum++;
943                         }
944                 }
945         }
946         
947 }
948         
949 void
950 ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_type)
951 {
952         if (cuefile_type == _("TOC")) {
953                 session->locations()->apply (*this, &ExportDialog::export_toc_file, path);      
954         } else {
955                 session->locations()->apply (*this, &ExportDialog::export_cue_file, path);
956         }
957 }
958
959
960 void
961 ExportDialog::do_export ()
962 {
963         string filepath = file_chooser.get_filename();
964
965         if (!ARDOUR_UI::instance()->the_engine().connected()) {
966                 MessageDialog msg (*this, 
967                                    _("Not connected to audioengine"),
968                                    true,
969                                    MESSAGE_ERROR,
970                                    BUTTONS_OK);
971                 msg.set_secondary_text (_("Ardour cannot export audio when disconnected"));
972                 msg.present ();
973                 msg.run ();
974                 return;
975         }
976                 
977         if(!is_filepath_valid(filepath)){
978                 return;
979         }
980
981         if (!Profile->get_sae() && export_cd_markers_allowed) {
982                 if (cue_file_combo.get_active_text () != _("None")) {
983                         do_export_cd_markers (file_chooser.get_filename(), cue_file_combo.get_active_text ());
984                 }
985
986                 if (cuefile_only_checkbox.get_active()) {
987                         end_dialog ();
988                         return;
989                 }
990         }
991
992         ok_button->set_sensitive(false);
993         save_state();
994
995         set_modal (true);
996         
997         // read user input into spec
998         initSpec(filepath);
999         
1000         progress_bar.show();
1001         progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportDialog::progress_timeout), 100);
1002         cancel_label.set_text (_("Stop Export"));
1003
1004         export_audio_data();
1005         
1006         progress_connection.disconnect ();
1007         session->engine().freewheel (false);
1008         progress_bar.hide();
1009         end_dialog ();
1010 }
1011         
1012 void
1013 ExportDialog::end_dialog ()
1014 {
1015         if (spec.running) {
1016                 spec.stop = true;
1017
1018                 while (spec.running) {
1019                         if (gtk_events_pending()) {
1020                                 gtk_main_iteration ();
1021                         } else {
1022                                 usleep (10000);
1023                         }
1024                 }
1025         }
1026
1027         hide ();
1028
1029         session->finalize_audio_export ();
1030
1031         set_modal (false);
1032         ok_button->set_sensitive(true);
1033 }
1034
1035 void
1036 ExportDialog::start_export ()
1037 {
1038         if (session == 0) {
1039                 return;
1040         }
1041
1042         /* If the filename hasn't been set before, use the
1043            current session's export directory as a default
1044            location for the export.  
1045         */
1046         
1047         if (file_entry.get_text().length() == 0) {
1048
1049                 sys::path export_file_path = session->session_directory().export_path();
1050
1051                 if (!wants_dir()) {
1052                         export_file_path /= "export.wav";
1053                 }
1054                 
1055                 file_entry.set_text (export_file_path.to_string());
1056         }
1057
1058         progress_bar.set_fraction (0);
1059         progress_bar.hide();
1060         cancel_label.set_text (_("Cancel"));
1061
1062         hpacker.show_all();
1063
1064         file_hbox.show();
1065         file_frame.show();
1066         file_chooser.show();
1067         show ();
1068
1069         if (track_and_master_selection_allowed) {
1070                 track_vpacker.show();
1071         } else {
1072                 track_vpacker.hide();
1073         }
1074
1075         if (channel_count_selection_allowed) {
1076                 channel_count_combo.show();
1077                 channel_count_label.show();
1078         } else {
1079                 channel_count_combo.hide();
1080                 channel_count_label.hide();
1081         }
1082
1083         if (export_cd_markers_allowed) {
1084                 cue_file_label.show();
1085                 cue_file_combo.show();
1086                 cuefile_only_checkbox.show();
1087         } else {
1088                 cue_file_label.hide();
1089                 cue_file_combo.hide();
1090                 cuefile_only_checkbox.hide();
1091         }
1092
1093         if (session->master_out()) {
1094                 track_scroll.hide ();
1095         } else {
1096                 master_scroll.hide ();
1097                 track_selector_button.hide ();
1098         }
1099
1100         track_and_master_selection_allowed = true;
1101         channel_count_selection_allowed =  true;
1102         export_cd_markers_allowed = true;
1103 }
1104
1105 void
1106 ExportDialog::header_chosen ()
1107 {
1108         if (sndfile_header_format_from_string (header_format_combo.get_active_text ()) == SF_FORMAT_WAV) {
1109                 endian_format_combo.set_active_text (N_("Little-endian (Intel)"));
1110                 endian_format_combo.set_sensitive (false);
1111         } else {
1112                 endian_format_combo.set_sensitive (true);
1113                 endian_format_combo.set_active_text (N_("Big-endian (Mac)"));
1114         }
1115 }
1116
1117 void
1118 ExportDialog::bitdepth_chosen ()
1119 {
1120         int format = sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());    
1121         switch (format) {
1122         case SF_FORMAT_PCM_24:
1123         case SF_FORMAT_PCM_32:
1124         case SF_FORMAT_FLOAT:
1125                 dither_type_combo.set_sensitive (false);
1126                 break;
1127
1128         default:
1129                 dither_type_combo.set_sensitive (true);
1130                 break;
1131         }
1132 }
1133
1134 void
1135 ExportDialog::cue_file_type_chosen ()
1136 {
1137         if (cue_file_combo.get_active_text () != "None") {
1138                 cuefile_only_checkbox.set_sensitive (true);
1139         } else {
1140                 cuefile_only_checkbox.set_active (false);
1141                 cuefile_only_checkbox.set_sensitive (false);
1142         }
1143 }
1144
1145 void
1146 ExportDialog::file_chooser_selection_changed ()
1147 {
1148
1149   /*
1150     if the user selects an existing file from the 'browse for other folders' tab,
1151     change the format settings to match the file.
1152   */
1153         if (file_chooser.get_filename().length() == 0) {
1154                 return;
1155         }
1156         if (Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_IS_DIR)){
1157                 file_chooser.set_current_name (_(""));
1158                 return;
1159         }
1160         if (!Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_EXISTS)) {
1161                 return;
1162         }
1163
1164         SoundFileInfo finfo;
1165         string error_msg, format_str;
1166         
1167         if (!AudioFileSource::get_soundfile_info (file_chooser.get_preview_filename(), finfo, error_msg)) {
1168                 error << string_compose(_("Export: cannot open file \"%1\"."), error_msg ) << endmsg;
1169                 return;
1170         }
1171
1172         if (finfo.samplerate == 22050) {
1173                 sample_rate_combo.set_active_text (N_("22.05kHz"));
1174         } else if (finfo.samplerate == 44100) {
1175                 sample_rate_combo.set_active_text (N_("44.1kHz"));
1176         } else if (finfo.samplerate == 48000) {
1177                 sample_rate_combo.set_active_text (N_("48kHz"));
1178         } else if (finfo.samplerate == 88200) {
1179                 sample_rate_combo.set_active_text (N_("88.2kHz"));
1180         } else if (finfo.samplerate == 96000) {
1181                 sample_rate_combo.set_active_text (N_("96kHz"));
1182         } else if (finfo.samplerate == 192000) {
1183                 sample_rate_combo.set_active_text (N_("192kHz"));
1184         } 
1185
1186         if (finfo.channels == 1) {
1187                 channel_count_combo.set_active_text(N_("Mono"));
1188         } else {
1189                 channel_count_combo.set_active_text(N_("Stereo"));
1190         }
1191
1192         string::size_type pos;
1193
1194         pos = finfo.format_name.find_first_of (" ");
1195         format_str = finfo.format_name.substr(pos + 1, 255);
1196         pos = format_str.find_first_of (" ");
1197         header_format_combo.set_active_text(format_str.substr(0, pos));
1198
1199         format_str = finfo.format_name;
1200         pos = format_str.find_first_of (",");
1201         bitdepth_format_combo.set_active_text(format_str.substr(pos + 2, 255));
1202 }
1203
1204 void
1205 ExportDialog::sample_rate_chosen ()
1206 {
1207         string sr_str = sample_rate_combo.get_active_text();
1208         nframes_t rate;
1209
1210         if (sr_str == N_("22.05kHz")) {
1211                 rate = 22050;
1212         } else if (sr_str == _("44.1kHz")) {
1213                 rate = 44100;
1214         } else if (sr_str == _("48kHz")) {
1215                 rate = 48000;
1216         } else if (sr_str == _("88.2kHz")) {
1217                 rate = 88200;
1218         } else if (sr_str == _("96kHz")) {
1219                 rate = 96000;
1220         } else if (sr_str == _("192kHz")) {
1221                 rate = 192000;
1222         } else {
1223                 rate = session->frame_rate();
1224         }
1225                 
1226         if (rate != session->frame_rate()) {
1227                 src_quality_combo.set_sensitive (true);
1228         } else {
1229                 src_quality_combo.set_sensitive (false);
1230         }
1231 }
1232
1233 void
1234 ExportDialog::channels_chosen ()
1235 {
1236         bool mono;
1237
1238         mono = (channel_count_combo.get_active_text() == _("Mono"));
1239
1240         if (mono) {
1241                 track_selector.get_column(2)->set_visible(false);
1242                 track_selector.get_column(1)->set_title(_("Export"));
1243
1244                 if (session->master_out()) {
1245                         master_selector.get_column(2)->set_visible(false);
1246                         master_selector.get_column(1)->set_title(_("Export"));
1247                 }
1248
1249         } else {
1250                 track_selector.get_column(2)->set_visible(true);
1251                 track_selector.get_column(1)->set_title(_("Left"));
1252
1253                 if (session->master_out()) {
1254                         master_selector.get_column(2)->set_visible(true);
1255                         master_selector.get_column(1)->set_title(_("Left"));
1256                 }
1257         }
1258
1259         fill_lists();
1260 }
1261
1262 void
1263 ExportDialog::fill_lists ()
1264 {
1265         track_list->clear();
1266         master_list->clear();
1267         
1268         boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
1269
1270         for (Session::RouteList::iterator ri = routes->begin(); ri != routes->end(); ++ri) {
1271                 
1272                 boost::shared_ptr<Route> route = (*ri);
1273                 
1274                 if (route->is_hidden()) {
1275                         continue;
1276                 }
1277
1278                 for (uint32_t i=0; i < route->n_outputs().n_audio(); ++i) {
1279                         string name;
1280                         if (route->n_outputs().n_audio() == 1) {
1281                                 name = route->name();
1282                         } else {
1283                                 name = string_compose("%1: out-%2", route->name(), i+1);
1284                         }
1285
1286                         if (route == session->master_out()) {
1287                                 TreeModel::iterator iter = master_list->append();
1288                                 TreeModel::Row row = *iter;
1289                                 row[exp_cols.output] = name;
1290                                 row[exp_cols.left] = false;
1291                                 row[exp_cols.right] = false;
1292                                 row[exp_cols.port] = route->output (i);
1293                         } else {
1294                                 TreeModel::iterator iter = track_list->append();
1295                                 TreeModel::Row row = *iter;
1296                                 row[exp_cols.output] = name;
1297                                 row[exp_cols.left] = false;
1298                                 row[exp_cols.right] = false;
1299                                 row[exp_cols.port] = route->output (i);
1300                         }
1301                 }
1302         }
1303 }
1304
1305
1306 bool
1307 ExportDialog::is_filepath_valid(string &filepath)
1308 {
1309         // sanity check file name first
1310
1311         struct stat statbuf;
1312   
1313         if (filepath.empty()) {
1314                 string txt = _("Please enter a valid filename.");
1315                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1316                 msg.run();
1317                 return false;
1318         }
1319         
1320         // check if file exists already and warn
1321
1322         if (stat (filepath.c_str(), &statbuf) == 0) {
1323                 if (S_ISDIR (statbuf.st_mode)) {
1324                         string txt = _("Please specify a complete filename for the audio file.");
1325                         MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1326                         msg.run();
1327                         return false;
1328                 }
1329                 else {
1330                         string txt = _("File ") + filepath + _(" already exists, do you want to overwrite it?");
1331                         MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true);
1332                         if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) {
1333                                 return false;
1334                         }
1335                 }
1336         }
1337         
1338         // directory needs to exist and be writable
1339
1340         string dirpath = Glib::path_get_dirname (filepath);
1341         if (::access (dirpath.c_str(), W_OK) != 0) {
1342                 string txt = _("Cannot write file in: ") + dirpath;
1343                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1344                 msg.run();
1345                 return false;
1346         }
1347         
1348         return true;
1349 }
1350
1351 void
1352 ExportDialog::initSpec(string &filepath)
1353 {
1354         spec.path = filepath;
1355         spec.progress = 0;
1356         spec.running = true;
1357         spec.stop = false;
1358         spec.port_map.clear();
1359         
1360         if (channel_count_combo.get_active_text() == _("Mono")) {
1361                 spec.channels = 1;
1362         } else {
1363                 spec.channels = 2;
1364         }
1365
1366         spec.format = 0;
1367
1368         spec.format |= sndfile_header_format_from_string (header_format_combo.get_active_text ());
1369
1370         if (!Profile->get_sae()) {
1371                 if ((spec.format & SF_FORMAT_WAV) == 0) {
1372                         /* RIFF/WAV specifies endianess */
1373                         spec.format |= sndfile_endian_format_from_string (endian_format_combo.get_active_text ());
1374                 }
1375         }
1376
1377         spec.format |= sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());
1378
1379         string sr_str = sample_rate_combo.get_active_text();
1380         if (sr_str == N_("22.05kHz")) {
1381                 spec.sample_rate = 22050;
1382         } else if (sr_str == _("44.1kHz")) {
1383                 spec.sample_rate = 44100;
1384         } else if (sr_str == _("48kHz")) {
1385                 spec.sample_rate = 48000;
1386         } else if (sr_str == _("88.2kHz")) {
1387                 spec.sample_rate = 88200;
1388         } else if (sr_str == _("96kHz")) {
1389                 spec.sample_rate = 96000;
1390         } else if (sr_str == _("192kHz")) {
1391                 spec.sample_rate = 192000;
1392         } else {
1393                 spec.sample_rate = session->frame_rate();
1394         }
1395         
1396         if (Profile->get_sae()) {
1397                 spec.src_quality = SRC_SINC_BEST_QUALITY;
1398         } else {
1399                 string src_str = src_quality_combo.get_active_text();
1400                 if (src_str == _("fastest")) {
1401                         spec.src_quality = SRC_ZERO_ORDER_HOLD;
1402                 } else if (src_str == _("linear")) {
1403                         spec.src_quality = SRC_LINEAR;
1404                 } else if (src_str == _("better")) {
1405                         spec.src_quality = SRC_SINC_FASTEST;
1406                 } else if (src_str == _("intermediate")) {
1407                         spec.src_quality = SRC_SINC_MEDIUM_QUALITY;
1408                 } else {
1409                         spec.src_quality = SRC_SINC_BEST_QUALITY;
1410                 }
1411         }
1412
1413         string dither_str = dither_type_combo.get_active_text();
1414         if (dither_str == _("None")) {
1415                 spec.dither_type = GDitherNone;
1416         } else if (dither_str == _("Rectangular")) {
1417                 spec.dither_type = GDitherRect;
1418         } else if (dither_str == _("Triangular")) {
1419                 spec.dither_type = GDitherTri;
1420         } else {
1421                 spec.dither_type = GDitherShaped;
1422         } 
1423
1424         write_track_and_master_selection_to_spec();
1425 }
1426
1427
1428 void
1429 ExportDialog::write_track_and_master_selection_to_spec()
1430 {
1431         if(!track_and_master_selection_allowed){
1432                 return;
1433         }
1434
1435         uint32_t chan=0;
1436         Port *last_port = 0;
1437                 
1438         TreeModel::Children rows = master_selector.get_model()->children();
1439         TreeModel::Children::iterator ri;
1440         TreeModel::Row row;
1441         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1442                 row = *ri;
1443                 Port* port = row[exp_cols.port];
1444                 
1445                 if (last_port != port) {
1446                         chan = 0;
1447                 }
1448                 
1449                 if (row[exp_cols.left]) {
1450                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1451                 } 
1452                 
1453                 if (spec.channels == 2) {
1454                         if (row[exp_cols.right]) {
1455                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1456                         }
1457                 }
1458         }
1459         
1460         chan = 0;
1461         rows = track_selector.get_model()->children();
1462
1463         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1464                 row = *ri;
1465                 
1466                 Port* port = row[exp_cols.port];
1467                 
1468                 if (last_port != port) {
1469                         chan = 0;
1470                 }
1471                 
1472                 if (row[exp_cols.left]) {
1473                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1474                 } 
1475                 
1476                 if (spec.channels == 2) {
1477                         if (row[exp_cols.right]) {
1478                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1479                         }
1480                         
1481                 }
1482                 
1483                 last_port = port;
1484                 ++chan;
1485         }
1486 }
1487
1488
1489 gint
1490 ExportDialog::window_closed (GdkEventAny *ignored)
1491 {
1492         end_dialog ();
1493         return TRUE;
1494 }
1495
1496 void
1497 ExportDialog::track_selector_button_click ()
1498 {
1499         if (track_scroll.is_visible ()) {
1500                 track_scroll.hide ();
1501         } else {
1502                 track_scroll.show_all ();
1503         }
1504 }