a508048fc2c8e34e7b0cd6d0f8f3a12953be7520
[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
711         meter_packer.set_border_width (12);
712         meter_packer.pack_start (*gm, false, true);
713         hpacker.pack_end (meter_packer, false, false);
714         meter_packer.show_all ();
715         start_metering ();
716 }
717
718 void
719 SoundFileBrowser::remove_gain_meter ()
720 {
721         if (gm) {
722                 meter_packer.remove (*gm);
723                 hpacker.remove (meter_packer);
724                 delete gm;
725                 gm = 0;
726         }
727 }
728
729 void
730 SoundFileBrowser::start_metering ()
731 {
732         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
733 }
734
735 void
736 SoundFileBrowser::stop_metering ()
737 {
738         metering_connection.disconnect();
739 }
740
741 void
742 SoundFileBrowser::meter ()
743 {
744         if (is_mapped () && _session && gm) {
745                 gm->update_meters ();
746         }
747 }
748
749 bool
750 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
751 {
752         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
753 }
754
755 bool
756 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
757 {
758         return SMFSource::safe_midi_file_extension (filter_info.filename);
759 }
760
761 bool
762 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
763 {
764         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
765 }
766
767 void
768 SoundFileBrowser::update_preview ()
769 {
770         if (preview.setup_labels (chooser.get_preview_filename())) {
771                 if (preview.autoplay()) {
772                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
773                 }
774         }
775 }
776
777 void
778 SoundFileBrowser::found_list_view_selected ()
779 {
780         if (!reset_options ()) {
781                 set_action_sensitive (false);
782         } else {
783                 string file;
784
785                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
786
787                 if (!rows.empty()) {
788                         TreeIter iter = found_list->get_iter(*rows.begin());
789                         file = (*iter)[found_list_columns.pathname];
790                         chooser.set_filename (file);
791                         set_action_sensitive (true);
792                 } else {
793                         set_action_sensitive (false);
794                 }
795
796                 preview.setup_labels (file);
797         }
798 }
799
800 void
801 SoundFileBrowser::freesound_list_view_selected ()
802 {
803         freesound_download_cancel = false;
804
805 #ifdef FREESOUND
806         if (!reset_options ()) {
807                 set_action_sensitive (false);
808         } else {
809
810                 string file;
811
812                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
813
814                 if (!rows.empty()) {
815                         TreeIter iter = freesound_list->get_iter(*rows.begin());
816
817                         string id  = (*iter)[freesound_list_columns.id];
818                         string uri = (*iter)[freesound_list_columns.uri];
819                         string ofn = (*iter)[freesound_list_columns.filename];
820
821                         // download the sound file                      
822                         GdkCursor *prev_cursor;
823                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
824                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
825                         gdk_flush();
826
827                         file = mootcher->getAudioFile(ofn, id, uri, this);
828
829                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
830
831                         if (file != "") {
832                                 chooser.set_filename (file);
833                                 set_action_sensitive (true);
834                         }
835                 } else {
836                         set_action_sensitive (false);
837                 }
838
839                 freesound_progress_bar.set_text(
840                                 string_compose(_("found %1 matche(s)"), matches));
841
842                 preview.setup_labels (file);
843         }
844 #endif
845 }
846
847 void
848 SoundFileBrowser::found_search_clicked ()
849 {
850         string tag_string = found_entry.get_text ();
851
852         vector<string> tags;
853
854         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
855                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
856                 return;
857         }
858
859         vector<string> results;
860         Library->search_members_and (results, tags);
861
862         found_list->clear();
863         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
864                 TreeModel::iterator new_row = found_list->append();
865                 TreeModel::Row row = *new_row;
866                 string path = Glib::filename_from_uri (string ("file:") + *i);
867                 row[found_list_columns.pathname] = path;
868         }
869 }
870
871 void
872 SoundFileBrowser::freesound_search_clicked ()
873 {
874         freesound_search_cancel = false;
875         freesound_search();
876 }
877
878 void
879 SoundFileBrowser::freesound_stop_clicked ()
880 {
881         freesound_download_cancel = true;
882         freesound_search_cancel = true;
883 }
884
885
886 void
887 SoundFileBrowser::freesound_search()
888 {
889 #ifdef FREESOUND
890         freesound_list->clear();
891         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_GROW_ONLY);
892         matches = 0;
893
894         string search_string = freesound_entry.get_text ();
895         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
896
897         GdkCursor *prev_cursor;
898         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
899         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
900         freesound_progress_bar.set_fraction(0.0);
901         gdk_flush();
902
903         int freesound_n_pages = 1;
904         for (int page = 1; page <= 99 && page <= freesound_n_pages; page++ ) {
905                 
906                 std::string prog;
907                 if (freesound_n_pages > 1) {
908                         freesound_progress_bar.set_fraction(page/(float)freesound_n_pages);
909                         prog = string_compose (_("Searching Page %1 of %2, click Stop to cancel"), page, freesound_n_pages);
910                 } else {
911                         prog = _("Searching, click Stop to cancel");
912                 }
913                 freesound_progress_bar.set_text(prog);
914                 while (Glib::MainContext::get_default()->iteration (false)) {
915                         /* do nothing */
916                 }
917
918                 std::string theString = mootcher->searchText(
919                         search_string, 
920                         page,
921 #ifdef GTKOSX
922                         "", // OSX eats anything incl mp3
923 #else
924                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
925 #endif
926                         sort_method
927                 );
928
929                 XMLTree doc;
930                 doc.read_buffer( theString );
931                 XMLNode *root = doc.root();
932
933                 if (!root) {
934                         error << "no root XML node!" << endmsg;
935                         break;
936                 }
937
938                 if ( strcmp(root->name().c_str(), "response") != 0) {
939                         error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
940                         break;
941                 }
942
943                 //find out how many pages are available to search
944                 XMLNode *res = root->child("num_pages");
945                 if (res) {
946                         string result = res->child("text")->content();
947                         freesound_n_pages = atoi(result.c_str());
948                 }
949
950                 XMLNode *sounds_root = root->child("sounds");
951                 
952                 if (!sounds_root) {
953                         error << "no child node \"sounds\" found!" << endmsg;
954                         break;
955                 }
956                 
957                 XMLNodeList sounds = sounds_root->children();
958                 if (sounds.size() == 0) {
959                         /* nothing found */
960                         break;
961                 }
962
963                 XMLNodeConstIterator niter;
964                 XMLNode *node;
965                 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
966                         node = *niter;
967                         if( strcmp( node->name().c_str(), "resource") != 0 ){
968                                 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
969                                 freesound_search_cancel = true;
970                                 break;
971                         }
972
973                         // node->dump(cerr, "node:");
974                         
975                         XMLNode *id_node  = node->child ("id");
976                         XMLNode *uri_node = node->child ("serve");
977                         XMLNode *ofn_node = node->child ("original_filename");
978                         XMLNode *dur_node = node->child ("duration");
979                         XMLNode *siz_node = node->child ("filesize");
980                         XMLNode *srt_node = node->child ("samplerate");
981                         XMLNode *lic_node = node->child ("license");
982
983                         if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
984                                 
985                                 std::string  id =  id_node->child("text")->content();
986                                 std::string uri = uri_node->child("text")->content();
987                                 std::string ofn = ofn_node->child("text")->content();
988                                 std::string dur = dur_node->child("text")->content();
989                                 std::string siz = siz_node->child("text")->content();
990                                 std::string srt = srt_node->child("text")->content();
991                                 std::string lic = lic_node->child("text")->content();
992
993                                 std::string r;
994                                 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
995                                 
996                                 double duration_seconds = atof(dur.c_str());
997                                 double h, m, s;
998                                 char duration_hhmmss[16];
999                                 if (duration_seconds >= 99 * 60 * 60) {
1000                                         strcpy(duration_hhmmss, ">99h");
1001                                 } else {
1002                                         s = modf(duration_seconds/60, &m) * 60;
1003                                         m = modf(m/60, &h) * 60;
1004                                         sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1005                                                 h, m, s
1006                                         );
1007                                 }
1008
1009                                 double size_bytes = atof(siz.c_str());
1010                                 char bsize[32];
1011                                 if (size_bytes < 1000) {
1012                                         sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1013                                 } else if (size_bytes < 1000000 ) {
1014                                         sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1015                                 } else if (size_bytes < 10000000) {
1016                                         sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1017                                 } else if (size_bytes < 1000000000) {
1018                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1019                                 } else {
1020                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1021                                 }
1022
1023                                 /* see http://www.freesound.org/help/faq/#licenses */
1024                                 char shortlicense[64];
1025                                 if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1026                                         sprintf(shortlicense, "CC-BY-NC");
1027                                 } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1028                                         sprintf(shortlicense, "CC-BY");
1029                                 } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1030                                         sprintf(shortlicense, "sampling+");
1031                                 } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1032                                         sprintf(shortlicense, "PD");
1033                                 } else {
1034                                         snprintf(shortlicense, 64, "%s", lic.c_str());
1035                                         shortlicense[63]= '\0';
1036                                 }
1037
1038                                 TreeModel::iterator new_row = freesound_list->append();
1039                                 TreeModel::Row row = *new_row;
1040                                 
1041                                 row[freesound_list_columns.id      ] = id;
1042                                 row[freesound_list_columns.uri     ] = uri;
1043                                 row[freesound_list_columns.filename] = ofn;
1044                                 row[freesound_list_columns.duration] = duration_hhmmss;
1045                                 row[freesound_list_columns.filesize] = bsize;
1046                                 row[freesound_list_columns.smplrate] = srt;
1047                                 row[freesound_list_columns.license ] = shortlicense;
1048                                 matches++;
1049
1050                         }
1051                 }
1052         
1053                 if (freesound_search_cancel)
1054                         break;
1055
1056         }  //page "for" loop
1057
1058         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1059
1060         freesound_progress_bar.set_fraction(0.0);
1061         switch (matches) {
1062                 case 0:
1063                         freesound_progress_bar.set_text(_("Search returned no results."));
1064                         break;
1065                 case 1:
1066                         freesound_progress_bar.set_text(_("Found one match."));
1067                         break;
1068                 default:
1069                         freesound_progress_bar.set_text(string_compose(_("Found %1 matche(s)"), matches));
1070         }
1071         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_AUTOSIZE);
1072 #endif
1073 }
1074
1075 vector<string>
1076 SoundFileBrowser::get_paths ()
1077 {
1078         vector<string> results;
1079
1080         int n = notebook.get_current_page ();
1081
1082         if (n == 0) {
1083                 vector<string> filenames = chooser.get_filenames();
1084                 vector<string>::iterator i;
1085
1086                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1087                         struct stat buf;
1088                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1089                                 results.push_back (*i);
1090                         }
1091                 }
1092
1093         } else if (n==1){
1094
1095                 typedef TreeView::Selection::ListHandle_Path ListPath;
1096
1097                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1098                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1099                         TreeIter iter = found_list->get_iter(*i);
1100                         string str = (*iter)[found_list_columns.pathname];
1101
1102                         results.push_back (str);
1103                 }
1104         } else {
1105 #ifdef FREESOUND
1106                 typedef TreeView::Selection::ListHandle_Path ListPath;
1107
1108                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1109                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1110                         TreeIter iter = freesound_list->get_iter(*i);
1111                         string id  = (*iter)[freesound_list_columns.id];
1112                         string uri = (*iter)[freesound_list_columns.uri];
1113                         string ofn = (*iter)[freesound_list_columns.filename];
1114
1115                         GdkCursor *prev_cursor;
1116                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1117                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1118                         gdk_flush();
1119
1120                         string str = mootcher->getAudioFile(ofn, id, uri, this);
1121                         if (str != "") {
1122                                 results.push_back (str);
1123                         }
1124                         
1125                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1126
1127                 }
1128 #endif
1129         }
1130
1131         return results;
1132 }
1133
1134 void
1135 SoundFileOmega::reset_options_noret ()
1136 {
1137         if (!resetting_ourselves) {
1138                 (void) reset_options ();
1139         }
1140 }
1141
1142 bool
1143 SoundFileOmega::reset_options ()
1144 {
1145         vector<string> paths = get_paths ();
1146
1147         if (paths.empty()) {
1148
1149                 channel_combo.set_sensitive (false);
1150                 action_combo.set_sensitive (false);
1151                 where_combo.set_sensitive (false);
1152                 copy_files_btn.set_active (true);
1153                 copy_files_btn.set_sensitive (false);
1154
1155                 return false;
1156
1157         } else {
1158
1159                 channel_combo.set_sensitive (true);
1160                 action_combo.set_sensitive (true);
1161                 where_combo.set_sensitive (true);
1162
1163                 /* if we get through this function successfully, this may be
1164                    reset at the end, once we know if we can use hard links
1165                    to do embedding (or if we are importing a MIDI file).
1166                 */
1167
1168                 if (Config->get_only_copy_imported_files()) {
1169                         copy_files_btn.set_sensitive (false);
1170                 } else {
1171                         copy_files_btn.set_sensitive (false);
1172                 }
1173         }
1174
1175         bool same_size;
1176         bool src_needed;
1177         bool selection_includes_multichannel;
1178         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1179         ImportMode mode;
1180
1181         /* See if we are thinking about importing any MIDI files */
1182         vector<string>::iterator i = paths.begin ();
1183         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1184                 ++i;
1185         }
1186         bool const have_a_midi_file = (i != paths.end ());
1187
1188         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1189                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1190                 return false;
1191         }
1192
1193         string existing_choice;
1194         vector<string> action_strings;
1195
1196         resetting_ourselves = true;
1197
1198         if (chooser.get_filter() == &audio_filter) {
1199
1200                 /* AUDIO */
1201
1202                 if (selected_audio_track_cnt > 0) {
1203                         if (channel_combo.get_active_text().length()) {
1204                                 ImportDisposition id = get_channel_disposition();
1205                                 
1206                                 switch (id) {
1207                                 case Editing::ImportDistinctFiles:
1208                                         if (selected_audio_track_cnt == paths.size()) {
1209                                                 action_strings.push_back (importmode2string (ImportToTrack));
1210                                         }
1211                                         break;
1212                                         
1213                                 case Editing::ImportDistinctChannels:
1214                                         /* XXX it would be nice to allow channel-per-selected track
1215                                            but its too hard we don't want to deal with all the
1216                                            different per-file + per-track channel configurations.
1217                                         */
1218                                         break;
1219                                         
1220                                 default:
1221                                         action_strings.push_back (importmode2string (ImportToTrack));
1222                                         break;
1223                                 }
1224                         }
1225                 }
1226                 
1227         }  else {
1228
1229                 /* MIDI ONLY */
1230
1231                 if (selected_midi_track_cnt > 0) {
1232                         action_strings.push_back (importmode2string (ImportToTrack));
1233                 }
1234         }
1235
1236         action_strings.push_back (importmode2string (ImportAsTrack));
1237         action_strings.push_back (importmode2string (ImportAsRegion));
1238         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1239
1240         existing_choice = action_combo.get_active_text();
1241
1242         set_popdown_strings (action_combo, action_strings);
1243
1244         /* preserve any existing choice, if possible */
1245
1246
1247         if (existing_choice.length()) {
1248                 vector<string>::iterator x;
1249                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1250                         if (*x == existing_choice) {
1251                                 action_combo.set_active_text (existing_choice);
1252                                 break;
1253                         }
1254                 }
1255                 if (x == action_strings.end()) {
1256                         action_combo.set_active_text (action_strings.front());
1257                 }
1258         } else {
1259                 action_combo.set_active_text (action_strings.front());
1260         }
1261
1262         resetting_ourselves = false;
1263
1264         if ((mode = get_mode()) == ImportAsRegion) {
1265                 where_combo.set_sensitive (false);
1266         } else {
1267                 where_combo.set_sensitive (true);
1268         }
1269
1270         vector<string> channel_strings;
1271
1272         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1273                 channel_strings.push_back (_("one track per file"));
1274
1275                 if (selection_includes_multichannel) {
1276                         channel_strings.push_back (_("one track per channel"));
1277                 }
1278
1279                 if (paths.size() > 1) {
1280                         /* tape tracks are a single region per track, so we cannot
1281                            sequence multiple files.
1282                         */
1283                         if (mode != ImportAsTapeTrack) {
1284                                 channel_strings.push_back (_("sequence files"));
1285                         }
1286                         if (same_size) {
1287                                 channel_strings.push_back (_("all files in one track"));
1288                                 channel_strings.push_back (_("merge files"));
1289                         }
1290
1291                 }
1292
1293         } else {
1294                 channel_strings.push_back (_("one region per file"));
1295
1296                 if (selection_includes_multichannel) {
1297                         channel_strings.push_back (_("one region per channel"));
1298                 }
1299
1300                 if (paths.size() > 1) {
1301                         if (same_size) {
1302                                 channel_strings.push_back (_("all files in one region"));
1303                         }
1304                 }
1305         }
1306
1307         resetting_ourselves = true;
1308
1309         existing_choice = channel_combo.get_active_text();
1310
1311         set_popdown_strings (channel_combo, channel_strings);
1312
1313         /* preserve any existing choice, if possible */
1314
1315         if (existing_choice.length()) {
1316                 vector<string>::iterator x;
1317                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1318                         if (*x == existing_choice) {
1319                                 channel_combo.set_active_text (existing_choice);
1320                                 break;
1321                         }
1322                 }
1323                 if (x == channel_strings.end()) {
1324                         channel_combo.set_active_text (channel_strings.front());
1325                 }
1326         } else {
1327                 channel_combo.set_active_text (channel_strings.front());
1328         }
1329
1330         resetting_ourselves = false;
1331
1332         if (src_needed) {
1333                 src_combo.set_sensitive (true);
1334         } else {
1335                 src_combo.set_sensitive (false);
1336         }
1337
1338         /* We must copy MIDI files or those from Freesound */
1339         bool const must_copy = have_a_midi_file || notebook.get_current_page() == 2;
1340         
1341         if (Config->get_only_copy_imported_files()) {
1342
1343                 if (selection_can_be_embedded_with_links && !must_copy) {
1344                         copy_files_btn.set_sensitive (true);
1345                 } else {
1346                         if (must_copy) {
1347                                 copy_files_btn.set_active (true);
1348                         }
1349                         copy_files_btn.set_sensitive (false);
1350                 }
1351
1352         }  else {
1353
1354                 if (must_copy) {
1355                         copy_files_btn.set_active (true);
1356                 }                       
1357                 copy_files_btn.set_sensitive (!must_copy);
1358         }
1359
1360         return true;
1361 }
1362
1363
1364 bool
1365 SoundFileOmega::bad_file_message()
1366 {
1367         MessageDialog msg (*this,
1368                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1369                            true,
1370                            Gtk::MESSAGE_INFO,
1371                            Gtk::BUTTONS_OK);
1372         msg.run ();
1373         resetting_ourselves = true;
1374         chooser.unselect_uri (chooser.get_preview_uri());
1375         resetting_ourselves = false;
1376
1377         return false;
1378 }
1379
1380 bool
1381 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1382 {
1383         SoundFileInfo info;
1384         framepos_t sz = 0;
1385         bool err = false;
1386         string errmsg;
1387
1388         same_size = true;
1389         src_needed = false;
1390         multichannel = false;
1391
1392         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1393
1394                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1395                         if (info.channels > 1) {
1396                                 multichannel = true;
1397                         }
1398                         if (sz == 0) {
1399                                 sz = info.length;
1400                         } else {
1401                                 if (sz != info.length) {
1402                                         same_size = false;
1403                                 }
1404                         }
1405
1406                         if (info.samplerate != _session->frame_rate()) {
1407                                 src_needed = true;
1408                         }
1409
1410                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1411
1412                         Evoral::SMF reader;
1413                         reader.open(*i);
1414                         if (reader.num_tracks() > 1) {
1415                                 multichannel = true; // "channel" == track here...
1416                         }
1417
1418                         /* XXX we need err = true handling here in case
1419                            we can't check the file
1420                         */
1421
1422                 } else {
1423                         err = true;
1424                 }
1425         }
1426
1427         return err;
1428 }
1429
1430
1431 bool
1432 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1433 {
1434         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1435         bool ret = false;
1436
1437         if (mkdir (tmpdir.c_str(), 0744)) {
1438                 if (errno != EEXIST) {
1439                         return false;
1440                 }
1441         }
1442
1443         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1444
1445                 char tmpc[MAXPATHLEN+1];
1446
1447                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1448
1449                 /* can we link ? */
1450
1451                 if (link ((*i).c_str(), tmpc)) {
1452                         goto out;
1453                 }
1454
1455                 unlink (tmpc);
1456         }
1457
1458         ret = true;
1459
1460   out:
1461         rmdir (tmpdir.c_str());
1462         return ret;
1463 }
1464
1465 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1466         : SoundFileBrowser (title, s, false)
1467 {
1468         chooser.set_select_multiple (false);
1469         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1470         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1471 }
1472
1473 void
1474 SoundFileChooser::on_hide ()
1475 {
1476         ArdourWindow::on_hide();
1477         stop_metering ();
1478
1479         if (_session) {
1480                 _session->cancel_audition();
1481         }
1482 }
1483
1484 string
1485 SoundFileChooser::get_filename ()
1486 {
1487         vector<string> paths;
1488
1489         paths = get_paths ();
1490
1491         if (paths.empty()) {
1492                 return string ();
1493         }
1494
1495         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1496                 return string();
1497         }
1498
1499         return paths.front();
1500 }
1501
1502 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1503                                 uint32_t selected_audio_tracks, 
1504                                 uint32_t selected_midi_tracks, 
1505                                 bool persistent,
1506                                 Editing::ImportMode mode_hint)
1507         : SoundFileBrowser (title, s, persistent)
1508         , copy_files_btn ( _("Copy files to session"))
1509         , selected_audio_track_cnt (selected_audio_tracks)
1510         , selected_midi_track_cnt (selected_midi_tracks)
1511 {
1512         VBox* vbox;
1513         HBox* hbox;
1514         vector<string> str;
1515
1516         set_size_request (-1, 450);
1517
1518         block_two.set_border_width (12);
1519         block_three.set_border_width (12);
1520         block_four.set_border_width (12);
1521
1522         options.set_spacing (12);
1523
1524         str.clear ();
1525         str.push_back (_("file timestamp"));
1526         str.push_back (_("edit point"));
1527         str.push_back (_("playhead"));
1528         str.push_back (_("session start"));
1529         set_popdown_strings (where_combo, str);
1530         where_combo.set_active_text (str.front());
1531
1532         Label* l = manage (new Label);
1533         l->set_markup (_("<b>Add files as ...</b>"));
1534
1535         vbox = manage (new VBox);
1536         vbox->set_border_width (12);
1537         vbox->set_spacing (6);
1538         vbox->pack_start (*l, false, false);
1539         vbox->pack_start (action_combo, false, false);
1540         hbox = manage (new HBox);
1541         hbox->pack_start (*vbox, false, false);
1542         options.pack_start (*hbox, false, false);
1543
1544         /* dummy entry for action combo so that it doesn't look odd if we
1545            come up with no tracks selected.
1546         */
1547
1548         str.clear ();
1549         str.push_back (importmode2string (mode_hint));
1550         set_popdown_strings (action_combo, str);
1551         action_combo.set_active_text (str.front());
1552         action_combo.set_sensitive (false);
1553
1554         l = manage (new Label);
1555         l->set_markup (_("<b>Insert at</b>"));
1556
1557         vbox = manage (new VBox);
1558         vbox->set_border_width (12);
1559         vbox->set_spacing (6);
1560         vbox->pack_start (*l, false, false);
1561         vbox->pack_start (where_combo, false, false);
1562         hbox = manage (new HBox);
1563         hbox->pack_start (*vbox, false, false);
1564         options.pack_start (*hbox, false, false);
1565
1566
1567         l = manage (new Label);
1568         l->set_markup (_("<b>Mapping</b>"));
1569
1570         vbox = manage (new VBox);
1571         vbox->set_border_width (12);
1572         vbox->set_spacing (6);
1573         vbox->pack_start (*l, false, false);
1574         vbox->pack_start (channel_combo, false, false);
1575         hbox = manage (new HBox);
1576         hbox->pack_start (*vbox, false, false);
1577         options.pack_start (*hbox, false, false);
1578
1579         str.clear ();
1580         str.push_back (_("one track per file"));
1581         set_popdown_strings (channel_combo, str);
1582         channel_combo.set_active_text (str.front());
1583         channel_combo.set_sensitive (false);
1584
1585         l = manage (new Label);
1586         l->set_markup (_("<b>Conversion quality</b>"));
1587
1588         vbox = manage (new VBox);
1589         vbox->set_border_width (12);
1590         vbox->set_spacing (6);
1591         vbox->pack_start (*l, false, false);
1592         vbox->pack_start (src_combo, false, false);
1593         hbox = manage (new HBox);
1594         hbox->pack_start (*vbox, false, false);
1595         options.pack_start (*hbox, false, false);
1596
1597         str.clear ();
1598         str.push_back (_("Best"));
1599         str.push_back (_("Good"));
1600         str.push_back (_("Quick"));
1601         str.push_back (_("Fast"));
1602         str.push_back (_("Fastest"));
1603
1604         set_popdown_strings (src_combo, str);
1605         src_combo.set_active_text (str.front());
1606         src_combo.set_sensitive (false);
1607
1608         reset_options ();
1609
1610         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1611         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1612
1613         copy_files_btn.set_active (true);
1614
1615         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1616
1617         if (copy_label) {
1618                 copy_label->set_size_request (175, -1);
1619                 copy_label->set_line_wrap (true);
1620         }
1621
1622         block_four.pack_start (copy_files_btn, false, false);
1623
1624         options.pack_start (block_four, false, false);
1625
1626         vpacker.pack_start (options, false, false);
1627
1628         /* setup disposition map */
1629
1630         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1631         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1632         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1633         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1634
1635         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1636         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1637         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1638         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1639
1640         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1641
1642         /* set size requests for a couple of combos to allow them to display the longest text
1643            they will ever be asked to display.  This prevents them being resized when the user
1644            selects a file to import, which in turn prevents the size of the dialog from jumping
1645            around. */
1646
1647         vector<string> t;
1648         t.push_back (_("one track per file"));
1649         t.push_back (_("one track per channel"));
1650         t.push_back (_("sequence files"));
1651         t.push_back (_("all files in one region"));
1652         set_popdown_strings (channel_combo, t);
1653
1654         t.clear ();
1655         t.push_back (importmode2string (ImportAsTrack));
1656         t.push_back (importmode2string (ImportToTrack));
1657         t.push_back (importmode2string (ImportAsRegion));
1658         t.push_back (importmode2string (ImportAsTapeTrack));
1659         set_popdown_strings (action_combo, t);
1660 }
1661
1662 void
1663 SoundFileOmega::set_mode (ImportMode mode)
1664 {
1665         action_combo.set_active_text (importmode2string (mode));
1666 }
1667
1668 ImportMode
1669 SoundFileOmega::get_mode () const
1670 {
1671         return string2importmode (action_combo.get_active_text());
1672 }
1673
1674 void
1675 SoundFileOmega::on_hide ()
1676 {
1677         ArdourWindow::on_hide();
1678         if (_session) {
1679                 _session->cancel_audition();
1680         }
1681 }
1682
1683 ImportPosition
1684 SoundFileOmega::get_position() const
1685 {
1686         string str = where_combo.get_active_text();
1687
1688         if (str == _("file timestamp")) {
1689                 return ImportAtTimestamp;
1690         } else if (str == _("edit point")) {
1691                 return ImportAtEditPoint;
1692         } else if (str == _("playhead")) {
1693                 return ImportAtPlayhead;
1694         } else {
1695                 return ImportAtStart;
1696         }
1697 }
1698
1699 SrcQuality
1700 SoundFileOmega::get_src_quality() const
1701 {
1702         string str = where_combo.get_active_text();
1703
1704         if (str == _("Best")) {
1705                 return SrcBest;
1706         } else if (str == _("Good")) {
1707                 return SrcGood;
1708         } else if (str == _("Quick")) {
1709                 return SrcQuick;
1710         } else if (str == _("Fast")) {
1711                 return SrcFast;
1712         } else {
1713                 return SrcFastest;
1714         }
1715 }
1716
1717 ImportDisposition
1718 SoundFileOmega::get_channel_disposition () const
1719 {
1720         /* we use a map here because the channel combo can contain different strings
1721            depending on the state of the other combos. the map contains all possible strings
1722            and the ImportDisposition enum that corresponds to it.
1723         */
1724
1725         string str = channel_combo.get_active_text();
1726         DispositionMap::const_iterator x = disposition_map.find (str);
1727
1728         if (x == disposition_map.end()) {
1729                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1730                 /*NOTREACHED*/
1731         }
1732
1733         return x->second;
1734 }
1735
1736 void
1737 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1738 {
1739         selected_audio_track_cnt = selected_audio_tracks;
1740         selected_midi_track_cnt = selected_midi_tracks;
1741
1742         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1743                 chooser.set_filter (midi_filter);
1744         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1745                 chooser.set_filter (audio_filter);
1746         } else {
1747                 chooser.set_filter (audio_and_midi_filter);
1748         }
1749
1750         reset_options ();
1751 }
1752
1753 void
1754 SoundFileOmega::file_selection_changed ()
1755 {
1756         if (resetting_ourselves) {
1757                 return;
1758         }
1759
1760         if (!reset_options ()) {
1761                 set_action_sensitive (false);
1762         } else {
1763                 if (chooser.get_filenames().size() > 0) {
1764                         set_action_sensitive (true);
1765                 } else {
1766                         set_action_sensitive (false);
1767                 }
1768         }
1769 }
1770
1771 void
1772 SoundFileOmega::do_something (int action)
1773 {
1774         SoundFileBrowser::do_something (action);
1775
1776         if (action == RESPONSE_CANCEL) {
1777                 hide ();
1778                 return;
1779         }
1780
1781         /* lets do it */
1782         
1783         vector<string> paths = get_paths ();
1784         ImportPosition pos = get_position ();
1785         ImportMode mode = get_mode ();
1786         ImportDisposition chns = get_channel_disposition ();
1787         framepos_t where;
1788         
1789         switch (pos) {
1790         case ImportAtEditPoint:
1791                 where = PublicEditor::instance().get_preferred_edit_position ();
1792                 break;
1793         case ImportAtTimestamp:
1794                 where = -1;
1795                 break;
1796         case ImportAtPlayhead:
1797                 where = _session->transport_frame();
1798                 break;
1799         case ImportAtStart:
1800                 where = _session->current_start_frame();
1801                 break;
1802         }
1803         
1804         SrcQuality quality = get_src_quality();
1805         
1806         if (copy_files_btn.get_active()) {
1807                 PublicEditor::instance().do_import (paths, chns, mode, quality, where);
1808         } else {
1809                 PublicEditor::instance().do_embed (paths, chns, mode, where);
1810         }
1811         
1812         if (action == RESPONSE_OK) {
1813                 hide ();
1814         }
1815 }
1816