drastic, deep and wide changes to make RouteGroup use boost::shared_ptr<Route> and...
[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         SessionEvent::create_per_thread_pool ("freesound events", 64);
737
738         static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
739
740         return 0;
741 }
742
743 bool searching = false;
744 bool canceling = false;
745
746 void
747 SoundFileBrowser::freesound_search_clicked ()
748 {
749         if (canceling)  //already canceling, button does nothing
750                 return;
751
752         if ( searching ) {
753                 freesound_search_btn.set_label(_("Cancelling.."));
754                 canceling = true;
755         } else {
756                 searching = true;
757                 freesound_search_btn.set_label(_("Cancel"));
758                 pthread_t freesound_thr;
759                 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
760         }
761 }
762
763 void
764 SoundFileBrowser::freesound_search_thread()
765 {
766 #if 0
767
768         THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
769
770 #ifdef FREESOUND
771         freesound_list->clear();
772
773         string path;
774         path = Glib::get_home_dir();
775         path += "/Freesound/";
776         Mootcher theMootcher(path.c_str());
777
778         string name_string = freesound_name_entry.get_text ();
779         string pass_string = freesound_pass_entry.get_text ();
780         string search_string = freesound_entry.get_text ();
781
782         if ( theMootcher.doLogin( name_string, pass_string ) ) {
783
784                 string theString = theMootcher.searchText(search_string);
785
786                 XMLTree doc;
787                 doc.read_buffer( theString );
788                 XMLNode *root = doc.root();
789
790                 if (root==NULL) return;
791
792                 if ( strcmp(root->name().c_str(), "freesound") == 0) {
793
794                         XMLNode *node = 0;
795                         XMLNodeList children = root->children();
796                         XMLNodeConstIterator niter;
797                         for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
798                                 node = *niter;
799                                 if( strcmp( node->name().c_str(), "sample") == 0 ){
800                                         XMLProperty *prop=node->property ("id");
801                                         string filename = theMootcher.getFile( prop->value().c_str() );
802                                         if ( filename != "" ) {
803                                                 TreeModel::iterator new_row = freesound_list->append();
804                                                 TreeModel::Row row = *new_row;
805                                                 string path = Glib::filename_from_uri (string ("file:") + filename);
806                                                 row[freesound_list_columns.pathname] = path;
807                                         }
808                                 }
809                         }
810                 }
811         }
812
813         searching = false;
814         canceling = false;
815         freesound_search_btn.set_label(_("Start Downloading"));
816 #endif
817 #endif
818
819 }
820
821 vector<ustring>
822 SoundFileBrowser::get_paths ()
823 {
824         vector<ustring> results;
825
826         int n = notebook.get_current_page ();
827
828         if (n == 0) {
829                 vector<ustring> filenames = chooser.get_filenames();
830                 vector<ustring>::iterator i;
831
832                 for (i = filenames.begin(); i != filenames.end(); ++i) {
833                         struct stat buf;
834                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
835                                 results.push_back (*i);
836                         }
837                 }
838
839         } else if (n==1){
840
841                 typedef TreeView::Selection::ListHandle_Path ListPath;
842
843                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
844                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
845                         TreeIter iter = found_list->get_iter(*i);
846                         ustring str = (*iter)[found_list_columns.pathname];
847
848                         results.push_back (str);
849                 }
850         } else {
851
852                 typedef TreeView::Selection::ListHandle_Path ListPath;
853
854                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
855                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
856                         TreeIter iter = freesound_list->get_iter(*i);
857                         ustring str = (*iter)[freesound_list_columns.pathname];
858
859                         results.push_back (str);
860                 }
861         }
862
863         return results;
864 }
865
866 void
867 SoundFileOmega::reset_options_noret ()
868 {
869         if (!resetting_ourselves) {
870                 (void) reset_options ();
871         }
872 }
873
874 bool
875 SoundFileOmega::reset_options ()
876 {
877         vector<ustring> paths = get_paths ();
878
879         if (paths.empty()) {
880
881                 channel_combo.set_sensitive (false);
882                 action_combo.set_sensitive (false);
883                 where_combo.set_sensitive (false);
884                 copy_files_btn.set_sensitive (false);
885
886                 return false;
887
888         } else {
889
890                 channel_combo.set_sensitive (true);
891                 action_combo.set_sensitive (true);
892                 where_combo.set_sensitive (true);
893
894                 /* if we get through this function successfully, this may be
895                    reset at the end, once we know if we can use hard links
896                    to do embedding
897                 */
898
899                 if (Config->get_only_copy_imported_files()) {
900                         copy_files_btn.set_sensitive (false);
901                 } else {
902                         copy_files_btn.set_sensitive (false);
903                 }
904         }
905
906         bool same_size;
907         bool src_needed;
908         bool selection_includes_multichannel;
909         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
910         ImportMode mode;
911
912         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
913                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
914                 return false;
915         }
916
917         ustring existing_choice;
918         vector<string> action_strings;
919
920         if (selected_track_cnt > 0) {
921                 if (channel_combo.get_active_text().length()) {
922                         ImportDisposition id = get_channel_disposition();
923
924                         switch (id) {
925                         case Editing::ImportDistinctFiles:
926                                 if (selected_track_cnt == paths.size()) {
927                                         action_strings.push_back (importmode2string (ImportToTrack));
928                                 }
929                                 break;
930
931                         case Editing::ImportDistinctChannels:
932                                 /* XXX it would be nice to allow channel-per-selected track
933                                    but its too hard we don't want to deal with all the
934                                    different per-file + per-track channel configurations.
935                                 */
936                                 break;
937
938                         default:
939                                 action_strings.push_back (importmode2string (ImportToTrack));
940                                 break;
941                         }
942                 }
943         }
944
945         action_strings.push_back (importmode2string (ImportAsTrack));
946         action_strings.push_back (importmode2string (ImportAsRegion));
947         action_strings.push_back (importmode2string (ImportAsTapeTrack));
948
949         resetting_ourselves = true;
950
951         existing_choice = action_combo.get_active_text();
952
953         set_popdown_strings (action_combo, action_strings);
954
955         /* preserve any existing choice, if possible */
956
957
958         if (existing_choice.length()) {
959                 vector<string>::iterator x;
960                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
961                         if (*x == existing_choice) {
962                                 action_combo.set_active_text (existing_choice);
963                                 break;
964                         }
965                 }
966                 if (x == action_strings.end()) {
967                         action_combo.set_active_text (action_strings.front());
968                 }
969         } else {
970                 action_combo.set_active_text (action_strings.front());
971         }
972
973         resetting_ourselves = false;
974
975         if ((mode = get_mode()) == ImportAsRegion) {
976                 where_combo.set_sensitive (false);
977         } else {
978                 where_combo.set_sensitive (true);
979         }
980
981         vector<string> channel_strings;
982
983         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
984                 channel_strings.push_back (_("one track per file"));
985
986                 if (selection_includes_multichannel) {
987                         channel_strings.push_back (_("one track per channel"));
988                 }
989
990                 if (paths.size() > 1) {
991                         /* tape tracks are a single region per track, so we cannot
992                            sequence multiple files.
993                         */
994                         if (mode != ImportAsTapeTrack) {
995                                 channel_strings.push_back (_("sequence files"));
996                         }
997                         if (same_size) {
998                                 channel_strings.push_back (_("all files in one region"));
999                         }
1000
1001                 }
1002
1003         } else {
1004                 channel_strings.push_back (_("one region per file"));
1005
1006                 if (selection_includes_multichannel) {
1007                         channel_strings.push_back (_("one region per channel"));
1008                 }
1009
1010                 if (paths.size() > 1) {
1011                         if (same_size) {
1012                                 channel_strings.push_back (_("all files in one region"));
1013                         }
1014                 }
1015         }
1016
1017         existing_choice = channel_combo.get_active_text();
1018
1019         set_popdown_strings (channel_combo, channel_strings);
1020
1021         /* preserve any existing choice, if possible */
1022
1023         if (existing_choice.length()) {
1024                 vector<string>::iterator x;
1025                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1026                         if (*x == existing_choice) {
1027                                 channel_combo.set_active_text (existing_choice);
1028                                 break;
1029                         }
1030                 }
1031                 if (x == channel_strings.end()) {
1032                         channel_combo.set_active_text (channel_strings.front());
1033                 }
1034         } else {
1035                 channel_combo.set_active_text (channel_strings.front());
1036         }
1037
1038         if (src_needed) {
1039                 src_combo.set_sensitive (true);
1040         } else {
1041                 src_combo.set_sensitive (false);
1042         }
1043
1044         if (Config->get_only_copy_imported_files()) {
1045
1046                 if (selection_can_be_embedded_with_links) {
1047                         copy_files_btn.set_sensitive (true);
1048                 } else {
1049                         copy_files_btn.set_sensitive (false);
1050                 }
1051
1052         }  else {
1053
1054                 copy_files_btn.set_sensitive (true);
1055         }
1056
1057         return true;
1058 }
1059
1060
1061 bool
1062 SoundFileOmega::bad_file_message()
1063 {
1064         MessageDialog msg (*this,
1065                            _("One or more of the selected files\ncannot be used by Ardour"),
1066                            true,
1067                            Gtk::MESSAGE_INFO,
1068                            Gtk::BUTTONS_OK);
1069         msg.run ();
1070         resetting_ourselves = true;
1071         chooser.unselect_uri (chooser.get_preview_uri());
1072         resetting_ourselves = false;
1073
1074         return false;
1075 }
1076
1077 bool
1078 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1079 {
1080         SoundFileInfo info;
1081         nframes64_t sz = 0;
1082         bool err = false;
1083         string errmsg;
1084
1085         same_size = true;
1086         src_needed = false;
1087         multichannel = false;
1088
1089         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1090
1091                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1092                         if (info.channels > 1) {
1093                                 multichannel = true;
1094                         }
1095                         if (sz == 0) {
1096                                 sz = info.length;
1097                         } else {
1098                                 if (sz != info.length) {
1099                                         same_size = false;
1100                                 }
1101                         }
1102
1103                         if ((nframes_t) info.samplerate != session->frame_rate()) {
1104                                 src_needed = true;
1105                         }
1106
1107                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1108
1109                         Evoral::SMF reader;
1110                         reader.open(*i);
1111                         if (reader.num_tracks() > 1) {
1112                                 multichannel = true; // "channel" == track here...
1113                         }
1114
1115                         /* XXX we need err = true handling here in case
1116                            we can't check the file
1117                         */
1118
1119                 } else {
1120                         err = true;
1121                 }
1122         }
1123
1124         return err;
1125 }
1126
1127
1128 bool
1129 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
1130 {
1131         sys::path path = s.session_directory().sound_path() / "linktest";
1132         string tmpdir = path.to_string();
1133         bool ret = false;
1134
1135         if (mkdir (tmpdir.c_str(), 0744)) {
1136                 if (errno != EEXIST) {
1137                         return false;
1138                 }
1139         }
1140
1141         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1142
1143                 char tmpc[MAXPATHLEN+1];
1144
1145                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1146
1147                 /* can we link ? */
1148
1149                 if (link ((*i).c_str(), tmpc)) {
1150                         goto out;
1151                 }
1152
1153                 unlink (tmpc);
1154         }
1155
1156         ret = true;
1157
1158   out:
1159         rmdir (tmpdir.c_str());
1160         return ret;
1161 }
1162
1163 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1164         : SoundFileBrowser (parent, title, s, false)
1165 {
1166         chooser.set_select_multiple (false);
1167         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1168         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1169 }
1170
1171 void
1172 SoundFileChooser::on_hide ()
1173 {
1174         ArdourDialog::on_hide();
1175         stop_metering ();
1176
1177         if (session) {
1178                 session->cancel_audition();
1179         }
1180 }
1181
1182 ustring
1183 SoundFileChooser::get_filename ()
1184 {
1185         vector<ustring> paths;
1186
1187         paths = get_paths ();
1188
1189         if (paths.empty()) {
1190                 return ustring ();
1191         }
1192
1193         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1194                 return ustring();
1195         }
1196
1197         return paths.front();
1198 }
1199
1200 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1201                                 Editing::ImportMode mode_hint)
1202         : SoundFileBrowser (parent, title, s, persistent),
1203           copy_files_btn ( _("Copy files to session")),
1204           selected_track_cnt (selected_tracks)
1205 {
1206         VBox* vbox;
1207         HBox* hbox;
1208         vector<string> str;
1209
1210         set_size_request (-1, 450);
1211
1212         block_two.set_border_width (12);
1213         block_three.set_border_width (12);
1214         block_four.set_border_width (12);
1215
1216         options.set_spacing (12);
1217
1218         str.clear ();
1219         str.push_back (_("file timestamp"));
1220         str.push_back (_("edit point"));
1221         str.push_back (_("playhead"));
1222         str.push_back (_("session start"));
1223         set_popdown_strings (where_combo, str);
1224         where_combo.set_active_text (str.front());
1225
1226         Label* l = manage (new Label);
1227         l->set_text (_("Add files:"));
1228
1229         hbox = manage (new HBox);
1230         hbox->set_border_width (12);
1231         hbox->set_spacing (6);
1232         hbox->pack_start (*l, false, false);
1233         hbox->pack_start (action_combo, false, false);
1234         vbox = manage (new VBox);
1235         vbox->pack_start (*hbox, false, false);
1236         options.pack_start (*vbox, false, false);
1237
1238         /* dummy entry for action combo so that it doesn't look odd if we
1239            come up with no tracks selected.
1240         */
1241
1242         str.clear ();
1243         str.push_back (importmode2string (mode_hint));
1244         set_popdown_strings (action_combo, str);
1245         action_combo.set_active_text (str.front());
1246         action_combo.set_sensitive (false);
1247
1248         l = manage (new Label);
1249         l->set_text (_("Insert at:"));
1250
1251         hbox = manage (new HBox);
1252         hbox->set_border_width (12);
1253         hbox->set_spacing (6);
1254         hbox->pack_start (*l, false, false);
1255         hbox->pack_start (where_combo, false, false);
1256         vbox = manage (new VBox);
1257         vbox->pack_start (*hbox, false, false);
1258         options.pack_start (*vbox, false, false);
1259
1260
1261         l = manage (new Label);
1262         l->set_text (_("Mapping:"));
1263
1264         hbox = manage (new HBox);
1265         hbox->set_border_width (12);
1266         hbox->set_spacing (6);
1267         hbox->pack_start (*l, false, false);
1268         hbox->pack_start (channel_combo, false, false);
1269         vbox = manage (new VBox);
1270         vbox->pack_start (*hbox, false, false);
1271         options.pack_start (*vbox, false, false);
1272
1273         str.clear ();
1274         str.push_back (_("one track per file"));
1275         set_popdown_strings (channel_combo, str);
1276         channel_combo.set_active_text (str.front());
1277         channel_combo.set_sensitive (false);
1278
1279         l = manage (new Label);
1280         l->set_text (_("Conversion quality:"));
1281
1282         hbox = manage (new HBox);
1283         hbox->set_border_width (12);
1284         hbox->set_spacing (6);
1285         hbox->pack_start (*l, false, false);
1286         hbox->pack_start (src_combo, false, false);
1287         vbox = manage (new VBox);
1288         vbox->pack_start (*hbox, false, false);
1289         options.pack_start (*vbox, false, false);
1290
1291         str.clear ();
1292         str.push_back (_("Best"));
1293         str.push_back (_("Good"));
1294         str.push_back (_("Quick"));
1295         str.push_back (_("Fast"));
1296         str.push_back (_("Fastest"));
1297
1298         set_popdown_strings (src_combo, str);
1299         src_combo.set_active_text (str.front());
1300         src_combo.set_sensitive (false);
1301
1302         reset_options ();
1303
1304         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1305
1306         copy_files_btn.set_active (true);
1307
1308         block_four.pack_start (copy_files_btn, false, false);
1309
1310         options.pack_start (block_four, false, false);
1311
1312         get_vbox()->pack_start (options, false, false);
1313
1314         /* setup disposition map */
1315
1316         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1317         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1318         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1319         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1320
1321         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1322         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1323         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1324
1325         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1326
1327         /* set size requests for a couple of combos to allow them to display the longest text
1328            they will ever be asked to display.  This prevents them being resized when the user
1329            selects a file to import, which in turn prevents the size of the dialog from jumping
1330            around. */
1331
1332         vector<string> t;
1333         t.push_back (_("one track per file"));
1334         t.push_back (_("one track per channel"));
1335         t.push_back (_("sequence files"));
1336         t.push_back (_("all files in one region"));
1337         set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1338
1339         t.clear ();
1340         t.push_back (importmode2string (ImportAsTrack));
1341         t.push_back (importmode2string (ImportToTrack));
1342         t.push_back (importmode2string (ImportAsRegion));
1343         t.push_back (importmode2string (ImportAsTapeTrack));
1344         set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1345 }
1346
1347 void
1348 SoundFileOmega::set_mode (ImportMode mode)
1349 {
1350         action_combo.set_active_text (importmode2string (mode));
1351 }
1352
1353 ImportMode
1354 SoundFileOmega::get_mode () const
1355 {
1356         return string2importmode (action_combo.get_active_text());
1357 }
1358
1359 void
1360 SoundFileOmega::on_hide ()
1361 {
1362         ArdourDialog::on_hide();
1363         if (session) {
1364                 session->cancel_audition();
1365         }
1366 }
1367
1368 ImportPosition
1369 SoundFileOmega::get_position() const
1370 {
1371         ustring str = where_combo.get_active_text();
1372
1373         if (str == _("file timestamp")) {
1374                 return ImportAtTimestamp;
1375         } else if (str == _("edit point")) {
1376                 return ImportAtEditPoint;
1377         } else if (str == _("playhead")) {
1378                 return ImportAtPlayhead;
1379         } else {
1380                 return ImportAtStart;
1381         }
1382 }
1383
1384 SrcQuality
1385 SoundFileOmega::get_src_quality() const
1386 {
1387         ustring str = where_combo.get_active_text();
1388
1389         if (str == _("Best")) {
1390                 return SrcBest;
1391         } else if (str == _("Good")) {
1392                 return SrcGood;
1393         } else if (str == _("Quick")) {
1394                 return SrcQuick;
1395         } else if (str == _("Fast")) {
1396                 return SrcFast;
1397         } else {
1398                 return SrcFastest;
1399         }
1400 }
1401
1402 ImportDisposition
1403 SoundFileOmega::get_channel_disposition () const
1404 {
1405         /* we use a map here because the channel combo can contain different strings
1406            depending on the state of the other combos. the map contains all possible strings
1407            and the ImportDisposition enum that corresponds to it.
1408         */
1409
1410         ustring str = channel_combo.get_active_text();
1411         DispositionMap::const_iterator x = disposition_map.find (str);
1412
1413         if (x == disposition_map.end()) {
1414                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1415                 /*NOTREACHED*/
1416         }
1417
1418         return x->second;
1419 }
1420
1421 void
1422 SoundFileOmega::reset (int selected_tracks)
1423 {
1424         selected_track_cnt = selected_tracks;
1425         reset_options ();
1426 }
1427
1428 void
1429 SoundFileOmega::file_selection_changed ()
1430 {
1431         if (resetting_ourselves) {
1432                 return;
1433         }
1434
1435         if (!reset_options ()) {
1436                 set_response_sensitive (RESPONSE_OK, false);
1437         } else {
1438                 if (chooser.get_filenames().size() > 0) {
1439                         set_response_sensitive (RESPONSE_OK, true);
1440                 } else {
1441                         set_response_sensitive (RESPONSE_OK, false);
1442                 }
1443         }
1444 }
1445