After a bit of searching, I found an article surveying some of the commercial software noise reduction options. For hiss/hum type noise removal (as opposed to crackles and pops), no approach other than noise-gates in multiple frequency bands was mentioned. The differences between implementations are in the default settings, the control knobs available, and things like that. (and whether the a noise sample is used to get a profile. Apparently there are faster implementations that do well without needing a noise sample to build a tailored profile of the noise to remove.)
So AFAICT, Audacity's noise reduction plugin works the same way as commercial software implementations.
(For pops and crackles, Audacity allows making rectangular selections on the spectrum plot. It might not have as sophisticated algorithms for filling in deleted glitches with similar-sounding audio from nearby, compared to some commercial software. IDK, I haven't tried that.)
The other thing I was interested in was what's up with recent development activity in Audacity's Noise Reduction filter:
Following the svn history of NoiseReduction.cpp
, there are really only changes to the GUI for setting parameters, from it's appearance in SVN r13591 (Nov 10, 2014) up to latest change in r13895 (Jan 24, 2015).
It replaces the over-optimistically-titled NoiseRemoval.cpp
. It appears to be a rewrite of the same basic design. The intro comment describing the design is only slightly changed, and some of the same comments are kicking around in the code. However, almost every line of code is different, and it's 1.9k lines of code instead of 870.
So it's probably not critical to get a pre-release build of Audacity 2.1 for noise removal. If you get chimes / dropouts where you don't want them, or otherwise have problems, then go for a new version. It looks at more data to decide if something is noise or not, as detailed below.
One critical part of the new filter now has several methods to choose from. (OLD_METHOD_AVAILABLE
is not enabled by default. And DM_DEFAULT_METHOD = DM_SECOND_GREATEST
)
(The code is well-commented. I mostly just read the comments, on the assumption that the code matches well enough.)
//***** NoiseReduction.cpp:1079
// Return true iff the given band of the "center" window looks like noise.
// Examine the band in a few neighboring windows to decide.
inline
bool EffectNoiseReduction::Worker::Classify(const Statistics &statistics, int band)
{
switch (mMethod) {
#ifdef OLD_METHOD_AVAILABLE
case DM_OLD_METHOD:
{
float min = mQueue[0]->mSpectrums[band];
for (int ii = 1; ii < mNWindowsToExamine; ++ii)
min = std::min(min, mQueue[ii]->mSpectrums[band]);
return min <= mOldSensitivityFactor * statistics.mNoiseThreshold[band];
}
// New methods suppose an exponential distribution of power values
// in the noise; new sensitivity is meant to be log of probability
// that noise strays above the threshold. Call that probability
// 1 - F. The quantile function of an exponential distribution is
// log (1 - F) * mean. Thus simply multiply mean by sensitivity
// to get the threshold.
case DM_MEDIAN:
// This method examines the window and all windows
// that partly overlap it, and takes a median, to
// avoid being fooled by up and down excursions into
// either the mistake of classifying noise as not noise
// (leaving a musical noise chime), or the opposite
// (distorting the signal with a drop out).
if (mNWindowsToExamine == 3)
// No different from second greatest.
goto secondGreatest;
else if (mNWindowsToExamine == 5)
{
float greatest = 0.0, second = 0.0, third = 0.0;
for (int ii = 0; ii < mNWindowsToExamine; ++ii) {
const float power = mQueue[ii]->mSpectrums[band];
if (power >= greatest)
third = second, second = greatest, greatest = power;
else if (power >= second)
third = second, second = power;
else if (power >= third)
third = power;
}
return third <= mNewSensitivity * statistics.mMeans[band];
}
else {
wxASSERT(false);
return true;
}
secondGreatest:
case DM_SECOND_GREATEST:
{
// This method just throws out the high outlier. It
// should be less prone to distortions and more prone to
// chimes.
float greatest = 0.0, second = 0.0;
for (int ii = 0; ii < mNWindowsToExamine; ++ii) {
const float power = mQueue[ii]->mSpectrums[band];
if (power >= greatest)
second = greatest, greatest = power;
else if (power >= second)
second = power;
}
return second <= mNewSensitivity * statistics.mMeans[band];
}
default:
wxASSERT(false);
return true;
}
}
(why isn't syntax highlighting working? I put <!-- language: lang-cpp -->
before the code block :/)
I'm probably going to build audacity from this SVN checkout I already have, but I'm not planning to compare noise reduction between the latest dev build and the stable 2.0.6 release.