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