aa8d7b77f2a24164e23731b26964e9d624bc12ee
[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 #include <map>
21 #include <cerrno>
22 #include <sstream>
23
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
27
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
31
32 #include "pbd/convert.h"
33 #include "pbd/tokenizer.h"
34 #include "pbd/enumwriter.h"
35 #include "pbd/pthread_utils.h"
36 #include "pbd/xml++.h"
37
38 #include <gtkmm2ext/utils.h>
39
40 #include "evoral/SMF.hpp"
41
42 #include "ardour/amp.h"
43 #include "ardour/audio_library.h"
44 #include "ardour/auditioner.h"
45 #include "ardour/audioregion.h"
46 #include "ardour/audiofilesource.h"
47 #include "ardour/smf_source.h"
48 #include "ardour/region_factory.h"
49 #include "ardour/source_factory.h"
50 #include "ardour/session.h"
51 #include "ardour/session_directory.h"
52 #include "ardour/profile.h"
53
54 #include "ardour_ui.h"
55 #include "editing.h"
56 #include "gui_thread.h"
57 #include "prompter.h"
58 #include "sfdb_ui.h"
59 #include "editing.h"
60 #include "utils.h"
61 #include "gain_meter.h"
62
63 #ifdef FREESOUND
64 #include "sfdb_freesound_mootcher.h"
65 #endif
66
67 #include "i18n.h"
68
69 using namespace ARDOUR;
70 using namespace PBD;
71 using namespace std;
72 using namespace Gtk;
73 using namespace Gtkmm2ext;
74 using namespace Editing;
75
76 using Glib::ustring;
77
78 ustring SoundFileBrowser::persistent_folder;
79
80 static ImportMode
81 string2importmode (string str)
82 {
83         if (str == _("as new tracks")) {
84                 return ImportAsTrack;
85         } else if (str == _("to selected tracks")) {
86                 return ImportToTrack;
87         } else if (str == _("to region list")) {
88                 return ImportAsRegion;
89         } else if (str == _("as new tape tracks")) {
90                 return ImportAsTapeTrack;
91         }
92
93         warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
94
95         return ImportAsTrack;
96 }
97
98 static string
99 importmode2string (ImportMode mode)
100 {
101         switch (mode) {
102         case ImportAsTrack:
103                 return _("as new tracks");
104         case ImportToTrack:
105                 return _("to selected tracks");
106         case ImportAsRegion:
107                 return _("to region list");
108         case ImportAsTapeTrack:
109                 return _("as new tape tracks");
110         }
111         /*NOTREACHED*/
112         return _("as new tracks");
113 }
114
115 SoundFileBox::SoundFileBox (bool persistent)
116         : _session(0),
117           table (6, 2),
118           length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, false, true, false),
119           timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false, false),
120           main_box (false, 6),
121           autoplay_btn (_("Auto-play"))
122
123 {
124         set_name (X_("SoundFileBox"));
125         set_size_request (300, -1);
126
127         preview_label.set_markup (_("<b>Sound File Information</b>"));
128
129         border_frame.set_label_widget (preview_label);
130         border_frame.add (main_box);
131
132         pack_start (border_frame, true, true);
133         set_border_width (6);
134
135         main_box.set_border_width (6);
136
137         length.set_text (_("Length:"));
138         length.set_alignment (1, 0.5);
139         timecode.set_text (_("Timestamp:"));
140         timecode.set_alignment (1, 0.5);
141         format.set_text (_("Format:"));
142         format.set_alignment (1, 0.5);
143         channels.set_text (_("Channels:"));
144         channels.set_alignment (1, 0.5);
145         samplerate.set_text (_("Sample rate:"));
146         samplerate.set_alignment (1, 0.5);
147
148         format_text.set_max_width_chars (8);
149         format_text.set_ellipsize (Pango::ELLIPSIZE_END);
150         format_text.set_alignment (0, 1);
151
152         table.set_col_spacings (6);
153         table.set_homogeneous (false);
154         table.set_row_spacings (6);
155
156         table.attach (channels, 0, 1, 0, 1, FILL, FILL);
157         table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
158         table.attach (format, 0, 1, 2, 4, FILL, FILL);
159         table.attach (length, 0, 1, 4, 5, FILL, FILL);
160         table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
161
162         table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
163         table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
164         table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
165         table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
166         table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
167
168         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
169         timecode_clock.set_mode (AudioClock::Timecode);
170
171         main_box.pack_start (table, false, false);
172
173         tags_entry.set_editable (true);
174         tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
175
176         Label* label = manage (new Label (_("Tags:")));
177         label->set_alignment (0.0f, 0.5f);
178         main_box.pack_start (*label, false, false);
179         main_box.pack_start (tags_entry, true, true);
180
181         main_box.pack_start (bottom_box, false, false);
182
183         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
184         play_btn.set_label (_("Play"));
185
186         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
187         stop_btn.set_label (_("Stop"));
188
189         bottom_box.set_homogeneous (false);
190         bottom_box.set_spacing (6);
191         bottom_box.pack_start(play_btn, true, true);
192         bottom_box.pack_start(stop_btn, true, true);
193         bottom_box.pack_start(autoplay_btn, false, false);
194
195         play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
196         stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
197
198         channels_value.set_alignment (0.0f, 0.5f);
199         samplerate_value.set_alignment (0.0f, 0.5f);
200 }
201
202 void
203 SoundFileBox::set_session(Session* s)
204 {
205         _session = s;
206
207         if (!_session) {
208                 play_btn.set_sensitive (false);
209                 stop_btn.set_sensitive (false);
210         }
211
212
213         length_clock.set_session (s);
214         timecode_clock.set_session (s);
215 }
216
217 bool
218 SoundFileBox::setup_labels (const ustring& filename)
219 {
220         if (!path.empty()) {
221                 // save existing tags
222                 tags_changed ();
223         }
224
225         path = filename;
226
227         string error_msg;
228
229         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
230
231                 preview_label.set_markup (_("<b>Sound File Information</b>"));
232                 format_text.set_text ("");
233                 channels_value.set_text ("");
234                 samplerate_value.set_text ("");
235                 tags_entry.get_buffer()->set_text ("");
236
237                 length_clock.set (0);
238                 timecode_clock.set (0);
239
240                 tags_entry.set_sensitive (false);
241                 play_btn.set_sensitive (false);
242
243                 return false;
244         }
245
246         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
247         std::string n = sf_info.format_name;
248         if (n.substr (0, 8) == X_("Format: ")) {
249                 n = n.substr (8);
250         }
251         format_text.set_text (n);
252         channels_value.set_text (to_string (sf_info.channels, std::dec));
253
254         if (_session && sf_info.samplerate != _session->frame_rate()) {
255                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
256                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
257                 samplerate_value.set_name ("NewSessionSR1Label");
258                 samplerate.set_name ("NewSessionSR1Label");
259         } else {
260                 samplerate.set_text (_("Sample rate:"));
261                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
262                 samplerate_value.set_name ("NewSessionSR2Label");
263                 samplerate.set_name ("NewSessionSR2Label");
264         }
265
266         nframes_t const nfr = _session ? _session->nominal_frame_rate() : 25;
267         double src_coef = (double) nfr / sf_info.samplerate;
268
269         length_clock.set (sf_info.length * src_coef + 0.5, true);
270         timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
271
272         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
273
274         vector<string> tags = Library->get_tags (string ("//") + filename);
275
276         stringstream tag_string;
277         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
278                 if (i != tags.begin()) {
279                         tag_string << ", ";
280                 }
281                 tag_string << *i;
282         }
283         tags_entry.get_buffer()->set_text (tag_string.str());
284
285         tags_entry.set_sensitive (true);
286         if (_session) {
287                 play_btn.set_sensitive (true);
288         }
289
290         return true;
291 }
292
293 bool
294 SoundFileBox::autoplay() const
295 {
296         return autoplay_btn.get_active();
297 }
298
299 bool
300 SoundFileBox::audition_oneshot()
301 {
302         audition ();
303         return false;
304 }
305
306 void
307 SoundFileBox::audition ()
308 {
309         if (!_session) {
310                 return;
311         }
312
313         _session->cancel_audition();
314
315         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
316                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
317                 return;
318         }
319
320         boost::shared_ptr<Region> r;
321         SourceList srclist;
322         boost::shared_ptr<AudioFileSource> afs;
323         bool old_sbp = AudioSource::get_build_peakfiles ();
324
325         /* don't even think of building peakfiles for these files */
326
327         AudioSource::set_build_peakfiles (false);
328
329         for (int n = 0; n < sf_info.channels; ++n) {
330                 try {
331                         afs = boost::dynamic_pointer_cast<AudioFileSource> (
332                                         SourceFactory::createReadable (DataType::AUDIO, *_session,
333                                                         path, n, Source::Flag (0), false));
334
335                         srclist.push_back(afs);
336
337                 } catch (failed_constructor& err) {
338                         error << _("Could not access soundfile: ") << path << endmsg;
339                         AudioSource::set_build_peakfiles (old_sbp);
340                         return;
341                 }
342         }
343
344         AudioSource::set_build_peakfiles (old_sbp);
345
346         if (srclist.empty()) {
347                 return;
348         }
349
350         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
351         string rname = region_name_from_path (afs->path(), false);
352         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0,
353                                 srclist[0]->length(srclist[0]->timeline_position()),
354                                 rname, 0, Region::DefaultFlags, false));
355
356         _session->audition_region(r);
357 }
358
359 void
360 SoundFileBox::stop_audition ()
361 {
362         if (_session) {
363                 _session->cancel_audition();
364         }
365 }
366
367 bool
368 SoundFileBox::tags_entry_left (GdkEventFocus *)
369 {
370         tags_changed ();
371         return false;
372 }
373
374 void
375 SoundFileBox::tags_changed ()
376 {
377         string tag_string = tags_entry.get_buffer()->get_text ();
378
379         if (tag_string.empty()) {
380                 return;
381         }
382
383         vector<string> tags;
384
385         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
386                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
387                 return;
388         }
389
390         save_tags (tags);
391 }
392
393 void
394 SoundFileBox::save_tags (const vector<string>& tags)
395 {
396         Library->set_tags (string ("//") + path, tags);
397         Library->save_changes ();
398 }
399
400 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
401         : ArdourDialog (parent, title, false, false),
402           found_list (ListStore::create(found_list_columns)),
403           freesound_list (ListStore::create(freesound_list_columns)),
404           chooser (FILE_CHOOSER_ACTION_OPEN),
405           preview (persistent),
406           found_search_btn (_("Search")),
407           found_list_view (found_list),
408           freesound_search_btn (_("Start Downloading")),
409           freesound_list_view (freesound_list)
410 {
411         resetting_ourselves = false;
412         gm = 0;
413
414         resetting_ourselves = false;
415         gm = 0;
416
417         if (ARDOUR::Profile->get_sae()) {
418                 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
419                 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
420         }
421
422
423         //add the file chooser
424         {
425                 chooser.set_border_width (12);
426
427                 audio_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_audio_filter));
428                 audio_filter.set_name (_("Audio files"));
429
430                 midi_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_midi_filter));
431                 midi_filter.set_name (_("MIDI files"));
432
433                 matchall_filter.add_pattern ("*.*");
434                 matchall_filter.set_name (_("All files"));
435
436                 chooser.add_filter (audio_filter);
437                 chooser.add_filter (midi_filter);
438                 chooser.add_filter (matchall_filter);
439                 chooser.set_select_multiple (true);
440                 chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
441                 chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
442
443                 if (!persistent_folder.empty()) {
444                         chooser.set_current_folder (persistent_folder);
445                 }
446                 notebook.append_page (chooser, _("Browse Files"));
447         }
448
449         hpacker.set_spacing (6);
450         hpacker.pack_start (notebook, true, true);
451         hpacker.pack_start (preview, false, false);
452
453         get_vbox()->pack_start (hpacker, true, true);
454
455         //add tag search
456         {
457                 VBox* vbox;
458                 HBox* hbox;
459
460
461                 hbox = manage(new HBox);
462                 hbox->pack_start (found_entry);
463                 hbox->pack_start (found_search_btn);
464
465                 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
466                 scroll->add(found_list_view);
467                 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
468
469                 vbox = manage(new VBox);
470                 vbox->pack_start (*hbox, PACK_SHRINK);
471                 vbox->pack_start (*scroll);
472
473                 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
474
475                 found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
476
477                 found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
478
479                 found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
480                 found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
481
482                 notebook.append_page (*vbox, _("Search Tags"));
483         }
484
485         //add freesound search
486 #ifdef FREESOUND
487         {
488                 VBox* vbox;
489                 HBox* passbox;
490                 Label* label;
491
492                 passbox = manage(new HBox);
493                 passbox->set_border_width (12);
494                 passbox->set_spacing (6);
495
496                 label = manage (new Label);
497                 label->set_text (_("User:"));
498                 passbox->pack_start (*label, false, false);
499                 passbox->pack_start (freesound_name_entry);
500                 label = manage (new Label);
501                 label->set_text (_("Password:"));
502                 passbox->pack_start (*label, false, false);
503                 passbox->pack_start (freesound_pass_entry);
504                 label = manage (new Label);
505                 label->set_text (_("Tags:"));
506                 passbox->pack_start (*label, false, false);
507                 passbox->pack_start (freesound_entry, false, false);
508                 passbox->pack_start (freesound_search_btn, false, false);
509
510                 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
511                 scroll->add(freesound_list_view);
512                 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
513
514                 vbox = manage(new VBox);
515                 vbox->pack_start (*passbox, PACK_SHRINK);
516                 vbox->pack_start(*scroll);
517
518                 //vbox->pack_start (freesound_list_view);
519
520                 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
521                 freesound_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
522
523                 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
524                 freesound_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
525                 freesound_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
526                 freesound_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
527                 notebook.append_page (*vbox, _("Search Freesound"));
528         }
529 #endif
530
531
532         notebook.set_size_request (500, -1);
533
534         set_session (s);
535
536         add_button (Stock::CANCEL, RESPONSE_CANCEL);
537         add_button (Stock::APPLY, RESPONSE_APPLY);
538         add_button (Stock::OK, RESPONSE_OK);
539
540 }
541
542 SoundFileBrowser::~SoundFileBrowser ()
543 {
544         persistent_folder = chooser.get_current_folder();
545 }
546
547
548 void
549 SoundFileBrowser::on_show ()
550 {
551         ArdourDialog::on_show ();
552         start_metering ();
553 }
554
555 void
556 SoundFileBrowser::clear_selection ()
557 {
558         chooser.unselect_all ();
559         found_list_view.get_selection()->unselect_all ();
560 }
561
562 void
563 SoundFileBrowser::chooser_file_activated ()
564 {
565         preview.audition ();
566 }
567
568 void
569 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
570 {
571         preview.audition ();
572 }
573
574 void
575 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
576 {
577         preview.audition ();
578 }
579
580 void
581 SoundFileBrowser::set_session (Session* s)
582 {
583         ArdourDialog::set_session (s);
584         preview.set_session (s);
585         if (s) {
586                 add_gain_meter ();
587         } else {
588                 remove_gain_meter ();
589         }
590 }
591
592 void
593 SoundFileBrowser::add_gain_meter ()
594 {
595         delete gm;
596
597         gm = new GainMeter (*session, 250);
598
599         boost::shared_ptr<Route> r = session->the_auditioner ();
600
601         gm->set_controls (r, r->shared_peak_meter(), r->amp());
602
603         meter_packer.set_border_width (12);
604         meter_packer.pack_start (*gm, false, true);
605         hpacker.pack_end (meter_packer, false, false);
606         meter_packer.show_all ();
607         start_metering ();
608 }
609
610 void
611 SoundFileBrowser::remove_gain_meter ()
612 {
613         if (gm) {
614                 meter_packer.remove (*gm);
615                 hpacker.remove (meter_packer);
616                 delete gm;
617                 gm = 0;
618         }
619 }
620
621 void
622 SoundFileBrowser::start_metering ()
623 {
624         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
625 }
626
627 void
628 SoundFileBrowser::stop_metering ()
629 {
630         metering_connection.disconnect();
631 }
632
633 void
634 SoundFileBrowser::meter ()
635 {
636         if (is_mapped () && session && gm) {
637                 gm->update_meters ();
638         }
639 }
640
641 bool
642 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
643 {
644         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
645 }
646
647 bool
648 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
649 {
650         return SMFSource::safe_midi_file_extension (filter_info.filename);
651 }
652
653 void
654 SoundFileBrowser::update_preview ()
655 {
656         if (preview.setup_labels (chooser.get_filename())) {
657                 if (preview.autoplay()) {
658                         Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
659                 }
660         }
661 }
662
663 void
664 SoundFileBrowser::found_list_view_selected ()
665 {
666         if (!reset_options ()) {
667                 set_response_sensitive (RESPONSE_OK, false);
668         } else {
669                 ustring file;
670
671                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
672
673                 if (!rows.empty()) {
674                         TreeIter iter = found_list->get_iter(*rows.begin());
675                         file = (*iter)[found_list_columns.pathname];
676                         chooser.set_filename (file);
677                         set_response_sensitive (RESPONSE_OK, true);
678                 } else {
679                         set_response_sensitive (RESPONSE_OK, false);
680                 }
681
682                 preview.setup_labels (file);
683         }
684 }
685
686 void
687 SoundFileBrowser::freesound_list_view_selected ()
688 {
689         if (!reset_options ()) {
690                 set_response_sensitive (RESPONSE_OK, false);
691         } else {
692                 ustring file;
693
694                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
695
696                 if (!rows.empty()) {
697                         TreeIter iter = freesound_list->get_iter(*rows.begin());
698                         file = (*iter)[freesound_list_columns.pathname];
699                         chooser.set_filename (file);
700                         set_response_sensitive (RESPONSE_OK, true);
701                 } else {
702                         set_response_sensitive (RESPONSE_OK, false);
703                 }
704
705                 preview.setup_labels (file);
706         }
707 }
708
709 void
710 SoundFileBrowser::found_search_clicked ()
711 {
712         string tag_string = found_entry.get_text ();
713
714         vector<string> tags;
715
716         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
717                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
718                 return;
719         }
720
721         vector<string> results;
722         Library->search_members_and (results, tags);
723
724         found_list->clear();
725         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
726                 TreeModel::iterator new_row = found_list->append();
727                 TreeModel::Row row = *new_row;
728                 string path = Glib::filename_from_uri (string ("file:") + *i);
729                 row[found_list_columns.pathname] = path;
730         }
731 }
732
733 void*
734 freesound_search_thread_entry (void* arg)
735 {
736         PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freesound Search"));
737         SessionEvent::create_per_thread_pool ("freesound events", 64);
738
739         static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
740
741         return 0;
742 }
743
744 bool searching = false;
745 bool canceling = false;
746
747 void
748 SoundFileBrowser::freesound_search_clicked ()
749 {
750         if (canceling)  //already canceling, button does nothing
751                 return;
752
753         if ( searching ) {
754                 freesound_search_btn.set_label(_("Cancelling.."));
755                 canceling = true;
756         } else {
757                 searching = true;
758                 freesound_search_btn.set_label(_("Cancel"));
759                 pthread_t freesound_thr;
760                 pthread_create_and_store ("freesound_search", &freesound_thr, 0, freesound_search_thread_entry, this);
761         }
762 }
763
764 void
765 SoundFileBrowser::freesound_search_thread()
766 {
767 #if 0
768
769         THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
770
771 #ifdef FREESOUND
772         freesound_list->clear();
773
774         string path;
775         path = Glib::get_home_dir();
776         path += "/Freesound/";
777         Mootcher theMootcher(path.c_str());
778
779         string name_string = freesound_name_entry.get_text ();
780         string pass_string = freesound_pass_entry.get_text ();
781         string search_string = freesound_entry.get_text ();
782
783         if ( theMootcher.doLogin( name_string, pass_string ) ) {
784
785                 string theString = theMootcher.searchText(search_string);
786
787                 XMLTree doc;
788                 doc.read_buffer( theString );
789                 XMLNode *root = doc.root();
790
791                 if (root==NULL) return;
792
793                 if ( strcmp(root->name().c_str(), "freesound") == 0) {
794
795                         XMLNode *node = 0;
796                         XMLNodeList children = root->children();
797                         XMLNodeConstIterator niter;
798                         for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
799                                 node = *niter;
800                                 if( strcmp( node->name().c_str(), "sample") == 0 ){
801                                         XMLProperty *prop=node->property ("id");
802                                         string filename = theMootcher.getFile( prop->value().c_str() );
803                                         if ( filename != "" ) {
804                                                 TreeModel::iterator new_row = freesound_list->append();
805                                                 TreeModel::Row row = *new_row;
806                                                 string path = Glib::filename_from_uri (string ("file:") + filename);
807                                                 row[freesound_list_columns.pathname] = path;
808                                         }
809                                 }
810                         }
811                 }
812         }
813
814         searching = false;
815         canceling = false;
816         freesound_search_btn.set_label(_("Start Downloading"));
817 #endif
818 #endif
819
820 }
821
822 vector<ustring>
823 SoundFileBrowser::get_paths ()
824 {
825         vector<ustring> results;
826
827         int n = notebook.get_current_page ();
828
829         if (n == 0) {
830                 vector<ustring> filenames = chooser.get_filenames();
831                 vector<ustring>::iterator i;
832
833                 for (i = filenames.begin(); i != filenames.end(); ++i) {
834                         struct stat buf;
835                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
836                                 results.push_back (*i);
837                         }
838                 }
839
840         } else if (n==1){
841
842                 typedef TreeView::Selection::ListHandle_Path ListPath;
843
844                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
845                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
846                         TreeIter iter = found_list->get_iter(*i);
847                         ustring str = (*iter)[found_list_columns.pathname];
848
849                         results.push_back (str);
850                 }
851         } else {
852
853                 typedef TreeView::Selection::ListHandle_Path ListPath;
854
855                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
856                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
857                         TreeIter iter = freesound_list->get_iter(*i);
858                         ustring str = (*iter)[freesound_list_columns.pathname];
859
860                         results.push_back (str);
861                 }
862         }
863
864         return results;
865 }
866
867 void
868 SoundFileOmega::reset_options_noret ()
869 {
870         if (!resetting_ourselves) {
871                 (void) reset_options ();
872         }
873 }
874
875 bool
876 SoundFileOmega::reset_options ()
877 {
878         vector<ustring> paths = get_paths ();
879
880         if (paths.empty()) {
881
882                 channel_combo.set_sensitive (false);
883                 action_combo.set_sensitive (false);
884                 where_combo.set_sensitive (false);
885                 copy_files_btn.set_sensitive (false);
886
887                 return false;
888
889         } else {
890
891                 channel_combo.set_sensitive (true);
892                 action_combo.set_sensitive (true);
893                 where_combo.set_sensitive (true);
894
895                 /* if we get through this function successfully, this may be
896                    reset at the end, once we know if we can use hard links
897                    to do embedding
898                 */
899
900                 if (Config->get_only_copy_imported_files()) {
901                         copy_files_btn.set_sensitive (false);
902                 } else {
903                         copy_files_btn.set_sensitive (false);
904                 }
905         }
906
907         bool same_size;
908         bool src_needed;
909         bool selection_includes_multichannel;
910         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
911         ImportMode mode;
912
913         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
914                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
915                 return false;
916         }
917
918         ustring existing_choice;
919         vector<string> action_strings;
920
921         if (selected_track_cnt > 0) {
922                 if (channel_combo.get_active_text().length()) {
923                         ImportDisposition id = get_channel_disposition();
924
925                         switch (id) {
926                         case Editing::ImportDistinctFiles:
927                                 if (selected_track_cnt == paths.size()) {
928                                         action_strings.push_back (importmode2string (ImportToTrack));
929                                 }
930                                 break;
931
932                         case Editing::ImportDistinctChannels:
933                                 /* XXX it would be nice to allow channel-per-selected track
934                                    but its too hard we don't want to deal with all the
935                                    different per-file + per-track channel configurations.
936                                 */
937                                 break;
938
939                         default:
940                                 action_strings.push_back (importmode2string (ImportToTrack));
941                                 break;
942                         }
943                 }
944         }
945
946         action_strings.push_back (importmode2string (ImportAsTrack));
947         action_strings.push_back (importmode2string (ImportAsRegion));
948         action_strings.push_back (importmode2string (ImportAsTapeTrack));
949
950         resetting_ourselves = true;
951
952         existing_choice = action_combo.get_active_text();
953
954         set_popdown_strings (action_combo, action_strings);
955
956         /* preserve any existing choice, if possible */
957
958
959         if (existing_choice.length()) {
960                 vector<string>::iterator x;
961                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
962                         if (*x == existing_choice) {
963                                 action_combo.set_active_text (existing_choice);
964                                 break;
965                         }
966                 }
967                 if (x == action_strings.end()) {
968                         action_combo.set_active_text (action_strings.front());
969                 }
970         } else {
971                 action_combo.set_active_text (action_strings.front());
972         }
973
974         resetting_ourselves = false;
975
976         if ((mode = get_mode()) == ImportAsRegion) {
977                 where_combo.set_sensitive (false);
978         } else {
979                 where_combo.set_sensitive (true);
980         }
981
982         vector<string> channel_strings;
983
984         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
985                 channel_strings.push_back (_("one track per file"));
986
987                 if (selection_includes_multichannel) {
988                         channel_strings.push_back (_("one track per channel"));
989                 }
990
991                 if (paths.size() > 1) {
992                         /* tape tracks are a single region per track, so we cannot
993                            sequence multiple files.
994                         */
995                         if (mode != ImportAsTapeTrack) {
996                                 channel_strings.push_back (_("sequence files"));
997                         }
998                         if (same_size) {
999                                 channel_strings.push_back (_("all files in one region"));
1000                         }
1001
1002                 }
1003
1004         } else {
1005                 channel_strings.push_back (_("one region per file"));
1006
1007                 if (selection_includes_multichannel) {
1008                         channel_strings.push_back (_("one region per channel"));
1009                 }
1010
1011                 if (paths.size() > 1) {
1012                         if (same_size) {
1013                                 channel_strings.push_back (_("all files in one region"));
1014                         }
1015                 }
1016         }
1017
1018         existing_choice = channel_combo.get_active_text();
1019
1020         set_popdown_strings (channel_combo, channel_strings);
1021
1022         /* preserve any existing choice, if possible */
1023
1024         if (existing_choice.length()) {
1025                 vector<string>::iterator x;
1026                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1027                         if (*x == existing_choice) {
1028                                 channel_combo.set_active_text (existing_choice);
1029                                 break;
1030                         }
1031                 }
1032                 if (x == channel_strings.end()) {
1033                         channel_combo.set_active_text (channel_strings.front());
1034                 }
1035         } else {
1036                 channel_combo.set_active_text (channel_strings.front());
1037         }
1038
1039         if (src_needed) {
1040                 src_combo.set_sensitive (true);
1041         } else {
1042                 src_combo.set_sensitive (false);
1043         }
1044
1045         if (Config->get_only_copy_imported_files()) {
1046
1047                 if (selection_can_be_embedded_with_links) {
1048                         copy_files_btn.set_sensitive (true);
1049                 } else {
1050                         copy_files_btn.set_sensitive (false);
1051                 }
1052
1053         }  else {
1054
1055                 copy_files_btn.set_sensitive (true);
1056         }
1057
1058         return true;
1059 }
1060
1061
1062 bool
1063 SoundFileOmega::bad_file_message()
1064 {
1065         MessageDialog msg (*this,
1066                            _("One or more of the selected files\ncannot be used by Ardour"),
1067                            true,
1068                            Gtk::MESSAGE_INFO,
1069                            Gtk::BUTTONS_OK);
1070         msg.run ();
1071         resetting_ourselves = true;
1072         chooser.unselect_uri (chooser.get_preview_uri());
1073         resetting_ourselves = false;
1074
1075         return false;
1076 }
1077
1078 bool
1079 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1080 {
1081         SoundFileInfo info;
1082         nframes64_t sz = 0;
1083         bool err = false;
1084         string errmsg;
1085
1086         same_size = true;
1087         src_needed = false;
1088         multichannel = false;
1089
1090         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1091
1092                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1093                         if (info.channels > 1) {
1094                                 multichannel = true;
1095                         }
1096                         if (sz == 0) {
1097                                 sz = info.length;
1098                         } else {
1099                                 if (sz != info.length) {
1100                                         same_size = false;
1101                                 }
1102                         }
1103
1104                         if ((nframes_t) info.samplerate != session->frame_rate()) {
1105                                 src_needed = true;
1106                         }
1107
1108                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1109
1110                         Evoral::SMF reader;
1111                         reader.open(*i);
1112                         if (reader.num_tracks() > 1) {
1113                                 multichannel = true; // "channel" == track here...
1114                         }
1115
1116                         /* XXX we need err = true handling here in case
1117                            we can't check the file
1118                         */
1119
1120                 } else {
1121                         err = true;
1122                 }
1123         }
1124
1125         return err;
1126 }
1127
1128
1129 bool
1130 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
1131 {
1132         sys::path path = s.session_directory().sound_path() / "linktest";
1133         string tmpdir = path.to_string();
1134         bool ret = false;
1135
1136         if (mkdir (tmpdir.c_str(), 0744)) {
1137                 if (errno != EEXIST) {
1138                         return false;
1139                 }
1140         }
1141
1142         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1143
1144                 char tmpc[MAXPATHLEN+1];
1145
1146                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1147
1148                 /* can we link ? */
1149
1150                 if (link ((*i).c_str(), tmpc)) {
1151                         goto out;
1152                 }
1153
1154                 unlink (tmpc);
1155         }
1156
1157         ret = true;
1158
1159   out:
1160         rmdir (tmpdir.c_str());
1161         return ret;
1162 }
1163
1164 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1165         : SoundFileBrowser (parent, title, s, false)
1166 {
1167         chooser.set_select_multiple (false);
1168         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1169         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1170 }
1171
1172 void
1173 SoundFileChooser::on_hide ()
1174 {
1175         ArdourDialog::on_hide();
1176         stop_metering ();
1177
1178         if (session) {
1179                 session->cancel_audition();
1180         }
1181 }
1182
1183 ustring
1184 SoundFileChooser::get_filename ()
1185 {
1186         vector<ustring> paths;
1187
1188         paths = get_paths ();
1189
1190         if (paths.empty()) {
1191                 return ustring ();
1192         }
1193
1194         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1195                 return ustring();
1196         }
1197
1198         return paths.front();
1199 }
1200
1201 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1202                                 Editing::ImportMode mode_hint)
1203         : SoundFileBrowser (parent, title, s, persistent),
1204           copy_files_btn ( _("Copy files to session")),
1205           selected_track_cnt (selected_tracks)
1206 {
1207         VBox* vbox;
1208         HBox* hbox;
1209         vector<string> str;
1210
1211         set_size_request (-1, 450);
1212
1213         block_two.set_border_width (12);
1214         block_three.set_border_width (12);
1215         block_four.set_border_width (12);
1216
1217         options.set_spacing (12);
1218
1219         str.clear ();
1220         str.push_back (_("file timestamp"));
1221         str.push_back (_("edit point"));
1222         str.push_back (_("playhead"));
1223         str.push_back (_("session start"));
1224         set_popdown_strings (where_combo, str);
1225         where_combo.set_active_text (str.front());
1226
1227         Label* l = manage (new Label);
1228         l->set_text (_("Add files:"));
1229
1230         hbox = manage (new HBox);
1231         hbox->set_border_width (12);
1232         hbox->set_spacing (6);
1233         hbox->pack_start (*l, false, false);
1234         hbox->pack_start (action_combo, false, false);
1235         vbox = manage (new VBox);
1236         vbox->pack_start (*hbox, false, false);
1237         options.pack_start (*vbox, false, false);
1238
1239         /* dummy entry for action combo so that it doesn't look odd if we
1240            come up with no tracks selected.
1241         */
1242
1243         str.clear ();
1244         str.push_back (importmode2string (mode_hint));
1245         set_popdown_strings (action_combo, str);
1246         action_combo.set_active_text (str.front());
1247         action_combo.set_sensitive (false);
1248
1249         l = manage (new Label);
1250         l->set_text (_("Insert at:"));
1251
1252         hbox = manage (new HBox);
1253         hbox->set_border_width (12);
1254         hbox->set_spacing (6);
1255         hbox->pack_start (*l, false, false);
1256         hbox->pack_start (where_combo, false, false);
1257         vbox = manage (new VBox);
1258         vbox->pack_start (*hbox, false, false);
1259         options.pack_start (*vbox, false, false);
1260
1261
1262         l = manage (new Label);
1263         l->set_text (_("Mapping:"));
1264
1265         hbox = manage (new HBox);
1266         hbox->set_border_width (12);
1267         hbox->set_spacing (6);
1268         hbox->pack_start (*l, false, false);
1269         hbox->pack_start (channel_combo, false, false);
1270         vbox = manage (new VBox);
1271         vbox->pack_start (*hbox, false, false);
1272         options.pack_start (*vbox, false, false);
1273
1274         str.clear ();
1275         str.push_back (_("one track per file"));
1276         set_popdown_strings (channel_combo, str);
1277         channel_combo.set_active_text (str.front());
1278         channel_combo.set_sensitive (false);
1279
1280         l = manage (new Label);
1281         l->set_text (_("Conversion quality:"));
1282
1283         hbox = manage (new HBox);
1284         hbox->set_border_width (12);
1285         hbox->set_spacing (6);
1286         hbox->pack_start (*l, false, false);
1287         hbox->pack_start (src_combo, false, false);
1288         vbox = manage (new VBox);
1289         vbox->pack_start (*hbox, false, false);
1290         options.pack_start (*vbox, false, false);
1291
1292         str.clear ();
1293         str.push_back (_("Best"));
1294         str.push_back (_("Good"));
1295         str.push_back (_("Quick"));
1296         str.push_back (_("Fast"));
1297         str.push_back (_("Fastest"));
1298
1299         set_popdown_strings (src_combo, str);
1300         src_combo.set_active_text (str.front());
1301         src_combo.set_sensitive (false);
1302
1303         reset_options ();
1304
1305         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1306
1307         copy_files_btn.set_active (true);
1308
1309         block_four.pack_start (copy_files_btn, false, false);
1310
1311         options.pack_start (block_four, false, false);
1312
1313         get_vbox()->pack_start (options, false, false);
1314
1315         /* setup disposition map */
1316
1317         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1318         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1319         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1320         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1321
1322         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1323         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1324         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1325
1326         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1327
1328         /* set size requests for a couple of combos to allow them to display the longest text
1329            they will ever be asked to display.  This prevents them being resized when the user
1330            selects a file to import, which in turn prevents the size of the dialog from jumping
1331            around. */
1332
1333         vector<string> t;
1334         t.push_back (_("one track per file"));
1335         t.push_back (_("one track per channel"));
1336         t.push_back (_("sequence files"));
1337         t.push_back (_("all files in one region"));
1338         set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1339
1340         t.clear ();
1341         t.push_back (importmode2string (ImportAsTrack));
1342         t.push_back (importmode2string (ImportToTrack));
1343         t.push_back (importmode2string (ImportAsRegion));
1344         t.push_back (importmode2string (ImportAsTapeTrack));
1345         set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1346 }
1347
1348 void
1349 SoundFileOmega::set_mode (ImportMode mode)
1350 {
1351         action_combo.set_active_text (importmode2string (mode));
1352 }
1353
1354 ImportMode
1355 SoundFileOmega::get_mode () const
1356 {
1357         return string2importmode (action_combo.get_active_text());
1358 }
1359
1360 void
1361 SoundFileOmega::on_hide ()
1362 {
1363         ArdourDialog::on_hide();
1364         if (session) {
1365                 session->cancel_audition();
1366         }
1367 }
1368
1369 ImportPosition
1370 SoundFileOmega::get_position() const
1371 {
1372         ustring str = where_combo.get_active_text();
1373
1374         if (str == _("file timestamp")) {
1375                 return ImportAtTimestamp;
1376         } else if (str == _("edit point")) {
1377                 return ImportAtEditPoint;
1378         } else if (str == _("playhead")) {
1379                 return ImportAtPlayhead;
1380         } else {
1381                 return ImportAtStart;
1382         }
1383 }
1384
1385 SrcQuality
1386 SoundFileOmega::get_src_quality() const
1387 {
1388         ustring str = where_combo.get_active_text();
1389
1390         if (str == _("Best")) {
1391                 return SrcBest;
1392         } else if (str == _("Good")) {
1393                 return SrcGood;
1394         } else if (str == _("Quick")) {
1395                 return SrcQuick;
1396         } else if (str == _("Fast")) {
1397                 return SrcFast;
1398         } else {
1399                 return SrcFastest;
1400         }
1401 }
1402
1403 ImportDisposition
1404 SoundFileOmega::get_channel_disposition () const
1405 {
1406         /* we use a map here because the channel combo can contain different strings
1407            depending on the state of the other combos. the map contains all possible strings
1408            and the ImportDisposition enum that corresponds to it.
1409         */
1410
1411         ustring str = channel_combo.get_active_text();
1412         DispositionMap::const_iterator x = disposition_map.find (str);
1413
1414         if (x == disposition_map.end()) {
1415                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1416                 /*NOTREACHED*/
1417         }
1418
1419         return x->second;
1420 }
1421
1422 void
1423 SoundFileOmega::reset (int selected_tracks)
1424 {
1425         selected_track_cnt = selected_tracks;
1426         reset_options ();
1427 }
1428
1429 void
1430 SoundFileOmega::file_selection_changed ()
1431 {
1432         if (resetting_ourselves) {
1433                 return;
1434         }
1435
1436         if (!reset_options ()) {
1437                 set_response_sensitive (RESPONSE_OK, false);
1438         } else {
1439                 if (chooser.get_filenames().size() > 0) {
1440                         set_response_sensitive (RESPONSE_OK, true);
1441                 } else {
1442                         set_response_sensitive (RESPONSE_OK, false);
1443                 }
1444         }
1445 }
1446