use lucida grande for clocks with all OS X versions, BUT BETTER
[ardour.git] / gtk2_ardour / sfdb_ui.cc
1 /*
2     Copyright (C) 2005-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <map>
25 #include <cerrno>
26 #include <sstream>
27
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/param.h>
31
32 #include <gtkmm/box.h>
33 #include <gtkmm/stock.h>
34 #include <glibmm/fileutils.h>
35
36 #include "pbd/convert.h"
37 #include "pbd/tokenizer.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/xml++.h"
41
42 #include <gtkmm2ext/utils.h>
43
44 #include "evoral/SMF.hpp"
45
46 #include "ardour/audio_library.h"
47 #include "ardour/auditioner.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/audiofilesource.h"
50 #include "ardour/smf_source.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/source_factory.h"
53 #include "ardour/session.h"
54 #include "ardour/session_directory.h"
55
56 #include "ardour_ui.h"
57 #include "editing.h"
58 #include "gui_thread.h"
59 #include "prompter.h"
60 #include "sfdb_ui.h"
61 #include "editing.h"
62 #include "utils.h"
63 #include "gain_meter.h"
64 #include "main_clock.h"
65 #include "public_editor.h"
66
67 #ifdef FREESOUND
68 #include "sfdb_freesound_mootcher.h"
69 #endif
70
71 #include "i18n.h"
72
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace std;
76 using namespace Gtk;
77 using namespace Gtkmm2ext;
78 using namespace Editing;
79
80 using std::string;
81
82 string SoundFileBrowser::persistent_folder;
83
84 static ImportMode
85 string2importmode (string str)
86 {
87         if (str == _("as new tracks")) {
88                 return ImportAsTrack;
89         } else if (str == _("to selected tracks")) {
90                 return ImportToTrack;
91         } else if (str == _("to region list")) {
92                 return ImportAsRegion;
93         } else if (str == _("as new tape tracks")) {
94                 return ImportAsTapeTrack;
95         }
96
97         warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
98
99         return ImportAsTrack;
100 }
101
102 static string
103 importmode2string (ImportMode mode)
104 {
105         switch (mode) {
106         case ImportAsTrack:
107                 return _("as new tracks");
108         case ImportToTrack:
109                 return _("to selected tracks");
110         case ImportAsRegion:
111                 return _("to region list");
112         case ImportAsTapeTrack:
113                 return _("as new tape tracks");
114         }
115         /*NOTREACHED*/
116         return _("as new tracks");
117 }
118
119 SoundFileBox::SoundFileBox (bool persistent)
120         : table (6, 2),
121           length_clock ("sfboxLengthClock", !persistent, "", false, false, true, false),
122           timecode_clock ("sfboxTimecodeClock", !persistent, "", false, false, false, false),
123           main_box (false, 6),
124           autoplay_btn (_("Auto-play"))
125
126 {
127         set_name (X_("SoundFileBox"));
128         set_size_request (300, -1);
129
130         preview_label.set_markup (_("<b>Sound File Information</b>"));
131
132         border_frame.set_label_widget (preview_label);
133         border_frame.add (main_box);
134
135         pack_start (border_frame, true, true);
136         set_border_width (6);
137
138         main_box.set_border_width (6);
139
140         length.set_text (_("Length:"));
141         length.set_alignment (1, 0.5);
142         timecode.set_text (_("Timestamp:"));
143         timecode.set_alignment (1, 0.5);
144         format.set_text (_("Format:"));
145         format.set_alignment (1, 0.5);
146         channels.set_text (_("Channels:"));
147         channels.set_alignment (1, 0.5);
148         samplerate.set_text (_("Sample rate:"));
149         samplerate.set_alignment (1, 0.5);
150
151         preview_label.set_max_width_chars (50);
152         preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
153
154         format_text.set_max_width_chars (20);
155         format_text.set_ellipsize (Pango::ELLIPSIZE_END);
156         format_text.set_alignment (0, 1);
157
158         table.set_col_spacings (6);
159         table.set_homogeneous (false);
160         table.set_row_spacings (6);
161
162         table.attach (channels, 0, 1, 0, 1, FILL, FILL);
163         table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
164         table.attach (format, 0, 1, 2, 4, FILL, FILL);
165         table.attach (length, 0, 1, 4, 5, FILL, FILL);
166         table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
167
168         table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
169         table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
170         table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
171         table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
172         table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
173
174         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
175         timecode_clock.set_mode (AudioClock::Timecode);
176
177         main_box.pack_start (table, false, false);
178
179         tags_entry.set_editable (true);
180         tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
181         tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
182
183         Label* label = manage (new Label (_("Tags:")));
184         label->set_alignment (0.0f, 0.5f);
185         main_box.pack_start (*label, false, false);
186         main_box.pack_start (tags_entry, true, true);
187
188         main_box.pack_start (bottom_box, false, false);
189
190         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
191 //      play_btn.set_label (_("Play"));
192
193         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
194 //      stop_btn.set_label (_("Stop"));
195
196         bottom_box.set_homogeneous (false);
197         bottom_box.set_spacing (6);
198         bottom_box.pack_start(play_btn, true, true);
199         bottom_box.pack_start(stop_btn, true, true);
200         bottom_box.pack_start(autoplay_btn, false, false);
201
202         play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
203         stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
204
205         channels_value.set_alignment (0.0f, 0.5f);
206         samplerate_value.set_alignment (0.0f, 0.5f);
207 }
208
209 void
210 SoundFileBox::set_session(Session* s)
211 {
212         SessionHandlePtr::set_session (s);
213
214         length_clock.set_session (s);
215         timecode_clock.set_session (s);
216
217         if (!_session) {
218                 play_btn.set_sensitive (false);
219                 stop_btn.set_sensitive (false);
220         }
221 }
222
223 bool
224 SoundFileBox::setup_labels (const string& filename)
225 {
226         if (!path.empty()) {
227                 // save existing tags
228                 tags_changed ();
229         }
230
231         path = filename;
232
233         string error_msg;
234
235         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
236
237                 preview_label.set_markup (_("<b>Sound File Information</b>"));
238                 format_text.set_text ("");
239                 channels_value.set_text ("");
240                 samplerate_value.set_text ("");
241                 tags_entry.get_buffer()->set_text ("");
242
243                 length_clock.set (0);
244                 timecode_clock.set (0);
245
246                 tags_entry.set_sensitive (false);
247                 play_btn.set_sensitive (false);
248
249                 return false;
250         }
251
252         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
253         std::string n = sf_info.format_name;
254         if (n.substr (0, 8) == X_("Format: ")) {
255                 n = n.substr (8);
256         }
257         format_text.set_text (n);
258         channels_value.set_text (to_string (sf_info.channels, std::dec));
259
260         if (_session && sf_info.samplerate != _session->frame_rate()) {
261                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
262                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
263                 samplerate_value.set_name ("NewSessionSR1Label");
264                 samplerate.set_name ("NewSessionSR1Label");
265         } else {
266                 samplerate.set_text (_("Sample rate:"));
267                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
268                 samplerate_value.set_name ("NewSessionSR2Label");
269                 samplerate.set_name ("NewSessionSR2Label");
270         }
271
272         framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
273         double src_coef = (double) nfr / sf_info.samplerate;
274
275         length_clock.set (sf_info.length * src_coef + 0.5, true);
276         timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
277
278         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
279
280         vector<string> tags = Library->get_tags (string ("//") + filename);
281
282         stringstream tag_string;
283         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
284                 if (i != tags.begin()) {
285                         tag_string << ", ";
286                 }
287                 tag_string << *i;
288         }
289         tags_entry.get_buffer()->set_text (tag_string.str());
290
291         tags_entry.set_sensitive (true);
292         if (_session) {
293                 play_btn.set_sensitive (true);
294         }
295
296         return true;
297 }
298
299 bool
300 SoundFileBox::autoplay() const
301 {
302         return autoplay_btn.get_active();
303 }
304
305 bool
306 SoundFileBox::audition_oneshot()
307 {
308         audition ();
309         return false;
310 }
311
312 void
313 SoundFileBox::audition ()
314 {
315         if (!_session) {
316                 return;
317         }
318
319         if (SMFSource::safe_midi_file_extension (path)) {
320                 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
321                 return;
322         }
323
324         _session->cancel_audition();
325
326         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
327                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
328                 return;
329         }
330
331         boost::shared_ptr<Region> r;
332         SourceList srclist;
333         boost::shared_ptr<AudioFileSource> afs;
334         bool old_sbp = AudioSource::get_build_peakfiles ();
335
336         /* don't even think of building peakfiles for these files */
337
338         AudioSource::set_build_peakfiles (false);
339
340         for (int n = 0; n < sf_info.channels; ++n) {
341                 try {
342                         afs = boost::dynamic_pointer_cast<AudioFileSource> (
343                                         SourceFactory::createReadable (DataType::AUDIO, *_session,
344                                                         path, n, 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         freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
516         
517         notebook.append_page (*vbox, _("Search Tags"));
518
519 #ifdef FREESOUND
520
521         //add freesound search
522
523         mootcher = new Mootcher();
524         
525         HBox* passbox;
526         Label* label;
527         
528         passbox = manage(new HBox);
529         passbox->set_spacing (6);
530         
531         label = manage (new Label);
532         label->set_text (_("Tags:"));
533         passbox->pack_start (*label, false, false);
534         passbox->pack_start (freesound_entry, true, true);
535         
536         label = manage (new Label);
537         label->set_text (_("Sort:"));
538         passbox->pack_start (*label, false, false);
539         passbox->pack_start (freesound_sort, false, false);
540         freesound_sort.clear_items();
541         
542         // Order of the following must correspond with enum sortMethod
543         // in sfdb_freesound_mootcher.h 
544         freesound_sort.append_text(_("None"));
545         freesound_sort.append_text(_("Longest"));
546         freesound_sort.append_text(_("Shortest"));
547         freesound_sort.append_text(_("Newest"));
548         freesound_sort.append_text(_("Oldest"));
549         freesound_sort.append_text(_("Most downloaded"));
550         freesound_sort.append_text(_("Least downloaded"));
551         freesound_sort.append_text(_("Highest rated"));
552         freesound_sort.append_text(_("Lowest rated"));
553         freesound_sort.set_active(0);
554         
555         passbox->pack_start (freesound_search_btn, false, false);
556         passbox->pack_end   (freesound_stop_btn, false, false);
557         freesound_stop_btn.set_label(_("Stop"));
558         
559         scroll = manage(new ScrolledWindow);
560         scroll->add(freesound_list_view);
561         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
562         
563         vbox = manage(new VBox);
564         vbox->set_spacing (3);
565         vbox->pack_start (*passbox, PACK_SHRINK);
566         vbox->pack_start (freesound_progress_bar, PACK_SHRINK);
567         vbox->pack_start (*scroll);
568         
569         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
570         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
571         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
572         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
573         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
574         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
575         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
576         freesound_list_view.get_column(0)->set_alignment(0.5);
577         freesound_list_view.get_column(1)->set_expand(true);
578         freesound_list_view.get_column(2)->set_alignment(0.5);
579         freesound_list_view.get_column(3)->set_alignment(0.5);
580         freesound_list_view.get_column(4)->set_alignment(0.5);
581         freesound_list_view.get_column(5)->set_alignment(0.5);
582         
583         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
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_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
590         notebook.append_page (*vbox, _("Search Freesound"));
591 #endif
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                 TreeView::Selection::ListHandle_Path 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::freesound_list_view_selected ()
803 {
804         freesound_download_cancel = false;
805
806 #ifdef FREESOUND
807         if (!reset_options ()) {
808                 set_action_sensitive (false);
809         } else {
810
811                 string file;
812
813                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
814
815                 if (!rows.empty()) {
816                         TreeIter iter = freesound_list->get_iter(*rows.begin());
817
818                         string id  = (*iter)[freesound_list_columns.id];
819                         string uri = (*iter)[freesound_list_columns.uri];
820                         string ofn = (*iter)[freesound_list_columns.filename];
821
822                         // download the sound file                      
823                         GdkCursor *prev_cursor;
824                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
825                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
826                         gdk_flush();
827
828                         file = mootcher->getAudioFile(ofn, id, uri, this);
829
830                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
831
832                         if (file != "") {
833                                 chooser.set_filename (file);
834                                 set_action_sensitive (true);
835                         }
836                 } else {
837                         set_action_sensitive (false);
838                 }
839
840                 freesound_progress_bar.set_text(
841                         string_compose(P_("found %1 match", "found %1 matches", matches), matches));
842
843                 preview.setup_labels (file);
844         }
845 #endif
846 }
847
848 void
849 SoundFileBrowser::found_search_clicked ()
850 {
851         string tag_string = found_entry.get_text ();
852
853         vector<string> tags;
854
855         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
856                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
857                 return;
858         }
859
860         vector<string> results;
861         Library->search_members_and (results, tags);
862
863         found_list->clear();
864         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
865                 TreeModel::iterator new_row = found_list->append();
866                 TreeModel::Row row = *new_row;
867                 string path = Glib::filename_from_uri (string ("file:") + *i);
868                 row[found_list_columns.pathname] = path;
869         }
870 }
871
872 void
873 SoundFileBrowser::freesound_search_clicked ()
874 {
875         freesound_search_cancel = false;
876         freesound_search();
877 }
878
879 void
880 SoundFileBrowser::freesound_stop_clicked ()
881 {
882         freesound_download_cancel = true;
883         freesound_search_cancel = true;
884 }
885
886
887 void
888 SoundFileBrowser::freesound_search()
889 {
890 #ifdef FREESOUND
891         freesound_list->clear();
892         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_GROW_ONLY);
893         matches = 0;
894
895         string search_string = freesound_entry.get_text ();
896         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
897
898         GdkCursor *prev_cursor;
899         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
900         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
901         freesound_progress_bar.set_fraction(0.0);
902         gdk_flush();
903
904         int freesound_n_pages = 1;
905         for (int page = 1; page <= 99 && page <= freesound_n_pages; page++ ) {
906                 
907                 std::string prog;
908                 if (freesound_n_pages > 1) {
909                         freesound_progress_bar.set_fraction(page/(float)freesound_n_pages);
910                         prog = string_compose (_("Searching Page %1 of %2, click Stop to cancel"), page, freesound_n_pages);
911                 } else {
912                         prog = _("Searching, click Stop to cancel");
913                 }
914                 freesound_progress_bar.set_text(prog);
915                 while (Glib::MainContext::get_default()->iteration (false)) {
916                         /* do nothing */
917                 }
918
919                 std::string theString = mootcher->searchText(
920                         search_string, 
921                         page,
922 #ifdef GTKOSX
923                         "", // OSX eats anything incl mp3
924 #else
925                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
926 #endif
927                         sort_method
928                 );
929
930                 XMLTree doc;
931                 doc.read_buffer( theString );
932                 XMLNode *root = doc.root();
933
934                 if (!root) {
935                         error << "no root XML node!" << endmsg;
936                         break;
937                 }
938
939                 if ( strcmp(root->name().c_str(), "response") != 0) {
940                         error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
941                         break;
942                 }
943
944                 //find out how many pages are available to search
945                 XMLNode *res = root->child("num_pages");
946                 if (res) {
947                         string result = res->child("text")->content();
948                         freesound_n_pages = atoi(result.c_str());
949                 }
950
951                 XMLNode *sounds_root = root->child("sounds");
952                 
953                 if (!sounds_root) {
954                         error << "no child node \"sounds\" found!" << endmsg;
955                         break;
956                 }
957                 
958                 XMLNodeList sounds = sounds_root->children();
959                 if (sounds.size() == 0) {
960                         /* nothing found */
961                         break;
962                 }
963
964                 XMLNodeConstIterator niter;
965                 XMLNode *node;
966                 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
967                         node = *niter;
968                         if( strcmp( node->name().c_str(), "resource") != 0 ){
969                                 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
970                                 freesound_search_cancel = true;
971                                 break;
972                         }
973
974                         // node->dump(cerr, "node:");
975                         
976                         XMLNode *id_node  = node->child ("id");
977                         XMLNode *uri_node = node->child ("serve");
978                         XMLNode *ofn_node = node->child ("original_filename");
979                         XMLNode *dur_node = node->child ("duration");
980                         XMLNode *siz_node = node->child ("filesize");
981                         XMLNode *srt_node = node->child ("samplerate");
982                         XMLNode *lic_node = node->child ("license");
983
984                         if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
985                                 
986                                 std::string  id =  id_node->child("text")->content();
987                                 std::string uri = uri_node->child("text")->content();
988                                 std::string ofn = ofn_node->child("text")->content();
989                                 std::string dur = dur_node->child("text")->content();
990                                 std::string siz = siz_node->child("text")->content();
991                                 std::string srt = srt_node->child("text")->content();
992                                 std::string lic = lic_node->child("text")->content();
993
994                                 std::string r;
995                                 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
996                                 
997                                 double duration_seconds = atof(dur.c_str());
998                                 double h, m, s;
999                                 char duration_hhmmss[16];
1000                                 if (duration_seconds >= 99 * 60 * 60) {
1001                                         strcpy(duration_hhmmss, ">99h");
1002                                 } else {
1003                                         s = modf(duration_seconds/60, &m) * 60;
1004                                         m = modf(m/60, &h) * 60;
1005                                         sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1006                                                 h, m, s
1007                                         );
1008                                 }
1009
1010                                 double size_bytes = atof(siz.c_str());
1011                                 char bsize[32];
1012                                 if (size_bytes < 1000) {
1013                                         sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1014                                 } else if (size_bytes < 1000000 ) {
1015                                         sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1016                                 } else if (size_bytes < 10000000) {
1017                                         sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1018                                 } else if (size_bytes < 1000000000) {
1019                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1020                                 } else {
1021                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1022                                 }
1023
1024                                 /* see http://www.freesound.org/help/faq/#licenses */
1025                                 char shortlicense[64];
1026                                 if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1027                                         sprintf(shortlicense, "CC-BY-NC");
1028                                 } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1029                                         sprintf(shortlicense, "CC-BY");
1030                                 } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1031                                         sprintf(shortlicense, "sampling+");
1032                                 } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1033                                         sprintf(shortlicense, "PD");
1034                                 } else {
1035                                         snprintf(shortlicense, 64, "%s", lic.c_str());
1036                                         shortlicense[63]= '\0';
1037                                 }
1038
1039                                 TreeModel::iterator new_row = freesound_list->append();
1040                                 TreeModel::Row row = *new_row;
1041                                 
1042                                 row[freesound_list_columns.id      ] = id;
1043                                 row[freesound_list_columns.uri     ] = uri;
1044                                 row[freesound_list_columns.filename] = ofn;
1045                                 row[freesound_list_columns.duration] = duration_hhmmss;
1046                                 row[freesound_list_columns.filesize] = bsize;
1047                                 row[freesound_list_columns.smplrate] = srt;
1048                                 row[freesound_list_columns.license ] = shortlicense;
1049                                 matches++;
1050
1051                         }
1052                 }
1053         
1054                 if (freesound_search_cancel)
1055                         break;
1056
1057         }  //page "for" loop
1058
1059         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1060
1061         freesound_progress_bar.set_fraction(0.0);
1062         if (matches == 0) {
1063                 freesound_progress_bar.set_text(_("Search returned no results."));
1064         } else {
1065                 freesound_progress_bar.set_text(string_compose(P_("Found %1 match", "Found %1 matches", matches), matches));
1066         }
1067         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_AUTOSIZE);
1068 #endif
1069 }
1070
1071 vector<string>
1072 SoundFileBrowser::get_paths ()
1073 {
1074         vector<string> results;
1075
1076         int n = notebook.get_current_page ();
1077
1078         if (n == 0) {
1079                 vector<string> filenames = chooser.get_filenames();
1080                 vector<string>::iterator i;
1081
1082                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1083                         struct stat buf;
1084                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1085                                 results.push_back (*i);
1086                         }
1087                 }
1088
1089         } else if (n==1){
1090
1091                 typedef TreeView::Selection::ListHandle_Path ListPath;
1092
1093                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1094                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1095                         TreeIter iter = found_list->get_iter(*i);
1096                         string str = (*iter)[found_list_columns.pathname];
1097
1098                         results.push_back (str);
1099                 }
1100         } else {
1101 #ifdef FREESOUND
1102                 typedef TreeView::Selection::ListHandle_Path ListPath;
1103
1104                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1105                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1106                         TreeIter iter = freesound_list->get_iter(*i);
1107                         string id  = (*iter)[freesound_list_columns.id];
1108                         string uri = (*iter)[freesound_list_columns.uri];
1109                         string ofn = (*iter)[freesound_list_columns.filename];
1110
1111                         GdkCursor *prev_cursor;
1112                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1113                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1114                         gdk_flush();
1115
1116                         string str = mootcher->getAudioFile(ofn, id, uri, this);
1117                         if (str != "") {
1118                                 results.push_back (str);
1119                         }
1120                         
1121                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1122
1123                 }
1124 #endif
1125         }
1126
1127         return results;
1128 }
1129
1130 void
1131 SoundFileOmega::reset_options_noret ()
1132 {
1133         if (!resetting_ourselves) {
1134                 (void) reset_options ();
1135         }
1136 }
1137
1138 bool
1139 SoundFileOmega::reset_options ()
1140 {
1141         vector<string> paths = get_paths ();
1142
1143         if (paths.empty()) {
1144
1145                 channel_combo.set_sensitive (false);
1146                 action_combo.set_sensitive (false);
1147                 where_combo.set_sensitive (false);
1148                 copy_files_btn.set_active (true);
1149                 copy_files_btn.set_sensitive (false);
1150
1151                 return false;
1152
1153         } else {
1154
1155                 channel_combo.set_sensitive (true);
1156                 action_combo.set_sensitive (true);
1157                 where_combo.set_sensitive (true);
1158
1159                 /* if we get through this function successfully, this may be
1160                    reset at the end, once we know if we can use hard links
1161                    to do embedding (or if we are importing a MIDI file).
1162                 */
1163
1164                 if (Config->get_only_copy_imported_files()) {
1165                         copy_files_btn.set_sensitive (false);
1166                 } else {
1167                         copy_files_btn.set_sensitive (false);
1168                 }
1169         }
1170
1171         bool same_size;
1172         bool src_needed;
1173         bool selection_includes_multichannel;
1174         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1175         ImportMode mode;
1176
1177         /* See if we are thinking about importing any MIDI files */
1178         vector<string>::iterator i = paths.begin ();
1179         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1180                 ++i;
1181         }
1182         bool const have_a_midi_file = (i != paths.end ());
1183
1184         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1185                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1186                 return false;
1187         }
1188
1189         string existing_choice;
1190         vector<string> action_strings;
1191
1192         resetting_ourselves = true;
1193
1194         if (chooser.get_filter() == &audio_filter) {
1195
1196                 /* AUDIO */
1197
1198                 if (selected_audio_track_cnt > 0) {
1199                         if (channel_combo.get_active_text().length()) {
1200                                 ImportDisposition id = get_channel_disposition();
1201                                 
1202                                 switch (id) {
1203                                 case Editing::ImportDistinctFiles:
1204                                         if (selected_audio_track_cnt == paths.size()) {
1205                                                 action_strings.push_back (importmode2string (ImportToTrack));
1206                                         }
1207                                         break;
1208                                         
1209                                 case Editing::ImportDistinctChannels:
1210                                         /* XXX it would be nice to allow channel-per-selected track
1211                                            but its too hard we don't want to deal with all the
1212                                            different per-file + per-track channel configurations.
1213                                         */
1214                                         break;
1215                                         
1216                                 default:
1217                                         action_strings.push_back (importmode2string (ImportToTrack));
1218                                         break;
1219                                 }
1220                         }
1221                 }
1222                 
1223         }  else {
1224
1225                 /* MIDI ONLY */
1226
1227                 if (selected_midi_track_cnt > 0) {
1228                         action_strings.push_back (importmode2string (ImportToTrack));
1229                 }
1230         }
1231
1232         action_strings.push_back (importmode2string (ImportAsTrack));
1233         action_strings.push_back (importmode2string (ImportAsRegion));
1234         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1235
1236         existing_choice = action_combo.get_active_text();
1237
1238         set_popdown_strings (action_combo, action_strings);
1239
1240         /* preserve any existing choice, if possible */
1241
1242
1243         if (existing_choice.length()) {
1244                 vector<string>::iterator x;
1245                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1246                         if (*x == existing_choice) {
1247                                 action_combo.set_active_text (existing_choice);
1248                                 break;
1249                         }
1250                 }
1251                 if (x == action_strings.end()) {
1252                         action_combo.set_active_text (action_strings.front());
1253                 }
1254         } else {
1255                 action_combo.set_active_text (action_strings.front());
1256         }
1257
1258         resetting_ourselves = false;
1259
1260         if ((mode = get_mode()) == ImportAsRegion) {
1261                 where_combo.set_sensitive (false);
1262         } else {
1263                 where_combo.set_sensitive (true);
1264         }
1265
1266         vector<string> channel_strings;
1267
1268         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1269                 channel_strings.push_back (_("one track per file"));
1270
1271                 if (selection_includes_multichannel) {
1272                         channel_strings.push_back (_("one track per channel"));
1273                 }
1274
1275                 if (paths.size() > 1) {
1276                         /* tape tracks are a single region per track, so we cannot
1277                            sequence multiple files.
1278                         */
1279                         if (mode != ImportAsTapeTrack) {
1280                                 channel_strings.push_back (_("sequence files"));
1281                         }
1282                         if (same_size) {
1283                                 channel_strings.push_back (_("all files in one track"));
1284                                 channel_strings.push_back (_("merge files"));
1285                         }
1286
1287                 }
1288
1289         } else {
1290                 channel_strings.push_back (_("one region per file"));
1291
1292                 if (selection_includes_multichannel) {
1293                         channel_strings.push_back (_("one region per channel"));
1294                 }
1295
1296                 if (paths.size() > 1) {
1297                         if (same_size) {
1298                                 channel_strings.push_back (_("all files in one region"));
1299                         }
1300                 }
1301         }
1302
1303         resetting_ourselves = true;
1304
1305         existing_choice = channel_combo.get_active_text();
1306
1307         set_popdown_strings (channel_combo, channel_strings);
1308
1309         /* preserve any existing choice, if possible */
1310
1311         if (existing_choice.length()) {
1312                 vector<string>::iterator x;
1313                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1314                         if (*x == existing_choice) {
1315                                 channel_combo.set_active_text (existing_choice);
1316                                 break;
1317                         }
1318                 }
1319                 if (x == channel_strings.end()) {
1320                         channel_combo.set_active_text (channel_strings.front());
1321                 }
1322         } else {
1323                 channel_combo.set_active_text (channel_strings.front());
1324         }
1325
1326         resetting_ourselves = false;
1327
1328         if (src_needed) {
1329                 src_combo.set_sensitive (true);
1330         } else {
1331                 src_combo.set_sensitive (false);
1332         }
1333
1334         /* We must copy MIDI files or those from Freesound */
1335         bool const must_copy = have_a_midi_file || notebook.get_current_page() == 2;
1336         
1337         if (Config->get_only_copy_imported_files()) {
1338
1339                 if (selection_can_be_embedded_with_links && !must_copy) {
1340                         copy_files_btn.set_sensitive (true);
1341                 } else {
1342                         if (must_copy) {
1343                                 copy_files_btn.set_active (true);
1344                         }
1345                         copy_files_btn.set_sensitive (false);
1346                 }
1347
1348         }  else {
1349
1350                 if (must_copy) {
1351                         copy_files_btn.set_active (true);
1352                 }                       
1353                 copy_files_btn.set_sensitive (!must_copy);
1354         }
1355
1356         return true;
1357 }
1358
1359
1360 bool
1361 SoundFileOmega::bad_file_message()
1362 {
1363         MessageDialog msg (*this,
1364                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1365                            true,
1366                            Gtk::MESSAGE_INFO,
1367                            Gtk::BUTTONS_OK);
1368         msg.run ();
1369         resetting_ourselves = true;
1370         chooser.unselect_uri (chooser.get_preview_uri());
1371         resetting_ourselves = false;
1372
1373         return false;
1374 }
1375
1376 bool
1377 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1378 {
1379         SoundFileInfo info;
1380         framepos_t sz = 0;
1381         bool err = false;
1382         string errmsg;
1383
1384         same_size = true;
1385         src_needed = false;
1386         multichannel = false;
1387
1388         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1389
1390                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1391                         if (info.channels > 1) {
1392                                 multichannel = true;
1393                         }
1394                         if (sz == 0) {
1395                                 sz = info.length;
1396                         } else {
1397                                 if (sz != info.length) {
1398                                         same_size = false;
1399                                 }
1400                         }
1401
1402                         if (info.samplerate != _session->frame_rate()) {
1403                                 src_needed = true;
1404                         }
1405
1406                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1407
1408                         Evoral::SMF reader;
1409                         reader.open(*i);
1410                         if (reader.num_tracks() > 1) {
1411                                 multichannel = true; // "channel" == track here...
1412                         }
1413
1414                         /* XXX we need err = true handling here in case
1415                            we can't check the file
1416                         */
1417
1418                 } else {
1419                         err = true;
1420                 }
1421         }
1422
1423         return err;
1424 }
1425
1426
1427 bool
1428 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1429 {
1430         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1431         bool ret = false;
1432
1433         if (mkdir (tmpdir.c_str(), 0744)) {
1434                 if (errno != EEXIST) {
1435                         return false;
1436                 }
1437         }
1438
1439         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1440
1441                 char tmpc[MAXPATHLEN+1];
1442
1443                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1444
1445                 /* can we link ? */
1446
1447                 if (link ((*i).c_str(), tmpc)) {
1448                         goto out;
1449                 }
1450
1451                 unlink (tmpc);
1452         }
1453
1454         ret = true;
1455
1456   out:
1457         rmdir (tmpdir.c_str());
1458         return ret;
1459 }
1460
1461 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1462         : SoundFileBrowser (title, s, false)
1463 {
1464         chooser.set_select_multiple (false);
1465         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1466         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1467 }
1468
1469 void
1470 SoundFileChooser::on_hide ()
1471 {
1472         ArdourWindow::on_hide();
1473         stop_metering ();
1474
1475         if (_session) {
1476                 _session->cancel_audition();
1477         }
1478 }
1479
1480 string
1481 SoundFileChooser::get_filename ()
1482 {
1483         vector<string> paths;
1484
1485         paths = get_paths ();
1486
1487         if (paths.empty()) {
1488                 return string ();
1489         }
1490
1491         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1492                 return string();
1493         }
1494
1495         return paths.front();
1496 }
1497
1498 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1499                                 uint32_t selected_audio_tracks, 
1500                                 uint32_t selected_midi_tracks, 
1501                                 bool persistent,
1502                                 Editing::ImportMode mode_hint)
1503         : SoundFileBrowser (title, s, persistent)
1504         , copy_files_btn ( _("Copy files to session"))
1505         , selected_audio_track_cnt (selected_audio_tracks)
1506         , selected_midi_track_cnt (selected_midi_tracks)
1507 {
1508         VBox* vbox;
1509         HBox* hbox;
1510         vector<string> str;
1511
1512         set_size_request (-1, 450);
1513
1514         block_two.set_border_width (12);
1515         block_three.set_border_width (12);
1516         block_four.set_border_width (12);
1517
1518         options.set_spacing (12);
1519
1520         str.clear ();
1521         str.push_back (_("file timestamp"));
1522         str.push_back (_("edit point"));
1523         str.push_back (_("playhead"));
1524         str.push_back (_("session start"));
1525         set_popdown_strings (where_combo, str);
1526         where_combo.set_active_text (str.front());
1527
1528         Label* l = manage (new Label);
1529         l->set_markup (_("<b>Add files as ...</b>"));
1530
1531         vbox = manage (new VBox);
1532         vbox->set_border_width (12);
1533         vbox->set_spacing (6);
1534         vbox->pack_start (*l, false, false);
1535         vbox->pack_start (action_combo, false, false);
1536         hbox = manage (new HBox);
1537         hbox->pack_start (*vbox, false, false);
1538         options.pack_start (*hbox, false, false);
1539
1540         /* dummy entry for action combo so that it doesn't look odd if we
1541            come up with no tracks selected.
1542         */
1543
1544         str.clear ();
1545         str.push_back (importmode2string (mode_hint));
1546         set_popdown_strings (action_combo, str);
1547         action_combo.set_active_text (str.front());
1548         action_combo.set_sensitive (false);
1549
1550         l = manage (new Label);
1551         l->set_markup (_("<b>Insert at</b>"));
1552
1553         vbox = manage (new VBox);
1554         vbox->set_border_width (12);
1555         vbox->set_spacing (6);
1556         vbox->pack_start (*l, false, false);
1557         vbox->pack_start (where_combo, false, false);
1558         hbox = manage (new HBox);
1559         hbox->pack_start (*vbox, false, false);
1560         options.pack_start (*hbox, false, false);
1561
1562
1563         l = manage (new Label);
1564         l->set_markup (_("<b>Mapping</b>"));
1565
1566         vbox = manage (new VBox);
1567         vbox->set_border_width (12);
1568         vbox->set_spacing (6);
1569         vbox->pack_start (*l, false, false);
1570         vbox->pack_start (channel_combo, false, false);
1571         hbox = manage (new HBox);
1572         hbox->pack_start (*vbox, false, false);
1573         options.pack_start (*hbox, false, false);
1574
1575         str.clear ();
1576         str.push_back (_("one track per file"));
1577         set_popdown_strings (channel_combo, str);
1578         channel_combo.set_active_text (str.front());
1579         channel_combo.set_sensitive (false);
1580
1581         l = manage (new Label);
1582         l->set_markup (_("<b>Conversion quality</b>"));
1583
1584         vbox = manage (new VBox);
1585         vbox->set_border_width (12);
1586         vbox->set_spacing (6);
1587         vbox->pack_start (*l, false, false);
1588         vbox->pack_start (src_combo, false, false);
1589         hbox = manage (new HBox);
1590         hbox->pack_start (*vbox, false, false);
1591         options.pack_start (*hbox, false, false);
1592
1593         str.clear ();
1594         str.push_back (_("Best"));
1595         str.push_back (_("Good"));
1596         str.push_back (_("Quick"));
1597         str.push_back (_("Fast"));
1598         str.push_back (_("Fastest"));
1599
1600         set_popdown_strings (src_combo, str);
1601         src_combo.set_active_text (str.front());
1602         src_combo.set_sensitive (false);
1603
1604         reset_options ();
1605
1606         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1607         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1608
1609         copy_files_btn.set_active (true);
1610
1611         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1612
1613         if (copy_label) {
1614                 copy_label->set_size_request (175, -1);
1615                 copy_label->set_line_wrap (true);
1616         }
1617
1618         block_four.pack_start (copy_files_btn, false, false);
1619
1620         options.pack_start (block_four, false, false);
1621
1622         vpacker.pack_start (options, false, false);
1623
1624         /* setup disposition map */
1625
1626         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1627         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1628         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1629         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1630
1631         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1632         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1633         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1634         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1635
1636         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1637
1638         /* set size requests for a couple of combos to allow them to display the longest text
1639            they will ever be asked to display.  This prevents them being resized when the user
1640            selects a file to import, which in turn prevents the size of the dialog from jumping
1641            around. */
1642
1643         vector<string> t;
1644         t.push_back (_("one track per file"));
1645         t.push_back (_("one track per channel"));
1646         t.push_back (_("sequence files"));
1647         t.push_back (_("all files in one region"));
1648         set_popdown_strings (channel_combo, t);
1649
1650         t.clear ();
1651         t.push_back (importmode2string (ImportAsTrack));
1652         t.push_back (importmode2string (ImportToTrack));
1653         t.push_back (importmode2string (ImportAsRegion));
1654         t.push_back (importmode2string (ImportAsTapeTrack));
1655         set_popdown_strings (action_combo, t);
1656 }
1657
1658 void
1659 SoundFileOmega::set_mode (ImportMode mode)
1660 {
1661         action_combo.set_active_text (importmode2string (mode));
1662 }
1663
1664 ImportMode
1665 SoundFileOmega::get_mode () const
1666 {
1667         return string2importmode (action_combo.get_active_text());
1668 }
1669
1670 void
1671 SoundFileOmega::on_hide ()
1672 {
1673         ArdourWindow::on_hide();
1674         if (_session) {
1675                 _session->cancel_audition();
1676         }
1677 }
1678
1679 ImportPosition
1680 SoundFileOmega::get_position() const
1681 {
1682         string str = where_combo.get_active_text();
1683
1684         if (str == _("file timestamp")) {
1685                 return ImportAtTimestamp;
1686         } else if (str == _("edit point")) {
1687                 return ImportAtEditPoint;
1688         } else if (str == _("playhead")) {
1689                 return ImportAtPlayhead;
1690         } else {
1691                 return ImportAtStart;
1692         }
1693 }
1694
1695 SrcQuality
1696 SoundFileOmega::get_src_quality() const
1697 {
1698         string str = src_combo.get_active_text();
1699
1700         if (str == _("Best")) {
1701                 return SrcBest;
1702         } else if (str == _("Good")) {
1703                 return SrcGood;
1704         } else if (str == _("Quick")) {
1705                 return SrcQuick;
1706         } else if (str == _("Fast")) {
1707                 return SrcFast;
1708         } else {
1709                 return SrcFastest;
1710         }
1711 }
1712
1713 ImportDisposition
1714 SoundFileOmega::get_channel_disposition () const
1715 {
1716         /* we use a map here because the channel combo can contain different strings
1717            depending on the state of the other combos. the map contains all possible strings
1718            and the ImportDisposition enum that corresponds to it.
1719         */
1720
1721         string str = channel_combo.get_active_text();
1722         DispositionMap::const_iterator x = disposition_map.find (str);
1723
1724         if (x == disposition_map.end()) {
1725                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1726                 /*NOTREACHED*/
1727         }
1728
1729         return x->second;
1730 }
1731
1732 void
1733 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1734 {
1735         selected_audio_track_cnt = selected_audio_tracks;
1736         selected_midi_track_cnt = selected_midi_tracks;
1737
1738         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1739                 chooser.set_filter (midi_filter);
1740         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1741                 chooser.set_filter (audio_filter);
1742         } else {
1743                 chooser.set_filter (audio_and_midi_filter);
1744         }
1745
1746         reset_options ();
1747 }
1748
1749 void
1750 SoundFileOmega::file_selection_changed ()
1751 {
1752         if (resetting_ourselves) {
1753                 return;
1754         }
1755
1756         if (!reset_options ()) {
1757                 set_action_sensitive (false);
1758         } else {
1759                 if (chooser.get_filenames().size() > 0) {
1760                         set_action_sensitive (true);
1761                 } else {
1762                         set_action_sensitive (false);
1763                 }
1764         }
1765 }
1766
1767 void
1768 SoundFileOmega::do_something (int action)
1769 {
1770         SoundFileBrowser::do_something (action);
1771
1772         if (action == RESPONSE_CANCEL) {
1773                 hide ();
1774                 return;
1775         }
1776
1777         /* lets do it */
1778         
1779         vector<string> paths = get_paths ();
1780         ImportPosition pos = get_position ();
1781         ImportMode mode = get_mode ();
1782         ImportDisposition chns = get_channel_disposition ();
1783         framepos_t where;
1784         
1785         switch (pos) {
1786         case ImportAtEditPoint:
1787                 where = PublicEditor::instance().get_preferred_edit_position ();
1788                 break;
1789         case ImportAtTimestamp:
1790                 where = -1;
1791                 break;
1792         case ImportAtPlayhead:
1793                 where = _session->transport_frame();
1794                 break;
1795         case ImportAtStart:
1796                 where = _session->current_start_frame();
1797                 break;
1798         }
1799         
1800         SrcQuality quality = get_src_quality();
1801         
1802         if (copy_files_btn.get_active()) {
1803                 PublicEditor::instance().do_import (paths, chns, mode, quality, where);
1804         } else {
1805                 PublicEditor::instance().do_embed (paths, chns, mode, where);
1806         }
1807         
1808         if (action == RESPONSE_OK) {
1809                 hide ();
1810         }
1811 }
1812