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