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