2010-01-23 19:44:49 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
ExportMultiple.cpp
|
|
|
|
|
|
|
|
Dominic Mazzoni
|
|
|
|
|
|
|
|
*******************************************************************//**
|
|
|
|
|
|
|
|
\class ExportMultiple
|
|
|
|
\brief Presents a dialog box allowing the user to export multiple files
|
|
|
|
either by exporting each track as a separate file, or by
|
|
|
|
exporting each label as a separate file.
|
|
|
|
|
|
|
|
*//********************************************************************/
|
|
|
|
|
|
|
|
#include "../Audacity.h"
|
2015-06-18 14:24:36 +00:00
|
|
|
#include "ExportMultiple.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
#include <wx/defs.h>
|
|
|
|
#include <wx/button.h>
|
|
|
|
#include <wx/checkbox.h>
|
|
|
|
#include <wx/choice.h>
|
|
|
|
#include <wx/dialog.h>
|
|
|
|
#include <wx/dirdlg.h>
|
|
|
|
#include <wx/event.h>
|
2018-11-16 15:12:10 +00:00
|
|
|
#include <wx/listbase.h>
|
2010-01-23 19:44:49 +00:00
|
|
|
#include <wx/filedlg.h>
|
|
|
|
#include <wx/filefn.h>
|
|
|
|
#include <wx/filename.h>
|
|
|
|
#include <wx/intl.h>
|
|
|
|
#include <wx/radiobut.h>
|
2018-11-14 20:53:31 +00:00
|
|
|
#include <wx/simplebook.h>
|
2010-01-23 19:44:49 +00:00
|
|
|
#include <wx/sizer.h>
|
|
|
|
#include <wx/statbox.h>
|
|
|
|
#include <wx/stattext.h>
|
|
|
|
#include <wx/textctrl.h>
|
|
|
|
#include <wx/textdlg.h>
|
|
|
|
|
2019-01-22 11:57:30 +00:00
|
|
|
#include "../DirManager.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
#include "../FileFormats.h"
|
|
|
|
#include "../FileNames.h"
|
|
|
|
#include "../LabelTrack.h"
|
|
|
|
#include "../Project.h"
|
|
|
|
#include "../Prefs.h"
|
2015-06-18 14:24:36 +00:00
|
|
|
#include "../ShuttleGui.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
#include "../Tags.h"
|
2015-07-03 04:20:21 +00:00
|
|
|
#include "../WaveTrack.h"
|
2014-06-06 21:34:36 +00:00
|
|
|
#include "../widgets/HelpSystem.h"
|
2019-05-20 18:27:11 +00:00
|
|
|
#include "../widgets/AudacityMessageBox.h"
|
2017-09-06 21:39:33 +00:00
|
|
|
#include "../widgets/ErrorDialog.h"
|
2019-03-31 20:12:07 +00:00
|
|
|
#include "../widgets/ProgressDialog.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
|
2019-03-31 19:51:54 +00:00
|
|
|
namespace {
|
|
|
|
/** \brief A private class used to store the information needed to do an
|
|
|
|
* export.
|
|
|
|
*
|
|
|
|
* We create a set of these during the interactive phase of the export
|
|
|
|
* cycle, then use them when the actual exports are done. */
|
|
|
|
class ExportKit
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Tags filetags; /**< The set of metadata to use for the export */
|
|
|
|
wxFileNameWrapper destfile; /**< The file to export to */
|
|
|
|
double t0; /**< Start time for the export */
|
|
|
|
double t1; /**< End time for the export */
|
|
|
|
unsigned channels; /**< Number of channels for ExportMultipleByTrack */
|
|
|
|
}; // end of ExportKit declaration
|
|
|
|
/* we are going to want an set of these kits, and don't know how many until
|
|
|
|
* runtime. I would dearly like to use a std::vector, but it seems that
|
|
|
|
* this isn't done anywhere else in Audacity, presumably for a reason?, so
|
|
|
|
* I'm stuck with wxArrays, which are much harder, as well as non-standard.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
/* define our dynamic array of export settings */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
FormatID = 10001,
|
|
|
|
OptionsID,
|
|
|
|
DirID,
|
|
|
|
CreateID,
|
|
|
|
ChooseID,
|
|
|
|
LabelID,
|
|
|
|
FirstID,
|
|
|
|
FirstFileNameID,
|
|
|
|
TrackID,
|
2010-02-07 20:17:36 +00:00
|
|
|
ByNameAndNumberID,
|
2010-01-23 19:44:49 +00:00
|
|
|
ByNameID,
|
|
|
|
ByNumberID,
|
|
|
|
PrefixID,
|
|
|
|
OverwriteID
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// ExportMultiple methods
|
|
|
|
//
|
|
|
|
|
2016-07-10 21:10:50 +00:00
|
|
|
BEGIN_EVENT_TABLE(ExportMultiple, wxDialogWrapper)
|
2010-01-23 19:44:49 +00:00
|
|
|
EVT_CHOICE(FormatID, ExportMultiple::OnFormat)
|
2015-08-05 07:28:42 +00:00
|
|
|
// EVT_BUTTON(OptionsID, ExportMultiple::OnOptions)
|
2010-01-23 19:44:49 +00:00
|
|
|
EVT_BUTTON(CreateID, ExportMultiple::OnCreate)
|
|
|
|
EVT_BUTTON(ChooseID, ExportMultiple::OnChoose)
|
|
|
|
EVT_BUTTON(wxID_OK, ExportMultiple::OnExport)
|
|
|
|
EVT_BUTTON(wxID_CANCEL, ExportMultiple::OnCancel)
|
2018-08-09 19:49:20 +00:00
|
|
|
EVT_BUTTON(wxID_HELP, ExportMultiple::OnHelp)
|
2010-01-23 19:44:49 +00:00
|
|
|
EVT_RADIOBUTTON(LabelID, ExportMultiple::OnLabel)
|
|
|
|
EVT_RADIOBUTTON(TrackID, ExportMultiple::OnTrack)
|
2010-02-07 20:38:56 +00:00
|
|
|
EVT_RADIOBUTTON(ByNameAndNumberID, ExportMultiple::OnByName)
|
2010-01-23 19:44:49 +00:00
|
|
|
EVT_RADIOBUTTON(ByNameID, ExportMultiple::OnByName)
|
|
|
|
EVT_RADIOBUTTON(ByNumberID, ExportMultiple::OnByNumber)
|
|
|
|
EVT_CHECKBOX(FirstID, ExportMultiple::OnFirst)
|
|
|
|
EVT_TEXT(FirstFileNameID, ExportMultiple::OnFirstFileName)
|
|
|
|
EVT_TEXT(PrefixID, ExportMultiple::OnPrefix)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
2016-07-10 21:10:50 +00:00
|
|
|
BEGIN_EVENT_TABLE(SuccessDialog, wxDialogWrapper)
|
2010-01-23 19:44:49 +00:00
|
|
|
EVT_LIST_KEY_DOWN(wxID_ANY, SuccessDialog::OnKeyDown)
|
|
|
|
EVT_LIST_ITEM_ACTIVATED(wxID_ANY, SuccessDialog::OnItemActivated) // happens when <enter> is pressed with list item having focus
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
BEGIN_EVENT_TABLE(MouseEvtHandler, wxEvtHandler)
|
|
|
|
EVT_LEFT_DCLICK(MouseEvtHandler::OnMouse)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
ExportMultiple::ExportMultiple(AudacityProject *project)
|
2016-07-10 21:10:50 +00:00
|
|
|
: wxDialogWrapper(project, wxID_ANY, wxString(_("Export Multiple")))
|
2017-06-11 15:21:36 +00:00
|
|
|
, mSelectionState{ project->GetSelectionState() }
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2015-05-18 12:57:05 +00:00
|
|
|
SetName(GetTitle());
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
mProject = project;
|
|
|
|
mTracks = project->GetTracks();
|
2016-03-31 04:46:22 +00:00
|
|
|
// Construct an array of non-owning pointers
|
|
|
|
for (const auto &plugin : mExporter.GetPlugins())
|
|
|
|
mPlugins.push_back(plugin.get());
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
this->CountTracksAndLabels();
|
|
|
|
|
2015-08-05 07:28:42 +00:00
|
|
|
mBook = NULL;
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
ShuttleGui S(this, eIsCreatingFromPrefs);
|
|
|
|
|
2016-07-15 15:20:25 +00:00
|
|
|
// Creating some of the widgets cause events to fire
|
2010-01-23 19:44:49 +00:00
|
|
|
// and we don't want that until after we're completely
|
|
|
|
// created. (Observed on Windows)
|
|
|
|
mInitialized = false;
|
|
|
|
PopulateOrExchange(S);
|
|
|
|
mInitialized = true;
|
|
|
|
|
|
|
|
Layout();
|
|
|
|
Fit();
|
|
|
|
SetMinSize(GetSize());
|
|
|
|
Center();
|
|
|
|
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExportMultiple::~ExportMultiple()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExportMultiple::CountTracksAndLabels()
|
|
|
|
{
|
2018-09-18 16:00:42 +00:00
|
|
|
mNumWaveTracks =
|
|
|
|
(mTracks->Leaders< const WaveTrack >() - &WaveTrack::GetMute).size();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2018-09-18 16:00:42 +00:00
|
|
|
// only the first label track
|
|
|
|
mLabels = *mTracks->Any< const LabelTrack >().begin();
|
|
|
|
mNumLabels = mLabels ? mLabels->GetNumLabels() : 0;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ExportMultiple::ShowModal()
|
|
|
|
{
|
2013-01-08 00:44:57 +00:00
|
|
|
// Cannot export if all audio tracks are muted.
|
2014-06-03 20:30:19 +00:00
|
|
|
if (mNumWaveTracks == 0)
|
2013-01-08 01:15:08 +00:00
|
|
|
{
|
2017-09-06 21:39:33 +00:00
|
|
|
::AudacityMessageBox(_("All audio is muted."),
|
2013-01-08 00:44:57 +00:00
|
|
|
_("Cannot Export Multiple"),
|
2013-01-05 00:05:59 +00:00
|
|
|
wxOK | wxCENTRE, this);
|
|
|
|
return wxID_CANCEL;
|
|
|
|
}
|
2013-01-08 00:44:57 +00:00
|
|
|
|
2018-04-01 16:52:34 +00:00
|
|
|
if ((mNumWaveTracks < 1) && (mNumLabels < 1))
|
2013-01-08 01:15:08 +00:00
|
|
|
{
|
2017-09-06 21:39:33 +00:00
|
|
|
::AudacityMessageBox(_(
|
2018-04-01 16:52:34 +00:00
|
|
|
"You have no unmuted Audio Tracks and no applicable \
|
2013-01-12 00:56:31 +00:00
|
|
|
\nlabels, so you cannot export to separate audio files."),
|
2013-01-08 00:44:57 +00:00
|
|
|
_("Cannot Export Multiple"),
|
2010-01-23 19:44:49 +00:00
|
|
|
wxOK | wxCENTRE, this);
|
|
|
|
return wxID_CANCEL;
|
|
|
|
}
|
|
|
|
|
2018-08-10 18:25:21 +00:00
|
|
|
bool bHasLabels = (mNumLabels > 0);
|
|
|
|
bool bHasTracks = (mNumWaveTracks > 0);
|
|
|
|
|
|
|
|
mLabel->Enable(bHasLabels && bHasTracks);
|
|
|
|
mTrack->Enable(bHasTracks);
|
|
|
|
|
|
|
|
// If you have 2 or more tracks, then it is export by tracks.
|
|
|
|
// If you have no labels, then it is export by tracks.
|
|
|
|
// Otherwise it is export by labels, by default.
|
|
|
|
bool bPreferByLabels = bHasLabels && (mNumWaveTracks < 2);
|
|
|
|
mLabel->SetValue(bPreferByLabels);
|
|
|
|
mTrack->SetValue(!bPreferByLabels);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
EnableControls();
|
|
|
|
|
2016-07-10 21:10:50 +00:00
|
|
|
return wxDialogWrapper::ShowModal();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExportMultiple::PopulateOrExchange(ShuttleGui& S)
|
|
|
|
{
|
2019-04-21 21:33:18 +00:00
|
|
|
wxString name = mProject->GetProjectName();
|
2015-08-26 17:40:55 +00:00
|
|
|
wxString defaultFormat = gPrefs->Read(wxT("/Export/Format"), wxT("WAV"));
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2018-02-02 00:23:02 +00:00
|
|
|
wxArrayStringEx formats;
|
2010-01-23 19:44:49 +00:00
|
|
|
mPluginIndex = -1;
|
|
|
|
mFilterIndex = 0;
|
|
|
|
|
2016-03-31 04:46:22 +00:00
|
|
|
{
|
|
|
|
int i = -1;
|
|
|
|
for (const auto &pPlugin : mPlugins)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
++i;
|
|
|
|
for (int j = 0; j < pPlugin->GetFormatCount(); j++)
|
|
|
|
{
|
2019-02-12 00:10:48 +00:00
|
|
|
formats.push_back(mPlugins[i]->GetDescription(j));
|
2016-03-31 04:46:22 +00:00
|
|
|
if (mPlugins[i]->GetFormat(j) == defaultFormat) {
|
|
|
|
mPluginIndex = i;
|
|
|
|
mSubFormatIndex = j;
|
|
|
|
}
|
|
|
|
if (mPluginIndex == -1) mFilterIndex++;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-31 04:46:22 +00:00
|
|
|
|
2017-01-18 14:19:06 +00:00
|
|
|
|
|
|
|
// Bug 1304: Set the default file path. It's used if none stored in config.
|
2017-08-01 19:11:56 +00:00
|
|
|
auto filename = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path"));
|
2017-01-18 14:19:06 +00:00
|
|
|
wxString DefaultPath = filename.GetPath();
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
if (mPluginIndex == -1)
|
|
|
|
{
|
|
|
|
mPluginIndex = 0;
|
|
|
|
mFilterIndex = 0;
|
|
|
|
mSubFormatIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
S.SetBorder(5);
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartHorizontalLay(wxEXPAND, true);
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
S.SetBorder(5);
|
|
|
|
S.StartStatic(_("Export files to:"), true);
|
|
|
|
{
|
|
|
|
S.StartMultiColumn(4, true);
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
mDir = S.Id(DirID)
|
|
|
|
.TieTextBox(_("Folder:"),
|
|
|
|
wxT("/Export/MultiplePath"),
|
2017-08-01 19:11:56 +00:00
|
|
|
DefaultPath,
|
2015-08-05 07:28:42 +00:00
|
|
|
64);
|
|
|
|
S.Id(ChooseID).AddButton(_("Choose..."));
|
|
|
|
S.Id(CreateID).AddButton(_("Create"));
|
|
|
|
|
|
|
|
mFormat = S.Id(FormatID)
|
|
|
|
.TieChoice(_("Format:"),
|
|
|
|
wxT("/Export/MultipleFormat"),
|
2015-08-26 17:40:55 +00:00
|
|
|
formats[mFilterIndex],
|
2015-08-05 07:28:42 +00:00
|
|
|
formats,
|
|
|
|
formats);
|
2017-09-28 01:20:14 +00:00
|
|
|
S.AddVariableText( {}, false);
|
|
|
|
S.AddVariableText( {}, false);
|
2015-08-05 07:28:42 +00:00
|
|
|
|
|
|
|
S.AddPrompt(_("Options:"));
|
|
|
|
if (!mBook)
|
|
|
|
{
|
2016-02-13 23:06:49 +00:00
|
|
|
mBook = safenew wxSimplebook(S.GetParent(), OptionsID, wxDefaultPosition, wxDefaultSize, wxBORDER_STATIC);
|
2016-03-31 04:46:22 +00:00
|
|
|
for (const auto &pPlugin : mPlugins)
|
2015-08-05 07:28:42 +00:00
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
for (int j = 0; j < pPlugin->GetFormatCount(); j++)
|
2015-08-05 07:28:42 +00:00
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
mBook->AddPage(pPlugin->OptionsCreate(mBook, j), wxEmptyString);
|
2015-08-05 07:28:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mBook->ChangeSelection(mFormat->GetSelection());
|
|
|
|
}
|
|
|
|
S.AddWindow(mBook);
|
2017-09-28 01:20:14 +00:00
|
|
|
S.AddVariableText( {}, false);
|
|
|
|
S.AddVariableText( {}, false);
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
S.EndMultiColumn();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
S.EndStatic();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
S.EndHorizontalLay();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartHorizontalLay(wxEXPAND, false);
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
S.SetBorder(5);
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartStatic(_("Split files based on:"), 1);
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2013-05-19 08:51:34 +00:00
|
|
|
// Row 1
|
2014-06-03 20:30:19 +00:00
|
|
|
S.SetBorder(1);
|
2015-08-05 07:28:42 +00:00
|
|
|
mTrack = S.Id(TrackID)
|
2017-09-30 16:19:44 +00:00
|
|
|
.AddRadioButton(_("Tracks"));
|
2015-08-05 07:28:42 +00:00
|
|
|
mTrack->SetName(_("Tracks"));
|
|
|
|
|
|
|
|
// Row 2
|
|
|
|
S.SetBorder(1);
|
2017-09-30 16:19:44 +00:00
|
|
|
mLabel = S.Id(LabelID).AddRadioButtonToGroup(_("Labels"));
|
2013-05-19 08:51:34 +00:00
|
|
|
mLabel->SetName(_("Labels"));
|
|
|
|
S.SetBorder(3);
|
|
|
|
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartMultiColumn(2, wxEXPAND);
|
2010-01-23 19:44:49 +00:00
|
|
|
S.SetStretchyCol(1);
|
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
// Row 3 (indented)
|
2013-05-19 08:51:34 +00:00
|
|
|
S.AddVariableText(wxT(" "), false);
|
2010-01-23 19:44:49 +00:00
|
|
|
mFirst = S.Id(FirstID)
|
2018-02-02 02:37:34 +00:00
|
|
|
.AddCheckBox(_("Include audio before first label"), false);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2015-08-05 07:28:42 +00:00
|
|
|
// Row 4
|
2017-09-28 01:20:14 +00:00
|
|
|
S.AddVariableText( {}, false);
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartMultiColumn(2, wxEXPAND);
|
|
|
|
S.SetStretchyCol(1);
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
mFirstFileLabel = S.AddVariableText(_("First file name:"), false);
|
2010-01-23 19:44:49 +00:00
|
|
|
mFirstFileName = S.Id(FirstFileNameID)
|
2017-09-28 01:20:14 +00:00
|
|
|
.Prop(1).TieTextBox( {},
|
2010-01-23 19:44:49 +00:00
|
|
|
name,
|
|
|
|
30);
|
|
|
|
mFirstFileName->SetName(_("First file name"));
|
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
S.EndMultiColumn();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
S.EndMultiColumn();
|
2013-05-19 08:51:34 +00:00
|
|
|
|
|
|
|
S.SetBorder(3);
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
S.EndStatic();
|
|
|
|
|
|
|
|
S.SetBorder(5);
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartStatic(_("Name files:"), 1);
|
|
|
|
{
|
2010-02-07 22:25:16 +00:00
|
|
|
S.SetBorder(2);
|
2010-02-10 14:03:47 +00:00
|
|
|
S.StartRadioButtonGroup(wxT("/Export/TrackNameWithOrWithoutNumbers"), wxT("labelTrack"));
|
|
|
|
{
|
|
|
|
mByName = S.Id(ByNameID)
|
|
|
|
.TieRadioButton(_("Using Label/Track Name"), wxT("labelTrack"));
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2010-02-10 14:03:47 +00:00
|
|
|
mByNumberAndName = S.Id(ByNameAndNumberID)
|
|
|
|
.TieRadioButton(_("Numbering before Label/Track Name"), wxT("numberBefore"));
|
2010-02-07 20:17:36 +00:00
|
|
|
|
2010-02-10 14:03:47 +00:00
|
|
|
mByNumber = S.Id(ByNumberID)
|
2011-01-01 11:51:24 +00:00
|
|
|
.TieRadioButton(_("Numbering after File name prefix"), wxT("numberAfter"));
|
2010-02-10 14:03:47 +00:00
|
|
|
}
|
|
|
|
S.EndRadioButtonGroup();
|
2010-02-07 20:17:36 +00:00
|
|
|
|
2015-08-05 07:28:42 +00:00
|
|
|
S.StartMultiColumn(3, wxEXPAND);
|
|
|
|
S.SetStretchyCol(2);
|
2010-02-07 20:17:36 +00:00
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
// Row 3 (indented)
|
|
|
|
S.AddVariableText(wxT(" "), false);
|
|
|
|
mPrefixLabel = S.AddVariableText(_("File name prefix:"), false);
|
2010-02-07 20:17:36 +00:00
|
|
|
mPrefix = S.Id(PrefixID)
|
2017-09-28 01:20:14 +00:00
|
|
|
.TieTextBox( {},
|
2010-02-07 20:17:36 +00:00
|
|
|
name,
|
|
|
|
30);
|
|
|
|
mPrefix->SetName(_("File name prefix"));
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
S.EndMultiColumn();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
S.EndStatic();
|
|
|
|
}
|
|
|
|
S.EndHorizontalLay();
|
|
|
|
|
|
|
|
S.SetBorder(5);
|
|
|
|
S.StartHorizontalLay(wxEXPAND, false);
|
|
|
|
{
|
2015-08-03 15:02:07 +00:00
|
|
|
mOverwrite = S.Id(OverwriteID).TieCheckBox(_("Overwrite existing files"),
|
|
|
|
wxT("/Export/OverwriteExisting"),
|
|
|
|
false);
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
S.EndHorizontalLay();
|
|
|
|
|
2018-08-09 19:49:20 +00:00
|
|
|
S.AddStandardButtons(eOkButton | eCancelButton | eHelpButton);
|
2010-01-23 19:44:49 +00:00
|
|
|
mExport = (wxButton *)wxWindow::FindWindowById(wxID_OK, this);
|
|
|
|
mExport->SetLabel(_("Export"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExportMultiple::EnableControls()
|
|
|
|
{
|
|
|
|
bool enable;
|
|
|
|
|
|
|
|
if (!mInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mFirst->Enable(mLabel->GetValue());
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-02-07 20:17:36 +00:00
|
|
|
enable = mLabel->GetValue() &&
|
2014-06-03 20:30:19 +00:00
|
|
|
(mByName->GetValue() || mByNumberAndName->GetValue()) &&
|
2010-02-07 20:17:36 +00:00
|
|
|
mFirst->GetValue();
|
2010-01-23 19:44:49 +00:00
|
|
|
mFirstFileLabel->Enable(enable);
|
|
|
|
mFirstFileName->Enable(enable);
|
|
|
|
|
|
|
|
enable = mByNumber->GetValue();
|
|
|
|
mPrefixLabel->Enable(enable);
|
|
|
|
mPrefix->Enable(enable);
|
|
|
|
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
if (mLabel->GetValue() && mFirst->GetValue() &&
|
2019-03-14 17:04:37 +00:00
|
|
|
mFirstFileName->GetValue().empty() &&
|
|
|
|
mPrefix->GetValue().empty())
|
2010-01-23 19:44:49 +00:00
|
|
|
ok = false;
|
|
|
|
|
|
|
|
if (mByNumber->GetValue() &&
|
2019-03-14 17:04:37 +00:00
|
|
|
mPrefix->GetValue().empty())
|
2010-01-23 19:44:49 +00:00
|
|
|
ok = false;
|
|
|
|
|
|
|
|
mExport->Enable(ok);
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnFormat(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2015-08-05 07:28:42 +00:00
|
|
|
mBook->ChangeSelection(mFormat->GetSelection());
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnOptions(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
const int sel = mFormat->GetSelection();
|
|
|
|
if (sel != wxNOT_FOUND)
|
|
|
|
{
|
|
|
|
size_t c = 0;
|
2016-03-31 04:46:22 +00:00
|
|
|
int i = -1;
|
|
|
|
for (const auto &pPlugin : mPlugins)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
++i;
|
|
|
|
for (int j = 0; j < pPlugin->GetFormatCount(); j++)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
if ((size_t)sel == c)
|
|
|
|
{
|
|
|
|
mPluginIndex = i;
|
|
|
|
mSubFormatIndex = j;
|
|
|
|
}
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mPlugins[mPluginIndex]->DisplayOptions(this,mSubFormatIndex);
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnCreate(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
wxFileName fn;
|
|
|
|
|
|
|
|
fn.AssignDir(mDir->GetValue());
|
|
|
|
|
|
|
|
bool ok = fn.Mkdir(0777, wxPATH_MKDIR_FULL);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
// Mkdir will produce an error dialog
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-06 21:39:33 +00:00
|
|
|
::AudacityMessageBox(wxString::Format(_("\"%s\" successfully created."),
|
2017-10-09 05:03:14 +00:00
|
|
|
fn.GetPath()),
|
2010-01-23 19:44:49 +00:00
|
|
|
_("Export Multiple"),
|
|
|
|
wxOK | wxCENTRE, this);
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnChoose(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2017-10-12 19:23:52 +00:00
|
|
|
wxDirDialogWrapper dlog(this,
|
2010-01-23 19:44:49 +00:00
|
|
|
_("Choose a location to save the exported files"),
|
|
|
|
mDir->GetValue());
|
|
|
|
dlog.ShowModal();
|
2019-03-14 17:04:37 +00:00
|
|
|
if (!dlog.GetPath().empty())
|
2010-01-23 19:44:49 +00:00
|
|
|
mDir->SetValue(dlog.GetPath());
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnLabel(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnFirst(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnFirstFileName(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnTrack(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnByName(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnByNumber(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnPrefix(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EnableControls();
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnCancel(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EndModal(0);
|
|
|
|
}
|
|
|
|
|
2018-08-09 19:49:20 +00:00
|
|
|
void ExportMultiple::OnHelp(wxCommandEvent& WXUNUSED(event))
|
|
|
|
{
|
|
|
|
HelpSystem::ShowHelp(this, wxT("Export_Multiple"), true);
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void ExportMultiple::OnExport(wxCommandEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
ShuttleGui S(this, eIsSavingToPrefs);
|
|
|
|
PopulateOrExchange(S);
|
|
|
|
|
2015-12-22 02:07:24 +00:00
|
|
|
gPrefs->Flush();
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// Make sure the output directory is in good shape
|
|
|
|
if (!DirOk()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mFilterIndex = mFormat->GetSelection();
|
|
|
|
if (mFilterIndex != wxNOT_FOUND)
|
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
size_t c = 0;
|
|
|
|
int i = -1;
|
|
|
|
for (const auto &pPlugin : mPlugins)
|
2015-08-05 07:28:42 +00:00
|
|
|
{
|
2016-03-31 04:46:22 +00:00
|
|
|
++i;
|
|
|
|
for (int j = 0; j < pPlugin->GetFormatCount(); j++, c++)
|
2015-08-05 07:28:42 +00:00
|
|
|
{
|
|
|
|
if ((size_t)mFilterIndex == c)
|
|
|
|
{ // this is the selected format. Store the plug-in and sub-format
|
|
|
|
// needed to acheive it.
|
|
|
|
mPluginIndex = i;
|
|
|
|
mSubFormatIndex = j;
|
|
|
|
mBook->GetPage(mFilterIndex)->TransferDataFromWindow();
|
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// bool overwrite = mOverwrite->GetValue();
|
2016-12-24 17:37:46 +00:00
|
|
|
ProgressResult ok = ProgressResult::Failed;
|
2019-02-12 00:10:48 +00:00
|
|
|
mExported.clear();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Give 'em the result
|
2016-12-24 17:37:46 +00:00
|
|
|
auto cleanup = finally( [&]
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
msg.Printf(
|
2016-12-24 15:43:25 +00:00
|
|
|
ok == ProgressResult::Success ? _("Successfully exported the following %lld file(s).")
|
|
|
|
: (ok == ProgressResult::Failed ? _("Something went wrong after exporting the following %lld file(s).")
|
|
|
|
: (ok == ProgressResult::Cancelled ? _("Export canceled after exporting the following %lld file(s).")
|
|
|
|
: (ok == ProgressResult::Stopped ? _("Export stopped after exporting the following %lld file(s).")
|
2014-11-08 16:42:34 +00:00
|
|
|
: _("Something went really wrong after exporting the following %lld file(s).")
|
2010-01-23 19:44:49 +00:00
|
|
|
)
|
|
|
|
)
|
2019-02-12 00:10:48 +00:00
|
|
|
), (long long) mExported.size());
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2010-02-13 18:24:57 +00:00
|
|
|
wxString FileList;
|
2019-02-12 00:10:48 +00:00
|
|
|
for (size_t i = 0; i < mExported.size(); i++) {
|
2010-02-13 18:24:57 +00:00
|
|
|
FileList += mExported[i];
|
|
|
|
FileList += '\n';
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2016-12-24 17:37:46 +00:00
|
|
|
|
2018-01-24 19:21:27 +00:00
|
|
|
// TODO: give some warning dialog first, when only some files exported
|
|
|
|
// successfully.
|
|
|
|
|
2018-01-13 06:32:41 +00:00
|
|
|
GuardedCall( [&] {
|
2016-12-24 17:37:46 +00:00
|
|
|
// This results dialog is a child of this dialog.
|
|
|
|
HelpSystem::ShowInfoDialog( this,
|
|
|
|
_("Export Multiple"),
|
|
|
|
msg,
|
|
|
|
FileList,
|
|
|
|
450,400);
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
|
|
|
|
if (mLabel->GetValue()) {
|
|
|
|
ok = ExportMultipleByLabel(mByName->GetValue() || mByNumberAndName->GetValue(),
|
|
|
|
mPrefix->GetValue(),
|
|
|
|
mByNumberAndName->GetValue());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ok = ExportMultipleByTrack(mByName->GetValue() || mByNumberAndName->GetValue(),
|
|
|
|
mPrefix->GetValue(),
|
|
|
|
mByNumberAndName->GetValue());
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
2016-12-24 15:43:25 +00:00
|
|
|
if (ok == ProgressResult::Success || ok == ProgressResult::Stopped) {
|
2010-01-23 19:44:49 +00:00
|
|
|
EndModal(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExportMultiple::DirOk()
|
|
|
|
{
|
|
|
|
wxFileName fn;
|
|
|
|
|
|
|
|
fn.AssignDir(mDir->GetValue());
|
|
|
|
|
|
|
|
if (fn.DirExists()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString prompt;
|
|
|
|
|
|
|
|
prompt.Printf(_("\"%s\" doesn't exist.\n\nWould you like to create it?"),
|
2017-10-09 05:03:14 +00:00
|
|
|
fn.GetFullPath());
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2017-09-06 21:39:33 +00:00
|
|
|
int action = AudacityMessageBox(prompt,
|
2010-01-23 19:44:49 +00:00
|
|
|
wxT("Warning"),
|
|
|
|
wxYES_NO | wxICON_EXCLAMATION);
|
|
|
|
if (action != wxYES) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fn.Mkdir(0777, wxPATH_MKDIR_FULL);
|
|
|
|
}
|
|
|
|
|
2016-07-15 15:20:25 +00:00
|
|
|
// TODO: JKC July2016: Merge labels/tracks duplicated export code.
|
2019-04-13 13:27:25 +00:00
|
|
|
// TODO: JKC Apr2019: Doubly so merge these! Too much duplication.
|
2016-12-24 15:43:25 +00:00
|
|
|
ProgressResult ExportMultiple::ExportMultipleByLabel(bool byName,
|
2016-02-23 02:17:04 +00:00
|
|
|
const wxString &prefix, bool addNumber)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
wxASSERT(mProject);
|
|
|
|
int numFiles = mNumLabels;
|
|
|
|
int l = 0; // counter for files done
|
2018-02-02 18:24:53 +00:00
|
|
|
std::vector<ExportKit> exportSettings; // dynamic array for settings.
|
|
|
|
exportSettings.reserve(numFiles); // Allocate some guessed space to use.
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Account for exporting before first label
|
2016-07-15 15:20:25 +00:00
|
|
|
if( mFirst->GetValue() ) {
|
2010-01-23 19:44:49 +00:00
|
|
|
l--;
|
|
|
|
numFiles++;
|
|
|
|
}
|
|
|
|
|
2013-01-05 00:05:59 +00:00
|
|
|
// Figure out how many channels we should export.
|
2016-09-02 19:53:09 +00:00
|
|
|
auto channels = mTracks->GetNumExportChannels(false);
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2019-03-07 19:50:22 +00:00
|
|
|
FilePaths otherNames; // keep track of file names we will use, so we
|
2016-07-15 15:20:25 +00:00
|
|
|
// don't duplicate them
|
2010-01-23 19:44:49 +00:00
|
|
|
ExportKit setting; // the current batch of settings
|
|
|
|
setting.destfile.SetPath(mDir->GetValue());
|
|
|
|
setting.destfile.SetExt(mPlugins[mPluginIndex]->GetExtension(mSubFormatIndex));
|
|
|
|
wxLogDebug(wxT("Plug-in index = %d, Sub-format = %d"), mPluginIndex, mSubFormatIndex);
|
2017-10-09 05:03:14 +00:00
|
|
|
wxLogDebug(wxT("File extension is %s"), setting.destfile.GetExt());
|
2010-01-23 19:44:49 +00:00
|
|
|
wxString name; // used to hold file name whilst we mess with it
|
|
|
|
wxString title; // un-messed-with title of file for tagging with
|
|
|
|
|
|
|
|
const LabelStruct *info = NULL;
|
|
|
|
/* Examine all labels a first time, sort out all data but don't do any
|
|
|
|
* exporting yet (so this run is quick but interactive) */
|
2016-07-15 15:20:25 +00:00
|
|
|
while( l < mNumLabels ) {
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// Get file name and starting time
|
2016-07-15 15:20:25 +00:00
|
|
|
if( l < 0 ) {
|
2014-06-03 20:30:19 +00:00
|
|
|
// create wxFileName for output file
|
2010-01-23 19:44:49 +00:00
|
|
|
name = (mFirstFileName->GetValue());
|
|
|
|
setting.t0 = 0.0;
|
2016-07-15 15:20:25 +00:00
|
|
|
} else {
|
2010-01-23 19:44:49 +00:00
|
|
|
info = mLabels->GetLabel(l);
|
|
|
|
name = (info->title);
|
2014-10-05 17:10:09 +00:00
|
|
|
setting.t0 = info->selectedRegion.t0();
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out the ending time
|
2016-07-15 15:20:25 +00:00
|
|
|
if( info && !info->selectedRegion.isPoint() ) {
|
2014-10-05 17:10:09 +00:00
|
|
|
setting.t1 = info->selectedRegion.t1();
|
2016-07-15 15:20:25 +00:00
|
|
|
} else if( l < mNumLabels-1 ) {
|
2014-10-05 17:10:09 +00:00
|
|
|
// Use start of next label as end
|
2010-01-23 19:44:49 +00:00
|
|
|
const LabelStruct *info1 = mLabels->GetLabel(l+1);
|
2014-10-05 17:10:09 +00:00
|
|
|
setting.t1 = info1->selectedRegion.t0();
|
2016-07-15 15:20:25 +00:00
|
|
|
} else {
|
2010-01-23 19:44:49 +00:00
|
|
|
setting.t1 = mTracks->GetEndTime();
|
|
|
|
}
|
|
|
|
|
2019-02-12 00:10:48 +00:00
|
|
|
if( name.empty() )
|
2010-02-12 17:28:24 +00:00
|
|
|
name = _("untitled");
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// store title of label to use in tags
|
|
|
|
title = name;
|
|
|
|
|
|
|
|
// Numbering files...
|
2016-07-15 15:20:25 +00:00
|
|
|
if( !byName ) {
|
2017-10-09 05:03:14 +00:00
|
|
|
name.Printf(wxT("%s-%02d"), prefix, l+1);
|
2016-07-15 15:20:25 +00:00
|
|
|
} else if( addNumber ) {
|
2010-02-07 20:17:36 +00:00
|
|
|
// Following discussion with GA, always have 2 digits
|
2010-02-10 14:03:47 +00:00
|
|
|
// for easy file-name sorting (on Windows)
|
2010-02-07 20:17:36 +00:00
|
|
|
name.Prepend(wxString::Format(wxT("%02d-"), l+1));
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
2010-02-07 20:17:36 +00:00
|
|
|
// store sanitised and user checked name in object
|
2010-01-23 19:44:49 +00:00
|
|
|
setting.destfile.SetName(MakeFileName(name));
|
2019-02-12 00:10:48 +00:00
|
|
|
if( setting.destfile.GetName().empty() )
|
2016-07-15 15:20:25 +00:00
|
|
|
{ // user cancelled dialogue, or deleted everything in field.
|
|
|
|
// or maybe the label was empty??
|
|
|
|
// So we ignore this one and keep going.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME: TRAP_ERR User could have given an illegal filename prefix.
|
|
|
|
// in that case we should tell them, not fail silently.
|
|
|
|
wxASSERT(setting.destfile.IsOk()); // burp if file name is broke
|
|
|
|
|
|
|
|
// Make sure the (final) file name is unique within the set of exports
|
|
|
|
FileNames::MakeNameUnique(otherNames, setting.destfile);
|
|
|
|
|
|
|
|
/* do the metadata for this file */
|
|
|
|
// copy project metadata to start with
|
|
|
|
setting.filetags = *(mProject->GetTags());
|
|
|
|
// over-ride with values
|
|
|
|
setting.filetags.SetTag(TAG_TITLE, title);
|
|
|
|
setting.filetags.SetTag(TAG_TRACK, l+1);
|
|
|
|
// let the user have a crack at editing it, exit if cancelled
|
2019-04-13 13:27:25 +00:00
|
|
|
bool bShowTagsDialog = mProject->GetShowId3Dialog();
|
|
|
|
if( bShowTagsDialog ){
|
|
|
|
bool bCancelled = !setting.filetags.ShowEditDialog(mProject,_("Edit Metadata Tags"), bShowTagsDialog);
|
|
|
|
gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &bShowTagsDialog, true);
|
|
|
|
mProject->SetShowId3Dialog( bShowTagsDialog );
|
|
|
|
if( bCancelled )
|
|
|
|
return ProgressResult::Cancelled;
|
|
|
|
}
|
2016-07-15 15:20:25 +00:00
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
/* add the settings to the array of settings to be used for export */
|
2018-02-02 18:24:53 +00:00
|
|
|
exportSettings.push_back(setting);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
l++; // next label, count up one
|
|
|
|
}
|
|
|
|
|
2016-12-24 15:43:25 +00:00
|
|
|
auto ok = ProgressResult::Success; // did it work?
|
2010-01-23 19:44:49 +00:00
|
|
|
int count = 0; // count the number of sucessful runs
|
|
|
|
ExportKit activeSetting; // pointer to the settings in use for this export
|
|
|
|
/* Go round again and do the exporting (so this run is slow but
|
|
|
|
* non-interactive) */
|
2018-01-25 20:58:37 +00:00
|
|
|
std::unique_ptr<ProgressDialog> pDialog;
|
2010-01-23 19:44:49 +00:00
|
|
|
for (count = 0; count < numFiles; count++) {
|
|
|
|
/* get the settings to use for the export from the array */
|
|
|
|
activeSetting = exportSettings[count];
|
2016-07-15 15:20:25 +00:00
|
|
|
// Bug 1440 fix.
|
2019-02-12 00:10:48 +00:00
|
|
|
if( activeSetting.destfile.GetName().empty() )
|
2016-07-15 15:20:25 +00:00
|
|
|
continue;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Export it
|
2018-01-25 20:58:37 +00:00
|
|
|
ok = DoExport(pDialog, channels, activeSetting.destfile, false,
|
|
|
|
activeSetting.t0, activeSetting.t1, activeSetting.filetags);
|
2016-12-24 15:43:25 +00:00
|
|
|
if (ok != ProgressResult::Success && ok != ProgressResult::Stopped) {
|
2010-01-23 19:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2016-12-24 15:43:25 +00:00
|
|
|
ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName,
|
2016-02-23 02:17:04 +00:00
|
|
|
const wxString &prefix, bool addNumber)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
wxASSERT(mProject);
|
|
|
|
int l = 0; // track counter
|
2016-12-24 15:43:25 +00:00
|
|
|
auto ok = ProgressResult::Success;
|
2019-03-07 19:50:22 +00:00
|
|
|
FilePaths otherNames;
|
2018-02-02 18:24:53 +00:00
|
|
|
std::vector<ExportKit> exportSettings; // dynamic array we will use to store the
|
2010-01-23 19:44:49 +00:00
|
|
|
// settings needed to do the exports with in
|
2018-02-02 18:24:53 +00:00
|
|
|
exportSettings.reserve(mNumWaveTracks); // Allocate some guessed space to use.
|
2010-01-23 19:44:49 +00:00
|
|
|
ExportKit setting; // the current batch of settings
|
|
|
|
setting.destfile.SetPath(mDir->GetValue());
|
|
|
|
setting.destfile.SetExt(mPlugins[mPluginIndex]->GetExtension(mSubFormatIndex));
|
|
|
|
|
|
|
|
wxString name; // used to hold file name whilst we mess with it
|
|
|
|
wxString title; // un-messed-with title of file for tagging with
|
|
|
|
|
|
|
|
/* Remember which tracks were selected, and set them to unselected */
|
2017-06-11 15:21:36 +00:00
|
|
|
SelectionStateChanger changer{ mSelectionState, *mTracks };
|
2018-09-18 16:00:42 +00:00
|
|
|
for (auto tr : mTracks->Selected<WaveTrack>())
|
|
|
|
tr->SetSelected(false);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
/* Examine all tracks in turn, collecting export information */
|
2018-09-18 16:00:42 +00:00
|
|
|
for (auto tr : mTracks->Leaders<WaveTrack>() - &WaveTrack::GetMute) {
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Get the times for the track
|
2018-09-18 16:00:42 +00:00
|
|
|
auto channels = TrackList::Channels(tr);
|
|
|
|
setting.t0 = channels.min( &Track::GetStartTime );
|
|
|
|
setting.t1 = channels.max( &Track::GetEndTime );
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// number of export channels?
|
2018-09-18 16:00:42 +00:00
|
|
|
setting.channels = channels.size();
|
|
|
|
if (setting.channels == 1 &&
|
|
|
|
!(tr->GetChannel() == WaveTrack::MonoChannel &&
|
|
|
|
tr->GetPan() == 0.0))
|
2013-01-05 00:05:59 +00:00
|
|
|
setting.channels = 2;
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Get name and title
|
|
|
|
title = tr->GetName();
|
2019-02-12 00:10:48 +00:00
|
|
|
if( title.empty() )
|
2010-02-12 17:28:24 +00:00
|
|
|
title = _("untitled");
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
if (byName) {
|
|
|
|
name = title;
|
2010-02-07 20:17:36 +00:00
|
|
|
if (addNumber) {
|
2014-10-19 03:08:10 +00:00
|
|
|
name.Prepend(
|
2016-02-26 23:10:45 +00:00
|
|
|
wxString::Format(wxT("%02d-"), l+1));
|
2013-01-05 00:05:59 +00:00
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-10-09 05:03:14 +00:00
|
|
|
name = (wxString::Format(wxT("%s-%02d"), prefix, l+1));
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// store sanitised and user checked name in object
|
|
|
|
setting.destfile.SetName(MakeFileName(name));
|
|
|
|
|
2019-02-12 00:10:48 +00:00
|
|
|
if (setting.destfile.GetName().empty())
|
2016-07-15 15:20:25 +00:00
|
|
|
{ // user cancelled dialogue, or deleted everything in field.
|
|
|
|
// So we ignore this one and keep going.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-07-15 15:20:25 +00:00
|
|
|
// FIXME: TRAP_ERR User could have given an illegal track name.
|
|
|
|
// in that case we should tell them, not fail silently.
|
|
|
|
wxASSERT(setting.destfile.IsOk()); // burp if file name is broke
|
|
|
|
|
|
|
|
// Make sure the (final) file name is unique within the set of exports
|
|
|
|
FileNames::MakeNameUnique(otherNames, setting.destfile);
|
|
|
|
|
|
|
|
/* do the metadata for this file */
|
|
|
|
// copy project metadata to start with
|
|
|
|
setting.filetags = *(mProject->GetTags());
|
|
|
|
// over-ride with values
|
|
|
|
setting.filetags.SetTag(TAG_TITLE, title);
|
|
|
|
setting.filetags.SetTag(TAG_TRACK, l+1);
|
|
|
|
// let the user have a crack at editing it, exit if cancelled
|
2019-04-13 11:25:31 +00:00
|
|
|
bool bShowTagsDialog = mProject->GetShowId3Dialog();
|
|
|
|
if( bShowTagsDialog ){
|
|
|
|
bool bCancelled = !setting.filetags.ShowEditDialog(mProject,_("Edit Metadata Tags"), bShowTagsDialog);
|
|
|
|
gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &bShowTagsDialog, true);
|
|
|
|
mProject->SetShowId3Dialog( bShowTagsDialog );
|
|
|
|
if( bCancelled )
|
|
|
|
return ProgressResult::Cancelled;
|
|
|
|
}
|
2016-07-15 15:20:25 +00:00
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
/* add the settings to the array of settings to be used for export */
|
2018-02-02 18:24:53 +00:00
|
|
|
exportSettings.push_back(setting);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
l++; // next track, count up one
|
|
|
|
}
|
|
|
|
// end of user-interactive data gathering loop, start of export processing
|
|
|
|
// loop
|
|
|
|
int count = 0; // count the number of sucessful runs
|
|
|
|
ExportKit activeSetting; // pointer to the settings in use for this export
|
2018-01-25 20:58:37 +00:00
|
|
|
std::unique_ptr<ProgressDialog> pDialog;
|
2018-09-18 16:00:42 +00:00
|
|
|
for (auto tr : mTracks->Leaders<WaveTrack>() - &WaveTrack::GetMute) {
|
2016-09-10 19:00:32 +00:00
|
|
|
wxLogDebug( "Get setting %i", count );
|
2016-07-15 15:20:25 +00:00
|
|
|
/* get the settings to use for the export from the array */
|
|
|
|
activeSetting = exportSettings[count];
|
2019-02-12 00:10:48 +00:00
|
|
|
if( activeSetting.destfile.GetName().empty() ){
|
2016-07-15 15:20:25 +00:00
|
|
|
count++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
/* Select the track */
|
2017-06-11 15:21:36 +00:00
|
|
|
SelectionStateChanger changer2{ mSelectionState, *mTracks };
|
2018-09-18 16:00:42 +00:00
|
|
|
const auto range = TrackList::Channels(tr);
|
|
|
|
for (auto channel : range)
|
|
|
|
channel->SetSelected(true);
|
2017-04-23 03:43:10 +00:00
|
|
|
|
2013-01-05 00:05:59 +00:00
|
|
|
// Export the data. "channels" are per track.
|
2018-01-25 20:58:37 +00:00
|
|
|
ok = DoExport(pDialog,
|
|
|
|
activeSetting.channels, activeSetting.destfile, true,
|
|
|
|
activeSetting.t0, activeSetting.t1, activeSetting.filetags);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Stop if an error occurred
|
2016-12-24 15:43:25 +00:00
|
|
|
if (ok != ProgressResult::Success && ok != ProgressResult::Stopped) {
|
2010-01-23 19:44:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// increment export counter
|
|
|
|
count++;
|
|
|
|
|
2014-06-03 20:30:19 +00:00
|
|
|
}
|
|
|
|
|
2016-07-15 15:20:25 +00:00
|
|
|
return ok ;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
2018-01-25 20:58:37 +00:00
|
|
|
ProgressResult ExportMultiple::DoExport(std::unique_ptr<ProgressDialog> &pDialog,
|
|
|
|
unsigned channels,
|
2016-02-22 04:21:11 +00:00
|
|
|
const wxFileName &inName,
|
2010-01-23 19:44:49 +00:00
|
|
|
bool selectedOnly,
|
|
|
|
double t0,
|
|
|
|
double t1,
|
2016-02-08 20:59:50 +00:00
|
|
|
const Tags &tags)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2016-02-22 04:21:11 +00:00
|
|
|
wxFileName name;
|
|
|
|
|
2017-10-09 05:03:14 +00:00
|
|
|
wxLogDebug(wxT("Doing multiple Export: File name \"%s\""), (inName.GetFullName()));
|
2010-01-23 19:44:49 +00:00
|
|
|
wxLogDebug(wxT("Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
|
2016-12-24 17:37:46 +00:00
|
|
|
if (selectedOnly)
|
|
|
|
wxLogDebug(wxT("Selected Region Only"));
|
|
|
|
else
|
|
|
|
wxLogDebug(wxT("Whole Project"));
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2018-01-24 19:21:27 +00:00
|
|
|
wxFileName backup;
|
2010-01-23 19:44:49 +00:00
|
|
|
if (mOverwrite->GetValue()) {
|
|
|
|
// Make sure we don't overwrite (corrupt) alias files
|
2016-02-22 04:21:11 +00:00
|
|
|
if (!mProject->GetDirManager()->EnsureSafeFilename(inName)) {
|
2016-12-24 15:43:25 +00:00
|
|
|
return ProgressResult::Cancelled;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2016-02-22 04:21:11 +00:00
|
|
|
name = inName;
|
2018-01-24 19:21:27 +00:00
|
|
|
backup.Assign(name);
|
|
|
|
|
|
|
|
int suffix = 0;
|
|
|
|
do {
|
|
|
|
backup.SetName(name.GetName() +
|
|
|
|
wxString::Format(wxT("%d"), suffix));
|
|
|
|
++suffix;
|
|
|
|
}
|
|
|
|
while (backup.FileExists());
|
|
|
|
::wxRenameFile(inName.GetFullPath(), backup.GetFullPath());
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-02-22 04:21:11 +00:00
|
|
|
name = inName;
|
2010-01-23 19:44:49 +00:00
|
|
|
int i = 2;
|
|
|
|
wxString base(name.GetName());
|
|
|
|
while (name.FileExists()) {
|
2017-10-09 05:03:14 +00:00
|
|
|
name.SetName(wxString::Format(wxT("%s-%d"), base, i++));
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:21:27 +00:00
|
|
|
ProgressResult success = ProgressResult::Cancelled;
|
2016-02-22 04:21:11 +00:00
|
|
|
const wxString fullPath{name.GetFullPath()};
|
2018-01-24 19:21:27 +00:00
|
|
|
|
|
|
|
auto cleanup = finally( [&] {
|
|
|
|
bool ok =
|
|
|
|
success == ProgressResult::Stopped ||
|
|
|
|
success == ProgressResult::Success;
|
|
|
|
if (backup.IsOk()) {
|
|
|
|
if ( ok )
|
|
|
|
// Remove backup
|
|
|
|
::wxRemoveFile(backup.GetFullPath());
|
|
|
|
else {
|
|
|
|
// Restore original
|
|
|
|
::wxRemoveFile(fullPath);
|
|
|
|
::wxRenameFile(backup.GetFullPath(), fullPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( ! ok )
|
|
|
|
// Remove any new, and only partially written, file.
|
|
|
|
::wxRemoveFile(fullPath);
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
|
|
|
// Call the format export routine
|
|
|
|
success = mPlugins[mPluginIndex]->Export(mProject,
|
2018-01-25 20:58:37 +00:00
|
|
|
pDialog,
|
2010-01-23 19:44:49 +00:00
|
|
|
channels,
|
2016-02-22 04:21:11 +00:00
|
|
|
fullPath,
|
2010-01-23 19:44:49 +00:00
|
|
|
selectedOnly,
|
|
|
|
t0,
|
|
|
|
t1,
|
|
|
|
NULL,
|
|
|
|
&tags,
|
|
|
|
mSubFormatIndex);
|
|
|
|
|
2016-12-24 15:43:25 +00:00
|
|
|
if (success == ProgressResult::Success || success == ProgressResult::Stopped) {
|
2019-02-12 00:10:48 +00:00
|
|
|
mExported.push_back(fullPath);
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
2015-08-24 05:34:59 +00:00
|
|
|
Refresh();
|
|
|
|
Update();
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:17:04 +00:00
|
|
|
wxString ExportMultiple::MakeFileName(const wxString &input)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2016-06-21 02:23:06 +00:00
|
|
|
wxString newname = input; // name we are generating
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// strip out anything that isn't allowed in file names on this platform
|
2016-06-21 02:23:06 +00:00
|
|
|
auto changed = Internat::SanitiseFilename(newname, wxT("_"));
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-06-21 02:23:06 +00:00
|
|
|
if(changed)
|
2010-01-23 19:44:49 +00:00
|
|
|
{ // need to get user to fix file name
|
|
|
|
// build the dialog
|
|
|
|
wxString msg;
|
2016-09-07 14:53:23 +00:00
|
|
|
wxString excluded = ::wxJoin( Internat::GetExcludedCharacters(), wxChar(' ') );
|
|
|
|
// TODO: For Russian langauge we should have separate cases for 2 and more than 2 letters.
|
2019-03-06 19:53:39 +00:00
|
|
|
if( excluded.length() > 1 ){
|
2016-11-21 10:31:52 +00:00
|
|
|
// i18n-hint: The second %s gives some letters that can't be used.
|
2017-10-09 05:03:14 +00:00
|
|
|
msg.Printf(_("Label or track \"%s\" is not a legal file name. You cannot use any of: %s\nUse..."), input,
|
|
|
|
excluded);
|
2016-09-07 14:53:23 +00:00
|
|
|
} else {
|
2016-11-21 10:31:52 +00:00
|
|
|
// i18n-hint: The second %s gives a letter that can't be used.
|
2017-10-09 05:03:14 +00:00
|
|
|
msg.Printf(_("Label or track \"%s\" is not a legal file name. You cannot use \"%s\".\nUse..."), input,
|
|
|
|
excluded);
|
2016-09-07 14:53:23 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:49:57 +00:00
|
|
|
AudacityTextEntryDialog dlg( this, msg, _("Save As..."), newname );
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-09-07 14:53:23 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
// And tell the validator about excluded chars
|
|
|
|
dlg.SetTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
|
|
|
|
wxTextValidator *tv = dlg.GetTextValidator();
|
2016-06-21 02:23:06 +00:00
|
|
|
tv->SetExcludes(Internat::GetExcludedCharacters());
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Show the dialog and bail if the user cancels
|
|
|
|
if( dlg.ShowModal() == wxID_CANCEL )
|
|
|
|
{
|
|
|
|
return wxEmptyString;
|
|
|
|
}
|
|
|
|
// Extract the name from the dialog
|
|
|
|
newname = dlg.GetValue();
|
|
|
|
} // phew - end of file name sanitisation procedure
|
|
|
|
return newname;
|
|
|
|
}
|
2015-08-05 07:28:42 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
void SuccessDialog::OnKeyDown(wxListEvent& event)
|
|
|
|
{
|
|
|
|
if (event.GetKeyCode() == WXK_RETURN)
|
|
|
|
EndModal(1);
|
|
|
|
else
|
|
|
|
event.Skip(); // allow standard behaviour
|
|
|
|
}
|
|
|
|
|
2013-08-25 21:51:26 +00:00
|
|
|
void SuccessDialog::OnItemActivated(wxListEvent& WXUNUSED(event))
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
|
|
|
EndModal(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MouseEvtHandler::OnMouse(wxMouseEvent& event)
|
|
|
|
{
|
|
|
|
event.Skip(false);
|
|
|
|
}
|