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