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