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