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