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