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