2 Copyright (C) 2005-2006 Paul Davis
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.
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.
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.
26 #include <sys/param.h>
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
32 #include <pbd/convert.h>
33 #include <pbd/tokenizer.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/pthread_utils.h>
36 #include <pbd/xml++.h>
38 #include <gtkmm2ext/utils.h>
40 #include <ardour/audio_library.h>
41 #include <ardour/auditioner.h>
42 #include <ardour/audioregion.h>
43 #include <ardour/audiofilesource.h>
44 #include <ardour/region_factory.h>
45 #include <ardour/source_factory.h>
46 #include <ardour/profile.h>
48 #include "ardour_ui.h"
50 #include "gui_thread.h"
55 #include "gain_meter.h"
58 #include "sfdb_freesound_mootcher.h"
63 using namespace ARDOUR
;
67 using namespace Gtkmm2ext
;
68 using namespace Editing
;
72 ustring
SoundFileBrowser::persistent_folder
;
75 string2importmode (string str
)
77 if (str
== _("as new tracks")) {
79 } else if (str
== _("to selected tracks")) {
81 } else if (str
== _("to region list")) {
82 return ImportAsRegion
;
83 } else if (str
== _("as new tape tracks")) {
84 return ImportAsTapeTrack
;
87 warning
<< string_compose (_("programming error: unknown import mode string %1"), str
) << endmsg
;
93 importmode2string (ImportMode mode
)
97 return _("as new tracks");
99 return _("to selected tracks");
101 return _("to region list");
102 case ImportAsTapeTrack
:
103 return _("as new tape tracks");
106 return _("as new tracks");
109 SoundFileBox::SoundFileBox (bool persistent
)
112 length_clock ("sfboxLengthClock", !persistent
, "EditCursorClock", false, true, false),
113 timecode_clock ("sfboxTimecodeClock", !persistent
, "EditCursorClock", false, false, false),
115 autoplay_btn (_("Auto-play"))
121 set_name (X_("SoundFileBox"));
122 set_size_request (300, -1);
124 preview_label
.set_markup (_("<b>Soundfile Info</b>"));
126 border_frame
.set_label_widget (preview_label
);
127 border_frame
.add (main_box
);
129 pack_start (border_frame
, true, true);
130 set_border_width (6);
132 main_box
.set_border_width (6);
133 main_box
.set_spacing (12);
135 length
.set_text (_("Length:"));
136 timecode
.set_text (_("Timestamp:"));
137 format
.set_text (_("Format:"));
138 channels
.set_text (_("Channels:"));
139 samplerate
.set_text (_("Sample rate:"));
141 table
.set_col_spacings (6);
142 table
.set_homogeneous (false);
143 table
.set_row_spacings (6);
145 table
.attach (channels
, 0, 1, 0, 1, FILL
|EXPAND
, (AttachOptions
) 0);
146 table
.attach (samplerate
, 0, 1, 1, 2, FILL
|EXPAND
, (AttachOptions
) 0);
147 table
.attach (format
, 0, 1, 2, 4, FILL
|EXPAND
, (AttachOptions
) 0);
148 table
.attach (length
, 0, 1, 4, 5, FILL
|EXPAND
, (AttachOptions
) 0);
149 table
.attach (timecode
, 0, 1, 5, 6, FILL
|EXPAND
, (AttachOptions
) 0);
151 table
.attach (channels_value
, 1, 2, 0, 1, FILL
, (AttachOptions
) 0);
152 table
.attach (samplerate_value
, 1, 2, 1, 2, FILL
, (AttachOptions
) 0);
153 table
.attach (format_text
, 1, 2, 2, 4, FILL
, AttachOptions (0));
154 table
.attach (length_clock
, 1, 2, 4, 5, FILL
, (AttachOptions
) 0);
155 table
.attach (timecode_clock
, 1, 2, 5, 6, FILL
, (AttachOptions
) 0);
157 length_clock
.set_mode (ARDOUR_UI::instance()->secondary_clock
.mode());
158 timecode_clock
.set_mode (AudioClock::SMPTE
);
160 hbox
= manage (new HBox
);
161 hbox
->pack_start (table
, false, false);
162 main_box
.pack_start (*hbox
, false, false);
164 tags_entry
.set_editable (true);
165 tags_entry
.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left
));
166 hbox
= manage (new HBox
);
167 hbox
->pack_start (tags_entry
, true, true);
169 vbox
= manage (new VBox
);
171 Label
* label
= manage (new Label (_("Tags:")));
172 label
->set_alignment (0.0f
, 0.5f
);
173 vbox
->set_spacing (6);
174 vbox
->pack_start(*label
, false, false);
175 vbox
->pack_start(*hbox
, true, true);
177 main_box
.pack_start(*vbox
, true, true);
178 main_box
.pack_start(bottom_box
, false, false);
180 play_btn
.set_image (*(manage (new Image (Stock::MEDIA_PLAY
, ICON_SIZE_BUTTON
))));
181 play_btn
.set_label (_("Play (double click)"));
183 stop_btn
.set_image (*(manage (new Image (Stock::MEDIA_STOP
, ICON_SIZE_BUTTON
))));
184 stop_btn
.set_label (_("Stop"));
186 bottom_box
.set_homogeneous (false);
187 bottom_box
.set_spacing (6);
188 bottom_box
.pack_start(play_btn
, true, true);
189 bottom_box
.pack_start(stop_btn
, true, true);
190 bottom_box
.pack_start(autoplay_btn
, false, false);
192 play_btn
.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition
));
193 stop_btn
.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition
));
195 length
.set_alignment (0.0f
, 0.5f
);
196 format
.set_alignment (0.0f
, 0.5f
);
197 channels
.set_alignment (0.0f
, 0.5f
);
198 samplerate
.set_alignment (0.0f
, 0.5f
);
199 timecode
.set_alignment (0.0f
, 0.5f
);
201 channels_value
.set_alignment (0.0f
, 0.5f
);
202 samplerate_value
.set_alignment (0.0f
, 0.5f
);
206 SoundFileBox::set_session(Session
* s
)
211 play_btn
.set_sensitive (false);
212 stop_btn
.set_sensitive (false);
216 length_clock
.set_session (s
);
217 timecode_clock
.set_session (s
);
221 SoundFileBox::setup_labels (const ustring
& filename
)
224 // save existing tags
232 if(!AudioFileSource::get_soundfile_info (filename
, sf_info
, error_msg
)) {
234 preview_label
.set_markup (_("<b>Soundfile Info</b>"));
235 format_text
.set_text (_("n/a"));
236 channels_value
.set_text (_("n/a"));
237 samplerate_value
.set_text (_("n/a"));
238 tags_entry
.get_buffer()->set_text ("");
240 length_clock
.set (0);
241 timecode_clock
.set (0);
243 tags_entry
.set_sensitive (false);
244 play_btn
.set_sensitive (false);
249 preview_label
.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename
)));
250 format_text
.set_text (sf_info
.format_name
);
251 channels_value
.set_text (to_string (sf_info
.channels
, std::dec
));
253 if (_session
&& sf_info
.samplerate
!= _session
->frame_rate()) {
254 samplerate
.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
255 samplerate_value
.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info
.samplerate
));
256 samplerate_value
.set_name ("NewSessionSR1Label");
257 samplerate
.set_name ("NewSessionSR1Label");
259 samplerate
.set_text (_("Sample rate:"));
260 samplerate_value
.set_text (string_compose (X_("%1 Hz"), sf_info
.samplerate
));
261 samplerate_value
.set_name ("NewSessionSR2Label");
262 samplerate
.set_name ("NewSessionSR2Label");
265 double src_coef
= (double) _session
->nominal_frame_rate() / sf_info
.samplerate
;
267 length_clock
.set (sf_info
.length
* src_coef
+ 0.5, true);
268 timecode_clock
.set (sf_info
.timecode
* src_coef
+ 0.5, true);
270 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
272 vector
<string
> tags
= Library
->get_tags (string ("//") + filename
);
274 stringstream tag_string
;
275 for (vector
<string
>::iterator i
= tags
.begin(); i
!= tags
.end(); ++i
) {
276 if (i
!= tags
.begin()) {
281 tags_entry
.get_buffer()->set_text (tag_string
.str());
283 tags_entry
.set_sensitive (true);
285 play_btn
.set_sensitive (true);
292 SoundFileBox::autoplay() const
294 return autoplay_btn
.get_active();
298 SoundFileBox::audition_oneshot()
305 SoundFileBox::audition ()
311 _session
->cancel_audition();
313 if (!Glib::file_test (path
, Glib::FILE_TEST_EXISTS
)) {
314 warning
<< string_compose(_("Could not read file: %1 (%2)."), path
, strerror(errno
)) << endmsg
;
318 boost::shared_ptr
<Region
> r
;
320 boost::shared_ptr
<AudioFileSource
> afs
;
321 bool old_sbp
= AudioSource::get_build_peakfiles ();
323 /* don't even think of building peakfiles for these files */
325 AudioSource::set_build_peakfiles (false);
327 for (int n
= 0; n
< sf_info
.channels
; ++n
) {
329 afs
= boost::dynamic_pointer_cast
<AudioFileSource
> (SourceFactory::createReadable (*_session
, path
, n
, AudioFileSource::Flag (0), false));
331 srclist
.push_back(afs
);
333 } catch (failed_constructor
& err
) {
334 error
<< _("Could not access soundfile: ") << path
<< endmsg
;
335 AudioSource::set_build_peakfiles (old_sbp
);
340 AudioSource::set_build_peakfiles (old_sbp
);
342 if (srclist
.empty()) {
346 afs
= boost::dynamic_pointer_cast
<AudioFileSource
> (srclist
[0]);
347 string rname
= region_name_from_path (afs
->path(), false);
348 r
= boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (srclist
, 0, srclist
[0]->length(), rname
, 0, Region::DefaultFlags
, false));
350 _session
->audition_region(r
);
354 SoundFileBox::stop_audition ()
357 _session
->cancel_audition();
362 SoundFileBox::tags_entry_left (GdkEventFocus
*ev
)
369 SoundFileBox::tags_changed ()
371 string tag_string
= tags_entry
.get_buffer()->get_text ();
373 if (tag_string
.empty()) {
379 if (!PBD::tokenize (tag_string
, string(",\n"), std::back_inserter (tags
), true)) {
380 warning
<< _("SoundFileBox: Could not tokenize string: ") << tag_string
<< endmsg
;
388 SoundFileBox::save_tags (const vector
<string
>& tags
)
390 Library
->set_tags (string ("//") + path
, tags
);
391 Library
->save_changes ();
394 SoundFileBrowser::SoundFileBrowser (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
, bool persistent
)
395 : ArdourDialog (parent
, title
, false, false),
396 found_list (ListStore::create(found_list_columns
)),
397 freesound_list (ListStore::create(freesound_list_columns
)),
398 chooser (FILE_CHOOSER_ACTION_OPEN
),
399 preview (persistent
),
400 found_search_btn (_("Search")),
401 found_list_view (found_list
),
402 freesound_search_btn (_("Start Downloading")),
403 freesound_list_view (freesound_list
)
405 resetting_ourselves
= false;
408 if (ARDOUR::Profile
->get_sae()) {
409 chooser
.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
410 chooser
.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
414 chooser
.add_shortcut_folder_uri("file:///Volumes");
417 //add the file chooser
419 chooser
.set_border_width (12);
420 custom_filter
.add_custom (FILE_FILTER_FILENAME
, mem_fun(*this, &SoundFileBrowser::on_custom
));
421 custom_filter
.set_name (_("Audio files"));
423 matchall_filter
.add_pattern ("*.*");
424 matchall_filter
.set_name (_("All files"));
426 chooser
.add_filter (custom_filter
);
427 chooser
.add_filter (matchall_filter
);
428 chooser
.set_select_multiple (true);
429 chooser
.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview
));
430 chooser
.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated
));
432 /* some broken redraw behaviour - this is a bandaid */
433 chooser
.signal_selection_changed().connect (mem_fun (chooser
, &Widget::queue_draw
));
436 if (!persistent_folder
.empty()) {
437 chooser
.set_current_folder (persistent_folder
);
439 notebook
.append_page (chooser
, _("Browse Files"));
442 hpacker
.set_spacing (6);
443 hpacker
.pack_start (notebook
, true, true);
444 hpacker
.pack_start (preview
, false, false);
446 get_vbox()->pack_start (hpacker
, true, true);
454 hbox
= manage(new HBox
);
455 hbox
->pack_start (found_entry
);
456 hbox
->pack_start (found_search_btn
);
458 Gtk::ScrolledWindow
*scroll
= manage(new ScrolledWindow
);
459 scroll
->add(found_list_view
);
460 scroll
->set_policy(Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
462 vbox
= manage(new VBox
);
463 vbox
->pack_start (*hbox
, PACK_SHRINK
);
464 vbox
->pack_start (*scroll
);
466 found_list_view
.append_column(_("Paths"), found_list_columns
.pathname
);
468 found_list_view
.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected
));
470 found_list_view
.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated
));
472 found_search_btn
.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked
));
473 found_entry
.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked
));
475 notebook
.append_page (*vbox
, _("Search Tags"));
478 //add freesound search
485 passbox
= manage(new HBox
);
486 passbox
->set_border_width (12);
487 passbox
->set_spacing (6);
489 label
= manage (new Label
);
490 label
->set_text (_("User:"));
491 passbox
->pack_start (*label
, false, false);
492 passbox
->pack_start (freesound_name_entry
);
493 label
= manage (new Label
);
494 label
->set_text (_("Password:"));
495 passbox
->pack_start (*label
, false, false);
496 passbox
->pack_start (freesound_pass_entry
);
497 label
= manage (new Label
);
498 label
->set_text (_("Tags:"));
499 passbox
->pack_start (*label
, false, false);
500 passbox
->pack_start (freesound_entry
, false, false);
501 passbox
->pack_start (freesound_search_btn
, false, false);
503 Gtk::ScrolledWindow
*scroll
= manage(new ScrolledWindow
);
504 scroll
->add(freesound_list_view
);
505 scroll
->set_policy(Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
507 vbox
= manage(new VBox
);
508 vbox
->pack_start (*passbox
, PACK_SHRINK
);
509 vbox
->pack_start(*scroll
);
511 //vbox->pack_start (freesound_list_view);
513 freesound_list_view
.append_column(_("Paths"), freesound_list_columns
.pathname
);
515 freesound_list_view
.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected
));
517 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
518 freesound_list_view
.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated
));
520 freesound_search_btn
.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked
));
521 freesound_entry
.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked
));
523 notebook
.append_page (*vbox
, _("Search Freesound"));
528 notebook
.set_size_request (500, -1);
532 add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
533 add_button (Stock::APPLY
, RESPONSE_APPLY
);
534 add_button (Stock::OK
, RESPONSE_OK
);
538 SoundFileBrowser::~SoundFileBrowser ()
540 persistent_folder
= chooser
.get_current_folder();
545 SoundFileBrowser::on_show ()
547 ArdourDialog::on_show ();
552 SoundFileBrowser::clear_selection ()
554 chooser
.unselect_all ();
555 found_list_view
.get_selection()->unselect_all ();
559 SoundFileBrowser::chooser_file_activated ()
565 SoundFileBrowser::found_list_view_activated (const TreeModel::Path
& path
, TreeViewColumn
* col
)
571 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path
& path
, TreeViewColumn
* col
)
577 SoundFileBrowser::set_session (Session
* s
)
579 ArdourDialog::set_session (s
);
580 preview
.set_session (s
);
584 remove_gain_meter ();
589 SoundFileBrowser::add_gain_meter ()
595 gm
= new GainMeter (*session
);
596 gm
->set_io (session
->the_auditioner());
598 meter_packer
.set_border_width (12);
599 meter_packer
.pack_start (*gm
, false, true);
600 hpacker
.pack_end (meter_packer
, false, false);
601 meter_packer
.show_all ();
606 SoundFileBrowser::remove_gain_meter ()
609 meter_packer
.remove (*gm
);
610 hpacker
.remove (meter_packer
);
617 SoundFileBrowser::start_metering ()
619 metering_connection
= ARDOUR_UI::instance()->SuperRapidScreenUpdate
.connect (mem_fun(*this, &SoundFileBrowser::meter
));
623 SoundFileBrowser::stop_metering ()
625 metering_connection
.disconnect();
629 SoundFileBrowser::meter ()
631 if (is_mapped () && session
&& gm
) {
632 gm
->update_meters ();
637 SoundFileBrowser::on_custom (const FileFilter::Info
& filter_info
)
639 return AudioFileSource::safe_file_extension (filter_info
.filename
);
643 SoundFileBrowser::update_preview ()
645 if (preview
.setup_labels (chooser
.get_filename())) {
646 if (preview
.autoplay()) {
647 Glib::signal_idle().connect (mem_fun (preview
, &SoundFileBox::audition_oneshot
));
653 SoundFileBrowser::found_list_view_selected ()
655 if (!reset_options ()) {
656 set_response_sensitive (RESPONSE_OK
, false);
660 TreeView::Selection::ListHandle_Path rows
= found_list_view
.get_selection()->get_selected_rows ();
663 TreeIter iter
= found_list
->get_iter(*rows
.begin());
664 file
= (*iter
)[found_list_columns
.pathname
];
665 chooser
.set_filename (file
);
666 set_response_sensitive (RESPONSE_OK
, true);
668 set_response_sensitive (RESPONSE_OK
, false);
671 preview
.setup_labels (file
);
676 SoundFileBrowser::freesound_list_view_selected ()
678 if (!reset_options ()) {
679 set_response_sensitive (RESPONSE_OK
, false);
683 TreeView::Selection::ListHandle_Path rows
= freesound_list_view
.get_selection()->get_selected_rows ();
686 TreeIter iter
= freesound_list
->get_iter(*rows
.begin());
687 file
= (*iter
)[freesound_list_columns
.pathname
];
688 chooser
.set_filename (file
);
689 set_response_sensitive (RESPONSE_OK
, true);
691 set_response_sensitive (RESPONSE_OK
, false);
694 preview
.setup_labels (file
);
699 SoundFileBrowser::found_search_clicked ()
701 string tag_string
= found_entry
.get_text ();
705 if (!PBD::tokenize (tag_string
, string(","), std::back_inserter (tags
), true)) {
706 warning
<< _("SoundFileBrowser: Could not tokenize string: ") << tag_string
<< endmsg
;
710 vector
<string
> results
;
711 Library
->search_members_and (results
, tags
);
714 for (vector
<string
>::iterator i
= results
.begin(); i
!= results
.end(); ++i
) {
715 TreeModel::iterator new_row
= found_list
->append();
716 TreeModel::Row row
= *new_row
;
717 string path
= Glib::filename_from_uri (string ("file:") + *i
);
718 row
[found_list_columns
.pathname
] = path
;
723 freesound_search_thread_entry (void* arg
)
725 PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freesound Search"));
727 static_cast<SoundFileBrowser
*>(arg
)->freesound_search_thread ();
732 bool searching
= false;
733 bool canceling
= false;
736 SoundFileBrowser::freesound_search_clicked ()
738 if (canceling
) //already canceling, button does nothing
742 freesound_search_btn
.set_label(_("Cancelling.."));
746 freesound_search_btn
.set_label(_("Cancel"));
747 pthread_t freesound_thr
;
748 pthread_create_and_store ("freesound_search", &freesound_thr
, 0, freesound_search_thread_entry
, this);
753 SoundFileBrowser::freesound_search_thread()
756 freesound_list
->clear();
759 path
= Glib::get_home_dir();
760 path
+= "/Freesound/";
761 Mootcher
theMootcher(path
.c_str());
763 string name_string
= freesound_name_entry
.get_text ();
764 string pass_string
= freesound_pass_entry
.get_text ();
765 string search_string
= freesound_entry
.get_text ();
767 if ( theMootcher
.doLogin( name_string
, pass_string
) ) {
769 string theString
= theMootcher
.searchText(search_string
);
772 doc
.read_buffer( theString
);
773 XMLNode
*root
= doc
.root();
775 if (root
==NULL
) return;
777 if ( strcmp(root
->name().c_str(), "freesound") == 0) {
780 XMLNodeList children
= root
->children();
781 XMLNodeConstIterator niter
;
782 for (niter
= children
.begin(); niter
!= children
.end() && !canceling
; ++niter
) {
784 if( strcmp( node
->name().c_str(), "sample") == 0 ){
785 XMLProperty
*prop
=node
->property ("id");
786 string filename
= theMootcher
.getFile( prop
->value().c_str() );
787 if ( filename
!= "" ) {
788 TreeModel::iterator new_row
= freesound_list
->append();
789 TreeModel::Row row
= *new_row
;
790 string path
= Glib::filename_from_uri (string ("file:") + filename
);
791 row
[freesound_list_columns
.pathname
] = path
;
800 freesound_search_btn
.set_label(_("Start Downloading"));
805 SoundFileBrowser::get_paths ()
807 vector
<ustring
> results
;
809 int n
= notebook
.get_current_page ();
812 vector
<ustring
> filenames
= chooser
.get_filenames();
813 vector
<ustring
>::iterator i
;
815 for (i
= filenames
.begin(); i
!= filenames
.end(); ++i
) {
817 if ((!stat((*i
).c_str(), &buf
)) && S_ISREG(buf
.st_mode
)) {
818 results
.push_back (*i
);
824 typedef TreeView::Selection::ListHandle_Path ListPath
;
826 ListPath rows
= found_list_view
.get_selection()->get_selected_rows ();
827 for (ListPath::iterator i
= rows
.begin() ; i
!= rows
.end(); ++i
) {
828 TreeIter iter
= found_list
->get_iter(*i
);
829 ustring str
= (*iter
)[found_list_columns
.pathname
];
831 results
.push_back (str
);
835 typedef TreeView::Selection::ListHandle_Path ListPath
;
837 ListPath rows
= freesound_list_view
.get_selection()->get_selected_rows ();
838 for (ListPath::iterator i
= rows
.begin() ; i
!= rows
.end(); ++i
) {
839 TreeIter iter
= freesound_list
->get_iter(*i
);
840 ustring str
= (*iter
)[freesound_list_columns
.pathname
];
842 results
.push_back (str
);
850 SoundFileOmega::reset_options_noret ()
852 if (!resetting_ourselves
) {
853 (void) reset_options ();
858 SoundFileOmega::reset_options ()
860 vector
<ustring
> paths
= get_paths ();
864 channel_combo
.set_sensitive (false);
865 action_combo
.set_sensitive (false);
866 where_combo
.set_sensitive (false);
867 copy_files_btn
.set_sensitive (false);
873 channel_combo
.set_sensitive (true);
874 action_combo
.set_sensitive (true);
875 where_combo
.set_sensitive (true);
877 /* if we get through this function successfully, this may be
878 reset at the end, once we know if we can use hard links
882 if (Config
->get_only_copy_imported_files()) {
883 copy_files_btn
.set_sensitive (false);
885 copy_files_btn
.set_sensitive (false);
891 bool selection_includes_multichannel
;
892 bool selection_can_be_embedded_with_links
= check_link_status (*session
, paths
);
895 if (check_info (paths
, same_size
, src_needed
, selection_includes_multichannel
)) {
896 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message
));
900 ustring existing_choice
;
901 vector
<string
> action_strings
;
903 if (selected_track_cnt
> 0) {
904 if (channel_combo
.get_active_text().length()) {
905 ImportDisposition id
= get_channel_disposition();
908 case Editing::ImportDistinctFiles
:
909 if (selected_track_cnt
== paths
.size()) {
910 action_strings
.push_back (importmode2string (ImportToTrack
));
914 case Editing::ImportDistinctChannels
:
915 /* XXX it would be nice to allow channel-per-selected track
916 but its too hard we don't want to deal with all the
917 different per-file + per-track channel configurations.
922 action_strings
.push_back (importmode2string (ImportToTrack
));
928 action_strings
.push_back (importmode2string (ImportAsTrack
));
929 action_strings
.push_back (importmode2string (ImportAsRegion
));
930 action_strings
.push_back (importmode2string (ImportAsTapeTrack
));
932 resetting_ourselves
= true;
934 existing_choice
= action_combo
.get_active_text();
936 set_popdown_strings (action_combo
, action_strings
);
938 /* preserve any existing choice, if possible */
941 if (existing_choice
.length()) {
942 vector
<string
>::iterator x
;
943 for (x
= action_strings
.begin(); x
!= action_strings
.end(); ++x
) {
944 if (*x
== existing_choice
) {
945 action_combo
.set_active_text (existing_choice
);
949 if (x
== action_strings
.end()) {
950 action_combo
.set_active_text (action_strings
.front());
953 action_combo
.set_active_text (action_strings
.front());
956 resetting_ourselves
= false;
958 if ((mode
= get_mode()) == ImportAsRegion
) {
959 where_combo
.set_sensitive (false);
961 where_combo
.set_sensitive (true);
964 vector
<string
> channel_strings
;
966 if (mode
== ImportAsTrack
|| mode
== ImportAsTapeTrack
|| mode
== ImportToTrack
) {
967 channel_strings
.push_back (_("one track per file"));
969 if (selection_includes_multichannel
) {
970 channel_strings
.push_back (_("one track per channel"));
973 if (paths
.size() > 1) {
974 /* tape tracks are a single region per track, so we cannot
975 sequence multiple files.
977 if (mode
!= ImportAsTapeTrack
) {
978 channel_strings
.push_back (_("sequence files"));
981 channel_strings
.push_back (_("all files in one track"));
987 channel_strings
.push_back (_("one region per file"));
989 if (selection_includes_multichannel
) {
990 channel_strings
.push_back (_("one region per channel"));
993 if (paths
.size() > 1) {
995 channel_strings
.push_back (_("all files in one region"));
1000 existing_choice
= channel_combo
.get_active_text();
1002 set_popdown_strings (channel_combo
, channel_strings
);
1004 /* preserve any existing choice, if possible */
1006 if (existing_choice
.length()) {
1007 vector
<string
>::iterator x
;
1008 for (x
= channel_strings
.begin(); x
!= channel_strings
.end(); ++x
) {
1009 if (*x
== existing_choice
) {
1010 channel_combo
.set_active_text (existing_choice
);
1014 if (x
== channel_strings
.end()) {
1015 channel_combo
.set_active_text (channel_strings
.front());
1018 channel_combo
.set_active_text (channel_strings
.front());
1022 src_combo
.set_sensitive (true);
1024 src_combo
.set_sensitive (false);
1027 if (Config
->get_only_copy_imported_files()) {
1029 if (selection_can_be_embedded_with_links
) {
1030 copy_files_btn
.set_sensitive (true);
1032 copy_files_btn
.set_sensitive (false);
1037 copy_files_btn
.set_sensitive (true);
1045 SoundFileOmega::bad_file_message()
1047 MessageDialog
msg (*this,
1048 _("One or more of the selected files\ncannot be used by Ardour"),
1053 resetting_ourselves
= true;
1054 chooser
.unselect_uri (chooser
.get_preview_uri());
1055 resetting_ourselves
= false;
1061 SoundFileOmega::check_info (const vector
<ustring
>& paths
, bool& same_size
, bool& src_needed
, bool& multichannel
)
1070 multichannel
= false;
1072 for (vector
<ustring
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1074 if (!AudioFileSource::get_soundfile_info (*i
, info
, errmsg
)) {
1078 if (info
.channels
> 1) {
1079 multichannel
= true;
1085 if (sz
!= info
.length
) {
1090 if ((nframes_t
) info
.samplerate
!= session
->frame_rate()) {
1100 SoundFileOmega::check_link_status (const Session
& s
, const vector
<ustring
>& paths
)
1102 string tmpdir
= s
.sound_dir();
1105 tmpdir
+= "/linktest";
1107 if (mkdir (tmpdir
.c_str(), 0744)) {
1108 if (errno
!= EEXIST
) {
1113 for (vector
<ustring
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1115 char tmpc
[MAXPATHLEN
+1];
1117 snprintf (tmpc
, sizeof(tmpc
), "%s/%s", tmpdir
.c_str(), Glib::path_get_basename (*i
).c_str());
1121 if (link ((*i
).c_str(), tmpc
)) {
1131 rmdir (tmpdir
.c_str());
1135 SoundFileChooser::SoundFileChooser (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
)
1136 : SoundFileBrowser (parent
, title
, s
, false)
1138 chooser
.set_select_multiple (false);
1139 found_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1140 freesound_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1144 SoundFileChooser::on_hide ()
1146 ArdourDialog::on_hide();
1150 session
->cancel_audition();
1155 SoundFileChooser::get_filename ()
1157 vector
<ustring
> paths
;
1159 paths
= get_paths ();
1161 if (paths
.empty()) {
1165 if (!Glib::file_test (paths
.front(), Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
1169 return paths
.front();
1172 SoundFileOmega::SoundFileOmega (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
, int selected_tracks
, bool persistent
,
1173 Editing::ImportMode mode_hint
)
1174 : SoundFileBrowser (parent
, title
, s
, persistent
),
1175 copy_files_btn ( _("Copy files to session")),
1176 selected_track_cnt (selected_tracks
)
1182 set_size_request (-1, 450);
1184 block_two
.set_border_width (12);
1185 block_three
.set_border_width (12);
1186 block_four
.set_border_width (12);
1188 options
.set_spacing (12);
1191 str
.push_back (_("use file timestamp"));
1192 str
.push_back (_("at edit point"));
1193 str
.push_back (_("at playhead"));
1194 str
.push_back (_("at session start"));
1195 set_popdown_strings (where_combo
, str
);
1196 where_combo
.set_active_text (str
.front());
1198 Label
* l
= manage (new Label
);
1199 l
->set_text (_("Add files:"));
1201 hbox
= manage (new HBox
);
1202 hbox
->set_border_width (12);
1203 hbox
->set_spacing (6);
1204 hbox
->pack_start (*l
, false, false);
1205 hbox
->pack_start (action_combo
, false, false);
1206 vbox
= manage (new VBox
);
1207 vbox
->pack_start (*hbox
, false, false);
1208 options
.pack_start (*vbox
, false, false);
1210 /* dummy entry for action combo so that it doesn't look odd if we
1211 come up with no tracks selected.
1215 str
.push_back (importmode2string (mode_hint
));
1216 set_popdown_strings (action_combo
, str
);
1217 action_combo
.set_active_text (str
.front());
1218 action_combo
.set_sensitive (false);
1220 l
= manage (new Label
);
1221 l
->set_text (_("Insert:"));
1223 hbox
= manage (new HBox
);
1224 hbox
->set_border_width (12);
1225 hbox
->set_spacing (6);
1226 hbox
->pack_start (*l
, false, false);
1227 hbox
->pack_start (where_combo
, false, false);
1228 vbox
= manage (new VBox
);
1229 vbox
->pack_start (*hbox
, false, false);
1230 options
.pack_start (*vbox
, false, false);
1233 l
= manage (new Label
);
1234 l
->set_text (_("Mapping:"));
1236 hbox
= manage (new HBox
);
1237 hbox
->set_border_width (12);
1238 hbox
->set_spacing (6);
1239 hbox
->pack_start (*l
, false, false);
1240 hbox
->pack_start (channel_combo
, false, false);
1241 vbox
= manage (new VBox
);
1242 vbox
->pack_start (*hbox
, false, false);
1243 options
.pack_start (*vbox
, false, false);
1246 str
.push_back (_("one track per file"));
1247 set_popdown_strings (channel_combo
, str
);
1248 channel_combo
.set_active_text (str
.front());
1249 channel_combo
.set_sensitive (false);
1251 l
= manage (new Label
);
1252 l
->set_text (_("Conversion Quality:"));
1254 hbox
= manage (new HBox
);
1255 hbox
->set_border_width (12);
1256 hbox
->set_spacing (6);
1257 hbox
->pack_start (*l
, false, false);
1258 hbox
->pack_start (src_combo
, false, false);
1259 vbox
= manage (new VBox
);
1260 vbox
->pack_start (*hbox
, false, false);
1261 options
.pack_start (*vbox
, false, false);
1264 str
.push_back (_("Best"));
1265 str
.push_back (_("Good"));
1266 str
.push_back (_("Quick"));
1267 str
.push_back (_("Fast"));
1268 str
.push_back (_("Fastest"));
1270 set_popdown_strings (src_combo
, str
);
1271 src_combo
.set_active_text (str
.front());
1272 src_combo
.set_sensitive (false);
1276 action_combo
.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret
));
1278 copy_files_btn
.set_active (true);
1280 block_four
.pack_start (copy_files_btn
, false, false);
1282 options
.pack_start (block_four
, false, false);
1284 get_vbox()->pack_start (options
, false, false);
1286 /* setup disposition map */
1288 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("one track per file"), ImportDistinctFiles
));
1289 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("one track per channel"), ImportDistinctChannels
));
1290 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("merge files"), ImportMergeFiles
));
1291 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("sequence files"), ImportSerializeFiles
));
1293 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("one region per file"), ImportDistinctFiles
));
1294 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("one region per channel"), ImportDistinctChannels
));
1295 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("all files in one region"), ImportMergeFiles
));
1296 disposition_map
.insert (pair
<ustring
,ImportDisposition
>(_("all files in one track"), ImportSerializeFiles
));
1298 chooser
.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed
));
1300 /* set size requests for a couple of combos to allow them to display the longest text
1301 they will ever be asked to display. This prevents them being resized when the user
1302 selects a file to import, which in turn prevents the size of the dialog from jumping
1306 t
.push_back (_("one track per file"));
1307 t
.push_back (_("one track per channel"));
1308 t
.push_back (_("sequence files"));
1309 t
.push_back (_("all files in one region"));
1310 set_size_request_to_display_given_text (channel_combo
, t
, COMBO_FUDGE
+ 10, 15);
1313 t
.push_back (importmode2string (ImportAsTrack
));
1314 t
.push_back (importmode2string (ImportToTrack
));
1315 t
.push_back (importmode2string (ImportAsRegion
));
1316 t
.push_back (importmode2string (ImportAsTapeTrack
));
1317 set_size_request_to_display_given_text (action_combo
, t
, COMBO_FUDGE
+ 10, 15);
1321 SoundFileOmega::set_mode (ImportMode mode
)
1323 action_combo
.set_active_text (importmode2string (mode
));
1327 SoundFileOmega::get_mode () const
1329 return string2importmode (action_combo
.get_active_text());
1333 SoundFileOmega::on_hide ()
1335 ArdourDialog::on_hide();
1337 session
->cancel_audition();
1342 SoundFileOmega::get_position() const
1344 ustring str
= where_combo
.get_active_text();
1346 if (str
== _("use file timestamp")) {
1347 return ImportAtTimestamp
;
1348 } else if (str
== _("at edit point")) {
1349 return ImportAtEditPoint
;
1350 } else if (str
== _("at playhead")) {
1351 return ImportAtPlayhead
;
1353 return ImportAtStart
;
1358 SoundFileOmega::get_src_quality() const
1360 ustring str
= where_combo
.get_active_text();
1362 if (str
== _("Best")) {
1364 } else if (str
== _("Good")) {
1366 } else if (str
== _("Quick")) {
1368 } else if (str
== _("Fast")) {
1376 SoundFileOmega::get_channel_disposition () const
1378 /* we use a map here because the channel combo can contain different strings
1379 depending on the state of the other combos. the map contains all possible strings
1380 and the ImportDisposition enum that corresponds to it.
1383 ustring str
= channel_combo
.get_active_text();
1384 DispositionMap::const_iterator x
= disposition_map
.find (str
);
1386 if (x
== disposition_map
.end()) {
1387 fatal
<< string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str
) << endmsg
;
1395 SoundFileOmega::reset (int selected_tracks
)
1397 selected_track_cnt
= selected_tracks
;
1402 SoundFileOmega::file_selection_changed ()
1404 if (resetting_ourselves
) {
1408 if (!reset_options ()) {
1409 set_response_sensitive (RESPONSE_OK
, false);
1411 if (chooser
.get_filenames().size() > 0) {
1412 set_response_sensitive (RESPONSE_OK
, true);
1414 set_response_sensitive (RESPONSE_OK
, false);