30#include <wx/checkbox.h>
31#include <wx/textctrl.h>
33#include <wx/radiobut.h>
34#include <wx/stattext.h>
48#if wxUSE_ACCESSIBILITY
73 {
"project",
XO(
"Entire &Project") },
74 {
"split",
XO(
"M&ultiple Files") },
75 {
"selection",
XO(
"Curren&t Selection") }
83 {
"tracks",
XO(
"Tracks") },
84 {
"labels",
XO(
"Labels") }
91 {
"name",
XO(
"Using Label/Track Name") },
92 {
"num_and_name",
XO(
"Numbering before Label/Track Name") },
93 {
"num_and_prefix",
XO(
"Numbering after File name prefix") }
162 const wxString& defaultName,
163 const wxString& defaultFormat,
171 PopulateOrExchange(
S);
173 SetMinSize({GetBestSize().GetWidth(), -1});
177 if(exportPath.empty())
179 filename.SetPath(exportPath);
182 filename.SetEmptyExt();
183 if(defaultName.empty())
185 filename.SetName(
_(
"untitled"));
187 filename.SetName(defaultName);
197 wxString
format = defaultFormat;
205 const auto hasLabels = !labelTracks.empty() &&
206 (*labelTracks.begin())->GetNumLabels() > 0;
210 mRangeSelection->Enable(hasSelectedAudio);
211 mRangeSplit->Enable(hasLabels || hasMultipleWaveTracks);
213 mSplitByLabels->Enable(hasLabels);
214 mSplitByTracks->Enable(hasMultipleWaveTracks);
216 if(mRangeSelection->IsEnabled() && mode == ExportMode::SelectedOnly)
218 mRangeSelection->SetValue(
true);
223 mRangeProject->SetValue(
true);
226 mRangeProject->SetValue(
true);
228 if(!hasLabels && hasMultipleWaveTracks)
229 mSplitByTracks->SetValue(
true);
230 if (!hasMultipleWaveTracks && hasLabels)
231 mSplitByLabels->SetValue(
true);
234 if (mRangeSelection->IsEnabled() && !hasLabels && !hasMultipleWaveTracks)
235 mRangeSelection->MoveAfterInTabOrder(mRangeProject);
238 mSplitsPanel->Hide();
240 mExportOptionsPanel->SetCustomMappingEnabled(!mRangeSplit->GetValue());
242 mIncludeAudioBeforeFirstLabel->Enable(mSplitByLabels->GetValue());
245 mSplitFileNamePrefix->Disable();
259#if defined(__WXMSW__)
270 S.StartVerticalLay();
283 S.StartHorizontalLay(wxSHRINK | wxALIGN_TOP);
285 if(
auto prompt =
S.AddPrompt(
XO(
"Export Range:")))
286 prompt->SetMinSize({145, -1});
288 S.EndHorizontalLay();
290 S.StartVerticalLay();
295 .Name(
XO(
"Export entire project"))
298 .Name(
XO(
"Export multiple files"))
301 .Name(
XO(
"Export current selection"))
303#if wxUSE_ACCESSIBILITY
309 S.EndRadioButtonGroup();
331 S.StartMultiColumn(2);
333 S.StartStatic(
XO(
"Split files based on:"));
335 S.StartVerticalLay();
342 S.EndRadioButtonGroup();
344 S.StartHorizontalLay(wxALIGN_TOP);
351 S.EndHorizontalLay();
357 S.StartStatic(
XO(
"Name files:"));
359 S.StartVerticalLay();
367 S.EndRadioButtonGroup();
368 S.StartHorizontalLay(wxALIGN_TOP);
373 .AddTextBox(
XO(
"File name prefix:"), {}, 0);
375 S.EndHorizontalLay();
394 S.StartHorizontalLay(wxEXPAND);
397 S.AddSpace(1, 1, wxEXPAND);
398 S.Id(wxID_CANCEL).AddButton(
XO(
"&Cancel"), wxBOTTOM);
399 S.Id(wxID_OK).AddButton(
XO(
"&Export"), wxRIGHT | wxBOTTOM,
true);
401 S.EndHorizontalLay();
453 std::vector<Tags*> tags;
454 std::vector<wxString>
names;
459 tags.push_back(&spec.tags);
460 names.push_back(spec.filename.GetFullName());
468 XO(
"Edit Metadata Tags"),
XO(
"Exported Tags"));
480 if(selectedPlugin ==
nullptr)
484 if(!parameters.has_value())
489 if(!wxDirExists(path))
490 wxFileName::Mkdir(path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
492 if(!wxDirExists(path))
515 ?
XO(
"Successfully exported the following %lld file(s).")
517 ?
XO(
"Something went wrong after exporting the following %lld file(s).")
519 ?
XO(
"Export canceled after exporting the following %lld file(s).")
521 ?
XO(
"Export stopped after exporting the following %lld file(s).")
522 :
XO(
"Something went really wrong after exporting the following %lld file(s).")
523 ).
Format((
long long) exportedFiles.size());
526 for (
auto& path : exportedFiles)
527 fileList += path +
'\n';
542 if (filename.FileExists()) {
544 XO(
"A file named \"%s\" already exists. Replace?")
545 .
Format( filename.GetFullPath() ),
547 wxYES_NO | wxICON_EXCLAMATION);
548 if (result != wxYES) {
555 .
SetPlugin(selectedPlugin, selectedFormat)
563 auto t0 = selectedOnly
564 ? std::max(.0, viewInfo.selectedRegion.t0())
567 auto t1 = selectedOnly
572 if(exportedTracks.empty())
575 selectedOnly ?
XO(
"All selected audio is muted.") :
XO(
"All audio is muted."),
584 builder.
SetRange(t0, t1, selectedOnly);
586 std::unique_ptr<MixerOptions::Downmix> tempMixerSpec;
595 std::vector<bool> channelMask(
596 tracks.sum([](
const auto track) { return track->NChannels(); }),
598 unsigned trackIndex = 0;
599 for(
const auto track :
tracks)
603 channelMask.assign(channelMask.size(),
false);
604 for(
unsigned i = 0; i < track->NChannels(); ++i)
605 channelMask[trackIndex++] =
true;
608 if(!track->GetMute() && (!selectedOnly || track->GetSelected()))
610 for(
unsigned i = 0; i < track->NChannels(); ++i)
611 channelMask[trackIndex++] =
true;
614 trackIndex += track->NChannels();
647 auto enableMeta =
false;
660 if(selectedPlugin ==
nullptr)
684 const auto numLabels = labels->GetNumLabels();
686 auto numFiles = numLabels;
688 std::vector<ExportSetting> exportSettings;
689 exportSettings.reserve(numFiles);
712 while( fileIndex < numLabels ) {
715 if( fileIndex < 0 ) {
720 info = labels->GetLabel(fileIndex);
728 }
else if( fileIndex < numLabels - 1 ) {
730 const LabelStruct *info1 = labels->GetLabel(fileIndex+1);
737 name =
_(
"untitled");
744 name.Printf(
wxT(
"%s-%02d"), prefix, fileIndex + 1);
745 }
else if( addNumber ) {
748 name.Prepend(wxString::Format(
wxT(
"%02d-"), fileIndex + 1));
763 if (exportSettings.empty())
769 setting.
tags = exportSettings.back().tags;
776 exportSettings.push_back(setting);
784 const wxString& prefix)
793 const auto numWaveTracks = waveTracks.size();
798 std::vector<ExportSetting> exportSettings;
800 exportSettings.reserve(numWaveTracks);
811 for (
auto tr : waveTracks) {
814 setting.
t0 = skipSilenceAtBeginning ? tr->GetStartTime() : 0;
815 setting.
t1 = tr->GetEndTime();
819 title = tr->GetName();
827 wxString::Format(
wxT(
"%02d-"), fileIndex+1));
831 name = (wxString::Format(
wxT(
"%s-%02d"), prefix, fileIndex+1));
848 if(exportSettings.empty())
854 setting.
tags = exportSettings.back().tags;
860 exportSettings.push_back(setting);
879 if( activeSetting.filename.GetName().empty() )
883 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
884 activeSetting.t0, activeSetting.t1,
false, activeSetting.tags, exporterFiles);
889 XO(
"Continue to export remaining files?"),
891 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
892 if (dlgMessage.ShowModal() != wxID_YES ) {
923 tr->SetSelected(
false);
928 for (
auto tr : waveTracks) {
930 wxLogDebug(
"Get setting %i", count );
933 if( activeSetting.filename.GetName().empty() ){
940 tr->SetSelected(
true);
943 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
944 activeSetting.t0, activeSetting.t1,
true, activeSetting.tags, exporterFiles);
949 XO(
"Continue to export remaining files?"),
951 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
952 if (dlgMessage.ShowModal() != wxID_YES ) {
972 const wxFileName& filename,
974 double t0,
double t1,
bool selectedOnly,
980 wxLogDebug(
wxT(
"Doing multiple Export: File name \"%s\""), (filename.GetFullName()));
981 wxLogDebug(
wxT(
"Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
983 wxLogDebug(
wxT(
"Selected Region Only"));
985 wxLogDebug(
wxT(
"Whole Project"));
994 backup.SetName(
name.GetName() +
995 wxString::Format(
wxT(
"%d"), suffix));
998 while (backup.FileExists());
999 ::wxRenameFile(filename.GetFullPath(), backup.GetFullPath());
1004 wxString base(
name.GetName());
1005 while (
name.FileExists()) {
1006 name.SetName(wxString::Format(
wxT(
"%s-%d"), base, i++));
1010 bool success{
false};
1011 const wxString fullPath{
name.GetFullPath()};
1013 auto cleanup =
finally( [&] {
1014 if (backup.IsOk()) {
1017 ::wxRemoveFile(backup.GetFullPath());
1020 ::wxRemoveFile(fullPath);
1021 ::wxRenameFile(backup.GetFullPath(), fullPath);
1027 ::wxRemoveFile(fullPath);
1035 .SetParameters(parameters)
1036 .SetRange(t0, t1, selectedOnly)
1038 .SetNumChannels(channels)
1039 .SetFileName(fullPath)
1040 .SetSampleRate(mExportOptionsPanel->GetSampleRate())
1047 exportedFiles.push_back(fullPath);
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
void ShowExportErrorDialog(const TranslatableString &message, const TranslatableString &caption, bool allowReporting)
wxString FileExtension
File extension, not including any leading dot.
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
This specialization of Setting for bool adds a Toggle method to negate the saved value.
double GetStartTime() const
Get the minimum of Start() values of intervals, or 0 when none.
ExportResult DoExportSplitByTracks(const ExportPlugin &plugin, int formatIndex, const ExportProcessor::Parameters ¶meters, FilePaths &exporterFiles)
void OnEditMetadata(wxCommandEvent &event)
void OnIncludeAudioBeforeFirstLabelChange(wxCommandEvent &)
wxRadioButton * mRangeSplit
wxCheckBox * mSkipSilenceAtBeginning
bool mExportSettingsDirty
wxCheckBox * mOverwriteExisting
void UpdateLabelExportSettings(const ExportPlugin &plugin, int formatIndex, bool byName, bool addNumber, const wxString &prefix)
void OnHelp(wxCommandEvent &event)
wxRadioButton * mRangeSelection
void OnExport(wxCommandEvent &event)
void OnTrimBlankSpaceBeforeFirstClip(wxCommandEvent &)
void PopulateOrExchange(ShuttleGui &S)
ExportResult DoExport(const ExportPlugin &plugin, int formatIndex, const ExportProcessor::Parameters ¶meters, const wxFileName &filename, int channels, double t0, double t1, bool selectedOnly, const Tags &tags, FilePaths &exportedFiles)
void OnSplitNamePolicyChange(wxCommandEvent &event)
void OnExportRangeChange(wxCommandEvent &event)
void OnFileNamePrefixChange(wxCommandEvent &)
wxRadioButton * mSplitUseName
bool Show(bool show=true) override
ExportResult DoExportSplitByLabels(const ExportPlugin &plugin, int formatIndex, const ExportProcessor::Parameters ¶meters, FilePaths &exporterFiles)
void UpdateExportSettings()
wxRadioButton * mSplitUseNumAndName
wxRadioButton * mSplitByTracks
ExportFilePanel * mExportOptionsPanel
~ExportAudioDialog() override
wxRadioButton * mSplitByLabels
void UpdateTrackExportSettings(const ExportPlugin &plugin, int formatIndex, bool byName, bool addNumber, const wxString &prefix)
wxTextCtrl * mSplitFileNamePrefix
void OnFormatChange(wxCommandEvent &event)
AudacityProject & mProject
void OnSplitModeChange(wxCommandEvent &event)
wxCheckBox * mIncludeAudioBeforeFirstLabel
std::vector< ExportSetting > mExportSettings
wxRadioButton * mRangeProject
wxRadioButton * mSplitUseNumAndPrefix
const ExportPlugin * GetPlugin() const
int GetSampleRate() const
void SetCustomMappingEnabled(bool enabled)
MixerOptions::Downmix * GetMixerSpec() const
std::optional< ExportProcessor::Parameters > GetParameters() const
Main class to control the export function.
virtual FormatInfo GetFormatInfo(int index) const =0
Returns FormatInfo structure for given index if it's valid, or a default one. FormatInfo::format isn'...
std::vector< std::tuple< ExportOptionID, ExportValue > > Parameters
ExportTaskBuilder & SetPlugin(const ExportPlugin *plugin, int format=0) noexcept
ExportTaskBuilder & SetMixerSpec(MixerOptions::Downmix *mixerSpec) noexcept
ExportTask Build(AudacityProject &project)
ExportTaskBuilder & SetParameters(ExportProcessor::Parameters parameters) noexcept
ExportTaskBuilder & SetNumChannels(unsigned numChannels) noexcept
ExportTaskBuilder & SetSampleRate(double sampleRate) noexcept
ExportTaskBuilder & SetFileName(const wxFileName &filename)
ExportTaskBuilder & SetRange(double t0, double t1, bool selectedOnly=false) noexcept
static TrackIterRange< const WaveTrack > FindExportWaveTracks(const TrackList &tracks, bool selectedOnly)
static bool HasSelectedAudio(const AudacityProject &project)
static void RegisterExportHook(ExportHook hook, Priority=DEFAULT_EXPORT_HOOK_PRIORITY)
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
static void ShowInfoDialog(wxWindow *parent, const TranslatableString &dlogTitle, const TranslatableString &shortMsg, const wxString &message, const int xSize, const int ySize)
Displays cuttable information in a text ctrl, with an OK button.
static ImportExport & Get(AudacityProject &project)
void SetPreferredExportRate(double rate)
double GetPreferredExportRate() const
static constexpr double InvalidRate
static bool SanitiseFilename(wxString &name, const wxString &sub)
Check a proposed file name string for illegal characters and remove them return true iff name is "vis...
A LabelStruct holds information for ONE label in a LabelTrack.
SelectedRegion selectedRegion
A LabelTrack is a Track that holds labels (LabelStruct).
static SelectionState & Get(AudacityProject &project)
bool Write(const T &value)
Write value to config and return true if successful.
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Specialization of Setting for strings.
double GetEndTime() const
Return the greatest end time of the tracks, or 0 when no tracks.
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static ViewInfo & Get(AudacityProject &project)
A Track that contains audio waveform data.
bool GetMute() const override
May vary asynchronously.
bool GetSolo() const override
May vary asynchronously.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
IMPORT_EXPORT_API ExportResult Show(ExportTask exportTask)
void ExceptionWrappedCall(Callable callable)
FILES_API void MakeNameUnique(FilePaths &otherNames, wxFileName &newName)
FILES_API FilePath FindDefaultPath(Operation op)
constexpr auto sampleRate
ChoiceSetting ExportAudioSplitMode
const bool hookRegistered
BoolSetting ExportAudioOverwriteExisting
BoolSetting ExportAudioIncludeAudioBeforeFirstLabel
StringSetting ExportAudioDefaultFormat
BoolSetting ExportAudioSkipSilenceAtBeginning
ChoiceSetting ExportAudioSplitNamePolicy
StringSetting ExportAudioDefaultPath
@ TrimBlankSpaceBeforeFirstClipID
@ OverwriteExistingFilesID
@ IncludeAudioBeforeFirstLabelID
@ ExportSplitNamePolicyTrackNameID
@ ExportSplitNamePolicyNumberingBeforeNameID
@ ExportSplitNamePolicyNumberingAfterPrefixID
ChoiceSetting ExportAudioExportRange
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
const char * begin(const char *str) noexcept
A private class used to store the information needed to do an export.