49#undef SPECTRAL_EDIT_NOISE_REDUCTION
85 {
XO(
"Second greatest") },
114 {
Verbatim(
"none, Hann (2.0.6 behavior)"), 2 },
118 {
Verbatim(
"Hann, Hann (default)"), 4 },
144 Statistics(
size_t spectrumSize,
double rate,
int windowTypes)
150 ,
mSums(spectrumSize)
152#ifdef OLD_METHOD_AVAILABLE
153 , mNoiseThreshold(spectrumSize)
169#ifdef OLD_METHOD_AVAILABLE
180 : mDoProfile { true }
191 unsigned stepsPerWindow,
bool leadingPadding,
bool trailingPadding)
193 inWindowType, outWindowType,
194 windowSize, stepsPerWindow,
195 leadingPadding, trailingPadding }
202 : Window { windowSize }
203 , mSpectrums(windowSize / 2 + 1)
204 , mGains(windowSize / 2 + 1)
215 return static_cast<MyWindow&
>(Nth(nn));
217 std::unique_ptr<Window> NewWindow(
size_t windowSize)
override;
218 bool DoStart()
override;
219 bool DoFinish()
override;
238#ifdef SPECTRAL_EDIT_NOISE_REDUCTION
290 "Noise Reduction") };
310 return XO(
"Removes background noise such as fans, tape noise, or hums");
331template <
typename StructureType,
typename FieldType>
333 StructureType* structure,
const wxString& prefix,
336 for (
size_t ii = 0; ii < numFields; ++ii)
340 prefix +
entry.name, &(structure->*(
entry.field)),
entry.defaultValue);
344template <
typename StructureType,
typename FieldType>
346 const StructureType* structure,
const wxString& prefix,
349 for (
size_t ii = 0; ii < numFields; ++ii)
359 static const double DEFAULT_OLD_SENSITIVITY = 0.0;
361 static const PrefsTableEntry<Settings, double> doubleTable[] = {
370 DEFAULT_OLD_SENSITIVITY },
372 static auto doubleTableSize =
sizeof(doubleTable) /
sizeof(doubleTable[0]);
374 static const PrefsTableEntry<Settings, int> intTable[] = {
386 static auto intTableSize =
sizeof(intTable) /
sizeof(intTable[0]);
388 static const wxString prefix(
wxT(
"/Effects/NoiseReduction/"));
392 readPrefs(
this, prefix, doubleTable, doubleTableSize);
393 readPrefs(
this, prefix, intTable, intTableSize);
396#if !(defined(RESIDUE_CHOICE) || defined(ISOLATE_CHOICE))
398#elif !(defined(RESIDUE_CHOICE))
401#elif !(defined(ISOLATE_CHOICE))
406#ifndef ADVANCED_SETTINGS
415#ifndef OLD_METHOD_AVAILABLE
424 writePrefs(
this, prefix, doubleTable, doubleTableSize);
425 writePrefs(
this, prefix, intTable, intTableSize);
439 if (StepsPerWindow() > WindowSize())
445 if (mMethod ==
DM_MEDIAN && StepsPerWindow() > 4)
448 "Median method is not implemented for more than four steps per window."));
457 return std::make_unique<MyWindow>(windowSize);
470 auto track = *(outputs.Get().Selected<
const WaveTrack>()).begin();
474 const auto stepsPerWindow =
mSettings->StepsPerWindow();
475 const auto stepSize =
mSettings->WindowSize() / stepsPerWindow;
481 const auto spectrumSize =
mSettings->SpectrumSize();
483 spectrumSize, track->GetRate(),
mSettings->mWindowTypes);
489 XO(
"You must specify the same window size for steps 1 and 2."));
496 XO(
"Warning: window types are not the same as for profiling."));
530#ifdef SPECTRAL_EDIT_NOISE_REDUCTION
536 worker.Process(inWindowType, outWindowType, outputs.Get(),
mT0,
mT1);
537 const auto wasProfile =
mSettings->mDoProfile;
547 if (bGoodResult && !wasProfile)
561 mProgressTrackCount = 0;
564 mProgressWindowCount = 0;
569 XO(
"All noise profile data must have the same sample rate."));
572 "The sample rate of the noise profile must match that of the sound to be processed."));
576 double trackStart = track->GetStartTime();
577 double trackEnd = track->GetEndTime();
578 double t0 = std::max(trackStart, inT0);
579 double t1 =
std::min(trackEnd, inT1);
583 auto start = track->TimeToLongSamples(t0);
584 auto end = track->TimeToLongSamples(t1);
585 const auto len =
end - start;
597 auto t0 = track->LongSamplesToTime(start);
598 auto tLen = track->LongSamplesToTime(len);
599 std::optional<WaveTrack::Holder> ppTempTrack;
600 std::optional<ChannelGroup::ChannelIterator<WaveChannel>> pIter;
604 ppTempTrack.emplace(track->EmptyCopy());
605 pFirstTrack = ppTempTrack->get();
606 pIter.emplace(pFirstTrack->Channels().begin());
608 for (
const auto pChannel : track->Channels())
610 auto pOutputTrack = pIter ? *(*pIter)++ :
nullptr;
620 if (!transformer.Process(
621 Processor, *pChannel, mHistoryLen, start, len))
623 ++mProgressTrackCount;
628 constexpr auto preserveSplits =
true;
629 constexpr auto merge =
true;
630 track->ClearAndPaste(
631 t0, t0 + tLen, **ppTempTrack, preserveSplits, merge);
654 if (mFreqSmoothingBins == 0)
657 const auto spectrumSize =
mSettings.SpectrumSize();
660 auto pScratch = mFreqSmoothingScratch.data();
661 std::fill(pScratch, pScratch + spectrumSize, 0.0f);
664 for (
size_t ii = 0; ii < spectrumSize; ++ii)
665 gains[ii] = log(gains[ii]);
668 for (
int ii = 0; ii < (int)spectrumSize; ++ii)
670 const int j0 = std::max(0, ii - (
int)mFreqSmoothingBins);
671 const int j1 =
std::min(spectrumSize - 1, ii + mFreqSmoothingBins);
672 for (
int jj = j0; jj <= j1; ++jj)
674 mFreqSmoothingScratch[ii] += gains[jj];
676 mFreqSmoothingScratch[ii] /= (j1 - j0 + 1);
679 for (
size_t ii = 0; ii < spectrumSize; ++ii)
680 gains[ii] = exp(mFreqSmoothingScratch[ii]);
685#ifdef SPECTRAL_EDIT_NOISE_REDUCTION
690 : mDoProfile {
settings.mDoProfile }
696 , mFreqSmoothingScratch(
mSettings.SpectrumSize())
697 , mFreqSmoothingBins { size_t(
std::max(0.0,
settings.mFreqSmoothingBands)) }
701 , mNoiseReductionChoice {
settings.mNoiseReductionChoice }
705 , mNewSensitivity {
settings.mNewSensitivity * log(10.0) }
709#ifdef SPECTRAL_EDIT_NOISE_REDUCTION
723 const unsigned nAttackBlocks =
725 const unsigned nReleaseBlocks =
744#ifdef OLD_METHOD_AVAILABLE
760 for (
size_t ii = 0, nn = TotalQueueSize(); ii < nn; ++ii)
765 record.
mGains.begin(), record.
mGains.end(), mWorker.mNoiseAttenFactor);
773 auto& worker = transformer.
mWorker;
776 auto& record = transformer.NthWindow(0);
777 float* pSpectrum = &record.mSpectrums[0];
778 const double dc = record.mRealFFTs[0];
779 *pSpectrum++ = dc * dc;
780 float *pReal = &record.mRealFFTs[1], *pImag = &record.mImagFFTs[1];
781 for (
size_t nn = worker.mSettings.SpectrumSize() - 2; nn--;)
783 const double re = *pReal++, im = *pImag++;
784 *pSpectrum++ = re * re + im * im;
786 const double nyquist = record.mImagFFTs[0];
787 *pSpectrum = nyquist * nyquist;
790 if (worker.mDoProfile)
793 worker.ReduceNoise(transformer);
796 return !worker.mEffect.TrackProgress(
797 worker.mProgressTrackCount,
799 1.0, ((++worker.mProgressWindowCount).as_double() *
800 worker.mSettings.StepSize()) /
801 worker.mLen.as_double()));
812 const auto denom = windows + multiplier;
813 for (
size_t ii = 0, nn =
mStatistics.mMeans.size(); ii < nn; ++ii)
817 mean = (mean * multiplier + sum) / denom;
835 for (
size_t jj = 0; jj <
mSettings.SpectrumSize(); ++jj)
837 *pSum++ += *pPower++;
841#ifdef OLD_METHOD_AVAILABLE
846 auto finish = mHistoryLen;
850 auto pPower = NthWindow(0).mSpectrums.data();
851 auto pThreshold =
mStatistics.mNoiseThreshold.data();
852 for (
size_t jj = 0; jj < mSpectrumSize; ++jj)
854 float min = *pPower++;
855 for (
unsigned ii = 1; ii < finish; ++ii)
857 *pThreshold = std::max(*pThreshold,
min);
871#ifdef OLD_METHOD_AVAILABLE
874 float min = NthWindow(0).mSpectrums[band];
875 for (
unsigned ii = 1; ii < nWindows; ++ii)
877 return min <= mOldSensitivityFactor *
mStatistics.mNoiseThreshold[band];
897 else if (nWindows <= 5)
899 float greatest = 0.0, second = 0.0, third = 0.0;
900 for (
unsigned ii = 0; ii < nWindows; ++ii)
903 if (
power >= greatest)
904 third = second, second = greatest, greatest =
power;
905 else if (
power >= second)
906 third = second, second =
power;
907 else if (
power >= third)
910 return third <= mNewSensitivity *
mStatistics.mMeans[band];
924 float greatest = 0.0, second = 0.0;
925 for (
unsigned ii = 0; ii < nWindows; ++ii)
928 if (
power >= greatest)
929 second = greatest, greatest =
power;
930 else if (
power >= second)
933 return second <= mNewSensitivity *
mStatistics.mMeans[band];
944 auto nWindows = std::min<unsigned>(mNWindowsToExamine, historyLen);
946 const auto spectrumSize =
mSettings.SpectrumSize();
953 float* pGain = &record.
mGains[0];
954 std::fill(pGain, pGain + spectrumSize, mNoiseAttenFactor);
959 if (nWindows > mCenter)
965 std::fill(pGain, pGain + mBinLow, 0.0f);
966 std::fill(pGain + mBinHigh, pGain + spectrumSize, 0.0f);
968 for (
size_t jj = mBinLow; jj < mBinHigh; ++jj)
970 const bool isNoise = Classify(transformer, nWindows, jj);
971 *pGain++ = isNoise ? 1.0 : 0.0;
977 std::fill(pGain, pGain + mBinLow, 1.0f);
978 std::fill(pGain + mBinHigh, pGain + spectrumSize, 1.0f);
980 for (
size_t jj = mBinLow; jj < mBinHigh; ++jj)
982 const bool isNoise = Classify(transformer, nWindows, jj);
998 for (
size_t jj = 0; jj < spectrumSize; ++jj)
1000 for (
unsigned ii = mCenter + 1; ii < historyLen; ++ii)
1002 const float minimum = std::max(
1021 for (
auto nn =
mSettings.SpectrumSize(); nn--;)
1023 *pNextGain = std::max(
1025 std::max(mNoiseAttenFactor, *pThisGain++ * mOneBlockRelease));
1033 auto& record = transformer.
NthWindow(historyLen - 1);
1034 const auto last =
mSettings.SpectrumSize() - 1;
1039 ApplyFreqSmoothing(record.mGains);
1043 const float* pGain = &record.mGains[1];
1044 float* pReal = &record.mRealFFTs[1];
1045 float* pImag = &record.mImagFFTs[1];
1053 const double gain = *pGain++ - 1.0;
1057 record.mRealFFTs[0] *= (record.mGains[0] - 1.0);
1060 record.mImagFFTs[0] *= (record.mGains[last] - 1.0);
1066 const double gain = *pGain++;
1070 record.mRealFFTs[0] *= record.mGains[0];
1073 record.mImagFFTs[0] *= record.mGains[last];
1081 if (mWorker.mDoProfile)
1082 mWorker.FinishTrackStatistics();
Toolkit-neutral facade for basic user interface services.
static ProjectFileIORegistry::AttributeWriterEntry entry
std::vector< float > FloatVector
audacity::BasicSettings * gPrefs
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
std::shared_ptr< TrackList > mTracks
Performs effect computation.
Use this object to copy the input tracks to tentative outputTracks.
unsigned StepsPerWindow() const
bool Validate(NoiseReductionBase *effect) const
int mStepsPerWindowChoice
int mNoiseReductionChoice
double mFreqSmoothingBands
Statistics(size_t spectrumSize, double rate, int windowTypes)
const double mNewSensitivity
unsigned mNWindowsToExamine
unsigned mProgressTrackCount
void ReduceNoise(MyTransformer &transformer)
Worker(NoiseReductionBase &effect, const Settings &settings, Statistics &statistics)
void GatherStatistics(MyTransformer &transformer)
bool Process(eWindowFunctions inWindowType, eWindowFunctions outWindowType, TrackList &tracks, double mT0, double mT1)
float mOldSensitivityFactor
bool Classify(MyTransformer &transformer, unsigned nWindows, int band)
const Settings & mSettings
sampleCount mProgressWindowCount
FloatVector mFreqSmoothingScratch
static bool Processor(SpectrumTransformer &transformer)
void FinishTrackStatistics()
void ApplyFreqSmoothing(FloatVector &gains)
NoiseReductionBase::Statistics Statistics
NoiseReductionBase & mEffect
const int mNoiseReductionChoice
NoiseReductionBase::Settings Settings
const size_t mFreqSmoothingBins
A two-pass effect to reduce background noise.
ComponentInterfaceSymbol GetSymbol() const override
bool Process(EffectInstance &instance, EffectSettings &settings) override
std::unique_ptr< Settings > mSettings
static const ComponentInterfaceSymbol Symbol
virtual ~NoiseReductionBase()
std::unique_ptr< Statistics > mStatistics
TranslatableString GetDescription() const override
EffectType GetType() const override
Type determines how it behaves.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
Positions or offsets within audio files need a wide type.
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
constexpr auto sampleRate
const float minSignalTime
const struct anonymous_namespace{NoiseReductionBase.cpp}::WindowTypesInfo windowTypesInfo[WT_N_WINDOW_TYPES]
const struct anonymous_namespace{NoiseReductionBase.cpp}::DiscriminationMethodInfo discriminationMethodInfo[DM_N_METHODS]
void readPrefs(StructureType *structure, const wxString &prefix, const PrefsTableEntry< StructureType, FieldType > *fields, size_t numFields)
@ DEFAULT_STEPS_PER_WINDOW_CHOICE
@ DEFAULT_WINDOW_SIZE_CHOICE
@ WT_DEFAULT_WINDOW_TYPES
void writePrefs(const StructureType *structure, const wxString &prefix, const PrefsTableEntry< StructureType, FieldType > *fields, size_t numFields)
const char * end(const char *str) noexcept
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept
Externalized state of a plug-in.
const TranslatableString name
FieldTypeStructureType::* MemberPointer
const TranslatableString name