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