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