mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-07 06:05:43 +01:00
439 lines
14 KiB
C++
439 lines
14 KiB
C++
/*
|
|
Copyright (C) 2005-2006 Paul Davis
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
#include <glib/gstdio.h>
|
|
#include <glibmm/fileutils.h>
|
|
|
|
#include "ardour/smf_source.h"
|
|
#include "ardour/audiofilesource.h"
|
|
#include "ardour/session.h"
|
|
#include "ardour/session_directory.h"
|
|
|
|
#include "waves_import_dialog.h"
|
|
#include "open_file_dialog_proxy.h"
|
|
#include "audio_time_axis.h"
|
|
|
|
std::string WavesImportDialog::__initial_folder;
|
|
|
|
WavesImportDialog::WavesImportDialog (ARDOUR::Session* session, uint32_t selected_audio_track_count)
|
|
: WavesDialog ("waves_import_dialog.xml", true, false )
|
|
, _add_as_dropdown (get_waves_dropdown ("add_as_dropdown"))
|
|
, _status (0)
|
|
, _done (false)
|
|
, _selected_audio_track_count (selected_audio_track_count)
|
|
, _insert_at_home (get_container ("insert_at_home"))
|
|
, _insert_at_dropdown (get_waves_dropdown ("insert_at_dropdown"))
|
|
, _mapping_dropdown (get_waves_dropdown ("mapping_dropdown"))
|
|
, _quality_home (get_container ("quality_home"))
|
|
, _quality_dropdown (get_waves_dropdown ("quality_dropdown"))
|
|
, _copy_to_session_home (get_container ("copy_to_session_home"))
|
|
, _copy_to_session_button (get_waves_button ("copy_to_session_button"))
|
|
, _self_reset (false)
|
|
, _import_as_track_str (xml_property (*xml_tree ()->root (), "ImportAsTrack", "???"))
|
|
, _import_to_track_str (xml_property (*xml_tree ()->root (), "ImportToTrack", "???"))
|
|
, _import_as_region_str (xml_property (*xml_tree ()->root (), "ImportAsRegion", "???"))
|
|
, _import_as_tape_track_str (xml_property (*xml_tree ()->root (), "ImportAsTapeTrack", "???"))
|
|
, _one_track_per_file_str (xml_property (*xml_tree ()->root (), "OneTrackPerFile", "???"))
|
|
, _one_track_per_channel_str (xml_property (*xml_tree ()->root (), "OneTrackPerChannel", "???"))
|
|
, _sequence_files_str (xml_property (*xml_tree ()->root (), "SequenceFiles", "???"))
|
|
, _all_files_in_one_track_str (xml_property (*xml_tree ()->root (), "AllFilesInOneTrack", "???"))
|
|
, _merge_files_str (xml_property (*xml_tree ()->root (), "MergeFiles", "???"))
|
|
, _one_region_per_file_str (xml_property (*xml_tree ()->root (), "OneRegionPerFile", "???"))
|
|
, _one_region_per_channel_str (xml_property (*xml_tree ()->root (), "OneRegionPerChannel", "???"))
|
|
, _all_files_in_one_region_str (xml_property (*xml_tree ()->root (), "AllFilesInOneRegion", "???"))
|
|
{
|
|
set_session (session);
|
|
_disposition_map.insert (DispositionMapKey (OneTrackPerFile, Editing::ImportDistinctFiles));
|
|
_disposition_map.insert (DispositionMapKey (OneTrackPerChannel, Editing::ImportDistinctChannels));
|
|
_disposition_map.insert (DispositionMapKey (MergeFiles, Editing::ImportMergeFiles));
|
|
_disposition_map.insert (DispositionMapKey (SequenceFiles, Editing::ImportSerializeFiles));
|
|
|
|
_disposition_map.insert (DispositionMapKey (OneRegionPerFile, Editing::ImportDistinctFiles));
|
|
_disposition_map.insert (DispositionMapKey (OneRegionPerChannel, Editing::ImportDistinctChannels));
|
|
_disposition_map.insert (DispositionMapKey (AllFilesInOneRegion, Editing::ImportMergeFiles));
|
|
_disposition_map.insert (DispositionMapKey (AllFilesInOneTrack, Editing::ImportMergeFiles));
|
|
|
|
_insert_at_dropdown.set_current_item (0);
|
|
_mapping_dropdown.set_current_item (0);
|
|
_quality_dropdown.set_current_item (0);
|
|
|
|
get_waves_button ("import_button").signal_clicked.connect (sigc::mem_fun (*this, &WavesImportDialog::_on_import_button));
|
|
get_waves_button ("cancel_button").signal_clicked.connect (sigc::mem_fun (*this, &WavesImportDialog::_on_cancel_button));
|
|
_add_as_dropdown.selected_item_changed.connect (sigc::mem_fun (*this, &WavesImportDialog::_on_dropdowns));
|
|
_mapping_dropdown.selected_item_changed.connect (sigc::mem_fun (*this, &WavesImportDialog::_on_dropdowns));
|
|
}
|
|
|
|
ARDOUR::SrcQuality
|
|
WavesImportDialog::_get_src_quality() const
|
|
{
|
|
ARDOUR::SrcQuality quality;
|
|
|
|
switch (_quality_dropdown.get_item_data_u (_quality_dropdown.get_current_item ())) {
|
|
case Good:
|
|
quality = ARDOUR::SrcGood;
|
|
break;
|
|
case Quick:
|
|
quality = ARDOUR::SrcQuick;
|
|
break;
|
|
case Fast:
|
|
quality = ARDOUR::SrcFast;
|
|
break;
|
|
case Fastest:
|
|
quality = ARDOUR::SrcFastest;
|
|
break;
|
|
case Best:
|
|
default:
|
|
quality = ARDOUR::SrcBest;
|
|
break;
|
|
}
|
|
|
|
return quality;
|
|
}
|
|
|
|
Editing::ImportMode
|
|
WavesImportDialog::_get_import_mode() const
|
|
{
|
|
Editing::ImportMode import_mode;
|
|
switch (_add_as_dropdown.get_item_data_u (_add_as_dropdown.get_current_item ())) {
|
|
case AsTrack:
|
|
import_mode = Editing::ImportAsTrack;
|
|
break;
|
|
case ToTrack:
|
|
import_mode = Editing::ImportToTrack;
|
|
break;
|
|
case AsRegion:
|
|
import_mode = Editing::ImportAsRegion;
|
|
break;
|
|
case AsTapeTrack:
|
|
import_mode = Editing::ImportAsTapeTrack;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return import_mode;
|
|
}
|
|
|
|
const std::string __audiofile_types[] = {
|
|
"aif", "AIF", "aifc", "AIFC", "aiff", "AIFF", "amb", "AMB", "au", "AU", "caf", "CAF",
|
|
"cdr", "CDR", "flac", "FLAC", "htk", "HTK", "iff", "IFF", "mat", "MAT", "oga", "OGA",
|
|
"ogg", "OGG", "paf", "PAF", "pvf", "PVF", "sf", "SF", "smp", "SMP", "snd", "SND",
|
|
"maud", "MAUD", "voc", "VOC", "vwe", "VWE", "w64", "W64", "wav", "WAV",
|
|
#ifdef HAVE_COREAUDIO
|
|
"aac", "AAC", "adts", "ADTS",
|
|
"ac3", "AC3", "amr", "AMR",
|
|
"mpa", "MPA", "mpeg", "MPEG",
|
|
"mp1", "MP1", "mp2", "MP2",
|
|
"mp3", "MP3", "mp4", "MP4",
|
|
"m4a", "M4A", "sd2", "SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
|
|
#endif // HAVE_COREAUDIO
|
|
};
|
|
|
|
int
|
|
WavesImportDialog::run_import ()
|
|
{
|
|
std::vector<std::string> audiofile_types (__audiofile_types,
|
|
__audiofile_types + sizeof (__audiofile_types)/sizeof(__audiofile_types[0]));
|
|
do {
|
|
_files_to_import = ARDOUR::open_file_dialog (audiofile_types, __initial_folder);
|
|
if (_files_to_import.empty ()) {
|
|
return Gtk::RESPONSE_CANCEL;
|
|
}
|
|
__initial_folder = Glib::path_get_dirname (_files_to_import[0]);
|
|
} while (!_reset_options ());
|
|
return run ();
|
|
}
|
|
|
|
Editing::ImportDisposition
|
|
WavesImportDialog::_get_channel_disposition () const
|
|
{
|
|
/* we use a map here because the channel combo can contain different strings
|
|
depending on the state of the other combos. the map contains all possible strings
|
|
and the ImportDisposition enum that corresponds to it.
|
|
*/
|
|
|
|
Mapping mapping = Mapping(_mapping_dropdown.get_item_data_i (_mapping_dropdown.get_current_item ()));
|
|
DispositionMap::const_iterator x = _disposition_map.find (mapping);
|
|
|
|
if (x == _disposition_map.end()) {
|
|
PBD::fatal << string_compose (_("programming error: %1 (%2)"), "unknown value for import disposition", mapping) << endmsg;
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
return x->second;
|
|
}
|
|
|
|
bool
|
|
WavesImportDialog::_reset_options ()
|
|
{
|
|
bool same_size;
|
|
bool src_needed;
|
|
bool selection_includes_multichannel;
|
|
bool selection_can_be_embedded_with_links = _check_link_status ();
|
|
|
|
if (_check_info (same_size, src_needed, selection_includes_multichannel)) {
|
|
WavesMessageDialog msg ("", string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME));
|
|
msg.run ();
|
|
return false;
|
|
}
|
|
|
|
_copy_to_session_home.set_visible (!ARDOUR::Config->get_only_copy_imported_files ());
|
|
|
|
_self_reset = true;
|
|
int current_add_as_mode = AddingMode(_add_as_dropdown.get_item_data_i (_add_as_dropdown.get_current_item ()));
|
|
_add_as_dropdown.clear_items ();
|
|
_add_as_dropdown.add_menu_item (_import_as_track_str, (void*)AsTrack);
|
|
// _add_as_dropdown.add_menu_item (_import_as_tape_track_str, (void*)AsTapeTrack);
|
|
|
|
if (_selected_audio_track_count > 0) {
|
|
if (_mapping_dropdown.get_current_item () >= 0) {
|
|
switch (_get_channel_disposition ()) {
|
|
case Editing::ImportDistinctFiles:
|
|
if (_selected_audio_track_count == _files_to_import.size ()) {
|
|
_add_as_dropdown.add_menu_item (_import_to_track_str, (void*)ToTrack);
|
|
}
|
|
break;
|
|
|
|
case Editing::ImportDistinctChannels:
|
|
/* XXX it would be nice to allow channel-per-selected track
|
|
but its too hard we don't want to deal with all the
|
|
different per-file + per-track channel configurations.
|
|
*/
|
|
break;
|
|
|
|
default:
|
|
_add_as_dropdown.add_menu_item (_import_to_track_str, (void*)ToTrack);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (current_add_as_mode >= 0) {
|
|
int size = _add_as_dropdown.get_menu ().items ().size ();
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
if (_add_as_dropdown.get_item_data_i (i) == current_add_as_mode) {
|
|
_add_as_dropdown.set_current_item (i);
|
|
break;
|
|
}
|
|
}
|
|
if (i == size) {
|
|
_add_as_dropdown.set_current_item (0);
|
|
}
|
|
} else {
|
|
_add_as_dropdown.set_current_item (0);
|
|
}
|
|
|
|
int current_mapping = _mapping_dropdown.get_item_data_i (_mapping_dropdown.get_current_item ());
|
|
_mapping_dropdown.clear_items ();
|
|
Editing::ImportMode mode = _get_import_mode ();
|
|
_insert_at_home.set_visible (mode != Editing::ImportAsRegion);
|
|
|
|
if ((mode == Editing::ImportAsTrack) || (mode == Editing::ImportAsTapeTrack) || (mode == Editing::ImportToTrack)) {
|
|
_mapping_dropdown.add_menu_item (_one_track_per_file_str, (void*)OneTrackPerFile);
|
|
|
|
if (selection_includes_multichannel) {
|
|
_mapping_dropdown.add_menu_item (_one_track_per_channel_str, (void*)OneTrackPerChannel);
|
|
}
|
|
|
|
if (_files_to_import.size() > 1) {
|
|
/* tape tracks are a single region per track, so we cannot
|
|
sequence multiple files.
|
|
*/
|
|
if (mode != Editing::ImportAsTapeTrack) {
|
|
_mapping_dropdown.add_menu_item (_sequence_files_str, (void*)SequenceFiles);
|
|
}
|
|
if (same_size) {
|
|
_mapping_dropdown.add_menu_item (_all_files_in_one_track_str, (void*)AllFilesInOneTrack);
|
|
_mapping_dropdown.add_menu_item (_merge_files_str, (void*)MergeFiles);
|
|
}
|
|
}
|
|
} else {
|
|
_mapping_dropdown.add_menu_item (_one_region_per_file_str, (void*)OneRegionPerFile);
|
|
|
|
if (selection_includes_multichannel) {
|
|
_mapping_dropdown.add_menu_item (_one_region_per_channel_str, (void*)OneRegionPerChannel);
|
|
}
|
|
|
|
if (_files_to_import.size() > 1) {
|
|
if (same_size) {
|
|
_mapping_dropdown.add_menu_item (_all_files_in_one_region_str, (void*)AllFilesInOneRegion);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* preserve any existing choice, if possible */
|
|
if (current_mapping >= 0) {
|
|
int size = _mapping_dropdown.get_menu ().items ().size ();
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
if (_mapping_dropdown.get_item_data_i (i) == current_mapping) {
|
|
_mapping_dropdown.set_current_item (i);
|
|
break;
|
|
}
|
|
}
|
|
if (i == size) {
|
|
_mapping_dropdown.set_current_item (0);
|
|
}
|
|
} else {
|
|
_mapping_dropdown.set_current_item (0);
|
|
}
|
|
|
|
_self_reset = false;
|
|
|
|
_quality_home.set_visible (src_needed);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
WavesImportDialog::_check_link_status ()
|
|
{
|
|
#ifdef PLATFORM_WINDOWS
|
|
return false;
|
|
#else
|
|
std::string tmpdir(Glib::build_filename (_session->session_directory().sound_path(), "linktest"));
|
|
bool ret = false;
|
|
|
|
if (mkdir (tmpdir.c_str(), 0744)) {
|
|
if (errno != EEXIST) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (std::vector<std::string>::const_iterator i = _files_to_import.begin(); i != _files_to_import.end(); ++i) {
|
|
|
|
char tmpc[PATH_MAX+1];
|
|
|
|
snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
|
|
|
|
/* can we link ? */
|
|
|
|
if (link ((*i).c_str(), tmpc)) {
|
|
goto out;
|
|
}
|
|
|
|
::g_unlink (tmpc);
|
|
}
|
|
|
|
ret = true;
|
|
|
|
out:
|
|
rmdir (tmpdir.c_str());
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
WavesImportDialog::_check_info (bool& same_size, bool& src_needed, bool& multichannel)
|
|
{
|
|
ARDOUR::SoundFileInfo info;
|
|
framepos_t sz = 0;
|
|
bool err = false;
|
|
std::string errmsg;
|
|
|
|
same_size = true;
|
|
src_needed = false;
|
|
multichannel = false;
|
|
|
|
for (std::vector<std::string>::const_iterator i = _files_to_import.begin(); i != _files_to_import.end(); ++i) {
|
|
if (ARDOUR::AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
|
|
if (info.channels > 2 ) {
|
|
err = true;
|
|
}
|
|
if (info.channels > 1) {
|
|
multichannel = true;
|
|
}
|
|
if (sz == 0) {
|
|
sz = info.length;
|
|
} else {
|
|
if (sz != info.length) {
|
|
same_size = false;
|
|
}
|
|
}
|
|
|
|
if (info.samplerate != _session->frame_rate()) {
|
|
src_needed = true;
|
|
}
|
|
} else if (ARDOUR::SMFSource::valid_midi_file (*i)) {
|
|
Evoral::SMF reader;
|
|
reader.open(*i);
|
|
if (reader.num_tracks() > 1) {
|
|
multichannel = true; // "channel" == track here...
|
|
}
|
|
|
|
/* XXX we need err = true handling here in case
|
|
we can't check the file
|
|
*/
|
|
err = true;
|
|
} else {
|
|
err = true;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
void
|
|
WavesImportDialog::_on_dropdowns (WavesDropdown*, int)
|
|
{
|
|
if (!_self_reset) {
|
|
_reset_options ();
|
|
}
|
|
}
|
|
|
|
void
|
|
WavesImportDialog::_on_cancel_button (WavesButton*)
|
|
{
|
|
response (Gtk::RESPONSE_CANCEL);
|
|
}
|
|
|
|
void
|
|
WavesImportDialog::_on_import_button (WavesButton*)
|
|
{
|
|
_done = true;
|
|
_status = Gtk::RESPONSE_OK;
|
|
framepos_t where;
|
|
|
|
switch (_insert_at_dropdown.get_item_data_i (_insert_at_dropdown.get_current_item ())) {
|
|
case EditPoint:
|
|
where = PublicEditor::instance().get_preferred_edit_position ();
|
|
break;
|
|
case Timestamp:
|
|
where = -1;
|
|
break;
|
|
case Playhead:
|
|
where = _session->transport_frame();
|
|
break;
|
|
case Start:
|
|
default:
|
|
where = _session->current_start_frame();
|
|
break;
|
|
}
|
|
|
|
Editing::ImportMode import_mode = _get_import_mode ();
|
|
Editing::ImportDisposition channel_disposition = _get_channel_disposition ();
|
|
ARDOUR::SrcQuality quality = _get_src_quality ();
|
|
hide ();
|
|
if (_copy_to_session_button.active_state () == Gtkmm2ext::ExplicitActive) {
|
|
PublicEditor::instance().do_import (_files_to_import, channel_disposition, import_mode, quality, where);
|
|
} else {
|
|
PublicEditor::instance().do_embed (_files_to_import, channel_disposition, import_mode, where);
|
|
}
|
|
|
|
response (Gtk::RESPONSE_OK);
|
|
}
|