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