improving logic/flow for SMF type 1 files part 1:
[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
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
1582                         if (reader.open (*i)) {
1583                                 err = true;
1584                         } else {
1585                                 if (reader.is_type0 ()) {
1586                                         if (reader.channels().size() > 1) {
1587                                                 /* for type-0 files, we can split
1588                                                  * "one track per channel"
1589                                                  */
1590                                                 multichannel = true;
1591                                         }
1592                                 } else {
1593                                         if (reader.num_tracks() > 1) {
1594                                                 multichannel = true;
1595                                         }
1596                                 }
1597                         }
1598
1599                 } else {
1600                         err = true;
1601                 }
1602         }
1603
1604         return err;
1605 }
1606
1607
1608 bool
1609 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1610 {
1611 #ifdef PLATFORM_WINDOWS
1612         return false;
1613 #else
1614         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1615         bool ret = false;
1616
1617         if (g_mkdir (tmpdir.c_str(), 0744)) {
1618                 if (errno != EEXIST) {
1619                         return false;
1620                 }
1621         }
1622
1623         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1624
1625                 char tmpc[PATH_MAX+1];
1626
1627                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1628
1629                 /* can we link ? */
1630
1631                 if (link ((*i).c_str(), tmpc)) {
1632                         goto out;
1633                 }
1634
1635                 ::g_unlink (tmpc);
1636         }
1637
1638         ret = true;
1639
1640   out:
1641         g_rmdir (tmpdir.c_str());
1642         return ret;
1643 #endif
1644 }
1645
1646 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1647         : SoundFileBrowser (title, s, false)
1648 {
1649         chooser.set_select_multiple (false);
1650         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1651         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1652 }
1653
1654 void
1655 SoundFileChooser::on_hide ()
1656 {
1657         ArdourWindow::on_hide();
1658         stop_metering ();
1659
1660         if (_session) {
1661                 _session->cancel_audition();
1662         }
1663 }
1664
1665 string
1666 SoundFileChooser::get_filename ()
1667 {
1668         vector<string> paths;
1669
1670         paths = get_paths ();
1671
1672         if (paths.empty()) {
1673                 return string ();
1674         }
1675
1676         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1677                 return string();
1678         }
1679
1680         return paths.front();
1681 }
1682
1683 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1684                                 uint32_t selected_audio_tracks,
1685                                 uint32_t selected_midi_tracks,
1686                                 bool persistent,
1687                                 Editing::ImportMode mode_hint)
1688         : SoundFileBrowser (title, s, persistent)
1689         , copy_files_btn ( _("Copy files to session"))
1690         , selected_audio_track_cnt (selected_audio_tracks)
1691         , selected_midi_track_cnt (selected_midi_tracks)
1692         , _import_active (false)
1693         , _reset_post_import (false)
1694 {
1695         vector<string> str;
1696
1697         set_size_request (-1, 550);
1698
1699         block_two.set_border_width (12);
1700         block_three.set_border_width (12);
1701         block_four.set_border_width (12);
1702
1703         str.clear ();
1704         str.push_back (_("file timestamp"));
1705         str.push_back (_("edit point"));
1706         str.push_back (_("playhead"));
1707         str.push_back (_("session start"));
1708         set_popdown_strings (where_combo, str);
1709         where_combo.set_active_text (str.back());
1710         where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1711
1712         Label* l = manage (new Label);
1713         l->set_markup (_("<b>Add files ...</b>"));
1714         options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
1715         options.attach (action_combo, 0, 1, 1, 2, FILL, SHRINK, 8, 0);
1716
1717         l = manage (new Label);
1718         l->set_markup (_("<b>Insert at</b>"));
1719         options.attach (*l, 0, 1, 3, 4, FILL, SHRINK, 8, 0);
1720         options.attach (where_combo, 0, 1, 4, 5, FILL, SHRINK, 8, 0);
1721
1722         l = manage (new Label);
1723         l->set_markup (_("<b>Mapping</b>"));
1724         options.attach (*l, 1, 2, 0, 1, FILL, SHRINK, 8, 0);
1725         options.attach (channel_combo, 1, 2, 1, 2, FILL, SHRINK, 8, 0);
1726
1727         l = manage (new Label);
1728         l->set_markup (_("<b>Conversion quality</b>"));
1729         options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
1730         options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
1731
1732         l = manage (new Label);
1733         l->set_markup (_("<b>Instrument</b>"));
1734         options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
1735         options.attach (instrument_combo, 3, 4, 1, 2, FILL, SHRINK, 8, 0);
1736
1737         Alignment *hspace = manage (new Alignment ());
1738         hspace->set_size_request (2, 2);
1739         options.attach (*hspace, 0, 3, 2, 3, FILL, SHRINK, 0, 8);
1740
1741         Alignment *vspace = manage (new Alignment ());
1742         vspace->set_size_request (2, 2);
1743         options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
1744
1745         str.clear ();
1746         str.push_back (_("one track per file"));
1747         set_popdown_strings (channel_combo, str);
1748         channel_combo.set_active_text (str.front());
1749         channel_combo.set_sensitive (false);
1750
1751         str.clear ();
1752         str.push_back (_("Best"));
1753         str.push_back (_("Good"));
1754         str.push_back (_("Quick"));
1755         str.push_back (_("Fast"));
1756         str.push_back (_("Fastest"));
1757
1758         set_popdown_strings (src_combo, str);
1759         src_combo.set_active_text (str.front());
1760         src_combo.set_sensitive (false);
1761         src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1762
1763         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1764         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1765
1766         copy_files_btn.set_active (true);
1767
1768         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1769
1770         if (copy_label) {
1771                 copy_label->set_size_request (175, -1);
1772                 copy_label->set_line_wrap (true);
1773         }
1774
1775         block_four.pack_start (copy_files_btn, false, false);
1776         options.attach (block_four, 3, 4, 4, 5, FILL, SHRINK, 8, 0);
1777
1778         vpacker.pack_start (options, false, true);
1779
1780         /* setup disposition map */
1781
1782         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1783         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1784         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1785         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1786
1787         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1788         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1789         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1790         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1791
1792         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1793
1794         /* set size requests for a couple of combos to allow them to display the longest text
1795            they will ever be asked to display.  This prevents them being resized when the user
1796            selects a file to import, which in turn prevents the size of the dialog from jumping
1797            around. */
1798
1799         str.clear ();
1800         str.push_back (_("one track per file"));
1801         str.push_back (_("one track per channel"));
1802         str.push_back (_("sequence files"));
1803         str.push_back (_("all files in one region"));
1804         set_popdown_strings (channel_combo, str);
1805
1806         str.clear ();
1807         str.push_back (importmode2string (ImportAsTrack));
1808         str.push_back (importmode2string (ImportToTrack));
1809         str.push_back (importmode2string (ImportAsRegion));
1810         str.push_back (importmode2string (ImportAsTapeTrack));
1811         set_popdown_strings (action_combo, str);
1812         action_combo.set_active_text (importmode2string(mode_hint));
1813
1814         reset (selected_audio_tracks, selected_midi_tracks);
1815 }
1816
1817 void
1818 SoundFileOmega::set_mode (ImportMode mode)
1819 {
1820         action_combo.set_active_text (importmode2string (mode));
1821 }
1822
1823 ImportMode
1824 SoundFileOmega::get_mode () const
1825 {
1826         return string2importmode (action_combo.get_active_text());
1827 }
1828
1829 void
1830 SoundFileOmega::on_hide ()
1831 {
1832         ArdourWindow::on_hide();
1833         if (_session) {
1834                 _session->cancel_audition();
1835         }
1836 }
1837
1838 ImportPosition
1839 SoundFileOmega::get_position() const
1840 {
1841         string str = where_combo.get_active_text();
1842
1843         if (str == _("file timestamp")) {
1844                 return ImportAtTimestamp;
1845         } else if (str == _("edit point")) {
1846                 return ImportAtEditPoint;
1847         } else if (str == _("playhead")) {
1848                 return ImportAtPlayhead;
1849         } else {
1850                 return ImportAtStart;
1851         }
1852 }
1853
1854 SrcQuality
1855 SoundFileOmega::get_src_quality() const
1856 {
1857         string str = src_combo.get_active_text();
1858
1859         if (str == _("Best")) {
1860                 return SrcBest;
1861         } else if (str == _("Good")) {
1862                 return SrcGood;
1863         } else if (str == _("Quick")) {
1864                 return SrcQuick;
1865         } else if (str == _("Fast")) {
1866                 return SrcFast;
1867         } else {
1868                 return SrcFastest;
1869         }
1870 }
1871
1872 void
1873 SoundFileOmega::src_combo_changed()
1874 {
1875         preview.set_src_quality(get_src_quality());
1876 }
1877
1878 void
1879 SoundFileOmega::where_combo_changed()
1880 {
1881         preview.set_import_position(get_position());
1882 }
1883
1884 ImportDisposition
1885 SoundFileOmega::get_channel_disposition () const
1886 {
1887         /* we use a map here because the channel combo can contain different strings
1888            depending on the state of the other combos. the map contains all possible strings
1889            and the ImportDisposition enum that corresponds to it.
1890         */
1891
1892         string str = channel_combo.get_active_text();
1893         DispositionMap::const_iterator x = disposition_map.find (str);
1894
1895         if (x == disposition_map.end()) {
1896                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1897                 abort(); /*NOTREACHED*/
1898         }
1899
1900         return x->second;
1901 }
1902
1903 void
1904 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1905 {
1906         selected_audio_track_cnt = selected_audio_tracks;
1907         selected_midi_track_cnt = selected_midi_tracks;
1908
1909         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1910                 chooser.set_filter (midi_filter);
1911         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1912                 chooser.set_filter (audio_filter);
1913         } else {
1914                 chooser.set_filter (audio_and_midi_filter);
1915         }
1916
1917         reset_options ();
1918 }
1919
1920 void
1921 SoundFileOmega::file_selection_changed ()
1922 {
1923         if (resetting_ourselves) {
1924                 return;
1925         }
1926
1927         if (!reset_options ()) {
1928                 set_action_sensitive (false);
1929         } else {
1930                 if (chooser.get_filenames().size() > 0) {
1931                         set_action_sensitive (true);
1932                 } else {
1933                         set_action_sensitive (false);
1934                 }
1935         }
1936 }
1937
1938 void
1939 SoundFileOmega::do_something (int action)
1940 {
1941         SoundFileBrowser::do_something (action);
1942
1943         if (action == RESPONSE_CLOSE) {
1944                 hide ();
1945                 return;
1946         }
1947
1948         /* lets do it */
1949
1950         vector<string> paths = get_paths ();
1951         ImportPosition pos = get_position ();
1952         ImportMode mode = get_mode ();
1953         ImportDisposition chns = get_channel_disposition ();
1954         PluginInfoPtr instrument = instrument_combo.selected_instrument();
1955         framepos_t where;
1956
1957         switch (pos) {
1958         case ImportAtEditPoint:
1959                 where = PublicEditor::instance().get_preferred_edit_position ();
1960                 break;
1961         case ImportAtTimestamp:
1962                 where = -1;
1963                 break;
1964         case ImportAtPlayhead:
1965                 where = _session->transport_frame();
1966                 break;
1967         case ImportAtStart:
1968                 where = _session->current_start_frame();
1969                 break;
1970         }
1971
1972         SrcQuality quality = get_src_quality();
1973
1974         _import_active = true;
1975
1976         if (copy_files_btn.get_active()) {
1977                 PublicEditor::instance().do_import (paths, chns, mode, quality, where, instrument);
1978         } else {
1979                 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
1980         }
1981
1982         _import_active = false;
1983
1984         if (_reset_post_import) {
1985                 _reset_post_import = false;
1986                 reset_options ();
1987         }
1988 }
1989