1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-26 17:18:41 +02:00

Eliminate some more news and deletes, with the help of class Maybe...

... which can stack-allocate an object conditionally.

(Name inspired by Haskell.)
This commit is contained in:
Paul Licameli 2016-02-25 20:18:46 -05:00
commit 0eb4de9304
11 changed files with 268 additions and 174 deletions

View File

@ -242,4 +242,118 @@ namespace std {
} }
#endif #endif
/*
* template class Maybe<X>
* Can be used for monomorphic objects that are stack-allocable, but only conditionally constructed.
* You might also use it as a member.
* Initialize with create(), then use like a smart pointer,
* with *, ->, get(), reset(), or in if()
*/
template<typename X>
class Maybe {
public:
// Construct as NULL
Maybe() {}
// Supply the copy and move, so you might use this as a class member too
Maybe(const Maybe &that)
{
if (that.get())
create(*that);
}
Maybe& operator= (const Maybe &that)
{
if (this != &that) {
if (that.get())
create(*that);
else
reset();
}
return *this;
}
Maybe(Maybe &&that)
{
if (that.get())
create(::std::move(*that));
}
Maybe& operator= (Maybe &&that)
{
if (this != &that) {
if (that.get())
create(::std::move(*that));
else
reset();
}
return *this;
}
// Make an object in the buffer, passing constructor arguments,
// but destroying any previous object first
// Note that if constructor throws, we remain in a consistent
// NULL state -- giving exception safety but only weakly
// (previous value was lost if present)
template<typename... Args>
void create(Args... args)
{
// Lose any old value
reset();
// Create new value
pp = safenew(address()) X( std::forward<Args>(args)... );
}
// Destroy any object that was built in it
~Maybe()
{
reset();
}
// Pointer-like operators
// Dereference, with the usual bad consequences if NULL
X &operator* () const
{
return *pp;
}
X *operator-> () const
{
return pp;
}
X* get() const
{
return pp;
}
void reset()
{
if (pp)
pp->~X(), pp = nullptr;
}
// So you can say if(ptr)
explicit operator bool() const
{
return pp != nullptr;
}
private:
X* address()
{
return reinterpret_cast<X*>(&storage);
}
// Data
typename ::std::aligned_storage<
sizeof(X)
// , alignof(X) // Not here yet in all compilers
>::type storage{};
X* pp{ nullptr };
};
#endif // __AUDACITY_H__ #endif // __AUDACITY_H__

View File

@ -317,7 +317,7 @@ void QuitAudacity(bool bForce)
AudacityProject::DeleteAllProjectsDeleteLock(); AudacityProject::DeleteAllProjectsDeleteLock();
//remove our logger //remove our logger
delete wxLog::SetActiveTarget(NULL); std::unique_ptr<wxLog>{ wxLog::SetActiveTarget(NULL) }; // DELETE
if (bForce) if (bForce)
{ {
@ -1147,7 +1147,7 @@ bool AudacityApp::OnInit()
// Ensure we have an event loop during initialization // Ensure we have an event loop during initialization
wxEventLoopGuarantor eventLoop; wxEventLoopGuarantor eventLoop;
delete wxLog::SetActiveTarget(new AudacityLogger); std::unique_ptr < wxLog > { wxLog::SetActiveTarget(new AudacityLogger) }; // DELETE
mLocale = NULL; mLocale = NULL;

View File

@ -1343,72 +1343,67 @@ bool AudioIO::StartPortAudioStream(double sampleRate,
mNumPlaybackChannels = numPlaybackChannels; mNumPlaybackChannels = numPlaybackChannels;
mNumCaptureChannels = numCaptureChannels; mNumCaptureChannels = numCaptureChannels;
PaStreamParameters *playbackParameters = NULL; bool usePlayback = false, useCapture = false;
PaStreamParameters *captureParameters = NULL; PaStreamParameters playbackParameters{};
PaStreamParameters captureParameters{};
double latencyDuration = DEFAULT_LATENCY_DURATION; double latencyDuration = DEFAULT_LATENCY_DURATION;
gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration); gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration);
if( numPlaybackChannels > 0) if( numPlaybackChannels > 0)
{ {
playbackParameters = new PaStreamParameters; usePlayback = true;
// this sets the device index to whatever is "right" based on preferences, // this sets the device index to whatever is "right" based on preferences,
// then defaults // then defaults
playbackParameters->device = getPlayDevIndex(); playbackParameters.device = getPlayDevIndex();
const PaDeviceInfo *playbackDeviceInfo; const PaDeviceInfo *playbackDeviceInfo;
playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters->device ); playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
if( playbackDeviceInfo == NULL ) if( playbackDeviceInfo == NULL )
{
delete playbackParameters;
return false; return false;
}
// regardless of source formats, we always mix to float // regardless of source formats, we always mix to float
playbackParameters->sampleFormat = paFloat32; playbackParameters.sampleFormat = paFloat32;
playbackParameters->hostApiSpecificStreamInfo = NULL; playbackParameters.hostApiSpecificStreamInfo = NULL;
playbackParameters->channelCount = mNumPlaybackChannels; playbackParameters.channelCount = mNumPlaybackChannels;
if (mSoftwarePlaythrough) if (mSoftwarePlaythrough)
playbackParameters->suggestedLatency = playbackParameters.suggestedLatency =
playbackDeviceInfo->defaultLowOutputLatency; playbackDeviceInfo->defaultLowOutputLatency;
else else
playbackParameters->suggestedLatency = latencyDuration/1000.0; playbackParameters.suggestedLatency = latencyDuration/1000.0;
mOutputMeter = mOwningProject->GetPlaybackMeter(); mOutputMeter = mOwningProject->GetPlaybackMeter();
} }
if( numCaptureChannels > 0) if( numCaptureChannels > 0)
{ {
useCapture = true;
mCaptureFormat = captureFormat; mCaptureFormat = captureFormat;
captureParameters = new PaStreamParameters;
const PaDeviceInfo *captureDeviceInfo; const PaDeviceInfo *captureDeviceInfo;
// retrieve the index of the device set in the prefs, or a sensible // retrieve the index of the device set in the prefs, or a sensible
// default if it isn't set/valid // default if it isn't set/valid
captureParameters->device = getRecordDevIndex(); captureParameters.device = getRecordDevIndex();
captureDeviceInfo = Pa_GetDeviceInfo( captureParameters->device ); captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
if( captureDeviceInfo == NULL ) if( captureDeviceInfo == NULL )
{
delete captureParameters;
delete playbackParameters;
return false; return false;
}
captureParameters->sampleFormat = captureParameters.sampleFormat =
AudacityToPortAudioSampleFormat(mCaptureFormat); AudacityToPortAudioSampleFormat(mCaptureFormat);
captureParameters->hostApiSpecificStreamInfo = NULL; captureParameters.hostApiSpecificStreamInfo = NULL;
captureParameters->channelCount = mNumCaptureChannels; captureParameters.channelCount = mNumCaptureChannels;
if (mSoftwarePlaythrough) if (mSoftwarePlaythrough)
captureParameters->suggestedLatency = captureParameters.suggestedLatency =
captureDeviceInfo->defaultHighInputLatency; captureDeviceInfo->defaultHighInputLatency;
else else
captureParameters->suggestedLatency = latencyDuration/1000.0; captureParameters.suggestedLatency = latencyDuration/1000.0;
mInputMeter = mOwningProject->GetCaptureMeter(); mInputMeter = mOwningProject->GetCaptureMeter();
} }
@ -1429,7 +1424,8 @@ bool AudioIO::StartPortAudioStream(double sampleRate,
#endif #endif
#endif #endif
mLastPaError = Pa_OpenStream( &mPortStreamV19, mLastPaError = Pa_OpenStream( &mPortStreamV19,
captureParameters, playbackParameters, useCapture ? &captureParameters : NULL,
usePlayback ? &playbackParameters : NULL,
mRate, paFramesPerBufferUnspecified, mRate, paFramesPerBufferUnspecified,
paNoFlag, paNoFlag,
audacityAudioCallback, NULL ); audacityAudioCallback, NULL );
@ -1457,10 +1453,6 @@ bool AudioIO::StartPortAudioStream(double sampleRate,
} }
#endif #endif
// these may be null, but deleting a null pointer should never crash.
delete captureParameters;
delete playbackParameters;
return (mLastPaError == paNoError); return (mLastPaError == paNoError);
} }

View File

@ -597,25 +597,27 @@ AliasBlockFile::~AliasBlockFile()
bool AliasBlockFile::ReadSummary(void *data) bool AliasBlockFile::ReadSummary(void *data)
{ {
wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb"));
wxLogNull *silence=0;
if(mSilentLog)silence= new wxLogNull();
if( !summaryFile.IsOpened() ){ {
Maybe<wxLogNull> silence{};
if (mSilentLog)
silence.create();
// NEW model; we need to return valid data if (!summaryFile.IsOpened()){
memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes);
if(silence) delete silence;
// we silence the logging for this operation in this object // NEW model; we need to return valid data
// after first occurrence of error; it's already reported and memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes);
// spewing at the user will complicate the user's ability to
// deal
mSilentLog=TRUE;
return true;
}else mSilentLog=FALSE; // worked properly, any future error is NEW // we silence the logging for this operation in this object
// after first occurrence of error; it's already reported and
// spewing at the user will complicate the user's ability to
// deal
mSilentLog = TRUE;
return true;
if(silence) delete silence; }
else mSilentLog = FALSE; // worked properly, any future error is NEW
}
int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes); int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);

View File

@ -197,7 +197,6 @@ static int RecursivelyEnumerate(wxString dirPath,
return count; return count;
} }
static int RecursivelyEnumerateWithProgress(wxString dirPath, static int RecursivelyEnumerateWithProgress(wxString dirPath,
wxArrayString& filePathArray, // output: all files in dirPath tree wxArrayString& filePathArray, // output: all files in dirPath tree
wxString dirspec, wxString dirspec,
@ -205,19 +204,16 @@ static int RecursivelyEnumerateWithProgress(wxString dirPath,
int progress_count, int progress_count,
const wxChar* message) const wxChar* message)
{ {
ProgressDialog *progress = NULL; Maybe<ProgressDialog> progress{};
if (message) if (message)
progress = new ProgressDialog(_("Progress"), message); progress.create( _("Progress"), message );
int count = RecursivelyEnumerate( int count = RecursivelyEnumerate(
dirPath, filePathArray, dirspec, dirPath, filePathArray, dirspec,
bFiles, bDirs, bFiles, bDirs,
progress_count, 0, progress_count, 0,
progress); progress.get());
if (progress)
delete progress;
return count; return count;
} }
@ -291,10 +287,10 @@ static void RecursivelyRemove(wxArrayString& filePathArray, int count,
bool bFiles, bool bDirs, bool bFiles, bool bDirs,
const wxChar* message = NULL) const wxChar* message = NULL)
{ {
ProgressDialog *progress = NULL; Maybe<ProgressDialog> progress{};
if (message) if (message)
progress = new ProgressDialog(_("Progress"), message); progress.create( _("Progress"), message );
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
const wxChar *file = filePathArray[i].c_str(); const wxChar *file = filePathArray[i].c_str();
@ -305,9 +301,6 @@ static void RecursivelyRemove(wxArrayString& filePathArray, int count,
if (progress) if (progress)
progress->Update(i, count); progress->Update(i, count);
} }
if (progress)
delete progress;
} }

View File

@ -69,26 +69,28 @@ void ComputeLegacySummaryInfo(wxFileName fileName,
SampleBuffer data(info->frames64K * fields, SampleBuffer data(info->frames64K * fields,
info->format); info->format);
wxLogNull *silence=0;
wxFFile summaryFile(fileName.GetFullPath(), wxT("rb"));
int read; int read;
if(Silent)silence= new wxLogNull(); {
Maybe<wxLogNull> silence{};
wxFFile summaryFile(fileName.GetFullPath(), wxT("rb"));
if (Silent)
silence.create();
if( !summaryFile.IsOpened() ) { if (!summaryFile.IsOpened()) {
wxLogWarning(wxT("Unable to access summary file %s; substituting silence for remainder of session"), wxLogWarning(wxT("Unable to access summary file %s; substituting silence for remainder of session"),
fileName.GetFullPath().c_str()); fileName.GetFullPath().c_str());
read=info->frames64K * info->bytesPerFrame; read = info->frames64K * info->bytesPerFrame;
memset(data.ptr(), 0, read); memset(data.ptr(), 0, read);
}else{ }
summaryFile.Seek(info->offset64K); else{
read = summaryFile.Read(data.ptr(), summaryFile.Seek(info->offset64K);
info->frames64K * read = summaryFile.Read(data.ptr(),
info->bytesPerFrame); info->frames64K *
info->bytesPerFrame);
}
} }
if(silence) delete silence;
int count = read / info->bytesPerFrame; int count = read / info->bytesPerFrame;
CopySamples(data.ptr(), info->format, CopySamples(data.ptr(), info->format,
@ -151,22 +153,23 @@ LegacyBlockFile::~LegacyBlockFile()
bool LegacyBlockFile::ReadSummary(void *data) bool LegacyBlockFile::ReadSummary(void *data)
{ {
wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb"));
wxLogNull *silence=0; int read;
if(mSilentLog)silence= new wxLogNull(); {
Maybe<wxLogNull> silence{};
if (mSilentLog)
silence.create();
if( !summaryFile.IsOpened() ){ if (!summaryFile.IsOpened()){
memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes); memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes);
if(silence) delete silence; mSilentLog = TRUE;
mSilentLog=TRUE;
return true; return true;
}
read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);
} }
int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);
if(silence) delete silence;
mSilentLog=FALSE; mSilentLog=FALSE;
return (read == mSummaryInfo.totalSummaryBytes); return (read == mSummaryInfo.totalSummaryBytes);
@ -215,19 +218,20 @@ int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
} }
wxLogNull *silence=0; {
if(mSilentLog)silence= new wxLogNull(); Maybe<wxLogNull> silence{};
if (mSilentLog)
silence.create();
if (!sf){ if (!sf){
memset(data,0,SAMPLE_SIZE(format)*len); memset(data, 0, SAMPLE_SIZE(format)*len);
if(silence) delete silence; mSilentLog = TRUE;
mSilentLog=TRUE;
return len; return len;
}
} }
if(silence) delete silence;
mSilentLog=FALSE; mSilentLog=FALSE;
sf_count_t seekstart = start + sf_count_t seekstart = start +

View File

@ -80,37 +80,37 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
return len; return len;
} }
wxLogNull *silence=0;
if(mSilentAliasLog)silence= new wxLogNull();
memset(&info, 0, sizeof(info));
wxFile f; // will be closed when it goes out of scope wxFile f; // will be closed when it goes out of scope
SNDFILE *sf = NULL; SNDFILE *sf = NULL;
{
Maybe<wxLogNull> silence{};
if (mSilentAliasLog)
silence.create();
if (f.Exists(mAliasedFileName.GetFullPath())) { // Don't use Open if file does not exits memset(&info, 0, sizeof(info));
if (f.Open(mAliasedFileName.GetFullPath())) {
// Even though there is an sf_open() that takes a filename, use the one that if (f.Exists(mAliasedFileName.GetFullPath())) { // Don't use Open if file does not exits
// takes a file descriptor since wxWidgets can open a file with a Unicode name and if (f.Open(mAliasedFileName.GetFullPath())) {
// libsndfile can't (under Windows). // Even though there is an sf_open() that takes a filename, use the one that
ODManager::LockLibSndFileMutex(); // takes a file descriptor since wxWidgets can open a file with a Unicode name and
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); // libsndfile can't (under Windows).
ODManager::UnlockLibSndFileMutex(); ODManager::LockLibSndFileMutex();
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
ODManager::UnlockLibSndFileMutex();
}
}
if (!sf){
memset(data, 0, SAMPLE_SIZE(format)*len);
silence.reset();
mSilentAliasLog = TRUE;
// Set a marker to display an error message for the silence
if (!wxGetApp().ShouldShowMissingAliasedFileWarning())
wxGetApp().MarkAliasedFilesMissingWarning(this);
return len;
} }
} }
if (!sf){
memset(data,0,SAMPLE_SIZE(format)*len);
if(silence) delete silence;
mSilentAliasLog=TRUE;
// Set a marker to display an error message for the silence
if (!wxGetApp().ShouldShowMissingAliasedFileWarning())
wxGetApp().MarkAliasedFilesMissingWarning(this);
return len;
}
if(silence) delete silence;
mSilentAliasLog=FALSE; mSilentAliasLog=FALSE;
ODManager::LockLibSndFileMutex(); ODManager::LockLibSndFileMutex();

View File

@ -345,21 +345,21 @@ bool SimpleBlockFile::ReadSummary(void *data)
wxFFile file(mFileName.GetFullPath(), wxT("rb")); wxFFile file(mFileName.GetFullPath(), wxT("rb"));
wxLogNull *silence=0; {
if(mSilentLog)silence= new wxLogNull(); Maybe<wxLogNull> silence{};
if (mSilentLog)
silence.create();
if(!file.IsOpened() ){ if (!file.IsOpened()){
memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes); memset(data, 0, (size_t)mSummaryInfo.totalSummaryBytes);
if(silence) delete silence; mSilentLog = TRUE;
mSilentLog=TRUE;
return true; return true;
}
} }
if(silence) delete silence;
mSilentLog=FALSE; mSilentLog=FALSE;
// The offset is just past the au header // The offset is just past the au header
@ -400,31 +400,31 @@ int SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
//wxLogDebug("SimpleBlockFile::ReadData(): Reading data from disk."); //wxLogDebug("SimpleBlockFile::ReadData(): Reading data from disk.");
SF_INFO info; SF_INFO info;
wxLogNull *silence=0;
if(mSilentLog)silence= new wxLogNull();
memset(&info, 0, sizeof(info));
wxFile f; // will be closed when it goes out of scope wxFile f; // will be closed when it goes out of scope
SNDFILE *sf = NULL; SNDFILE *sf = NULL;
{
Maybe<wxLogNull> silence{};
if (mSilentLog)
silence.create();
if (f.Open(mFileName.GetFullPath())) { memset(&info, 0, sizeof(info));
// Even though there is an sf_open() that takes a filename, use the one that
// takes a file descriptor since wxWidgets can open a file with a Unicode name and if (f.Open(mFileName.GetFullPath())) {
// libsndfile can't (under Windows). // Even though there is an sf_open() that takes a filename, use the one that
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); // takes a file descriptor since wxWidgets can open a file with a Unicode name and
// libsndfile can't (under Windows).
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
}
if (!sf) {
memset(data, 0, SAMPLE_SIZE(format)*len);
mSilentLog = TRUE;
return len;
}
} }
if (!sf) {
memset(data,0,SAMPLE_SIZE(format)*len);
if(silence) delete silence;
mSilentLog=TRUE;
return len;
}
if(silence) delete silence;
mSilentLog=FALSE; mSilentLog=FALSE;
sf_seek(sf, start, SEEK_SET); sf_seek(sf, start, SEEK_SET);

View File

@ -456,7 +456,7 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin
wxString effectIDs = wxT("0;"); wxString effectIDs = wxT("0;");
wxStringTokenizer effectTzr(effectIDs, wxT(";")); wxStringTokenizer effectTzr(effectIDs, wxT(";"));
wxProgressDialog *progress = NULL; Maybe<wxProgressDialog> progress{};
size_t idCnt = 0; size_t idCnt = 0;
size_t idNdx = 0; size_t idNdx = 0;
@ -517,16 +517,16 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin
idCnt = effectTzr.CountTokens(); idCnt = effectTzr.CountTokens();
if (idCnt > 3) if (idCnt > 3)
{ {
progress = new wxProgressDialog(_("Scanning Shell VST"), progress.create( _("Scanning Shell VST"),
wxString::Format(_("Registering %d of %d: %-64.64s"), 0, idCnt, proc.GetName().c_str()), wxString::Format(_("Registering %d of %d: %-64.64s"), 0, idCnt, proc.GetName().c_str()),
idCnt, static_cast<int>(idCnt),
NULL, nullptr,
wxPD_APP_MODAL | wxPD_APP_MODAL |
wxPD_AUTO_HIDE | wxPD_AUTO_HIDE |
wxPD_CAN_ABORT | wxPD_CAN_ABORT |
wxPD_ELAPSED_TIME | wxPD_ELAPSED_TIME |
wxPD_ESTIMATED_TIME | wxPD_ESTIMATED_TIME |
wxPD_REMAINING_TIME); wxPD_REMAINING_TIME );
progress->Show(); progress->Show();
} }
break; break;
@ -611,11 +611,6 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin
} }
} }
if (progress)
{
delete progress;
}
return valid; return valid;
} }

View File

@ -213,7 +213,7 @@ int MP3ImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks,
mPrivateData.file = mFile; mPrivateData.file = mFile;
mPrivateData.inputBuffer = new unsigned char [INPUT_BUFFER_SIZE]; mPrivateData.inputBuffer = new unsigned char [INPUT_BUFFER_SIZE];
mPrivateData.progress = mProgress; mPrivateData.progress = mProgress.get();
mPrivateData.channels = NULL; mPrivateData.channels = NULL;
mPrivateData.updateResult= eProgressSuccess; mPrivateData.updateResult= eProgressSuccess;
mPrivateData.id3checked = false; mPrivateData.id3checked = false;

View File

@ -119,17 +119,12 @@ class ImportFileHandle /* not final */
public: public:
ImportFileHandle(const wxString & filename) ImportFileHandle(const wxString & filename)
: mFilename(filename), : mFilename(filename),
mProgress(NULL) mProgress{}
{ {
} }
virtual ~ImportFileHandle() virtual ~ImportFileHandle()
{ {
if (mProgress != NULL)
{
delete mProgress;
mProgress = NULL;
}
} }
// The importer should call this to create the progress dialog and // The importer should call this to create the progress dialog and
@ -140,8 +135,7 @@ public:
wxString title; wxString title;
title.Printf(_("Importing %s"), GetFileDescription().c_str()); title.Printf(_("Importing %s"), GetFileDescription().c_str());
mProgress = new ProgressDialog(title, mProgress.create(title, f.GetFullName());
f.GetFullName());
} }
// This is similar to GetImporterDescription, but if possible the // This is similar to GetImporterDescription, but if possible the
@ -170,7 +164,7 @@ public:
protected: protected:
wxString mFilename; wxString mFilename;
ProgressDialog *mProgress; Maybe<ProgressDialog> mProgress;
}; };