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"
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());
186 XO(
"All audio is muted."),
187 XO(
"Cannot Export Multiple"),
197"You have no unmuted Audio Tracks and no applicable \
198\nlabels, so you cannot export to separate audio files."),
199 XO(
"Cannot Export Multiple"),
208 mLabel->Enable(bHasLabels && bHasTracks);
209 mTrack->Enable(bHasTracks);
215 mLabel->SetValue(bPreferByLabels);
216 mTrack->SetValue(!bPreferByLabels);
223#if defined(__WXMSW__)
227 return wxDialogWrapper::ShowModal();
233 wxT(
"/Export/TrackNameWithOrWithoutNumbers"),
235 {
wxT(
"labelTrack"),
XXO(
"Using Label/Track Name") },
236 {
wxT(
"numberBefore"),
XXO(
"Numbering before Label/Track Name") },
237 {
wxT(
"numberAfter"),
XXO(
"Numbering after File name prefix") },
243 wxString defaultFormat =
gPrefs->Read(
wxT(
"/Export/Format"),
wxT(
"WAV"));
252 for (
const auto &pPlugin :
mPlugins)
255 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
258 visibleFormats.push_back(
format );
262 formats.push_back(
format.MSGID().GET() );
263 if (
mPlugins[i]->GetFormat(j) == defaultFormat) {
292 S.StartHorizontalLay(wxEXPAND,
true);
295 S.StartStatic(
XO(
"Export files to:"),
true);
297 S.StartMultiColumn(4,
true);
300 .AddTextBox(
XXO(
"Folder:"),
307 .TieChoice(
XXO(
"Format:"),
310 S.AddVariableText( {},
false);
311 S.AddVariableText( {},
false);
313 S.AddPrompt(
XXO(
"Options:"));
316 .Style(wxBORDER_STATIC)
320 for (
const auto &pPlugin :
mPlugins)
322 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
325 S.StartNotebookPage( {} );
326 pPlugin->OptionsCreate(
S, j);
333 S.AddVariableText( {},
false);
334 S.AddVariableText( {},
false);
340 S.EndHorizontalLay();
342 S.StartHorizontalLay(wxEXPAND,
false);
345 S.StartStatic(
XO(
"Split files based on:"), 1);
355 .AddRadioButton(
XXO(
"Tracks"));
360 .AddRadioButtonToGroup(
XXO(
"Labels"));
365 S.StartMultiColumn(2, wxEXPAND);
371 .AddCheckBox(
XXO(
"Include audio before first label"),
false);
374 S.AddVariableText( {},
false);
375 S.StartMultiColumn(2, wxEXPAND);
379 S.AddVariableText(
XO(
"First file name:"),
false);
382 .Name(
XO(
"First file name"))
396 S.StartStatic(
XO(
"Name files:"), 1);
404 S.StartRadioButtonGroup(NumberingSetting);
412 S.EndRadioButtonGroup();
416 S.StartMultiColumn(3, wxEXPAND);
423 .Name(
XO(
"File name prefix"))
432 S.EndHorizontalLay();
435 S.StartHorizontalLay(wxEXPAND,
false);
438 {
wxT(
"/Export/OverwriteExisting"),
441 S.EndHorizontalLay();
444 mExport = (wxButton *)wxWindow::FindWindowById(wxID_OK,
this);
459 enable =
mLabel->GetValue() &&
492 const int sel =
mFormat->GetSelection();
493 if (sel != wxNOT_FOUND)
497 for (
const auto &pPlugin :
mPlugins)
500 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
502 if ((
size_t)sel == c)
518 fn.AssignDir(
mDir->GetValue());
520 bool ok =
fn.Mkdir(0777, wxPATH_MKDIR_FULL);
528 XO(
"\"%s\" successfully created.").
Format(
fn.GetPath() ),
529 XO(
"Export Multiple"),
537 XO(
"Choose a location to save the exported files"),
540 if (!dlog.GetPath().empty())
541 mDir->SetValue(dlog.GetPath());
608 for (
const auto &pPlugin :
mPlugins)
611 for (
int j = 0; j < pPlugin->GetFormatCount(); j++, c++)
629 auto cleanup =
finally( [&]
632 ?
XO(
"Successfully exported the following %lld file(s).")
633 : ok == ProgressResult::Failed
634 ?
XO(
"Something went wrong after exporting the following %lld file(s).")
636 ?
XO(
"Export canceled after exporting the following %lld file(s).")
637 : ok == ProgressResult::Stopped
638 ?
XO(
"Export stopped after exporting the following %lld file(s).")
639 :
XO(
"Something went really wrong after exporting the following %lld file(s).")
643 for (
size_t i = 0; i <
mExported.size(); i++) {
654 XO(
"Export Multiple"),
681 fn.AssignDir(
mDir->GetValue());
683 if (
fn.DirExists()) {
687 auto prompt =
XO(
"\"%s\" doesn't exist.\n\nWould you like to create it?")
688 .Format(
fn.GetFullPath() );
693 wxYES_NO | wxICON_EXCLAMATION);
694 if (action != wxYES) {
698 return fn.Mkdir(0777, wxPATH_MKDIR_FULL);
709 return std::all_of(range.begin(), range.end(),
710 [](
auto *pTrack){ return IsMono(*pTrack); }
719 const wxString &prefix,
bool addNumber)
724 std::vector<ExportKit> exportSettings;
725 exportSettings.reserve(numFiles);
728 if(
mFirst->GetValue() ) {
739 setting.destfile.SetPath(
mDir->GetValue());
742 wxLogDebug(
wxT(
"File extension is %s"), setting.destfile.GetExt());
774 name =
_(
"untitled");
781 name.Printf(
wxT(
"%s-%02d"), prefix, l+1);
782 }
else if( addNumber ) {
785 name.Prepend(wxString::Format(
wxT(
"%02d-"), l+1));
790 if( setting.destfile.GetName().empty() )
799 wxASSERT(setting.destfile.IsOk());
807 setting.filetags.LoadDefaults();
808 if (exportSettings.size()) {
809 setting.filetags = exportSettings.back().filetags;
816 bool bShowTagsDialog =
settings.GetShowId3Dialog();
820 if( bShowTagsDialog ){
823 XO(
"Edit Metadata Tags"), bShowTagsDialog);
824 gPrefs->Read(
wxT(
"/AudioFiles/ShowId3Dialog"), &bShowTagsDialog,
true);
825 settings.SetShowId3Dialog( bShowTagsDialog );
832 exportSettings.push_back(setting);
839 ExportKit activeSetting;
842 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
843 for (count = 0; count < numFiles; count++) {
845 activeSetting = exportSettings[count];
847 if( activeSetting.destfile.GetName().empty() )
851 ok =
DoExport(pDialog, channels, activeSetting.destfile,
false,
852 activeSetting.t0, activeSetting.t1, activeSetting.filetags);
853 if (ok == ProgressResult::Stopped) {
856 XO(
"Continue to export remaining files?"),
858 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
859 if (dlgMessage.ShowModal() != wxID_YES ) {
873 const wxString &prefix,
bool addNumber)
879 std::vector<ExportKit> exportSettings;
883 setting.destfile.SetPath(
mDir->GetValue());
892 tr->SetSelected(
false);
897 bool skipSilenceAtBeginning;
898 gPrefs->Read(
wxT(
"/AudioFiles/SkipSilenceAtBeginning"), &skipSilenceAtBeginning,
false);
911 setting.channels = (
IsMono(*tr) && tr->GetPan() == 0.0) ? 1 : 2;
914 title = tr->GetName();
922 wxString::Format(
wxT(
"%02d-"), l+1));
926 name = (wxString::Format(
wxT(
"%s-%02d"), prefix, l+1));
932 if (setting.destfile.GetName().empty())
941 wxASSERT(setting.destfile.IsOk());
949 setting.filetags.LoadDefaults();
950 if (exportSettings.size()) {
951 setting.filetags = exportSettings.back().filetags;
958 bool bShowTagsDialog =
settings.GetShowId3Dialog();
962 if( bShowTagsDialog ){
965 XO(
"Edit Metadata Tags"), bShowTagsDialog);
966 gPrefs->Read(
wxT(
"/AudioFiles/ShowId3Dialog"), &bShowTagsDialog,
true);
967 settings.SetShowId3Dialog( bShowTagsDialog );
973 exportSettings.push_back(setting);
980 ExportKit activeSetting;
981 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
986 wxLogDebug(
"Get setting %i", count );
988 activeSetting = exportSettings[count];
989 if( activeSetting.destfile.GetName().empty() ){
996 tr->SetSelected(
true);
1000 activeSetting.channels, activeSetting.destfile,
true,
1001 activeSetting.t0, activeSetting.t1, activeSetting.filetags);
1002 if (ok == ProgressResult::Stopped) {
1005 XO(
"Continue to export remaining files?"),
1007 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
1008 if (dlgMessage.ShowModal() != wxID_YES ) {
1026 const wxFileName &inName,
1034 wxLogDebug(
wxT(
"Doing multiple Export: File name \"%s\""), (inName.GetFullName()));
1035 wxLogDebug(
wxT(
"Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
1037 wxLogDebug(
wxT(
"Selected Region Only"));
1039 wxLogDebug(
wxT(
"Whole Project"));
1044 backup.Assign(
name);
1048 backup.SetName(
name.GetName() +
1049 wxString::Format(
wxT(
"%d"), suffix));
1052 while (backup.FileExists());
1053 ::wxRenameFile(inName.GetFullPath(), backup.GetFullPath());
1058 wxString base(
name.GetName());
1059 while (
name.FileExists()) {
1060 name.SetName(wxString::Format(
wxT(
"%s-%d"), base, i++));
1065 const wxString fullPath{
name.GetFullPath()};
1067 auto cleanup =
finally( [&] {
1069 success == ProgressResult::Stopped ||
1071 if (backup.IsOk()) {
1074 ::wxRemoveFile(backup.GetFullPath());
1077 ::wxRemoveFile(fullPath);
1078 ::wxRenameFile(backup.GetFullPath(), fullPath);
1084 ::wxRemoveFile(fullPath);
1089 success = mPlugins[mPluginIndex]->Export(mProject,
1101 mExported.push_back(fullPath);
1112 wxString newname = input;
1123 if( excluded.length() > 1 ){
1126"Label or track \"%s\" is not a legal file name.\nYou cannot use any of these characters:\n\n%s\n\nSuggested replacement:")
1127 .Format( input, excluded );
1131"Label or track \"%s\" is not a legal file name. You cannot use \"%s\".\n\nSuggested replacement:")
1132 .Format( input, excluded );
1139 dlg.SetTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
1140 wxTextValidator *tv = dlg.GetTextValidator();
1144 if( dlg.ShowModal() == wxID_CANCEL )
1146 return wxEmptyString;
1149 newname = dlg.GetValue();
1156 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 SelectedLeaders() -> TrackIterRange< TrackType >
auto Leaders() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
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.
bool GetMute() const override
May vary asynchronously.
bool GetSolo() const override
May vary asynchronously.
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.
bool IsMono(const Channel &channel)
Whether the channel is mono.
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.