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