add copyright comments
[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(P_("found %1 match", "found %1 matches", matches), 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         if (matches == 0) {
1062                 freesound_progress_bar.set_text(_("Search returned no results."));
1063         } else {
1064                 freesound_progress_bar.set_text(string_compose(P_("Found %1 match", "Found %1 matches", matches), matches));
1065         }
1066         freesound_list_view.get_column(1)->set_sizing(TREE_VIEW_COLUMN_AUTOSIZE);
1067 #endif
1068 }
1069
1070 vector<string>
1071 SoundFileBrowser::get_paths ()
1072 {
1073         vector<string> results;
1074
1075         int n = notebook.get_current_page ();
1076
1077         if (n == 0) {
1078                 vector<string> filenames = chooser.get_filenames();
1079                 vector<string>::iterator i;
1080
1081                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1082                         struct stat buf;
1083                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1084                                 results.push_back (*i);
1085                         }
1086                 }
1087
1088         } else if (n==1){
1089
1090                 typedef TreeView::Selection::ListHandle_Path ListPath;
1091
1092                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1093                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1094                         TreeIter iter = found_list->get_iter(*i);
1095                         string str = (*iter)[found_list_columns.pathname];
1096
1097                         results.push_back (str);
1098                 }
1099         } else {
1100 #ifdef FREESOUND
1101                 typedef TreeView::Selection::ListHandle_Path ListPath;
1102
1103                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1104                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1105                         TreeIter iter = freesound_list->get_iter(*i);
1106                         string id  = (*iter)[freesound_list_columns.id];
1107                         string uri = (*iter)[freesound_list_columns.uri];
1108                         string ofn = (*iter)[freesound_list_columns.filename];
1109
1110                         GdkCursor *prev_cursor;
1111                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1112                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1113                         gdk_flush();
1114
1115                         string str = mootcher->getAudioFile(ofn, id, uri, this);
1116                         if (str != "") {
1117                                 results.push_back (str);
1118                         }
1119                         
1120                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1121
1122                 }
1123 #endif
1124         }
1125
1126         return results;
1127 }
1128
1129 void
1130 SoundFileOmega::reset_options_noret ()
1131 {
1132         if (!resetting_ourselves) {
1133                 (void) reset_options ();
1134         }
1135 }
1136
1137 bool
1138 SoundFileOmega::reset_options ()
1139 {
1140         vector<string> paths = get_paths ();
1141
1142         if (paths.empty()) {
1143
1144                 channel_combo.set_sensitive (false);
1145                 action_combo.set_sensitive (false);
1146                 where_combo.set_sensitive (false);
1147                 copy_files_btn.set_active (true);
1148                 copy_files_btn.set_sensitive (false);
1149
1150                 return false;
1151
1152         } else {
1153
1154                 channel_combo.set_sensitive (true);
1155                 action_combo.set_sensitive (true);
1156                 where_combo.set_sensitive (true);
1157
1158                 /* if we get through this function successfully, this may be
1159                    reset at the end, once we know if we can use hard links
1160                    to do embedding (or if we are importing a MIDI file).
1161                 */
1162
1163                 if (Config->get_only_copy_imported_files()) {
1164                         copy_files_btn.set_sensitive (false);
1165                 } else {
1166                         copy_files_btn.set_sensitive (false);
1167                 }
1168         }
1169
1170         bool same_size;
1171         bool src_needed;
1172         bool selection_includes_multichannel;
1173         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1174         ImportMode mode;
1175
1176         /* See if we are thinking about importing any MIDI files */
1177         vector<string>::iterator i = paths.begin ();
1178         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1179                 ++i;
1180         }
1181         bool const have_a_midi_file = (i != paths.end ());
1182
1183         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1184                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1185                 return false;
1186         }
1187
1188         string existing_choice;
1189         vector<string> action_strings;
1190
1191         resetting_ourselves = true;
1192
1193         if (chooser.get_filter() == &audio_filter) {
1194
1195                 /* AUDIO */
1196
1197                 if (selected_audio_track_cnt > 0) {
1198                         if (channel_combo.get_active_text().length()) {
1199                                 ImportDisposition id = get_channel_disposition();
1200                                 
1201                                 switch (id) {
1202                                 case Editing::ImportDistinctFiles:
1203                                         if (selected_audio_track_cnt == paths.size()) {
1204                                                 action_strings.push_back (importmode2string (ImportToTrack));
1205                                         }
1206                                         break;
1207                                         
1208                                 case Editing::ImportDistinctChannels:
1209                                         /* XXX it would be nice to allow channel-per-selected track
1210                                            but its too hard we don't want to deal with all the
1211                                            different per-file + per-track channel configurations.
1212                                         */
1213                                         break;
1214                                         
1215                                 default:
1216                                         action_strings.push_back (importmode2string (ImportToTrack));
1217                                         break;
1218                                 }
1219                         }
1220                 }
1221                 
1222         }  else {
1223
1224                 /* MIDI ONLY */
1225
1226                 if (selected_midi_track_cnt > 0) {
1227                         action_strings.push_back (importmode2string (ImportToTrack));
1228                 }
1229         }
1230
1231         action_strings.push_back (importmode2string (ImportAsTrack));
1232         action_strings.push_back (importmode2string (ImportAsRegion));
1233         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1234
1235         existing_choice = action_combo.get_active_text();
1236
1237         set_popdown_strings (action_combo, action_strings);
1238
1239         /* preserve any existing choice, if possible */
1240
1241
1242         if (existing_choice.length()) {
1243                 vector<string>::iterator x;
1244                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1245                         if (*x == existing_choice) {
1246                                 action_combo.set_active_text (existing_choice);
1247                                 break;
1248                         }
1249                 }
1250                 if (x == action_strings.end()) {
1251                         action_combo.set_active_text (action_strings.front());
1252                 }
1253         } else {
1254                 action_combo.set_active_text (action_strings.front());
1255         }
1256
1257         resetting_ourselves = false;
1258
1259         if ((mode = get_mode()) == ImportAsRegion) {
1260                 where_combo.set_sensitive (false);
1261         } else {
1262                 where_combo.set_sensitive (true);
1263         }
1264
1265         vector<string> channel_strings;
1266
1267         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1268                 channel_strings.push_back (_("one track per file"));
1269
1270                 if (selection_includes_multichannel) {
1271                         channel_strings.push_back (_("one track per channel"));
1272                 }
1273
1274                 if (paths.size() > 1) {
1275                         /* tape tracks are a single region per track, so we cannot
1276                            sequence multiple files.
1277                         */
1278                         if (mode != ImportAsTapeTrack) {
1279                                 channel_strings.push_back (_("sequence files"));
1280                         }
1281                         if (same_size) {
1282                                 channel_strings.push_back (_("all files in one track"));
1283                                 channel_strings.push_back (_("merge files"));
1284                         }
1285
1286                 }
1287
1288         } else {
1289                 channel_strings.push_back (_("one region per file"));
1290
1291                 if (selection_includes_multichannel) {
1292                         channel_strings.push_back (_("one region per channel"));
1293                 }
1294
1295                 if (paths.size() > 1) {
1296                         if (same_size) {
1297                                 channel_strings.push_back (_("all files in one region"));
1298                         }
1299                 }
1300         }
1301
1302         resetting_ourselves = true;
1303
1304         existing_choice = channel_combo.get_active_text();
1305
1306         set_popdown_strings (channel_combo, channel_strings);
1307
1308         /* preserve any existing choice, if possible */
1309
1310         if (existing_choice.length()) {
1311                 vector<string>::iterator x;
1312                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1313                         if (*x == existing_choice) {
1314                                 channel_combo.set_active_text (existing_choice);
1315                                 break;
1316                         }
1317                 }
1318                 if (x == channel_strings.end()) {
1319                         channel_combo.set_active_text (channel_strings.front());
1320                 }
1321         } else {
1322                 channel_combo.set_active_text (channel_strings.front());
1323         }
1324
1325         resetting_ourselves = false;
1326
1327         if (src_needed) {
1328                 src_combo.set_sensitive (true);
1329         } else {
1330                 src_combo.set_sensitive (false);
1331         }
1332
1333         /* We must copy MIDI files or those from Freesound */
1334         bool const must_copy = have_a_midi_file || notebook.get_current_page() == 2;
1335         
1336         if (Config->get_only_copy_imported_files()) {
1337
1338                 if (selection_can_be_embedded_with_links && !must_copy) {
1339                         copy_files_btn.set_sensitive (true);
1340                 } else {
1341                         if (must_copy) {
1342                                 copy_files_btn.set_active (true);
1343                         }
1344                         copy_files_btn.set_sensitive (false);
1345                 }
1346
1347         }  else {
1348
1349                 if (must_copy) {
1350                         copy_files_btn.set_active (true);
1351                 }                       
1352                 copy_files_btn.set_sensitive (!must_copy);
1353         }
1354
1355         return true;
1356 }
1357
1358
1359 bool
1360 SoundFileOmega::bad_file_message()
1361 {
1362         MessageDialog msg (*this,
1363                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1364                            true,
1365                            Gtk::MESSAGE_INFO,
1366                            Gtk::BUTTONS_OK);
1367         msg.run ();
1368         resetting_ourselves = true;
1369         chooser.unselect_uri (chooser.get_preview_uri());
1370         resetting_ourselves = false;
1371
1372         return false;
1373 }
1374
1375 bool
1376 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1377 {
1378         SoundFileInfo info;
1379         framepos_t sz = 0;
1380         bool err = false;
1381         string errmsg;
1382
1383         same_size = true;
1384         src_needed = false;
1385         multichannel = false;
1386
1387         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1388
1389                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1390                         if (info.channels > 1) {
1391                                 multichannel = true;
1392                         }
1393                         if (sz == 0) {
1394                                 sz = info.length;
1395                         } else {
1396                                 if (sz != info.length) {
1397                                         same_size = false;
1398                                 }
1399                         }
1400
1401                         if (info.samplerate != _session->frame_rate()) {
1402                                 src_needed = true;
1403                         }
1404
1405                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1406
1407                         Evoral::SMF reader;
1408                         reader.open(*i);
1409                         if (reader.num_tracks() > 1) {
1410                                 multichannel = true; // "channel" == track here...
1411                         }
1412
1413                         /* XXX we need err = true handling here in case
1414                            we can't check the file
1415                         */
1416
1417                 } else {
1418                         err = true;
1419                 }
1420         }
1421
1422         return err;
1423 }
1424
1425
1426 bool
1427 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1428 {
1429         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1430         bool ret = false;
1431
1432         if (mkdir (tmpdir.c_str(), 0744)) {
1433                 if (errno != EEXIST) {
1434                         return false;
1435                 }
1436         }
1437
1438         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1439
1440                 char tmpc[MAXPATHLEN+1];
1441
1442                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1443
1444                 /* can we link ? */
1445
1446                 if (link ((*i).c_str(), tmpc)) {
1447                         goto out;
1448                 }
1449
1450                 unlink (tmpc);
1451         }
1452
1453         ret = true;
1454
1455   out:
1456         rmdir (tmpdir.c_str());
1457         return ret;
1458 }
1459
1460 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1461         : SoundFileBrowser (title, s, false)
1462 {
1463         chooser.set_select_multiple (false);
1464         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1465         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1466 }
1467
1468 void
1469 SoundFileChooser::on_hide ()
1470 {
1471         ArdourWindow::on_hide();
1472         stop_metering ();
1473
1474         if (_session) {
1475                 _session->cancel_audition();
1476         }
1477 }
1478
1479 string
1480 SoundFileChooser::get_filename ()
1481 {
1482         vector<string> paths;
1483
1484         paths = get_paths ();
1485
1486         if (paths.empty()) {
1487                 return string ();
1488         }
1489
1490         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1491                 return string();
1492         }
1493
1494         return paths.front();
1495 }
1496
1497 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s, 
1498                                 uint32_t selected_audio_tracks, 
1499                                 uint32_t selected_midi_tracks, 
1500                                 bool persistent,
1501                                 Editing::ImportMode mode_hint)
1502         : SoundFileBrowser (title, s, persistent)
1503         , copy_files_btn ( _("Copy files to session"))
1504         , selected_audio_track_cnt (selected_audio_tracks)
1505         , selected_midi_track_cnt (selected_midi_tracks)
1506 {
1507         VBox* vbox;
1508         HBox* hbox;
1509         vector<string> str;
1510
1511         set_size_request (-1, 450);
1512
1513         block_two.set_border_width (12);
1514         block_three.set_border_width (12);
1515         block_four.set_border_width (12);
1516
1517         options.set_spacing (12);
1518
1519         str.clear ();
1520         str.push_back (_("file timestamp"));
1521         str.push_back (_("edit point"));
1522         str.push_back (_("playhead"));
1523         str.push_back (_("session start"));
1524         set_popdown_strings (where_combo, str);
1525         where_combo.set_active_text (str.front());
1526
1527         Label* l = manage (new Label);
1528         l->set_markup (_("<b>Add files as ...</b>"));
1529
1530         vbox = manage (new VBox);
1531         vbox->set_border_width (12);
1532         vbox->set_spacing (6);
1533         vbox->pack_start (*l, false, false);
1534         vbox->pack_start (action_combo, false, false);
1535         hbox = manage (new HBox);
1536         hbox->pack_start (*vbox, false, false);
1537         options.pack_start (*hbox, false, false);
1538
1539         /* dummy entry for action combo so that it doesn't look odd if we
1540            come up with no tracks selected.
1541         */
1542
1543         str.clear ();
1544         str.push_back (importmode2string (mode_hint));
1545         set_popdown_strings (action_combo, str);
1546         action_combo.set_active_text (str.front());
1547         action_combo.set_sensitive (false);
1548
1549         l = manage (new Label);
1550         l->set_markup (_("<b>Insert at</b>"));
1551
1552         vbox = manage (new VBox);
1553         vbox->set_border_width (12);
1554         vbox->set_spacing (6);
1555         vbox->pack_start (*l, false, false);
1556         vbox->pack_start (where_combo, false, false);
1557         hbox = manage (new HBox);
1558         hbox->pack_start (*vbox, false, false);
1559         options.pack_start (*hbox, false, false);
1560
1561
1562         l = manage (new Label);
1563         l->set_markup (_("<b>Mapping</b>"));
1564
1565         vbox = manage (new VBox);
1566         vbox->set_border_width (12);
1567         vbox->set_spacing (6);
1568         vbox->pack_start (*l, false, false);
1569         vbox->pack_start (channel_combo, false, false);
1570         hbox = manage (new HBox);
1571         hbox->pack_start (*vbox, false, false);
1572         options.pack_start (*hbox, false, false);
1573
1574         str.clear ();
1575         str.push_back (_("one track per file"));
1576         set_popdown_strings (channel_combo, str);
1577         channel_combo.set_active_text (str.front());
1578         channel_combo.set_sensitive (false);
1579
1580         l = manage (new Label);
1581         l->set_markup (_("<b>Conversion quality</b>"));
1582
1583         vbox = manage (new VBox);
1584         vbox->set_border_width (12);
1585         vbox->set_spacing (6);
1586         vbox->pack_start (*l, false, false);
1587         vbox->pack_start (src_combo, false, false);
1588         hbox = manage (new HBox);
1589         hbox->pack_start (*vbox, false, false);
1590         options.pack_start (*hbox, false, false);
1591
1592         str.clear ();
1593         str.push_back (_("Best"));
1594         str.push_back (_("Good"));
1595         str.push_back (_("Quick"));
1596         str.push_back (_("Fast"));
1597         str.push_back (_("Fastest"));
1598
1599         set_popdown_strings (src_combo, str);
1600         src_combo.set_active_text (str.front());
1601         src_combo.set_sensitive (false);
1602
1603         reset_options ();
1604
1605         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1606         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1607
1608         copy_files_btn.set_active (true);
1609
1610         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1611
1612         if (copy_label) {
1613                 copy_label->set_size_request (175, -1);
1614                 copy_label->set_line_wrap (true);
1615         }
1616
1617         block_four.pack_start (copy_files_btn, false, false);
1618
1619         options.pack_start (block_four, false, false);
1620
1621         vpacker.pack_start (options, false, false);
1622
1623         /* setup disposition map */
1624
1625         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1626         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1627         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1628         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1629
1630         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1631         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1632         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1633         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1634
1635         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1636
1637         /* set size requests for a couple of combos to allow them to display the longest text
1638            they will ever be asked to display.  This prevents them being resized when the user
1639            selects a file to import, which in turn prevents the size of the dialog from jumping
1640            around. */
1641
1642         vector<string> t;
1643         t.push_back (_("one track per file"));
1644         t.push_back (_("one track per channel"));
1645         t.push_back (_("sequence files"));
1646         t.push_back (_("all files in one region"));
1647         set_popdown_strings (channel_combo, t);
1648
1649         t.clear ();
1650         t.push_back (importmode2string (ImportAsTrack));
1651         t.push_back (importmode2string (ImportToTrack));
1652         t.push_back (importmode2string (ImportAsRegion));
1653         t.push_back (importmode2string (ImportAsTapeTrack));
1654         set_popdown_strings (action_combo, t);
1655 }
1656
1657 void
1658 SoundFileOmega::set_mode (ImportMode mode)
1659 {
1660         action_combo.set_active_text (importmode2string (mode));
1661 }
1662
1663 ImportMode
1664 SoundFileOmega::get_mode () const
1665 {
1666         return string2importmode (action_combo.get_active_text());
1667 }
1668
1669 void
1670 SoundFileOmega::on_hide ()
1671 {
1672         ArdourWindow::on_hide();
1673         if (_session) {
1674                 _session->cancel_audition();
1675         }
1676 }
1677
1678 ImportPosition
1679 SoundFileOmega::get_position() const
1680 {
1681         string str = where_combo.get_active_text();
1682
1683         if (str == _("file timestamp")) {
1684                 return ImportAtTimestamp;
1685         } else if (str == _("edit point")) {
1686                 return ImportAtEditPoint;
1687         } else if (str == _("playhead")) {
1688                 return ImportAtPlayhead;
1689         } else {
1690                 return ImportAtStart;
1691         }
1692 }
1693
1694 SrcQuality
1695 SoundFileOmega::get_src_quality() const
1696 {
1697         string str = where_combo.get_active_text();
1698
1699         if (str == _("Best")) {
1700                 return SrcBest;
1701         } else if (str == _("Good")) {
1702                 return SrcGood;
1703         } else if (str == _("Quick")) {
1704                 return SrcQuick;
1705         } else if (str == _("Fast")) {
1706                 return SrcFast;
1707         } else {
1708                 return SrcFastest;
1709         }
1710 }
1711
1712 ImportDisposition
1713 SoundFileOmega::get_channel_disposition () const
1714 {
1715         /* we use a map here because the channel combo can contain different strings
1716            depending on the state of the other combos. the map contains all possible strings
1717            and the ImportDisposition enum that corresponds to it.
1718         */
1719
1720         string str = channel_combo.get_active_text();
1721         DispositionMap::const_iterator x = disposition_map.find (str);
1722
1723         if (x == disposition_map.end()) {
1724                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1725                 /*NOTREACHED*/
1726         }
1727
1728         return x->second;
1729 }
1730
1731 void
1732 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1733 {
1734         selected_audio_track_cnt = selected_audio_tracks;
1735         selected_midi_track_cnt = selected_midi_tracks;
1736
1737         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1738                 chooser.set_filter (midi_filter);
1739         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1740                 chooser.set_filter (audio_filter);
1741         } else {
1742                 chooser.set_filter (audio_and_midi_filter);
1743         }
1744
1745         reset_options ();
1746 }
1747
1748 void
1749 SoundFileOmega::file_selection_changed ()
1750 {
1751         if (resetting_ourselves) {
1752                 return;
1753         }
1754
1755         if (!reset_options ()) {
1756                 set_action_sensitive (false);
1757         } else {
1758                 if (chooser.get_filenames().size() > 0) {
1759                         set_action_sensitive (true);
1760                 } else {
1761                         set_action_sensitive (false);
1762                 }
1763         }
1764 }
1765
1766 void
1767 SoundFileOmega::do_something (int action)
1768 {
1769         SoundFileBrowser::do_something (action);
1770
1771         if (action == RESPONSE_CANCEL) {
1772                 hide ();
1773                 return;
1774         }
1775
1776         /* lets do it */
1777         
1778         vector<string> paths = get_paths ();
1779         ImportPosition pos = get_position ();
1780         ImportMode mode = get_mode ();
1781         ImportDisposition chns = get_channel_disposition ();
1782         framepos_t where;
1783         
1784         switch (pos) {
1785         case ImportAtEditPoint:
1786                 where = PublicEditor::instance().get_preferred_edit_position ();
1787                 break;
1788         case ImportAtTimestamp:
1789                 where = -1;
1790                 break;
1791         case ImportAtPlayhead:
1792                 where = _session->transport_frame();
1793                 break;
1794         case ImportAtStart:
1795                 where = _session->current_start_frame();
1796                 break;
1797         }
1798         
1799         SrcQuality quality = get_src_quality();
1800         
1801         if (copy_files_btn.get_active()) {
1802                 PublicEditor::instance().do_import (paths, chns, mode, quality, where);
1803         } else {
1804                 PublicEditor::instance().do_embed (paths, chns, mode, where);
1805         }
1806         
1807         if (action == RESPONSE_OK) {
1808                 hide ();
1809         }
1810 }
1811