Merge branch 'master' into windows
[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
35 #include <glib/gstdio.h>
36 #include <glibmm/fileutils.h>
37
38 #include "pbd/convert.h"
39 #include "pbd/tokenizer.h"
40 #include "pbd/enumwriter.h"
41 #include "pbd/pthread_utils.h"
42 #include "pbd/xml++.h"
43
44 #include <gtkmm2ext/utils.h>
45
46 #include "evoral/SMF.hpp"
47
48 #include "ardour/audio_library.h"
49 #include "ardour/auditioner.h"
50 #include "ardour/audioregion.h"
51 #include "ardour/audiofilesource.h"
52 #include "ardour/smf_source.h"
53 #include "ardour/region_factory.h"
54 #include "ardour/source_factory.h"
55 #include "ardour/session.h"
56 #include "ardour/session_directory.h"
57
58 #include "ardour_ui.h"
59 #include "editing.h"
60 #include "gui_thread.h"
61 #include "prompter.h"
62 #include "sfdb_ui.h"
63 #include "editing.h"
64 #include "utils.h"
65 #include "gain_meter.h"
66 #include "main_clock.h"
67 #include "public_editor.h"
68
69 #include "sfdb_freesound_mootcher.h"
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,
346                                                                Source::Flag (0), false));
347                         
348                         srclist.push_back(afs);
349
350                 } catch (failed_constructor& err) {
351                         error << _("Could not access soundfile: ") << path << endmsg;
352                         AudioSource::set_build_peakfiles (old_sbp);
353                         return;
354                 }
355         }
356
357         AudioSource::set_build_peakfiles (old_sbp);
358
359         if (srclist.empty()) {
360                 return;
361         }
362
363         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
364         string rname = region_name_from_path (afs->path(), false);
365
366         PropertyList plist;
367
368         plist.add (ARDOUR::Properties::start, 0);
369         plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
370         plist.add (ARDOUR::Properties::name, rname);
371         plist.add (ARDOUR::Properties::layer, 0);
372
373         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
374
375         _session->audition_region(r);
376 }
377
378 void
379 SoundFileBox::stop_audition ()
380 {
381         if (_session) {
382                 _session->cancel_audition();
383         }
384 }
385
386 bool
387 SoundFileBox::tags_entry_left (GdkEventFocus *)
388 {
389         tags_changed ();
390         return false;
391 }
392
393 void
394 SoundFileBox::tags_changed ()
395 {
396         string tag_string = tags_entry.get_buffer()->get_text ();
397
398         if (tag_string.empty()) {
399                 return;
400         }
401
402         vector<string> tags;
403
404         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
405                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
406                 return;
407         }
408
409         save_tags (tags);
410 }
411
412 void
413 SoundFileBox::save_tags (const vector<string>& tags)
414 {
415         Library->set_tags (string ("//") + path, tags);
416         Library->save_changes ();
417 }
418
419 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
420         : ArdourWindow (title)
421         , found_list (ListStore::create(found_list_columns))
422         , freesound_list (ListStore::create(freesound_list_columns))
423         , chooser (FILE_CHOOSER_ACTION_OPEN)
424         , preview (persistent)
425         , found_search_btn (_("Search"))
426         , found_list_view (found_list)
427         , freesound_search_btn (_("Search"))
428         , freesound_list_view (freesound_list)
429         , resetting_ourselves (false)
430         , matches (0)
431         , _status (0)
432         , _done (false)
433         , ok_button (Stock::OK)
434         , cancel_button (Stock::CANCEL)
435         , apply_button (Stock::APPLY)
436         , gm (0)
437 {
438
439 #ifdef GTKOSX
440         chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
441         chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
442         chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
443         chooser.add_shortcut_folder_uri("file:///Volumes");
444 #endif
445
446         //add the file chooser
447
448         chooser.set_border_width (12);
449         
450         audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
451         audio_and_midi_filter.set_name (_("Audio and MIDI files"));
452         
453         audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
454         audio_filter.set_name (_("Audio files"));
455         
456         midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
457         midi_filter.set_name (_("MIDI files"));
458         
459         matchall_filter.add_pattern ("*.*");
460         matchall_filter.set_name (_("All files"));
461         
462         chooser.add_filter (audio_and_midi_filter);
463         chooser.add_filter (audio_filter);
464         chooser.add_filter (midi_filter);
465         chooser.add_filter (matchall_filter);
466         chooser.set_select_multiple (true);
467         chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
468         chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
469
470 #ifdef GTKOSX
471         /* some broken redraw behaviour - this is a bandaid */
472         chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
473 #endif
474         
475         if (!persistent_folder.empty()) {
476                 chooser.set_current_folder (persistent_folder);
477         }
478
479         notebook.append_page (chooser, _("Browse Files"));
480         
481         hpacker.set_spacing (6);
482         hpacker.pack_start (notebook, true, true);
483         hpacker.pack_start (preview, false, false);
484
485         vpacker.set_spacing (6);
486         vpacker.pack_start (hpacker, true, true);
487
488         add (vpacker);
489
490         //add tag search
491
492         VBox* vbox;
493         HBox* hbox;
494         
495         
496         hbox = manage(new HBox);
497         hbox->pack_start (found_entry);
498         hbox->pack_start (found_search_btn);
499         
500         Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
501         scroll->add(found_list_view);
502         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
503         
504         vbox = manage(new VBox);
505         vbox->pack_start (*hbox, PACK_SHRINK);
506         vbox->pack_start (*scroll);
507         
508         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
509         
510         found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
511         
512         found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
513         
514         found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
515         found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
516         
517         notebook.append_page (*vbox, _("Search Tags"));
518
519         //add freesound search
520
521         HBox* passbox;
522         Label* label;
523         
524         passbox = manage(new HBox);
525         passbox->set_spacing (6);
526         
527         label = manage (new Label);
528         label->set_text (_("Tags:"));
529         passbox->pack_start (*label, false, false);
530         passbox->pack_start (freesound_entry, true, true);
531         
532         label = manage (new Label);
533         label->set_text (_("Sort:"));
534         passbox->pack_start (*label, false, false);
535         passbox->pack_start (freesound_sort, false, false);
536         freesound_sort.clear_items();
537         
538         // Order of the following must correspond with enum sortMethod
539         // in sfdb_freesound_mootcher.h 
540         freesound_sort.append_text(_("None"));
541         freesound_sort.append_text(_("Longest"));
542         freesound_sort.append_text(_("Shortest"));
543         freesound_sort.append_text(_("Newest"));
544         freesound_sort.append_text(_("Oldest"));
545         freesound_sort.append_text(_("Most downloaded"));
546         freesound_sort.append_text(_("Least downloaded"));
547         freesound_sort.append_text(_("Highest rated"));
548         freesound_sort.append_text(_("Lowest rated"));
549         freesound_sort.set_active(0);
550         
551         passbox->pack_start (freesound_search_btn, false, false);
552         passbox->pack_start (freesound_more_btn, false, false);
553         freesound_more_btn.set_label(_("More"));
554         freesound_more_btn.set_sensitive(false);
555
556         passbox->pack_start (freesound_similar_btn, false, false);
557         freesound_similar_btn.set_label(_("Similar"));
558         freesound_similar_btn.set_sensitive(false);
559         
560         scroll = manage(new ScrolledWindow);
561         scroll->add(freesound_list_view);
562         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
563         
564         vbox = manage(new VBox);
565         vbox->set_spacing (3);
566         vbox->pack_start (*passbox, PACK_SHRINK);
567         vbox->pack_start (*scroll);
568
569         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
570         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
571         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
572         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
573         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
574         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
575         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
576         freesound_list_view.get_column(0)->set_alignment(0.5);
577         freesound_list_view.get_column(1)->set_expand(true); // filename
578         freesound_list_view.get_column(1)->set_resizable(true); // filename
579         freesound_list_view.get_column(2)->set_alignment(0.5);
580         freesound_list_view.get_column(3)->set_alignment(0.5);
581         freesound_list_view.get_column(4)->set_alignment(0.5);
582         freesound_list_view.get_column(5)->set_alignment(0.5);
583         
584         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
585         freesound_list_view.set_tooltip_column(1);
586
587         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
588         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
589         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
590         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
591         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
592         freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
593         notebook.append_page (*vbox, _("Search Freesound"));
594
595         notebook.set_size_request (500, -1);
596         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
597
598         set_session (s);
599
600         Gtk::HButtonBox* button_box = manage (new HButtonBox);
601
602         button_box->set_layout (BUTTONBOX_END);
603         button_box->pack_start (cancel_button, false, false);
604         cancel_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CANCEL));
605         if (persistent) {
606                 button_box->pack_start (apply_button, false, false);
607                 apply_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_APPLY));
608         }
609
610         button_box->pack_start (ok_button, false, false);
611         ok_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
612
613         Gtkmm2ext::UI::instance()->set_tip (ok_button, _("Press to import selected files and close this window"));
614         Gtkmm2ext::UI::instance()->set_tip (apply_button, _("Press to import selected files and leave this window open"));
615         Gtkmm2ext::UI::instance()->set_tip (cancel_button, _("Press to close this window without importing any files"));
616
617         vpacker.pack_end (*button_box, false, false);
618
619         set_wmclass (X_("import"), PROGRAM_NAME);
620 }
621
622 SoundFileBrowser::~SoundFileBrowser ()
623 {
624         persistent_folder = chooser.get_current_folder();
625 }
626
627 int
628 SoundFileBrowser::run ()
629 {
630         set_modal (true);
631         show_all ();
632         present ();
633
634         _done = false;
635
636         while (!_done) {
637                 gtk_main_iteration ();
638         }
639
640         return _status;
641 }
642
643 void
644 SoundFileBrowser::set_action_sensitive (bool yn)
645 {
646         ok_button.set_sensitive (yn);
647         apply_button.set_sensitive (yn);
648 }
649
650 void
651 SoundFileBrowser::do_something (int action)
652 {
653         _done = true;
654         _status = action;
655 }
656
657 void
658 SoundFileBrowser::on_show ()
659 {
660         ArdourWindow::on_show ();
661         start_metering ();
662 }
663
664 void
665 SoundFileBrowser::clear_selection ()
666 {
667         chooser.unselect_all ();
668         found_list_view.get_selection()->unselect_all ();
669 }
670
671 void
672 SoundFileBrowser::chooser_file_activated ()
673 {
674         preview.audition ();
675 }
676
677 void
678 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
679 {
680         preview.audition ();
681 }
682
683 void
684 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
685 {
686         preview.audition ();
687 }
688
689 void
690 SoundFileBrowser::set_session (Session* s)
691 {
692         ArdourWindow::set_session (s);
693         preview.set_session (s);
694
695         if (_session) {
696                 add_gain_meter ();
697         } else {
698                 remove_gain_meter ();
699         }
700 }
701
702 void
703 SoundFileBrowser::add_gain_meter ()
704 {
705         delete gm;
706
707         gm = new GainMeter (_session, 250);
708
709         boost::shared_ptr<Route> r = _session->the_auditioner ();
710
711         gm->set_controls (r, r->shared_peak_meter(), r->amp());
712         gm->set_fader_name (X_("AudioTrackFader"));
713
714         meter_packer.set_border_width (12);
715         meter_packer.pack_start (*gm, false, true);
716         hpacker.pack_end (meter_packer, false, false);
717         meter_packer.show_all ();
718         start_metering ();
719 }
720
721 void
722 SoundFileBrowser::remove_gain_meter ()
723 {
724         if (gm) {
725                 meter_packer.remove (*gm);
726                 hpacker.remove (meter_packer);
727                 delete gm;
728                 gm = 0;
729         }
730 }
731
732 void
733 SoundFileBrowser::start_metering ()
734 {
735         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
736 }
737
738 void
739 SoundFileBrowser::stop_metering ()
740 {
741         metering_connection.disconnect();
742 }
743
744 void
745 SoundFileBrowser::meter ()
746 {
747         if (is_mapped () && _session && gm) {
748                 gm->update_meters ();
749         }
750 }
751
752 bool
753 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
754 {
755         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
756 }
757
758 bool
759 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
760 {
761         return SMFSource::safe_midi_file_extension (filter_info.filename);
762 }
763
764 bool
765 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
766 {
767         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
768 }
769
770 void
771 SoundFileBrowser::update_preview ()
772 {
773         if (preview.setup_labels (chooser.get_preview_filename())) {
774                 if (preview.autoplay()) {
775                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
776                 }
777         }
778 }
779
780 void
781 SoundFileBrowser::found_list_view_selected ()
782 {
783         if (!reset_options ()) {
784                 set_action_sensitive (false);
785         } else {
786                 string file;
787
788                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
789
790                 if (!rows.empty()) {
791                         TreeIter iter = found_list->get_iter(*rows.begin());
792                         file = (*iter)[found_list_columns.pathname];
793                         chooser.set_filename (file);
794                         set_action_sensitive (true);
795                 } else {
796                         set_action_sensitive (false);
797                 }
798
799                 preview.setup_labels (file);
800         }
801 }
802
803 void
804 SoundFileBrowser::found_search_clicked ()
805 {
806         string tag_string = found_entry.get_text ();
807
808         vector<string> tags;
809
810         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
811                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
812                 return;
813         }
814
815         vector<string> results;
816         Library->search_members_and (results, tags);
817
818         found_list->clear();
819         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
820                 TreeModel::iterator new_row = found_list->append();
821                 TreeModel::Row row = *new_row;
822                 string path = Glib::filename_from_uri (string ("file:") + *i);
823                 row[found_list_columns.pathname] = path;
824         }
825 }
826
827
828 std::string
829 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
830 {
831
832         Mootcher *mootcher = new Mootcher;
833         std::string file;
834
835         string id  = (*iter)[freesound_list_columns.id];
836         string uri = (*iter)[freesound_list_columns.uri];
837         string ofn = (*iter)[freesound_list_columns.filename];
838
839         if (mootcher->checkAudioFile(ofn, id)) {
840                 // file already exists, no need to download it again
841                 file = mootcher->audioFileName;
842                 delete mootcher;
843                 (*iter)[freesound_list_columns.started] = false;
844                 return file;
845         }
846         if (!(*iter)[freesound_list_columns.started]) {
847                 // start downloading the sound file
848                 (*iter)[freesound_list_columns.started] = true;
849                 mootcher->fetchAudioFile(ofn, id, uri, this);
850         }
851         return "";
852 }
853
854 void
855 SoundFileBrowser::freesound_list_view_selected ()
856 {
857
858         if (!reset_options ()) {
859                 set_action_sensitive (false);
860         } else {
861                 std::string file;
862                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
863                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
864                         file = freesound_get_audio_file (freesound_list->get_iter(*i));
865                 }
866
867                 switch (rows.size()) {
868                         case 0:
869                                 // nothing selected
870                                 freesound_similar_btn.set_sensitive(false);
871                                 set_action_sensitive (false);
872                                 break;
873                         case 1:
874                                 // exactly one item selected
875                                 if (file != "") {
876                                         // file exists on disk already
877                                         chooser.set_filename (file);
878                                         preview.setup_labels (file);
879                                         set_action_sensitive (true);
880                                 }
881                                 freesound_similar_btn.set_sensitive(true);
882                                 break;
883                         default:
884                                 // multiple items selected
885                                 preview.setup_labels ("");
886                                 freesound_similar_btn.set_sensitive(false);
887                                 break;
888                 }
889
890         }
891 }
892
893 void
894 SoundFileBrowser::refresh_display(std::string ID, std::string file)
895 {
896         // called when the mootcher has finished downloading a file
897         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
898         if (rows.size() == 1) {
899                 // there's a single item selected in the freesound list
900                 //XXX make a function to be used to construct the actual file name both here and in the mootcher
901                 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
902                 std::string selected_ID = (*row)[freesound_list_columns.id]; 
903                 if (ID == selected_ID) {
904                         // the selected item in the freesound list is the item that has just finished downloading
905                         chooser.set_filename(file);
906                         preview.setup_labels (file);
907                         set_action_sensitive (true);
908                 }
909         }
910 }
911
912 void
913 SoundFileBrowser::freesound_search_clicked ()
914 {
915         freesound_page = 1;
916         freesound_list->clear();
917         matches = 0;
918         freesound_search();
919 }
920
921 void
922 SoundFileBrowser::freesound_more_clicked ()
923 {
924         char row_path[21];
925         freesound_page++;
926         freesound_search();
927         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
928         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
929 }
930
931 void
932 SoundFileBrowser::freesound_similar_clicked ()
933 {
934         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
935         if (rows.size() == 1) {
936                 Mootcher mootcher;
937                 string id;
938                 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
939                 id = (*iter)[freesound_list_columns.id];
940                 freesound_list->clear();
941
942                 GdkCursor *prev_cursor;
943                 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
944                 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
945                 gdk_flush();
946                 
947                 std::string theString = mootcher.searchSimilar(id);
948                 
949                 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
950                 handle_freesound_results(theString);
951         }
952 }
953
954 void
955 SoundFileBrowser::freesound_search()
956 {
957         Mootcher mootcher;
958
959         string search_string = freesound_entry.get_text ();
960         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
961
962         GdkCursor *prev_cursor;
963         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
964         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
965         gdk_flush();
966
967         std::string theString = mootcher.searchText(
968                         search_string, 
969                         freesound_page,
970 #ifdef GTKOSX
971                         "", // OSX eats anything incl mp3
972 #else
973                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
974 #endif
975                         sort_method
976                         );
977
978         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
979         handle_freesound_results(theString);
980 }
981
982 void
983 SoundFileBrowser::handle_freesound_results(std::string theString) {
984         XMLTree doc;
985         doc.read_buffer( theString );
986         XMLNode *root = doc.root();
987
988         if (!root) {
989                 error << "no root XML node!" << endmsg;
990                 return;
991         }
992
993         if ( strcmp(root->name().c_str(), "response") != 0) {
994                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
995                 return;
996         }
997
998         // find out how many pages are available to search
999         int freesound_n_pages = 1;
1000         XMLNode *res = root->child("num_pages");
1001         if (res) {
1002                 string result = res->child("text")->content();
1003                 freesound_n_pages = atoi(result);
1004         }
1005
1006         int more_pages = freesound_n_pages - freesound_page;
1007
1008         if (more_pages > 0) {
1009                 freesound_more_btn.set_sensitive(true);
1010                 freesound_more_btn.set_tooltip_text(string_compose(P_(
1011                                                 "%1 more page of 100 results available",
1012                                                 "%1 more pages of 100 results available",
1013                                                 more_pages), more_pages));
1014         } else {
1015                 freesound_more_btn.set_sensitive(false);
1016                 freesound_more_btn.set_tooltip_text(_("No more results available"));
1017         }
1018
1019         XMLNode *sounds_root = root->child("sounds");
1020         if (!sounds_root) {
1021                 error << "no child node \"sounds\" found!" << endmsg;
1022                 return;
1023         }
1024
1025         XMLNodeList sounds = sounds_root->children();
1026         if (sounds.size() == 0) {
1027                 /* nothing found */
1028                 return;
1029         }
1030
1031         XMLNodeConstIterator niter;
1032         XMLNode *node;
1033         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1034                 node = *niter;
1035                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1036                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1037                         break;
1038                 }
1039
1040                 // node->dump(cerr, "node:");
1041
1042
1043                 XMLNode *id_node  = node->child ("id");
1044                 XMLNode *uri_node = node->child ("serve");
1045                 XMLNode *ofn_node = node->child ("original_filename");
1046                 XMLNode *dur_node = node->child ("duration");
1047                 XMLNode *siz_node = node->child ("filesize");
1048                 XMLNode *srt_node = node->child ("samplerate");
1049                 XMLNode *lic_node = node->child ("license");
1050
1051                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1052
1053                         std::string  id =  id_node->child("text")->content();
1054                         std::string uri = uri_node->child("text")->content();
1055                         std::string ofn = ofn_node->child("text")->content();
1056                         std::string dur = dur_node->child("text")->content();
1057                         std::string siz = siz_node->child("text")->content();
1058                         std::string srt = srt_node->child("text")->content();
1059                         std::string lic = lic_node->child("text")->content();
1060
1061                         std::string r;
1062                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1063
1064                         double duration_seconds = atof(dur);
1065                         double h, m, s;
1066                         char duration_hhmmss[16];
1067                         if (duration_seconds >= 99 * 60 * 60) {
1068                                 strcpy(duration_hhmmss, ">99h");
1069                         } else {
1070                                 s = modf(duration_seconds/60, &m) * 60;
1071                                 m = modf(m/60, &h) * 60;
1072                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1073                                                 h, m, s
1074                                        );
1075                         }
1076
1077                         double size_bytes = atof(siz);
1078                         char bsize[32];
1079                         if (size_bytes < 1000) {
1080                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1081                         } else if (size_bytes < 1000000 ) {
1082                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1083                         } else if (size_bytes < 10000000) {
1084                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1085                         } else if (size_bytes < 1000000000) {
1086                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1087                         } else {
1088                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1089                         }
1090
1091                         /* see http://www.freesound.org/help/faq/#licenses */
1092                         char shortlicense[64];
1093                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1094                                 sprintf(shortlicense, "CC-BY-NC");
1095                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1096                                 sprintf(shortlicense, "CC-BY");
1097                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1098                                 sprintf(shortlicense, "sampling+");
1099                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1100                                 sprintf(shortlicense, "PD");
1101                         } else {
1102                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1103                                 shortlicense[63]= '\0';
1104                         }
1105
1106                         TreeModel::iterator new_row = freesound_list->append();
1107                         TreeModel::Row row = *new_row;
1108
1109                         row[freesound_list_columns.id      ] = id;
1110                         row[freesound_list_columns.uri     ] = uri;
1111                         row[freesound_list_columns.filename] = ofn;
1112                         row[freesound_list_columns.duration] = duration_hhmmss;
1113                         row[freesound_list_columns.filesize] = bsize;
1114                         row[freesound_list_columns.smplrate] = srt;
1115                         row[freesound_list_columns.license ] = shortlicense;
1116                         matches++;
1117                 }
1118         }
1119 }
1120
1121 vector<string>
1122 SoundFileBrowser::get_paths ()
1123 {
1124         vector<string> results;
1125
1126         int n = notebook.get_current_page ();
1127
1128         if (n == 0) {
1129                 vector<string> filenames = chooser.get_filenames();
1130                 vector<string>::iterator i;
1131
1132                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1133                         struct stat buf;
1134                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1135                                 results.push_back (*i);
1136                         }
1137                 }
1138
1139         } else if (n == 1) {
1140
1141                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1142                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1143                         TreeIter iter = found_list->get_iter(*i);
1144                         string str = (*iter)[found_list_columns.pathname];
1145
1146                         results.push_back (str);
1147                 }
1148         } else {
1149                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1150                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1151                         string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1152                         if (str != "") {
1153                                 results.push_back (str);
1154                         }
1155                 }
1156         }
1157
1158         return results;
1159 }
1160
1161 void
1162 SoundFileOmega::reset_options_noret ()
1163 {
1164         if (!resetting_ourselves) {
1165                 (void) reset_options ();
1166         }
1167 }
1168
1169 bool
1170 SoundFileOmega::reset_options ()
1171 {
1172         vector<string> paths = get_paths ();
1173
1174         if (paths.empty()) {
1175
1176                 channel_combo.set_sensitive (false);
1177                 action_combo.set_sensitive (false);
1178                 where_combo.set_sensitive (false);
1179                 copy_files_btn.set_active (true);
1180                 copy_files_btn.set_sensitive (false);
1181
1182                 return false;
1183
1184         } else {
1185
1186                 channel_combo.set_sensitive (true);
1187                 action_combo.set_sensitive (true);
1188                 where_combo.set_sensitive (true);
1189
1190                 /* if we get through this function successfully, this may be
1191                    reset at the end, once we know if we can use hard links
1192                    to do embedding (or if we are importing a MIDI file).
1193                 */
1194
1195                 if (Config->get_only_copy_imported_files()) {
1196                         copy_files_btn.set_sensitive (false);
1197                 } else {
1198                         copy_files_btn.set_sensitive (false);
1199                 }
1200         }
1201
1202         bool same_size;
1203         bool src_needed;
1204         bool selection_includes_multichannel;
1205         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1206         ImportMode mode;
1207
1208         /* See if we are thinking about importing any MIDI files */
1209         vector<string>::iterator i = paths.begin ();
1210         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1211                 ++i;
1212         }
1213         bool const have_a_midi_file = (i != paths.end ());
1214
1215         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1216                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1217                 return false;
1218         }
1219
1220         string existing_choice;
1221         vector<string> action_strings;
1222
1223         resetting_ourselves = true;
1224
1225         if (chooser.get_filter() == &audio_filter) {
1226
1227                 /* AUDIO */
1228
1229                 if (selected_audio_track_cnt > 0) {
1230                         if (channel_combo.get_active_text().length()) {
1231                                 ImportDisposition id = get_channel_disposition();
1232                                 
1233                                 switch (id) {
1234                                 case Editing::ImportDistinctFiles:
1235                                         if (selected_audio_track_cnt == paths.size()) {
1236                                                 action_strings.push_back (importmode2string (ImportToTrack));
1237                                         }
1238                                         break;
1239                                         
1240                                 case Editing::ImportDistinctChannels:
1241                                         /* XXX it would be nice to allow channel-per-selected track
1242                                            but its too hard we don't want to deal with all the
1243                                            different per-file + per-track channel configurations.
1244                                         */
1245                                         break;
1246                                         
1247                                 default:
1248                                         action_strings.push_back (importmode2string (ImportToTrack));
1249                                         break;
1250                                 }
1251                         }
1252                 }
1253                 
1254         }  else {
1255
1256                 /* MIDI ONLY */
1257
1258                 if (selected_midi_track_cnt > 0) {
1259                         action_strings.push_back (importmode2string (ImportToTrack));
1260                 }
1261         }
1262
1263         action_strings.push_back (importmode2string (ImportAsTrack));
1264         action_strings.push_back (importmode2string (ImportAsRegion));
1265         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1266
1267         existing_choice = action_combo.get_active_text();
1268
1269         set_popdown_strings (action_combo, action_strings);
1270
1271         /* preserve any existing choice, if possible */
1272
1273
1274         if (existing_choice.length()) {
1275                 vector<string>::iterator x;
1276                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1277                         if (*x == existing_choice) {
1278                                 action_combo.set_active_text (existing_choice);
1279                                 break;
1280                         }
1281                 }
1282                 if (x == action_strings.end()) {
1283                         action_combo.set_active_text (action_strings.front());
1284                 }
1285         } else {
1286                 action_combo.set_active_text (action_strings.front());
1287         }
1288
1289         resetting_ourselves = false;
1290
1291         if ((mode = get_mode()) == ImportAsRegion) {
1292                 where_combo.set_sensitive (false);
1293         } else {
1294                 where_combo.set_sensitive (true);
1295         }
1296
1297         vector<string> channel_strings;
1298
1299         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1300                 channel_strings.push_back (_("one track per file"));
1301
1302                 if (selection_includes_multichannel) {
1303                         channel_strings.push_back (_("one track per channel"));
1304                 }
1305
1306                 if (paths.size() > 1) {
1307                         /* tape tracks are a single region per track, so we cannot
1308                            sequence multiple files.
1309                         */
1310                         if (mode != ImportAsTapeTrack) {
1311                                 channel_strings.push_back (_("sequence files"));
1312                         }
1313                         if (same_size) {
1314                                 channel_strings.push_back (_("all files in one track"));
1315                                 channel_strings.push_back (_("merge files"));
1316                         }
1317
1318                 }
1319
1320         } else {
1321                 channel_strings.push_back (_("one region per file"));
1322
1323                 if (selection_includes_multichannel) {
1324                         channel_strings.push_back (_("one region per channel"));
1325                 }
1326
1327                 if (paths.size() > 1) {
1328                         if (same_size) {
1329                                 channel_strings.push_back (_("all files in one region"));
1330                         }
1331                 }
1332         }
1333
1334         resetting_ourselves = true;
1335
1336         existing_choice = channel_combo.get_active_text();
1337
1338         set_popdown_strings (channel_combo, channel_strings);
1339
1340         /* preserve any existing choice, if possible */
1341
1342         if (existing_choice.length()) {
1343                 vector<string>::iterator x;
1344                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1345                         if (*x == existing_choice) {
1346                                 channel_combo.set_active_text (existing_choice);
1347                                 break;
1348                         }
1349                 }
1350                 if (x == channel_strings.end()) {
1351                         channel_combo.set_active_text (channel_strings.front());
1352                 }
1353         } else {
1354                 channel_combo.set_active_text (channel_strings.front());
1355         }
1356
1357         resetting_ourselves = false;
1358
1359         if (src_needed) {
1360                 src_combo.set_sensitive (true);
1361         } else {
1362                 src_combo.set_sensitive (false);
1363         }
1364
1365         /* We must copy MIDI files or those from Freesound
1366          * or any file if we are under nsm control */
1367         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1368         
1369         if (Config->get_only_copy_imported_files()) {
1370
1371                 if (selection_can_be_embedded_with_links && !must_copy) {
1372                         copy_files_btn.set_sensitive (true);
1373                 } else {
1374                         if (must_copy) {
1375                                 copy_files_btn.set_active (true);
1376                         }
1377                         copy_files_btn.set_sensitive (false);
1378                 }
1379
1380         }  else {
1381
1382                 if (must_copy) {
1383                         copy_files_btn.set_active (true);
1384                 }                       
1385                 copy_files_btn.set_sensitive (!must_copy);
1386         }
1387
1388         return true;
1389 }
1390
1391
1392 bool
1393 SoundFileOmega::bad_file_message()
1394 {
1395         MessageDialog msg (*this,
1396                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1397                            true,
1398                            Gtk::MESSAGE_INFO,
1399                            Gtk::BUTTONS_OK);
1400         msg.run ();
1401         resetting_ourselves = true;
1402         chooser.unselect_uri (chooser.get_preview_uri());
1403         resetting_ourselves = false;
1404
1405         return false;
1406 }
1407
1408 bool
1409 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1410 {
1411         SoundFileInfo info;
1412         framepos_t sz = 0;
1413         bool err = false;
1414         string errmsg;
1415
1416         same_size = true;
1417         src_needed = false;
1418         multichannel = false;
1419
1420         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1421
1422                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1423                         if (info.channels > 1) {
1424                                 multichannel = true;
1425                         }
1426                         if (sz == 0) {
1427                                 sz = info.length;
1428                         } else {
1429                                 if (sz != info.length) {
1430                                         same_size = false;
1431                                 }
1432                         }
1433
1434                         if (info.samplerate != _session->frame_rate()) {
1435                                 src_needed = true;
1436                         }
1437
1438                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1439
1440                         Evoral::SMF reader;
1441                         reader.open(*i);
1442                         if (reader.num_tracks() > 1) {
1443                                 multichannel = true; // "channel" == track here...
1444                         }
1445
1446                         /* XXX we need err = true handling here in case
1447                            we can't check the file
1448                         */
1449
1450                 } else {
1451                         err = true;
1452                 }
1453         }
1454
1455         return err;
1456 }
1457
1458
1459 bool
1460 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1461 {
1462 #ifdef WIN32
1463         return false;
1464 #else
1465         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1466         bool ret = false;
1467
1468         if (mkdir (tmpdir.c_str(), 0744)) {
1469                 if (errno != EEXIST) {
1470                         return false;
1471                 }
1472         }
1473
1474         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1475
1476                 char tmpc[MAXPATHLEN+1];
1477
1478                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1479
1480                 /* can we link ? */
1481
1482                 if (link ((*i).c_str(), tmpc)) {
1483                         goto out;
1484                 }
1485
1486                 ::g_unlink (tmpc);
1487         }
1488
1489         ret = true;
1490
1491   out:
1492         rmdir (tmpdir.c_str());
1493         return ret;
1494 #endif
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