0ee8935f1b3c89ba57195ad3d48fcb4e188f7fa4
[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> (
335                                         SourceFactory::createReadable (DataType::AUDIO, *_session,
336                                                         path, false, n, Source::Flag (0), false));
337                         
338                         srclist.push_back(afs);
339                         
340                 } catch (failed_constructor& err) {
341                         error << _("Could not access soundfile: ") << path << endmsg;
342                         AudioSource::set_build_peakfiles (old_sbp);
343                         return;
344                 }
345         }
346
347         AudioSource::set_build_peakfiles (old_sbp);
348                         
349         if (srclist.empty()) {
350                 return;
351         }
352         
353         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
354         string rname = region_name_from_path (afs->path(), false);
355         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0,
356                                 srclist[0]->length(srclist[0]->timeline_position()),
357                                 rname, 0, Region::DefaultFlags, false));
358
359         _session->audition_region(r);
360 }
361
362 void
363 SoundFileBox::stop_audition ()
364 {
365         if (_session) {
366                 _session->cancel_audition();
367         }
368 }
369
370 bool
371 SoundFileBox::tags_entry_left (GdkEventFocus *ev)
372 {
373         tags_changed ();
374         return false;
375 }
376
377 void
378 SoundFileBox::tags_changed ()
379 {
380         string tag_string = tags_entry.get_buffer()->get_text ();
381
382         if (tag_string.empty()) {
383                 return;
384         }
385
386         vector<string> tags;
387
388         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
389                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
390                 return;
391         }
392
393         save_tags (tags);
394 }
395
396 void
397 SoundFileBox::save_tags (const vector<string>& tags)
398 {
399         Library->set_tags (string ("//") + path, tags);
400         Library->save_changes ();
401 }
402
403 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
404         : ArdourDialog (parent, title, false, false),
405           found_list (ListStore::create(found_list_columns)),
406           freesound_list (ListStore::create(freesound_list_columns)),
407           chooser (FILE_CHOOSER_ACTION_OPEN),
408           preview (persistent),
409           found_search_btn (_("Search")),
410           found_list_view (found_list),
411           freesound_search_btn (_("Start Downloading")),
412           freesound_list_view (freesound_list)
413 {
414         resetting_ourselves = false;
415         gm = 0;
416
417         resetting_ourselves = false;
418         gm = 0;
419
420         if (ARDOUR::Profile->get_sae()) {
421                 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
422                 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
423         }
424         
425
426         //add the file chooser
427         {
428                 chooser.set_border_width (12);
429
430                 audio_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_audio_filter));
431                 audio_filter.set_name (_("Audio files"));
432                 
433                 midi_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_midi_filter));
434                 midi_filter.set_name (_("MIDI files"));
435                 
436                 matchall_filter.add_pattern ("*.*");
437                 matchall_filter.set_name (_("All files"));
438
439                 chooser.add_filter (audio_filter);
440                 chooser.add_filter (midi_filter);
441                 chooser.add_filter (matchall_filter);
442                 chooser.set_select_multiple (true);
443                 chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
444                 chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
445
446                 if (!persistent_folder.empty()) {
447                         chooser.set_current_folder (persistent_folder);
448                 }
449                 notebook.append_page (chooser, _("Browse Files"));
450         }
451         
452         hpacker.set_spacing (6);
453         hpacker.pack_start (notebook, true, true);
454         hpacker.pack_start (preview, false, false);
455         
456         get_vbox()->pack_start (hpacker, true, true);
457         
458         //add tag search
459         {
460                 VBox* vbox;
461                 HBox* hbox;
462
463
464                 hbox = manage(new HBox);
465                 hbox->pack_start (found_entry);
466                 hbox->pack_start (found_search_btn);
467                 
468                 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
469                 scroll->add(found_list_view);
470                 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
471
472                 vbox = manage(new VBox);
473                 vbox->pack_start (*hbox, PACK_SHRINK);
474                 vbox->pack_start (*scroll);
475                 
476                 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
477
478                 found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
479                 
480                 found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
481
482                 found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
483                 found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
484
485                 notebook.append_page (*vbox, _("Search Tags"));
486         }
487
488         //add freesound search
489 #ifdef FREESOUND
490         {
491                 VBox* vbox;
492                 HBox* passbox;
493                 Label* label;
494
495                 passbox = manage(new HBox);
496                 passbox->set_border_width (12);
497                 passbox->set_spacing (6);
498
499                 label = manage (new Label);
500                 label->set_text (_("User:"));
501                 passbox->pack_start (*label, false, false);
502                 passbox->pack_start (freesound_name_entry);
503                 label = manage (new Label);
504                 label->set_text (_("Password:"));
505                 passbox->pack_start (*label, false, false);
506                 passbox->pack_start (freesound_pass_entry);
507                 label = manage (new Label);
508                 label->set_text (_("Tags:"));
509                 passbox->pack_start (*label, false, false);
510                 passbox->pack_start (freesound_entry, false, false);
511                 passbox->pack_start (freesound_search_btn, false, false);
512                 
513                 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
514                 scroll->add(freesound_list_view);
515                 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
516
517                 vbox = manage(new VBox);
518                 vbox->pack_start (*passbox, PACK_SHRINK);
519                 vbox->pack_start(*scroll);
520                 
521                 //vbox->pack_start (freesound_list_view);
522
523                 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
524                 freesound_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
525                 
526                 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
527                 freesound_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
528                 freesound_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
529                 freesound_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
530                 notebook.append_page (*vbox, _("Search Freesound"));
531         }
532 #endif
533         
534
535         notebook.set_size_request (500, -1);
536
537         set_session (s);
538
539         add_button (Stock::CANCEL, RESPONSE_CANCEL);
540         add_button (Stock::APPLY, RESPONSE_APPLY);
541         add_button (Stock::OK, RESPONSE_OK);
542         
543 }
544
545 SoundFileBrowser::~SoundFileBrowser ()
546 {
547         persistent_folder = chooser.get_current_folder();
548 }
549
550
551 void
552 SoundFileBrowser::on_show ()
553 {
554         ArdourDialog::on_show ();
555         start_metering ();
556 }
557
558 void
559 SoundFileBrowser::clear_selection ()
560 {
561         chooser.unselect_all ();
562         found_list_view.get_selection()->unselect_all ();
563 }
564
565 void
566 SoundFileBrowser::chooser_file_activated ()
567 {
568         preview.audition ();
569 }
570
571 void
572 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
573 {
574         preview.audition ();
575 }
576
577 void
578 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
579 {
580         preview.audition ();
581 }
582
583 void
584 SoundFileBrowser::set_session (Session* s)
585 {
586         ArdourDialog::set_session (s);
587         preview.set_session (s);
588         if (s) {
589                 add_gain_meter ();
590         } else {
591                 remove_gain_meter ();
592         }
593 }
594
595 void
596 SoundFileBrowser::add_gain_meter ()
597 {
598         delete gm;
599
600         gm = new GainMeter (*session);
601         gm->set_io (session->the_auditioner());
602
603         meter_packer.set_border_width (12);
604         meter_packer.pack_start (*gm, false, true);
605         hpacker.pack_end (meter_packer, false, false);
606         meter_packer.show_all ();
607         start_metering ();
608 }
609
610 void
611 SoundFileBrowser::remove_gain_meter ()
612 {
613         if (gm) {
614                 meter_packer.remove (*gm);
615                 hpacker.remove (meter_packer);
616                 delete gm;
617                 gm = 0;
618         }
619 }
620
621 void
622 SoundFileBrowser::start_metering ()
623 {
624         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
625 }
626
627 void
628 SoundFileBrowser::stop_metering ()
629 {
630         metering_connection.disconnect();
631 }
632
633 void
634 SoundFileBrowser::meter ()
635 {
636         if (is_mapped () && session && gm) {
637                 gm->update_meters ();
638         }
639 }
640
641 bool
642 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
643 {
644         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
645 }
646
647 bool
648 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
649 {
650         return SMFSource::safe_midi_file_extension (filter_info.filename);
651 }
652
653 void
654 SoundFileBrowser::update_preview ()
655 {
656         if (preview.setup_labels (chooser.get_filename())) {
657                 if (preview.autoplay()) {
658                         Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
659                 }
660         }
661 }
662
663 void
664 SoundFileBrowser::found_list_view_selected ()
665 {
666         if (!reset_options ()) {
667                 set_response_sensitive (RESPONSE_OK, false);
668         } else {
669                 ustring file;
670
671                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
672                 
673                 if (!rows.empty()) {
674                         TreeIter iter = found_list->get_iter(*rows.begin());
675                         file = (*iter)[found_list_columns.pathname];
676                         chooser.set_filename (file);
677                         set_response_sensitive (RESPONSE_OK, true);
678                 } else {
679                         set_response_sensitive (RESPONSE_OK, false);
680                 }
681                 
682                 preview.setup_labels (file);
683         }
684 }
685
686 void
687 SoundFileBrowser::freesound_list_view_selected ()
688 {
689         if (!reset_options ()) {
690                 set_response_sensitive (RESPONSE_OK, false);
691         } else {
692                 ustring file;
693
694                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
695                 
696                 if (!rows.empty()) {
697                         TreeIter iter = freesound_list->get_iter(*rows.begin());
698                         file = (*iter)[freesound_list_columns.pathname];
699                         chooser.set_filename (file);
700                         set_response_sensitive (RESPONSE_OK, true);
701                 } else {
702                         set_response_sensitive (RESPONSE_OK, false);
703                 }
704                 
705                 preview.setup_labels (file);
706         }
707 }
708
709 void
710 SoundFileBrowser::found_search_clicked ()
711 {
712         string tag_string = found_entry.get_text ();
713
714         vector<string> tags;
715
716         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
717                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
718                 return;
719         }
720         
721         vector<string> results;
722         Library->search_members_and (results, tags);
723         
724         found_list->clear();
725         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
726                 TreeModel::iterator new_row = found_list->append();
727                 TreeModel::Row row = *new_row;
728                 string path = Glib::filename_from_uri (string ("file:") + *i);
729                 row[found_list_columns.pathname] = path;
730         }
731 }
732
733 void*
734 freesound_search_thread_entry (void* arg)
735 {
736         PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freesound Search"));
737
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                         if (info.channels > 1) {
1087                                 multichannel = true;
1088                         }
1089                         if (sz == 0) {
1090                                 sz = info.length;
1091                         } else {
1092                                 if (sz != info.length) {
1093                                         same_size = false;
1094                                 }
1095                         }
1096
1097                         if ((nframes_t) info.samplerate != session->frame_rate()) {
1098                                 src_needed = true;
1099                         }
1100
1101                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1102
1103                         Evoral::SMFReader reader(*i);
1104                         if (reader.num_tracks() > 1) {
1105                                 multichannel = true; // "channel" == track here...
1106                         }
1107
1108                         /* XXX we need err = true handling here in case 
1109                            we can't check the file
1110                         */
1111
1112                 } else {
1113                         err = true;
1114                 }
1115         }
1116
1117         return err;
1118 }
1119
1120
1121 bool
1122 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
1123 {
1124         sys::path path = s.session_directory().sound_path() / "linktest";
1125         string tmpdir = path.to_string();
1126         bool ret = false;
1127
1128         if (mkdir (tmpdir.c_str(), 0744)) {
1129                 if (errno != EEXIST) {
1130                         return false;
1131                 }
1132         }
1133         
1134         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1135
1136                 char tmpc[MAXPATHLEN+1];
1137
1138                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1139
1140                 /* can we link ? */
1141
1142                 if (link ((*i).c_str(), tmpc)) {
1143                         goto out;
1144                 }
1145                 
1146                 unlink (tmpc);
1147         }
1148
1149         ret = true;
1150
1151   out:
1152         rmdir (tmpdir.c_str());
1153         return ret;
1154 }
1155
1156 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1157         : SoundFileBrowser (parent, title, s, false)
1158 {
1159         chooser.set_select_multiple (false);
1160         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1161         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1162 }
1163
1164 void
1165 SoundFileChooser::on_hide ()
1166 {
1167         ArdourDialog::on_hide();
1168         stop_metering ();
1169
1170         if (session) {
1171                 session->cancel_audition();
1172         }
1173 }
1174
1175 ustring
1176 SoundFileChooser::get_filename ()
1177 {
1178         vector<ustring> paths;
1179
1180         paths = get_paths ();
1181
1182         if (paths.empty()) {
1183                 return ustring ();
1184         }
1185         
1186         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1187                 return ustring();
1188         }
1189
1190         return paths.front();
1191 }
1192
1193 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1194                                 Editing::ImportMode mode_hint)
1195         : SoundFileBrowser (parent, title, s, persistent),
1196           copy_files_btn ( _("Copy files to session")),
1197           selected_track_cnt (selected_tracks)
1198 {
1199         VBox* vbox;
1200         HBox* hbox;
1201         vector<string> str;
1202
1203         set_size_request (-1, 450);
1204         
1205         block_two.set_border_width (12);
1206         block_three.set_border_width (12);
1207         block_four.set_border_width (12);
1208         
1209         options.set_spacing (12);
1210
1211         str.clear ();
1212         str.push_back (_("use file timestamp"));
1213         str.push_back (_("at edit point"));
1214         str.push_back (_("at playhead"));
1215         str.push_back (_("at session start"));
1216         set_popdown_strings (where_combo, str);
1217         where_combo.set_active_text (str.front());
1218
1219         Label* l = manage (new Label);
1220         l->set_text (_("Add files:"));
1221         
1222         hbox = manage (new HBox);
1223         hbox->set_border_width (12);
1224         hbox->set_spacing (6);
1225         hbox->pack_start (*l, false, false);
1226         hbox->pack_start (action_combo, false, false);
1227         vbox = manage (new VBox);
1228         vbox->pack_start (*hbox, false, false);
1229         options.pack_start (*vbox, false, false);
1230
1231         /* dummy entry for action combo so that it doesn't look odd if we 
1232            come up with no tracks selected.
1233         */
1234
1235         str.clear ();
1236         str.push_back (importmode2string (mode_hint));
1237         set_popdown_strings (action_combo, str);
1238         action_combo.set_active_text (str.front());
1239         action_combo.set_sensitive (false);
1240
1241         l = manage (new Label);
1242         l->set_text (_("Insert:"));
1243
1244         hbox = manage (new HBox);
1245         hbox->set_border_width (12);
1246         hbox->set_spacing (6);
1247         hbox->pack_start (*l, false, false);
1248         hbox->pack_start (where_combo, false, false);
1249         vbox = manage (new VBox);
1250         vbox->pack_start (*hbox, false, false);
1251         options.pack_start (*vbox, false, false);
1252
1253
1254         l = manage (new Label);
1255         l->set_text (_("Mapping:"));
1256
1257         hbox = manage (new HBox);
1258         hbox->set_border_width (12);
1259         hbox->set_spacing (6);
1260         hbox->pack_start (*l, false, false);
1261         hbox->pack_start (channel_combo, false, false);
1262         vbox = manage (new VBox);
1263         vbox->pack_start (*hbox, false, false);
1264         options.pack_start (*vbox, false, false);
1265
1266         str.clear ();
1267         str.push_back (_("one track per file"));
1268         set_popdown_strings (channel_combo, str);
1269         channel_combo.set_active_text (str.front());
1270         channel_combo.set_sensitive (false);
1271
1272         l = manage (new Label);
1273         l->set_text (_("Conversion Quality:"));
1274
1275         hbox = manage (new HBox);
1276         hbox->set_border_width (12);
1277         hbox->set_spacing (6);
1278         hbox->pack_start (*l, false, false);
1279         hbox->pack_start (src_combo, false, false);
1280         vbox = manage (new VBox);
1281         vbox->pack_start (*hbox, false, false);
1282         options.pack_start (*vbox, false, false);
1283
1284         str.clear ();
1285         str.push_back (_("Best"));
1286         str.push_back (_("Good"));
1287         str.push_back (_("Quick"));
1288         str.push_back (_("Fast"));
1289         str.push_back (_("Fastest"));
1290
1291         set_popdown_strings (src_combo, str);
1292         src_combo.set_active_text (str.front());
1293         src_combo.set_sensitive (false);
1294
1295         reset_options ();
1296
1297         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1298         
1299         copy_files_btn.set_active (true);
1300
1301         block_four.pack_start (copy_files_btn, false, false);
1302
1303         options.pack_start (block_four, false, false);
1304
1305         get_vbox()->pack_start (options, false, false);
1306
1307         /* setup disposition map */
1308
1309         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1310         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1311         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1312         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1313
1314         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1315         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1316         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1317
1318         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1319 }
1320
1321 void
1322 SoundFileOmega::set_mode (ImportMode mode)
1323 {
1324         action_combo.set_active_text (importmode2string (mode));
1325 }
1326
1327 ImportMode
1328 SoundFileOmega::get_mode () const
1329 {
1330         return string2importmode (action_combo.get_active_text());
1331 }
1332
1333 void
1334 SoundFileOmega::on_hide ()
1335 {
1336         ArdourDialog::on_hide();
1337         if (session) {
1338                 session->cancel_audition();
1339         }
1340 }
1341
1342 ImportPosition
1343 SoundFileOmega::get_position() const
1344 {
1345         ustring str = where_combo.get_active_text();
1346
1347         if (str == _("use file timestamp")) {
1348                 return ImportAtTimestamp;
1349         } else if (str == _("at edit point")) {
1350                 return ImportAtEditPoint;
1351         } else if (str == _("at playhead")) {
1352                 return ImportAtPlayhead;
1353         } else {
1354                 return ImportAtStart;
1355         }
1356 }
1357
1358 SrcQuality
1359 SoundFileOmega::get_src_quality() const
1360 {
1361         ustring str = where_combo.get_active_text();
1362
1363         if (str == _("Best")) {
1364                 return SrcBest;
1365         } else if (str == _("Good")) {
1366                 return SrcGood;
1367         } else if (str == _("Quick")) {
1368                 return SrcQuick;
1369         } else if (str == _("Fast")) {
1370                 return SrcFast;
1371         } else {
1372                 return SrcFastest;
1373         }
1374 }
1375
1376 ImportDisposition
1377 SoundFileOmega::get_channel_disposition () const
1378 {
1379         /* we use a map here because the channel combo can contain different strings
1380            depending on the state of the other combos. the map contains all possible strings
1381            and the ImportDisposition enum that corresponds to it.
1382         */
1383
1384         ustring str = channel_combo.get_active_text();
1385         DispositionMap::const_iterator x = disposition_map.find (str);
1386
1387         if (x == disposition_map.end()) {
1388                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1389                 /*NOTREACHED*/
1390         }
1391
1392         return x->second;
1393 }
1394
1395 void
1396 SoundFileOmega::reset (int selected_tracks)
1397 {
1398         selected_track_cnt = selected_tracks;
1399         reset_options ();
1400 }       
1401
1402 void
1403 SoundFileOmega::file_selection_changed ()
1404 {
1405         if (resetting_ourselves) {
1406                 return;
1407         }
1408
1409         if (!reset_options ()) {
1410                 set_response_sensitive (RESPONSE_OK, false);
1411         } else {
1412                 if (chooser.get_filenames().size() > 0) {
1413                         set_response_sensitive (RESPONSE_OK, true);
1414                 } else {
1415                         set_response_sensitive (RESPONSE_OK, false);
1416                 }
1417         }
1418 }
1419