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