diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp index 21b16e939..82437e11f 100644 --- a/src/effects/Amplify.cpp +++ b/src/effects/Amplify.cpp @@ -179,13 +179,10 @@ bool EffectAmplify::Init() void EffectAmplify::Preview(bool dryOnly) { - double ratio = mRatio; - double peak = mPeak; + auto cleanup1 = valueRestorer( mRatio ); + auto cleanup2 = valueRestorer( mPeak ); Effect::Preview(dryOnly); - - mRatio = ratio; - mPeak = peak; } void EffectAmplify::PopulateOrExchange(ShuttleGui & S) diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 41338f0fa..954f733fb 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -1092,9 +1092,7 @@ bool EffectEqualization::ProcessOne(int count, WaveTrack * t, for(size_t j = mM - 1; j < wcopy; j++) buffer[i+j] = thisWindow[j]; - float *tempP = thisWindow; - thisWindow = lastWindow; - lastWindow = tempP; + std::swap( thisWindow, lastWindow ); } //next i, lump of this block output->Append((samplePtr)buffer.get(), floatSample, block); diff --git a/src/effects/Equalization48x.cpp b/src/effects/Equalization48x.cpp index 594f76355..0a6c2170c 100644 --- a/src/effects/Equalization48x.cpp +++ b/src/effects/Equalization48x.cpp @@ -16,6 +16,7 @@ #include "../Audacity.h" #include "../Experimental.h" #ifdef EXPERIMENTAL_EQ_SSE_THREADED +#include "../MemoryX.h" #include "../Project.h" #include "Equalization.h" #include "../WaveTrack.h" @@ -296,6 +297,7 @@ bool EffectEqualization48x::Process(EffectEqualization* effectEqualization) if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(sMathPath&MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); SelectedTrackListOfKindIterator iter(Track::Wave, mEffectEqualization->mOutputTracks.get()); WaveTrack *track = (WaveTrack *) iter.First(); int count = 0; @@ -316,7 +318,6 @@ bool EffectEqualization48x::Process(EffectEqualization* effectEqualization) track = (WaveTrack *) iter.Next(); count++; } - FreeBuffersWorkers(); mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); return !bBreakLoop; @@ -331,6 +332,7 @@ bool EffectEqualization48x::TrackCompare() if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(sMathPath&MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); // Reset map // PRL: These two maps aren't really used std::vector SecondIMap; @@ -402,9 +404,8 @@ bool EffectEqualization48x::TrackCompare() track = (WaveTrack *) iter.Next(); track2 = (WaveTrack *) iter2.Next(); } - FreeBuffersWorkers(); - mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); - return bBreakLoop; + mEffectEqualization->ReplaceProcessedTracks(!bBreakLoop); + return bBreakLoop; // return !bBreakLoop ? } bool EffectEqualization48x::DeltaTrack(WaveTrack * t, WaveTrack * t2, sampleCount start, sampleCount len) @@ -446,6 +447,7 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) if(sMathPath) // !!! Filter MUST BE QUAD WORD ALIGNED !!!! mEffectEqualization->mM=(mEffectEqualization->mM&(~15))+1; AllocateBuffersWorkers(MATH_FUNCTION_THREADED); + auto cleanup = finally( [&] { FreeBuffersWorkers(); } ); SelectedTrackListOfKindIterator iter(Track::Wave, mEffectEqualization->mOutputTracks.get()); long times[] = { 0,0,0,0,0 }; @@ -494,7 +496,6 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) times[i]=timer.Time(); } } - FreeBuffersWorkers(); mBenching=false; bBreakLoop=false; mEffectEqualization->ReplaceProcessedTracks(bBreakLoop); @@ -507,7 +508,7 @@ bool EffectEqualization48x::Benchmark(EffectEqualization* effectEqualization) wxMessageBox(wxString::Format(_("Benchmark times:\nOriginal: %s\nDefault Segmented: %s\nDefault Threaded: %s\nSSE: %s\nSSE Threaded: %s\n"),tsDefault.Format(wxT("%M:%S.%l")).c_str(), tsDefaultEnhanced.Format(wxT("%M:%S.%l")).c_str(), tsDefaultThreaded.Format(wxT("%M:%S.%l")).c_str(),tsSSE.Format(wxT("%M:%S.%l")).c_str(),tsSSEThreaded.Format(wxT("%M:%S.%l")).c_str())); - return bBreakLoop; + return bBreakLoop; // return !bBreakLoop ? } bool EffectEqualization48x::ProcessTail(WaveTrack * t, WaveTrack * output, sampleCount start, sampleCount len) @@ -862,30 +863,32 @@ bool EffectEqualization48x::ProcessOne4x(int count, WaveTrack * t, ProcessTail(t, output.get(), start, len); return bBreakLoop; } + void *EQWorker::Entry() { while(!mExitLoop) { - mMutex->Lock(); - bool bufferAquired=false; - for(int i=0;iUnlock(); - switch (mProcessingType) - { + int i = 0; + { + wxMutexLocker locker( mMutex ); + for(; i < mBufferInfoCount; i++) { + if(mBufferInfoList[i].mBufferStatus==BufferReady) { // we found an unlocked ready buffer + mBufferInfoList[i].mBufferStatus=BufferBusy; // we own it now + break; + } + } + } + if ( i < mBufferInfoCount ) { + switch (mProcessingType) + { case 1: mEffectEqualization48x->ProcessBuffer1x(&mBufferInfoList[i]); break; - case 4: + case 4: mEffectEqualization48x->ProcessBuffer4x(&mBufferInfoList[i]); break; - } - mBufferInfoList[i].mBufferStatus=BufferDone; // we're done - break; - } - if(!bufferAquired) - mMutex->Unlock(); + } + mBufferInfoList[i].mBufferStatus=BufferDone; // we're done + } } return NULL; } @@ -940,7 +943,7 @@ bool EffectEqualization48x::ProcessOne1x4xThreaded(int count, WaveTrack * t, bBreakLoop=mEffectEqualization->TrackProgress(count, (double)(bigBlocksWritten)/bigRuns.as_double()); if( bBreakLoop ) break; - mDataMutex.Lock(); // Get in line for data + wxMutexLocker locker( mDataMutex ); // Get in line for data // process as many blocks as we can while((mBufferInfo[currentIndex].mBufferStatus==BufferDone) && (bigBlocksWrittenAppend((samplePtr)&mBufferInfo[currentIndex].mBufferDest[0][(bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1)], floatSample, subBufferSize-((bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1))); @@ -961,7 +964,6 @@ bool EffectEqualization48x::ProcessOne1x4xThreaded(int count, WaveTrack * t, } else mBufferInfo[currentIndex].mBufferStatus=BufferEmpty; // this is completely unecessary currentIndex=(currentIndex+1)%mWorkerDataCount; } - mDataMutex.Unlock(); // Get back in line for data } if(singleProcessLength && !bBreakLoop) { t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1)); @@ -1237,7 +1239,7 @@ bool EffectEqualization48x::ProcessOne8xThreaded(int count, WaveTrack * t, { break; } - mDataMutex.Lock(); // Get in line for data + wxMutexLocker locker( mDataMutex ); // Get in line for data // process as many blocks as we can while((mBufferInfo[currentIndex].mBufferStatus==BufferDone) && (bigBlocksWrittenAppend((samplePtr)&mBufferInfo[currentIndex].mBufferDest[0][(bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1)], floatSample, mSubBufferSize-((bigBlocksWritten?mBlockSize:0)+(mFilterSize>>1))); @@ -1258,7 +1260,6 @@ bool EffectEqualization48x::ProcessOne8xThreaded(int count, WaveTrack * t, } else mBufferInfo[currentIndex].mBufferStatus=BufferEmpty; // this is completely unecessary currentIndex=(currentIndex+1)%mWorkerDataCount; } - mDataMutex.Unlock(); // Get back in line for data } if(singleProcessLength && !bBreakLoop) { t->Get((samplePtr)mBigBuffer.get(), floatSample, currentSample, singleProcessLength+mBlockSize+(mFilterSize>>1)); diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index 24e494151..647879780 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -1656,14 +1656,11 @@ void EffectNoiseReduction::Dialog::OnPreview(wxCommandEvent & WXUNUSED(event)) return; // Save & restore parameters around Preview, because we didn't do OK. - EffectNoiseReduction::Settings oldSettings(*m_pSettings); - + auto cleanup = valueRestorer( *m_pSettings ); *m_pSettings = mTempSettings; m_pSettings->mDoProfile = false; m_pEffect->Preview(); - - *m_pSettings = oldSettings; } void EffectNoiseReduction::Dialog::OnReduceNoise( wxCommandEvent & WXUNUSED(event)) diff --git a/src/effects/NoiseRemoval.cpp b/src/effects/NoiseRemoval.cpp index 26b50e2c6..761bf6098 100644 --- a/src/effects/NoiseRemoval.cpp +++ b/src/effects/NoiseRemoval.cpp @@ -224,7 +224,6 @@ bool EffectNoiseRemoval::Process() auto len = end - start; if (!ProcessOne(count, track, start, len)) { - Cleanup(); bGoodResult = false; break; } @@ -238,8 +237,6 @@ bool EffectNoiseRemoval::Process() mDoProfile = false; } - if (bGoodResult) - Cleanup(); this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; } @@ -305,7 +302,7 @@ void EffectNoiseRemoval::Initialize() } } -void EffectNoiseRemoval::Cleanup() +void EffectNoiseRemoval::End() { hFFT.reset(); @@ -322,6 +319,8 @@ void EffectNoiseRemoval::Cleanup() mInWaveBuffer.reset(); mWindow.reset(); mOutOverlapBuffer.reset(); + + mOutputTrack.reset(); } void EffectNoiseRemoval::StartNewTrack() @@ -579,9 +578,6 @@ bool EffectNoiseRemoval::ProcessOne(int count, WaveTrack * track, bool bResult = track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false); wxASSERT(bResult); // TO DO: Actually handle this. } - - // Delete the outputTrack now that its data is inserted in place - mOutputTrack.reset(); } return bLoopSuccess; @@ -688,14 +684,16 @@ void NoiseRemovalDialog::OnPreview(wxCommandEvent & WXUNUSED(event)) m_pEffect->mFreqSmoothingHz = mFreq; m_pEffect->mAttackDecayTime = mTime; - m_pEffect->Preview(); + auto cleanup = finally( [&] { + m_pEffect->mSensitivity = oldSensitivity; + m_pEffect->mNoiseGain = oldGain; + m_pEffect->mFreqSmoothingHz = oldFreq; + m_pEffect->mAttackDecayTime = oldTime; + m_pEffect->mbLeaveNoise = oldLeaveNoise; + m_pEffect->mDoProfile = oldDoProfile; + } ); - m_pEffect->mSensitivity = oldSensitivity; - m_pEffect->mNoiseGain = oldGain; - m_pEffect->mFreqSmoothingHz = oldFreq; - m_pEffect->mAttackDecayTime = oldTime; - m_pEffect->mbLeaveNoise = oldLeaveNoise; - m_pEffect->mDoProfile = oldDoProfile; + m_pEffect->Preview(); } void NoiseRemovalDialog::OnRemoveNoise( wxCommandEvent & WXUNUSED(event)) diff --git a/src/effects/NoiseRemoval.h b/src/effects/NoiseRemoval.h index ba13bb4dc..3e888aa2a 100644 --- a/src/effects/NoiseRemoval.h +++ b/src/effects/NoiseRemoval.h @@ -61,6 +61,7 @@ public: bool Init() override; bool CheckWhetherSkipEffect() override; bool Process() override; + void End() override; private: @@ -98,7 +99,6 @@ private: void RemoveNoise(); void RotateHistoryWindows(); void FinishTrack(); - void Cleanup(); // Variables that only exist during processing std::unique_ptr mOutputTrack; diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 91070f553..8278cd7ac 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -34,8 +34,6 @@ public: ResampleBuf() { processed = 0; - outputLeftTrack = NULL; - outputRightTrack = NULL; } ~ResampleBuf() diff --git a/src/effects/SimpleMono.cpp b/src/effects/SimpleMono.cpp index da48e3595..cd247ded7 100644 --- a/src/effects/SimpleMono.cpp +++ b/src/effects/SimpleMono.cpp @@ -103,10 +103,9 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track, track->Get((samplePtr) buffer.get(), floatSample, s, block); //Process the buffer. If it fails, clean up and exit. - if (!ProcessSimpleMono(buffer.get(), block)) { + if (!ProcessSimpleMono(buffer.get(), block)) //Return false because the effect failed. return false; - } //Processing succeeded. copy the newly-changed samples back //onto the track. @@ -118,9 +117,8 @@ bool EffectSimpleMono::ProcessOne(WaveTrack * track, //Update the Progress meter if (TrackProgress(mCurTrackNum, (s - start).as_double() / - len)) { + len)) return false; - } } //Return true because the effect processing succeeded. diff --git a/src/effects/SoundTouchEffect.cpp b/src/effects/SoundTouchEffect.cpp index 1783d16c5..b56de741c 100644 --- a/src/effects/SoundTouchEffect.cpp +++ b/src/effects/SoundTouchEffect.cpp @@ -159,14 +159,17 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) if (bGoodResult) ReplaceProcessedTracks(bGoodResult); - mSoundTouch.reset(); - // mT0 = mCurT0; // mT1 = mCurT0 + m_maxNewLength; // Update selection. return bGoodResult; } +void EffectSoundTouch::End() +{ + mSoundTouch.reset(); +} + //ProcessOne() takes a track, transforms it to bunch of buffer-blocks, //and executes ProcessSoundTouch on these blocks bool EffectSoundTouch::ProcessOne(WaveTrack *track, @@ -345,7 +348,7 @@ bool EffectSoundTouch::ProcessStereo( return true; } -bool EffectSoundTouch::ProcessStereoResults(const unsigned int outputCount, +bool EffectSoundTouch::ProcessStereoResults(const size_t outputCount, WaveTrack* outputLeftTrack, WaveTrack* outputRightTrack) { diff --git a/src/effects/SoundTouchEffect.h b/src/effects/SoundTouchEffect.h index ed38f94ad..7588766cf 100644 --- a/src/effects/SoundTouchEffect.h +++ b/src/effects/SoundTouchEffect.h @@ -39,6 +39,10 @@ class EffectSoundTouch /* not final */ : public Effect { public: + // Effect implementation + + void End() override; + // EffectSoundTouch implementation #ifdef USE_MIDI @@ -66,7 +70,7 @@ private: bool ProcessStereo(WaveTrack* leftTrack, WaveTrack* rightTrack, sampleCount start, sampleCount end, const TimeWarper &warper); - bool ProcessStereoResults(const unsigned int outputCount, + bool ProcessStereoResults(const size_t outputCount, WaveTrack* outputLeftTrack, WaveTrack* outputRightTrack); diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index a5e257497..f4721f067 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -125,11 +125,15 @@ bool EffectStereoToMono::Process() count++; } - mOutTrack.reset(); this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; } +void EffectStereoToMono::End() +{ + mOutTrack.reset(); +} + bool EffectStereoToMono::ProcessOne(int count) { float curLeftFrame; diff --git a/src/effects/StereoToMono.h b/src/effects/StereoToMono.h index d65f4eff6..754a7ba19 100644 --- a/src/effects/StereoToMono.h +++ b/src/effects/StereoToMono.h @@ -41,6 +41,7 @@ public: // Effect implementation bool Process() override; + void End() override; bool IsHidden() override; private: diff --git a/src/effects/TimeScale.cpp b/src/effects/TimeScale.cpp index 225493174..1501726ce 100644 --- a/src/effects/TimeScale.cpp +++ b/src/effects/TimeScale.cpp @@ -165,9 +165,8 @@ double EffectTimeScale::CalcPreviewInputLength(double previewLength) void EffectTimeScale::Preview(bool dryOnly) { previewSelectedDuration = Effect::GetDuration(); - bPreview = true; + auto cleanup = valueRestorer( bPreview, true ); Effect::Preview(dryOnly); - bPreview = false; } bool EffectTimeScale::Process() diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index a402dc8dc..6d4736bb8 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -117,6 +117,8 @@ END_EVENT_TABLE() NyquistEffect::NyquistEffect(const wxString &fName) { + mOutputTrack[0] = mOutputTrack[1] = nullptr; + mAction = _("Applying Nyquist Effect..."); mInputCmd = wxEmptyString; mCmd = wxEmptyString; @@ -670,6 +672,13 @@ _("Selection too long for Nyquist code.\nMaximum allowed selection is %ld sample nyx_set_os_callback(StaticOSCallback, (void *)this); nyx_capture_output(StaticOutputCallback, (void *)this); + auto cleanup = finally( [&] { + nyx_capture_output(NULL, (void *)NULL); + nyx_set_os_callback(NULL, (void *)NULL); + nyx_cleanup(); + } ); + + if (mVersion >= 4) { mPerTrackProps = wxEmptyString; @@ -709,10 +718,6 @@ _("Selection too long for Nyquist code.\nMaximum allowed selection is %ld sample success = ProcessOne(); - nyx_capture_output(NULL, (void *)NULL); - nyx_set_os_callback(NULL, (void *)NULL); - nyx_cleanup(); - // Reset previous locale wxSetlocale(LC_NUMERIC, prevlocale); @@ -1110,16 +1115,23 @@ bool NyquistEffect::ProcessOne() cmd += mCmd; } - int i; - for (i = 0; i < mCurNumChannels; i++) { + // Put the fetch buffers in a clean initial state + for (size_t i = 0; i < mCurNumChannels; i++) mCurBuffer[i].Free(); - } + // Guarantee release of memory when done + auto cleanup = finally( [&] { + for (size_t i = 0; i < mCurNumChannels; i++) + mCurBuffer[i].Free(); + } ); + + // Evaluate the expression, which may invoke the get callback, but often does + // not, leaving that to delayed evaluation of the output sound rval = nyx_eval_expression(cmd.mb_str(wxConvUTF8)); // Audacity has no idea how long Nyquist processing will take, but // can monitor audio being returned. - // Anything other than audio should be returmed almost instantly + // Anything other than audio should be returned almost instantly // so notify the user that process has completed (bug 558) if ((rval != nyx_audio) && ((mCount + mCurNumChannels) == mNumSelectedChannels)) { if (mCurNumChannels == 1) { @@ -1225,19 +1237,30 @@ bool NyquistEffect::ProcessOne() return false; } + std::unique_ptr outputTrack[2]; + double rate = mCurTrack[0]->GetRate(); - for (i = 0; i < outChannels; i++) { + for (size_t i = 0; i < outChannels; i++) { sampleFormat format = mCurTrack[i]->GetSampleFormat(); if (outChannels == (int)mCurNumChannels) { rate = mCurTrack[i]->GetRate(); } - mOutputTrack[i] = mFactory->NewWaveTrack(format, rate); + outputTrack[i] = mFactory->NewWaveTrack(format, rate); + + // Clean the initial buffer states again for the get callbacks + // -- is this really needed? mCurBuffer[i].Free(); } - int success = nyx_get_audio(StaticPutCallback, (void *)this); + // Now fully evaluate the sound + int success; + { + auto vr0 = valueRestorer( mOutputTrack[0], outputTrack[0].get() ); + auto vr1 = valueRestorer( mOutputTrack[1], outputTrack[1].get() ); + success = nyx_get_audio(StaticPutCallback, (void *)this); + } // See if GetCallback found read errors if (mFailedFileName.IsOk()) @@ -1250,38 +1273,29 @@ bool NyquistEffect::ProcessOne() // what, then? success = false; - if (!success) { - for(i = 0; i < outChannels; i++) { - mOutputTrack[i].reset(); - } - + if (!success) return false; - } - for (i = 0; i < outChannels; i++) { - mOutputTrack[i]->Flush(); - mCurBuffer[i].Free(); - mOutputTime = mOutputTrack[i]->GetEndTime(); + for (size_t i = 0; i < outChannels; i++) { + outputTrack[i]->Flush(); + mOutputTime = outputTrack[i]->GetEndTime(); if (mOutputTime <= 0) { wxMessageBox(_("Nyquist did not return audio.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mUIParent); - for (int j = 0; j < outChannels; j++) { - mOutputTrack[j].reset(); - } return true; } } - for (i = 0; i < mCurNumChannels; i++) { + for (size_t i = 0; i < mCurNumChannels; i++) { WaveTrack *out; if (outChannels == (int)mCurNumChannels) { - out = mOutputTrack[i].get(); + out = outputTrack[i].get(); } else { - out = mOutputTrack[0].get(); + out = outputTrack[0].get(); } if (mMergeClips < 0) { @@ -1310,9 +1324,6 @@ bool NyquistEffect::ProcessOne() mFirstInGroup = false; } - for (i = 0; i < outChannels; i++) { - mOutputTrack[i].reset(); - } mProjectChanged = true; return true; } diff --git a/src/effects/nyquist/Nyquist.h b/src/effects/nyquist/Nyquist.h index 7009d4ece..6db9e0b04 100644 --- a/src/effects/nyquist/Nyquist.h +++ b/src/effects/nyquist/Nyquist.h @@ -224,7 +224,7 @@ private: sampleCount mCurBufferStart[2]; size_t mCurBufferLen[2]; - std::unique_ptr mOutputTrack[2]; + WaveTrack *mOutputTrack[2]; wxArrayString mCategories;