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