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