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