GainMeter(Base) now has an explicit gain control given to it
[ardour.git] / gtk2_ardour / sfdb_ui.cc
1 /*
2     Copyright (C) 2005-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include "i18n.h"
25
26 #include <map>
27 #include <cerrno>
28 #include <sstream>
29
30 #include <unistd.h>
31 #include <limits.h>
32
33 #include <gtkmm/box.h>
34 #include <gtkmm/stock.h>
35
36 #include "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 GTKOSX
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 GTKOSX
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
651         HBox* passbox;
652         Label* label;
653
654         passbox = manage(new HBox);
655         passbox->set_spacing (6);
656
657         label = manage (new Label);
658         label->set_text (_("Tags:"));
659         passbox->pack_start (*label, false, false);
660         passbox->pack_start (freesound_entry, true, true);
661
662         label = manage (new Label);
663         label->set_text (_("Sort:"));
664         passbox->pack_start (*label, false, false);
665         passbox->pack_start (freesound_sort, false, false);
666         freesound_sort.clear_items();
667
668         // Order of the following must correspond with enum sortMethod
669         // in sfdb_freesound_mootcher.h
670         freesound_sort.append_text(_("None"));
671         freesound_sort.append_text(_("Longest"));
672         freesound_sort.append_text(_("Shortest"));
673         freesound_sort.append_text(_("Newest"));
674         freesound_sort.append_text(_("Oldest"));
675         freesound_sort.append_text(_("Most downloaded"));
676         freesound_sort.append_text(_("Least downloaded"));
677         freesound_sort.append_text(_("Highest rated"));
678         freesound_sort.append_text(_("Lowest rated"));
679         freesound_sort.set_active(0);
680
681         passbox->pack_start (freesound_search_btn, false, false);
682         passbox->pack_start (freesound_more_btn, false, false);
683         freesound_more_btn.set_label(_("More"));
684         freesound_more_btn.set_sensitive(false);
685
686         passbox->pack_start (freesound_similar_btn, false, false);
687         freesound_similar_btn.set_label(_("Similar"));
688         freesound_similar_btn.set_sensitive(false);
689
690         scroll = manage(new ScrolledWindow);
691         scroll->add(freesound_list_view);
692         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
693
694         vbox = manage(new VBox);
695         vbox->set_spacing (3);
696         vbox->pack_start (*passbox, PACK_SHRINK);
697         vbox->pack_start (*scroll);
698
699         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
700         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
701         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
702         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
703         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
704         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
705         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
706         freesound_list_view.get_column(0)->set_alignment(0.5);
707         freesound_list_view.get_column(1)->set_expand(true); // filename
708         freesound_list_view.get_column(1)->set_resizable(true); // filename
709         freesound_list_view.get_column(2)->set_alignment(0.5);
710         freesound_list_view.get_column(3)->set_alignment(0.5);
711         freesound_list_view.get_column(4)->set_alignment(0.5);
712         freesound_list_view.get_column(5)->set_alignment(0.5);
713
714         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
715         freesound_list_view.set_tooltip_column(1);
716
717         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
718         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
719         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
720         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
721         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
722         freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
723         notebook.append_page (*vbox, _("Search Freesound"));
724
725         notebook.set_size_request (500, -1);
726         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
727
728         set_session (s);
729
730         Gtk::HButtonBox* button_box = manage (new HButtonBox);
731
732         button_box->set_layout (BUTTONBOX_END);
733         button_box->pack_start (close_button, false, false);
734         close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CLOSE));
735
736         button_box->pack_start (import_button, false, false);
737         import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
738
739         Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
740         Gtkmm2ext::UI::instance()->set_tip (close_button, _("Press to close this window without importing any files"));
741
742         vpacker.pack_end (*button_box, false, false);
743
744         set_wmclass (X_("import"), PROGRAM_NAME);
745 }
746
747 SoundFileBrowser::~SoundFileBrowser ()
748 {
749         persistent_folder = chooser.get_current_folder();
750 }
751
752 int
753 SoundFileBrowser::run ()
754 {
755         set_modal (true);
756         show_all ();
757         present ();
758
759         _done = false;
760
761         while (!_done) {
762                 gtk_main_iteration ();
763         }
764
765         return _status;
766 }
767
768 void
769 SoundFileBrowser::set_action_sensitive (bool yn)
770 {
771         import_button.set_sensitive (yn);
772 }
773
774 void
775 SoundFileBrowser::do_something (int action)
776 {
777         _done = true;
778         _status = action;
779 }
780
781 void
782 SoundFileBrowser::on_show ()
783 {
784         ArdourWindow::on_show ();
785         start_metering ();
786 }
787
788 void
789 SoundFileBrowser::clear_selection ()
790 {
791         chooser.unselect_all ();
792         found_list_view.get_selection()->unselect_all ();
793 }
794
795 void
796 SoundFileBrowser::chooser_file_activated ()
797 {
798         preview.audition ();
799 }
800
801 void
802 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
803 {
804         preview.audition ();
805 }
806
807 void
808 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
809 {
810         preview.audition ();
811 }
812
813 void
814 SoundFileBrowser::set_session (Session* s)
815 {
816         ArdourWindow::set_session (s);
817         preview.set_session (s);
818
819         if (_session) {
820                 add_gain_meter ();
821         } else {
822                 remove_gain_meter ();
823         }
824 }
825
826 void
827 SoundFileBrowser::add_gain_meter ()
828 {
829         delete gm;
830
831         gm = new GainMeter (_session, 250);
832
833         boost::shared_ptr<Route> r = _session->the_auditioner ();
834
835         gm->set_controls (r, r->shared_peak_meter(), r->amp(), r->gain_control());
836         gm->set_fader_name (X_("GainFader"));
837
838         meter_packer.set_border_width (12);
839         meter_packer.pack_start (*gm, false, true);
840         hpacker.pack_end (meter_packer, false, false);
841         meter_packer.show_all ();
842         start_metering ();
843 }
844
845 void
846 SoundFileBrowser::remove_gain_meter ()
847 {
848         if (gm) {
849                 meter_packer.remove (*gm);
850                 hpacker.remove (meter_packer);
851                 delete gm;
852                 gm = 0;
853         }
854 }
855
856 void
857 SoundFileBrowser::start_metering ()
858 {
859         metering_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
860 }
861
862 void
863 SoundFileBrowser::stop_metering ()
864 {
865         metering_connection.disconnect();
866 }
867
868 void
869 SoundFileBrowser::meter ()
870 {
871         if (is_mapped () && _session && gm) {
872                 gm->update_meters ();
873         }
874 }
875
876 bool
877 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
878 {
879         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
880 }
881
882 bool
883 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
884 {
885         return SMFSource::safe_midi_file_extension (filter_info.filename);
886 }
887
888 bool
889 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
890 {
891         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
892 }
893
894 void
895 SoundFileBrowser::update_preview ()
896 {
897         if (preview.setup_labels (chooser.get_preview_filename())) {
898                 if (preview.autoplay()) {
899                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
900                 }
901         }
902 }
903
904 void
905 SoundFileBrowser::found_list_view_selected ()
906 {
907         if (!reset_options ()) {
908                 set_action_sensitive (false);
909         } else {
910                 string file;
911
912                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
913
914                 if (!rows.empty()) {
915                         TreeIter iter = found_list->get_iter(*rows.begin());
916                         file = (*iter)[found_list_columns.pathname];
917                         chooser.set_filename (file);
918                         set_action_sensitive (true);
919                 } else {
920                         set_action_sensitive (false);
921                 }
922
923                 preview.setup_labels (file);
924         }
925 }
926
927 void
928 SoundFileBrowser::found_search_clicked ()
929 {
930         string tag_string = found_entry.get_text ();
931
932         vector<string> tags;
933
934         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
935                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
936                 return;
937         }
938
939         vector<string> results;
940         Library->search_members_and (results, tags);
941
942         found_list->clear();
943         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
944                 TreeModel::iterator new_row = found_list->append();
945                 TreeModel::Row row = *new_row;
946                 string path = Glib::filename_from_uri (string ("file:") + *i);
947                 row[found_list_columns.pathname] = path;
948         }
949 }
950
951
952 std::string
953 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
954 {
955
956         Mootcher *mootcher = new Mootcher;
957         std::string file;
958
959         string id  = (*iter)[freesound_list_columns.id];
960         string uri = (*iter)[freesound_list_columns.uri];
961         string ofn = (*iter)[freesound_list_columns.filename];
962
963         if (mootcher->checkAudioFile(ofn, id)) {
964                 // file already exists, no need to download it again
965                 file = mootcher->audioFileName;
966                 delete mootcher;
967                 (*iter)[freesound_list_columns.started] = false;
968                 return file;
969         }
970         if (!(*iter)[freesound_list_columns.started]) {
971                 // start downloading the sound file
972                 (*iter)[freesound_list_columns.started] = true;
973                 mootcher->fetchAudioFile(ofn, id, uri, this);
974         }
975         return "";
976 }
977
978 void
979 SoundFileBrowser::freesound_list_view_selected ()
980 {
981
982         if (!reset_options ()) {
983                 set_action_sensitive (false);
984         } else {
985                 std::string file;
986                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
987                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
988                         file = freesound_get_audio_file (freesound_list->get_iter(*i));
989                 }
990
991                 switch (rows.size()) {
992                         case 0:
993                                 // nothing selected
994                                 freesound_similar_btn.set_sensitive(false);
995                                 set_action_sensitive (false);
996                                 break;
997                         case 1:
998                                 // exactly one item selected
999                                 if (file != "") {
1000                                         // file exists on disk already
1001                                         chooser.set_filename (file);
1002                                         preview.setup_labels (file);
1003                                         set_action_sensitive (true);
1004                                 }
1005                                 freesound_similar_btn.set_sensitive(true);
1006                                 break;
1007                         default:
1008                                 // multiple items selected
1009                                 preview.setup_labels ("");
1010                                 freesound_similar_btn.set_sensitive(false);
1011                                 break;
1012                 }
1013
1014         }
1015 }
1016
1017 void
1018 SoundFileBrowser::refresh_display(std::string ID, std::string file)
1019 {
1020         // called when the mootcher has finished downloading a file
1021         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1022         if (rows.size() == 1) {
1023                 // there's a single item selected in the freesound list
1024                 //XXX make a function to be used to construct the actual file name both here and in the mootcher
1025                 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
1026                 std::string selected_ID = (*row)[freesound_list_columns.id];
1027                 if (ID == selected_ID) {
1028                         // the selected item in the freesound list is the item that has just finished downloading
1029                         chooser.set_filename(file);
1030                         preview.setup_labels (file);
1031                         set_action_sensitive (true);
1032                 }
1033         }
1034 }
1035
1036 void
1037 SoundFileBrowser::freesound_search_clicked ()
1038 {
1039         freesound_page = 1;
1040         freesound_list->clear();
1041         matches = 0;
1042         freesound_search();
1043 }
1044
1045 void
1046 SoundFileBrowser::freesound_more_clicked ()
1047 {
1048         char row_path[21];
1049         freesound_page++;
1050         freesound_search();
1051         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
1052         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
1053 }
1054
1055 void
1056 SoundFileBrowser::freesound_similar_clicked ()
1057 {
1058         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1059         if (rows.size() == 1) {
1060                 Mootcher mootcher;
1061                 string id;
1062                 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
1063                 id = (*iter)[freesound_list_columns.id];
1064                 freesound_list->clear();
1065
1066                 GdkCursor *prev_cursor;
1067                 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1068                 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1069                 gdk_flush();
1070
1071                 std::string theString = mootcher.searchSimilar(id);
1072
1073                 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1074                 handle_freesound_results(theString);
1075         }
1076 }
1077
1078 void
1079 SoundFileBrowser::freesound_search()
1080 {
1081         Mootcher mootcher;
1082
1083         string search_string = freesound_entry.get_text ();
1084         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
1085
1086         GdkCursor *prev_cursor;
1087         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1088         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1089         gdk_flush();
1090
1091         std::string theString = mootcher.searchText(
1092                         search_string,
1093                         freesound_page,
1094 #ifdef GTKOSX
1095                         "", // OSX eats anything incl mp3
1096 #else
1097                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
1098 #endif
1099                         sort_method
1100                         );
1101
1102         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1103         handle_freesound_results(theString);
1104 }
1105
1106 void
1107 SoundFileBrowser::handle_freesound_results(std::string theString) {
1108         XMLTree doc;
1109         doc.read_buffer( theString );
1110         XMLNode *root = doc.root();
1111
1112         if (!root) {
1113                 error << "no root XML node!" << endmsg;
1114                 return;
1115         }
1116
1117         if ( strcmp(root->name().c_str(), "response") != 0) {
1118                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
1119                 return;
1120         }
1121
1122         // find out how many pages are available to search
1123         int freesound_n_pages = 1;
1124         XMLNode *res = root->child("num_pages");
1125         if (res) {
1126                 string result = res->child("text")->content();
1127                 freesound_n_pages = atoi(result);
1128         }
1129
1130         int more_pages = freesound_n_pages - freesound_page;
1131
1132         if (more_pages > 0) {
1133                 freesound_more_btn.set_sensitive(true);
1134                 freesound_more_btn.set_tooltip_text(string_compose(P_(
1135                                                 "%1 more page of 100 results available",
1136                                                 "%1 more pages of 100 results available",
1137                                                 more_pages), more_pages));
1138         } else {
1139                 freesound_more_btn.set_sensitive(false);
1140                 freesound_more_btn.set_tooltip_text(_("No more results available"));
1141         }
1142
1143         XMLNode *sounds_root = root->child("sounds");
1144         if (!sounds_root) {
1145                 error << "no child node \"sounds\" found!" << endmsg;
1146                 return;
1147         }
1148
1149         XMLNodeList sounds = sounds_root->children();
1150         if (sounds.size() == 0) {
1151                 /* nothing found */
1152                 return;
1153         }
1154
1155         XMLNodeConstIterator niter;
1156         XMLNode *node;
1157         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1158                 node = *niter;
1159                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1160                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1161                         break;
1162                 }
1163
1164                 // node->dump(cerr, "node:");
1165
1166
1167                 XMLNode *id_node  = node->child ("id");
1168                 XMLNode *uri_node = node->child ("serve");
1169                 XMLNode *ofn_node = node->child ("original_filename");
1170                 XMLNode *dur_node = node->child ("duration");
1171                 XMLNode *siz_node = node->child ("filesize");
1172                 XMLNode *srt_node = node->child ("samplerate");
1173                 XMLNode *lic_node = node->child ("license");
1174
1175                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1176
1177                         std::string  id =  id_node->child("text")->content();
1178                         std::string uri = uri_node->child("text")->content();
1179                         std::string ofn = ofn_node->child("text")->content();
1180                         std::string dur = dur_node->child("text")->content();
1181                         std::string siz = siz_node->child("text")->content();
1182                         std::string srt = srt_node->child("text")->content();
1183                         std::string lic = lic_node->child("text")->content();
1184
1185                         std::string r;
1186                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1187
1188                         double duration_seconds = atof(dur);
1189                         double h, m, s;
1190                         char duration_hhmmss[16];
1191                         if (duration_seconds >= 99 * 60 * 60) {
1192                                 strcpy(duration_hhmmss, ">99h");
1193                         } else {
1194                                 s = modf(duration_seconds/60, &m) * 60;
1195                                 m = modf(m/60, &h) * 60;
1196                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1197                                                 h, m, s
1198                                        );
1199                         }
1200
1201                         double size_bytes = atof(siz);
1202                         char bsize[32];
1203                         if (size_bytes < 1000) {
1204                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1205                         } else if (size_bytes < 1000000 ) {
1206                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1207                         } else if (size_bytes < 10000000) {
1208                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1209                         } else if (size_bytes < 1000000000) {
1210                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1211                         } else {
1212                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1213                         }
1214
1215                         /* see http://www.freesound.org/help/faq/#licenses */
1216                         char shortlicense[64];
1217                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1218                                 sprintf(shortlicense, "CC-BY-NC");
1219                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1220                                 sprintf(shortlicense, "CC-BY");
1221                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1222                                 sprintf(shortlicense, "sampling+");
1223                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1224                                 sprintf(shortlicense, "PD");
1225                         } else {
1226                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1227                                 shortlicense[63]= '\0';
1228                         }
1229
1230                         TreeModel::iterator new_row = freesound_list->append();
1231                         TreeModel::Row row = *new_row;
1232
1233                         row[freesound_list_columns.id      ] = id;
1234                         row[freesound_list_columns.uri     ] = uri;
1235                         row[freesound_list_columns.filename] = ofn;
1236                         row[freesound_list_columns.duration] = duration_hhmmss;
1237                         row[freesound_list_columns.filesize] = bsize;
1238                         row[freesound_list_columns.smplrate] = srt;
1239                         row[freesound_list_columns.license ] = shortlicense;
1240                         matches++;
1241                 }
1242         }
1243 }
1244
1245 vector<string>
1246 SoundFileBrowser::get_paths ()
1247 {
1248         vector<string> results;
1249
1250         int n = notebook.get_current_page ();
1251
1252         if (n == 0) {
1253                 vector<string> filenames = chooser.get_filenames();
1254                 vector<string>::iterator i;
1255
1256                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1257                         GStatBuf buf;
1258                         if ((!g_stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1259                                 results.push_back (*i);
1260                         }
1261                 }
1262
1263         } else if (n == 1) {
1264
1265                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1266                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1267                         TreeIter iter = found_list->get_iter(*i);
1268                         string str = (*iter)[found_list_columns.pathname];
1269
1270                         results.push_back (str);
1271                 }
1272         } else {
1273                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1274                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1275                         string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1276                         if (str != "") {
1277                                 results.push_back (str);
1278                         }
1279                 }
1280         }
1281
1282         return results;
1283 }
1284
1285 void
1286 SoundFileOmega::reset_options_noret ()
1287 {
1288         if (!resetting_ourselves) {
1289                 (void) reset_options ();
1290         }
1291 }
1292
1293 bool
1294 SoundFileOmega::reset_options ()
1295 {
1296         if (_import_active) {
1297                 _reset_post_import = true;
1298                 return true;
1299         }
1300
1301         vector<string> paths = get_paths ();
1302
1303         if (paths.empty()) {
1304
1305                 channel_combo.set_sensitive (false);
1306                 action_combo.set_sensitive (false);
1307                 where_combo.set_sensitive (false);
1308                 copy_files_btn.set_active (true);
1309                 copy_files_btn.set_sensitive (false);
1310
1311                 return false;
1312
1313         } else {
1314
1315                 channel_combo.set_sensitive (true);
1316                 action_combo.set_sensitive (true);
1317                 where_combo.set_sensitive (true);
1318
1319                 /* if we get through this function successfully, this may be
1320                    reset at the end, once we know if we can use hard links
1321                    to do embedding (or if we are importing a MIDI file).
1322                 */
1323
1324                 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1325                         copy_files_btn.set_sensitive (false);
1326                 } else {
1327                         copy_files_btn.set_sensitive (false);
1328                 }
1329         }
1330
1331         bool same_size;
1332         bool src_needed;
1333         bool selection_includes_multichannel;
1334         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1335         ImportMode mode;
1336
1337         /* See if we are thinking about importing any MIDI files */
1338         vector<string>::iterator i = paths.begin ();
1339         while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1340                 ++i;
1341         }
1342         bool const have_a_midi_file = (i != paths.end ());
1343
1344         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1345                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1346                 return false;
1347         }
1348
1349         string existing_choice;
1350         vector<string> action_strings;
1351
1352         resetting_ourselves = true;
1353
1354         if (chooser.get_filter() == &audio_filter) {
1355
1356                 /* AUDIO */
1357
1358                 if (selected_audio_track_cnt > 0) {
1359                         if (channel_combo.get_active_text().length()) {
1360                                 ImportDisposition id = get_channel_disposition();
1361
1362                                 switch (id) {
1363                                 case Editing::ImportDistinctFiles:
1364                                         if (selected_audio_track_cnt == paths.size()) {
1365                                                 action_strings.push_back (importmode2string (ImportToTrack));
1366                                         }
1367                                         break;
1368
1369                                 case Editing::ImportDistinctChannels:
1370                                         /* XXX it would be nice to allow channel-per-selected track
1371                                            but its too hard we don't want to deal with all the
1372                                            different per-file + per-track channel configurations.
1373                                         */
1374                                         break;
1375
1376                                 default:
1377                                         action_strings.push_back (importmode2string (ImportToTrack));
1378                                         break;
1379                                 }
1380                         }
1381                 }
1382
1383         }  else {
1384
1385                 /* MIDI ONLY */
1386
1387                 if (selected_midi_track_cnt > 0) {
1388                         action_strings.push_back (importmode2string (ImportToTrack));
1389                 }
1390         }
1391
1392         action_strings.push_back (importmode2string (ImportAsTrack));
1393         action_strings.push_back (importmode2string (ImportAsRegion));
1394         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1395
1396         existing_choice = action_combo.get_active_text();
1397
1398         set_popdown_strings (action_combo, action_strings);
1399
1400         /* preserve any existing choice, if possible */
1401
1402
1403         if (existing_choice.length()) {
1404                 vector<string>::iterator x;
1405                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1406                         if (*x == existing_choice) {
1407                                 action_combo.set_active_text (existing_choice);
1408                                 break;
1409                         }
1410                 }
1411                 if (x == action_strings.end()) {
1412                         action_combo.set_active_text (action_strings.front());
1413                 }
1414         } else {
1415                 action_combo.set_active_text (action_strings.front());
1416         }
1417
1418         resetting_ourselves = false;
1419
1420         if ((mode = get_mode()) == ImportAsRegion) {
1421                 where_combo.set_sensitive (false);
1422         } else {
1423                 where_combo.set_sensitive (true);
1424         }
1425
1426         vector<string> channel_strings;
1427
1428         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1429                 channel_strings.push_back (_("one track per file"));
1430
1431                 if (selection_includes_multichannel) {
1432                         channel_strings.push_back (_("one track per channel"));
1433                 }
1434
1435                 if (paths.size() > 1) {
1436                         /* tape tracks are a single region per track, so we cannot
1437                            sequence multiple files.
1438                         */
1439                         if (mode != ImportAsTapeTrack) {
1440                                 channel_strings.push_back (_("sequence files"));
1441                         }
1442                         if (same_size) {
1443                                 channel_strings.push_back (_("all files in one track"));
1444                                 channel_strings.push_back (_("merge files"));
1445                         }
1446
1447                 }
1448
1449         } else {
1450                 channel_strings.push_back (_("one region per file"));
1451
1452                 if (selection_includes_multichannel) {
1453                         channel_strings.push_back (_("one region per channel"));
1454                 }
1455
1456                 if (paths.size() > 1) {
1457                         if (same_size) {
1458                                 channel_strings.push_back (_("all files in one region"));
1459                         }
1460                 }
1461         }
1462
1463         resetting_ourselves = true;
1464
1465         existing_choice = channel_combo.get_active_text();
1466
1467         set_popdown_strings (channel_combo, channel_strings);
1468
1469         /* preserve any existing choice, if possible */
1470
1471         if (existing_choice.length()) {
1472                 vector<string>::iterator x;
1473                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1474                         if (*x == existing_choice) {
1475                                 channel_combo.set_active_text (existing_choice);
1476                                 break;
1477                         }
1478                 }
1479                 if (x == channel_strings.end()) {
1480                         channel_combo.set_active_text (channel_strings.front());
1481                 }
1482         } else {
1483                 channel_combo.set_active_text (channel_strings.front());
1484         }
1485
1486         resetting_ourselves = false;
1487
1488         if (src_needed) {
1489                 src_combo.set_sensitive (true);
1490         } else {
1491                 src_combo.set_sensitive (false);
1492         }
1493
1494         /* We must copy MIDI files or those from Freesound
1495          * or any file if we are under nsm control */
1496         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1497
1498         if (UIConfiguration::instance().get_only_copy_imported_files()) {
1499
1500                 if (selection_can_be_embedded_with_links && !must_copy) {
1501                         copy_files_btn.set_sensitive (true);
1502                 } else {
1503                         if (must_copy) {
1504                                 copy_files_btn.set_active (true);
1505                         }
1506                         copy_files_btn.set_sensitive (false);
1507                 }
1508
1509         }  else {
1510
1511                 if (must_copy) {
1512                         copy_files_btn.set_active (true);
1513                 }
1514                 copy_files_btn.set_sensitive (!must_copy);
1515         }
1516
1517         return true;
1518 }
1519
1520
1521 bool
1522 SoundFileOmega::bad_file_message()
1523 {
1524         MessageDialog msg (*this,
1525                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1526                            true,
1527                            Gtk::MESSAGE_INFO,
1528                            Gtk::BUTTONS_OK);
1529         msg.run ();
1530         resetting_ourselves = true;
1531         chooser.unselect_uri (chooser.get_preview_uri());
1532         resetting_ourselves = false;
1533
1534         return false;
1535 }
1536
1537 bool
1538 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1539 {
1540         SoundFileInfo info;
1541         framepos_t sz = 0;
1542         bool err = false;
1543         string errmsg;
1544
1545         same_size = true;
1546         src_needed = false;
1547         multichannel = false;
1548
1549         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1550
1551                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1552                         if (info.channels > 1) {
1553                                 multichannel = true;
1554                         }
1555                         if (sz == 0) {
1556                                 sz = info.length;
1557                         } else {
1558                                 if (sz != info.length) {
1559                                         same_size = false;
1560                                 }
1561                         }
1562
1563                         if (info.samplerate != _session->frame_rate()) {
1564                                 src_needed = true;
1565                         }
1566
1567                 } else if (SMFSource::valid_midi_file (*i)) {
1568
1569                         Evoral::SMF reader;
1570                         reader.open(*i);
1571                         if (reader.num_tracks() > 1) {
1572                                 multichannel = true; // "channel" == track here...
1573                         }
1574
1575                         /* XXX we need err = true handling here in case
1576                            we can't check the file
1577                         */
1578
1579                 } else {
1580                         err = true;
1581                 }
1582         }
1583
1584         return err;
1585 }
1586
1587
1588 bool
1589 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1590 {
1591 #ifdef PLATFORM_WINDOWS
1592         return false;
1593 #else
1594         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1595         bool ret = false;
1596
1597         if (g_mkdir (tmpdir.c_str(), 0744)) {
1598                 if (errno != EEXIST) {
1599                         return false;
1600                 }
1601         }
1602
1603         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1604
1605                 char tmpc[PATH_MAX+1];
1606
1607                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1608
1609                 /* can we link ? */
1610
1611                 if (link ((*i).c_str(), tmpc)) {
1612                         goto out;
1613                 }
1614
1615                 ::g_unlink (tmpc);
1616         }
1617
1618         ret = true;
1619
1620   out:
1621         g_rmdir (tmpdir.c_str());
1622         return ret;
1623 #endif
1624 }
1625
1626 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1627         : SoundFileBrowser (title, s, false)
1628 {
1629         chooser.set_select_multiple (false);
1630         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1631         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1632 }
1633
1634 void
1635 SoundFileChooser::on_hide ()
1636 {
1637         ArdourWindow::on_hide();
1638         stop_metering ();
1639
1640         if (_session) {
1641                 _session->cancel_audition();
1642         }
1643 }
1644
1645 string
1646 SoundFileChooser::get_filename ()
1647 {
1648         vector<string> paths;
1649
1650         paths = get_paths ();
1651
1652         if (paths.empty()) {
1653                 return string ();
1654         }
1655
1656         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1657                 return string();
1658         }
1659
1660         return paths.front();
1661 }
1662
1663 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1664                                 uint32_t selected_audio_tracks,
1665                                 uint32_t selected_midi_tracks,
1666                                 bool persistent,
1667                                 Editing::ImportMode mode_hint)
1668         : SoundFileBrowser (title, s, persistent)
1669         , copy_files_btn ( _("Copy files to session"))
1670         , selected_audio_track_cnt (selected_audio_tracks)
1671         , selected_midi_track_cnt (selected_midi_tracks)
1672         , _import_active (false)
1673         , _reset_post_import (false)
1674 {
1675         VBox* vbox;
1676         HBox* hbox;
1677         vector<string> str;
1678
1679         set_size_request (-1, 450);
1680
1681         block_two.set_border_width (12);
1682         block_three.set_border_width (12);
1683         block_four.set_border_width (12);
1684
1685         options.set_spacing (12);
1686
1687         str.clear ();
1688         str.push_back (_("file timestamp"));
1689         str.push_back (_("edit point"));
1690         str.push_back (_("playhead"));
1691         str.push_back (_("session start"));
1692         set_popdown_strings (where_combo, str);
1693         where_combo.set_active_text (str.front());
1694         where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1695
1696         Label* l = manage (new Label);
1697         l->set_markup (_("<b>Add files ...</b>"));
1698
1699         vbox = manage (new VBox);
1700         vbox->set_border_width (12);
1701         vbox->set_spacing (6);
1702         vbox->pack_start (*l, false, false);
1703         vbox->pack_start (action_combo, false, false);
1704         hbox = manage (new HBox);
1705         hbox->pack_start (*vbox, false, false);
1706         options.pack_start (*hbox, false, false);
1707
1708         l = manage (new Label);
1709         l->set_markup (_("<b>Insert at</b>"));
1710
1711         vbox = manage (new VBox);
1712         vbox->set_border_width (12);
1713         vbox->set_spacing (6);
1714         vbox->pack_start (*l, false, false);
1715         vbox->pack_start (where_combo, false, false);
1716         hbox = manage (new HBox);
1717         hbox->pack_start (*vbox, false, false);
1718         options.pack_start (*hbox, false, false);
1719
1720
1721         l = manage (new Label);
1722         l->set_markup (_("<b>Mapping</b>"));
1723
1724         vbox = manage (new VBox);
1725         vbox->set_border_width (12);
1726         vbox->set_spacing (6);
1727         vbox->pack_start (*l, false, false);
1728         vbox->pack_start (channel_combo, false, false);
1729         hbox = manage (new HBox);
1730         hbox->pack_start (*vbox, false, false);
1731         options.pack_start (*hbox, false, false);
1732
1733         str.clear ();
1734         str.push_back (_("one track per file"));
1735         set_popdown_strings (channel_combo, str);
1736         channel_combo.set_active_text (str.front());
1737         channel_combo.set_sensitive (false);
1738
1739         l = manage (new Label);
1740         l->set_markup (_("<b>Conversion quality</b>"));
1741
1742         vbox = manage (new VBox);
1743         vbox->set_border_width (12);
1744         vbox->set_spacing (6);
1745         vbox->pack_start (*l, false, false);
1746         vbox->pack_start (src_combo, false, false);
1747         hbox = manage (new HBox);
1748         hbox->pack_start (*vbox, false, false);
1749         options.pack_start (*hbox, false, false);
1750
1751         l = manage (new Label);
1752         l->set_markup (_("<b>Instrument</b>"));
1753
1754         vbox = manage (new VBox);
1755         vbox->set_border_width (12);
1756         vbox->set_spacing (6);
1757         vbox->pack_start (*l, false, false);
1758         vbox->pack_start (instrument_combo, false, false);
1759         hbox = manage (new HBox);
1760         hbox->pack_start (*vbox, false, false);
1761         options.pack_start (*hbox, false, false);
1762
1763         str.clear ();
1764         str.push_back (_("Best"));
1765         str.push_back (_("Good"));
1766         str.push_back (_("Quick"));
1767         str.push_back (_("Fast"));
1768         str.push_back (_("Fastest"));
1769
1770         set_popdown_strings (src_combo, str);
1771         src_combo.set_active_text (str.front());
1772         src_combo.set_sensitive (false);
1773         src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1774
1775         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1776         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1777
1778         copy_files_btn.set_active (true);
1779
1780         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1781
1782         if (copy_label) {
1783                 copy_label->set_size_request (175, -1);
1784                 copy_label->set_line_wrap (true);
1785         }
1786
1787         block_four.pack_start (copy_files_btn, false, false);
1788
1789         options.pack_start (block_four, false, false);
1790
1791         vpacker.pack_start (options, false, false);
1792
1793         /* setup disposition map */
1794
1795         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1796         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1797         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1798         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1799
1800         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1801         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1802         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1803         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1804
1805         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1806
1807         /* set size requests for a couple of combos to allow them to display the longest text
1808            they will ever be asked to display.  This prevents them being resized when the user
1809            selects a file to import, which in turn prevents the size of the dialog from jumping
1810            around. */
1811
1812         str.clear ();
1813         str.push_back (_("one track per file"));
1814         str.push_back (_("one track per channel"));
1815         str.push_back (_("sequence files"));
1816         str.push_back (_("all files in one region"));
1817         set_popdown_strings (channel_combo, str);
1818
1819         str.clear ();
1820         str.push_back (importmode2string (ImportAsTrack));
1821         str.push_back (importmode2string (ImportToTrack));
1822         str.push_back (importmode2string (ImportAsRegion));
1823         str.push_back (importmode2string (ImportAsTapeTrack));
1824         set_popdown_strings (action_combo, str);
1825         action_combo.set_active_text (importmode2string(mode_hint));
1826
1827         reset (selected_audio_tracks, selected_midi_tracks);
1828 }
1829
1830 void
1831 SoundFileOmega::set_mode (ImportMode mode)
1832 {
1833         action_combo.set_active_text (importmode2string (mode));
1834 }
1835
1836 ImportMode
1837 SoundFileOmega::get_mode () const
1838 {
1839         return string2importmode (action_combo.get_active_text());
1840 }
1841
1842 void
1843 SoundFileOmega::on_hide ()
1844 {
1845         ArdourWindow::on_hide();
1846         if (_session) {
1847                 _session->cancel_audition();
1848         }
1849 }
1850
1851 ImportPosition
1852 SoundFileOmega::get_position() const
1853 {
1854         string str = where_combo.get_active_text();
1855
1856         if (str == _("file timestamp")) {
1857                 return ImportAtTimestamp;
1858         } else if (str == _("edit point")) {
1859                 return ImportAtEditPoint;
1860         } else if (str == _("playhead")) {
1861                 return ImportAtPlayhead;
1862         } else {
1863                 return ImportAtStart;
1864         }
1865 }
1866
1867 SrcQuality
1868 SoundFileOmega::get_src_quality() const
1869 {
1870         string str = src_combo.get_active_text();
1871
1872         if (str == _("Best")) {
1873                 return SrcBest;
1874         } else if (str == _("Good")) {
1875                 return SrcGood;
1876         } else if (str == _("Quick")) {
1877                 return SrcQuick;
1878         } else if (str == _("Fast")) {
1879                 return SrcFast;
1880         } else {
1881                 return SrcFastest;
1882         }
1883 }
1884
1885 void
1886 SoundFileOmega::src_combo_changed()
1887 {
1888         preview.set_src_quality(get_src_quality());
1889 }
1890
1891 void
1892 SoundFileOmega::where_combo_changed()
1893 {
1894         preview.set_import_position(get_position());
1895 }
1896
1897 ImportDisposition
1898 SoundFileOmega::get_channel_disposition () const
1899 {
1900         /* we use a map here because the channel combo can contain different strings
1901            depending on the state of the other combos. the map contains all possible strings
1902            and the ImportDisposition enum that corresponds to it.
1903         */
1904
1905         string str = channel_combo.get_active_text();
1906         DispositionMap::const_iterator x = disposition_map.find (str);
1907
1908         if (x == disposition_map.end()) {
1909                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1910                 abort(); /*NOTREACHED*/
1911         }
1912
1913         return x->second;
1914 }
1915
1916 void
1917 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1918 {
1919         selected_audio_track_cnt = selected_audio_tracks;
1920         selected_midi_track_cnt = selected_midi_tracks;
1921
1922         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1923                 chooser.set_filter (midi_filter);
1924         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1925                 chooser.set_filter (audio_filter);
1926         } else {
1927                 chooser.set_filter (audio_and_midi_filter);
1928         }
1929
1930         reset_options ();
1931 }
1932
1933 void
1934 SoundFileOmega::file_selection_changed ()
1935 {
1936         if (resetting_ourselves) {
1937                 return;
1938         }
1939
1940         if (!reset_options ()) {
1941                 set_action_sensitive (false);
1942         } else {
1943                 if (chooser.get_filenames().size() > 0) {
1944                         set_action_sensitive (true);
1945                 } else {
1946                         set_action_sensitive (false);
1947                 }
1948         }
1949 }
1950
1951 void
1952 SoundFileOmega::do_something (int action)
1953 {
1954         SoundFileBrowser::do_something (action);
1955
1956         if (action == RESPONSE_CLOSE) {
1957                 hide ();
1958                 return;
1959         }
1960
1961         /* lets do it */
1962
1963         vector<string> paths = get_paths ();
1964         ImportPosition pos = get_position ();
1965         ImportMode mode = get_mode ();
1966         ImportDisposition chns = get_channel_disposition ();
1967         PluginInfoPtr instrument = instrument_combo.selected_instrument();
1968         framepos_t where;
1969
1970         switch (pos) {
1971         case ImportAtEditPoint:
1972                 where = PublicEditor::instance().get_preferred_edit_position ();
1973                 break;
1974         case ImportAtTimestamp:
1975                 where = -1;
1976                 break;
1977         case ImportAtPlayhead:
1978                 where = _session->transport_frame();
1979                 break;
1980         case ImportAtStart:
1981                 where = _session->current_start_frame();
1982                 break;
1983         }
1984
1985         SrcQuality quality = get_src_quality();
1986
1987         _import_active = true;
1988
1989         if (copy_files_btn.get_active()) {
1990                 PublicEditor::instance().do_import (paths, chns, mode, quality, where, instrument);
1991         } else {
1992                 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
1993         }
1994
1995         _import_active = false;
1996
1997         if (_reset_post_import) {
1998                 _reset_post_import = false;
1999                 reset_options ();
2000         }
2001 }
2002