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