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