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