30#include <wx/checkbox.h>
31#include <wx/textctrl.h>
33#include <wx/radiobut.h>
34#include <wx/stattext.h>
49#if wxUSE_ACCESSIBILITY
74 {
"project",
XO(
"Entire &Project") },
75 {
"split",
XO(
"M&ultiple Files") },
76 {
"selection",
XO(
"Curren&t Selection") }
84 {
"tracks",
XO(
"Tracks") },
85 {
"labels",
XO(
"Labels") }
92 {
"name",
XO(
"Using Label/Track Name") },
93 {
"num_and_name",
XO(
"Numbering before Label/Track Name") },
94 {
"num_and_prefix",
XO(
"Numbering after File name prefix") }
163 const wxString& defaultName,
164 const wxString& defaultFormat,
172 PopulateOrExchange(
S);
174 SetMinSize({GetBestSize().GetWidth(), -1});
178 if(exportPath.empty())
180 filename.SetPath(exportPath);
183 filename.SetEmptyExt();
184 if(defaultName.empty())
186 filename.SetName(
_(
"untitled"));
188 filename.SetName(defaultName);
198 wxString
format = defaultFormat;
206 const auto hasLabels = !labelTracks.empty() &&
207 (*labelTracks.begin())->GetNumLabels() > 0;
211 mRangeSelection->Enable(hasSelectedAudio);
212 mRangeSplit->Enable(hasLabels || hasMultipleWaveTracks);
214 mSplitByLabels->Enable(hasLabels);
215 mSplitByTracks->Enable(hasMultipleWaveTracks);
217 if(mRangeSelection->IsEnabled() && mode == ExportMode::SelectedOnly)
219 mRangeSelection->SetValue(
true);
224 mRangeProject->SetValue(
true);
227 mRangeProject->SetValue(
true);
229 if(!hasLabels && hasMultipleWaveTracks)
230 mSplitByTracks->SetValue(
true);
231 if (!hasMultipleWaveTracks && hasLabels)
232 mSplitByLabels->SetValue(
true);
235 if (mRangeSelection->IsEnabled() && !hasLabels && !hasMultipleWaveTracks)
236 mRangeSelection->MoveAfterInTabOrder(mRangeProject);
239 mSplitsPanel->Hide();
241 mExportOptionsPanel->SetCustomMappingEnabled(
242 !mRangeSplit->GetValue() &&
247 mIncludeAudioBeforeFirstLabel->Enable(mSplitByLabels->GetValue());
250 mSplitFileNamePrefix->Disable();
264#if defined(__WXMSW__)
275 S.StartVerticalLay();
288 S.StartHorizontalLay(wxSHRINK | wxALIGN_TOP);
290 if(
auto prompt =
S.AddPrompt(
XO(
"Export Range:")))
291 prompt->SetMinSize({145, -1});
293 S.EndHorizontalLay();
295 S.StartVerticalLay();
300 .Name(
XO(
"Export entire project"))
303 .Name(
XO(
"Export multiple files"))
306 .Name(
XO(
"Export current selection"))
308#if wxUSE_ACCESSIBILITY
314 S.EndRadioButtonGroup();
336 S.StartMultiColumn(2);
338 S.StartStatic(
XO(
"Split files based on:"));
340 S.StartVerticalLay();
347 S.EndRadioButtonGroup();
349 S.StartHorizontalLay(wxALIGN_TOP);
356 S.EndHorizontalLay();
362 S.StartStatic(
XO(
"Name files:"));
364 S.StartVerticalLay();
372 S.EndRadioButtonGroup();
373 S.StartHorizontalLay(wxALIGN_TOP);
378 .AddTextBox(
XO(
"File name prefix:"), {}, 0);
380 S.EndHorizontalLay();
399 S.StartHorizontalLay(wxEXPAND);
402 S.AddSpace(1, 1, wxEXPAND);
403 S.Id(wxID_CANCEL).AddButton(
XO(
"&Cancel"), wxBOTTOM);
404 S.Id(wxID_OK).AddButton(
XO(
"&Export"), wxRIGHT | wxBOTTOM,
true);
406 S.EndHorizontalLay();
458 std::vector<Tags*> tags;
459 std::vector<wxString>
names;
464 tags.push_back(&spec.tags);
465 names.push_back(spec.filename.GetFullName());
473 XO(
"Edit Metadata Tags"),
XO(
"Exported Tags"));
485 if(selectedPlugin ==
nullptr)
489 if(!parameters.has_value())
494 if(!wxDirExists(path))
495 wxFileName::Mkdir(path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
497 if(!wxDirExists(path))
520 ?
XO(
"Successfully exported the following %lld file(s).")
522 ?
XO(
"Something went wrong after exporting the following %lld file(s).")
524 ?
XO(
"Export canceled after exporting the following %lld file(s).")
526 ?
XO(
"Export stopped after exporting the following %lld file(s).")
527 :
XO(
"Something went really wrong after exporting the following %lld file(s).")
528 ).
Format((
long long) exportedFiles.size());
531 for (
auto& path : exportedFiles)
532 fileList += path +
'\n';
547 if (filename.FileExists()) {
549 XO(
"A file named \"%s\" already exists. Replace?")
550 .
Format( filename.GetFullPath() ),
552 wxYES_NO | wxICON_EXCLAMATION);
553 if (result != wxYES) {
560 .
SetPlugin(selectedPlugin, selectedFormat)
568 auto t0 = selectedOnly
569 ? std::max(.0, viewInfo.selectedRegion.t0())
572 auto t1 = selectedOnly
577 if(exportedTracks.empty())
580 selectedOnly ?
XO(
"All selected audio is muted.") :
XO(
"All audio is muted."),
589 builder.
SetRange(t0, t1, selectedOnly);
591 std::unique_ptr<MixerOptions::Downmix> tempMixerSpec;
600 std::vector<bool> channelMask(
601 tracks.sum([](
const auto track) { return track->NChannels(); }),
603 unsigned trackIndex = 0;
604 for(
const auto track :
tracks)
608 channelMask.assign(channelMask.size(),
false);
609 for(
unsigned i = 0; i < track->NChannels(); ++i)
610 channelMask[trackIndex++] =
true;
613 if(!track->GetMute() && (!selectedOnly || track->GetSelected()))
615 for(
unsigned i = 0; i < track->NChannels(); ++i)
616 channelMask[trackIndex++] =
true;
619 trackIndex += track->NChannels();
652 auto enableMeta =
false;
665 if(selectedPlugin ==
nullptr)
689 const auto numLabels = labels->GetNumLabels();
691 auto numFiles = numLabels;
693 std::vector<ExportSetting> exportSettings;
694 exportSettings.reserve(numFiles);
717 while( fileIndex < numLabels ) {
720 if( fileIndex < 0 ) {
725 info = labels->GetLabel(fileIndex);
733 }
else if( fileIndex < numLabels - 1 ) {
735 const LabelStruct *info1 = labels->GetLabel(fileIndex+1);
742 name =
_(
"untitled");
749 name.Printf(
wxT(
"%s-%02d"), prefix, fileIndex + 1);
750 }
else if( addNumber ) {
753 name.Prepend(wxString::Format(
wxT(
"%02d-"), fileIndex + 1));
768 if (exportSettings.empty())
774 setting.
tags = exportSettings.back().tags;
781 exportSettings.push_back(setting);
789 const wxString& prefix)
798 const auto numWaveTracks = waveTracks.size();
803 std::vector<ExportSetting> exportSettings;
805 exportSettings.reserve(numWaveTracks);
816 for (
auto tr : waveTracks) {
819 setting.
t0 = skipSilenceAtBeginning ? tr->GetStartTime() : 0;
820 setting.
t1 = tr->GetEndTime();
824 title = tr->GetName();
832 wxString::Format(
wxT(
"%02d-"), fileIndex+1));
836 name = (wxString::Format(
wxT(
"%s-%02d"), prefix, fileIndex+1));
853 if(exportSettings.empty())
859 setting.
tags = exportSettings.back().tags;
865 exportSettings.push_back(setting);
884 if( activeSetting.filename.GetName().empty() )
888 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
889 activeSetting.t0, activeSetting.t1,
false, activeSetting.tags, exporterFiles);
894 XO(
"Continue to export remaining files?"),
896 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
897 if (dlgMessage.ShowModal() != wxID_YES ) {
928 tr->SetSelected(
false);
933 for (
auto tr : waveTracks) {
935 wxLogDebug(
"Get setting %i", count );
938 if( activeSetting.filename.GetName().empty() ){
945 tr->SetSelected(
true);
948 ok =
DoExport(plugin, formatIndex, parameters, activeSetting.filename, activeSetting.channels,
949 activeSetting.t0, activeSetting.t1,
true, activeSetting.tags, exporterFiles);
954 XO(
"Continue to export remaining files?"),
956 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
957 if (dlgMessage.ShowModal() != wxID_YES ) {
977 const wxFileName& filename,
979 double t0,
double t1,
bool selectedOnly,
985 wxLogDebug(
wxT(
"Doing multiple Export: File name \"%s\""), (filename.GetFullName()));
986 wxLogDebug(
wxT(
"Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
988 wxLogDebug(
wxT(
"Selected Region Only"));
990 wxLogDebug(
wxT(
"Whole Project"));
999 backup.SetName(
name.GetName() +
1000 wxString::Format(
wxT(
"%d"), suffix));
1003 while (backup.FileExists());
1004 ::wxRenameFile(filename.GetFullPath(), backup.GetFullPath());
1009 wxString base(
name.GetName());
1010 while (
name.FileExists()) {
1011 name.SetName(wxString::Format(
wxT(
"%s-%d"), base, i++));
1015 bool success{
false};
1016 const wxString fullPath{
name.GetFullPath()};
1018 auto cleanup =
finally( [&] {
1019 if (backup.IsOk()) {
1022 ::wxRemoveFile(backup.GetFullPath());
1025 ::wxRemoveFile(fullPath);
1026 ::wxRenameFile(backup.GetFullPath(), fullPath);
1032 ::wxRemoveFile(fullPath);
1040 .SetParameters(parameters)
1041 .SetRange(t0, t1, selectedOnly)
1043 .SetNumChannels(channels)
1044 .SetFileName(fullPath)
1045 .SetSampleRate(mExportOptionsPanel->GetSampleRate())
1052 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
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 RealtimeEffectList & Get(AudacityProject &project)
size_t GetStatesCount() const noexcept
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
ChoiceSetting ExportAudioExportRange
@ TrimBlankSpaceBeforeFirstClipID
@ OverwriteExistingFilesID
@ IncludeAudioBeforeFirstLabelID
@ ExportSplitNamePolicyTrackNameID
@ ExportSplitNamePolicyNumberingBeforeNameID
@ ExportSplitNamePolicyNumberingAfterPrefixID
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.