Audacity  2.2.2
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
EffectNoiseReduction::Worker Class Reference

Classes

struct  Record
 

Public Types

typedef
EffectNoiseReduction::Settings 
Settings
 
typedef
EffectNoiseReduction::Statistics 
Statistics
 

Public Member Functions

 Worker (const Settings &settings, double sampleRate)
 
 ~Worker ()
 
bool Process (EffectNoiseReduction &effect, Statistics &statistics, TrackFactory &factory, SelectedTrackListOfKindIterator &iter, double mT0, double mT1)
 

Private Member Functions

bool ProcessOne (EffectNoiseReduction &effect, Statistics &statistics, TrackFactory &factory, int count, WaveTrack *track, sampleCount start, sampleCount len)
 
void StartNewTrack ()
 
void ProcessSamples (Statistics &statistics, WaveTrack *outputTrack, size_t len, float *buffer)
 
void FillFirstHistoryWindow ()
 
void ApplyFreqSmoothing (FloatVector &gains)
 
void GatherStatistics (Statistics &statistics)
 
bool Classify (const Statistics &statistics, int band)
 
void ReduceNoise (const Statistics &statistics, WaveTrack *outputTrack)
 
void RotateHistoryWindows ()
 
void FinishTrackStatistics (Statistics &statistics)
 
void FinishTrack (Statistics &statistics, WaveTrack *outputTrack)
 

Private Attributes

const bool mDoProfile
 
const double mSampleRate
 
const size_t mWindowSize
 
HFFT hFFT
 
FloatVector mFFTBuffer
 
FloatVector mInWaveBuffer
 
FloatVector mOutOverlapBuffer
 
FloatVector mInWindow
 
FloatVector mOutWindow
 
const size_t mSpectrumSize
 
FloatVector mFreqSmoothingScratch
 
const size_t mFreqSmoothingBins
 
int mBinLow
 
int mBinHigh
 
const int mNoiseReductionChoice
 
const unsigned mStepsPerWindow
 
const size_t mStepSize
 
const int mMethod
 
const double mNewSensitivity
 
sampleCount mInSampleCount
 
sampleCount mOutStepCount
 
int mInWavePos
 
float mOneBlockAttack
 
float mOneBlockRelease
 
float mNoiseAttenFactor
 
float mOldSensitivityFactor
 
unsigned mNWindowsToExamine
 
unsigned mCenter
 
unsigned mHistoryLen
 
std::vector< std::unique_ptr
< Record > > 
mQueue
 

Detailed Description

Definition at line 252 of file NoiseReduction.cpp.

Member Typedef Documentation

Definition at line 255 of file NoiseReduction.cpp.

Definition at line 256 of file NoiseReduction.cpp.

Constructor & Destructor Documentation

EffectNoiseReduction::Worker::Worker ( const Settings settings,
double  sampleRate 
)

Definition at line 726 of file NoiseReduction.cpp.

References DB_TO_LINEAR(), M_PI, EffectNoiseReduction::Settings::mAttackTime, EffectNoiseReduction::Settings::mNoiseGain, EffectNoiseReduction::Settings::mOldSensitivity, EffectNoiseReduction::Settings::mReleaseTime, Effect::mSampleRate, and EffectNoiseReduction::Settings::mWindowTypes.

731 : mDoProfile(settings.mDoProfile)
732 
733 , mSampleRate(sampleRate)
734 
735 , mWindowSize(settings.WindowSize())
740 , mInWindow()
741 , mOutWindow()
742 
743 , mSpectrumSize(1 + mWindowSize / 2)
745 , mFreqSmoothingBins((int)(settings.mFreqSmoothingBands))
746 , mBinLow(0)
748 
749 , mNoiseReductionChoice(settings.mNoiseReductionChoice)
750 , mStepsPerWindow(settings.StepsPerWindow())
752 , mMethod(settings.mMethod)
753 
754 // Sensitivity setting is a base 10 log, turn it into a natural log
755 , mNewSensitivity(settings.mNewSensitivity * log(10.0))
756 
757 , mInSampleCount(0)
758 , mOutStepCount(0)
759 , mInWavePos(0)
760 {
761 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
762  {
763  const double bin = mSampleRate / mWindowSize;
764  if (f0 >= 0.0 )
765  mBinLow = floor(f0 / bin);
766  if (f1 >= 0.0)
767  mBinHigh = ceil(f1 / bin);
768  }
769 #endif
770 
771  const double noiseGain = -settings.mNoiseGain;
772  const unsigned nAttackBlocks = 1 + (int)(settings.mAttackTime * sampleRate / mStepSize);
773  const unsigned nReleaseBlocks = 1 + (int)(settings.mReleaseTime * sampleRate / mStepSize);
774  // Applies to amplitudes, divide by 20:
775  mNoiseAttenFactor = DB_TO_LINEAR(noiseGain);
776  // Apply to gain factors which apply to amplitudes, divide by 20:
777  mOneBlockAttack = DB_TO_LINEAR(noiseGain / nAttackBlocks);
778  mOneBlockRelease = DB_TO_LINEAR(noiseGain / nReleaseBlocks);
779  // Applies to power, divide by 10:
780  mOldSensitivityFactor = pow(10.0, settings.mOldSensitivity / 10.0);
781 
782  mNWindowsToExamine = (mMethod == DM_OLD_METHOD)
783  ? std::max(2, (int)(minSignalTime * sampleRate / mStepSize))
784  : 1 + mStepsPerWindow;
785 
787  wxASSERT(mCenter >= 1); // release depends on this assumption
788 
789  if (mDoProfile)
790 #ifdef OLD_METHOD_AVAILABLE
792 #else
793  mHistoryLen = 1;
794 #endif
795  else {
796  // Allow long enough queue for sufficient inspection of the middle
797  // and for attack processing
798  // See ReduceNoise()
799  mHistoryLen = std::max(mNWindowsToExamine, mCenter + nAttackBlocks);
800  }
801 
802  mQueue.resize(mHistoryLen);
803  for (unsigned ii = 0; ii < mHistoryLen; ++ii)
804  mQueue[ii] = std::make_unique<Record>(mSpectrumSize);
805 
806  // Create windows
807 
808  const double constantTerm =
809  windowTypesInfo[settings.mWindowTypes].productConstantTerm;
810 
811  // One or the other window must by multiplied by this to correct for
812  // overlap. Must scale down as steps get smaller, and overlaps larger.
813  const double multiplier = 1.0 / (constantTerm * mStepsPerWindow);
814 
815  // Create the analysis window
816  switch (settings.mWindowTypes) {
817  case WT_RECTANGULAR_HANN:
818  break;
819  default:
820  {
821  const bool rectangularOut =
822  settings.mWindowTypes == WT_HAMMING_RECTANGULAR ||
823  settings.mWindowTypes == WT_HANN_RECTANGULAR;
824  const double m =
825  rectangularOut ? multiplier : 1;
826  const double *const coefficients =
827  windowTypesInfo[settings.mWindowTypes].inCoefficients;
828  const double c0 = coefficients[0];
829  const double c1 = coefficients[1];
830  const double c2 = coefficients[2];
831  mInWindow.resize(mWindowSize);
832  for (size_t ii = 0; ii < mWindowSize; ++ii)
833  mInWindow[ii] = m *
834  (c0 + c1 * cos((2.0*M_PI*ii) / mWindowSize)
835  + c2 * cos((4.0*M_PI*ii) / mWindowSize));
836  }
837  break;
838  }
839 
840  if (!mDoProfile) {
841  // Create the synthesis window
842  switch (settings.mWindowTypes) {
843  case WT_HANN_RECTANGULAR:
844  case WT_HAMMING_RECTANGULAR:
845  break;
846  case WT_HAMMING_INV_HAMMING:
847  {
848  mOutWindow.resize(mWindowSize);
849  for (size_t ii = 0; ii < mWindowSize; ++ii)
850  mOutWindow[ii] = multiplier / mInWindow[ii];
851  }
852  break;
853  default:
854  {
855  const double *const coefficients =
856  windowTypesInfo[settings.mWindowTypes].outCoefficients;
857  const double c0 = coefficients[0];
858  const double c1 = coefficients[1];
859  const double c2 = coefficients[2];
860  mOutWindow.resize(mWindowSize);
861  for (size_t ii = 0; ii < mWindowSize; ++ii)
862  mOutWindow[ii] = multiplier *
863  (c0 + c1 * cos((2.0 * M_PI * ii) / mWindowSize)
864  + c2 * cos((4.0 * M_PI * ii) / mWindowSize));
865  }
866  break;
867  }
868  }
869 }
std::vector< std::unique_ptr< Record > > mQueue
HFFT GetFFT(size_t fftlen)
Definition: RealFFTf.cpp:110
#define M_PI
Definition: Distortion.cpp:28
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
EffectNoiseReduction::Worker::~Worker ( )

Definition at line 647 of file NoiseReduction.cpp.

648 {
649 }

Member Function Documentation

void EffectNoiseReduction::Worker::ApplyFreqSmoothing ( FloatVector gains)
private

Definition at line 694 of file NoiseReduction.cpp.

References min().

695 {
696  // Given an array of gain mutipliers, average them
697  // GEOMETRICALLY. Don't multiply and take nth root --
698  // that may quickly cause underflows. Instead, average the logs.
699 
700  if (mFreqSmoothingBins == 0)
701  return;
702 
703  {
704  float *pScratch = &mFreqSmoothingScratch[0];
705  std::fill(pScratch, pScratch + mSpectrumSize, 0.0f);
706  }
707 
708  for (size_t ii = 0; ii < mSpectrumSize; ++ii)
709  gains[ii] = log(gains[ii]);
710 
711  // ii must be signed
712  for (int ii = 0; ii < (int)mSpectrumSize; ++ii) {
713  const int j0 = std::max(0, ii - (int)mFreqSmoothingBins);
714  const int j1 = std::min(mSpectrumSize - 1, ii + mFreqSmoothingBins);
715  for(int jj = j0; jj <= j1; ++jj) {
716  mFreqSmoothingScratch[ii] += gains[jj];
717  }
718  mFreqSmoothingScratch[ii] /= (j1 - j0 + 1);
719  }
720 
721  for (size_t ii = 0; ii < mSpectrumSize; ++ii)
722  gains[ii] = exp(mFreqSmoothingScratch[ii]);
723 }
int min(int a, int b)
bool EffectNoiseReduction::Worker::Classify ( const Statistics statistics,
int  band 
)
inlineprivate

Definition at line 1072 of file NoiseReduction.cpp.

References min(), and EffectNoiseReduction::Statistics::mMeans.

1073 {
1074  switch (mMethod) {
1075 #ifdef OLD_METHOD_AVAILABLE
1076  case DM_OLD_METHOD:
1077  {
1078  float min = mQueue[0]->mSpectrums[band];
1079  for (unsigned ii = 1; ii < mNWindowsToExamine; ++ii)
1080  min = std::min(min, mQueue[ii]->mSpectrums[band]);
1081  return min <= mOldSensitivityFactor * statistics.mNoiseThreshold[band];
1082  }
1083 #endif
1084  // New methods suppose an exponential distribution of power values
1085  // in the noise; NEW sensitivity is meant to be log of probability
1086  // that noise strays above the threshold. Call that probability
1087  // 1 - F. The quantile function of an exponential distribution is
1088  // log (1 - F) * mean. Thus simply multiply mean by sensitivity
1089  // to get the threshold.
1090  case DM_MEDIAN:
1091  // This method examines the window and all windows
1092  // that partly overlap it, and takes a median, to
1093  // avoid being fooled by up and down excursions into
1094  // either the mistake of classifying noise as not noise
1095  // (leaving a musical noise chime), or the opposite
1096  // (distorting the signal with a drop out).
1097  if (mNWindowsToExamine == 3)
1098  // No different from second greatest.
1099  goto secondGreatest;
1100  else if (mNWindowsToExamine == 5)
1101  {
1102  float greatest = 0.0, second = 0.0, third = 0.0;
1103  for (unsigned ii = 0; ii < mNWindowsToExamine; ++ii) {
1104  const float power = mQueue[ii]->mSpectrums[band];
1105  if (power >= greatest)
1106  third = second, second = greatest, greatest = power;
1107  else if (power >= second)
1108  third = second, second = power;
1109  else if (power >= third)
1110  third = power;
1111  }
1112  return third <= mNewSensitivity * statistics.mMeans[band];
1113  }
1114  else {
1115  wxASSERT(false);
1116  return true;
1117  }
1118  secondGreatest:
1119  case DM_SECOND_GREATEST:
1120  {
1121  // This method just throws out the high outlier. It
1122  // should be less prone to distortions and more prone to
1123  // chimes.
1124  float greatest = 0.0, second = 0.0;
1125  for (unsigned ii = 0; ii < mNWindowsToExamine; ++ii) {
1126  const float power = mQueue[ii]->mSpectrums[band];
1127  if (power >= greatest)
1128  second = greatest, greatest = power;
1129  else if (power >= second)
1130  second = power;
1131  }
1132  return second <= mNewSensitivity * statistics.mMeans[band];
1133  }
1134  default:
1135  wxASSERT(false);
1136  return true;
1137  }
1138 }
std::vector< std::unique_ptr< Record > > mQueue
int min(int a, int b)
void EffectNoiseReduction::Worker::FillFirstHistoryWindow ( )
private

Definition at line 946 of file NoiseReduction.cpp.

References EffectNoiseReduction::Worker::Record::mRealFFTs, and RealFFTf().

947 {
948  // Transform samples to frequency domain, windowed as needed
949  if (mInWindow.size() > 0)
950  for (size_t ii = 0; ii < mWindowSize; ++ii)
951  mFFTBuffer[ii] = mInWaveBuffer[ii] * mInWindow[ii];
952  else
953  memmove(&mFFTBuffer[0], &mInWaveBuffer[0], mWindowSize * sizeof(float));
954  RealFFTf(&mFFTBuffer[0], hFFT.get());
955 
956  Record &record = *mQueue[0];
957 
958  // Store real and imaginary parts for later inverse FFT, and compute
959  // power
960  {
961  float *pReal = &record.mRealFFTs[1];
962  float *pImag = &record.mImagFFTs[1];
963  float *pPower = &record.mSpectrums[1];
964  int *pBitReversed = &hFFT->BitReversed[1];
965  const auto last = mSpectrumSize - 1;
966  for (unsigned int ii = 1; ii < last; ++ii) {
967  const int kk = *pBitReversed++;
968  const float realPart = *pReal++ = mFFTBuffer[kk];
969  const float imagPart = *pImag++ = mFFTBuffer[kk + 1];
970  *pPower++ = realPart * realPart + imagPart * imagPart;
971  }
972  // DC and Fs/2 bins need to be handled specially
973  const float dc = mFFTBuffer[0];
974  record.mRealFFTs[0] = dc;
975  record.mSpectrums[0] = dc*dc;
976 
977  const float nyquist = mFFTBuffer[1];
978  record.mImagFFTs[0] = nyquist; // For Fs/2, not really imaginary
979  record.mSpectrums[last] = nyquist * nyquist;
980  }
981 
982  if (mNoiseReductionChoice != NRC_ISOLATE_NOISE)
983  {
984  // Default all gains to the reduction factor,
985  // until we decide to raise some of them later
986  float *pGain = &record.mGains[0];
987  std::fill(pGain, pGain + mSpectrumSize, mNoiseAttenFactor);
988  }
989 }
std::vector< std::unique_ptr< Record > > mQueue
void RealFFTf(fft_type *buffer, const FFTParam *h)
Definition: RealFFTf.cpp:167
void EffectNoiseReduction::Worker::FinishTrack ( Statistics statistics,
WaveTrack outputTrack 
)
private

Definition at line 1018 of file NoiseReduction.cpp.

1019 {
1020  // Keep flushing empty input buffers through the history
1021  // windows until we've output exactly as many samples as
1022  // were input.
1023  // Well, not exactly, but not more than one step-size of extra samples
1024  // at the end.
1025  // We'll DELETE them later in ProcessOne.
1026 
1027  FloatVector empty(mStepSize);
1028 
1029  while (mOutStepCount * mStepSize < mInSampleCount) {
1030  ProcessSamples(statistics, outputTrack, mStepSize, &empty[0]);
1031  }
1032 }
void ProcessSamples(Statistics &statistics, WaveTrack *outputTrack, size_t len, float *buffer)
std::vector< float > FloatVector
void EffectNoiseReduction::Worker::FinishTrackStatistics ( Statistics statistics)
private

Definition at line 996 of file NoiseReduction.cpp.

References EffectNoiseReduction::Statistics::mMeans, EffectNoiseReduction::Statistics::mSums, EffectNoiseReduction::Statistics::mTotalWindows, and EffectNoiseReduction::Statistics::mTrackWindows.

997 {
998  const int windows = statistics.mTrackWindows;
999  const int multiplier = statistics.mTotalWindows;
1000  const int denom = windows + multiplier;
1001 
1002  // Combine averages in case of multiple profile tracks.
1003  if (windows)
1004  for (int ii = 0, nn = statistics.mMeans.size(); ii < nn; ++ii) {
1005  float &mean = statistics.mMeans[ii];
1006  float &sum = statistics.mSums[ii];
1007  mean = (mean * multiplier + sum) / denom;
1008  // Reset for next track
1009  sum = 0;
1010  }
1011 
1012  // Reset for next track
1013  statistics.mTrackWindows = 0;
1014  statistics.mTotalWindows = denom;
1015 }
void EffectNoiseReduction::Worker::GatherStatistics ( Statistics statistics)
private

Definition at line 1034 of file NoiseReduction.cpp.

References min(), EffectNoiseReduction::Statistics::mSums, and EffectNoiseReduction::Statistics::mTrackWindows.

1035 {
1036  ++statistics.mTrackWindows;
1037 
1038  {
1039  // NEW statistics
1040  const float *pPower = &mQueue[0]->mSpectrums[0];
1041  float *pSum = &statistics.mSums[0];
1042  for (size_t jj = 0; jj < mSpectrumSize; ++jj) {
1043  *pSum++ += *pPower++;
1044  }
1045  }
1046 
1047 #ifdef OLD_METHOD_AVAILABLE
1048  // The noise threshold for each frequency is the maximum
1049  // level achieved at that frequency for a minimum of
1050  // mMinSignalBlocks blocks in a row - the max of a min.
1051 
1052  auto finish = mHistoryLen;
1053 
1054  {
1055  // old statistics
1056  const float *pPower = &mQueue[0]->mSpectrums[0];
1057  float *pThreshold = &statistics.mNoiseThreshold[0];
1058  for (int jj = 0; jj < mSpectrumSize; ++jj) {
1059  float min = *pPower++;
1060  for (unsigned ii = 1; ii < finish; ++ii)
1061  min = std::min(min, mQueue[ii]->mSpectrums[jj]);
1062  *pThreshold = std::max(*pThreshold, min);
1063  ++pThreshold;
1064  }
1065  }
1066 #endif
1067 }
std::vector< std::unique_ptr< Record > > mQueue
int min(int a, int b)
bool EffectNoiseReduction::Worker::Process ( EffectNoiseReduction effect,
Statistics statistics,
TrackFactory factory,
SelectedTrackListOfKindIterator iter,
double  mT0,
double  mT1 
)

Definition at line 652 of file NoiseReduction.cpp.

References _(), TrackListCondIterator::First(), WaveTrack::GetEndTime(), WaveTrack::GetRate(), WaveTrack::GetStartTime(), min(), Effect::mSampleRate, EffectNoiseReduction::Statistics::mTotalWindows, TrackListCondIterator::Next(), and WaveTrack::TimeToLongSamples().

Referenced by EffectNoiseReduction::Process().

654 {
655  int count = 0;
656  WaveTrack *track = (WaveTrack *) iter.First();
657  while (track) {
658  if (track->GetRate() != mSampleRate) {
659  if (mDoProfile)
660  effect.Effect::MessageBox(_("All noise profile data must have the same sample rate."));
661  else
662  effect.Effect::MessageBox(_("The sample rate of the noise profile must match that of the sound to be processed."));
663  return false;
664  }
665 
666  double trackStart = track->GetStartTime();
667  double trackEnd = track->GetEndTime();
668  double t0 = std::max(trackStart, mT0);
669  double t1 = std::min(trackEnd, mT1);
670 
671  if (t1 > t0) {
672  auto start = track->TimeToLongSamples(t0);
673  auto end = track->TimeToLongSamples(t1);
674  auto len = end - start;
675 
676  if (!ProcessOne(effect, statistics, factory,
677  count, track, start, len))
678  return false;
679  }
680  track = (WaveTrack *) iter.Next();
681  ++count;
682  }
683 
684  if (mDoProfile) {
685  if (statistics.mTotalWindows == 0) {
686  effect.Effect::MessageBox(_("Selected noise profile is too short."));
687  return false;
688  }
689  }
690 
691  return true;
692 }
bool ProcessOne(EffectNoiseReduction &effect, Statistics &statistics, TrackFactory &factory, int count, WaveTrack *track, sampleCount start, sampleCount len)
double mT1
Definition: Effect.h:461
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1873
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:569
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1853
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
int min(int a, int b)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1843
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:558
double GetRate() const
Definition: WaveTrack.cpp:398
double mT0
Definition: Effect.h:460
bool EffectNoiseReduction::Worker::ProcessOne ( EffectNoiseReduction effect,
Statistics statistics,
TrackFactory factory,
int  count,
WaveTrack track,
sampleCount  start,
sampleCount  len 
)
private

Definition at line 1288 of file NoiseReduction.cpp.

References sampleCount::as_double(), WaveTrack::ClearAndPaste(), floatSample, WaveTrack::Get(), WaveTrack::GetBestBlockSize(), WaveTrack::GetMaxBlockSize(), WaveTrack::GetRate(), WaveTrack::GetSampleFormat(), limitSampleBufferSize(), TrackFactory::NewWaveTrack(), and Effect::TrackProgress().

1290 {
1291  if (track == NULL)
1292  return false;
1293 
1294  StartNewTrack();
1295 
1296  WaveTrack::Holder outputTrack;
1297  if(!mDoProfile)
1298  outputTrack = factory.NewWaveTrack(track->GetSampleFormat(), track->GetRate());
1299 
1300  auto bufferSize = track->GetMaxBlockSize();
1301  FloatVector buffer(bufferSize);
1302 
1303  bool bLoopSuccess = true;
1304  auto samplePos = start;
1305  while (bLoopSuccess && samplePos < start + len) {
1306  //Get a blockSize of samples (smaller than the size of the buffer)
1307  const auto blockSize = limitSampleBufferSize(
1308  track->GetBestBlockSize(samplePos),
1309  start + len - samplePos
1310  );
1311 
1312  //Get the samples from the track and put them in the buffer
1313  track->Get((samplePtr)&buffer[0], floatSample, samplePos, blockSize);
1314  samplePos += blockSize;
1315 
1316  mInSampleCount += blockSize;
1317  ProcessSamples(statistics, outputTrack.get(), blockSize, &buffer[0]);
1318 
1319  // Update the Progress meter, let user cancel
1320  bLoopSuccess =
1321  !effect.TrackProgress(count,
1322  ( samplePos - start ).as_double() /
1323  len.as_double() );
1324  }
1325 
1326  if (bLoopSuccess) {
1327  if (mDoProfile)
1328  FinishTrackStatistics(statistics);
1329  else
1330  FinishTrack(statistics, &*outputTrack);
1331  }
1332 
1333  if (bLoopSuccess && !mDoProfile) {
1334  // Flush the output WaveTrack (since it's buffered)
1335  outputTrack->Flush();
1336 
1337  // Take the output track and insert it in place of the original
1338  // sample data (as operated on -- this may not match mT0/mT1)
1339  double t0 = outputTrack->LongSamplesToTime(start);
1340  double tLen = outputTrack->LongSamplesToTime(len);
1341  // Filtering effects always end up with more data than they started with. Delete this 'tail'.
1342  outputTrack->HandleClear(tLen, outputTrack->GetEndTime(), false, false);
1343  track->ClearAndPaste(t0, t0 + tLen, &*outputTrack, true, false);
1344  }
1345 
1346  return bLoopSuccess;
1347 }
bool TrackProgress(int whichTrack, double frac, const wxString &=wxEmptyString)
Definition: Effect.cpp:1985
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:782
double as_double() const
Definition: Types.h:88
size_t GetBestBlockSize(sampleCount t) const
Definition: WaveTrack.cpp:1607
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
std::unique_ptr< WaveTrack > Holder
Definition: WaveTrack.h:90
char * samplePtr
Definition: Types.h:203
void FinishTrack(Statistics &statistics, WaveTrack *outputTrack)
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:1625
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
void ProcessSamples(Statistics &statistics, WaveTrack *outputTrack, size_t len, float *buffer)
sampleFormat GetSampleFormat() const
Definition: WaveTrack.h:146
std::vector< float > FloatVector
double GetRate() const
Definition: WaveTrack.cpp:398
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumCopied=nullptr) const
Definition: WaveTrack.cpp:1971
void FinishTrackStatistics(Statistics &statistics)
void EffectNoiseReduction::Worker::ProcessSamples ( Statistics statistics,
WaveTrack outputTrack,
size_t  len,
float *  buffer 
)
private

Definition at line 919 of file NoiseReduction.cpp.

References min().

921 {
922  while (len && mOutStepCount * mStepSize < mInSampleCount) {
923  auto avail = std::min(len, mWindowSize - mInWavePos);
924  memmove(&mInWaveBuffer[mInWavePos], buffer, avail * sizeof(float));
925  buffer += avail;
926  len -= avail;
927  mInWavePos += avail;
928 
929  if (mInWavePos == (int)mWindowSize) {
931  if (mDoProfile)
932  GatherStatistics(statistics);
933  else
934  ReduceNoise(statistics, outputTrack);
935  ++mOutStepCount;
937 
938  // Rotate for overlap-add
939  memmove(&mInWaveBuffer[0], &mInWaveBuffer[mStepSize],
940  (mWindowSize - mStepSize) * sizeof(float));
941  mInWavePos -= mStepSize;
942  }
943  }
944 }
int min(int a, int b)
void GatherStatistics(Statistics &statistics)
void ReduceNoise(const Statistics &statistics, WaveTrack *outputTrack)
void EffectNoiseReduction::Worker::ReduceNoise ( const Statistics statistics,
WaveTrack outputTrack 
)
private

Definition at line 1141 of file NoiseReduction.cpp.

References WaveTrack::Append(), floatSample, InverseRealFFTf(), EffectNoiseReduction::Worker::Record::mGains, EffectNoiseReduction::Worker::Record::mImagFFTs, and EffectNoiseReduction::Worker::Record::mRealFFTs.

1142 {
1143  // Raise the gain for elements in the center of the sliding history
1144  // or, if isolating noise, zero out the non-noise
1145  {
1146  float *pGain = &mQueue[mCenter]->mGains[0];
1147  if (mNoiseReductionChoice == NRC_ISOLATE_NOISE) {
1148  // All above or below the selected frequency range is non-noise
1149  std::fill(pGain, pGain + mBinLow, 0.0f);
1150  std::fill(pGain + mBinHigh, pGain + mSpectrumSize, 0.0f);
1151  pGain += mBinLow;
1152  for (int jj = mBinLow; jj < mBinHigh; ++jj) {
1153  const bool isNoise = Classify(statistics, jj);
1154  *pGain++ = isNoise ? 1.0 : 0.0;
1155  }
1156  }
1157  else {
1158  // All above or below the selected frequency range is non-noise
1159  std::fill(pGain, pGain + mBinLow, 1.0f);
1160  std::fill(pGain + mBinHigh, pGain + mSpectrumSize, 1.0f);
1161  pGain += mBinLow;
1162  for (int jj = mBinLow; jj < mBinHigh; ++jj) {
1163  const bool isNoise = Classify(statistics, jj);
1164  if (!isNoise)
1165  *pGain = 1.0;
1166  ++pGain;
1167  }
1168  }
1169  }
1170 
1171  if (mNoiseReductionChoice != NRC_ISOLATE_NOISE)
1172  {
1173  // In each direction, define an exponential decay of gain from the
1174  // center; make actual gains the maximum of mNoiseAttenFactor, and
1175  // the decay curve, and their prior values.
1176 
1177  // First, the attack, which goes backward in time, which is,
1178  // toward higher indices in the queue.
1179  for (size_t jj = 0; jj < mSpectrumSize; ++jj) {
1180  for (unsigned ii = mCenter + 1; ii < mHistoryLen; ++ii) {
1181  const float minimum =
1182  std::max(mNoiseAttenFactor,
1183  mQueue[ii - 1]->mGains[jj] * mOneBlockAttack);
1184  float &gain = mQueue[ii]->mGains[jj];
1185  if (gain < minimum)
1186  gain = minimum;
1187  else
1188  // We can stop now, our attack curve is intersecting
1189  // the decay curve of some window previously processed.
1190  break;
1191  }
1192  }
1193 
1194  // Now, release. We need only look one window ahead. This part will
1195  // be visited again when we examine the next window, and
1196  // carry the decay further.
1197  {
1198  float *pNextGain = &mQueue[mCenter - 1]->mGains[0];
1199  const float *pThisGain = &mQueue[mCenter]->mGains[0];
1200  for (int nn = mSpectrumSize; nn--;) {
1201  *pNextGain =
1202  std::max(*pNextGain,
1203  std::max(mNoiseAttenFactor,
1204  *pThisGain++ * mOneBlockRelease));
1205  ++pNextGain;
1206  }
1207  }
1208  }
1209 
1210 
1211  if (mOutStepCount >= -(int)(mStepsPerWindow - 1)) {
1212  Record &record = *mQueue[mHistoryLen - 1]; // end of the queue
1213  const auto last = mSpectrumSize - 1;
1214 
1215  if (mNoiseReductionChoice != NRC_ISOLATE_NOISE)
1216  // Apply frequency smoothing to output gain
1217  // Gains are not less than mNoiseAttenFactor
1218  ApplyFreqSmoothing(record.mGains);
1219 
1220  // Apply gain to FFT
1221  {
1222  const float *pGain = &record.mGains[1];
1223  const float *pReal = &record.mRealFFTs[1];
1224  const float *pImag = &record.mImagFFTs[1];
1225  float *pBuffer = &mFFTBuffer[2];
1226  auto nn = mSpectrumSize - 2;
1227  if (mNoiseReductionChoice == NRC_LEAVE_RESIDUE) {
1228  for (; nn--;) {
1229  // Subtract the gain we would otherwise apply from 1, and
1230  // negate that to flip the phase.
1231  const double gain = *pGain++ - 1.0;
1232  *pBuffer++ = *pReal++ * gain;
1233  *pBuffer++ = *pImag++ * gain;
1234  }
1235  mFFTBuffer[0] = record.mRealFFTs[0] * (record.mGains[0] - 1.0);
1236  // The Fs/2 component is stored as the imaginary part of the DC component
1237  mFFTBuffer[1] = record.mImagFFTs[0] * (record.mGains[last] - 1.0);
1238  }
1239  else {
1240  for (; nn--;) {
1241  const double gain = *pGain++;
1242  *pBuffer++ = *pReal++ * gain;
1243  *pBuffer++ = *pImag++ * gain;
1244  }
1245  mFFTBuffer[0] = record.mRealFFTs[0] * record.mGains[0];
1246  // The Fs/2 component is stored as the imaginary part of the DC component
1247  mFFTBuffer[1] = record.mImagFFTs[0] * record.mGains[last];
1248  }
1249  }
1250 
1251  // Invert the FFT into the output buffer
1252  InverseRealFFTf(&mFFTBuffer[0], hFFT.get());
1253 
1254  // Overlap-add
1255  if (mOutWindow.size() > 0) {
1256  float *pOut = &mOutOverlapBuffer[0];
1257  float *pWindow = &mOutWindow[0];
1258  int *pBitReversed = &hFFT->BitReversed[0];
1259  for (unsigned int jj = 0; jj < last; ++jj) {
1260  int kk = *pBitReversed++;
1261  *pOut++ += mFFTBuffer[kk] * (*pWindow++);
1262  *pOut++ += mFFTBuffer[kk + 1] * (*pWindow++);
1263  }
1264  }
1265  else {
1266  float *pOut = &mOutOverlapBuffer[0];
1267  int *pBitReversed = &hFFT->BitReversed[0];
1268  for (unsigned int jj = 0; jj < last; ++jj) {
1269  int kk = *pBitReversed++;
1270  *pOut++ += mFFTBuffer[kk];
1271  *pOut++ += mFFTBuffer[kk + 1];
1272  }
1273  }
1274 
1275  float *buffer = &mOutOverlapBuffer[0];
1276  if (mOutStepCount >= 0) {
1277  // Output the first portion of the overlap buffer, they're done
1278  outputTrack->Append((samplePtr)buffer, floatSample, mStepSize);
1279  }
1280 
1281  // Shift the remainder over.
1282  memmove(buffer, buffer + mStepSize, sizeof(float) * (mWindowSize - mStepSize));
1283  std::fill(buffer + mWindowSize - mStepSize, buffer + mWindowSize, 0.0f);
1284  }
1285 }
std::vector< std::unique_ptr< Record > > mQueue
char * samplePtr
Definition: Types.h:203
void Append(samplePtr buffer, sampleFormat format, size_t len, unsigned int stride=1, XMLWriter *blockFileLog=NULL)
Append the sample data to the WaveTrack. You must call Flush() after the last Append.
Definition: WaveTrack.cpp:1557
void InverseRealFFTf(fft_type *buffer, const FFTParam *h)
Definition: RealFFTf.cpp:269
bool Classify(const Statistics &statistics, int band)
void ApplyFreqSmoothing(FloatVector &gains)
void EffectNoiseReduction::Worker::RotateHistoryWindows ( )
private

Definition at line 991 of file NoiseReduction.cpp.

992 {
993  std::rotate(mQueue.begin(), mQueue.end() - 1, mQueue.end());
994 }
std::vector< std::unique_ptr< Record > > mQueue
void EffectNoiseReduction::Worker::StartNewTrack ( )
private

Definition at line 871 of file NoiseReduction.cpp.

References EffectNoiseReduction::Worker::Record::mGains, EffectNoiseReduction::Worker::Record::mImagFFTs, EffectNoiseReduction::Worker::Record::mRealFFTs, and EffectNoiseReduction::Worker::Record::mSpectrums.

872 {
873  float *pFill;
874  for(unsigned ii = 0; ii < mHistoryLen; ++ii) {
875  Record &record = *mQueue[ii];
876 
877  pFill = &record.mSpectrums[0];
878  std::fill(pFill, pFill + mSpectrumSize, 0.0f);
879 
880  pFill = &record.mRealFFTs[0];
881  std::fill(pFill, pFill + mSpectrumSize - 1, 0.0f);
882 
883  pFill = &record.mImagFFTs[0];
884  std::fill(pFill, pFill + mSpectrumSize - 1, 0.0f);
885 
886  pFill = &record.mGains[0];
887  std::fill(pFill, pFill + mSpectrumSize, mNoiseAttenFactor);
888  }
889 
890  pFill = &mOutOverlapBuffer[0];
891  std::fill(pFill, pFill + mWindowSize, 0.0f);
892 
893  pFill = &mInWaveBuffer[0];
894  std::fill(pFill, pFill + mWindowSize, 0.0f);
895 
896  if (mDoProfile)
897  {
898  // We do not want leading zero padded windows
899  mInWavePos = 0;
900  mOutStepCount = -(int)(mHistoryLen - 1);
901  }
902  else
903  {
904  // So that the queue gets primed with some windows,
905  // zero-padded in front, the first having mStepSize
906  // samples of wave data:
908  // This starts negative, to count up until the queue fills:
909  mOutStepCount = -(int)(mHistoryLen - 1)
910  // ... and then must pass over the padded windows,
911  // before the first full window:
912  - (int)(mStepsPerWindow - 1);
913  }
914 
915  mInSampleCount = 0;
916 }
std::vector< std::unique_ptr< Record > > mQueue

Member Data Documentation

HFFT EffectNoiseReduction::Worker::hFFT
private

Definition at line 296 of file NoiseReduction.cpp.

int EffectNoiseReduction::Worker::mBinHigh
private

Definition at line 309 of file NoiseReduction.cpp.

int EffectNoiseReduction::Worker::mBinLow
private

Definition at line 308 of file NoiseReduction.cpp.

unsigned EffectNoiseReduction::Worker::mCenter
private

Definition at line 328 of file NoiseReduction.cpp.

const bool EffectNoiseReduction::Worker::mDoProfile
private

Definition at line 290 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mFFTBuffer
private

Definition at line 297 of file NoiseReduction.cpp.

const size_t EffectNoiseReduction::Worker::mFreqSmoothingBins
private

Definition at line 306 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mFreqSmoothingScratch
private

Definition at line 305 of file NoiseReduction.cpp.

unsigned EffectNoiseReduction::Worker::mHistoryLen
private

Definition at line 329 of file NoiseReduction.cpp.

sampleCount EffectNoiseReduction::Worker::mInSampleCount
private

Definition at line 318 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mInWaveBuffer
private

Definition at line 298 of file NoiseReduction.cpp.

int EffectNoiseReduction::Worker::mInWavePos
private

Definition at line 320 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mInWindow
private

Definition at line 301 of file NoiseReduction.cpp.

const int EffectNoiseReduction::Worker::mMethod
private

Definition at line 314 of file NoiseReduction.cpp.

const double EffectNoiseReduction::Worker::mNewSensitivity
private

Definition at line 315 of file NoiseReduction.cpp.

float EffectNoiseReduction::Worker::mNoiseAttenFactor
private

Definition at line 324 of file NoiseReduction.cpp.

const int EffectNoiseReduction::Worker::mNoiseReductionChoice
private

Definition at line 311 of file NoiseReduction.cpp.

unsigned EffectNoiseReduction::Worker::mNWindowsToExamine
private

Definition at line 327 of file NoiseReduction.cpp.

float EffectNoiseReduction::Worker::mOldSensitivityFactor
private

Definition at line 325 of file NoiseReduction.cpp.

float EffectNoiseReduction::Worker::mOneBlockAttack
private

Definition at line 322 of file NoiseReduction.cpp.

float EffectNoiseReduction::Worker::mOneBlockRelease
private

Definition at line 323 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mOutOverlapBuffer
private

Definition at line 299 of file NoiseReduction.cpp.

sampleCount EffectNoiseReduction::Worker::mOutStepCount
private

Definition at line 319 of file NoiseReduction.cpp.

FloatVector EffectNoiseReduction::Worker::mOutWindow
private

Definition at line 302 of file NoiseReduction.cpp.

std::vector<std::unique_ptr<Record> > EffectNoiseReduction::Worker::mQueue
private

Definition at line 346 of file NoiseReduction.cpp.

const double EffectNoiseReduction::Worker::mSampleRate
private

Definition at line 292 of file NoiseReduction.cpp.

const size_t EffectNoiseReduction::Worker::mSpectrumSize
private

Definition at line 304 of file NoiseReduction.cpp.

const size_t EffectNoiseReduction::Worker::mStepSize
private

Definition at line 313 of file NoiseReduction.cpp.

const unsigned EffectNoiseReduction::Worker::mStepsPerWindow
private

Definition at line 312 of file NoiseReduction.cpp.

const size_t EffectNoiseReduction::Worker::mWindowSize
private

Definition at line 294 of file NoiseReduction.cpp.


The documentation for this class was generated from the following file: