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