1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-22 15:10:23 +02:00

Multiple export dialog bugs fixed

Bug 2062 - Export as WAV does not remember the previously used setting
Bug 1355 - "Other uncompressed files" does not (visually) update target
           file extension according to the chosen "Header" type
Bug 1356 - "Other uncompressed files" forces the default extension for
           the format in the exported file
Bug 1381 - Export other uncompressed formats incorrectly assumes max 255
           channels

(and possibly others...not the best bugzilla searcher)
This commit is contained in:
Leland Lucius 2020-03-23 00:47:17 -05:00
parent 8570ab7402
commit 38bf51afea
9 changed files with 456 additions and 281 deletions

View File

@ -36,6 +36,8 @@ public:
virtual bool HasUserPaneCreator() const;
virtual void SetUserPaneCreator(UserPaneCreatorFunction creator, wxUIntPtr userdata);
virtual void SetFileExtension(const wxString& extension) {};
protected:
void CreateUserPane(wxWindow *parent);

View File

@ -472,6 +472,35 @@ int FileDialog::ShowModal()
return wxDialog::ShowModal();
}
// Change the currently displayed extension
void FileDialog::SetFileExtension(const wxString& extension)
{
wxString filename;
#if defined(__WXGTK3__)
filename = wxString::FromUTF8(gtk_file_chooser_get_current_name(m_fc));
#else
GtkWidget *entry = find_widget(m_widget, "GtkFileChooserEntry", 0);
if (entry)
{
filename = wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(entry)));
}
#endif
if (filename == wxEmptyString)
{
filename = m_fc.GetFilename();
}
if (filename != wxEmptyString)
{
wxFileName fn(filename);
fn.SetExt(extension);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), fn.GetFullName().utf8_str());
}
}
void FileDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
int WXUNUSED(width), int WXUNUSED(height),
int WXUNUSED(sizeFlags))
@ -571,7 +600,7 @@ void FileDialog::SetWildcard(const wxString& wildCard)
void FileDialog::SetFilterIndex(int filterIndex)
{
m_fc.SetFilterIndex( filterIndex);
m_fc.SetFilterIndex( filterIndex );
}
int FileDialog::GetFilterIndex() const

View File

@ -25,23 +25,23 @@ public:
FileDialog() { }
FileDialog(wxWindow *parent,
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
bool Create(wxWindow *parent,
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
virtual ~FileDialog();
virtual wxString GetPath() const;
@ -61,6 +61,8 @@ public:
virtual bool SupportsExtraControl() const { return true; }
virtual void SetFileExtension(const wxString& extension);
// Implementation only.
void GTKSelectionChanged(const wxString& filename);
void GTKFolderChanged();

View File

@ -66,6 +66,8 @@ public:
#endif
virtual bool SupportsExtraControl() const;
virtual void SetFileExtension(const wxString& extension);
// implementation only

View File

@ -793,3 +793,13 @@ void FileDialog::ModalFinishedCallback(void* panel, int returnCode)
UnsubclassWin();
[(NSSavePanel*) panel setAccessoryView:nil];
}
// Change the currently displayed extension
void FileDialog::SetFileExtension(const wxString& extension)
{
NSSavePanel* sPanel = (NSSavePanel*) GetWXWindow();
m_filterExtensions[m_filterIndex] = extension;
NSArray* types = GetTypesFromExtension(m_filterExtensions[m_filterIndex],m_currentExtensions);
[sPanel setAllowedFileTypes:types];
}

View File

@ -721,6 +721,28 @@ void FileDialog::GetFilenames(wxArrayString& files) const
files = m_fileNames;
}
void FileDialog::SetFileExtension(const wxString& extension)
{
if (mParentDlg)
{
wxChar path[wxMAXPATH];
if (CommDlg_OpenSave_GetFilePath(mParentDlg, path, WXSIZEOF(path)))
{
wxFileName fn(path);
fn.SetExt(extension);
// Change the currently entered file name.
CommDlg_OpenSave_SetControlText(mParentDlg, edt1, fn.GetFullName().t_str());
// Make this the default extension as well. So if the user specifies a file
// name without an extension, this one will be used instead of the first
// extension in the filter list.
CommDlg_OpenSave_SetDefExt(mParentDlg, fn.GetExt().t_str());
}
}
}
void FileDialog::DoGetPosition( int *x, int *y ) const
{
if (x)

View File

@ -24,22 +24,24 @@
class AUDACITY_DLL_API FileDialog : public FileDialogBase
{
public:
FileDialog();
FileDialog(wxWindow *parent,
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
public:
FileDialog();
FileDialog(wxWindow *parent,
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr);
virtual void GetPaths(wxArrayString& paths) const;
virtual void GetFilenames(wxArrayString& files) const;
virtual int ShowModal();
virtual void SetFileExtension(const wxString& extension);
protected:
// -----------------------------------------
// wxMSW-specific implementation from now on
@ -89,9 +91,7 @@ private:
wxArrayString m_FilterGroups;
wxArrayString m_Filters;
wxChar *m_NameBuf;
int m_NameBufLen;
HWND mParentDlg;
HWND mChildDlg;
WNDPROC mParentProc;

View File

@ -278,7 +278,7 @@ wxDEFINE_EVENT(AUDACITY_FILE_SUFFIX_EVENT, wxCommandEvent);
BEGIN_EVENT_TABLE(Exporter, wxEvtHandler)
EVT_FILECTRL_FILTERCHANGED(wxID_ANY, Exporter::OnFilterChanged)
EVT_BUTTON(wxID_HELP, Exporter::OnHelp)
EVT_COMMAND( wxID_ANY, AUDACITY_FILE_SUFFIX_EVENT, Exporter::OnExtensionChanged)
EVT_COMMAND(wxID_ANY, AUDACITY_FILE_SUFFIX_EVENT, Exporter::OnExtensionChanged)
END_EVENT_TABLE()
namespace {
@ -361,21 +361,9 @@ Exporter::~Exporter()
{
}
// Beginnings of a fix for bug 1355.
// 'Other Uncompressed Files' Header option updates do not update
// the extension shown in the file dialog.
// Unfortunately, although we get the new extension here, we
// can't do anything with it as the FileDialog does not provide
// methods for setting its standard controls.
// We would need OS specific code that 'knows' about the system
// dialogs.
void Exporter::OnExtensionChanged(wxCommandEvent &evt) {
wxString ext = evt.GetString();
ext = ext.BeforeFirst(' ').Lower();
wxLogDebug("Extension changed to '.%s'", ext);
// wxString Name = mDialog->GetFilename();
// Name = Name.BeforeLast('.')+ext;
// mDialog->SetFilename(Name);
void Exporter::OnExtensionChanged(wxCommandEvent &evt)
{
mDialog->SetFileExtension(evt.GetString().BeforeFirst(' ').Lower());
}
void Exporter::OnHelp(wxCommandEvent& WXUNUSED(evt))
@ -644,7 +632,7 @@ bool Exporter::GetFilename()
}
wxString defext = mPlugins[mFormat]->GetExtension(mSubFormat).Lower();
//Bug 1304: Set a default path if none was given. For Export.
//Bug 1304: Set a default path if none was given. For Export.
mFilename = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path"));
mFilename.SetName(mProject->GetProjectName());
if (mFilename.GetName().empty())
@ -1051,6 +1039,31 @@ void Exporter::OnFilterChanged(wxFileCtrlEvent & evt)
return;
}
#if defined(__WXGTK__)
// On Windows and MacOS, changing the filter in the dialog
// automatically changes the extension of the current file
// name. GTK doesn't, so do it here.
{
FileNames::FileTypes fileTypes;
int i = -1;
for (const auto &pPlugin : mPlugins)
{
++i;
for (int j = 0; j < pPlugin->GetFormatCount(); j++)
{
auto mask = pPlugin->GetMask(j);
fileTypes.insert( fileTypes.end(), mask.begin(), mask.end() );
}
}
if (index < fileTypes.size())
{
mDialog->SetFileExtension(fileTypes[index].extensions[0].Lower());
}
}
#endif
mBook->ChangeSelection(index);
}

View File

@ -59,32 +59,49 @@ struct
static const kFormats[] =
{
#if defined(__WXMAC__)
{ SF_FORMAT_AIFF | SF_FORMAT_PCM_16, wxT("AIFF"), XO("AIFF (Apple) signed 16-bit PCM") },
{SF_FORMAT_AIFF | SF_FORMAT_PCM_16, wxT("AIFF"), XO("AIFF (Apple/SGI)")},
#endif
{ SF_FORMAT_WAV | SF_FORMAT_PCM_16, wxT("WAV"), XO("WAV (Microsoft) signed 16-bit PCM") },
{ SF_FORMAT_WAV | SF_FORMAT_PCM_24, wxT("WAV24"), XO("WAV (Microsoft) signed 24-bit PCM") },
{ SF_FORMAT_WAV | SF_FORMAT_FLOAT, wxT("WAVFLT"), XO("WAV (Microsoft) 32-bit float PCM") },
// { SF_FORMAT_WAV | SF_FORMAT_GSM610, wxT("GSM610"), XO("GSM 6.10 WAV (mobile)") },
{SF_FORMAT_WAV | SF_FORMAT_PCM_16, wxT("WAV"), XO("WAV (Microsoft)")},
{SF_FORMAT_WAV | SF_FORMAT_PCM_24, wxT("WAV24"), XO("WAV (Microsoft) signed 24-bit PCM")},
{SF_FORMAT_WAV | SF_FORMAT_FLOAT, wxT("WAVFLT"), XO("WAV (Microsoft) 32-bit float PCM")},
};
enum
{
#if defined(__WXMAC__)
FMT_AIFF,
#endif
FMT_WAV,
FMT_WAV24,
FMT_WAVFLT,
FMT_OTHER
};
//----------------------------------------------------------------------------
// Statics
//----------------------------------------------------------------------------
static int ReadExportFormatPref()
static int LoadOtherFormat(int def = 0)
{
#if defined(__WXMAC__)
return gPrefs->Read(wxT("/FileFormats/ExportFormat_SF1"),
(long int)(SF_FORMAT_AIFF | SF_FORMAT_PCM_16));
#else
return gPrefs->Read(wxT("/FileFormats/ExportFormat_SF1"),
(long int)(SF_FORMAT_WAV | SF_FORMAT_PCM_16));
#endif
return gPrefs->Read(wxString::Format(wxT("/FileFormats/ExportFormat_SF1")), def);
}
static void WriteExportFormatPref(int format)
static void SaveOtherFormat(int val)
{
gPrefs->Write(wxT("/FileFormats/ExportFormat_SF1"), (long int)format);
gPrefs->Write(wxString::Format(wxT("/FileFormats/ExportFormat_SF1")), val);
gPrefs->Flush();
}
static int LoadEncoding(int type, int def = 0)
{
return gPrefs->Read(wxString::Format(wxT("/FileFormats/ExportFormat_SF1_Type/%s_%x"),
sf_header_shortname(type), type), def);
}
static void SaveEncoding(int type, int val)
{
gPrefs->Write(wxString::Format(wxT("/FileFormats/ExportFormat_SF1_Type/%s_%x"),
sf_header_shortname(type), type), val);
gPrefs->Flush();
}
@ -103,80 +120,71 @@ public:
virtual ~ExportPCMOptions();
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
void OnShow(wxShowEvent & evt);
void OnHeaderChoice(wxCommandEvent & evt);
void OnEncodingChoice(wxCommandEvent & evt);
private:
bool ValidatePair(int format);
int GetFormat();
void GetTypes();
void GetEncodings(int enc = 0);
void SendSuffixEvent();
private:
std::vector<int> mHeaderIndexes;
TranslatableStrings mHeaderNames;
TranslatableStrings mEncodingNames;
wxChoice *mHeaderChoice;
wxChoice *mEncodingChoice;
int mHeaderFromChoice;
std::vector<int> mEncodingIndexes;
TranslatableStrings mEncodingNames;
wxChoice *mEncodingChoice;
int mEncodingFromChoice;
std::vector<int> mEncodingFormats;
int mSelFormat;
int mType;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(ExportPCMOptions, wxPanelWrapper)
EVT_CHOICE(ID_HEADER_CHOICE, ExportPCMOptions::OnHeaderChoice)
EVT_CHOICE(ID_ENCODING_CHOICE, ExportPCMOptions::OnEncodingChoice)
END_EVENT_TABLE()
ExportPCMOptions::ExportPCMOptions(wxWindow *parent, int selformat)
: wxPanelWrapper(parent, wxID_ANY)
{
int format;
// Remember the selection format
mSelFormat = selformat;
if (selformat < 0 || static_cast<unsigned int>(selformat) >= WXSIZEOF(kFormats))
// Init choices
mHeaderFromChoice = 0;
mEncodingFromChoice = 0;
if (mSelFormat < FMT_OTHER)
{
format = ReadExportFormatPref();
mType = kFormats[selformat].format & SF_FORMAT_TYPEMASK;
GetEncodings(mType & SF_FORMAT_SUBMASK);
}
else
{
format = kFormats[selformat].format;
}
mHeaderFromChoice = 0;
for (int i = 0, num = sf_num_headers(); i < num; i++) {
mHeaderNames.push_back( Verbatim( sf_header_index_name(i) ) );
if ((format & SF_FORMAT_TYPEMASK) == (int)sf_header_index_to_type(i))
mHeaderFromChoice = i;
}
mEncodingFromChoice = 0;
for (int i = 0, sel = 0, num = sf_num_encodings(); i < num; i++) {
int enc = sf_encoding_index_to_subtype(i);
int fmt = (format & SF_FORMAT_TYPEMASK) | enc;
bool valid = ValidatePair(fmt);
if (valid)
{
mEncodingNames.push_back( Verbatim( sf_encoding_index_name(i) ) );
mEncodingFormats.push_back(enc);
if ((format & SF_FORMAT_SUBMASK) == (int)sf_encoding_index_to_subtype(i))
mEncodingFromChoice = sel;
else
sel++;
}
GetTypes();
GetEncodings();
}
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
TransferDataToWindow();
TransferDataFromWindow();
parent->Bind(wxEVT_SHOW, &ExportPCMOptions::OnShow, this);
}
ExportPCMOptions::~ExportPCMOptions()
{
TransferDataFromWindow();
// Save the encoding
SaveEncoding(mType, sf_encoding_index_to_subtype(mEncodingIndexes[mEncodingFromChoice]));
}
void ExportPCMOptions::PopulateOrExchange(ShuttleGui & S)
@ -188,10 +196,13 @@ void ExportPCMOptions::PopulateOrExchange(ShuttleGui & S)
S.StartMultiColumn(2, wxCENTER);
{
S.SetStretchyCol(1);
mHeaderChoice = S.Id(ID_HEADER_CHOICE)
.AddChoice(XO("Header:"),
mHeaderNames,
mHeaderFromChoice);
if (mSelFormat == FMT_OTHER)
{
mHeaderChoice = S.Id(ID_HEADER_CHOICE)
.AddChoice(XO("Header:"),
mHeaderNames,
mHeaderFromChoice);
}
mEncodingChoice = S.Id(ID_ENCODING_CHOICE)
.AddChoice(XO("Encoding:"),
mEncodingNames,
@ -206,113 +217,163 @@ void ExportPCMOptions::PopulateOrExchange(ShuttleGui & S)
return;
}
///
///
bool ExportPCMOptions::TransferDataToWindow()
void ExportPCMOptions::OnShow(wxShowEvent & evt)
{
return true;
}
evt.Skip();
///
///
bool ExportPCMOptions::TransferDataFromWindow()
{
ShuttleGui S(this, eIsSavingToPrefs);
PopulateOrExchange(S);
gPrefs->Flush();
WriteExportFormatPref(GetFormat());
return true;
}
void ExportPCMOptions::OnHeaderChoice(wxCommandEvent & WXUNUSED(evt))
{
int format = sf_header_index_to_type(mHeaderChoice->GetSelection());
// Fix for Bug 1218 - AIFF with no option should default to 16 bit.
if( format == SF_FORMAT_AIFF )
format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16;
mEncodingNames.clear();
mEncodingChoice->Clear();
mEncodingFormats.clear();
int sel = wxNOT_FOUND;
int i,j;
int sfnum = sf_num_simple_formats();
std::vector<int> sfs;
for (i = 0; i < sfnum; i++)
// Since the initial file name may not have the "correct" extension,
// send off an event to have it changed. Note that this will be
// done every time a user changes filters in the dialog.
if (evt.IsShown())
{
SF_FORMAT_INFO *fi = sf_simple_format(i);
sfs.push_back(fi->format);
SendSuffixEvent();
}
}
void ExportPCMOptions::OnHeaderChoice(wxCommandEvent & evt)
{
evt.Skip();
// Remember new selection
mHeaderFromChoice = evt.GetInt();
// Get the type for this selection
mType = sf_header_index_to_type(mHeaderIndexes[mHeaderFromChoice]);
// Save the newly selected type
SaveOtherFormat(mType);
// Reload the encodings valid for this new type
GetEncodings();
// Repopulate the encoding choices
mEncodingChoice->Clear();
for (int i = 0, num = mEncodingNames.size(); i < num; ++i)
{
mEncodingChoice->AppendString(mEncodingNames[i].StrippedTranslation());
}
int num = sf_num_encodings();
for (i = 0; i < num; i++)
// Select the desired encoding
mEncodingChoice->SetSelection(mEncodingFromChoice);
// Send the event indicating a file suffix change.
SendSuffixEvent();
}
void ExportPCMOptions::OnEncodingChoice(wxCommandEvent & evt)
{
evt.Skip();
// Remember new selection
mEncodingFromChoice = evt.GetInt();
// And save it
SaveEncoding(mType, sf_encoding_index_to_subtype(mEncodingIndexes[mEncodingFromChoice]));
}
void ExportPCMOptions::GetTypes()
{
// Reset arrays
mHeaderIndexes.clear();
mHeaderNames.clear();
// Get the previously saved type. Note that this is ONLY used for
// the FMT_OTHER ("Other uncompressed files") types.
int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
// Rebuild the arrays
mHeaderFromChoice = 0;
for (int i = 0, num = sf_num_headers(); i < num; ++i)
{
int encSubtype = sf_encoding_index_to_subtype(i);
int fmt = format | encSubtype;
bool valid = ValidatePair(fmt);
if (valid)
int type = sf_header_index_to_type(i);
switch (type)
{
const auto name = sf_encoding_index_name(i);
mEncodingNames.push_back( Verbatim( name ) );
mEncodingChoice->Append(name);
mEncodingFormats.push_back(encSubtype);
for (j = 0; j < sfnum; j++)
{
int enc = sfs[j];
if ((sel == wxNOT_FOUND) && (fmt == enc))
// On the Mac, do not include in header list
#if defined(__WXMAC__)
case SF_FORMAT_AIFF:
break;
#endif
// Do not include in header list
case SF_FORMAT_WAV:
break;
default:
// Remember the index if this is the desired type
if (type == typ)
{
sel = mEncodingFormats.size() - 1;
break;
mHeaderFromChoice = mHeaderIndexes.size();
}
}
// Store index and name
mHeaderIndexes.push_back(i);
mHeaderNames.push_back(Verbatim(sf_header_index_name(i)));
break;
}
}
if (sel == wxNOT_FOUND) sel = 0;
mEncodingFromChoice = sel;
mEncodingChoice->SetSelection(sel);
ValidatePair(GetFormat());
TransferDataFromWindow();
// Send the event indicating a file suffix change.
// We pass the entire header string, which starts with the suffix.
wxCommandEvent event(AUDACITY_FILE_SUFFIX_EVENT, GetId());
event.SetEventObject(this);
event.SetString(mHeaderChoice->GetString(mHeaderChoice->GetSelection()));
ProcessWindowEvent(event);
// Refresh the current type
mType = sf_header_index_to_type(mHeaderIndexes[mHeaderFromChoice]);
}
int ExportPCMOptions::GetFormat()
void ExportPCMOptions::GetEncodings(int enc)
{
int hdr = sf_header_index_to_type(mHeaderChoice->GetSelection());
int sel = mEncodingChoice->GetSelection();
int enc = mEncodingFormats[sel];
return hdr | enc;
}
/// Calls a libsndfile library function to determine whether the user's
/// choice of sample encoding (e.g. pcm 16-bit or GSM 6.10 compression)
/// is compatible with their choice of file format (e.g. WAV, AIFF)
/// and enables/disables the OK button accordingly.
bool ExportPCMOptions::ValidatePair(int format)
{
SF_INFO info;
memset(&info, 0, sizeof(info));
info.frames = 0;
// Setup for queries
SF_INFO info = {};
info.samplerate = 44100;
info.channels = 1;
info.format = format;
info.sections = 1;
info.seekable = 0;
return sf_format_check(&info) != 0 ? true : false;
// Reset arrays
mEncodingIndexes.clear();
mEncodingNames.clear();
// If the encoding wasn't supplied, look it up
if (!(enc & SF_FORMAT_SUBMASK))
{
enc = LoadEncoding(mType);
}
enc &= SF_FORMAT_SUBMASK;
// Fix for Bug 1218 - AIFF with no encoding should default to 16 bit.
if (mType == SF_FORMAT_AIFF && enc == 0)
{
enc = SF_FORMAT_PCM_16;
}
// Rebuild the arrays
mEncodingFromChoice = 0;
for (int i = 0, num = sf_num_encodings(); i < num; ++i)
{
int sub = sf_encoding_index_to_subtype(i);
// Since we're traversing the subtypes linearly, we have to
// make sure it can be paired with our current type.
info.format = mType | sub;
if (sf_format_check(&info))
{
// If this subtype matches our last saved encoding, remember
// it's index so we can set it in the dialog.
if (sub == enc)
{
mEncodingFromChoice = mEncodingIndexes.size();
}
// Store index and name
mEncodingIndexes.push_back(i);
mEncodingNames.push_back(Verbatim(sf_encoding_index_name(i)));
}
}
}
void ExportPCMOptions::SendSuffixEvent()
{
// Synchronously process a change in suffix.
wxCommandEvent evt(AUDACITY_FILE_SUFFIX_EVENT, GetId());
evt.SetEventObject(this);
evt.SetString(sf_header_extension(mType));
ProcessWindowEvent(evt);
}
//----------------------------------------------------------------------------
@ -329,18 +390,19 @@ public:
void OptionsCreate(ShuttleGui &S, int format) override;
ProgressResult Export(AudacityProject *project,
std::unique_ptr<ProgressDialog> &pDialog,
unsigned channels,
const wxFileNameWrapper &fName,
bool selectedOnly,
double t0,
double t1,
MixerSpec *mixerSpec = NULL,
const Tags *metadata = NULL,
int subformat = 0) override;
std::unique_ptr<ProgressDialog> &pDialog,
unsigned channels,
const wxFileNameWrapper &fName,
bool selectedOnly,
double t0,
double t1,
MixerSpec *mixerSpec = NULL,
const Tags *metadata = NULL,
int subformat = 0) override;
// optional
wxString GetFormat(int index) override;
FileExtension GetExtension(int index) override;
bool CheckFileName(wxFileName &filename, int format) override;
unsigned GetMaxChannels(int index) override;
private:
void ReportTooBigError(wxWindow * pParent);
@ -352,48 +414,28 @@ private:
};
ExportPCM::ExportPCM()
: ExportPlugin()
: ExportPlugin()
{
SF_INFO si;
si.samplerate = 0;
si.channels = 0;
int format; // the index of the format we are setting up at the moment
int selformat; // the index of the format we are setting up at the moment
// Add the "special" formats first
for (size_t i = 0; i < WXSIZEOF(kFormats); i++)
for (size_t i = 0; i < WXSIZEOF(kFormats); ++i)
{
format = AddFormat() - 1;
si.format = kFormats[i].format;
for (si.channels = 1; sf_format_check(&si); si.channels++)
;
auto ext = sf_header_extension(si.format);
SetFormat(kFormats[i].name, format);
SetCanMetaData(true, format);
SetDescription(kFormats[i].desc, format);
AddExtension(ext, format);
SetMaxChannels(si.channels - 1, format);
selformat = AddFormat() - 1;
AddExtension(sf_header_extension(kFormats[i].format), selformat);
SetFormat(kFormats[i].name, selformat);
SetDescription(kFormats[i].desc, selformat);
SetCanMetaData(true, selformat);
SetMaxChannels(255, selformat);
}
// Then add the generic libsndfile formats
format = AddFormat() - 1; // store the index = 1 less than the count
SetFormat(wxT("LIBSNDFILE"), format);
SetCanMetaData(true, format);
SetDescription(XO("Other uncompressed files"), format);
auto allext = sf_get_all_extensions();
wxString wavext = sf_header_extension(SF_FORMAT_WAV); // get WAV ext.
#if defined(wxMSW)
// On Windows make sure WAV is at the beginning of the list of all possible
// extensions for this format
allext.erase( std::find( allext.begin(), allext.end(), wavext ) );
allext.insert(allext.begin(), wavext);
#endif
SetExtensions(allext, format);
SetMaxChannels(255, format);
// Then add the generic libsndfile "format"
selformat = AddFormat() - 1; // Matches FMT_OTHER
SetExtensions(sf_get_all_extensions(), selformat);
SetFormat(wxT("LIBSNDFILE"), selformat);
SetDescription(XO("Other uncompressed files"), selformat);
SetCanMetaData(true, selformat);
SetMaxChannels(255, selformat);
}
void ExportPCM::ReportTooBigError(wxWindow * pParent)
@ -422,29 +464,51 @@ void ExportPCM::ReportTooBigError(wxWindow * pParent)
* file type, or giving the user full control over libsndfile.
*/
ProgressResult ExportPCM::Export(AudacityProject *project,
std::unique_ptr<ProgressDialog> &pDialog,
unsigned numChannels,
const wxFileNameWrapper &fName,
bool selectionOnly,
double t0,
double t1,
MixerSpec *mixerSpec,
const Tags *metadata,
int subformat)
std::unique_ptr<ProgressDialog> &pDialog,
unsigned numChannels,
const wxFileNameWrapper &fName,
bool selectionOnly,
double t0,
double t1,
MixerSpec *mixerSpec,
const Tags *metadata,
int subformat)
{
double rate = ProjectSettings::Get( *project ).GetRate();
double rate = ProjectSettings::Get( *project ).GetRate();
const auto &tracks = TrackList::Get( *project );
// Set a default in case the settings aren't found
int sf_format;
if (subformat < 0 || static_cast<unsigned int>(subformat) >= WXSIZEOF(kFormats))
switch (subformat)
{
sf_format = ReadExportFormatPref();
}
else
{
sf_format = kFormats[subformat].format;
#if defined(__WXMAC__)
case FMT_AIFF:
sf_format = SF_FORMAT_AIFF;
break;
#endif
case FMT_WAV:
sf_format = SF_FORMAT_WAV;
break;
case FMT_WAV24:
case FMT_WAVFLT:
sf_format = kFormats[subformat].format;
break;
default:
// Retrieve the current format.
sf_format = LoadOtherFormat();
break;
}
// Prior to v2.4.0, sf_format will include the subtype. If not present,
// check for the format specific preference.
if (!(sf_format & SF_FORMAT_SUBMASK))
{
sf_format |= LoadEncoding(sf_format);
}
int fileFormat = sf_format & SF_FORMAT_TYPEMASK;
@ -478,7 +542,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
return ProgressResult::Cancelled;
}
if( sf_format == SF_FORMAT_WAVEX + SF_FORMAT_GSM610){
if (sf_format == SF_FORMAT_WAVEX + SF_FORMAT_GSM610) {
AudacityMessageBox(
XO("WAVEX and GSM 6.10 formats are not compatible") );
return ProgressResult::Cancelled;
@ -486,13 +550,16 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
// If we can't export exactly the format they requested,
// try the default format for that header type...
//
// LLL: I don't think this is valid since libsndfile checks
// for all allowed subtypes explicitly and doesn't provide
// for an unspecified subtype.
if (!sf_format_check(&info))
info.format = (info.format & SF_FORMAT_TYPEMASK);
if (!sf_format_check(&info)) {
AudacityMessageBox( XO("Cannot export audio in this format.") );
return ProgressResult::Cancelled;
}
const auto path = fName.GetFullPath();
if (f.Open(path, wxFile::write)) {
// Even though there is an sf_open() that takes a filename, use the one that
@ -929,44 +996,72 @@ bool ExportPCM::AddID3Chunk(
void ExportPCM::OptionsCreate(ShuttleGui &S, int format)
{
// default, full user control
if (format < 0 || static_cast<unsigned int>(format) >= WXSIZEOF(kFormats))
switch (format)
{
S.AddWindow( safenew ExportPCMOptions{ S.GetParent(), format } );
return;
#if defined(__WXMAC__)
case FMT_AIFF:
#endif
case FMT_WAV:
case FMT_OTHER:
S.AddWindow(safenew ExportPCMOptions{ S.GetParent(), format });
break;
default:
ExportPlugin::OptionsCreate(S, format);
break;
}
}
wxString ExportPCM::GetFormat(int index)
{
if (index != FMT_OTHER)
{
return ExportPlugin::GetFormat(index);
}
ExportPlugin::OptionsCreate(S, format);
// Get the saved type
int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
// Return the format name for that type
return sf_header_shortname(typ);
}
FileExtension ExportPCM::GetExtension(int index)
{
if (index == WXSIZEOF(kFormats)) {
// get extension libsndfile thinks is correct for currently selected format
return sf_header_extension(ReadExportFormatPref());
}
else {
// return the default
if (index != FMT_OTHER)
{
return ExportPlugin::GetExtension(index);
}
// Get the saved type
int typ = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
// Return the extension for that type
return sf_header_extension(typ);
}
bool ExportPCM::CheckFileName(wxFileName &filename, int format)
unsigned ExportPCM::GetMaxChannels(int index)
{
if (format == WXSIZEOF(kFormats) &&
IsExtension(filename.GetExt(), format)) {
// PRL: Bug1217
// If the user left the extension blank, then the
// file dialog will have defaulted the extension, beyond our control,
// to the first in the wildcard list or (Linux) the last-saved extension,
// ignoring what we try to do with the additional drop-down mHeaderChoice.
// Here we can intercept file name processing and impose the correct default.
// However this has the consequence that in case an explicit extension was typed,
// we override it without asking.
filename.SetExt(GetExtension(format));
SF_INFO si = {};
if (index < FMT_OTHER)
{
si.format = kFormats[index].format;
}
else
{
// Get the saved type
si.format = LoadOtherFormat() & SF_FORMAT_TYPEMASK;
si.format |= LoadEncoding(si.format);
}
return ExportPlugin::CheckFileName(filename, format);
for (si.channels = 1; sf_format_check(&si); si.channels++)
{
// just counting
}
// Return the max number of channels
return si.channels - 1;
}
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "PCM",