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