Remove Apply button in Import dialog/Window and change OK to "Import"
[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         , import_button (_("Import"))
558         , close_button (Stock::CLOSE)
559         , gm (0)
560 {
561
562 #ifdef GTKOSX
563         chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
564         chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
565         chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
566         chooser.add_shortcut_folder_uri("file:///Volumes");
567 #endif
568
569         //add the file chooser
570
571         chooser.set_border_width (12);
572         
573         audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
574         audio_and_midi_filter.set_name (_("Audio and MIDI files"));
575         
576         audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
577         audio_filter.set_name (_("Audio files"));
578         
579         midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
580         midi_filter.set_name (_("MIDI files"));
581         
582         matchall_filter.add_pattern ("*.*");
583         matchall_filter.set_name (_("All files"));
584         
585         chooser.add_filter (audio_and_midi_filter);
586         chooser.add_filter (audio_filter);
587         chooser.add_filter (midi_filter);
588         chooser.add_filter (matchall_filter);
589         chooser.set_select_multiple (true);
590         chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
591         chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
592
593 #ifdef GTKOSX
594         /* some broken redraw behaviour - this is a bandaid */
595         chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
596 #endif
597         
598         if (!persistent_folder.empty()) {
599                 chooser.set_current_folder (persistent_folder);
600         }
601
602         notebook.append_page (chooser, _("Browse Files"));
603         
604         hpacker.set_spacing (6);
605         hpacker.pack_start (notebook, true, true);
606         hpacker.pack_start (preview, false, false);
607
608         vpacker.set_spacing (6);
609         vpacker.pack_start (hpacker, true, true);
610
611         add (vpacker);
612
613         //add tag search
614
615         VBox* vbox;
616         HBox* hbox;
617         
618         
619         hbox = manage(new HBox);
620         hbox->pack_start (found_entry);
621         hbox->pack_start (found_search_btn);
622         
623         Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
624         scroll->add(found_list_view);
625         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
626         
627         vbox = manage(new VBox);
628         vbox->pack_start (*hbox, PACK_SHRINK);
629         vbox->pack_start (*scroll);
630         
631         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
632         
633         found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
634         
635         found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
636         
637         found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
638         found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
639         
640         notebook.append_page (*vbox, _("Search Tags"));
641
642         //add freesound search
643
644         HBox* passbox;
645         Label* label;
646         
647         passbox = manage(new HBox);
648         passbox->set_spacing (6);
649         
650         label = manage (new Label);
651         label->set_text (_("Tags:"));
652         passbox->pack_start (*label, false, false);
653         passbox->pack_start (freesound_entry, true, true);
654         
655         label = manage (new Label);
656         label->set_text (_("Sort:"));
657         passbox->pack_start (*label, false, false);
658         passbox->pack_start (freesound_sort, false, false);
659         freesound_sort.clear_items();
660         
661         // Order of the following must correspond with enum sortMethod
662         // in sfdb_freesound_mootcher.h 
663         freesound_sort.append_text(_("None"));
664         freesound_sort.append_text(_("Longest"));
665         freesound_sort.append_text(_("Shortest"));
666         freesound_sort.append_text(_("Newest"));
667         freesound_sort.append_text(_("Oldest"));
668         freesound_sort.append_text(_("Most downloaded"));
669         freesound_sort.append_text(_("Least downloaded"));
670         freesound_sort.append_text(_("Highest rated"));
671         freesound_sort.append_text(_("Lowest rated"));
672         freesound_sort.set_active(0);
673         
674         passbox->pack_start (freesound_search_btn, false, false);
675         passbox->pack_start (freesound_more_btn, false, false);
676         freesound_more_btn.set_label(_("More"));
677         freesound_more_btn.set_sensitive(false);
678
679         passbox->pack_start (freesound_similar_btn, false, false);
680         freesound_similar_btn.set_label(_("Similar"));
681         freesound_similar_btn.set_sensitive(false);
682         
683         scroll = manage(new ScrolledWindow);
684         scroll->add(freesound_list_view);
685         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
686         
687         vbox = manage(new VBox);
688         vbox->set_spacing (3);
689         vbox->pack_start (*passbox, PACK_SHRINK);
690         vbox->pack_start (*scroll);
691
692         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
693         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
694         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
695         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
696         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
697         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
698         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
699         freesound_list_view.get_column(0)->set_alignment(0.5);
700         freesound_list_view.get_column(1)->set_expand(true); // filename
701         freesound_list_view.get_column(1)->set_resizable(true); // filename
702         freesound_list_view.get_column(2)->set_alignment(0.5);
703         freesound_list_view.get_column(3)->set_alignment(0.5);
704         freesound_list_view.get_column(4)->set_alignment(0.5);
705         freesound_list_view.get_column(5)->set_alignment(0.5);
706         
707         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
708         freesound_list_view.set_tooltip_column(1);
709
710         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
711         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
712         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
713         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
714         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
715         freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
716         notebook.append_page (*vbox, _("Search Freesound"));
717
718         notebook.set_size_request (500, -1);
719         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
720
721         set_session (s);
722
723         Gtk::HButtonBox* button_box = manage (new HButtonBox);
724
725         button_box->set_layout (BUTTONBOX_END);
726         button_box->pack_start (close_button, false, false);
727         close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CLOSE));
728
729         button_box->pack_start (import_button, false, false);
730         import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
731
732         Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
733         Gtkmm2ext::UI::instance()->set_tip (close_button, _("Press to close this window without importing any files"));
734
735         vpacker.pack_end (*button_box, false, false);
736
737         set_wmclass (X_("import"), PROGRAM_NAME);
738 }
739
740 SoundFileBrowser::~SoundFileBrowser ()
741 {
742         persistent_folder = chooser.get_current_folder();
743 }
744
745 int
746 SoundFileBrowser::run ()
747 {
748         set_modal (true);
749         show_all ();
750         present ();
751
752         _done = false;
753
754         while (!_done) {
755                 gtk_main_iteration ();
756         }
757
758         return _status;
759 }
760
761 void
762 SoundFileBrowser::set_action_sensitive (bool yn)
763 {
764         import_button.set_sensitive (yn);
765 }
766
767 void
768 SoundFileBrowser::do_something (int action)
769 {
770         _done = true;
771         _status = action;
772 }
773
774 void
775 SoundFileBrowser::on_show ()
776 {
777         ArdourWindow::on_show ();
778         start_metering ();
779 }
780
781 void
782 SoundFileBrowser::clear_selection ()
783 {
784         chooser.unselect_all ();
785         found_list_view.get_selection()->unselect_all ();
786 }
787
788 void
789 SoundFileBrowser::chooser_file_activated ()
790 {
791         preview.audition ();
792 }
793
794 void
795 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
796 {
797         preview.audition ();
798 }
799
800 void
801 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
802 {
803         preview.audition ();
804 }
805
806 void
807 SoundFileBrowser::set_session (Session* s)
808 {
809         ArdourWindow::set_session (s);
810         preview.set_session (s);
811
812         if (_session) {
813                 add_gain_meter ();
814         } else {
815                 remove_gain_meter ();
816         }
817 }
818
819 void
820 SoundFileBrowser::add_gain_meter ()
821 {
822         delete gm;
823
824         gm = new GainMeter (_session, 250);
825
826         boost::shared_ptr<Route> r = _session->the_auditioner ();
827
828         gm->set_controls (r, r->shared_peak_meter(), r->amp());
829         gm->set_fader_name (X_("GainFader"));
830
831         meter_packer.set_border_width (12);
832         meter_packer.pack_start (*gm, false, true);
833         hpacker.pack_end (meter_packer, false, false);
834         meter_packer.show_all ();
835         start_metering ();
836 }
837
838 void
839 SoundFileBrowser::remove_gain_meter ()
840 {
841         if (gm) {
842                 meter_packer.remove (*gm);
843                 hpacker.remove (meter_packer);
844                 delete gm;
845                 gm = 0;
846         }
847 }
848
849 void
850 SoundFileBrowser::start_metering ()
851 {
852         metering_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
853 }
854
855 void
856 SoundFileBrowser::stop_metering ()
857 {
858         metering_connection.disconnect();
859 }
860
861 void
862 SoundFileBrowser::meter ()
863 {
864         if (is_mapped () && _session && gm) {
865                 gm->update_meters ();
866         }
867 }
868
869 bool
870 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
871 {
872         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
873 }
874
875 bool
876 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
877 {
878         return SMFSource::safe_midi_file_extension (filter_info.filename);
879 }
880
881 bool
882 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
883 {
884         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
885 }
886
887 void
888 SoundFileBrowser::update_preview ()
889 {
890         if (preview.setup_labels (chooser.get_preview_filename())) {
891                 if (preview.autoplay()) {
892                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
893                 }
894         }
895 }
896
897 void
898 SoundFileBrowser::found_list_view_selected ()
899 {
900         if (!reset_options ()) {
901                 set_action_sensitive (false);
902         } else {
903                 string file;
904
905                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
906
907                 if (!rows.empty()) {
908                         TreeIter iter = found_list->get_iter(*rows.begin());
909                         file = (*iter)[found_list_columns.pathname];
910                         chooser.set_filename (file);
911                         set_action_sensitive (true);
912                 } else {
913                         set_action_sensitive (false);
914                 }
915
916                 preview.setup_labels (file);
917         }
918 }
919
920 void
921 SoundFileBrowser::found_search_clicked ()
922 {
923         string tag_string = found_entry.get_text ();
924
925         vector<string> tags;
926
927         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
928                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
929                 return;
930         }
931
932         vector<string> results;
933         Library->search_members_and (results, tags);
934
935         found_list->clear();
936         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
937                 TreeModel::iterator new_row = found_list->append();
938                 TreeModel::Row row = *new_row;
939                 string path = Glib::filename_from_uri (string ("file:") + *i);
940                 row[found_list_columns.pathname] = path;
941         }
942 }
943
944
945 std::string
946 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
947 {
948
949         Mootcher *mootcher = new Mootcher;
950         std::string file;
951
952         string id  = (*iter)[freesound_list_columns.id];
953         string uri = (*iter)[freesound_list_columns.uri];
954         string ofn = (*iter)[freesound_list_columns.filename];
955
956         if (mootcher->checkAudioFile(ofn, id)) {
957                 // file already exists, no need to download it again
958                 file = mootcher->audioFileName;
959                 delete mootcher;
960                 (*iter)[freesound_list_columns.started] = false;
961                 return file;
962         }
963         if (!(*iter)[freesound_list_columns.started]) {
964                 // start downloading the sound file
965                 (*iter)[freesound_list_columns.started] = true;
966                 mootcher->fetchAudioFile(ofn, id, uri, this);
967         }
968         return "";
969 }
970
971 void
972 SoundFileBrowser::freesound_list_view_selected ()
973 {
974
975         if (!reset_options ()) {
976                 set_action_sensitive (false);
977         } else {
978                 std::string file;
979                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
980                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
981                         file = freesound_get_audio_file (freesound_list->get_iter(*i));
982                 }
983
984                 switch (rows.size()) {
985                         case 0:
986                                 // nothing selected
987                                 freesound_similar_btn.set_sensitive(false);
988                                 set_action_sensitive (false);
989                                 break;
990                         case 1:
991                                 // exactly one item selected
992                                 if (file != "") {
993                                         // file exists on disk already
994                                         chooser.set_filename (file);
995                                         preview.setup_labels (file);
996                                         set_action_sensitive (true);
997                                 }
998                                 freesound_similar_btn.set_sensitive(true);
999                                 break;
1000                         default:
1001                                 // multiple items selected
1002                                 preview.setup_labels ("");
1003                                 freesound_similar_btn.set_sensitive(false);
1004                                 break;
1005                 }
1006
1007         }
1008 }
1009
1010 void
1011 SoundFileBrowser::refresh_display(std::string ID, std::string file)
1012 {
1013         // called when the mootcher has finished downloading a file
1014         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1015         if (rows.size() == 1) {
1016                 // there's a single item selected in the freesound list
1017                 //XXX make a function to be used to construct the actual file name both here and in the mootcher
1018                 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
1019                 std::string selected_ID = (*row)[freesound_list_columns.id]; 
1020                 if (ID == selected_ID) {
1021                         // the selected item in the freesound list is the item that has just finished downloading
1022                         chooser.set_filename(file);
1023                         preview.setup_labels (file);
1024                         set_action_sensitive (true);
1025                 }
1026         }
1027 }
1028
1029 void
1030 SoundFileBrowser::freesound_search_clicked ()
1031 {
1032         freesound_page = 1;
1033         freesound_list->clear();
1034         matches = 0;
1035         freesound_search();
1036 }
1037
1038 void
1039 SoundFileBrowser::freesound_more_clicked ()
1040 {
1041         char row_path[21];
1042         freesound_page++;
1043         freesound_search();
1044         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
1045         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
1046 }
1047
1048 void
1049 SoundFileBrowser::freesound_similar_clicked ()
1050 {
1051         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1052         if (rows.size() == 1) {
1053                 Mootcher mootcher;
1054                 string id;
1055                 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
1056                 id = (*iter)[freesound_list_columns.id];
1057                 freesound_list->clear();
1058
1059                 GdkCursor *prev_cursor;
1060                 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1061                 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1062                 gdk_flush();
1063                 
1064                 std::string theString = mootcher.searchSimilar(id);
1065                 
1066                 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1067                 handle_freesound_results(theString);
1068         }
1069 }
1070
1071 void
1072 SoundFileBrowser::freesound_search()
1073 {
1074         Mootcher mootcher;
1075
1076         string search_string = freesound_entry.get_text ();
1077         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
1078
1079         GdkCursor *prev_cursor;
1080         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1081         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1082         gdk_flush();
1083
1084         std::string theString = mootcher.searchText(
1085                         search_string, 
1086                         freesound_page,
1087 #ifdef GTKOSX
1088                         "", // OSX eats anything incl mp3
1089 #else
1090                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
1091 #endif
1092                         sort_method
1093                         );
1094
1095         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1096         handle_freesound_results(theString);
1097 }
1098
1099 void
1100 SoundFileBrowser::handle_freesound_results(std::string theString) {
1101         XMLTree doc;
1102         doc.read_buffer( theString );
1103         XMLNode *root = doc.root();
1104
1105         if (!root) {
1106                 error << "no root XML node!" << endmsg;
1107                 return;
1108         }
1109
1110         if ( strcmp(root->name().c_str(), "response") != 0) {
1111                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
1112                 return;
1113         }
1114
1115         // find out how many pages are available to search
1116         int freesound_n_pages = 1;
1117         XMLNode *res = root->child("num_pages");
1118         if (res) {
1119                 string result = res->child("text")->content();
1120                 freesound_n_pages = atoi(result);
1121         }
1122
1123         int more_pages = freesound_n_pages - freesound_page;
1124
1125         if (more_pages > 0) {
1126                 freesound_more_btn.set_sensitive(true);
1127                 freesound_more_btn.set_tooltip_text(string_compose(P_(
1128                                                 "%1 more page of 100 results available",
1129                                                 "%1 more pages of 100 results available",
1130                                                 more_pages), more_pages));
1131         } else {
1132                 freesound_more_btn.set_sensitive(false);
1133                 freesound_more_btn.set_tooltip_text(_("No more results available"));
1134         }
1135
1136         XMLNode *sounds_root = root->child("sounds");
1137         if (!sounds_root) {
1138                 error << "no child node \"sounds\" found!" << endmsg;
1139                 return;
1140         }
1141
1142         XMLNodeList sounds = sounds_root->children();
1143         if (sounds.size() == 0) {
1144                 /* nothing found */
1145                 return;
1146         }
1147
1148         XMLNodeConstIterator niter;
1149         XMLNode *node;
1150         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1151                 node = *niter;
1152                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1153                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1154                         break;
1155                 }
1156
1157                 // node->dump(cerr, "node:");
1158
1159
1160                 XMLNode *id_node  = node->child ("id");
1161                 XMLNode *uri_node = node->child ("serve");
1162                 XMLNode *ofn_node = node->child ("original_filename");
1163                 XMLNode *dur_node = node->child ("duration");
1164                 XMLNode *siz_node = node->child ("filesize");
1165                 XMLNode *srt_node = node->child ("samplerate");
1166                 XMLNode *lic_node = node->child ("license");
1167
1168                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1169
1170                         std::string  id =  id_node->child("text")->content();
1171                         std::string uri = uri_node->child("text")->content();
1172                         std::string ofn = ofn_node->child("text")->content();
1173                         std::string dur = dur_node->child("text")->content();
1174                         std::string siz = siz_node->child("text")->content();
1175                         std::string srt = srt_node->child("text")->content();
1176                         std::string lic = lic_node->child("text")->content();
1177
1178                         std::string r;
1179                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1180
1181                         double duration_seconds = atof(dur);
1182                         double h, m, s;
1183                         char duration_hhmmss[16];
1184                         if (duration_seconds >= 99 * 60 * 60) {
1185                                 strcpy(duration_hhmmss, ">99h");
1186                         } else {
1187                                 s = modf(duration_seconds/60, &m) * 60;
1188                                 m = modf(m/60, &h) * 60;
1189                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1190                                                 h, m, s
1191                                        );
1192                         }
1193
1194                         double size_bytes = atof(siz);
1195                         char bsize[32];
1196                         if (size_bytes < 1000) {
1197                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1198                         } else if (size_bytes < 1000000 ) {
1199                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1200                         } else if (size_bytes < 10000000) {
1201                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1202                         } else if (size_bytes < 1000000000) {
1203                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1204                         } else {
1205                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1206                         }
1207
1208                         /* see http://www.freesound.org/help/faq/#licenses */
1209                         char shortlicense[64];
1210                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1211                                 sprintf(shortlicense, "CC-BY-NC");
1212                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1213                                 sprintf(shortlicense, "CC-BY");
1214                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1215                                 sprintf(shortlicense, "sampling+");
1216                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1217                                 sprintf(shortlicense, "PD");
1218                         } else {
1219                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1220                                 shortlicense[63]= '\0';
1221                         }
1222
1223                         TreeModel::iterator new_row = freesound_list->append();
1224                         TreeModel::Row row = *new_row;
1225
1226                         row[freesound_list_columns.id      ] = id;
1227                         row[freesound_list_columns.uri     ] = uri;
1228                         row[freesound_list_columns.filename] = ofn;
1229                         row[freesound_list_columns.duration] = duration_hhmmss;
1230                         row[freesound_list_columns.filesize] = bsize;
1231                         row[freesound_list_columns.smplrate] = srt;
1232                         row[freesound_list_columns.license ] = shortlicense;
1233                         matches++;
1234                 }
1235         }
1236 }
1237
1238 vector<string>
1239 SoundFileBrowser::get_paths ()
1240 {
1241         vector<string> results;
1242
1243         int n = notebook.get_current_page ();
1244
1245         if (n == 0) {
1246                 vector<string> filenames = chooser.get_filenames();
1247                 vector<string>::iterator i;
1248
1249                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1250                         GStatBuf buf;
1251                         if ((!g_stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1252                                 results.push_back (*i);
1253                         }
1254                 }
1255
1256         } else if (n == 1) {
1257
1258                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1259                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1260                         TreeIter iter = found_list->get_iter(*i);
1261                         string str = (*iter)[found_list_columns.pathname];
1262
1263                         results.push_back (str);
1264                 }
1265         } else {
1266                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1267                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1268                         string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1269                         if (str != "") {
1270                                 results.push_back (str);
1271                         }
1272                 }
1273         }
1274
1275         return results;
1276 }
1277
1278 void
1279 SoundFileOmega::reset_options_noret ()
1280 {
1281         if (!resetting_ourselves) {
1282                 (void) reset_options ();
1283         }
1284 }
1285
1286 bool
1287 SoundFileOmega::reset_options ()
1288 {
1289         vector<string> paths = get_paths ();
1290
1291         if (paths.empty()) {
1292
1293                 channel_combo.set_sensitive (false);
1294                 action_combo.set_sensitive (false);
1295                 where_combo.set_sensitive (false);
1296                 copy_files_btn.set_active (true);
1297                 copy_files_btn.set_sensitive (false);
1298
1299                 return false;
1300
1301         } else {
1302
1303                 channel_combo.set_sensitive (true);
1304                 action_combo.set_sensitive (true);
1305                 where_combo.set_sensitive (true);
1306
1307                 /* if we get through this function successfully, this may be
1308                    reset at the end, once we know if we can use hard links
1309                    to do embedding (or if we are importing a MIDI file).
1310                 */
1311
1312                 if (ARDOUR_UI::config()->get_only_copy_imported_files()) {
1313                         copy_files_btn.set_sensitive (false);
1314                 } else {
1315                         copy_files_btn.set_sensitive (false);
1316                 }
1317         }
1318
1319         bool same_size;
1320         bool src_needed;
1321         bool selection_includes_multichannel;
1322         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1323         ImportMode mode;
1324
1325         /* See if we are thinking about importing any MIDI files */
1326         vector<string>::iterator i = paths.begin ();
1327         while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1328                 ++i;
1329         }
1330         bool const have_a_midi_file = (i != paths.end ());
1331
1332         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1333                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1334                 return false;
1335         }
1336
1337         string existing_choice;
1338         vector<string> action_strings;
1339
1340         resetting_ourselves = true;
1341
1342         if (chooser.get_filter() == &audio_filter) {
1343
1344                 /* AUDIO */
1345
1346                 if (selected_audio_track_cnt > 0) {
1347                         if (channel_combo.get_active_text().length()) {
1348                                 ImportDisposition id = get_channel_disposition();
1349                                 
1350                                 switch (id) {
1351                                 case Editing::ImportDistinctFiles:
1352                                         if (selected_audio_track_cnt == paths.size()) {
1353                                                 action_strings.push_back (importmode2string (ImportToTrack));
1354                                         }
1355                                         break;
1356                                         
1357                                 case Editing::ImportDistinctChannels:
1358                                         /* XXX it would be nice to allow channel-per-selected track
1359                                            but its too hard we don't want to deal with all the
1360                                            different per-file + per-track channel configurations.
1361                                         */
1362                                         break;
1363                                         
1364                                 default:
1365                                         action_strings.push_back (importmode2string (ImportToTrack));
1366                                         break;
1367                                 }
1368                         }
1369                 }
1370                 
1371         }  else {
1372
1373                 /* MIDI ONLY */
1374
1375                 if (selected_midi_track_cnt > 0) {
1376                         action_strings.push_back (importmode2string (ImportToTrack));
1377                 }
1378         }
1379
1380         action_strings.push_back (importmode2string (ImportAsTrack));
1381         action_strings.push_back (importmode2string (ImportAsRegion));
1382         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1383
1384         existing_choice = action_combo.get_active_text();
1385
1386         set_popdown_strings (action_combo, action_strings);
1387
1388         /* preserve any existing choice, if possible */
1389
1390
1391         if (existing_choice.length()) {
1392                 vector<string>::iterator x;
1393                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1394                         if (*x == existing_choice) {
1395                                 action_combo.set_active_text (existing_choice);
1396                                 break;
1397                         }
1398                 }
1399                 if (x == action_strings.end()) {
1400                         action_combo.set_active_text (action_strings.front());
1401                 }
1402         } else {
1403                 action_combo.set_active_text (action_strings.front());
1404         }
1405
1406         resetting_ourselves = false;
1407
1408         if ((mode = get_mode()) == ImportAsRegion) {
1409                 where_combo.set_sensitive (false);
1410         } else {
1411                 where_combo.set_sensitive (true);
1412         }
1413
1414         vector<string> channel_strings;
1415
1416         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1417                 channel_strings.push_back (_("one track per file"));
1418
1419                 if (selection_includes_multichannel) {
1420                         channel_strings.push_back (_("one track per channel"));
1421                 }
1422
1423                 if (paths.size() > 1) {
1424                         /* tape tracks are a single region per track, so we cannot
1425                            sequence multiple files.
1426                         */
1427                         if (mode != ImportAsTapeTrack) {
1428                                 channel_strings.push_back (_("sequence files"));
1429                         }
1430                         if (same_size) {
1431                                 channel_strings.push_back (_("all files in one track"));
1432                                 channel_strings.push_back (_("merge files"));
1433                         }
1434
1435                 }
1436
1437         } else {
1438                 channel_strings.push_back (_("one region per file"));
1439
1440                 if (selection_includes_multichannel) {
1441                         channel_strings.push_back (_("one region per channel"));
1442                 }
1443
1444                 if (paths.size() > 1) {
1445                         if (same_size) {
1446                                 channel_strings.push_back (_("all files in one region"));
1447                         }
1448                 }
1449         }
1450
1451         resetting_ourselves = true;
1452
1453         existing_choice = channel_combo.get_active_text();
1454
1455         set_popdown_strings (channel_combo, channel_strings);
1456
1457         /* preserve any existing choice, if possible */
1458
1459         if (existing_choice.length()) {
1460                 vector<string>::iterator x;
1461                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1462                         if (*x == existing_choice) {
1463                                 channel_combo.set_active_text (existing_choice);
1464                                 break;
1465                         }
1466                 }
1467                 if (x == channel_strings.end()) {
1468                         channel_combo.set_active_text (channel_strings.front());
1469                 }
1470         } else {
1471                 channel_combo.set_active_text (channel_strings.front());
1472         }
1473
1474         resetting_ourselves = false;
1475
1476         if (src_needed) {
1477                 src_combo.set_sensitive (true);
1478         } else {
1479                 src_combo.set_sensitive (false);
1480         }
1481
1482         /* We must copy MIDI files or those from Freesound
1483          * or any file if we are under nsm control */
1484         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1485         
1486         if (ARDOUR_UI::config()->get_only_copy_imported_files()) {
1487
1488                 if (selection_can_be_embedded_with_links && !must_copy) {
1489                         copy_files_btn.set_sensitive (true);
1490                 } else {
1491                         if (must_copy) {
1492                                 copy_files_btn.set_active (true);
1493                         }
1494                         copy_files_btn.set_sensitive (false);
1495                 }
1496
1497         }  else {
1498
1499                 if (must_copy) {
1500                         copy_files_btn.set_active (true);
1501                 }                       
1502                 copy_files_btn.set_sensitive (!must_copy);
1503         }
1504
1505         return true;
1506 }
1507
1508
1509 bool
1510 SoundFileOmega::bad_file_message()
1511 {
1512         MessageDialog msg (*this,
1513                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1514                            true,
1515                            Gtk::MESSAGE_INFO,
1516                            Gtk::BUTTONS_OK);
1517         msg.run ();
1518         resetting_ourselves = true;
1519         chooser.unselect_uri (chooser.get_preview_uri());
1520         resetting_ourselves = false;
1521
1522         return false;
1523 }
1524
1525 bool
1526 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1527 {
1528         SoundFileInfo info;
1529         framepos_t sz = 0;
1530         bool err = false;
1531         string errmsg;
1532
1533         same_size = true;
1534         src_needed = false;
1535         multichannel = false;
1536
1537         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1538
1539                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1540                         if (info.channels > 1) {
1541                                 multichannel = true;
1542                         }
1543                         if (sz == 0) {
1544                                 sz = info.length;
1545                         } else {
1546                                 if (sz != info.length) {
1547                                         same_size = false;
1548                                 }
1549                         }
1550
1551                         if (info.samplerate != _session->frame_rate()) {
1552                                 src_needed = true;
1553                         }
1554
1555                 } else if (SMFSource::valid_midi_file (*i)) {
1556
1557                         Evoral::SMF reader;
1558                         reader.open(*i);
1559                         if (reader.num_tracks() > 1) {
1560                                 multichannel = true; // "channel" == track here...
1561                         }
1562
1563                         /* XXX we need err = true handling here in case
1564                            we can't check the file
1565                         */
1566
1567                 } else {
1568                         err = true;
1569                 }
1570         }
1571
1572         return err;
1573 }
1574
1575
1576 bool
1577 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1578 {
1579 #ifdef PLATFORM_WINDOWS
1580         return false;
1581 #else
1582         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1583         bool ret = false;
1584
1585         if (g_mkdir (tmpdir.c_str(), 0744)) {
1586                 if (errno != EEXIST) {
1587                         return false;
1588                 }
1589         }
1590
1591         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1592
1593                 char tmpc[PATH_MAX+1];
1594
1595                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1596
1597                 /* can we link ? */
1598
1599                 if (link ((*i).c_str(), tmpc)) {
1600                         goto out;
1601                 }
1602
1603                 ::g_unlink (tmpc);
1604         }
1605
1606         ret = true;
1607
1608   out:
1609         g_rmdir (tmpdir.c_str());
1610         return ret;
1611 #endif
1612 }
1613
1614 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1615         : SoundFileBrowser (title, s, false)
1616 {
1617         chooser.set_select_multiple (false);
1618         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1619         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1620 }
1621
1622 void
1623 SoundFileChooser::on_hide ()
1624 {
1625         ArdourWindow::on_hide();
1626         stop_metering ();
1627
1628         if (_session) {
1629                 _session->cancel_audition();
1630         }
1631 }
1632
1633 string
1634 SoundFileChooser::get_filename ()
1635 {
1636         vector<string> paths;
1637
1638         paths = get_paths ();
1639
1640         if (paths.empty()) {
1641                 return string ();
1642         }
1643
1644         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1645                 return string();
1646         }
1647
1648         return paths.front();
1649 }
1650
1651 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1652                                 uint32_t selected_audio_tracks, 
1653                                 uint32_t selected_midi_tracks, 
1654                                 bool persistent,
1655                                 Editing::ImportMode mode_hint)
1656         : SoundFileBrowser (title, s, persistent)
1657         , copy_files_btn ( _("Copy files to session"))
1658         , selected_audio_track_cnt (selected_audio_tracks)
1659         , selected_midi_track_cnt (selected_midi_tracks)
1660 {
1661         VBox* vbox;
1662         HBox* hbox;
1663         vector<string> str;
1664
1665         set_size_request (-1, 450);
1666
1667         block_two.set_border_width (12);
1668         block_three.set_border_width (12);
1669         block_four.set_border_width (12);
1670
1671         options.set_spacing (12);
1672
1673         str.clear ();
1674         str.push_back (_("file timestamp"));
1675         str.push_back (_("edit point"));
1676         str.push_back (_("playhead"));
1677         str.push_back (_("session start"));
1678         set_popdown_strings (where_combo, str);
1679         where_combo.set_active_text (str.front());
1680         where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1681
1682         Label* l = manage (new Label);
1683         l->set_markup (_("<b>Add files as ...</b>"));
1684
1685         vbox = manage (new VBox);
1686         vbox->set_border_width (12);
1687         vbox->set_spacing (6);
1688         vbox->pack_start (*l, false, false);
1689         vbox->pack_start (action_combo, false, false);
1690         hbox = manage (new HBox);
1691         hbox->pack_start (*vbox, false, false);
1692         options.pack_start (*hbox, false, false);
1693
1694         /* dummy entry for action combo so that it doesn't look odd if we
1695            come up with no tracks selected.
1696         */
1697
1698         str.clear ();
1699         str.push_back (importmode2string (mode_hint));
1700         set_popdown_strings (action_combo, str);
1701         action_combo.set_active_text (str.front());
1702         action_combo.set_sensitive (false);
1703
1704         l = manage (new Label);
1705         l->set_markup (_("<b>Insert at</b>"));
1706
1707         vbox = manage (new VBox);
1708         vbox->set_border_width (12);
1709         vbox->set_spacing (6);
1710         vbox->pack_start (*l, false, false);
1711         vbox->pack_start (where_combo, false, false);
1712         hbox = manage (new HBox);
1713         hbox->pack_start (*vbox, false, false);
1714         options.pack_start (*hbox, false, false);
1715
1716
1717         l = manage (new Label);
1718         l->set_markup (_("<b>Mapping</b>"));
1719
1720         vbox = manage (new VBox);
1721         vbox->set_border_width (12);
1722         vbox->set_spacing (6);
1723         vbox->pack_start (*l, false, false);
1724         vbox->pack_start (channel_combo, false, false);
1725         hbox = manage (new HBox);
1726         hbox->pack_start (*vbox, false, false);
1727         options.pack_start (*hbox, false, false);
1728
1729         str.clear ();
1730         str.push_back (_("one track per file"));
1731         set_popdown_strings (channel_combo, str);
1732         channel_combo.set_active_text (str.front());
1733         channel_combo.set_sensitive (false);
1734
1735         l = manage (new Label);
1736         l->set_markup (_("<b>Conversion quality</b>"));
1737
1738         vbox = manage (new VBox);
1739         vbox->set_border_width (12);
1740         vbox->set_spacing (6);
1741         vbox->pack_start (*l, false, false);
1742         vbox->pack_start (src_combo, false, false);
1743         hbox = manage (new HBox);
1744         hbox->pack_start (*vbox, false, false);
1745         options.pack_start (*hbox, false, false);
1746
1747         l = manage (new Label);
1748         l->set_markup (_("<b>Instrument</b>"));
1749
1750         vbox = manage (new VBox);
1751         vbox->set_border_width (12);
1752         vbox->set_spacing (6);
1753         vbox->pack_start (*l, false, false);
1754         vbox->pack_start (instrument_combo, false, false);
1755         hbox = manage (new HBox);
1756         hbox->pack_start (*vbox, false, false);
1757         options.pack_start (*hbox, false, false);
1758
1759         str.clear ();
1760         str.push_back (_("Best"));
1761         str.push_back (_("Good"));
1762         str.push_back (_("Quick"));
1763         str.push_back (_("Fast"));
1764         str.push_back (_("Fastest"));
1765
1766         set_popdown_strings (src_combo, str);
1767         src_combo.set_active_text (str.front());
1768         src_combo.set_sensitive (false);
1769         src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1770
1771         reset_options ();
1772
1773         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1774         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1775
1776         copy_files_btn.set_active (true);
1777
1778         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1779
1780         if (copy_label) {
1781                 copy_label->set_size_request (175, -1);
1782                 copy_label->set_line_wrap (true);
1783         }
1784
1785         block_four.pack_start (copy_files_btn, false, false);
1786
1787         options.pack_start (block_four, false, false);
1788
1789         vpacker.pack_start (options, false, false);
1790
1791         /* setup disposition map */
1792
1793         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1794         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1795         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1796         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1797
1798         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1799         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1800         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1801         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1802
1803         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1804
1805         /* set size requests for a couple of combos to allow them to display the longest text
1806            they will ever be asked to display.  This prevents them being resized when the user
1807            selects a file to import, which in turn prevents the size of the dialog from jumping
1808            around. */
1809
1810         vector<string> t;
1811         t.push_back (_("one track per file"));
1812         t.push_back (_("one track per channel"));
1813         t.push_back (_("sequence files"));
1814         t.push_back (_("all files in one region"));
1815         set_popdown_strings (channel_combo, t);
1816
1817         t.clear ();
1818         t.push_back (importmode2string (ImportAsTrack));
1819         t.push_back (importmode2string (ImportToTrack));
1820         t.push_back (importmode2string (ImportAsRegion));
1821         t.push_back (importmode2string (ImportAsTapeTrack));
1822         set_popdown_strings (action_combo, t);
1823 }
1824
1825 void
1826 SoundFileOmega::set_mode (ImportMode mode)
1827 {
1828         action_combo.set_active_text (importmode2string (mode));
1829 }
1830
1831 ImportMode
1832 SoundFileOmega::get_mode () const
1833 {
1834         return string2importmode (action_combo.get_active_text());
1835 }
1836
1837 void
1838 SoundFileOmega::on_hide ()
1839 {
1840         ArdourWindow::on_hide();
1841         if (_session) {
1842                 _session->cancel_audition();
1843         }
1844 }
1845
1846 ImportPosition
1847 SoundFileOmega::get_position() const
1848 {
1849         string str = where_combo.get_active_text();
1850
1851         if (str == _("file timestamp")) {
1852                 return ImportAtTimestamp;
1853         } else if (str == _("edit point")) {
1854                 return ImportAtEditPoint;
1855         } else if (str == _("playhead")) {
1856                 return ImportAtPlayhead;
1857         } else {
1858                 return ImportAtStart;
1859         }
1860 }
1861
1862 SrcQuality
1863 SoundFileOmega::get_src_quality() const
1864 {
1865         string str = src_combo.get_active_text();
1866
1867         if (str == _("Best")) {
1868                 return SrcBest;
1869         } else if (str == _("Good")) {
1870                 return SrcGood;
1871         } else if (str == _("Quick")) {
1872                 return SrcQuick;
1873         } else if (str == _("Fast")) {
1874                 return SrcFast;
1875         } else {
1876                 return SrcFastest;
1877         }
1878 }
1879
1880 void
1881 SoundFileOmega::src_combo_changed()
1882 {
1883         preview.set_src_quality(get_src_quality());
1884 }
1885
1886 void
1887 SoundFileOmega::where_combo_changed()
1888 {
1889         preview.set_import_position(get_position());
1890 }
1891
1892 ImportDisposition
1893 SoundFileOmega::get_channel_disposition () const
1894 {
1895         /* we use a map here because the channel combo can contain different strings
1896            depending on the state of the other combos. the map contains all possible strings
1897            and the ImportDisposition enum that corresponds to it.
1898         */
1899
1900         string str = channel_combo.get_active_text();
1901         DispositionMap::const_iterator x = disposition_map.find (str);
1902
1903         if (x == disposition_map.end()) {
1904                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1905                 abort(); /*NOTREACHED*/
1906         }
1907
1908         return x->second;
1909 }
1910
1911 void
1912 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1913 {
1914         selected_audio_track_cnt = selected_audio_tracks;
1915         selected_midi_track_cnt = selected_midi_tracks;
1916
1917         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1918                 chooser.set_filter (midi_filter);
1919         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1920                 chooser.set_filter (audio_filter);
1921         } else {
1922                 chooser.set_filter (audio_and_midi_filter);
1923         }
1924
1925         reset_options ();
1926 }
1927
1928 void
1929 SoundFileOmega::file_selection_changed ()
1930 {
1931         if (resetting_ourselves) {
1932                 return;
1933         }
1934
1935         if (!reset_options ()) {
1936                 set_action_sensitive (false);
1937         } else {
1938                 if (chooser.get_filenames().size() > 0) {
1939                         set_action_sensitive (true);
1940                 } else {
1941                         set_action_sensitive (false);
1942                 }
1943         }
1944 }
1945
1946 void
1947 SoundFileOmega::do_something (int action)
1948 {
1949         SoundFileBrowser::do_something (action);
1950
1951         if (action == RESPONSE_CLOSE) {
1952                 hide ();
1953                 return;
1954         }
1955
1956         /* lets do it */
1957         
1958         vector<string> paths = get_paths ();
1959         ImportPosition pos = get_position ();
1960         ImportMode mode = get_mode ();
1961         ImportDisposition chns = get_channel_disposition ();
1962         PluginInfoPtr instrument = instrument_combo.selected_instrument();
1963         framepos_t where;
1964         
1965         switch (pos) {
1966         case ImportAtEditPoint:
1967                 where = PublicEditor::instance().get_preferred_edit_position ();
1968                 break;
1969         case ImportAtTimestamp:
1970                 where = -1;
1971                 break;
1972         case ImportAtPlayhead:
1973                 where = _session->transport_frame();
1974                 break;
1975         case ImportAtStart:
1976                 where = _session->current_start_frame();
1977                 break;
1978         }
1979         
1980         SrcQuality quality = get_src_quality();
1981         
1982         if (copy_files_btn.get_active()) {
1983                 PublicEditor::instance().do_import (paths, chns, mode, quality, where, instrument);
1984         } else {
1985                 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
1986         }
1987 }
1988