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