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