remove reference to fs.h
[ardour.git] / gtk2_ardour / sfdb_ui.cc
1 /*
2     Copyright (C) 2005-2006 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 #include <map>
21 #include <cerrno>
22 #include <sstream>
23
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
27
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
31
32 #include <pbd/convert.h>
33 #include <pbd/tokenizer.h>
34
35 #include <gtkmm2ext/utils.h>
36
37 #include <ardour/audio_library.h>
38 #include <ardour/auditioner.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audiofilesource.h>
41 #include <ardour/region_factory.h>
42 #include <ardour/source_factory.h>
43 #include <ardour/profile.h>
44
45 #include "ardour_ui.h"
46 #include "editing.h"
47 #include "gui_thread.h"
48 #include "prompter.h"
49 #include "sfdb_ui.h"
50 #include "editing.h"
51 #include "utils.h"
52 #include "gain_meter.h"
53
54 #include "i18n.h"
55
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace std;
59 using namespace Gtk;
60 using namespace Gtkmm2ext;
61 using namespace Editing;
62
63 using Glib::ustring;
64
65 ustring SoundFileBrowser::persistent_folder;
66
67 SoundFileBox::SoundFileBox ()
68         : _session(0),
69           table (6, 2),
70           length_clock ("sfboxLengthClock", false, "EditCursorClock", false, true, false),
71           timecode_clock ("sfboxTimecodeClock", false, "EditCursorClock", false, false, false),
72           main_box (false, 6),
73           autoplay_btn (_("Auto-play"))
74         
75 {
76         HBox* hbox;
77         VBox* vbox;
78
79         set_name (X_("SoundFileBox"));
80         set_size_request (300, -1);
81
82         preview_label.set_markup (_("<b>Soundfile Info</b>"));
83
84         border_frame.set_label_widget (preview_label);
85         border_frame.add (main_box);
86
87         pack_start (border_frame, true, true);
88         set_border_width (6);
89
90         main_box.set_border_width (6);
91         main_box.set_spacing (12);
92
93         length.set_text (_("Length:"));
94         timecode.set_text (_("Timestamp:"));
95         format.set_text (_("Format:"));
96         channels.set_text (_("Channels:"));
97         samplerate.set_text (_("Sample rate:"));
98
99         table.set_col_spacings (6);
100         table.set_homogeneous (false);
101         table.set_row_spacings (6);
102
103         table.attach (channels, 0, 1, 0, 1, FILL|EXPAND, (AttachOptions) 0);
104         table.attach (samplerate, 0, 1, 1, 2, FILL|EXPAND, (AttachOptions) 0);
105         table.attach (format, 0, 1, 2, 4, FILL|EXPAND, (AttachOptions) 0);
106         table.attach (length, 0, 1, 4, 5, FILL|EXPAND, (AttachOptions) 0);
107         table.attach (timecode, 0, 1, 5, 6, FILL|EXPAND, (AttachOptions) 0);
108
109         table.attach (channels_value, 1, 2, 0, 1, FILL, (AttachOptions) 0);
110         table.attach (samplerate_value, 1, 2, 1, 2, FILL, (AttachOptions) 0);
111         table.attach (format_text, 1, 2, 2, 4, FILL, AttachOptions (0));
112         table.attach (length_clock, 1, 2, 4, 5, FILL, (AttachOptions) 0);
113         table.attach (timecode_clock, 1, 2, 5, 6, FILL, (AttachOptions) 0);
114
115         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
116         timecode_clock.set_mode (AudioClock::SMPTE);
117
118         hbox = manage (new HBox);
119         hbox->pack_start (table, false, false);
120         main_box.pack_start (*hbox, false, false);
121
122         tags_entry.set_editable (true);
123         tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
124         hbox = manage (new HBox);
125         hbox->pack_start (tags_entry, true, true);
126
127         vbox = manage (new VBox);
128
129         Label* label = manage (new Label (_("Tags:")));
130         label->set_alignment (0.0f, 0.5f);
131         vbox->set_spacing (6);
132         vbox->pack_start(*label, false, false);
133         vbox->pack_start(*hbox, true, true);
134
135         main_box.pack_start(*vbox, true, true);
136         main_box.pack_start(bottom_box, false, false);
137         
138         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
139         play_btn.set_label (_("Play (double click)"));
140
141         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
142         stop_btn.set_label (_("Stop"));
143         
144         bottom_box.set_homogeneous (false);
145         bottom_box.set_spacing (6);
146         bottom_box.pack_start(play_btn, true, true);
147         bottom_box.pack_start(stop_btn, true, true);
148         bottom_box.pack_start(autoplay_btn, false, false);
149
150         play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
151         stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
152
153         length.set_alignment (0.0f, 0.5f);
154         format.set_alignment (0.0f, 0.5f);
155         channels.set_alignment (0.0f, 0.5f);
156         samplerate.set_alignment (0.0f, 0.5f);
157         timecode.set_alignment (0.0f, 0.5f);
158
159         channels_value.set_alignment (0.0f, 0.5f);
160         samplerate_value.set_alignment (0.0f, 0.5f);
161 }
162
163 void
164 SoundFileBox::set_session(Session* s)
165 {
166         _session = s;
167
168         if (!_session) {
169                 play_btn.set_sensitive (false);
170                 stop_btn.set_sensitive (false);
171         } 
172
173
174         length_clock.set_session (s);
175         timecode_clock.set_session (s);
176 }
177
178 bool
179 SoundFileBox::setup_labels (const ustring& filename) 
180 {
181         if (!path.empty()) {
182                 // save existing tags
183                 tags_changed ();
184         }
185
186         path = filename;
187
188         string error_msg;
189
190         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
191
192                 preview_label.set_markup (_("<b>Soundfile Info</b>"));
193                 format_text.set_text (_("n/a"));
194                 channels_value.set_text (_("n/a"));
195                 samplerate_value.set_text (_("n/a"));
196                 tags_entry.get_buffer()->set_text ("");
197
198                 length_clock.set (0);
199                 timecode_clock.set (0);
200                 
201                 tags_entry.set_sensitive (false);
202                 play_btn.set_sensitive (false);
203                 
204                 return false;
205         }
206
207         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
208         format_text.set_text (sf_info.format_name);
209         channels_value.set_text (to_string (sf_info.channels, std::dec));
210
211         if (_session && sf_info.samplerate != _session->frame_rate()) {
212                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
213                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
214                 samplerate_value.set_name ("NewSessionSR1Label");
215                 samplerate.set_name ("NewSessionSR1Label");
216         } else {
217                 samplerate.set_text (_("Sample rate:"));
218                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
219                 samplerate_value.set_name ("NewSessionSR2Label");
220                 samplerate.set_name ("NewSessionSR2Label");
221         }
222
223         length_clock.set (sf_info.length, true);
224         timecode_clock.set (sf_info.timecode, true);
225
226         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
227
228         vector<string> tags = Library->get_tags (string ("//") + filename);
229         
230         stringstream tag_string;
231         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
232                 if (i != tags.begin()) {
233                         tag_string << ", ";
234                 }
235                 tag_string << *i;
236         }
237         tags_entry.get_buffer()->set_text (tag_string.str());
238         
239         tags_entry.set_sensitive (true);
240         if (_session) {
241                 play_btn.set_sensitive (true);
242         }
243         
244         return true;
245 }
246
247 bool
248 SoundFileBox::autoplay() const
249 {
250         return autoplay_btn.get_active();
251 }
252
253 bool
254 SoundFileBox::audition_oneshot()
255 {
256         audition ();
257         return false;
258 }
259
260 void
261 SoundFileBox::audition ()
262 {
263         if (!_session) {
264                 return;
265         }
266         
267         _session->cancel_audition();
268
269         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
270                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
271                 return;
272         }
273
274         boost::shared_ptr<Region> r;
275         SourceList srclist;
276         boost::shared_ptr<AudioFileSource> afs;
277         bool old_sbp = AudioSource::get_build_peakfiles ();
278
279         /* don't even think of building peakfiles for these files */
280
281         AudioSource::set_build_peakfiles (false);
282
283         for (int n = 0; n < sf_info.channels; ++n) {
284                 try {
285                         afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (*_session, path, n, AudioFileSource::Flag (0), false));
286                         
287                         srclist.push_back(afs);
288                         
289                 } catch (failed_constructor& err) {
290                         error << _("Could not access soundfile: ") << path << endmsg;
291                         AudioSource::set_build_peakfiles (old_sbp);
292                         return;
293                 }
294         }
295
296         AudioSource::set_build_peakfiles (old_sbp);
297                         
298         if (srclist.empty()) {
299                 return;
300         }
301         
302         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
303         string rname = region_name_from_path (afs->path(), false);
304         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
305
306         _session->audition_region(r);
307 }
308
309 void
310 SoundFileBox::stop_audition ()
311 {
312         if (_session) {
313                 _session->cancel_audition();
314         }
315 }
316
317 bool
318 SoundFileBox::tags_entry_left (GdkEventFocus *ev)
319 {
320         tags_changed ();
321         return false;
322 }
323
324 void
325 SoundFileBox::tags_changed ()
326 {
327         string tag_string = tags_entry.get_buffer()->get_text ();
328
329         if (tag_string.empty()) {
330                 return;
331         }
332
333         vector<string> tags;
334
335         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
336                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
337                 return;
338         }
339
340         save_tags (tags);
341 }
342
343 void
344 SoundFileBox::save_tags (const vector<string>& tags)
345 {
346         Library->set_tags (string ("//") + path, tags);
347         Library->save_changes ();
348 }
349
350 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s)
351         : ArdourDialog (parent, title, false, false),
352           found_list (ListStore::create(found_list_columns)),
353           chooser (FILE_CHOOSER_ACTION_OPEN),
354           found_list_view (found_list),
355           found_search_btn (_("Search"))
356 {
357         VBox* vbox;
358         HBox* hbox;
359
360         gm = 0;
361
362         set_session (s);
363         resetting_ourselves = false;
364         
365         hpacker.set_spacing (6);
366         hpacker.pack_start (notebook, true, true);
367         hpacker.pack_start (preview, false, false);
368
369         get_vbox()->pack_start (hpacker, true, true);
370
371         hbox = manage(new HBox);
372         hbox->pack_start (found_entry);
373         hbox->pack_start (found_search_btn);
374         
375         vbox = manage(new VBox);
376         vbox->pack_start (*hbox, PACK_SHRINK);
377         vbox->pack_start (found_list_view);
378         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
379         
380         chooser.set_border_width (12);
381
382         notebook.append_page (chooser, _("Browse Files"));
383         notebook.append_page (*vbox, _("Search Tags"));
384
385         notebook.set_size_request (500, -1);
386
387         found_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
388         found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
389
390         custom_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
391         custom_filter.set_name (_("Audio files"));
392
393         matchall_filter.add_pattern ("*.*");
394         matchall_filter.set_name (_("All files"));
395
396         chooser.add_filter (custom_filter);
397         chooser.add_filter (matchall_filter);
398         chooser.set_select_multiple (true);
399         chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
400         chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
401
402         if (!persistent_folder.empty()) {
403                 chooser.set_current_folder (persistent_folder);
404         }
405
406         found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
407         
408         found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
409         found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
410
411         add_button (Stock::CANCEL, RESPONSE_CANCEL);
412         add_button (Stock::APPLY, RESPONSE_APPLY);
413         add_button (Stock::OK, RESPONSE_OK);
414         
415 }
416
417 SoundFileBrowser::~SoundFileBrowser ()
418 {
419         persistent_folder = chooser.get_current_folder();
420 }
421
422
423 void
424 SoundFileBrowser::on_show ()
425 {
426         ArdourDialog::on_show ();
427         start_metering ();
428 }
429
430 void
431 SoundFileBrowser::clear_selection ()
432 {
433         chooser.unselect_all ();
434         found_list_view.get_selection()->unselect_all ();
435 }
436
437 void
438 SoundFileBrowser::chooser_file_activated ()
439 {
440         preview.audition ();
441 }
442
443 void
444 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
445 {
446         preview.audition ();
447 }
448
449 void
450 SoundFileBrowser::set_session (Session* s)
451 {
452         ArdourDialog::set_session (s);
453         preview.set_session (s);
454         if (s) {
455                 add_gain_meter ();
456         } else {
457                 remove_gain_meter ();
458         }
459 }
460
461 void
462 SoundFileBrowser::add_gain_meter ()
463 {
464         if (gm) {
465                 delete gm;
466         }
467
468         gm = new GainMeter (session->the_auditioner(), *session);
469
470         meter_packer.set_border_width (12);
471         meter_packer.pack_start (*gm, false, true);
472         hpacker.pack_end (meter_packer, false, false);
473         meter_packer.show_all ();
474         start_metering ();
475 }
476
477 void
478 SoundFileBrowser::remove_gain_meter ()
479 {
480         if (gm) {
481                 meter_packer.remove (*gm);
482                 hpacker.remove (meter_packer);
483                 delete gm;
484                 gm = 0;
485         }
486 }
487
488 void
489 SoundFileBrowser::start_metering ()
490 {
491         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
492 }
493
494 void
495 SoundFileBrowser::stop_metering ()
496 {
497         metering_connection.disconnect();
498 }
499
500 void
501 SoundFileBrowser::meter ()
502 {
503         if (is_mapped () && session && gm) {
504                 gm->update_meters ();
505         }
506 }
507
508 bool
509 SoundFileBrowser::on_custom (const FileFilter::Info& filter_info)
510 {
511         return AudioFileSource::safe_file_extension (filter_info.filename);
512 }
513
514 void
515 SoundFileBrowser::update_preview ()
516 {
517         preview.setup_labels (chooser.get_filename());
518
519         if (preview.autoplay()) {
520                 Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
521         }
522 }
523
524 void
525 SoundFileBrowser::found_list_view_selected ()
526 {
527         if (!reset_options ()) {
528                 set_response_sensitive (RESPONSE_OK, false);
529         } else {
530                 ustring file;
531
532                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
533                 
534                 if (!rows.empty()) {
535                         TreeIter iter = found_list->get_iter(*rows.begin());
536                         file = (*iter)[found_list_columns.pathname];
537                         chooser.set_filename (file);
538                         set_response_sensitive (RESPONSE_OK, true);
539                 } else {
540                         set_response_sensitive (RESPONSE_OK, false);
541                 }
542                 
543                 preview.setup_labels (file);
544         }
545 }
546
547 void
548 SoundFileBrowser::found_search_clicked ()
549 {
550         string tag_string = found_entry.get_text ();
551
552         vector<string> tags;
553
554         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
555                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
556                 return;
557         }
558         
559         vector<string> results;
560         Library->search_members_and (results, tags);
561         
562         found_list->clear();
563         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
564                 TreeModel::iterator new_row = found_list->append();
565                 TreeModel::Row row = *new_row;
566                 string path = Glib::filename_from_uri (string ("file:") + *i);
567                 row[found_list_columns.pathname] = path;
568         }
569 }
570
571 vector<ustring>
572 SoundFileBrowser::get_paths ()
573 {
574         vector<ustring> results;
575         
576         int n = notebook.get_current_page ();
577         
578         if (n == 0) {
579                 vector<ustring> filenames = chooser.get_filenames();
580                 vector<ustring>::iterator i;
581
582                 for (i = filenames.begin(); i != filenames.end(); ++i) {
583                         struct stat buf;
584                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
585                                 results.push_back (*i);
586                         }
587                 }
588                 
589         } else {
590                 
591                 typedef TreeView::Selection::ListHandle_Path ListPath;
592                 
593                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
594                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
595                         TreeIter iter = found_list->get_iter(*i);
596                         ustring str = (*iter)[found_list_columns.pathname];
597                         
598                         results.push_back (str);
599                 }
600         }
601
602         return results;
603 }
604
605 void
606 SoundFileOmega::reset_options_noret ()
607 {
608         if (!resetting_ourselves) {
609                 (void) reset_options ();
610         }
611 }
612
613 bool
614 SoundFileOmega::reset_options ()
615 {
616         vector<ustring> paths = get_paths ();
617
618         if (paths.empty()) {
619
620                 channel_combo.set_sensitive (false);
621                 action_combo.set_sensitive (false);
622                 where_combo.set_sensitive (false);
623                 copy_files_btn.set_sensitive (false);
624
625                 return false;
626
627         } else {
628
629                 channel_combo.set_sensitive (true);
630                 action_combo.set_sensitive (true);
631                 where_combo.set_sensitive (true);
632                 copy_files_btn.set_sensitive (true);
633
634         }
635
636         bool same_size;
637         bool src_needed;
638         bool selection_includes_multichannel;
639         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
640         ImportMode mode;
641
642         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
643                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
644                 return false;
645         }
646
647         ustring existing_choice;
648         vector<string> action_strings;
649
650         if (selected_track_cnt > 0) {
651                 if (channel_combo.get_active_text().length()) {
652                         ImportDisposition id = get_channel_disposition();
653                         
654                         switch (id) {
655                         case Editing::ImportDistinctFiles:
656                                 if (selected_track_cnt == paths.size()) {
657                                         action_strings.push_back (_("to selected tracks"));
658                                 }
659                                 break;
660                                 
661                         case Editing::ImportDistinctChannels:
662                                 /* XXX it would be nice to allow channel-per-selected track
663                                    but its too hard we don't want to deal with all the 
664                                    different per-file + per-track channel configurations.
665                                 */
666                                 break;
667                                 
668                         default:
669                                 action_strings.push_back (_("to selected tracks"));
670                                 break;
671                         }
672                 } 
673         }
674
675         action_strings.push_back (_("as new tracks"));
676         action_strings.push_back (_("to the region list"));
677         action_strings.push_back (_("as new tape tracks"));
678
679         resetting_ourselves = true;
680
681         existing_choice = action_combo.get_active_text();
682
683         set_popdown_strings (action_combo, action_strings);
684
685         /* preserve any existing choice, if possible */
686
687
688         if (existing_choice.length()) {
689                 vector<string>::iterator x;
690                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
691                         if (*x == existing_choice) {
692                                 action_combo.set_active_text (existing_choice);
693                                 break;
694                         }
695                 }
696                 if (x == action_strings.end()) {
697                         action_combo.set_active_text (action_strings.front());
698                 }
699         } else {
700                 action_combo.set_active_text (action_strings.front());
701         }
702
703         resetting_ourselves = false;
704
705         if ((mode = get_mode()) == ImportAsRegion) {
706                 where_combo.set_sensitive (false);
707         } else {
708                 where_combo.set_sensitive (true);
709         }
710
711         vector<string> channel_strings;
712         
713         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
714                 channel_strings.push_back (_("one track per file"));
715
716                 if (selection_includes_multichannel) {
717                         channel_strings.push_back (_("one track per channel"));
718                 }
719
720                 if (paths.size() > 1) {
721                         /* tape tracks are a single region per track, so we cannot
722                            sequence multiple files.
723                         */
724                         if (mode != ImportAsTapeTrack) {
725                                 channel_strings.push_back (_("sequence files"));
726                         }
727                         if (same_size) {
728                                 channel_strings.push_back (_("all files in one region"));
729                         }
730                         
731                 }
732
733         } else {
734                 channel_strings.push_back (_("one region per file"));
735
736                 if (selection_includes_multichannel) {
737                         channel_strings.push_back (_("one region per channel"));
738                 }
739
740                 if (paths.size() > 1) {
741                         if (same_size) {
742                                 channel_strings.push_back (_("all files in one region"));
743                         }
744                 }
745         }
746
747         existing_choice = channel_combo.get_active_text();
748
749         set_popdown_strings (channel_combo, channel_strings);
750
751         /* preserve any existing choice, if possible */
752
753         if (existing_choice.length()) {
754                 vector<string>::iterator x;
755                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
756                         if (*x == existing_choice) {
757                                 channel_combo.set_active_text (existing_choice);
758                                 break;
759                         }
760                 }
761                 if (x == channel_strings.end()) {
762                         channel_combo.set_active_text (channel_strings.front());
763                 }
764         } else {
765                 channel_combo.set_active_text (channel_strings.front());
766         }
767
768         if (src_needed) {
769                 src_combo.set_sensitive (true);
770         } else {
771                 src_combo.set_sensitive (false);
772         }
773         
774         if (Config->get_only_copy_imported_files()) {
775
776                 if (selection_can_be_embedded_with_links) {
777                         copy_files_btn.set_sensitive (true);
778                 } else {
779                         copy_files_btn.set_sensitive (false);
780                 }
781
782         }  else {
783
784                 copy_files_btn.set_sensitive (true);
785         }
786         
787         return true;
788 }       
789
790
791 bool
792 SoundFileOmega::bad_file_message()
793 {
794         MessageDialog msg (*this, 
795                            _("One or more of the selected files\ncannot be used by Ardour"),
796                            true,
797                            Gtk::MESSAGE_INFO,
798                            Gtk::BUTTONS_OK);
799         msg.run ();
800         resetting_ourselves = true;
801         chooser.unselect_uri (chooser.get_preview_uri());
802         resetting_ourselves = false;
803
804         return false;
805 }
806
807 bool
808 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
809 {
810         SNDFILE* sf;
811         SF_INFO info;
812         nframes64_t sz = 0;
813         bool err = false;
814
815         same_size = true;
816         src_needed = false;
817         multichannel = false;
818
819         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
820
821                 info.format = 0; // libsndfile says to clear this before sf_open().
822                 
823                 if ((sf = sf_open ((char*) (*i).c_str(), SFM_READ, &info)) != 0) { 
824                         sf_close (sf);
825
826                         if (info.channels > 1) {
827                                 multichannel = true;
828                         }
829
830                         if (sz == 0) {
831                                 sz = info.frames;
832                         } else {
833                                 if (sz != info.frames) {
834                                         same_size = false;
835                                 }
836                         }
837
838                         if ((nframes_t) info.samplerate != session->frame_rate()) {
839                                 src_needed = true;
840                         }
841
842                 } else {
843                         err = true;
844                 }
845         }
846
847         return err;
848 }
849
850
851 bool
852 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
853 {
854         string tmpdir = s.sound_dir();
855         bool ret = false;
856
857         tmpdir += "/linktest";
858
859         if (mkdir (tmpdir.c_str(), 0744)) {
860                 if (errno != EEXIST) {
861                         return false;
862                 }
863         }
864         
865         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
866
867                 char tmpc[MAXPATHLEN+1];
868
869                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
870
871                 /* can we link ? */
872
873                 if (link ((*i).c_str(), tmpc)) {
874                         goto out;
875                 }
876                 
877                 unlink (tmpc);
878         }
879
880         ret = true;
881
882   out:
883         rmdir (tmpdir.c_str());
884         return ret;
885 }
886
887 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
888         : SoundFileBrowser (parent, title, s)
889 {
890         set_size_request (780, 300);
891         chooser.set_select_multiple (false);
892         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
893 }
894
895 void
896 SoundFileChooser::on_hide ()
897 {
898         ArdourDialog::on_hide();
899         stop_metering ();
900
901         if (session) {
902                 session->cancel_audition();
903         }
904 }
905
906 ustring
907 SoundFileChooser::get_filename ()
908 {
909         vector<ustring> paths;
910
911         paths = get_paths ();
912
913         if (paths.empty()) {
914                 return ustring ();
915         }
916         
917         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
918                 return ustring();
919         }
920
921         return paths.front();
922 }
923
924 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks)
925         : SoundFileBrowser (parent, title, s),
926           copy_files_btn ( _("Copy files to session")),
927           selected_track_cnt (selected_tracks)
928 {
929         VBox* vbox;
930         HBox* hbox;
931         vector<string> str;
932
933         set_size_request (-1, 450);
934         
935         block_two.set_border_width (12);
936         block_three.set_border_width (12);
937         block_four.set_border_width (12);
938         
939         options.set_spacing (12);
940
941         str.clear ();
942         str.push_back (_("use file timestamp"));
943         str.push_back (_("at edit cursor"));
944         str.push_back (_("at playhead"));
945         str.push_back (_("at session start"));
946         set_popdown_strings (where_combo, str);
947         where_combo.set_active_text (str.front());
948
949         Label* l = manage (new Label);
950         l->set_text (_("Add files:"));
951         
952         hbox = manage (new HBox);
953         hbox->set_border_width (12);
954         hbox->set_spacing (6);
955         hbox->pack_start (*l, false, false);
956         hbox->pack_start (action_combo, false, false);
957         vbox = manage (new VBox);
958         vbox->pack_start (*hbox, false, false);
959         options.pack_start (*vbox, false, false);
960
961         /* dummy entry for action combo so that it doesn't look odd if we 
962            come up with no tracks selected.
963         */
964
965         str.clear ();
966         str.push_back (_("as new tracks"));
967         set_popdown_strings (action_combo, str);
968         action_combo.set_active_text (str.front());
969         action_combo.set_sensitive (false);
970
971         l = manage (new Label);
972         l->set_text (_("Insert:"));
973
974         hbox = manage (new HBox);
975         hbox->set_border_width (12);
976         hbox->set_spacing (6);
977         hbox->pack_start (*l, false, false);
978         hbox->pack_start (where_combo, false, false);
979         vbox = manage (new VBox);
980         vbox->pack_start (*hbox, false, false);
981         options.pack_start (*vbox, false, false);
982
983
984         l = manage (new Label);
985         l->set_text (_("Mapping:"));
986
987         hbox = manage (new HBox);
988         hbox->set_border_width (12);
989         hbox->set_spacing (6);
990         hbox->pack_start (*l, false, false);
991         hbox->pack_start (channel_combo, false, false);
992         vbox = manage (new VBox);
993         vbox->pack_start (*hbox, false, false);
994         options.pack_start (*vbox, false, false);
995
996         str.clear ();
997         str.push_back (_("one track per file"));
998         set_popdown_strings (channel_combo, str);
999         channel_combo.set_active_text (str.front());
1000         channel_combo.set_sensitive (false);
1001
1002         l = manage (new Label);
1003         l->set_text (_("Conversion Quality:"));
1004
1005         hbox = manage (new HBox);
1006         hbox->set_border_width (12);
1007         hbox->set_spacing (6);
1008         hbox->pack_start (*l, false, false);
1009         hbox->pack_start (src_combo, false, false);
1010         vbox = manage (new VBox);
1011         vbox->pack_start (*hbox, false, false);
1012         options.pack_start (*vbox, false, false);
1013
1014         str.clear ();
1015         str.push_back (_("Best"));
1016         str.push_back (_("Good"));
1017         str.push_back (_("Quick"));
1018         str.push_back (_("Fast"));
1019         str.push_back (_("Fastest"));
1020
1021         set_popdown_strings (src_combo, str);
1022         src_combo.set_active_text (str.front());
1023         src_combo.set_sensitive (false);
1024
1025         reset_options ();
1026
1027         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1028         
1029         copy_files_btn.set_active (true);
1030
1031         block_four.pack_start (copy_files_btn, false, false);
1032
1033         options.pack_start (block_four, false, false);
1034
1035         get_vbox()->pack_start (options, false, false);
1036
1037         /* setup disposition map */
1038
1039         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1040         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1041         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1042         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1043
1044         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1045         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1046         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1047
1048         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1049 }
1050
1051 ImportMode
1052 SoundFileOmega::get_mode () const
1053 {
1054         ustring str = action_combo.get_active_text();
1055
1056         if (str == _("as new tracks")) {
1057                 return ImportAsTrack;
1058         } else if (str == _("to the region list")) {
1059                 return ImportAsRegion;
1060         } else if (str == _("to selected tracks")) {
1061                 return ImportToTrack;
1062         } else {
1063                 return ImportAsTapeTrack;
1064         }
1065 }
1066
1067 void
1068 SoundFileOmega::on_hide ()
1069 {
1070         ArdourDialog::on_hide();
1071         if (session) {
1072                 session->cancel_audition();
1073         }
1074 }
1075
1076 ImportPosition
1077 SoundFileOmega::get_position() const
1078 {
1079         ustring str = where_combo.get_active_text();
1080
1081         if (str == _("use file timestamp")) {
1082                 return ImportAtTimestamp;
1083         } else if (str == _("at edit cursor")) {
1084                 return ImportAtEditCursor;
1085         } else if (str == _("at playhead")) {
1086                 return ImportAtPlayhead;
1087         } else {
1088                 return ImportAtStart;
1089         }
1090 }
1091
1092 SrcQuality
1093 SoundFileOmega::get_src_quality() const
1094 {
1095         ustring str = where_combo.get_active_text();
1096
1097         if (str == _("Best")) {
1098                 return SrcBest;
1099         } else if (str == _("Good")) {
1100                 return SrcGood;
1101         } else if (str == _("Quick")) {
1102                 return SrcQuick;
1103         } else if (str == _("Fast")) {
1104                 return SrcFast;
1105         } else {
1106                 return SrcFastest;
1107         }
1108 }
1109
1110 ImportDisposition
1111 SoundFileOmega::get_channel_disposition () const
1112 {
1113         /* we use a map here because the channel combo can contain different strings
1114            depending on the state of the other combos. the map contains all possible strings
1115            and the ImportDisposition enum that corresponds to it.
1116         */
1117
1118         ustring str = channel_combo.get_active_text();
1119         DispositionMap::const_iterator x = disposition_map.find (str);
1120
1121         if (x == disposition_map.end()) {
1122                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1123                 /*NOTREACHED*/
1124         }
1125
1126         return x->second;
1127 }
1128
1129 void
1130 SoundFileOmega::reset (int selected_tracks)
1131 {
1132         selected_track_cnt = selected_tracks;
1133         reset_options ();
1134 }       
1135
1136 void
1137 SoundFileOmega::file_selection_changed ()
1138 {
1139         if (resetting_ourselves) {
1140                 return;
1141         }
1142
1143         if (!reset_options ()) {
1144                 set_response_sensitive (RESPONSE_OK, false);
1145         } else {
1146                 if (chooser.get_filenames().size() > 0) {
1147                         set_response_sensitive (RESPONSE_OK, true);
1148                 } else {
1149                         set_response_sensitive (RESPONSE_OK, false);
1150                 }
1151         }
1152 }
1153