freesound import - various small tweaks
[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 (3);
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.append_column(_("Size"), freesound_list_columns.filesize);
570                 freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
571                 freesound_list_view.get_column(0)->set_alignment(0.5);
572                 freesound_list_view.get_column(1)->set_expand(true);
573                 freesound_list_view.get_column(2)->set_alignment(0.5);
574                 freesound_list_view.get_column(3)->set_alignment(0.5);
575                 freesound_list_view.get_column(4)->set_alignment(0.5);
576
577                 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
578
579                 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
580                 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
581                 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
582                 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
583                 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
584                 notebook.append_page (*vbox, _("Search Freesound"));
585         }
586
587 #endif
588
589
590         notebook.set_size_request (500, -1);
591         notebook.signal_switch_page().connect (
592                 sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options))))
593                 );
594
595         set_session (s);
596
597         add_button (Stock::CANCEL, RESPONSE_CANCEL);
598         add_button (Stock::APPLY, RESPONSE_APPLY);
599         add_button (Stock::OK, RESPONSE_OK);
600
601 }
602
603 SoundFileBrowser::~SoundFileBrowser ()
604 {
605         persistent_folder = chooser.get_current_folder();
606 }
607
608
609 void
610 SoundFileBrowser::on_show ()
611 {
612         ArdourDialog::on_show ();
613         start_metering ();
614 }
615
616 void
617 SoundFileBrowser::clear_selection ()
618 {
619         chooser.unselect_all ();
620         found_list_view.get_selection()->unselect_all ();
621 }
622
623 void
624 SoundFileBrowser::chooser_file_activated ()
625 {
626         preview.audition ();
627 }
628
629 void
630 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
631 {
632         preview.audition ();
633 }
634
635 void
636 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
637 {
638         preview.audition ();
639 }
640
641 void
642 SoundFileBrowser::set_session (Session* s)
643 {
644         ArdourDialog::set_session (s);
645         preview.set_session (s);
646
647         if (_session) {
648                 add_gain_meter ();
649         } else {
650                 remove_gain_meter ();
651         }
652 }
653
654 void
655 SoundFileBrowser::add_gain_meter ()
656 {
657         delete gm;
658
659         gm = new GainMeter (_session, 250);
660
661         boost::shared_ptr<Route> r = _session->the_auditioner ();
662
663         gm->set_controls (r, r->shared_peak_meter(), r->amp());
664
665         meter_packer.set_border_width (12);
666         meter_packer.pack_start (*gm, false, true);
667         hpacker.pack_end (meter_packer, false, false);
668         meter_packer.show_all ();
669         start_metering ();
670 }
671
672 void
673 SoundFileBrowser::remove_gain_meter ()
674 {
675         if (gm) {
676                 meter_packer.remove (*gm);
677                 hpacker.remove (meter_packer);
678                 delete gm;
679                 gm = 0;
680         }
681 }
682
683 void
684 SoundFileBrowser::start_metering ()
685 {
686         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
687 }
688
689 void
690 SoundFileBrowser::stop_metering ()
691 {
692         metering_connection.disconnect();
693 }
694
695 void
696 SoundFileBrowser::meter ()
697 {
698         if (is_mapped () && _session && gm) {
699                 gm->update_meters ();
700         }
701 }
702
703 bool
704 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
705 {
706         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
707 }
708
709 bool
710 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
711 {
712         return SMFSource::safe_midi_file_extension (filter_info.filename);
713 }
714
715 bool
716 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
717 {
718         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
719 }
720
721 void
722 SoundFileBrowser::update_preview ()
723 {
724         if (preview.setup_labels (chooser.get_preview_filename())) {
725                 if (preview.autoplay()) {
726                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
727                 }
728         }
729 }
730
731 void
732 SoundFileBrowser::found_list_view_selected ()
733 {
734         if (!reset_options ()) {
735                 set_response_sensitive (RESPONSE_OK, false);
736         } else {
737                 string file;
738
739                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
740
741                 if (!rows.empty()) {
742                         TreeIter iter = found_list->get_iter(*rows.begin());
743                         file = (*iter)[found_list_columns.pathname];
744                         chooser.set_filename (file);
745                         set_response_sensitive (RESPONSE_OK, true);
746                 } else {
747                         set_response_sensitive (RESPONSE_OK, false);
748                 }
749
750                 preview.setup_labels (file);
751         }
752 }
753
754 void
755 SoundFileBrowser::freesound_list_view_selected ()
756 {
757         freesound_download_cancel = false;
758
759 #ifdef FREESOUND
760         if (!reset_options ()) {
761                 set_response_sensitive (RESPONSE_OK, false);
762         } else {
763
764                 string file;
765
766                 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
767
768                 if (!rows.empty()) {
769                         TreeIter iter = freesound_list->get_iter(*rows.begin());
770
771                         string id  = (*iter)[freesound_list_columns.id];
772                         string uri = (*iter)[freesound_list_columns.uri];
773                         string ofn = (*iter)[freesound_list_columns.filename];
774
775                         // download the sound file                      
776                         GdkCursor *prev_cursor;
777                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
778                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
779                         gdk_flush();
780
781                         file = mootcher->getAudioFile(ofn, id, uri, this);
782
783                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
784
785                         if (file != "") {
786                                 chooser.set_filename (file);
787                                 set_response_sensitive (RESPONSE_OK, true);
788                         }
789                 } else {
790                         set_response_sensitive (RESPONSE_OK, false);
791                 }
792
793                 preview.setup_labels (file);
794         }
795 #endif
796 }
797
798 void
799 SoundFileBrowser::found_search_clicked ()
800 {
801         string tag_string = found_entry.get_text ();
802
803         vector<string> tags;
804
805         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
806                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
807                 return;
808         }
809
810         vector<string> results;
811         Library->search_members_and (results, tags);
812
813         found_list->clear();
814         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
815                 TreeModel::iterator new_row = found_list->append();
816                 TreeModel::Row row = *new_row;
817                 string path = Glib::filename_from_uri (string ("file:") + *i);
818                 row[found_list_columns.pathname] = path;
819         }
820 }
821
822 void
823 SoundFileBrowser::freesound_search_clicked ()
824 {
825         freesound_search_cancel = false;
826         freesound_search();
827 }
828
829 void
830 SoundFileBrowser::freesound_stop_clicked ()
831 {
832         freesound_download_cancel = true;
833         freesound_search_cancel = true;
834 }
835
836
837 void
838 SoundFileBrowser::freesound_search()
839 {
840 #ifdef FREESOUND
841         freesound_list->clear();
842
843         string search_string = freesound_entry.get_text ();
844         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
845
846         GdkCursor *prev_cursor;
847         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
848         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
849         gdk_flush();
850         for (int page = 1; page <= 99; page++ ) {
851                 
852                 std::string prog;
853                 prog = string_compose (_("Page %1"), page);
854                 freesound_progress_bar.set_text(prog);
855                 while (Glib::MainContext::get_default()->iteration (false)) {
856                         /* do nothing */
857                 }
858
859                 std::string theString = mootcher->searchText(
860                         search_string, 
861                         page,
862 #ifdef GTKOSX
863                         "", // OSX eats anything incl mp3
864 #else
865                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
866 #endif
867                         sort_method
868                 );
869
870                 XMLTree doc;
871                 doc.read_buffer( theString );
872                 XMLNode *root = doc.root();
873
874                 if (!root) {
875                         error << "no root XML node!" << endmsg;
876                         break;
877                 }
878
879                 if ( strcmp(root->name().c_str(), "response") != 0) {
880                         error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
881                         break;
882                 }
883
884                 XMLNode *sounds_root = root->child("sounds");
885                 
886                 if (!sounds_root) {
887                         error << "no child node \"sounds\" found!" << endmsg;
888                         break;
889                 }
890                 
891                 XMLNodeList sounds = sounds_root->children();
892                 if (sounds.size() == 0) {
893                         /* nothing found */
894                         break;
895                 }
896
897                 XMLNodeConstIterator niter;
898                 XMLNode *node;
899                 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
900                         node = *niter;
901                         if( strcmp( node->name().c_str(), "resource") != 0 ){
902                                 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
903                                 freesound_search_cancel = true;
904                                 break;
905                         }
906
907                         // node->dump(cerr, "node:");
908                         
909                         XMLNode *id_node  = node->child ("id");
910                         XMLNode *uri_node = node->child ("serve");
911                         XMLNode *ofn_node = node->child ("original_filename");
912                         XMLNode *dur_node = node->child ("duration");
913                         XMLNode *siz_node = node->child ("filesize");
914                         XMLNode *srt_node = node->child ("samplerate");
915
916                         if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
917                                 
918                                 std::string  id =  id_node->child("text")->content();
919                                 std::string uri = uri_node->child("text")->content();
920                                 std::string ofn = ofn_node->child("text")->content();
921                                 std::string dur = dur_node->child("text")->content();
922                                 std::string siz = siz_node->child("text")->content();
923                                 std::string srt = srt_node->child("text")->content();
924
925                                 std::string r;
926                                 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
927                                 
928                                 double duration_seconds = atof(dur.c_str());
929                                 double h, m, s;
930                                 char duration_hhmmss[16];
931                                 if (duration_seconds >= 99 * 60 * 60) {
932                                         strcpy(duration_hhmmss, ">99h");
933                                 } else {
934                                         s = modf(duration_seconds/60, &m) * 60;
935                                         m = modf(m/60, &h) * 60;
936                                         sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
937                                                 h, m, s
938                                         );
939                                 }
940
941                                 double size_bytes = atof(siz.c_str());
942                                 char bsize[32];
943                                 if (size_bytes < 1000) {
944                                         sprintf(bsize, "%.0f %s", size_bytes, _("B"));
945                                 } else if (size_bytes < 1000000 ) {
946                                         sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
947                                 } else if (size_bytes < 10000000) {
948                                         sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
949                                 } else if (size_bytes < 1000000000) {
950                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
951                                 } else {
952                                         sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
953                                 }
954
955                                 TreeModel::iterator new_row = freesound_list->append();
956                                 TreeModel::Row row = *new_row;
957                                 
958                                 row[freesound_list_columns.id      ] = id;
959                                 row[freesound_list_columns.uri     ] = uri;
960                                 row[freesound_list_columns.filename] = ofn;
961                                 row[freesound_list_columns.duration] = duration_hhmmss;
962                                 row[freesound_list_columns.filesize] = bsize;
963                                 row[freesound_list_columns.smplrate] = srt;
964
965                         }
966                 }
967         
968                 if (freesound_search_cancel)
969                         break;
970
971         }  //page "for" loop
972
973         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
974
975         freesound_progress_bar.set_text("");
976
977 #endif
978 }
979
980 vector<string>
981 SoundFileBrowser::get_paths ()
982 {
983         vector<string> results;
984
985         int n = notebook.get_current_page ();
986
987         if (n == 0) {
988                 vector<string> filenames = chooser.get_filenames();
989                 vector<string>::iterator i;
990
991                 for (i = filenames.begin(); i != filenames.end(); ++i) {
992                         struct stat buf;
993                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
994                                 results.push_back (*i);
995                         }
996                 }
997
998         } else if (n==1){
999
1000                 typedef TreeView::Selection::ListHandle_Path ListPath;
1001
1002                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1003                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1004                         TreeIter iter = found_list->get_iter(*i);
1005                         string str = (*iter)[found_list_columns.pathname];
1006
1007                         results.push_back (str);
1008                 }
1009         } else {
1010 #ifdef FREESOUND
1011                 typedef TreeView::Selection::ListHandle_Path ListPath;
1012
1013                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1014                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1015                         TreeIter iter = freesound_list->get_iter(*i);
1016                         string id  = (*iter)[freesound_list_columns.id];
1017                         string uri = (*iter)[freesound_list_columns.uri];
1018                         string ofn = (*iter)[freesound_list_columns.filename];
1019
1020                         GdkCursor *prev_cursor;
1021                         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1022                         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1023                         gdk_flush();
1024
1025                         string str = mootcher->getAudioFile(ofn, id, uri, this);
1026                         if (str != "") {
1027                                 results.push_back (str);
1028                         }
1029                         
1030                         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1031
1032                 }
1033 #endif
1034         }
1035
1036         return results;
1037 }
1038
1039 void
1040 SoundFileOmega::reset_options_noret ()
1041 {
1042         if (!resetting_ourselves) {
1043                 (void) reset_options ();
1044         }
1045 }
1046
1047 bool
1048 SoundFileOmega::reset_options ()
1049 {
1050         vector<string> paths = get_paths ();
1051
1052         if (paths.empty()) {
1053
1054                 channel_combo.set_sensitive (false);
1055                 action_combo.set_sensitive (false);
1056                 where_combo.set_sensitive (false);
1057                 copy_files_btn.set_active (true);
1058                 copy_files_btn.set_sensitive (false);
1059
1060                 return false;
1061
1062         } else {
1063
1064                 channel_combo.set_sensitive (true);
1065                 action_combo.set_sensitive (true);
1066                 where_combo.set_sensitive (true);
1067
1068                 /* if we get through this function successfully, this may be
1069                    reset at the end, once we know if we can use hard links
1070                    to do embedding (or if we are importing a MIDI file).
1071                 */
1072
1073                 if (Config->get_only_copy_imported_files()) {
1074                         copy_files_btn.set_sensitive (false);
1075                 } else {
1076                         copy_files_btn.set_sensitive (false);
1077                 }
1078         }
1079
1080         bool same_size;
1081         bool src_needed;
1082         bool selection_includes_multichannel;
1083         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1084         ImportMode mode;
1085
1086         /* See if we are thinking about importing any MIDI files */
1087         vector<string>::iterator i = paths.begin ();
1088         while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1089                 ++i;
1090         }
1091         bool const have_a_midi_file = (i != paths.end ());
1092
1093         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1094                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1095                 return false;
1096         }
1097
1098         string existing_choice;
1099         vector<string> action_strings;
1100
1101         resetting_ourselves = true;
1102
1103         if (chooser.get_filter() == &audio_filter) {
1104
1105                 /* AUDIO */
1106
1107                 if (selected_audio_track_cnt > 0) {
1108                         if (channel_combo.get_active_text().length()) {
1109                                 ImportDisposition id = get_channel_disposition();
1110                                 
1111                                 switch (id) {
1112                                 case Editing::ImportDistinctFiles:
1113                                         if (selected_audio_track_cnt == paths.size()) {
1114                                                 action_strings.push_back (importmode2string (ImportToTrack));
1115                                         }
1116                                         break;
1117                                         
1118                                 case Editing::ImportDistinctChannels:
1119                                         /* XXX it would be nice to allow channel-per-selected track
1120                                            but its too hard we don't want to deal with all the
1121                                            different per-file + per-track channel configurations.
1122                                         */
1123                                         break;
1124                                         
1125                                 default:
1126                                         action_strings.push_back (importmode2string (ImportToTrack));
1127                                         break;
1128                                 }
1129                         }
1130                 }
1131                 
1132         }  else {
1133
1134                 /* MIDI ONLY */
1135
1136                 if (selected_midi_track_cnt > 0) {
1137                         action_strings.push_back (importmode2string (ImportToTrack));
1138                 }
1139         }
1140
1141         action_strings.push_back (importmode2string (ImportAsTrack));
1142         action_strings.push_back (importmode2string (ImportAsRegion));
1143         action_strings.push_back (importmode2string (ImportAsTapeTrack));
1144
1145         existing_choice = action_combo.get_active_text();
1146
1147         set_popdown_strings (action_combo, action_strings);
1148
1149         /* preserve any existing choice, if possible */
1150
1151
1152         if (existing_choice.length()) {
1153                 vector<string>::iterator x;
1154                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1155                         if (*x == existing_choice) {
1156                                 action_combo.set_active_text (existing_choice);
1157                                 break;
1158                         }
1159                 }
1160                 if (x == action_strings.end()) {
1161                         action_combo.set_active_text (action_strings.front());
1162                 }
1163         } else {
1164                 action_combo.set_active_text (action_strings.front());
1165         }
1166
1167         resetting_ourselves = false;
1168
1169         if ((mode = get_mode()) == ImportAsRegion) {
1170                 where_combo.set_sensitive (false);
1171         } else {
1172                 where_combo.set_sensitive (true);
1173         }
1174
1175         vector<string> channel_strings;
1176
1177         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1178                 channel_strings.push_back (_("one track per file"));
1179
1180                 if (selection_includes_multichannel) {
1181                         channel_strings.push_back (_("one track per channel"));
1182                 }
1183
1184                 if (paths.size() > 1) {
1185                         /* tape tracks are a single region per track, so we cannot
1186                            sequence multiple files.
1187                         */
1188                         if (mode != ImportAsTapeTrack) {
1189                                 channel_strings.push_back (_("sequence files"));
1190                         }
1191                         if (same_size) {
1192                                 channel_strings.push_back (_("all files in one track"));
1193                                 channel_strings.push_back (_("merge files"));
1194                         }
1195
1196                 }
1197
1198         } else {
1199                 channel_strings.push_back (_("one region per file"));
1200
1201                 if (selection_includes_multichannel) {
1202                         channel_strings.push_back (_("one region per channel"));
1203                 }
1204
1205                 if (paths.size() > 1) {
1206                         if (same_size) {
1207                                 channel_strings.push_back (_("all files in one region"));
1208                         }
1209                 }
1210         }
1211
1212         resetting_ourselves = true;
1213
1214         existing_choice = channel_combo.get_active_text();
1215
1216         set_popdown_strings (channel_combo, channel_strings);
1217
1218         /* preserve any existing choice, if possible */
1219
1220         if (existing_choice.length()) {
1221                 vector<string>::iterator x;
1222                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1223                         if (*x == existing_choice) {
1224                                 channel_combo.set_active_text (existing_choice);
1225                                 break;
1226                         }
1227                 }
1228                 if (x == channel_strings.end()) {
1229                         channel_combo.set_active_text (channel_strings.front());
1230                 }
1231         } else {
1232                 channel_combo.set_active_text (channel_strings.front());
1233         }
1234
1235         resetting_ourselves = false;
1236
1237         if (src_needed) {
1238                 src_combo.set_sensitive (true);
1239         } else {
1240                 src_combo.set_sensitive (false);
1241         }
1242
1243         /* We must copy MIDI files or those from Freesound */
1244         bool const must_copy = have_a_midi_file || notebook.get_current_page() == 2;
1245         
1246         if (Config->get_only_copy_imported_files()) {
1247
1248                 if (selection_can_be_embedded_with_links && !must_copy) {
1249                         copy_files_btn.set_sensitive (true);
1250                 } else {
1251                         if (must_copy) {
1252                                 copy_files_btn.set_active (true);
1253                         }
1254                         copy_files_btn.set_sensitive (false);
1255                 }
1256
1257         }  else {
1258
1259                 if (must_copy) {
1260                         copy_files_btn.set_active (true);
1261                 }                       
1262                 copy_files_btn.set_sensitive (!must_copy);
1263         }
1264
1265         return true;
1266 }
1267
1268
1269 bool
1270 SoundFileOmega::bad_file_message()
1271 {
1272         MessageDialog msg (*this,
1273                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1274                            true,
1275                            Gtk::MESSAGE_INFO,
1276                            Gtk::BUTTONS_OK);
1277         msg.run ();
1278         resetting_ourselves = true;
1279         chooser.unselect_uri (chooser.get_preview_uri());
1280         resetting_ourselves = false;
1281
1282         return false;
1283 }
1284
1285 bool
1286 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1287 {
1288         SoundFileInfo info;
1289         framepos_t sz = 0;
1290         bool err = false;
1291         string errmsg;
1292
1293         same_size = true;
1294         src_needed = false;
1295         multichannel = false;
1296
1297         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1298
1299                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1300                         if (info.channels > 1) {
1301                                 multichannel = true;
1302                         }
1303                         if (sz == 0) {
1304                                 sz = info.length;
1305                         } else {
1306                                 if (sz != info.length) {
1307                                         same_size = false;
1308                                 }
1309                         }
1310
1311                         if (info.samplerate != _session->frame_rate()) {
1312                                 src_needed = true;
1313                         }
1314
1315                 } else if (SMFSource::safe_midi_file_extension (*i)) {
1316
1317                         Evoral::SMF reader;
1318                         reader.open(*i);
1319                         if (reader.num_tracks() > 1) {
1320                                 multichannel = true; // "channel" == track here...
1321                         }
1322
1323                         /* XXX we need err = true handling here in case
1324                            we can't check the file
1325                         */
1326
1327                 } else {
1328                         err = true;
1329                 }
1330         }
1331
1332         return err;
1333 }
1334
1335
1336 bool
1337 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1338 {
1339         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1340         bool ret = false;
1341
1342         if (mkdir (tmpdir.c_str(), 0744)) {
1343                 if (errno != EEXIST) {
1344                         return false;
1345                 }
1346         }
1347
1348         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1349
1350                 char tmpc[MAXPATHLEN+1];
1351
1352                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1353
1354                 /* can we link ? */
1355
1356                 if (link ((*i).c_str(), tmpc)) {
1357                         goto out;
1358                 }
1359
1360                 unlink (tmpc);
1361         }
1362
1363         ret = true;
1364
1365   out:
1366         rmdir (tmpdir.c_str());
1367         return ret;
1368 }
1369
1370 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1371         : SoundFileBrowser (parent, title, s, false)
1372 {
1373         chooser.set_select_multiple (false);
1374         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1375         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1376 }
1377
1378 void
1379 SoundFileChooser::on_hide ()
1380 {
1381         ArdourDialog::on_hide();
1382         stop_metering ();
1383
1384         if (_session) {
1385                 _session->cancel_audition();
1386         }
1387 }
1388
1389 string
1390 SoundFileChooser::get_filename ()
1391 {
1392         vector<string> paths;
1393
1394         paths = get_paths ();
1395
1396         if (paths.empty()) {
1397                 return string ();
1398         }
1399
1400         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1401                 return string();
1402         }
1403
1404         return paths.front();
1405 }
1406
1407 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, 
1408                                 uint32_t selected_audio_tracks, 
1409                                 uint32_t selected_midi_tracks, 
1410                                 bool persistent,
1411                                 Editing::ImportMode mode_hint)
1412         : SoundFileBrowser (parent, title, s, persistent)
1413         , copy_files_btn ( _("Copy files to session"))
1414         , selected_audio_track_cnt (selected_audio_tracks)
1415         , selected_midi_track_cnt (selected_midi_tracks)
1416 {
1417         VBox* vbox;
1418         HBox* hbox;
1419         vector<string> str;
1420
1421         set_size_request (-1, 450);
1422
1423         block_two.set_border_width (12);
1424         block_three.set_border_width (12);
1425         block_four.set_border_width (12);
1426
1427         options.set_spacing (12);
1428
1429         str.clear ();
1430         str.push_back (_("file timestamp"));
1431         str.push_back (_("edit point"));
1432         str.push_back (_("playhead"));
1433         str.push_back (_("session start"));
1434         set_popdown_strings (where_combo, str);
1435         where_combo.set_active_text (str.front());
1436
1437         Label* l = manage (new Label);
1438         l->set_markup (_("<b>Add files as ...</b>"));
1439
1440         vbox = manage (new VBox);
1441         vbox->set_border_width (12);
1442         vbox->set_spacing (6);
1443         vbox->pack_start (*l, false, false);
1444         vbox->pack_start (action_combo, false, false);
1445         hbox = manage (new HBox);
1446         hbox->pack_start (*vbox, false, false);
1447         options.pack_start (*hbox, false, false);
1448
1449         /* dummy entry for action combo so that it doesn't look odd if we
1450            come up with no tracks selected.
1451         */
1452
1453         str.clear ();
1454         str.push_back (importmode2string (mode_hint));
1455         set_popdown_strings (action_combo, str);
1456         action_combo.set_active_text (str.front());
1457         action_combo.set_sensitive (false);
1458
1459         l = manage (new Label);
1460         l->set_markup (_("<b>Insert at</b>"));
1461
1462         vbox = manage (new VBox);
1463         vbox->set_border_width (12);
1464         vbox->set_spacing (6);
1465         vbox->pack_start (*l, false, false);
1466         vbox->pack_start (where_combo, false, false);
1467         hbox = manage (new HBox);
1468         hbox->pack_start (*vbox, false, false);
1469         options.pack_start (*hbox, false, false);
1470
1471
1472         l = manage (new Label);
1473         l->set_markup (_("<b>Mapping</b>"));
1474
1475         vbox = manage (new VBox);
1476         vbox->set_border_width (12);
1477         vbox->set_spacing (6);
1478         vbox->pack_start (*l, false, false);
1479         vbox->pack_start (channel_combo, false, false);
1480         hbox = manage (new HBox);
1481         hbox->pack_start (*vbox, false, false);
1482         options.pack_start (*hbox, false, false);
1483
1484         str.clear ();
1485         str.push_back (_("one track per file"));
1486         set_popdown_strings (channel_combo, str);
1487         channel_combo.set_active_text (str.front());
1488         channel_combo.set_sensitive (false);
1489
1490         l = manage (new Label);
1491         l->set_markup (_("<b>Conversion quality</b>"));
1492
1493         vbox = manage (new VBox);
1494         vbox->set_border_width (12);
1495         vbox->set_spacing (6);
1496         vbox->pack_start (*l, false, false);
1497         vbox->pack_start (src_combo, false, false);
1498         hbox = manage (new HBox);
1499         hbox->pack_start (*vbox, false, false);
1500         options.pack_start (*hbox, false, false);
1501
1502         str.clear ();
1503         str.push_back (_("Best"));
1504         str.push_back (_("Good"));
1505         str.push_back (_("Quick"));
1506         str.push_back (_("Fast"));
1507         str.push_back (_("Fastest"));
1508
1509         set_popdown_strings (src_combo, str);
1510         src_combo.set_active_text (str.front());
1511         src_combo.set_sensitive (false);
1512
1513         reset_options ();
1514
1515         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1516         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1517
1518         copy_files_btn.set_active (true);
1519
1520         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1521
1522         if (copy_label) {
1523                 copy_label->set_size_request (175, -1);
1524                 copy_label->set_line_wrap (true);
1525         }
1526
1527         block_four.pack_start (copy_files_btn, false, false);
1528
1529         options.pack_start (block_four, false, false);
1530
1531         get_vbox()->pack_start (options, false, false);
1532
1533         /* setup disposition map */
1534
1535         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1536         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1537         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1538         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1539
1540         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1541         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1542         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1543         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1544
1545         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1546
1547         /* set size requests for a couple of combos to allow them to display the longest text
1548            they will ever be asked to display.  This prevents them being resized when the user
1549            selects a file to import, which in turn prevents the size of the dialog from jumping
1550            around. */
1551
1552         vector<string> t;
1553         t.push_back (_("one track per file"));
1554         t.push_back (_("one track per channel"));
1555         t.push_back (_("sequence files"));
1556         t.push_back (_("all files in one region"));
1557         set_popdown_strings (channel_combo, t);
1558
1559         t.clear ();
1560         t.push_back (importmode2string (ImportAsTrack));
1561         t.push_back (importmode2string (ImportToTrack));
1562         t.push_back (importmode2string (ImportAsRegion));
1563         t.push_back (importmode2string (ImportAsTapeTrack));
1564         set_popdown_strings (action_combo, t);
1565 }
1566
1567 void
1568 SoundFileOmega::set_mode (ImportMode mode)
1569 {
1570         action_combo.set_active_text (importmode2string (mode));
1571 }
1572
1573 ImportMode
1574 SoundFileOmega::get_mode () const
1575 {
1576         return string2importmode (action_combo.get_active_text());
1577 }
1578
1579 void
1580 SoundFileOmega::on_hide ()
1581 {
1582         ArdourDialog::on_hide();
1583         if (_session) {
1584                 _session->cancel_audition();
1585         }
1586 }
1587
1588 ImportPosition
1589 SoundFileOmega::get_position() const
1590 {
1591         string str = where_combo.get_active_text();
1592
1593         if (str == _("file timestamp")) {
1594                 return ImportAtTimestamp;
1595         } else if (str == _("edit point")) {
1596                 return ImportAtEditPoint;
1597         } else if (str == _("playhead")) {
1598                 return ImportAtPlayhead;
1599         } else {
1600                 return ImportAtStart;
1601         }
1602 }
1603
1604 SrcQuality
1605 SoundFileOmega::get_src_quality() const
1606 {
1607         string str = where_combo.get_active_text();
1608
1609         if (str == _("Best")) {
1610                 return SrcBest;
1611         } else if (str == _("Good")) {
1612                 return SrcGood;
1613         } else if (str == _("Quick")) {
1614                 return SrcQuick;
1615         } else if (str == _("Fast")) {
1616                 return SrcFast;
1617         } else {
1618                 return SrcFastest;
1619         }
1620 }
1621
1622 ImportDisposition
1623 SoundFileOmega::get_channel_disposition () const
1624 {
1625         /* we use a map here because the channel combo can contain different strings
1626            depending on the state of the other combos. the map contains all possible strings
1627            and the ImportDisposition enum that corresponds to it.
1628         */
1629
1630         string str = channel_combo.get_active_text();
1631         DispositionMap::const_iterator x = disposition_map.find (str);
1632
1633         if (x == disposition_map.end()) {
1634                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1635                 /*NOTREACHED*/
1636         }
1637
1638         return x->second;
1639 }
1640
1641 void
1642 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1643 {
1644         selected_audio_track_cnt = selected_audio_tracks;
1645         selected_midi_track_cnt = selected_midi_tracks;
1646
1647         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1648                 chooser.set_filter (midi_filter);
1649         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1650                 chooser.set_filter (audio_filter);
1651         } else {
1652                 chooser.set_filter (audio_and_midi_filter);
1653         }
1654
1655         reset_options ();
1656 }
1657
1658 void
1659 SoundFileOmega::file_selection_changed ()
1660 {
1661         if (resetting_ourselves) {
1662                 return;
1663         }
1664
1665         if (!reset_options ()) {
1666                 set_response_sensitive (RESPONSE_OK, false);
1667         } else {
1668                 if (chooser.get_filenames().size() > 0) {
1669                         set_response_sensitive (RESPONSE_OK, true);
1670                 } else {
1671                         set_response_sensitive (RESPONSE_OK, false);
1672                 }
1673         }
1674 }
1675