34#include <wx/bmpbuttn.h>
35#include <wx/dcclient.h>
37#include <wx/filectrl.h>
38#include <wx/filename.h>
39#include <wx/simplebook.h>
42#include <wx/statbox.h>
43#include <wx/stattext.h>
44#include <wx/textctrl.h>
45#include <wx/dcmemory.h>
57#include "../prefs/ImportExportPrefs.h"
60#include "../ProjectSettings.h"
61#include "../ProjectWindow.h"
62#include "../ProjectWindows.h"
64#include "../TagsEditor.h"
68#include "../widgets/Warning.h"
133 mFormatInfos[index].mExtensions = std::move(extensions);
196 int indofext = defexts.Index(ext,
false);
197 if (defext.empty() || (indofext != wxNOT_FOUND))
210 S.StartHorizontalLay(wxCENTER);
212 S.StartHorizontalLay(wxCENTER, 0);
214 S.Prop(1).AddTitle(
XO(
"No format specific options"));
216 S.EndHorizontalLay();
218 S.EndHorizontalLay();
224 double startTime,
double stopTime,
225 unsigned numOutChannels,
size_t outBufferSize,
bool outInterleaved,
236 for (
auto pTrack: range)
240 return std::make_unique<Mixer>(move(inputs),
245 numOutChannels, outBufferSize, outInterleaved,
254 pDialog = std::make_unique<ProgressDialog>(
title, message );
263 pDialog->SetMessage(message);
281BEGIN_EVENT_TABLE(
Exporter, wxEvtHandler)
327 { {
wxT(
""),
wxT(
"PCM,MP3,OGG,FLAC,MP2,CommandLine,FFmpeg") } },
337 struct MyVisitor final :
Visitor {
384 for (
const auto &pPlugin :
mPlugins)
386 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
388 if (exportindex == c)
return j;
425 XO(
"Edit Metadata Tags"),
XO(
"Exported Tags"),
437 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
456 bool selectedOnly,
double t0,
double t1)
458 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
459 return Process(numChannels, type, filename, selectedOnly, t0, t1, pDialog);
463 unsigned numChannels,
const FileExtension& type,
const wxString& filename,
464 bool selectedOnly,
double t0,
double t1,
465 std::unique_ptr<BasicUI::ProgressDialog>& progressDialog)
476 for (
const auto& pPlugin :
mPlugins)
479 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
481 if (pPlugin->GetFormat(j).IsSameAs(type,
false))
507 double earliestBegin =
mT1;
508 double latestEnd =
mT0;
529 float pan = tr->GetPan();
544 if (tr->GetOffset() < earliestBegin) {
545 earliestBegin = tr->GetOffset();
548 if (tr->GetEndTime() > latestEnd) {
549 latestEnd = tr->GetEndTime();
556 message =
XO(
"All selected audio is muted.");
558 message =
XO(
"All audio is muted.");
570 if (
mT0 < earliestBegin){
574 bool skipSilenceAtBeginning;
575 gPrefs->Read(
wxT(
"/AudioFiles/SkipSilenceAtBeginning"),
576 &skipSilenceAtBeginning,
false);
577 if (skipSilenceAtBeginning)
594 if( defaultFormat.empty() )
595 defaultFormat =
gPrefs->Read(
wxT(
"/Export/Format"),
602 for (
const auto &pPlugin :
mPlugins) {
604 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
606 auto mask = pPlugin->GetMask(j);
607 fileTypes.insert( fileTypes.end(), mask.begin(), mask.end() );
608 if (
mPlugins[i]->GetFormat(j) == defaultFormat) {
635 if (!useFileName.HasExt())
636 useFileName.SetExt(defext);
640 useFileName.GetFullName(),
642 wxFD_SAVE | wxRESIZE_BORDER);
644 mDialog->PushEventHandler(
this);
653 if (result == wxID_CANCEL) {
669 for (
const auto &pPlugin :
mPlugins)
672 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
698 XO(
"Are you sure you want to export the file as \"%s\"?\n")
704 wxYES_NO | wxICON_EXCLAMATION);
705 if (action != wxYES) {
718 auto prompt =
XO(
"You are about to export a %s file with the name \"%s\".\n\nNormally these files end in \".%s\", and some programs will not open files with nonstandard extensions.\n\nAre you sure you want to export the file under this name?")
726 wxYES_NO | wxICON_EXCLAMATION);
727 if (action != wxYES) {
732 if (
mFilename.GetFullPath().length() >= 256) {
734 XO(
"Sorry, pathnames longer than 256 characters not supported.") );
739#if !defined(__WXMAC__)
741 auto prompt =
XO(
"A file named \"%s\" already exists. Replace?")
747 wxYES_NO | wxICON_EXCLAMATION);
748 if (action != wxYES) {
778 wxString::Format(
wxT(
"%d"), suffix));
788 int mf = -1, msf = -1;
790 for (
const auto &pPlugin :
mPlugins)
793 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
808#if defined(__WXMSW__)
841 if (exportFormat !=
wxT(
"CL") && exportFormat !=
wxT(
"FFMPEG") && exportedChannels == -1)
846 if (exportedChannels == 1) {
849 XO(
"Your tracks will be mixed down and exported as one mono file."),
850 true) == wxID_CANCEL)
853 else if (exportedChannels == 2) {
856 XO(
"Your tracks will be mixed down and exported as one stereo file."),
857 true) == wxID_CANCEL)
862 wxT(
"MixUnknownChannels"),
863 XO(
"Your tracks will be mixed down to one exported file according to the encoder settings."),
864 true) == wxID_CANCEL)
872 if (exportedChannels < 0)
880 XO(
"Advanced Mixing Options"));
882 if (md.ShowModal() != wxID_OK) {
895 std::unique_ptr<BasicUI::ProgressDialog>& progressDialog)
902 bool success =
false;
904 auto cleanup =
finally( [&] {
911 ::wxRemoveFile(mActualName.GetFullPath());
912 ::wxRenameFile(mFilename.GetFullPath(), mActualName.GetFullPath());
954 S.StartStatic(
XO(
"Format Options"), 1);
956 S.StartHorizontalLay(wxEXPAND);
958 mBook =
S.Position(wxEXPAND).StartSimplebook();
960 for (
const auto &pPlugin :
mPlugins)
962 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
965 S.StartNotebookPage( {} );
967 pPlugin->OptionsCreate(
S, j);
976 b->SetToolTip(
XO(
"Help").Translation() );
977 b->SetLabel(
XO(
"Help").Translation());
978 S.Position(wxALIGN_BOTTOM | wxRIGHT | wxBOTTOM).AddWindow(b);
980 S.EndHorizontalLay();
989 int index = evt.GetFilterIndex();
992 if (
mBook == NULL || index < 0 || index >= (
int)
mBook->GetPageCount())
997#if defined(__WXGTK__)
1005 for (
const auto &pPlugin :
mPlugins)
1008 for (
int j = 0; j < pPlugin->GetFormatCount(); j++)
1010 auto mask = pPlugin->GetMask(j);
1011 fileTypes.insert( fileTypes.end(), mask.begin(), mask.end() );
1015 if (index < fileTypes.size())
1022 mBook->ChangeSelection(index);
1060 std::unique_ptr<BasicUI::ProgressDialog> pDialog;
1094 XO(
"Edit Metadata Tags"),
1095 XO(
"Exported Tags"),
1115 wxArrayString trackNames,
1116 const wxPoint& pos, const wxSize&
size):
1118 , mMixerSpec{mixerSpec}
1119 , mChannelRects{ mMixerSpec->GetMaxNumChannels() }
1120 , mTrackRects{ mMixerSpec->GetNumTracks() }
1125 mSelectedTrack = mSelectedChannel = -1;
1127 mTrackNames = trackNames;
1138 int l = 0, u = 13, m, w, h;
1139 wxFont font = memDC.GetFont();
1143 font.SetPointSize( m );
1144 memDC.SetFont( font );
1145 memDC.GetTextExtent( text, &w, &h );
1147 if( w < width && h < height )
1152 font.SetPointSize( l );
1153 memDC.SetFont( font );
1158 wxPaintDC dc(
this );
1161 GetSize( &width, &height );
1170 wxColour bkgnd = GetBackgroundColour();
1171 wxBrush bkgndBrush( bkgnd, wxBRUSHSTYLE_SOLID );
1174 memDC.SelectObject( *
mBitmap );
1180 bkgndRect.width =
mWidth;
1183 memDC.SetBrush( *wxWHITE_BRUSH );
1184 memDC.SetPen( *wxBLACK_PEN );
1185 memDC.DrawRectangle( bkgndRect );
1198 static double PI = 2 * acos( 0.0 );
1200 double radius =
mHeight / ( 2.0 * sin(
PI - 2.0 * angle ) );
1201 double totAngle = ( asin(
mHeight / ( 2.0 * radius ) ) * 2.0 );
1217 cos( totAngle / 2.0 - angle * ( i + 1 ) ) -
mBoxWidth + 0.5 );
1219 sin( totAngle * 0.5 - angle * ( i + 1.0 ) ) -
1225 memDC.SetPen(
mSelectedTrack == (
int)i ? *wxRED_PEN : *wxBLACK_PEN );
1236 angle = ( asin(
mHeight / ( 2.0 * radius ) ) * 2.0 ) /
1240 memDC.GetTextExtent(
wxT(
"Channel: XX" ), &w, &h );
1245 cos( totAngle * 0.5 - angle * ( i + 1 ) ) + 0.5 );
1247 sin( totAngle * 0.5 - angle * ( i + 1 ) ) -
1256 memDC.DrawText( wxString::Format(
_(
"Channel: %2d" ), i + 1 ),
1262 memDC.SetPen( wxPen( *wxBLACK,
mHeight / 200 ) );
1270 dc.Blit( 0, 0,
mWidth,
mHeight, &memDC, 0, 0, wxCOPY, FALSE );
1275 return sqrt( pow( a.x - b.x, 2.0 ) + pow( a.y - b.y, 2.0 ) );
1286 if( event.ButtonDown() )
1291 if(
mTrackRects[ i ].Contains( event.m_x, event.m_y ) )
1360 const wxPoint &position, const wxSize&
size,
long style ) :
1365 unsigned numTracks = 0;
1375 const wxString sTrackName = (t->GetName()).Left(20);
1378 mTrackNames.push_back( wxString::Format(
_(
"%s - L" ), sTrackName ) );
1381 mTrackNames.push_back( wxString::Format(
_(
"%s - R" ), sTrackName ) );
1383 mTrackNames.push_back(sTrackName);
1392 if (maxNumChannels < 2 )
1396 if (maxNumChannels > 32)
1397 maxNumChannels = 32;
1399 mMixerSpec = std::make_unique<MixerSpec>(numTracks, maxNumChannels);
1401 auto label =
XO(
"Output Channels: %2d")
1402 .Format( mMixerSpec->GetNumChannels() );
1410 mTrackNames, wxDefaultPosition, wxSize(400, -1));
1412 .Name(
XO(
"Mixer Panel"))
1413 .Position(wxEXPAND | wxALL)
1414 .AddWindow(mixerPanel);
1416 S.StartHorizontalLay(wxALIGN_CENTER | wxALL, 0);
1418 mChannelsText =
S.AddVariableText(
1420 false, wxALIGN_LEFT | wxALL );
1426 .Style(wxSL_HORIZONTAL)
1427 .Position(wxEXPAND | wxALL)
1429 mMixerSpec->GetNumChannels(),
1430 mMixerSpec->GetMaxNumChannels(), 1 );
1432 S.EndHorizontalLay();
1437 SetAutoLayout(
true);
1438 GetSizer()->Fit(
this );
1439 GetSizer()->SetSizeHints(
this );
1441 SetSizeHints( 640, 480, 20000, 20000 );
1443 SetSize( 640, 480 );
1454 pnl->Refresh(
false );
1462 mMixerSpec->SetNumChannels( channels->GetValue() );
1463 pnl->Refresh(
false );
1467 channels->SetName(
label );
1472 EndModal( wxID_OK );
1477 EndModal( wxID_CANCEL );
1488 return XO(
"Warning");
1492 return XO(
"Unable to export.\nError %s");
1506 bool allowReporting)
1511 message.
Format( ErrorCode ),
1512 "Error:_Unable_to_export",
1513 ErrorDialogOptions { allowReporting ? ErrorDialogType::ModalErrorReport : ErrorDialogType::ModalError });
1521 "Error:_Disk_full_or_not_writable"
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Toolkit-neutral facade for basic user interface services.
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
wxDEFINE_EVENT(AUDACITY_FILE_SUFFIX_EVENT, wxCommandEvent)
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption, bool allowReporting)
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
TranslatableString AudacityExportCaptionStr()
TranslatableString AudacityExportMessageStr()
std::vector< std::unique_ptr< ExportPlugin > > ExportPluginArray
wxString FileExtension
File extension, not including any leading dot.
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
auto Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
std::vector< MixerOptions::StageSpecification > GetEffectStages(const WaveTrack &track)
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
int ShowWarningDialog(wxWindow *parent, const wxString &internalDialogName, const TranslatableString &message, bool showCancelButton, const TranslatableString &footer)
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static wxBrush playRegionBrush[1]
static wxBrush envelopeBrush
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
const wxString & GetProjectName() const
Dialog for advanced mixing.
std::unique_ptr< MixerSpec > mMixerSpec
void OnOk(wxCommandEvent &event)
void OnCancel(wxCommandEvent &event)
void OnSize(wxSizeEvent &event)
MixerSpec * GetMixerSpec()
virtual ~ExportMixerDialog()
wxStaticText * mChannelsText
void OnMixerPanelHelp(wxCommandEvent &event)
void OnSlider(wxCommandEvent &event)
Panel that displays mixing for advanced mixing option.
void OnMouseEvent(wxMouseEvent &event)
void SetFont(wxMemoryDC &memDC, const wxString &text, int width, int height)
std::unique_ptr< wxBitmap > mBitmap
bool IsOnLine(wxPoint p, wxPoint la, wxPoint lb)
void OnPaint(wxPaintEvent &event)
double Distance(wxPoint &a, wxPoint &b)
ArrayOf< wxRect > mChannelRects
ArrayOf< wxRect > mTrackRects
virtual ~ExportMixerPanel()
wxArrayString mTrackNames
virtual bool CheckFileName(wxFileName &filename, int format=0)
FileNames::FileTypes GetMask(int index)
virtual bool IsExtension(const FileExtension &ext, int index)
virtual bool DisplayOptions(wxWindow *parent, int format=0)
void SetMask(FileNames::FileTypes mask, int index)
virtual void OptionsCreate(ShuttleGui &S, int format)=0
virtual FileExtension GetExtension(int index=0)
Return the (first) file name extension for the sub-format.
virtual FileExtensions GetExtensions(int index=0)
Return all the file name extensions used for the sub-format.
TranslatableString GetDescription(int index)
virtual unsigned GetMaxChannels(int index)
void AddExtension(const FileExtension &extension, int index)
virtual int GetFormatCount()
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
virtual wxString GetFormat(int index)
static void InitProgress(std::unique_ptr< BasicUI::ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
void SetFormat(const wxString &format, int index)
std::unique_ptr< Mixer > CreateMixer(const TrackList &tracks, bool selectionOnly, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, MixerSpec *mixerSpec)
void SetDescription(const TranslatableString &description, int index)
void SetCanMetaData(bool canmetadata, int index)
std::vector< FormatInfo > mFormatInfos
virtual bool GetCanMetaData(int index)
void SetMaxChannels(unsigned maxchannels, unsigned index)
void SetExtensions(FileExtensions extensions, int index)
void OnExtensionChanged(wxCommandEvent &evt)
FileDialogWrapper * mDialog
bool Process(bool selectedOnly, double t0, double t1)
bool ExportTracks(std::unique_ptr< BasicUI::ProgressDialog > &progressDialog)
const ExportPluginArray & GetPlugins()
void SetFileDialogTitle(const TranslatableString &DialogTitle)
std::function< std::unique_ptr< ExportPlugin >() > ExportPluginFactory
int GetAutoExportFilterIndex()
bool CheckMix(bool prompt=true)
void CreateUserPane(wxWindow *parent)
int FindFormatIndex(int exportindex)
bool ProcessFromTimerRecording(bool selectedOnly, double t0, double t1, wxFileName fnFile, int iFormat, int iSubFormat, int iFilterIndex)
Exporter(AudacityProject &project)
int GetAutoExportSubFormat()
FileExtension mFormatName
void OnFilterChanged(wxFileCtrlEvent &evt)
int GetAutoExportFormat()
std::unique_ptr< MixerSpec > mMixerSpec
wxFileName GetAutoExportFileName()
void OnHelp(wxCommandEvent &evt)
bool SetAutoExportOptions()
static void CreateUserPaneCallback(wxWindow *parent, wxUIntPtr userdata)
ExportPluginArray mPlugins
AudacityProject * mProject
void DisplayOptions(int index)
TranslatableString mFileDialogTitle
virtual void SetUserPaneCreator(UserPaneCreatorFunction creator, wxUIntPtr userdata)
virtual int GetFilterIndex() const
virtual wxString GetPath() const
virtual void SetFileExtension(const wxString &extension)
virtual void SetFilterIndex(int filterIndex)
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
std::vector< FileType > FileTypes
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
An explicitly nonlocalized string, not meant for the user to see.
static EnumSetting< bool > ExportDownMixSetting
std::vector< Input > Inputs
A matrix of booleans, one row per input channel, column per output.
unsigned GetNumChannels()
static ProjectSettings & Get(AudacityProject &project)
bool GetShowId3Dialog() const
static ProjectWindow * Find(AudacityProject *pProject)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
wxBitmap & Bitmap(int iIndex)
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
A Track that contains audio waveform data.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
FILES_API FilePath FindDefaultPath(Operation op)
void Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItem *pRegistry)
ExportPluginFactories & sFactories()
std::vector< Exporter::ExportPluginFactory > ExportPluginFactories
static RegisteredToolbarFactory factory
Options for variations of error dialogs; the default is for modal dialogs.
static Registry::GroupItem & Registry()
ExporterItem(const Identifier &id, const Exporter::ExportPluginFactory &factory)
RegisteredExportPlugin(const Identifier &id, const ExportPluginFactory &, const Registry::Placement &placement={ wxEmptyString, {} })
Immutable structure is an argument to Mixer's constructor.