Further Freesound tweaks.
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <map>
25 #include <cerrno>
26 #include <sstream>
27
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/param.h>
31
32 #include <gtkmm/box.h>
33 #include <gtkmm/stock.h>
34 #include <glibmm/fileutils.h>
35
36 #include "pbd/convert.h"
37 #include "pbd/tokenizer.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/xml++.h"
41
42 #include <gtkmm2ext/utils.h>
43
44 #include "evoral/SMF.hpp"
45
46 #include "ardour/audio_library.h"
47 #include "ardour/auditioner.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/audiofilesource.h"
50 #include "ardour/smf_source.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/source_factory.h"
53 #include "ardour/session.h"
54 #include "ardour/session_directory.h"
55
56 #include "ardour_ui.h"
57 #include "editing.h"
58 #include "gui_thread.h"
59 #include "prompter.h"
60 #include "sfdb_ui.h"
61 #include "editing.h"
62 #include "utils.h"
63 #include "gain_meter.h"
64 #include "main_clock.h"
65 #include "public_editor.h"
66
67 #ifdef FREESOUND
68 #include "sfdb_freesound_mootcher.h"
69 #endif
70
71 #include "i18n.h"
72
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace std;
76 using namespace Gtk;
77 using namespace Gtkmm2ext;
78 using namespace Editing;
79
80 using std::string;
81
82 string SoundFileBrowser::persistent_folder;
83 typedef TreeView::Selection::ListHandle_Path ListPath;
84
85 static ImportMode
86 string2importmode (string str)
87 {
88         if (str == _("as new tracks")) {
89                 return ImportAsTrack;
90         } else if (str == _("to selected tracks")) {
91                 return ImportToTrack;
92         } else if (str == _("to region list")) {
93                 return ImportAsRegion;
94         } else if (str == _("as new tape tracks")) {
95                 return ImportAsTapeTrack;
96         }
97
98         warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
99
100         return ImportAsTrack;
101 }
102
103 static string
104 importmode2string (ImportMode mode)
105 {
106         switch (mode) {
107         case ImportAsTrack:
108                 return _("as new tracks");
109         case ImportToTrack:
110                 return _("to selected tracks");
111         case ImportAsRegion:
112                 return _("to region list");
113         case ImportAsTapeTrack:
114                 return _("as new tape tracks");
115         }
116         /*NOTREACHED*/
117         return _("as new tracks");
118 }
119
120 SoundFileBox::SoundFileBox (bool persistent)
121         : table (6, 2),
122           length_clock ("sfboxLengthClock", !persistent, "", false, false, true, false),
123           timecode_clock ("sfboxTimecodeClock", !persistent, "", false, false, false, false),
124           main_box (false, 6),
125           autoplay_btn (_("Auto-play"))
126
127 {
128         set_name (X_("SoundFileBox"));
129         set_size_request (300, -1);
130
131         preview_label.set_markup (_("<b>Sound File Information</b>"));
132
133         border_frame.set_label_widget (preview_label);
134         border_frame.add (main_box);
135
136         pack_start (border_frame, true, true);
137         set_border_width (6);
138
139         main_box.set_border_width (6);
140
141         length.set_text (_("Length:"));
142         length.set_alignment (1, 0.5);
143         timecode.set_text (_("Timestamp:"));
144         timecode.set_alignment (1, 0.5);
145         format.set_text (_("Format:"));
146         format.set_alignment (1, 0.5);
147         channels.set_text (_("Channels:"));
148         channels.set_alignment (1, 0.5);
149         samplerate.set_text (_("Sample rate:"));
150         samplerate.set_alignment (1, 0.5);
151
152         preview_label.set_max_width_chars (50);
153         preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
154
155         format_text.set_max_width_chars (20);
156         format_text.set_ellipsize (Pango::ELLIPSIZE_END);
157         format_text.set_alignment (0, 1);
158
159         table.set_col_spacings (6);
160         table.set_homogeneous (false);
161         table.set_row_spacings (6);
162
163         table.attach (channels, 0, 1, 0, 1, FILL, FILL);
164         table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
165         table.attach (format, 0, 1, 2, 4, FILL, FILL);
166         table.attach (length, 0, 1, 4, 5, FILL, FILL);
167         table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
168
169         table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
170         table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
171         table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
172         table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
173         table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
174
175         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
176         timecode_clock.set_mode (AudioClock::Timecode);
177
178         main_box.pack_start (table, false, false);
179
180         tags_entry.set_editable (true);
181         tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
182         tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
183
184         Label* label = manage (new Label (_("Tags:")));
185         label->set_alignment (0.0f, 0.5f);
186         main_box.pack_start (*label, false, false);
187         main_box.pack_start (tags_entry, true, true);
188
189         main_box.pack_start (bottom_box, false, false);
190
191         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
192 //      play_btn.set_label (_("Play"));
193
194         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
195 //      stop_btn.set_label (_("Stop"));
196
197         bottom_box.set_homogeneous (false);
198         bottom_box.set_spacing (6);
199         bottom_box.pack_start(play_btn, true, true);
200         bottom_box.pack_start(stop_btn, true, true);
201         bottom_box.pack_start(autoplay_btn, false, false);
202
203         play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
204         stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
205
206         channels_value.set_alignment (0.0f, 0.5f);
207         samplerate_value.set_alignment (0.0f, 0.5f);
208 }
209
210 void
211 SoundFileBox::set_session(Session* s)
212 {
213         SessionHandlePtr::set_session (s);
214
215         length_clock.set_session (s);
216         timecode_clock.set_session (s);
217
218         if (!_session) {
219                 play_btn.set_sensitive (false);
220                 stop_btn.set_sensitive (false);
221         }
222 }
223
224 bool
225 SoundFileBox::setup_labels (const string& filename)
226 {
227         if (!path.empty()) {
228                 // save existing tags
229                 tags_changed ();
230         }
231
232         path = filename;
233
234         string error_msg;
235
236         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
237
238                 preview_label.set_markup (_("<b>Sound File Information</b>"));
239                 format_text.set_text ("");
240                 channels_value.set_text ("");
241                 samplerate_value.set_text ("");
242                 tags_entry.get_buffer()->set_text ("");
243
244                 length_clock.set (0);
245                 timecode_clock.set (0);
246
247                 tags_entry.set_sensitive (false);
248                 play_btn.set_sensitive (false);
249
250                 return false;
251         }
252
253         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
254         std::string n = sf_info.format_name;
255         if (n.substr (0, 8) == X_("Format: ")) {
256                 n = n.substr (8);
257         }
258         format_text.set_text (n);
259         channels_value.set_text (to_string (sf_info.channels, std::dec));
260
261         if (_session && sf_info.samplerate != _session->frame_rate()) {
262                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
263                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
264                 samplerate_value.set_name ("NewSessionSR1Label");
265                 samplerate.set_name ("NewSessionSR1Label");
266         } else {
267                 samplerate.set_text (_("Sample rate:"));
268                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
269                 samplerate_value.set_name ("NewSessionSR2Label");
270                 samplerate.set_name ("NewSessionSR2Label");
271         }
272
273         framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
274         double src_coef = (double) nfr / sf_info.samplerate;
275
276         length_clock.set (sf_info.length * src_coef + 0.5, true);
277         timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
278
279         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
280
281         vector<string> tags = Library->get_tags (string ("//") + filename);
282
283         stringstream tag_string;
284         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
285                 if (i != tags.begin()) {
286                         tag_string << ", ";
287                 }
288                 tag_string << *i;
289         }
290         tags_entry.get_buffer()->set_text (tag_string.str());
291
292         tags_entry.set_sensitive (true);
293         if (_session) {
294                 play_btn.set_sensitive (true);
295         }
296
297         return true;
298 }
299
300 bool
301 SoundFileBox::autoplay() const
302 {
303         return autoplay_btn.get_active();
304 }
305
306 bool
307 SoundFileBox::audition_oneshot()
308 {
309         audition ();
310         return false;
311 }
312
313 void
314 SoundFileBox::audition ()
315 {
316         if (!_session) {
317                 return;
318         }
319
320         if (SMFSource::safe_midi_file_extension (path)) {
321                 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
322                 return;
323         }
324
325         _session->cancel_audition();
326
327         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
328                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
329                 return;
330         }
331
332         boost::shared_ptr<Region> r;
333         SourceList srclist;
334         boost::shared_ptr<AudioFileSource> afs;
335         bool old_sbp = AudioSource::get_build_peakfiles ();
336
337         /* don't even think of building peakfiles for these files */
338
339         AudioSource::set_build_peakfiles (false);
340
341         for (int n = 0; n < sf_info.channels; ++n) {
342                 try {
343                         afs = boost::dynamic_pointer_cast<AudioFileSource> (
344                                 SourceFactory::createExternal (DataType::AUDIO, *_session,
345                                                                path, n, Source::Flag (0), false));
346                         
347                         srclist.push_back(afs);
348
349                 } catch (failed_constructor& err) {
350                         error << _("Could not access soundfile: ") << path << endmsg;
351                         AudioSource::set_build_peakfiles (old_sbp);
352                         return;
353                 }
354         }
355
356         AudioSource::set_build_peakfiles (old_sbp);
357
358         if (srclist.empty()) {
359                 return;
360         }
361
362         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
363         string rname = region_name_from_path (afs->path(), false);
364
365         PropertyList plist;
366
367         plist.add (ARDOUR::Properties::start, 0);
368         plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
369         plist.add (ARDOUR::Properties::name, rname);
370         plist.add (ARDOUR::Properties::layer, 0);
371
372         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
373
374         _session->audition_region(r);
375 }
376
377 void
378 SoundFileBox::stop_audition ()
379 {
380         if (_session) {
381                 _session->cancel_audition();
382         }
383 }
384
385 bool
386 SoundFileBox::tags_entry_left (GdkEventFocus *)
387 {
388         tags_changed ();
389         return false;
390 }
391
392 void
393 SoundFileBox::tags_changed ()
394 {
395         string tag_string = tags_entry.get_buffer()->get_text ();
396
397         if (tag_string.empty()) {
398                 return;
399         }
400
401         vector<string> tags;
402
403         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
404                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
405                 return;
406         }
407
408         save_tags (tags);
409 }
410
411 void
412 SoundFileBox::save_tags (const vector<string>& tags)
413 {
414         Library->set_tags (string ("//") + path, tags);
415         Library->save_changes ();
416 }
417
418 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
419         : ArdourWindow (title)
420         , found_list (ListStore::create(found_list_columns))
421         , freesound_list (ListStore::create(freesound_list_columns))
422         , chooser (FILE_CHOOSER_ACTION_OPEN)
423         , preview (persistent)
424         , found_search_btn (_("Search"))
425         , found_list_view (found_list)
426         , freesound_search_btn (_("Search"))
427         , freesound_list_view (freesound_list)
428         , resetting_ourselves (false)
429         , matches (0)
430         , _status (0)
431         , _done (false)
432         , ok_button (Stock::OK)
433         , cancel_button (Stock::CANCEL)
434         , apply_button (Stock::APPLY)
435         , gm (0)
436 {
437
438 #ifdef GTKOSX
439         chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
440         chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
441         chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
442         chooser.add_shortcut_folder_uri("file:///Volumes");
443 #endif
444
445         //add the file chooser
446
447         chooser.set_border_width (12);
448         
449         audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
450         audio_and_midi_filter.set_name (_("Audio and MIDI files"));
451         
452         audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
453         audio_filter.set_name (_("Audio files"));
454         
455         midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
456         midi_filter.set_name (_("MIDI files"));
457         
458         matchall_filter.add_pattern ("*.*");
459         matchall_filter.set_name (_("All files"));
460         
461         chooser.add_filter (audio_and_midi_filter);
462         chooser.add_filter (audio_filter);
463         chooser.add_filter (midi_filter);
464         chooser.add_filter (matchall_filter);
465         chooser.set_select_multiple (true);
466         chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
467         chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
468
469 #ifdef GTKOSX
470         /* some broken redraw behaviour - this is a bandaid */
471         chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
472 #endif
473         
474         if (!persistent_folder.empty()) {
475                 chooser.set_current_folder (persistent_folder);
476         }
477
478         notebook.append_page (chooser, _("Browse Files"));
479         
480         hpacker.set_spacing (6);
481         hpacker.pack_start (notebook, true, true);
482         hpacker.pack_start (preview, false, false);
483
484         vpacker.set_spacing (6);
485         vpacker.pack_start (hpacker, true, true);
486
487         add (vpacker);
488
489         //add tag search
490
491         VBox* vbox;
492         HBox* hbox;
493         
494         
495         hbox = manage(new HBox);
496         hbox->pack_start (found_entry);
497         hbox->pack_start (found_search_btn);
498         
499         Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
500         scroll->add(found_list_view);
501         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
502         
503         vbox = manage(new VBox);
504         vbox->pack_start (*hbox, PACK_SHRINK);
505         vbox->pack_start (*scroll);
506         
507         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
508         
509         found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
510         
511         found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
512         
513         found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
514         found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
515         
516         notebook.append_page (*vbox, _("Search Tags"));
517
518 #ifdef FREESOUND
519
520         //add freesound search
521
522         HBox* passbox;
523         Label* label;
524         
525         passbox = manage(new HBox);
526         passbox->set_spacing (6);
527         
528         label = manage (new Label);
529         label->set_text (_("Tags:"));
530         passbox->pack_start (*label, false, false);
531         passbox->pack_start (freesound_entry, true, true);
532         
533         label = manage (new Label);
534         label->set_text (_("Sort:"));
535         passbox->pack_start (*label, false, false);
536         passbox->pack_start (freesound_sort, false, false);
537         freesound_sort.clear_items();
538         
539         // Order of the following must correspond with enum sortMethod
540         // in sfdb_freesound_mootcher.h 
541         freesound_sort.append_text(_("None"));
542         freesound_sort.append_text(_("Longest"));
543         freesound_sort.append_text(_("Shortest"));
544         freesound_sort.append_text(_("Newest"));
545         freesound_sort.append_text(_("Oldest"));
546         freesound_sort.append_text(_("Most downloaded"));
547         freesound_sort.append_text(_("Least downloaded"));
548         freesound_sort.append_text(_("Highest rated"));
549         freesound_sort.append_text(_("Lowest rated"));
550         freesound_sort.set_active(0);
551         
552         passbox->pack_start (freesound_search_btn, false, false);
553         passbox->pack_start (freesound_more_btn, false, false);
554         freesound_more_btn.set_label(_("More"));
555         freesound_more_btn.set_sensitive(false);
556
557         passbox->pack_start (freesound_similar_btn, false, false);
558         freesound_similar_btn.set_label(_("Similar"));
559         freesound_similar_btn.set_sensitive(false);
560         
561         scroll = manage(new ScrolledWindow);
562         scroll->add(freesound_list_view);
563         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
564         
565         vbox = manage(new VBox);
566         vbox->set_spacing (3);
567         vbox->pack_start (*passbox, PACK_SHRINK);
568         vbox->pack_start (*scroll);
569
570         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
571         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
572         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
573         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
574         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
575         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
576         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
577         freesound_list_view.get_column(0)->set_alignment(0.5);
578         freesound_list_view.get_column(1)->set_expand(true); // filename
579         freesound_list_view.get_column(1)->set_resizable(true); // filename
580         freesound_list_view.get_column(2)->set_alignment(0.5);
581         freesound_list_view.get_column(3)->set_alignment(0.5);
582         freesound_list_view.get_column(4)->set_alignment(0.5);
583         freesound_list_view.get_column(5)->set_alignment(0.5);
584         
585         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
586         freesound_list_view.set_tooltip_column(1);
587
588         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
589         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
590         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
591         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
592         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
593         freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
594         notebook.append_page (*vbox, _("Search Freesound"));
595 #endif
596
597         notebook.set_size_request (500, -1);
598         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
599
600         set_session (s);
601
602         Gtk::HButtonBox* button_box = manage (new HButtonBox);
603
604         button_box->set_layout (BUTTONBOX_END);
605         button_box->pack_start (cancel_button, false, false);
606         cancel_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CANCEL));
607         if (persistent) {
608                 button_box->pack_start (apply_button, false, false);
609                 apply_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_APPLY));
610         }
611
612         button_box->pack_start (ok_button, false, false);
613         ok_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
614
615         Gtkmm2ext::UI::instance()->set_tip (ok_button, _("Press to import selected files and close this window"));
616         Gtkmm2ext::UI::instance()->set_tip (apply_button, _("Press to import selected files and leave this window open"));
617         Gtkmm2ext::UI::instance()->set_tip (cancel_button, _("Press to close this window without importing any files"));
618
619         vpacker.pack_end (*button_box, false, false);
620
621         set_wmclass (X_("import"), PROGRAM_NAME);
622 }
623
624 SoundFileBrowser::~SoundFileBrowser ()
625 {
626         persistent_folder = chooser.get_current_folder();
627 }
628
629 int
630 SoundFileBrowser::run ()
631 {
632         set_modal (true);
633         show_all ();
634         present ();
635
636         _done = false;
637
638         while (!_done) {
639                 gtk_main_iteration ();
640         }
641
642         return _status;
643 }
644
645 void
646 SoundFileBrowser::set_action_sensitive (bool yn)
647 {
648         ok_button.set_sensitive (yn);
649         apply_button.set_sensitive (yn);
650 }
651
652 void
653 SoundFileBrowser::do_something (int action)
654 {
655         _done = true;
656         _status = action;
657 }
658
659 void
660 SoundFileBrowser::on_show ()
661 {
662         ArdourWindow::on_show ();
663         start_metering ();
664 }
665
666 void
667 SoundFileBrowser::clear_selection ()
668 {
669         chooser.unselect_all ();
670         found_list_view.get_selection()->unselect_all ();
671 }
672
673 void
674 SoundFileBrowser::chooser_file_activated ()
675 {
676         preview.audition ();
677 }
678
679 void
680 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
681 {
682         preview.audition ();
683 }
684
685 void
686 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
687 {
688         preview.audition ();
689 }
690
691 void
692 SoundFileBrowser::set_session (Session* s)
693 {
694         ArdourWindow::set_session (s);
695         preview.set_session (s);
696
697         if (_session) {
698                 add_gain_meter ();
699         } else {
700                 remove_gain_meter ();
701         }
702 }
703
704 void
705 SoundFileBrowser::add_gain_meter ()
706 {
707         delete gm;
708
709         gm = new GainMeter (_session, 250);
710
711         boost::shared_ptr<Route> r = _session->the_auditioner ();
712
713         gm->set_controls (r, r->shared_peak_meter(), r->amp());
714         gm->set_fader_name (X_("AudioTrackFader"));
715
716         meter_packer.set_border_width (12);
717         meter_packer.pack_start (*gm, false, true);
718         hpacker.pack_end (meter_packer, false, false);
719         meter_packer.show_all ();
720         start_metering ();
721 }
722
723 void
724 SoundFileBrowser::remove_gain_meter ()
725 {
726         if (gm) {
727                 meter_packer.remove (*gm);
728                 hpacker.remove (meter_packer);
729                 delete gm;
730                 gm = 0;
731         }
732 }
733
734 void
735 SoundFileBrowser::start_metering ()
736 {
737         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
738 }
739
740 void
741 SoundFileBrowser::stop_metering ()
742 {
743         metering_connection.disconnect();
744 }
745
746 void
747 SoundFileBrowser::meter ()
748 {
749         if (is_mapped () && _session && gm) {
750                 gm->update_meters ();
751         }
752 }
753
754 bool
755 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
756 {
757         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
758 }
759
760 bool
761 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
762 {
763         return SMFSource::safe_midi_file_extension (filter_info.filename);
764 }
765
766 bool
767 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
768 {
769         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
770 }
771
772 void
773 SoundFileBrowser::update_preview ()
774 {
775         if (preview.setup_labels (chooser.get_preview_filename())) {
776                 if (preview.autoplay()) {
777                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
778                 }
779         }
780 }
781
782 void
783 SoundFileBrowser::found_list_view_selected ()
784 {
785         if (!reset_options ()) {
786                 set_action_sensitive (false);
787         } else {
788                 string file;
789
790                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
791
792                 if (!rows.empty()) {
793                         TreeIter iter = found_list->get_iter(*rows.begin());
794                         file = (*iter)[found_list_columns.pathname];
795                         chooser.set_filename (file);
796                         set_action_sensitive (true);
797                 } else {
798                         set_action_sensitive (false);
799                 }
800
801                 preview.setup_labels (file);
802         }
803 }
804
805 void
806 SoundFileBrowser::found_search_clicked ()
807 {
808         string tag_string = found_entry.get_text ();
809
810         vector<string> tags;
811
812         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
813                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
814                 return;
815         }
816
817         vector<string> results;
818         Library->search_members_and (results, tags);
819
820         found_list->clear();
821         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
822                 TreeModel::iterator new_row = found_list->append();
823                 TreeModel::Row row = *new_row;
824                 string path = Glib::filename_from_uri (string ("file:") + *i);
825                 row[found_list_columns.pathname] = path;
826         }
827 }
828
829
830 std::string
831 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
832 {
833
834         Mootcher *mootcher = new Mootcher;
835         std::string file;
836
837         string id  = (*iter)[freesound_list_columns.id];
838         string uri = (*iter)[freesound_list_columns.uri];
839         string ofn = (*iter)[freesound_list_columns.filename];
840
841         if (mootcher->checkAudioFile(ofn, id)) {
842                 // file already exists, no need to download it again
843                 file = mootcher->audioFileName;
844                 delete mootcher;
845                 (*iter)[freesound_list_columns.started] = false;
846                 return file;
847         }
848         if (!(*iter)[freesound_list_columns.started]) {
849                 // start downloading the sound file
850                 (*iter)[freesound_list_columns.started] = true;
851                 mootcher->fetchAudioFile(ofn, id, uri, this);
852         }
853         return "";
854 }
855
856 void
857 SoundFileBrowser::freesound_list_view_selected ()
858 {
859
860         if (!reset_options ()) {
861                 set_action_sensitive (false);
862         } else {
863                 std::string file;
864                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
865                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
866                         file = freesound_get_audio_file (freesound_list->get_iter(*i));
867                 }
868
869                 switch (rows.size()) {
870                         case 0:
871                                 // nothing selected
872                                 freesound_similar_btn.set_sensitive(false);
873                                 set_action_sensitive (false);
874                                 break;
875                         case 1:
876                                 // exactly one item selected
877                                 if (file != "") {
878                                         // file exists on disk already
879                                         chooser.set_filename (file);
880                                         preview.setup_labels (file);
881                                         set_action_sensitive (true);
882                                 }
883                                 freesound_similar_btn.set_sensitive(true);
884                                 break;
885                         default:
886                                 // multiple items selected
887                                 preview.setup_labels ("");
888                                 freesound_similar_btn.set_sensitive(false);
889                                 break;
890                 }
891
892         }
893 }
894
895 void
896 SoundFileBrowser::refresh_display(std::string ID, std::string file)
897 {
898         // called when the mootcher has finished downloading a file
899         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
900         if (rows.size() == 1) {
901                 // there's a single item selected in the freesound list
902                 //XXX make a function to be used to construct the actual file name both here and in the mootcher
903                 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
904                 std::string selected_ID = (*row)[freesound_list_columns.id]; 
905                 if (ID == selected_ID) {
906                         // the selected item in the freesound list is the item that has just finished downloading
907                         chooser.set_filename(file);
908                         preview.setup_labels (file);
909                         set_action_sensitive (true);
910                 }
911         }
912 }
913
914 void
915 SoundFileBrowser::freesound_search_clicked ()
916 {
917         freesound_page = 1;
918         freesound_list->clear();
919         matches = 0;
920         freesound_search();
921 }
922
923 void
924 SoundFileBrowser::freesound_more_clicked ()
925 {
926         char row_path[21];
927         freesound_page++;
928         freesound_search();
929         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
930         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
931 }
932
933 void
934 SoundFileBrowser::freesound_similar_clicked ()
935 {
936         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
937         if (rows.size() == 1) {
938                 Mootcher mootcher;
939                 string id;
940                 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
941                 id = (*iter)[freesound_list_columns.id];
942                 freesound_list->clear();
943
944                 GdkCursor *prev_cursor;
945                 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
946                 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
947                 gdk_flush();
948                 
949                 std::string theString = mootcher.searchSimilar(id);
950                 
951                 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
952                 handle_freesound_results(theString);
953         }
954 }
955
956 void
957 SoundFileBrowser::freesound_search()
958 {
959         Mootcher mootcher;
960
961         string search_string = freesound_entry.get_text ();
962         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
963
964         GdkCursor *prev_cursor;
965         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
966         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
967         gdk_flush();
968
969         std::string theString = mootcher.searchText(
970                         search_string, 
971                         freesound_page,
972 #ifdef GTKOSX
973                         "", // OSX eats anything incl mp3
974 #else
975                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
976 #endif
977                         sort_method
978                         );
979
980         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
981         handle_freesound_results(theString);
982 }
983
984 void
985 SoundFileBrowser::handle_freesound_results(std::string theString) {
986         XMLTree doc;
987         doc.read_buffer( theString );
988         XMLNode *root = doc.root();
989
990         if (!root) {
991                 error << "no root XML node!" << endmsg;
992                 return;
993         }
994
995         if ( strcmp(root->name().c_str(), "response") != 0) {
996                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
997                 return;
998         }
999
1000         // find out how many pages are available to search
1001         int freesound_n_pages = 1;
1002         XMLNode *res = root->child("num_pages");
1003         if (res) {
1004                 string result = res->child("text")->content();
1005                 freesound_n_pages = atoi(result);
1006         }
1007
1008         int more_pages = freesound_n_pages - freesound_page;
1009
1010         if (more_pages > 0) {
1011                 freesound_more_btn.set_sensitive(true);
1012                 freesound_more_btn.set_tooltip_text(string_compose(P_(
1013                                                 "%1 more page of 100 results available",
1014                                                 "%1 more pages of 100 results available",
1015                                                 more_pages), more_pages));
1016         } else {
1017                 freesound_more_btn.set_sensitive(false);
1018                 freesound_more_btn.set_tooltip_text(_("No more results available"));
1019         }
1020
1021         XMLNode *sounds_root = root->child("sounds");
1022         if (!sounds_root) {
1023                 error << "no child node \"sounds\" found!" << endmsg;
1024                 return;
1025         }
1026
1027         XMLNodeList sounds = sounds_root->children();
1028         if (sounds.size() == 0) {
1029                 /* nothing found */
1030                 return;
1031         }
1032
1033         XMLNodeConstIterator niter;
1034         XMLNode *node;
1035         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1036                 node = *niter;
1037                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1038                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1039                         break;
1040                 }
1041
1042                 // node->dump(cerr, "node:");
1043
1044
1045                 XMLNode *id_node  = node->child ("id");
1046                 XMLNode *uri_node = node->child ("serve");
1047                 XMLNode *ofn_node = node->child ("original_filename");
1048                 XMLNode *dur_node = node->child ("duration");
1049                 XMLNode *siz_node = node->child ("filesize");
1050                 XMLNode *srt_node = node->child ("samplerate");
1051                 XMLNode *lic_node = node->child ("license");
1052
1053                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1054
1055                         std::string  id =  id_node->child("text")->content();
1056                         std::string uri = uri_node->child("text")->content();
1057                         std::string ofn = ofn_node->child("text")->content();
1058                         std::string dur = dur_node->child("text")->content();
1059                         std::string siz = siz_node->child("text")->content();
1060                         std::string srt = srt_node->child("text")->content();
1061                         std::string lic = lic_node->child("text")->content();
1062
1063                         std::string r;
1064                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1065
1066                         double duration_seconds = atof(dur);
1067                         double h, m, s;
1068                         char duration_hhmmss[16];
1069                         if (duration_seconds >= 99 * 60 * 60) {
1070                                 strcpy(duration_hhmmss, ">99h");
1071                         } else {
1072                                 s = modf(duration_seconds/60, &m) * 60;
1073                                 m = modf(m/60, &h) * 60;
1074                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1075                                                 h, m, s
1076                                        );
1077                         }
1078
1079                         double size_bytes = atof(siz);
1080                         char bsize[32];
1081                         if (size_bytes < 1000) {
1082                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1083                         } else if (size_bytes < 1000000 ) {
1084                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1085                         } else if (size_bytes < 10000000) {
1086                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1087                         } else if (size_bytes < 1000000000) {
1088                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1089                         } else {
1090                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1091                         }
1092
1093                         /* see http://www.freesound.org/help/faq/#licenses */
1094                         char shortlicense[64];
1095                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1096                                 sprintf(shortlicense, "CC-BY-NC");
1097                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1098                                 sprintf(shortlicense, "CC-BY");
1099                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1100                                 sprintf(shortlicense, "sampling+");
1101                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1102                                 sprintf(shortlicense, "PD");
1103                         } else {
1104                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1105                                 shortlicense[63]= '\0';
1106                         }
1107
1108                         TreeModel::iterator new_row = freesound_list->append();
1109                         TreeModel::Row row = *new_row;
1110
1111                         row[freesound_list_columns.id      ] = id;
1112                         row[freesound_list_columns.uri     ] = uri;
1113                         row[freesound_list_columns.filename] = ofn;
1114                         row[freesound_list_columns.duration] = duration_hhmmss;
1115                         row[freesound_list_columns.filesize] = bsize;
1116                         row[freesound_list_columns.smplrate] = srt;
1117                         row[freesound_list_columns.license ] = shortlicense;
1118                         matches++;
1119                 }
1120         }
1121 }
1122
1123 vector<string>
1124 SoundFileBrowser::get_paths ()
1125 {
1126         vector<string> results;
1127
1128         int n = notebook.get_current_page ();
1129
1130         if (n == 0) {
1131                 vector<string> filenames = chooser.get_filenames();
1132                 vector<string>::iterator i;
1133
1134                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1135                         struct stat buf;
1136                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1137                                 results.push_back (*i);
1138                         }
1139                 }
1140
1141         } else if (n == 1) {
1142
1143                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1144                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1145                         TreeIter iter = found_list->get_iter(*i);
1146                         string str = (*iter)[found_list_columns.pathname];
1147
1148                         results.push_back (str);
1149                 }
1150         } else {
1151 #ifdef FREESOUND
1152                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1153                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1154                         string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1155                         if (str != "") {
1156                                 results.push_back (str);
1157                         }
1158                 }
1159 #endif
1160         }
1161
1162         return results;
1163 }
1164
1165 void
1166 SoundFileOmega::reset_options_noret ()
1167 {
1168         if (!resetting_ourselves) {
1169                 (void) reset_options ();
1170         }
1171 }
1172
1173 bool
1174 SoundFileOmega::reset_options ()
1175 {
1176         vector<string> paths = get_paths ();
1177
1178         if (paths.empty()) {
1179
1180                 channel_combo.set_sensitive (false);
1181                 action_combo.set_sensitive (false);
1182                 where_combo.set_sensitive (false);
1183                 copy_files_btn.set_active (true);
1184                 copy_files_btn.set_sensitive (false);
1185
1186                 return false;
1187
1188         } else {
1189
1190                 channel_combo.set_sensitive (true);
1191                 action_combo.set_sensitive (true);
1192                 where_combo.set_sensitive (true);
1193
1194                 /* if we get through this function successfully, this may be
1195                    reset at the end, once we know if we can use hard links
1196                    to do embedding (or if we are importing a MIDI file).
1197                 */
1198
1199                 if (Config->get_only_copy_imported_files()) {
1200                         copy_files_btn.set_sensitive (false);
1201                 } else {
1202                         copy_files_btn.set_sensitive (false);
1203                 }
1204         }
1205
1206         bool same_size;
1207         bool src_needed;
1208         bool selection_includes_multichannel;
1209         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1210         ImportMode mode;
1211
1212         /* See if we are thinking about importing any MIDI files */
1213         vector<string>::iterator i = paths.begin ();
1214         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1215                 ++i;
1216         }
1217         bool const have_a_midi_file = (i != paths.end ());
1218
1219         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1220                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1221                 return false;
1222         }
1223
1224         string existing_choice;
1225         vector<string> action_strings;
1226
1227         resetting_ourselves = true;
1228
1229         if (chooser.get_filter() == &audio_filter) {
1230
1231                 /* AUDIO */
1232
1233                 if (selected_audio_track_cnt > 0) {
1234                         if (channel_combo.get_active_text().length()) {
1235                                 ImportDisposition id = get_channel_disposition();
1236                                 
1237                                 switch (id) {
1238                                 case Editing::ImportDistinctFiles:
1239                                         if (selected_audio_track_cnt == paths.size()) {
1240                                                 action_strings.push_back (importmode2string (ImportToTrack));
1241                                         }
1242                                         break;
1243                                         
1244                                 case Editing::ImportDistinctChannels:
1245                                         /* XXX it would be nice to allow channel-per-selected track
1246                                            but its too hard we don't want to deal with all the
1247                                            different per-file + per-track channel configurations.
1248                                         */
1249                                         break;
1250                                         
1251                                 default:
1252                                         action_strings.push_back (importmode2string (ImportToTrack));
1253                                         break;
1254                                 }
1255                         }
1256                 }
1257                 
1258         }  else {
1259
1260                 /* MIDI ONLY */
1261
1262                 if (selected_midi_track_cnt > 0) {
1263                         action_strings.push_back (importmode2string (ImportToTrack));
1264                 }
1265         }
1266
1267         action_strings.push_back (importmode2string (ImportAsTrack));
1268         action_strings.push_back (importmode2string (ImportAsRegion));
1269         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1270
1271         existing_choice = action_combo.get_active_text();
1272
1273         set_popdown_strings (action_combo, action_strings);
1274
1275         /* preserve any existing choice, if possible */
1276
1277
1278         if (existing_choice.length()) {
1279                 vector<string>::iterator x;
1280                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1281                         if (*x == existing_choice) {
1282                                 action_combo.set_active_text (existing_choice);
1283                                 break;
1284                         }
1285                 }
1286                 if (x == action_strings.end()) {
1287                         action_combo.set_active_text (action_strings.front());
1288                 }
1289         } else {
1290                 action_combo.set_active_text (action_strings.front());
1291         }
1292
1293         resetting_ourselves = false;
1294
1295         if ((mode = get_mode()) == ImportAsRegion) {
1296                 where_combo.set_sensitive (false);
1297         } else {
1298                 where_combo.set_sensitive (true);
1299         }
1300
1301         vector<string> channel_strings;
1302
1303         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1304                 channel_strings.push_back (_("one track per file"));
1305
1306                 if (selection_includes_multichannel) {
1307                         channel_strings.push_back (_("one track per channel"));
1308                 }
1309
1310                 if (paths.size() > 1) {
1311                         /* tape tracks are a single region per track, so we cannot
1312                            sequence multiple files.
1313                         */
1314                         if (mode != ImportAsTapeTrack) {
1315                                 channel_strings.push_back (_("sequence files"));
1316                         }
1317                         if (same_size) {
1318                                 channel_strings.push_back (_("all files in one track"));
1319                                 channel_strings.push_back (_("merge files"));
1320                         }
1321
1322                 }
1323
1324         } else {
1325                 channel_strings.push_back (_("one region per file"));
1326
1327                 if (selection_includes_multichannel) {
1328                         channel_strings.push_back (_("one region per channel"));
1329                 }
1330
1331                 if (paths.size() > 1) {
1332                         if (same_size) {
1333                                 channel_strings.push_back (_("all files in one region"));
1334                         }
1335                 }
1336         }
1337
1338         resetting_ourselves = true;
1339
1340         existing_choice = channel_combo.get_active_text();
1341
1342         set_popdown_strings (channel_combo, channel_strings);
1343
1344         /* preserve any existing choice, if possible */
1345
1346         if (existing_choice.length()) {
1347                 vector<string>::iterator x;
1348                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1349                         if (*x == existing_choice) {
1350                                 channel_combo.set_active_text (existing_choice);
1351                                 break;
1352                         }
1353                 }
1354                 if (x == channel_strings.end()) {
1355                         channel_combo.set_active_text (channel_strings.front());
1356                 }
1357         } else {
1358                 channel_combo.set_active_text (channel_strings.front());
1359         }
1360
1361         resetting_ourselves = false;
1362
1363         if (src_needed) {
1364                 src_combo.set_sensitive (true);
1365         } else {
1366                 src_combo.set_sensitive (false);
1367         }
1368
1369         /* We must copy MIDI files or those from Freesound
1370          * or any file if we are under nsm control */
1371         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1372         
1373         if (Config->get_only_copy_imported_files()) {
1374
1375                 if (selection_can_be_embedded_with_links && !must_copy) {
1376                         copy_files_btn.set_sensitive (true);
1377                 } else {
1378                         if (must_copy) {
1379                                 copy_files_btn.set_active (true);
1380                         }
1381                         copy_files_btn.set_sensitive (false);
1382                 }
1383
1384         }  else {
1385
1386                 if (must_copy) {
1387                         copy_files_btn.set_active (true);
1388                 }                       
1389                 copy_files_btn.set_sensitive (!must_copy);
1390         }
1391
1392         return true;
1393 }
1394
1395
1396 bool
1397 SoundFileOmega::bad_file_message()
1398 {
1399         MessageDialog msg (*this,
1400                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1401                            true,
1402                            Gtk::MESSAGE_INFO,
1403                            Gtk::BUTTONS_OK);
1404         msg.run ();
1405         resetting_ourselves = true;
1406         chooser.unselect_uri (chooser.get_preview_uri());
1407         resetting_ourselves = false;
1408
1409         return false;
1410 }
1411
1412 bool
1413 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1414 {
1415         SoundFileInfo info;
1416         framepos_t sz = 0;
1417         bool err = false;
1418         string errmsg;
1419
1420         same_size = true;
1421         src_needed = false;
1422         multichannel = false;
1423
1424         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1425
1426                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1427                         if (info.channels > 1) {
1428                                 multichannel = true;
1429                         }
1430                         if (sz == 0) {
1431                                 sz = info.length;
1432                         } else {
1433                                 if (sz != info.length) {
1434                                         same_size = false;
1435                                 }
1436                         }
1437
1438                         if (info.samplerate != _session->frame_rate()) {
1439                                 src_needed = true;
1440                         }
1441
1442                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1443
1444                         Evoral::SMF reader;
1445                         reader.open(*i);
1446                         if (reader.num_tracks() > 1) {
1447                                 multichannel = true; // "channel" == track here...
1448                         }
1449
1450                         /* XXX we need err = true handling here in case
1451                            we can't check the file
1452                         */
1453
1454                 } else {
1455                         err = true;
1456                 }
1457         }
1458
1459         return err;
1460 }
1461
1462
1463 bool
1464 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1465 {
1466         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1467         bool ret = false;
1468
1469         if (mkdir (tmpdir.c_str(), 0744)) {
1470                 if (errno != EEXIST) {
1471                         return false;
1472                 }
1473         }
1474
1475         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1476
1477                 char tmpc[MAXPATHLEN+1];
1478
1479                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1480
1481                 /* can we link ? */
1482
1483                 if (link ((*i).c_str(), tmpc)) {
1484                         goto out;
1485                 }
1486
1487                 unlink (tmpc);
1488         }
1489
1490         ret = true;
1491
1492   out:
1493         rmdir (tmpdir.c_str());
1494         return ret;
1495 }
1496
1497 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1498         : SoundFileBrowser (title, s, false)
1499 {
1500         chooser.set_select_multiple (false);
1501         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1502         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1503 }
1504
1505 void
1506 SoundFileChooser::on_hide ()
1507 {
1508         ArdourWindow::on_hide();
1509         stop_metering ();
1510
1511         if (_session) {
1512                 _session->cancel_audition();
1513         }
1514 }
1515
1516 string
1517 SoundFileChooser::get_filename ()
1518 {
1519         vector<string> paths;
1520
1521         paths = get_paths ();
1522
1523         if (paths.empty()) {
1524                 return string ();
1525         }
1526
1527         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1528                 return string();
1529         }
1530
1531         return paths.front();
1532 }
1533
1534 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1535                                 uint32_t selected_audio_tracks, 
1536                                 uint32_t selected_midi_tracks, 
1537                                 bool persistent,
1538                                 Editing::ImportMode mode_hint)
1539         : SoundFileBrowser (title, s, persistent)
1540         , copy_files_btn ( _("Copy files to session"))
1541         , selected_audio_track_cnt (selected_audio_tracks)
1542         , selected_midi_track_cnt (selected_midi_tracks)
1543 {
1544         VBox* vbox;
1545         HBox* hbox;
1546         vector<string> str;
1547
1548         set_size_request (-1, 450);
1549
1550         block_two.set_border_width (12);
1551         block_three.set_border_width (12);
1552         block_four.set_border_width (12);
1553
1554         options.set_spacing (12);
1555
1556         str.clear ();
1557         str.push_back (_("file timestamp"));
1558         str.push_back (_("edit point"));
1559         str.push_back (_("playhead"));
1560         str.push_back (_("session start"));
1561         set_popdown_strings (where_combo, str);
1562         where_combo.set_active_text (str.front());
1563
1564         Label* l = manage (new Label);
1565         l->set_markup (_("<b>Add files as ...</b>"));
1566
1567         vbox = manage (new VBox);
1568         vbox->set_border_width (12);
1569         vbox->set_spacing (6);
1570         vbox->pack_start (*l, false, false);
1571         vbox->pack_start (action_combo, false, false);
1572         hbox = manage (new HBox);
1573         hbox->pack_start (*vbox, false, false);
1574         options.pack_start (*hbox, false, false);
1575
1576         /* dummy entry for action combo so that it doesn't look odd if we
1577            come up with no tracks selected.
1578         */
1579
1580         str.clear ();
1581         str.push_back (importmode2string (mode_hint));
1582         set_popdown_strings (action_combo, str);
1583         action_combo.set_active_text (str.front());
1584         action_combo.set_sensitive (false);
1585
1586         l = manage (new Label);
1587         l->set_markup (_("<b>Insert at</b>"));
1588
1589         vbox = manage (new VBox);
1590         vbox->set_border_width (12);
1591         vbox->set_spacing (6);
1592         vbox->pack_start (*l, false, false);
1593         vbox->pack_start (where_combo, false, false);
1594         hbox = manage (new HBox);
1595         hbox->pack_start (*vbox, false, false);
1596         options.pack_start (*hbox, false, false);
1597
1598
1599         l = manage (new Label);
1600         l->set_markup (_("<b>Mapping</b>"));
1601
1602         vbox = manage (new VBox);
1603         vbox->set_border_width (12);
1604         vbox->set_spacing (6);
1605         vbox->pack_start (*l, false, false);
1606         vbox->pack_start (channel_combo, false, false);
1607         hbox = manage (new HBox);
1608         hbox->pack_start (*vbox, false, false);
1609         options.pack_start (*hbox, false, false);
1610
1611         str.clear ();
1612         str.push_back (_("one track per file"));
1613         set_popdown_strings (channel_combo, str);
1614         channel_combo.set_active_text (str.front());
1615         channel_combo.set_sensitive (false);
1616
1617         l = manage (new Label);
1618         l->set_markup (_("<b>Conversion quality</b>"));
1619
1620         vbox = manage (new VBox);
1621         vbox->set_border_width (12);
1622         vbox->set_spacing (6);
1623         vbox->pack_start (*l, false, false);
1624         vbox->pack_start (src_combo, false, false);
1625         hbox = manage (new HBox);
1626         hbox->pack_start (*vbox, false, false);
1627         options.pack_start (*hbox, false, false);
1628
1629         str.clear ();
1630         str.push_back (_("Best"));
1631         str.push_back (_("Good"));
1632         str.push_back (_("Quick"));
1633         str.push_back (_("Fast"));
1634         str.push_back (_("Fastest"));
1635
1636         set_popdown_strings (src_combo, str);
1637         src_combo.set_active_text (str.front());
1638         src_combo.set_sensitive (false);
1639
1640         reset_options ();
1641
1642         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1643         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1644
1645         copy_files_btn.set_active (true);
1646
1647         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1648
1649         if (copy_label) {
1650                 copy_label->set_size_request (175, -1);
1651                 copy_label->set_line_wrap (true);
1652         }
1653
1654         block_four.pack_start (copy_files_btn, false, false);
1655
1656         options.pack_start (block_four, false, false);
1657
1658         vpacker.pack_start (options, false, false);
1659
1660         /* setup disposition map */
1661
1662         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1663         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1664         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1665         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1666
1667         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1668         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1669         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1670         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1671
1672         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1673
1674         /* set size requests for a couple of combos to allow them to display the longest text
1675            they will ever be asked to display.  This prevents them being resized when the user
1676            selects a file to import, which in turn prevents the size of the dialog from jumping
1677            around. */
1678
1679         vector<string> t;
1680         t.push_back (_("one track per file"));
1681         t.push_back (_("one track per channel"));
1682         t.push_back (_("sequence files"));
1683         t.push_back (_("all files in one region"));
1684         set_popdown_strings (channel_combo, t);
1685
1686         t.clear ();
1687         t.push_back (importmode2string (ImportAsTrack));
1688         t.push_back (importmode2string (ImportToTrack));
1689         t.push_back (importmode2string (ImportAsRegion));
1690         t.push_back (importmode2string (ImportAsTapeTrack));
1691         set_popdown_strings (action_combo, t);
1692 }
1693
1694 void
1695 SoundFileOmega::set_mode (ImportMode mode)
1696 {
1697         action_combo.set_active_text (importmode2string (mode));
1698 }
1699
1700 ImportMode
1701 SoundFileOmega::get_mode () const
1702 {
1703         return string2importmode (action_combo.get_active_text());
1704 }
1705
1706 void
1707 SoundFileOmega::on_hide ()
1708 {
1709         ArdourWindow::on_hide();
1710         if (_session) {
1711                 _session->cancel_audition();
1712         }
1713 }
1714
1715 ImportPosition
1716 SoundFileOmega::get_position() const
1717 {
1718         string str = where_combo.get_active_text();
1719
1720         if (str == _("file timestamp")) {
1721                 return ImportAtTimestamp;
1722         } else if (str == _("edit point")) {
1723                 return ImportAtEditPoint;
1724         } else if (str == _("playhead")) {
1725                 return ImportAtPlayhead;
1726         } else {
1727                 return ImportAtStart;
1728         }
1729 }
1730
1731 SrcQuality
1732 SoundFileOmega::get_src_quality() const
1733 {
1734         string str = src_combo.get_active_text();
1735
1736         if (str == _("Best")) {
1737                 return SrcBest;
1738         } else if (str == _("Good")) {
1739                 return SrcGood;
1740         } else if (str == _("Quick")) {
1741                 return SrcQuick;
1742         } else if (str == _("Fast")) {
1743                 return SrcFast;
1744         } else {
1745                 return SrcFastest;
1746         }
1747 }
1748
1749 ImportDisposition
1750 SoundFileOmega::get_channel_disposition () const
1751 {
1752         /* we use a map here because the channel combo can contain different strings
1753            depending on the state of the other combos. the map contains all possible strings
1754            and the ImportDisposition enum that corresponds to it.
1755         */
1756
1757         string str = channel_combo.get_active_text();
1758         DispositionMap::const_iterator x = disposition_map.find (str);
1759
1760         if (x == disposition_map.end()) {
1761                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1762                 /*NOTREACHED*/
1763         }
1764
1765         return x->second;
1766 }
1767
1768 void
1769 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1770 {
1771         selected_audio_track_cnt = selected_audio_tracks;
1772         selected_midi_track_cnt = selected_midi_tracks;
1773
1774         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1775                 chooser.set_filter (midi_filter);
1776         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1777                 chooser.set_filter (audio_filter);
1778         } else {
1779                 chooser.set_filter (audio_and_midi_filter);
1780         }
1781
1782         reset_options ();
1783 }
1784
1785 void
1786 SoundFileOmega::file_selection_changed ()
1787 {
1788         if (resetting_ourselves) {
1789                 return;
1790         }
1791
1792         if (!reset_options ()) {
1793                 set_action_sensitive (false);
1794         } else {
1795                 if (chooser.get_filenames().size() > 0) {
1796                         set_action_sensitive (true);
1797                 } else {
1798                         set_action_sensitive (false);
1799                 }
1800         }
1801 }
1802
1803 void
1804 SoundFileOmega::do_something (int action)
1805 {
1806         SoundFileBrowser::do_something (action);
1807
1808         if (action == RESPONSE_CANCEL) {
1809                 hide ();
1810                 return;
1811         }
1812
1813         /* lets do it */
1814         
1815         vector<string> paths = get_paths ();
1816         ImportPosition pos = get_position ();
1817         ImportMode mode = get_mode ();
1818         ImportDisposition chns = get_channel_disposition ();
1819         framepos_t where;
1820         
1821         switch (pos) {
1822         case ImportAtEditPoint:
1823                 where = PublicEditor::instance().get_preferred_edit_position ();
1824                 break;
1825         case ImportAtTimestamp:
1826                 where = -1;
1827                 break;
1828         case ImportAtPlayhead:
1829                 where = _session->transport_frame();
1830                 break;
1831         case ImportAtStart:
1832                 where = _session->current_start_frame();
1833                 break;
1834         }
1835         
1836         SrcQuality quality = get_src_quality();
1837         
1838         if (copy_files_btn.get_active()) {
1839                 PublicEditor::instance().do_import (paths, chns, mode, quality, where);
1840         } else {
1841                 PublicEditor::instance().do_embed (paths, chns, mode, where);
1842         }
1843         
1844         if (action == RESPONSE_OK) {
1845                 hide ();
1846         }
1847 }
1848