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