30#include <wx/checkbox.h>
31#include <wx/textctrl.h>
33#include <wx/radiobut.h>
34#include <wx/stattext.h>
48#if wxUSE_ACCESSIBILITY
68 {
"project",
XO(
"Entire &Project") },
69 {
"split",
XO(
"M&ultiple Files") },
70 {
"selection",
XO(
"Curren&t Selection") }
78 {
"tracks",
XO(
"Tracks") },
79 {
"labels",
XO(
"Labels") }
86 {
"name",
XO(
"Using Label/Track Name") },
87 {
"num_and_name",
XO(
"Numbering before Label/Track Name") },
88 {
"num_and_prefix",
XO(
"Numbering after File name prefix") }
157 const wxString& defaultName,
158 const wxString& defaultFormat)
165 PopulateOrExchange(
S);
167 SetMinSize({GetBestSize().GetWidth(), -1});
171 if(exportPath.empty())
173 filename.SetPath(exportPath);
176 filename.SetEmptyExt();
177 if(defaultName.empty())
179 filename.SetName(
_(
"untitled"));
181 filename.SetName(defaultName);
191 wxString
format = defaultFormat;
199 const auto hasLabels = !labelTracks.empty() &&
200 (*labelTracks.begin())->GetNumLabels() > 0;
207 mRangeSelection->Disable();
209 mRangeProject->SetValue(
true);
211 else if (!hasLabels && !hasMultipleWaveTracks)
212 mRangeSelection->MoveAfterInTabOrder(mRangeProject);
216 mSplitByLabels->Disable();
217 if (hasMultipleWaveTracks)
218 mSplitByTracks->SetValue(
true);
221 if (!hasMultipleWaveTracks)
223 mSplitByTracks->Disable();
225 mSplitByLabels->SetValue(
true);
228 if (!hasLabels && !hasMultipleWaveTracks)
230 mRangeSplit->Disable();
232 mRangeProject->SetValue(
true);
233 mSplitsPanel->Hide();
237 mSplitsPanel->Hide();
239 mExportOptionsPanel->SetCustomMappingEnabled(!mRangeSplit->GetValue());
241 mIncludeAudioBeforeFirstLabel->Enable(mSplitByLabels->GetValue());
244 mSplitFileNamePrefix->Disable();
258#if defined(__WXMSW__)
269 S.StartVerticalLay();
282 S.StartHorizontalLay(wxSHRINK | wxALIGN_TOP);
284 if(
auto prompt =
S.AddPrompt(
XO(
"Export Range:")))
285 prompt->SetMinSize({145, -1});
287 S.EndHorizontalLay();
289 S.StartVerticalLay();
294 .Name(
XO(
"Export entire project"))
297 .Name(
XO(
"Export multiple files"))
300 .Name(
XO(
"Export current selection"))
302#if wxUSE_ACCESSIBILITY
308 S.EndRadioButtonGroup();
330 S.StartMultiColumn(2);
332 S.StartStatic(
XO(
"Split files based on:"));
334 S.StartVerticalLay();
341 S.EndRadioButtonGroup();
343 S.StartHorizontalLay(wxALIGN_TOP);
350 S.EndHorizontalLay();
356 S.StartStatic(
XO(
"Name files:"));
358 S.StartVerticalLay();
366 S.EndRadioButtonGroup();
367 S.StartHorizontalLay(wxALIGN_TOP);
372 .AddTextBox(
XO(
"File name prefix:"), {}, 0);
374 S.EndHorizontalLay();
393 S.StartHorizontalLay(wxEXPAND);
396 S.AddSpace(1, 1, wxEXPAND);
397 S.Id(wxID_CANCEL).AddButton(
XO(
"&Cancel"), wxBOTTOM);
398 S.Id(wxID_OK).AddButton(
XO(
"&Export"), wxRIGHT | wxBOTTOM,
true);
400 S.EndHorizontalLay();
452 std::vector<Tags*> tags;
453 std::vector<wxString>
names;
458 tags.push_back(&spec.tags);
459 names.push_back(spec.filename.GetFullName());
467 XO(
"Edit Metadata Tags"),
XO(
"Exported Tags"));
479 if(selectedPlugin ==
nullptr)
483 if(!parameters.has_value())
488 if(!wxDirExists(path))
489 wxFileName::Mkdir(path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
491 if(!wxDirExists(path))
514 ?
XO(
"Successfully exported the following %lld file(s).")
516 ?
XO(
"Something went wrong after exporting the following %lld file(s).")
518 ?
XO(
"Export canceled after exporting the following %lld file(s).")
520 ?
XO(
"Export stopped after exporting the following %lld file(s).")
521 :
XO(
"Something went really wrong after exporting the following %lld file(s).")
522 ).
Format((
long long) exportedFiles.size());
525 for (
auto& path : exportedFiles)
526 fileList += path +
'\n';
541 if (filename.FileExists()) {
543 XO(
"A file named \"%s\" already exists. Replace?")
544 .
Format( filename.GetFullPath() ),
546 wxYES_NO | wxICON_EXCLAMATION);
547 if (result != wxYES) {
554 .
SetPlugin(selectedPlugin, selectedFormat)
562 auto t0 = selectedOnly
563 ? std::max(.0, viewInfo.selectedRegion.t0())
566 auto t1 = selectedOnly
571 if(exportedTracks.empty())
574 selectedOnly ?
XO(
"All selected audio is muted.") :
XO(
"All audio is muted."),
583 builder.
SetRange(t0, t1, selectedOnly);
585 std::unique_ptr<MixerOptions::Downmix> tempMixerSpec;
594 std::vector<bool> channelMask(
595 tracks.sum([](
const auto track) { return track->NChannels(); }),
597 unsigned trackIndex = 0;
598 for(
const auto track :
tracks)
602 channelMask.assign(channelMask.size(),
false);
603 for(
unsigned i = 0; i < track->NChannels(); ++i)
604 channelMask[trackIndex++] =
true;
607 if(!track->GetMute() && (!selectedOnly || track->GetSelected()))
609 for(
unsigned i = 0; i < track->NChannels(); ++i)
610 channelMask[trackIndex++] =
true;
613 trackIndex += track->NChannels();
646 auto enableMeta =
false;
659 if(selectedPlugin ==
nullptr)
683 const auto numLabels = labels->GetNumLabels();
685 auto numFiles = numLabels;
687 std::vector<ExportSetting> exportSettings;
688 exportSettings.reserve(numFiles);
711 while( fileIndex < numLabels ) {
714 if( fileIndex < 0 ) {
719 info = labels->GetLabel(fileIndex);
727 }
else if( fileIndex < numLabels - 1 ) {
729 const LabelStruct *info1 = labels->GetLabel(fileIndex+1);
736 name =
_(
"untitled");
743 name.Printf(
wxT(
"%s-%02d"), prefix, fileIndex + 1);
744 }
else if( addNumber ) {
747 name.Prepend(wxString::Format(
wxT(
"%02d-"), fileIndex + 1));
762 if (exportSettings.empty())
768 setting.
tags = exportSettings.back().tags;
775 exportSettings.push_back(setting);
783 const wxString& prefix)
792 const auto numWaveTracks = waveTracks.size();
797 std::vector<ExportSetting> exportSettings;
799 exportSettings.reserve(numWaveTracks);
810 for (
auto tr : waveTracks) {
813 setting.
t0 = skipSilenceAtBeginning ? tr->GetStartTime() : 0;
814 setting.
t1 = tr->GetEndTime();
818 title = tr->GetName();
826 wxString::Format(
wxT(
"%02d-"), fileIndex+1));
830 name = (wxString::Format(
wxT(
"%s-%02d"), prefix, fileIndex+1));
847 if(exportSettings.empty())
853 setting.
tags = exportSettings.back().tags;
859 exportSettings.push_back(setting);
878 if( activeSetting.filename.GetName().empty() )
882 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
883 activeSetting.t0, activeSetting.t1,
false, activeSetting.tags, exporterFiles);
888 XO(
"Continue to export remaining files?"),
890 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
891 if (dlgMessage.ShowModal() != wxID_YES ) {
922 tr->SetSelected(
false);
927 for (
auto tr : waveTracks) {
929 wxLogDebug(
"Get setting %i", count );
932 if( activeSetting.filename.GetName().empty() ){
939 tr->SetSelected(
true);
942 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
943 activeSetting.t0, activeSetting.t1,
true, activeSetting.tags, exporterFiles);
948 XO(
"Continue to export remaining files?"),
950 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
951 if (dlgMessage.ShowModal() != wxID_YES ) {
971 const wxFileName& filename,
973 double t0,
double t1,
bool selectedOnly,
979 wxLogDebug(
wxT(
"Doing multiple Export: File name \"%s\""), (filename.GetFullName()));
980 wxLogDebug(
wxT(
"Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
982 wxLogDebug(
wxT(
"Selected Region Only"));
984 wxLogDebug(
wxT(
"Whole Project"));
993 backup.SetName(
name.GetName() +
994 wxString::Format(
wxT(
"%d"), suffix));
997 while (backup.FileExists());
998 ::wxRenameFile(filename.GetFullPath(), backup.GetFullPath());
1003 wxString base(
name.GetName());
1004 while (
name.FileExists()) {
1005 name.SetName(wxString::Format(
wxT(
"%s-%d"), base, i++));
1009 bool success{
false};
1010 const wxString fullPath{
name.GetFullPath()};
1012 auto cleanup =
finally( [&] {
1013 if (backup.IsOk()) {
1016 ::wxRemoveFile(backup.GetFullPath());
1019 ::wxRemoveFile(fullPath);
1020 ::wxRenameFile(backup.GetFullPath(), fullPath);
1026 ::wxRemoveFile(fullPath);
1034 .SetParameters(parameters)
1035 .SetRange(t0, t1, selectedOnly)
1037 .SetNumChannels(channels)
1038 .SetFileName(fullPath)
1039 .SetSampleRate(mExportOptionsPanel->GetSampleRate())
1046 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 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)
NotifyingSelectedRegion selectedRegion
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.