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