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