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