merge with master
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <map>
25 #include <cerrno>
26 #include <sstream>
27
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/param.h>
31
32 #include <gtkmm/box.h>
33 #include <gtkmm/stock.h>
34 #include <glibmm/fileutils.h>
35
36 #include "pbd/convert.h"
37 #include "pbd/tokenizer.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/xml++.h"
41
42 #include <gtkmm2ext/utils.h>
43
44 #include "evoral/SMF.hpp"
45
46 #include "ardour/audio_library.h"
47 #include "ardour/auditioner.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/audiofilesource.h"
50 #include "ardour/smf_source.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/source_factory.h"
53 #include "ardour/session.h"
54 #include "ardour/session_directory.h"
55
56 #include "ardour_ui.h"
57 #include "editing.h"
58 #include "gui_thread.h"
59 #include "prompter.h"
60 #include "sfdb_ui.h"
61 #include "editing.h"
62 #include "utils.h"
63 #include "gain_meter.h"
64 #include "main_clock.h"
65 #include "public_editor.h"
66
67 #ifdef FREESOUND
68 #include "sfdb_freesound_mootcher.h"
69 #endif
70
71 #include "i18n.h"
72
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace std;
76 using namespace Gtk;
77 using namespace Gtkmm2ext;
78 using namespace Editing;
79
80 using std::string;
81
82 string SoundFileBrowser::persistent_folder;
83
84 static ImportMode
85 string2importmode (string str)
86 {
87         if (str == _("as new tracks")) {
88                 return ImportAsTrack;
89         } else if (str == _("to selected tracks")) {
90                 return ImportToTrack;
91         } else if (str == _("to region list")) {
92                 return ImportAsRegion;
93         } else if (str == _("as new tape tracks")) {
94                 return ImportAsTapeTrack;
95         }
96
97         warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
98
99         return ImportAsTrack;
100 }
101
102 static string
103 importmode2string (ImportMode mode)
104 {
105         switch (mode) {
106         case ImportAsTrack:
107                 return _("as new tracks");
108         case ImportToTrack:
109                 return _("to selected tracks");
110         case ImportAsRegion:
111                 return _("to region list");
112         case ImportAsTapeTrack:
113                 return _("as new tape tracks");
114         }
115         /*NOTREACHED*/
116         return _("as new tracks");
117 }
118
119 SoundFileBox::SoundFileBox (bool persistent)
120         : table (6, 2),
121           length_clock ("sfboxLengthClock", !persistent, "", false, false, true, false),
122           timecode_clock ("sfboxTimecodeClock", !persistent, "", false, false, false, false),
123           main_box (false, 6),
124           autoplay_btn (_("Auto-play"))
125
126 {
127         set_name (X_("SoundFileBox"));
128         set_size_request (300, -1);
129
130         preview_label.set_markup (_("<b>Sound File Information</b>"));
131
132         border_frame.set_label_widget (preview_label);
133         border_frame.add (main_box);
134
135         pack_start (border_frame, true, true);
136         set_border_width (6);
137
138         main_box.set_border_width (6);
139
140         length.set_text (_("Length:"));
141         length.set_alignment (1, 0.5);
142         timecode.set_text (_("Timestamp:"));
143         timecode.set_alignment (1, 0.5);
144         format.set_text (_("Format:"));
145         format.set_alignment (1, 0.5);
146         channels.set_text (_("Channels:"));
147         channels.set_alignment (1, 0.5);
148         samplerate.set_text (_("Sample rate:"));
149         samplerate.set_alignment (1, 0.5);
150
151         preview_label.set_max_width_chars (50);
152         preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
153
154         format_text.set_max_width_chars (20);
155         format_text.set_ellipsize (Pango::ELLIPSIZE_END);
156         format_text.set_alignment (0, 1);
157
158         table.set_col_spacings (6);
159         table.set_homogeneous (false);
160         table.set_row_spacings (6);
161
162         table.attach (channels, 0, 1, 0, 1, FILL, FILL);
163         table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
164         table.attach (format, 0, 1, 2, 4, FILL, FILL);
165         table.attach (length, 0, 1, 4, 5, FILL, FILL);
166         table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
167
168         table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
169         table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
170         table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
171         table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
172         table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
173
174         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
175         timecode_clock.set_mode (AudioClock::Timecode);
176
177         main_box.pack_start (table, false, false);
178
179         tags_entry.set_editable (true);
180         tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
181         tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
182
183         Label* label = manage (new Label (_("Tags:")));
184         label->set_alignment (0.0f, 0.5f);
185         main_box.pack_start (*label, false, false);
186         main_box.pack_start (tags_entry, true, true);
187
188         main_box.pack_start (bottom_box, false, false);
189
190         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
191 //      play_btn.set_label (_("Play"));
192
193         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
194 //      stop_btn.set_label (_("Stop"));
195
196         bottom_box.set_homogeneous (false);
197         bottom_box.set_spacing (6);
198         bottom_box.pack_start(play_btn, true, true);
199         bottom_box.pack_start(stop_btn, true, true);
200         bottom_box.pack_start(autoplay_btn, false, false);
201
202         play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
203         stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
204
205         channels_value.set_alignment (0.0f, 0.5f);
206         samplerate_value.set_alignment (0.0f, 0.5f);
207 }
208
209 void
210 SoundFileBox::set_session(Session* s)
211 {
212         SessionHandlePtr::set_session (s);
213
214         length_clock.set_session (s);
215         timecode_clock.set_session (s);
216
217         if (!_session) {
218                 play_btn.set_sensitive (false);
219                 stop_btn.set_sensitive (false);
220         }
221 }
222
223 bool
224 SoundFileBox::setup_labels (const string& filename)
225 {
226         if (!path.empty()) {
227                 // save existing tags
228                 tags_changed ();
229         }
230
231         path = filename;
232
233         string error_msg;
234
235         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
236
237                 preview_label.set_markup (_("<b>Sound File Information</b>"));
238                 format_text.set_text ("");
239                 channels_value.set_text ("");
240                 samplerate_value.set_text ("");
241                 tags_entry.get_buffer()->set_text ("");
242
243                 length_clock.set (0);
244                 timecode_clock.set (0);
245
246                 tags_entry.set_sensitive (false);
247                 play_btn.set_sensitive (false);
248
249                 return false;
250         }
251
252         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
253         std::string n = sf_info.format_name;
254         if (n.substr (0, 8) == X_("Format: ")) {
255                 n = n.substr (8);
256         }
257         format_text.set_text (n);
258         channels_value.set_text (to_string (sf_info.channels, std::dec));
259
260         if (_session && sf_info.samplerate != _session->frame_rate()) {
261                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
262                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
263                 samplerate_value.set_name ("NewSessionSR1Label");
264                 samplerate.set_name ("NewSessionSR1Label");
265         } else {
266                 samplerate.set_text (_("Sample rate:"));
267                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
268                 samplerate_value.set_name ("NewSessionSR2Label");
269                 samplerate.set_name ("NewSessionSR2Label");
270         }
271
272         framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
273         double src_coef = (double) nfr / sf_info.samplerate;
274
275         length_clock.set (sf_info.length * src_coef + 0.5, true);
276         timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
277
278         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
279
280         vector<string> tags = Library->get_tags (string ("//") + filename);
281
282         stringstream tag_string;
283         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
284                 if (i != tags.begin()) {
285                         tag_string << ", ";
286                 }
287                 tag_string << *i;
288         }
289         tags_entry.get_buffer()->set_text (tag_string.str());
290
291         tags_entry.set_sensitive (true);
292         if (_session) {
293                 play_btn.set_sensitive (true);
294         }
295
296         return true;
297 }
298
299 bool
300 SoundFileBox::autoplay() const
301 {
302         return autoplay_btn.get_active();
303 }
304
305 bool
306 SoundFileBox::audition_oneshot()
307 {
308         audition ();
309         return false;
310 }
311
312 void
313 SoundFileBox::audition ()
314 {
315         if (!_session) {
316                 return;
317         }
318
319         if (SMFSource::safe_midi_file_extension (path)) {
320                 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
321                 return;
322         }
323
324         _session->cancel_audition();
325
326         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
327                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
328                 return;
329         }
330
331         boost::shared_ptr<Region> r;
332         SourceList srclist;
333         boost::shared_ptr<AudioFileSource> afs;
334         bool old_sbp = AudioSource::get_build_peakfiles ();
335
336         /* don't even think of building peakfiles for these files */
337
338         AudioSource::set_build_peakfiles (false);
339
340         for (int n = 0; n < sf_info.channels; ++n) {
341                 try {
342                         afs = boost::dynamic_pointer_cast<AudioFileSource> (
343                                 SourceFactory::createExternal (DataType::AUDIO, *_session,
344                                                                path, n, Source::Flag (0), false));
345                         
346                         srclist.push_back(afs);
347
348                 } catch (failed_constructor& err) {
349                         error << _("Could not access soundfile: ") << path << endmsg;
350                         AudioSource::set_build_peakfiles (old_sbp);
351                         return;
352                 }
353         }
354
355         AudioSource::set_build_peakfiles (old_sbp);
356
357         if (srclist.empty()) {
358                 return;
359         }
360
361         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
362         string rname = region_name_from_path (afs->path(), false);
363
364         PropertyList plist;
365
366         plist.add (ARDOUR::Properties::start, 0);
367         plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
368         plist.add (ARDOUR::Properties::name, rname);
369         plist.add (ARDOUR::Properties::layer, 0);
370
371         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
372
373         _session->audition_region(r);
374 }
375
376 void
377 SoundFileBox::stop_audition ()
378 {
379         if (_session) {
380                 _session->cancel_audition();
381         }
382 }
383
384 bool
385 SoundFileBox::tags_entry_left (GdkEventFocus *)
386 {
387         tags_changed ();
388         return false;
389 }
390
391 void
392 SoundFileBox::tags_changed ()
393 {
394         string tag_string = tags_entry.get_buffer()->get_text ();
395
396         if (tag_string.empty()) {
397                 return;
398         }
399
400         vector<string> tags;
401
402         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
403                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
404                 return;
405         }
406
407         save_tags (tags);
408 }
409
410 void
411 SoundFileBox::save_tags (const vector<string>& tags)
412 {
413         Library->set_tags (string ("//") + path, tags);
414         Library->save_changes ();
415 }
416
417 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
418         : ArdourWindow (title)
419         , found_list (ListStore::create(found_list_columns))
420         , freesound_list (ListStore::create(freesound_list_columns))
421         , chooser (FILE_CHOOSER_ACTION_OPEN)
422         , preview (persistent)
423         , found_search_btn (_("Search"))
424         , found_list_view (found_list)
425         , freesound_search_btn (_("Search"))
426         , freesound_list_view (freesound_list)
427         , resetting_ourselves (false)
428         , matches (0)
429         , _status (0)
430         , _done (false)
431         , ok_button (Stock::OK)
432         , cancel_button (Stock::CANCEL)
433         , apply_button (Stock::APPLY)
434         , gm (0)
435 {
436
437 #ifdef GTKOSX
438         chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
439         chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
440         chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
441         chooser.add_shortcut_folder_uri("file:///Volumes");
442 #endif
443
444         //add the file chooser
445
446         chooser.set_border_width (12);
447         
448         audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
449         audio_and_midi_filter.set_name (_("Audio and MIDI files"));
450         
451         audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
452         audio_filter.set_name (_("Audio files"));
453         
454         midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
455         midi_filter.set_name (_("MIDI files"));
456         
457         matchall_filter.add_pattern ("*.*");
458         matchall_filter.set_name (_("All files"));
459         
460         chooser.add_filter (audio_and_midi_filter);
461         chooser.add_filter (audio_filter);
462         chooser.add_filter (midi_filter);
463         chooser.add_filter (matchall_filter);
464         chooser.set_select_multiple (true);
465         chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
466         chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
467
468 #ifdef GTKOSX
469         /* some broken redraw behaviour - this is a bandaid */
470         chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
471 #endif
472         
473         if (!persistent_folder.empty()) {
474                 chooser.set_current_folder (persistent_folder);
475         }
476
477         notebook.append_page (chooser, _("Browse Files"));
478         
479         hpacker.set_spacing (6);
480         hpacker.pack_start (notebook, true, true);
481         hpacker.pack_start (preview, false, false);
482
483         vpacker.set_spacing (6);
484         vpacker.pack_start (hpacker, true, true);
485
486         add (vpacker);
487
488         //add tag search
489
490         VBox* vbox;
491         HBox* hbox;
492         
493         
494         hbox = manage(new HBox);
495         hbox->pack_start (found_entry);
496         hbox->pack_start (found_search_btn);
497         
498         Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
499         scroll->add(found_list_view);
500         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
501         
502         vbox = manage(new VBox);
503         vbox->pack_start (*hbox, PACK_SHRINK);
504         vbox->pack_start (*scroll);
505         
506         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
507         
508         found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
509         
510         found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
511         
512         found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
513         found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
514         
515         freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
516         
517         notebook.append_page (*vbox, _("Search Tags"));
518
519 #ifdef FREESOUND
520
521         //add freesound search
522
523         HBox* passbox;
524         Label* label;
525         
526         passbox = manage(new HBox);
527         passbox->set_spacing (6);
528         
529         label = manage (new Label);
530         label->set_text (_("Tags:"));
531         passbox->pack_start (*label, false, false);
532         passbox->pack_start (freesound_entry, true, true);
533         
534         label = manage (new Label);
535         label->set_text (_("Sort:"));
536         passbox->pack_start (*label, false, false);
537         passbox->pack_start (freesound_sort, false, false);
538         freesound_sort.clear_items();
539         
540         // Order of the following must correspond with enum sortMethod
541         // in sfdb_freesound_mootcher.h 
542         freesound_sort.append_text(_("None"));
543         freesound_sort.append_text(_("Longest"));
544         freesound_sort.append_text(_("Shortest"));
545         freesound_sort.append_text(_("Newest"));
546         freesound_sort.append_text(_("Oldest"));
547         freesound_sort.append_text(_("Most downloaded"));
548         freesound_sort.append_text(_("Least downloaded"));
549         freesound_sort.append_text(_("Highest rated"));
550         freesound_sort.append_text(_("Lowest rated"));
551         freesound_sort.set_active(0);
552         
553         passbox->pack_start (freesound_search_btn, false, false);
554         passbox->pack_start (freesound_more_btn, false, false);
555         freesound_more_btn.set_label(_("More"));
556         freesound_more_btn.set_sensitive(false);
557
558         passbox->pack_end   (freesound_stop_btn, false, false);
559         freesound_stop_btn.set_label(_("Stop"));
560         freesound_stop_btn.set_sensitive(false);
561         
562         scroll = manage(new ScrolledWindow);
563         scroll->add(freesound_list_view);
564         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
565         
566         vbox = manage(new VBox);
567         vbox->set_spacing (3);
568         vbox->pack_start (*passbox, PACK_SHRINK);
569         vbox->pack_start (freesound_progress_bar, PACK_SHRINK);
570         vbox->pack_start (*scroll);
571         
572         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
573         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
574         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
575         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
576         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
577         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
578         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
579         freesound_list_view.get_column(0)->set_alignment(0.5);
580         freesound_list_view.get_column(1)->set_expand(true);
581         freesound_list_view.get_column(2)->set_alignment(0.5);
582         freesound_list_view.get_column(3)->set_alignment(0.5);
583         freesound_list_view.get_column(4)->set_alignment(0.5);
584         freesound_list_view.get_column(5)->set_alignment(0.5);
585         
586         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
587
588         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
589         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
590         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
591         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
592         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
593         freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
594         notebook.append_page (*vbox, _("Search Freesound"));
595 #endif
596
597         notebook.set_size_request (500, -1);
598         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
599
600         set_session (s);
601
602         Gtk::HButtonBox* button_box = manage (new HButtonBox);
603
604         button_box->set_layout (BUTTONBOX_END);
605         button_box->pack_start (cancel_button, false, false);
606         cancel_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CANCEL));
607         if (persistent) {
608                 button_box->pack_start (apply_button, false, false);
609                 apply_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_APPLY));
610         }
611
612         button_box->pack_start (ok_button, false, false);
613         ok_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
614
615         Gtkmm2ext::UI::instance()->set_tip (ok_button, _("Press to import selected files and close this window"));
616         Gtkmm2ext::UI::instance()->set_tip (apply_button, _("Press to import selected files and leave this window open"));
617         Gtkmm2ext::UI::instance()->set_tip (cancel_button, _("Press to close this window without importing any files"));
618
619         vpacker.pack_end (*button_box, false, false);
620
621         set_wmclass (X_("import"), PROGRAM_NAME);
622 }
623
624 SoundFileBrowser::~SoundFileBrowser ()
625 {
626         persistent_folder = chooser.get_current_folder();
627 }
628
629 int
630 SoundFileBrowser::run ()
631 {
632         set_modal (true);
633         show_all ();
634         present ();
635
636         _done = false;
637
638         while (!_done) {
639                 gtk_main_iteration ();
640         }
641
642         return _status;
643 }
644
645 void
646 SoundFileBrowser::set_action_sensitive (bool yn)
647 {
648         ok_button.set_sensitive (yn);
649         apply_button.set_sensitive (yn);
650 }
651
652 void
653 SoundFileBrowser::do_something (int action)
654 {
655         _done = true;
656         _status = action;
657 }
658
659 void
660 SoundFileBrowser::on_show ()
661 {
662         ArdourWindow::on_show ();
663         start_metering ();
664 }
665
666 void
667 SoundFileBrowser::clear_selection ()
668 {
669         chooser.unselect_all ();
670         found_list_view.get_selection()->unselect_all ();
671 }
672
673 void
674 SoundFileBrowser::chooser_file_activated ()
675 {
676         preview.audition ();
677 }
678
679 void
680 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
681 {
682         preview.audition ();
683 }
684
685 void
686 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
687 {
688         preview.audition ();
689 }
690
691 void
692 SoundFileBrowser::set_session (Session* s)
693 {
694         ArdourWindow::set_session (s);
695         preview.set_session (s);
696
697         if (_session) {
698                 add_gain_meter ();
699         } else {
700                 remove_gain_meter ();
701         }
702 }
703
704 void
705 SoundFileBrowser::add_gain_meter ()
706 {
707         delete gm;
708
709         gm = new GainMeter (_session, 250);
710
711         boost::shared_ptr<Route> r = _session->the_auditioner ();
712
713         gm->set_controls (r, r->shared_peak_meter(), r->amp());
714         gm->set_fader_name (X_("AudioTrackFader"));
715
716         meter_packer.set_border_width (12);
717         meter_packer.pack_start (*gm, false, true);
718         hpacker.pack_end (meter_packer, false, false);
719         meter_packer.show_all ();
720         start_metering ();
721 }
722
723 void
724 SoundFileBrowser::remove_gain_meter ()
725 {
726         if (gm) {
727                 meter_packer.remove (*gm);
728                 hpacker.remove (meter_packer);
729                 delete gm;
730                 gm = 0;
731         }
732 }
733
734 void
735 SoundFileBrowser::start_metering ()
736 {
737         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
738 }
739
740 void
741 SoundFileBrowser::stop_metering ()
742 {
743         metering_connection.disconnect();
744 }
745
746 void
747 SoundFileBrowser::meter ()
748 {
749         if (is_mapped () && _session && gm) {
750                 gm->update_meters ();
751         }
752 }
753
754 bool
755 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
756 {
757         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
758 }
759
760 bool
761 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
762 {
763         return SMFSource::safe_midi_file_extension (filter_info.filename);
764 }
765
766 bool
767 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
768 {
769         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
770 }
771
772 void
773 SoundFileBrowser::update_preview ()
774 {
775         if (preview.setup_labels (chooser.get_preview_filename())) {
776                 if (preview.autoplay()) {
777                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
778                 }
779         }
780 }
781
782 void
783 SoundFileBrowser::found_list_view_selected ()
784 {
785         if (!reset_options ()) {
786                 set_action_sensitive (false);
787         } else {
788                 string file;
789
790                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
791
792                 if (!rows.empty()) {
793                         TreeIter iter = found_list->get_iter(*rows.begin());
794                         file = (*iter)[found_list_columns.pathname];
795                         chooser.set_filename (file);
796                         set_action_sensitive (true);
797                 } else {
798                         set_action_sensitive (false);
799                 }
800
801                 preview.setup_labels (file);
802         }
803 }
804
805 void
806 SoundFileBrowser::freesound_list_view_selected ()
807 {
808         freesound_download_cancel = false;
809         freesound_stop_btn.set_sensitive(true);
810
811 #ifdef FREESOUND
812         if (!reset_options ()) {
813                 set_action_sensitive (false);
814         } else {
815                 Mootcher mootcher; 
816                 string file;
817
818                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
819
820                 if (!rows.empty()) {
821                         TreeIter iter = freesound_list->get_iter(*rows.begin());
822
823                         string id  = (*iter)[freesound_list_columns.id];
824                         string uri = (*iter)[freesound_list_columns.uri];
825                         string ofn = (*iter)[freesound_list_columns.filename];
826
827                         // download the sound file                      
828                         GdkCursor *prev_cursor;
829                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
830                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
831                         gdk_flush();
832
833                         file = mootcher.getAudioFile(ofn, id, uri, this);
834
835                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
836
837                         if (file != "") {
838                                 chooser.set_filename (file);
839                                 set_action_sensitive (true);
840                         }
841                 } else {
842                         set_action_sensitive (false);
843                 }
844
845                 freesound_progress_bar.set_text(
846                         string_compose(P_("found %1 match", "found %1 matches", matches), matches));
847
848                 preview.setup_labels (file);
849         }
850 #endif
851         freesound_stop_btn.set_sensitive(false);
852 }
853
854 void
855 SoundFileBrowser::found_search_clicked ()
856 {
857         string tag_string = found_entry.get_text ();
858
859         vector<string> tags;
860
861         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
862                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
863                 return;
864         }
865
866         vector<string> results;
867         Library->search_members_and (results, tags);
868
869         found_list->clear();
870         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
871                 TreeModel::iterator new_row = found_list->append();
872                 TreeModel::Row row = *new_row;
873                 string path = Glib::filename_from_uri (string ("file:") + *i);
874                 row[found_list_columns.pathname] = path;
875         }
876 }
877
878 void
879 SoundFileBrowser::freesound_search_clicked ()
880 {
881         freesound_page = 1;
882         freesound_list->clear();
883         matches = 0;
884         freesound_search();
885 }
886
887 void
888 SoundFileBrowser::freesound_more_clicked ()
889 {
890         char row_path[21];
891         freesound_page++;
892         freesound_search();
893         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
894         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
895 }
896
897 void
898 SoundFileBrowser::freesound_stop_clicked ()
899 {
900         freesound_download_cancel = true;
901 }
902
903
904 void
905 SoundFileBrowser::freesound_search()
906 {
907 #ifdef FREESOUND
908         Mootcher mootcher;
909         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_GROW_ONLY);
910
911         string search_string = freesound_entry.get_text ();
912         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
913
914         GdkCursor *prev_cursor;
915         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
916         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
917         freesound_progress_bar.set_fraction(0.0);
918         gdk_flush();
919
920         std::string theString = mootcher.searchText(
921                         search_string, 
922                         freesound_page,
923 #ifdef GTKOSX
924                         "", // OSX eats anything incl mp3
925 #else
926                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
927 #endif
928                         sort_method
929                         );
930
931         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
932
933         XMLTree doc;
934         doc.read_buffer( theString );
935         XMLNode *root = doc.root();
936
937         if (!root) {
938                 error << "no root XML node!" << endmsg;
939                 return;
940         }
941
942         if ( strcmp(root->name().c_str(), "response") != 0) {
943                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
944                 return;
945         }
946
947         // find out how many pages are available to search
948         int freesound_n_pages = 1;
949         XMLNode *res = root->child("num_pages");
950         if (res) {
951                 string result = res->child("text")->content();
952                 freesound_n_pages = atoi(result.c_str());
953         }
954
955         int more_pages = freesound_n_pages - freesound_page;
956
957         if (more_pages > 0) {
958                 freesound_more_btn.set_sensitive(true);
959                 freesound_more_btn.set_tooltip_text(string_compose(P_(
960                                                 "%1 more page of 100 results available",
961                                                 "%1 more pages of 100 results available",
962                                                 more_pages), more_pages));
963         } else {
964                 freesound_more_btn.set_sensitive(false);
965                 freesound_more_btn.set_tooltip_text(_("No more results available"));
966         }
967
968         XMLNode *sounds_root = root->child("sounds");
969         if (!sounds_root) {
970                 error << "no child node \"sounds\" found!" << endmsg;
971                 return;
972         }
973
974         XMLNodeList sounds = sounds_root->children();
975         if (sounds.size() == 0) {
976                 /* nothing found */
977                 return;
978         }
979
980         XMLNodeConstIterator niter;
981         XMLNode *node;
982         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
983                 node = *niter;
984                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
985                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
986                         break;
987                 }
988
989                 // node->dump(cerr, "node:");
990
991
992                 XMLNode *id_node  = node->child ("id");
993                 XMLNode *uri_node = node->child ("serve");
994                 XMLNode *ofn_node = node->child ("original_filename");
995                 XMLNode *dur_node = node->child ("duration");
996                 XMLNode *siz_node = node->child ("filesize");
997                 XMLNode *srt_node = node->child ("samplerate");
998                 XMLNode *lic_node = node->child ("license");
999
1000                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1001
1002                         std::string  id =  id_node->child("text")->content();
1003                         std::string uri = uri_node->child("text")->content();
1004                         std::string ofn = ofn_node->child("text")->content();
1005                         std::string dur = dur_node->child("text")->content();
1006                         std::string siz = siz_node->child("text")->content();
1007                         std::string srt = srt_node->child("text")->content();
1008                         std::string lic = lic_node->child("text")->content();
1009
1010                         std::string r;
1011                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1012
1013                         double duration_seconds = atof(dur.c_str());
1014                         double h, m, s;
1015                         char duration_hhmmss[16];
1016                         if (duration_seconds >= 99 * 60 * 60) {
1017                                 strcpy(duration_hhmmss, ">99h");
1018                         } else {
1019                                 s = modf(duration_seconds/60, &m) * 60;
1020                                 m = modf(m/60, &h) * 60;
1021                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1022                                                 h, m, s
1023                                        );
1024                         }
1025
1026                         double size_bytes = atof(siz.c_str());
1027                         char bsize[32];
1028                         if (size_bytes < 1000) {
1029                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1030                         } else if (size_bytes < 1000000 ) {
1031                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1032                         } else if (size_bytes < 10000000) {
1033                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1034                         } else if (size_bytes < 1000000000) {
1035                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1036                         } else {
1037                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1038                         }
1039
1040                         /* see http://www.freesound.org/help/faq/#licenses */
1041                         char shortlicense[64];
1042                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1043                                 sprintf(shortlicense, "CC-BY-NC");
1044                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1045                                 sprintf(shortlicense, "CC-BY");
1046                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1047                                 sprintf(shortlicense, "sampling+");
1048                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1049                                 sprintf(shortlicense, "PD");
1050                         } else {
1051                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1052                                 shortlicense[63]= '\0';
1053                         }
1054
1055                         TreeModel::iterator new_row = freesound_list->append();
1056                         TreeModel::Row row = *new_row;
1057
1058                         row[freesound_list_columns.id      ] = id;
1059                         row[freesound_list_columns.uri     ] = uri;
1060                         row[freesound_list_columns.filename] = ofn;
1061                         row[freesound_list_columns.duration] = duration_hhmmss;
1062                         row[freesound_list_columns.filesize] = bsize;
1063                         row[freesound_list_columns.smplrate] = srt;
1064                         row[freesound_list_columns.license ] = shortlicense;
1065                         matches++;
1066                 }
1067         }
1068
1069         if (matches == 0) {
1070                 freesound_progress_bar.set_text(_("Search returned no results."));
1071         } else {
1072                 freesound_progress_bar.set_text(string_compose(P_("Found %1 match", "Found %1 matches", matches), matches));
1073         }
1074         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_AUTOSIZE);
1075 #endif
1076 }
1077
1078 vector<string>
1079 SoundFileBrowser::get_paths ()
1080 {
1081         vector<string> results;
1082
1083         int n = notebook.get_current_page ();
1084
1085         if (n == 0) {
1086                 vector<string> filenames = chooser.get_filenames();
1087                 vector<string>::iterator i;
1088
1089                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1090                         struct stat buf;
1091                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1092                                 results.push_back (*i);
1093                         }
1094                 }
1095
1096         } else if (n==1){
1097
1098                 typedef TreeView::Selection::ListHandle_Path ListPath;
1099
1100                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1101                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1102                         TreeIter iter = found_list->get_iter(*i);
1103                         string str = (*iter)[found_list_columns.pathname];
1104
1105                         results.push_back (str);
1106                 }
1107         } else {
1108 #ifdef FREESOUND
1109                 typedef TreeView::Selection::ListHandle_Path ListPath;
1110                 Mootcher mootcher;
1111
1112                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1113                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1114                         TreeIter iter = freesound_list->get_iter(*i);
1115                         string id  = (*iter)[freesound_list_columns.id];
1116                         string uri = (*iter)[freesound_list_columns.uri];
1117                         string ofn = (*iter)[freesound_list_columns.filename];
1118
1119                         GdkCursor *prev_cursor;
1120                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1121                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1122                         gdk_flush();
1123
1124                         string str = mootcher.getAudioFile(ofn, id, uri, this);
1125                         if (str != "") {
1126                                 results.push_back (str);
1127                         }
1128                         
1129                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1130
1131                 }
1132 #endif
1133         }
1134
1135         return results;
1136 }
1137
1138 void
1139 SoundFileOmega::reset_options_noret ()
1140 {
1141         if (!resetting_ourselves) {
1142                 (void) reset_options ();
1143         }
1144 }
1145
1146 bool
1147 SoundFileOmega::reset_options ()
1148 {
1149         vector<string> paths = get_paths ();
1150
1151         if (paths.empty()) {
1152
1153                 channel_combo.set_sensitive (false);
1154                 action_combo.set_sensitive (false);
1155                 where_combo.set_sensitive (false);
1156                 copy_files_btn.set_active (true);
1157                 copy_files_btn.set_sensitive (false);
1158
1159                 return false;
1160
1161         } else {
1162
1163                 channel_combo.set_sensitive (true);
1164                 action_combo.set_sensitive (true);
1165                 where_combo.set_sensitive (true);
1166
1167                 /* if we get through this function successfully, this may be
1168                    reset at the end, once we know if we can use hard links
1169                    to do embedding (or if we are importing a MIDI file).
1170                 */
1171
1172                 if (Config->get_only_copy_imported_files()) {
1173                         copy_files_btn.set_sensitive (false);
1174                 } else {
1175                         copy_files_btn.set_sensitive (false);
1176                 }
1177         }
1178
1179         bool same_size;
1180         bool src_needed;
1181         bool selection_includes_multichannel;
1182         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1183         ImportMode mode;
1184
1185         /* See if we are thinking about importing any MIDI files */
1186         vector<string>::iterator i = paths.begin ();
1187         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1188                 ++i;
1189         }
1190         bool const have_a_midi_file = (i != paths.end ());
1191
1192         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1193                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1194                 return false;
1195         }
1196
1197         string existing_choice;
1198         vector<string> action_strings;
1199
1200         resetting_ourselves = true;
1201
1202         if (chooser.get_filter() == &audio_filter) {
1203
1204                 /* AUDIO */
1205
1206                 if (selected_audio_track_cnt > 0) {
1207                         if (channel_combo.get_active_text().length()) {
1208                                 ImportDisposition id = get_channel_disposition();
1209                                 
1210                                 switch (id) {
1211                                 case Editing::ImportDistinctFiles:
1212                                         if (selected_audio_track_cnt == paths.size()) {
1213                                                 action_strings.push_back (importmode2string (ImportToTrack));
1214                                         }
1215                                         break;
1216                                         
1217                                 case Editing::ImportDistinctChannels:
1218                                         /* XXX it would be nice to allow channel-per-selected track
1219                                            but its too hard we don't want to deal with all the
1220                                            different per-file + per-track channel configurations.
1221                                         */
1222                                         break;
1223                                         
1224                                 default:
1225                                         action_strings.push_back (importmode2string (ImportToTrack));
1226                                         break;
1227                                 }
1228                         }
1229                 }
1230                 
1231         }  else {
1232
1233                 /* MIDI ONLY */
1234
1235                 if (selected_midi_track_cnt > 0) {
1236                         action_strings.push_back (importmode2string (ImportToTrack));
1237                 }
1238         }
1239
1240         action_strings.push_back (importmode2string (ImportAsTrack));
1241         action_strings.push_back (importmode2string (ImportAsRegion));
1242         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1243
1244         existing_choice = action_combo.get_active_text();
1245
1246         set_popdown_strings (action_combo, action_strings);
1247
1248         /* preserve any existing choice, if possible */
1249
1250
1251         if (existing_choice.length()) {
1252                 vector<string>::iterator x;
1253                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1254                         if (*x == existing_choice) {
1255                                 action_combo.set_active_text (existing_choice);
1256                                 break;
1257                         }
1258                 }
1259                 if (x == action_strings.end()) {
1260                         action_combo.set_active_text (action_strings.front());
1261                 }
1262         } else {
1263                 action_combo.set_active_text (action_strings.front());
1264         }
1265
1266         resetting_ourselves = false;
1267
1268         if ((mode = get_mode()) == ImportAsRegion) {
1269                 where_combo.set_sensitive (false);
1270         } else {
1271                 where_combo.set_sensitive (true);
1272         }
1273
1274         vector<string> channel_strings;
1275
1276         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1277                 channel_strings.push_back (_("one track per file"));
1278
1279                 if (selection_includes_multichannel) {
1280                         channel_strings.push_back (_("one track per channel"));
1281                 }
1282
1283                 if (paths.size() > 1) {
1284                         /* tape tracks are a single region per track, so we cannot
1285                            sequence multiple files.
1286                         */
1287                         if (mode != ImportAsTapeTrack) {
1288                                 channel_strings.push_back (_("sequence files"));
1289                         }
1290                         if (same_size) {
1291                                 channel_strings.push_back (_("all files in one track"));
1292                                 channel_strings.push_back (_("merge files"));
1293                         }
1294
1295                 }
1296
1297         } else {
1298                 channel_strings.push_back (_("one region per file"));
1299
1300                 if (selection_includes_multichannel) {
1301                         channel_strings.push_back (_("one region per channel"));
1302                 }
1303
1304                 if (paths.size() > 1) {
1305                         if (same_size) {
1306                                 channel_strings.push_back (_("all files in one region"));
1307                         }
1308                 }
1309         }
1310
1311         resetting_ourselves = true;
1312
1313         existing_choice = channel_combo.get_active_text();
1314
1315         set_popdown_strings (channel_combo, channel_strings);
1316
1317         /* preserve any existing choice, if possible */
1318
1319         if (existing_choice.length()) {
1320                 vector<string>::iterator x;
1321                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1322                         if (*x == existing_choice) {
1323                                 channel_combo.set_active_text (existing_choice);
1324                                 break;
1325                         }
1326                 }
1327                 if (x == channel_strings.end()) {
1328                         channel_combo.set_active_text (channel_strings.front());
1329                 }
1330         } else {
1331                 channel_combo.set_active_text (channel_strings.front());
1332         }
1333
1334         resetting_ourselves = false;
1335
1336         if (src_needed) {
1337                 src_combo.set_sensitive (true);
1338         } else {
1339                 src_combo.set_sensitive (false);
1340         }
1341
1342         /* We must copy MIDI files or those from Freesound
1343          * or any file if we are under nsm control */
1344         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1345         
1346         if (Config->get_only_copy_imported_files()) {
1347
1348                 if (selection_can_be_embedded_with_links && !must_copy) {
1349                         copy_files_btn.set_sensitive (true);
1350                 } else {
1351                         if (must_copy) {
1352                                 copy_files_btn.set_active (true);
1353                         }
1354                         copy_files_btn.set_sensitive (false);
1355                 }
1356
1357         }  else {
1358
1359                 if (must_copy) {
1360                         copy_files_btn.set_active (true);
1361                 }                       
1362                 copy_files_btn.set_sensitive (!must_copy);
1363         }
1364
1365         return true;
1366 }
1367
1368
1369 bool
1370 SoundFileOmega::bad_file_message()
1371 {
1372         MessageDialog msg (*this,
1373                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1374                            true,
1375                            Gtk::MESSAGE_INFO,
1376                            Gtk::BUTTONS_OK);
1377         msg.run ();
1378         resetting_ourselves = true;
1379         chooser.unselect_uri (chooser.get_preview_uri());
1380         resetting_ourselves = false;
1381
1382         return false;
1383 }
1384
1385 bool
1386 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1387 {
1388         SoundFileInfo info;
1389         framepos_t sz = 0;
1390         bool err = false;
1391         string errmsg;
1392
1393         same_size = true;
1394         src_needed = false;
1395         multichannel = false;
1396
1397         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1398
1399                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1400                         if (info.channels > 1) {
1401                                 multichannel = true;
1402                         }
1403                         if (sz == 0) {
1404                                 sz = info.length;
1405                         } else {
1406                                 if (sz != info.length) {
1407                                         same_size = false;
1408                                 }
1409                         }
1410
1411                         if (info.samplerate != _session->frame_rate()) {
1412                                 src_needed = true;
1413                         }
1414
1415                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1416
1417                         Evoral::SMF reader;
1418                         reader.open(*i);
1419                         if (reader.num_tracks() > 1) {
1420                                 multichannel = true; // "channel" == track here...
1421                         }
1422
1423                         /* XXX we need err = true handling here in case
1424                            we can't check the file
1425                         */
1426
1427                 } else {
1428                         err = true;
1429                 }
1430         }
1431
1432         return err;
1433 }
1434
1435
1436 bool
1437 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1438 {
1439         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1440         bool ret = false;
1441
1442         if (mkdir (tmpdir.c_str(), 0744)) {
1443                 if (errno != EEXIST) {
1444                         return false;
1445                 }
1446         }
1447
1448         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1449
1450                 char tmpc[MAXPATHLEN+1];
1451
1452                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1453
1454                 /* can we link ? */
1455
1456                 if (link ((*i).c_str(), tmpc)) {
1457                         goto out;
1458                 }
1459
1460                 unlink (tmpc);
1461         }
1462
1463         ret = true;
1464
1465   out:
1466         rmdir (tmpdir.c_str());
1467         return ret;
1468 }
1469
1470 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1471         : SoundFileBrowser (title, s, false)
1472 {
1473         chooser.set_select_multiple (false);
1474         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1475         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1476 }
1477
1478 void
1479 SoundFileChooser::on_hide ()
1480 {
1481         ArdourWindow::on_hide();
1482         stop_metering ();
1483
1484         if (_session) {
1485                 _session->cancel_audition();
1486         }
1487 }
1488
1489 string
1490 SoundFileChooser::get_filename ()
1491 {
1492         vector<string> paths;
1493
1494         paths = get_paths ();
1495
1496         if (paths.empty()) {
1497                 return string ();
1498         }
1499
1500         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1501                 return string();
1502         }
1503
1504         return paths.front();
1505 }
1506
1507 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1508                                 uint32_t selected_audio_tracks, 
1509                                 uint32_t selected_midi_tracks, 
1510                                 bool persistent,
1511                                 Editing::ImportMode mode_hint)
1512         : SoundFileBrowser (title, s, persistent)
1513         , copy_files_btn ( _("Copy files to session"))
1514         , selected_audio_track_cnt (selected_audio_tracks)
1515         , selected_midi_track_cnt (selected_midi_tracks)
1516 {
1517         VBox* vbox;
1518         HBox* hbox;
1519         vector<string> str;
1520
1521         set_size_request (-1, 450);
1522
1523         block_two.set_border_width (12);
1524         block_three.set_border_width (12);
1525         block_four.set_border_width (12);
1526
1527         options.set_spacing (12);
1528
1529         str.clear ();
1530         str.push_back (_("file timestamp"));
1531         str.push_back (_("edit point"));
1532         str.push_back (_("playhead"));
1533         str.push_back (_("session start"));
1534         set_popdown_strings (where_combo, str);
1535         where_combo.set_active_text (str.front());
1536
1537         Label* l = manage (new Label);
1538         l->set_markup (_("<b>Add files as ...</b>"));
1539
1540         vbox = manage (new VBox);
1541         vbox->set_border_width (12);
1542         vbox->set_spacing (6);
1543         vbox->pack_start (*l, false, false);
1544         vbox->pack_start (action_combo, false, false);
1545         hbox = manage (new HBox);
1546         hbox->pack_start (*vbox, false, false);
1547         options.pack_start (*hbox, false, false);
1548
1549         /* dummy entry for action combo so that it doesn't look odd if we
1550            come up with no tracks selected.
1551         */
1552
1553         str.clear ();
1554         str.push_back (importmode2string (mode_hint));
1555         set_popdown_strings (action_combo, str);
1556         action_combo.set_active_text (str.front());
1557         action_combo.set_sensitive (false);
1558
1559         l = manage (new Label);
1560         l->set_markup (_("<b>Insert at</b>"));
1561
1562         vbox = manage (new VBox);
1563         vbox->set_border_width (12);
1564         vbox->set_spacing (6);
1565         vbox->pack_start (*l, false, false);
1566         vbox->pack_start (where_combo, false, false);
1567         hbox = manage (new HBox);
1568         hbox->pack_start (*vbox, false, false);
1569         options.pack_start (*hbox, false, false);
1570
1571
1572         l = manage (new Label);
1573         l->set_markup (_("<b>Mapping</b>"));
1574
1575         vbox = manage (new VBox);
1576         vbox->set_border_width (12);
1577         vbox->set_spacing (6);
1578         vbox->pack_start (*l, false, false);
1579         vbox->pack_start (channel_combo, false, false);
1580         hbox = manage (new HBox);
1581         hbox->pack_start (*vbox, false, false);
1582         options.pack_start (*hbox, false, false);
1583
1584         str.clear ();
1585         str.push_back (_("one track per file"));
1586         set_popdown_strings (channel_combo, str);
1587         channel_combo.set_active_text (str.front());
1588         channel_combo.set_sensitive (false);
1589
1590         l = manage (new Label);
1591         l->set_markup (_("<b>Conversion quality</b>"));
1592
1593         vbox = manage (new VBox);
1594         vbox->set_border_width (12);
1595         vbox->set_spacing (6);
1596         vbox->pack_start (*l, false, false);
1597         vbox->pack_start (src_combo, false, false);
1598         hbox = manage (new HBox);
1599         hbox->pack_start (*vbox, false, false);
1600         options.pack_start (*hbox, false, false);
1601
1602         str.clear ();
1603         str.push_back (_("Best"));
1604         str.push_back (_("Good"));
1605         str.push_back (_("Quick"));
1606         str.push_back (_("Fast"));
1607         str.push_back (_("Fastest"));
1608
1609         set_popdown_strings (src_combo, str);
1610         src_combo.set_active_text (str.front());
1611         src_combo.set_sensitive (false);
1612
1613         reset_options ();
1614
1615         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1616         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1617
1618         copy_files_btn.set_active (true);
1619
1620         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1621
1622         if (copy_label) {
1623                 copy_label->set_size_request (175, -1);
1624                 copy_label->set_line_wrap (true);
1625         }
1626
1627         block_four.pack_start (copy_files_btn, false, false);
1628
1629         options.pack_start (block_four, false, false);
1630
1631         vpacker.pack_start (options, false, false);
1632
1633         /* setup disposition map */
1634
1635         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1636         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1637         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1638         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1639
1640         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1641         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1642         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1643         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1644
1645         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1646
1647         /* set size requests for a couple of combos to allow them to display the longest text
1648            they will ever be asked to display.  This prevents them being resized when the user
1649            selects a file to import, which in turn prevents the size of the dialog from jumping
1650            around. */
1651
1652         vector<string> t;
1653         t.push_back (_("one track per file"));
1654         t.push_back (_("one track per channel"));
1655         t.push_back (_("sequence files"));
1656         t.push_back (_("all files in one region"));
1657         set_popdown_strings (channel_combo, t);
1658
1659         t.clear ();
1660         t.push_back (importmode2string (ImportAsTrack));
1661         t.push_back (importmode2string (ImportToTrack));
1662         t.push_back (importmode2string (ImportAsRegion));
1663         t.push_back (importmode2string (ImportAsTapeTrack));
1664         set_popdown_strings (action_combo, t);
1665 }
1666
1667 void
1668 SoundFileOmega::set_mode (ImportMode mode)
1669 {
1670         action_combo.set_active_text (importmode2string (mode));
1671 }
1672
1673 ImportMode
1674 SoundFileOmega::get_mode () const
1675 {
1676         return string2importmode (action_combo.get_active_text());
1677 }
1678
1679 void
1680 SoundFileOmega::on_hide ()
1681 {
1682         ArdourWindow::on_hide();
1683         if (_session) {
1684                 _session->cancel_audition();
1685         }
1686 }
1687
1688 ImportPosition
1689 SoundFileOmega::get_position() const
1690 {
1691         string str = where_combo.get_active_text();
1692
1693         if (str == _("file timestamp")) {
1694                 return ImportAtTimestamp;
1695         } else if (str == _("edit point")) {
1696                 return ImportAtEditPoint;
1697         } else if (str == _("playhead")) {
1698                 return ImportAtPlayhead;
1699         } else {
1700                 return ImportAtStart;
1701         }
1702 }
1703
1704 SrcQuality
1705 SoundFileOmega::get_src_quality() const
1706 {
1707         string str = src_combo.get_active_text();
1708
1709         if (str == _("Best")) {
1710                 return SrcBest;
1711         } else if (str == _("Good")) {
1712                 return SrcGood;
1713         } else if (str == _("Quick")) {
1714                 return SrcQuick;
1715         } else if (str == _("Fast")) {
1716                 return SrcFast;
1717         } else {
1718                 return SrcFastest;
1719         }
1720 }
1721
1722 ImportDisposition
1723 SoundFileOmega::get_channel_disposition () const
1724 {
1725         /* we use a map here because the channel combo can contain different strings
1726            depending on the state of the other combos. the map contains all possible strings
1727            and the ImportDisposition enum that corresponds to it.
1728         */
1729
1730         string str = channel_combo.get_active_text();
1731         DispositionMap::const_iterator x = disposition_map.find (str);
1732
1733         if (x == disposition_map.end()) {
1734                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1735                 /*NOTREACHED*/
1736         }
1737
1738         return x->second;
1739 }
1740
1741 void
1742 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1743 {
1744         selected_audio_track_cnt = selected_audio_tracks;
1745         selected_midi_track_cnt = selected_midi_tracks;
1746
1747         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1748                 chooser.set_filter (midi_filter);
1749         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1750                 chooser.set_filter (audio_filter);
1751         } else {
1752                 chooser.set_filter (audio_and_midi_filter);
1753         }
1754
1755         reset_options ();
1756 }
1757
1758 void
1759 SoundFileOmega::file_selection_changed ()
1760 {
1761         if (resetting_ourselves) {
1762                 return;
1763         }
1764
1765         if (!reset_options ()) {
1766                 set_action_sensitive (false);
1767         } else {
1768                 if (chooser.get_filenames().size() > 0) {
1769                         set_action_sensitive (true);
1770                 } else {
1771                         set_action_sensitive (false);
1772                 }
1773         }
1774 }
1775
1776 void
1777 SoundFileOmega::do_something (int action)
1778 {
1779         SoundFileBrowser::do_something (action);
1780
1781         if (action == RESPONSE_CANCEL) {
1782                 hide ();
1783                 return;
1784         }
1785
1786         /* lets do it */
1787         
1788         vector<string> paths = get_paths ();
1789         ImportPosition pos = get_position ();
1790         ImportMode mode = get_mode ();
1791         ImportDisposition chns = get_channel_disposition ();
1792         framepos_t where;
1793         
1794         switch (pos) {
1795         case ImportAtEditPoint:
1796                 where = PublicEditor::instance().get_preferred_edit_position ();
1797                 break;
1798         case ImportAtTimestamp:
1799                 where = -1;
1800                 break;
1801         case ImportAtPlayhead:
1802                 where = _session->transport_frame();
1803                 break;
1804         case ImportAtStart:
1805                 where = _session->current_start_frame();
1806                 break;
1807         }
1808         
1809         SrcQuality quality = get_src_quality();
1810         
1811         if (copy_files_btn.get_active()) {
1812                 PublicEditor::instance().do_import (paths, chns, mode, quality, where);
1813         } else {
1814                 PublicEditor::instance().do_embed (paths, chns, mode, where);
1815         }
1816         
1817         if (action == RESPONSE_OK) {
1818                 hide ();
1819         }
1820 }
1821