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