From 703fafacb2354185729e913f01af007980743f44 Mon Sep 17 00:00:00 2001 From: "james.k.crook@gmail.com" Date: Tue, 11 Nov 2014 18:02:31 +0000 Subject: [PATCH] Frequency-selection aware noise reduction, plus small adjustments to toolbar and effect. (patch from Paul Licameli) 1. Change in project.cpp fixes misbehavior of spectral selection toolbar, when you try to enter numbers in the low or high frequency boxes and one of the frequencies was undefined. 2. Changes in NoiseReduction.cpp now take the spectral selection into account in step 2, so that noise is reduced (or isolated) only in the selected range of frequencies. No effect on statistics gathered in step 1. 3. Other noise reduction changes: avoid an assertion in case of certain incompatible settings, and end all messages in message boxes consistently with a period. --- src/Project.cpp | 6 ++-- src/effects/NoiseReduction.cpp | 61 ++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index c23ca374c..2ddf2105f 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1263,8 +1263,10 @@ void AudacityProject::SSBL_ModifySpectralSelection(double &bottom, double &top, { #ifdef EXPERIMENTAL_SPECTRAL_EDITING double nyq = mRate / 2.0; - bottom = std::max(1.0, std::min(nyq, bottom)); - top = std::max(0.0, std::min(nyq, top)); + if (bottom >= 0.0) + bottom = std::min(nyq, bottom); + if (top >= 0.0) + top = std::min(nyq, top); mViewInfo.selectedRegion.setFrequencies(bottom, top); mTrackPanel->Refresh(false); if (done) { diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index ed10062f4..8869d848a 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -37,6 +37,7 @@ */ #include "../Audacity.h" +#include "../Experimental.h" #include "NoiseReduction.h" #include "../Prefs.h" @@ -229,7 +230,11 @@ public: typedef EffectNoiseReduction::Settings Settings; typedef EffectNoiseReduction::Statistics Statistics; - Worker(const Settings &settings, double sampleRate); + Worker(const Settings &settings, double sampleRate +#ifdef EXPERIMENTAL_SPECTRAL_EDITING + , double f0, double f1 +#endif + ); ~Worker(); bool Process(EffectNoiseReduction &effect, @@ -274,6 +279,9 @@ private: const int mSpectrumSize; FloatVector mFreqSmoothingScratch; const int mFreqSmoothingBins; + // When spectral selection limits the affected band: + int mBinLow; // inclusive lower bound + int mBinHigh; // exclusive upper bound const int mNoiseReductionChoice; const int mStepsPerWindow; @@ -545,12 +553,17 @@ bool EffectNoiseReduction::Settings::PrefsIO(bool read) bool EffectNoiseReduction::Settings::Validate() const { if (StepsPerWindow() < windowTypesInfo[mWindowTypes].minSteps) { - ::wxMessageBox(_("Steps per block are too few for the window types")); + ::wxMessageBox(_("Steps per block are too few for the window types.")); return false; } if (StepsPerWindow() > WindowSize()) { - ::wxMessageBox(_("Steps per block cannot exceed the window size")); + ::wxMessageBox(_("Steps per block cannot exceed the window size.")); + return false; + } + + if (mMethod == DM_MEDIAN && StepsPerWindow() > 4) { + ::wxMessageBox(_("Median method is not implemented for more than four steps per window.")); return false; } @@ -589,10 +602,14 @@ bool EffectNoiseReduction::Process() } else if (mStatistics->mWindowTypes != mSettings->mWindowTypes) { // A warning only - ::wxMessageBox(_("Warning: window types are not the same as for profiling")); + ::wxMessageBox(_("Warning: window types are not the same as for profiling.")); } - Worker worker(*mSettings, mStatistics->mRate); + Worker worker(*mSettings, mStatistics->mRate +#ifdef EXPERIMENTAL_SPECTRAL_EDITING + , mF0, mF1 +#endif + ); bool bGoodResult = worker.Process(*this, *mStatistics, *mFactory, iter, mT0, mT1); if (mSettings->mDoProfile) { if (bGoodResult) @@ -646,7 +663,7 @@ bool EffectNoiseReduction::Worker::Process if (mDoProfile) { if (statistics.mTotalWindows == 0) { - ::wxMessageBox(_("Selected noise profile is too short")); + ::wxMessageBox(_("Selected noise profile is too short.")); return false; } } @@ -685,7 +702,11 @@ void EffectNoiseReduction::Worker::ApplyFreqSmoothing(FloatVector &gains) } EffectNoiseReduction::Worker::Worker -(const Settings &settings, double sampleRate) +(const Settings &settings, double sampleRate +#ifdef EXPERIMENTAL_SPECTRAL_EDITING +, double f0, double f1 +#endif +) : mDoProfile(settings.mDoProfile) , mSampleRate(sampleRate) @@ -701,6 +722,8 @@ EffectNoiseReduction::Worker::Worker , mSpectrumSize(1 + mWindowSize / 2) , mFreqSmoothingScratch(mSpectrumSize) , mFreqSmoothingBins((int)(settings.mFreqSmoothingHz * mWindowSize / mSampleRate)) +, mBinLow(0) +, mBinHigh(mSpectrumSize) , mNoiseReductionChoice(settings.mNoiseReductionChoice) , mStepsPerWindow(settings.StepsPerWindow()) @@ -714,6 +737,16 @@ EffectNoiseReduction::Worker::Worker , mOutStepCount(0) , mInWavePos(0) { +#ifdef EXPERIMENTAL_SPECTRAL_EDITING + { + const double bin = mSampleRate / mWindowSize; + if (f0 >= 0.0 ) + mBinLow = floor(f0 / bin); + if (f1 >= 0.0) + mBinHigh = ceil(f1 / bin); + } +#endif + const double noiseGain = -settings.mNoiseGain; const int nAttackBlocks = 1 + (int)(settings.mAttackTime * sampleRate / mStepSize); const int nReleaseBlocks = 1 + (int)(settings.mReleaseTime * sampleRate / mStepSize); @@ -1074,13 +1107,21 @@ void EffectNoiseReduction::Worker::ReduceNoise { float *pGain = &mQueue[mCenter]->mGains[0]; if (mNoiseReductionChoice == NRC_ISOLATE_NOISE) { - for (int jj = 0; jj < mSpectrumSize; ++jj) { - const bool isNoise = Classify(statistics, jj); + // All above or below the selected frequency range is non-noise + std::fill(pGain, pGain + mBinLow, 0.0f); + std::fill(pGain + mBinHigh, pGain + mSpectrumSize, 0.0f); + pGain += mBinLow; + for (int jj = mBinLow; jj < mBinHigh; ++jj) { + const bool isNoise = Classify(statistics, jj); *pGain++ = isNoise ? 1.0 : 0.0; } } else { - for (int jj = 0; jj < mSpectrumSize; ++jj) { + // All above or below the selected frequency range is non-noise + std::fill(pGain, pGain + mBinLow, 1.0f); + std::fill(pGain + mBinHigh, pGain + mSpectrumSize, 1.0f); + pGain += mBinLow; + for (int jj = mBinLow; jj < mBinHigh; ++jj) { const bool isNoise = Classify(statistics, jj); if (!isNoise) *pGain = 1.0;