23#include <wx/checkbox.h>
27#include <wx/listbase.h>
29#include <wx/filename.h>
31#include <wx/radiobut.h>
32#include <wx/simplebook.h>
33#include <wx/statbox.h>
34#include <wx/stattext.h>
35#include <wx/textctrl.h>
36#include <wx/textdlg.h>
47#include "../TagsEditor.h"
130, mExporter{ *project }
138 for (
const auto &plugin : mExporter.GetPlugins())
139 mPlugins.push_back(plugin.get());
141 this->CountTracksAndLabels();
150 mInitialized =
false;
151 PopulateOrExchange(
S);
156 SetMinSize(GetSize());
185 XO(
"All audio is muted."),
186 XO(
"Cannot Export Multiple"),
196"You have no unmuted Audio Tracks and no applicable \
197\nlabels, so you cannot export to separate audio files."),
198 XO(
"Cannot Export Multiple"),
207 mLabel->Enable(bHasLabels && bHasTracks);
208 mTrack->Enable(bHasTracks);
214 mLabel->SetValue(bPreferByLabels);
215 mTrack->SetValue(!bPreferByLabels);
222#if defined(__WXMSW__)
226 return wxDialogWrapper::ShowModal();
232 wxT(
"/Export/TrackNameWithOrWithoutNumbers"),
234 {
wxT(
"labelTrack"),
XXO(
"Using Label/Track Name") },
235 {
wxT(
"numberBefore"),
XXO(
"Numbering before Label/Track Name") },
236 {
wxT(
"numberAfter"),
XXO(
"Numbering after File name prefix") },
242 wxString defaultFormat =
gPrefs->Read(
wxT(
"/Export/Format"),
wxT(
"WAV"));
251 for (
const auto &pPlugin :
mPlugins)
254 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
257 visibleFormats.push_back(
format );
261 formats.push_back(
format.MSGID().GET() );
262 if (
mPlugins[i]->GetFormat(j) == defaultFormat) {
291 S.StartHorizontalLay(wxEXPAND,
true);
294 S.StartStatic(
XO(
"Export files to:"),
true);
296 S.StartMultiColumn(4,
true);
299 .AddTextBox(
XXO(
"Folder:"),
306 .TieChoice(
XXO(
"Format:"),
309 S.AddVariableText( {},
false);
310 S.AddVariableText( {},
false);
312 S.AddPrompt(
XXO(
"Options:"));
315 .Style(wxBORDER_STATIC)
319 for (
const auto &pPlugin :
mPlugins)
321 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
324 S.StartNotebookPage( {} );
325 pPlugin->OptionsCreate(
S, j);
332 S.AddVariableText( {},
false);
333 S.AddVariableText( {},
false);
339 S.EndHorizontalLay();
341 S.StartHorizontalLay(wxEXPAND,
false);
344 S.StartStatic(
XO(
"Split files based on:"), 1);
354 .AddRadioButton(
XXO(
"Tracks"));
359 .AddRadioButtonToGroup(
XXO(
"Labels"));
364 S.StartMultiColumn(2, wxEXPAND);
370 .AddCheckBox(
XXO(
"Include audio before first label"),
false);
373 S.AddVariableText( {},
false);
374 S.StartMultiColumn(2, wxEXPAND);
378 S.AddVariableText(
XO(
"First file name:"),
false);
381 .Name(
XO(
"First file name"))
395 S.StartStatic(
XO(
"Name files:"), 1);
403 S.StartRadioButtonGroup(NumberingSetting);
411 S.EndRadioButtonGroup();
415 S.StartMultiColumn(3, wxEXPAND);
422 .Name(
XO(
"File name prefix"))
431 S.EndHorizontalLay();
434 S.StartHorizontalLay(wxEXPAND,
false);
437 {
wxT(
"/Export/OverwriteExisting"),
440 S.EndHorizontalLay();
443 mExport = (wxButton *)wxWindow::FindWindowById(wxID_OK,
this);
458 enable =
mLabel->GetValue() &&
491 const int sel =
mFormat->GetSelection();
492 if (sel != wxNOT_FOUND)
496 for (
const auto &pPlugin :
mPlugins)
499 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
501 if ((
size_t)sel == c)
517 fn.AssignDir(
mDir->GetValue());
519 bool ok =
fn.Mkdir(0777, wxPATH_MKDIR_FULL);
527 XO(
"\"%s\" successfully created.").
Format(
fn.GetPath() ),
528 XO(
"Export Multiple"),
536 XO(
"Choose a location to save the exported files"),
539 if (!dlog.GetPath().empty())
540 mDir->SetValue(dlog.GetPath());
607 for (
const auto &pPlugin :
mPlugins)
610 for (
int j = 0; j < pPlugin->GetFormatCount(); j++, c++)
628 auto cleanup =
finally( [&]
631 ?
XO(
"Successfully exported the following %lld file(s).")
632 : ok == ProgressResult::Failed
633 ?
XO(
"Something went wrong after exporting the following %lld file(s).")
635 ?
XO(
"Export canceled after exporting the following %lld file(s).")
636 : ok == ProgressResult::Stopped
637 ?
XO(
"Export stopped after exporting the following %lld file(s).")
638 :
XO(
"Something went really wrong after exporting the following %lld file(s).")
642 for (
size_t i = 0; i <
mExported.size(); i++) {
653 XO(
"Export Multiple"),
680 fn.AssignDir(
mDir->GetValue());
682 if (
fn.DirExists()) {
686 auto prompt =
XO(
"\"%s\" doesn't exist.\n\nWould you like to create it?")
687 .Format(
fn.GetFullPath() );
692 wxYES_NO | wxICON_EXCLAMATION);
693 if (action != wxYES) {
697 return fn.Mkdir(0777, wxPATH_MKDIR_FULL);
727 float pan = tr->GetPan();
733 else if (pan == 1.0) {
747 if (numRight > 0 || numLeft > 0) {
757 const wxString &prefix,
bool addNumber)
762 std::vector<ExportKit> exportSettings;
763 exportSettings.reserve(numFiles);
766 if(
mFirst->GetValue() ) {
777 setting.destfile.SetPath(
mDir->GetValue());
780 wxLogDebug(
wxT(
"File extension is %s"), setting.destfile.GetExt());
812 name =
_(
"untitled");
819 name.Printf(
wxT(
"%s-%02d"), prefix, l+1);
820 }
else if( addNumber ) {
823 name.Prepend(wxString::Format(
wxT(
"%02d-"), l+1));
828 if( setting.destfile.GetName().empty() )
837 wxASSERT(setting.destfile.IsOk());
845 setting.filetags.LoadDefaults();
846 if (exportSettings.size()) {
847 setting.filetags = exportSettings.back().filetags;
854 bool bShowTagsDialog =
settings.GetShowId3Dialog();
858 if( bShowTagsDialog ){
861 XO(
"Edit Metadata Tags"), bShowTagsDialog);
862 gPrefs->Read(
wxT(
"/AudioFiles/ShowId3Dialog"), &bShowTagsDialog,
true);
863 settings.SetShowId3Dialog( bShowTagsDialog );
870 exportSettings.push_back(setting);
877 ExportKit activeSetting;
880 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
881 for (count = 0; count < numFiles; count++) {
883 activeSetting = exportSettings[count];
885 if( activeSetting.destfile.GetName().empty() )
889 ok =
DoExport(pDialog, channels, activeSetting.destfile,
false,
890 activeSetting.t0, activeSetting.t1, activeSetting.filetags);
891 if (ok == ProgressResult::Stopped) {
894 XO(
"Continue to export remaining files?"),
896 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
897 if (dlgMessage.ShowModal() != wxID_YES ) {
911 const wxString &prefix,
bool addNumber)
917 std::vector<ExportKit> exportSettings;
921 setting.destfile.SetPath(
mDir->GetValue());
930 tr->SetSelected(
false);
934 bool skipSilenceAtBeginning;
935 gPrefs->Read(
wxT(
"/AudioFiles/SkipSilenceAtBeginning"), &skipSilenceAtBeginning,
false);
947 setting.channels = channels.size();
948 if (setting.channels == 1 &&
950 tr->GetPan() == 0.0))
951 setting.channels = 2;
954 title = tr->GetName();
962 wxString::Format(
wxT(
"%02d-"), l+1));
966 name = (wxString::Format(
wxT(
"%s-%02d"), prefix, l+1));
972 if (setting.destfile.GetName().empty())
981 wxASSERT(setting.destfile.IsOk());
989 setting.filetags.LoadDefaults();
990 if (exportSettings.size()) {
991 setting.filetags = exportSettings.back().filetags;
998 bool bShowTagsDialog =
settings.GetShowId3Dialog();
1002 if( bShowTagsDialog ){
1005 XO(
"Edit Metadata Tags"), bShowTagsDialog);
1006 gPrefs->Read(
wxT(
"/AudioFiles/ShowId3Dialog"), &bShowTagsDialog,
true);
1007 settings.SetShowId3Dialog( bShowTagsDialog );
1013 exportSettings.push_back(setting);
1020 ExportKit activeSetting;
1021 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
1026 wxLogDebug(
"Get setting %i", count );
1028 activeSetting = exportSettings[count];
1029 if( activeSetting.destfile.GetName().empty() ){
1037 for (
auto channel : range)
1038 channel->SetSelected(
true);
1042 activeSetting.channels, activeSetting.destfile,
true,
1043 activeSetting.t0, activeSetting.t1, activeSetting.filetags);
1044 if (ok == ProgressResult::Stopped) {
1047 XO(
"Continue to export remaining files?"),
1049 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
1050 if (dlgMessage.ShowModal() != wxID_YES ) {
1068 const wxFileName &inName,
1076 wxLogDebug(
wxT(
"Doing multiple Export: File name \"%s\""), (inName.GetFullName()));
1077 wxLogDebug(
wxT(
"Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
1079 wxLogDebug(
wxT(
"Selected Region Only"));
1081 wxLogDebug(
wxT(
"Whole Project"));
1086 backup.Assign(
name);
1090 backup.SetName(
name.GetName() +
1091 wxString::Format(
wxT(
"%d"), suffix));
1094 while (backup.FileExists());
1095 ::wxRenameFile(inName.GetFullPath(), backup.GetFullPath());
1100 wxString base(
name.GetName());
1101 while (
name.FileExists()) {
1102 name.SetName(wxString::Format(
wxT(
"%s-%d"), base, i++));
1107 const wxString fullPath{
name.GetFullPath()};
1109 auto cleanup =
finally( [&] {
1111 success == ProgressResult::Stopped ||
1113 if (backup.IsOk()) {
1116 ::wxRemoveFile(backup.GetFullPath());
1119 ::wxRemoveFile(fullPath);
1120 ::wxRenameFile(backup.GetFullPath(), fullPath);
1126 ::wxRemoveFile(fullPath);
1131 success = mPlugins[mPluginIndex]->Export(mProject,
1143 mExported.push_back(fullPath);
1154 wxString newname = input;
1165 if( excluded.length() > 1 ){
1168"Label or track \"%s\" is not a legal file name.\nYou cannot use any of these characters:\n\n%s\n\nSuggested replacement:")
1169 .Format( input, excluded );
1173"Label or track \"%s\" is not a legal file name. You cannot use \"%s\".\n\nSuggested replacement:")
1174 .Format( input, excluded );
1181 dlg.SetTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
1182 wxTextValidator *tv = dlg.GetTextValidator();
1186 if( dlg.ShowModal() == wxID_CANCEL )
1188 return wxEmptyString;
1191 newname = dlg.GetValue();
1198 if (event.GetKeyCode() == WXK_RETURN)
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
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
static unsigned GetNumExportChannels(const TrackList &tracks)
EVT_LIST_ITEM_ACTIVATED(wxID_ANY, SuccessDialog::OnItemActivated) ExportMultipleDialog
XXO("&Cut/Copy/Paste Toolbar")
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
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
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...
const wxString & GetProjectName() const
Wrap wxTextEntryDialog so that caption IS translatable.
Main class to control the export function.
Presents a dialog box allowing the user to export multiple files either by exporting each track as a ...
ProgressResult ExportMultipleByTrack(bool byName, const wxString &prefix, bool addNumber)
Export each track in the project to a separate file.
void OnCreate(wxCommandEvent &event)
wxString MakeFileName(const wxString &input)
Takes an arbitrary text string and converts it to a form that can be used as a file name,...
void OnFormat(wxCommandEvent &event)
void OnChoose(wxCommandEvent &event)
void OnByName(wxCommandEvent &event)
void OnByNumber(wxCommandEvent &event)
void CountTracksAndLabels()
std::vector< ExportPlugin * > mPlugins
void OnHelp(wxCommandEvent &event)
wxTextCtrl * mFirstFileName
void OnCancel(wxCommandEvent &event)
ProgressResult ExportMultipleByLabel(bool byName, const wxString &prefix, bool addNumber)
Export multiple labeled regions of the project to separate files.
const LabelTrack * mLabels
void OnTrack(wxCommandEvent &event)
ProgressResult DoExport(std::unique_ptr< BasicUI::ProgressDialog > &pDialog, unsigned channels, const wxFileName &name, bool selectedOnly, double t0, double t1, const Tags &tags)
wxStaticText * mFirstFileLabel
virtual ~ExportMultipleDialog()
SelectionState & mSelectionState
void OnFirstFileName(wxCommandEvent &event)
void OnLabel(wxCommandEvent &event)
wxRadioButton * mByNumberAndName
wxStaticText * mPrefixLabel
void OnFirst(wxCommandEvent &event)
void OnExport(wxCommandEvent &event)
wxRadioButton * mByNumber
void PopulateOrExchange(ShuttleGui &S)
AudacityProject * mProject
void OnPrefix(wxCommandEvent &event)
void OnOptions(wxCommandEvent &event)
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
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 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...
static const wxArrayString & GetExcludedCharacters()
A LabelStruct holds information for ONE label in a LabelTrack.
SelectedRegion selectedRegion
A LabelTrack is a Track that holds labels (LabelStruct).
const LabelStruct * GetLabel(int index) const
void OnMouse(wxMouseEvent &event)
static ProjectSettings & Get(AudacityProject &project)
static ProjectWindow * Find(AudacityProject *pProject)
static SelectionState & Get(AudacityProject &project)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
void OnKeyDown(wxListEvent &event)
void OnItemActivated(wxListEvent &event)
virtual double GetStartTime() const =0
virtual double GetEndTime() const =0
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
double GetEndTime() const
auto Leaders() -> TrackIterRange< TrackType >
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
A private class used to store the information needed to do an export.
wxFileNameWrapper destfile
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
FILES_API void MakeNameUnique(FilePaths &otherNames, wxFileName &newName)
FILES_API FilePath FindDefaultPath(Operation op)
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.