Beispiel #1
0
void EffectNoiseRemoval::GetProfile(sampleCount len,
                                    float *buffer)
{
   float *in = new float[len];
   float *out = new float[len];
   
   int i;
   
   for(i=0; i<len; i++)
      in[i] = buffer[i];

   // Apply window and FFT
   /* WindowFunc(3, len, in); // Hanning window */
   PowerSpectrum(len, in, out);
   
   for(i=0; i<=len/2; i++) {
      float value = log(out[i]);
      
      if (finite(value)) {
         sum[i] += value;
         sumsq[i] += value*value;
         profileCount[i]++;
      }
   }

   delete[] in;
   delete[] out;
}
Beispiel #2
0
void EffectNoiseRemoval::RemoveNoise(sampleCount len, float *buffer)
{
   float *inr = new float[len];
   float *ini = new float[len];
   float *outr = new float[len];
   float *outi = new float[len];
   float *power = new float[len];
   float *plog = new float[len];
   
   int i;
   
   for(i=0; i<len; i++)
      inr[i] = buffer[i];

   // Apply window and FFT
   /* WindowFunc(3, len, inr); // Hanning window */
   FFT(len, false, inr, NULL, outr, outi);

   for(i=0; i<len; i++)
      inr[i] = buffer[i];
   WindowFunc(3, len, inr); // Hanning window
   PowerSpectrum(len, inr, power);

   for(i=0; i<=len/2; i++)
      plog[i] = log(power[i]);
    
   int half = len/2;
   for(i=0; i<=half; i++) {
      float smooth;
      
//Factor of 4 here replaces previous 2, giving a 
//finer gradation of noise removal choice.      
      if (plog[i] < mNoiseGate[i] + (mLevel / 4.0))
         smooth = float(0.0);
      else
         smooth = float(1.0);
      
      smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5;
   }

   /* try to eliminate tinkle bells */
   for(i=2; i<=half-2; i++) {
      if (smoothing[i]>=0.5 &&
          smoothing[i]<=0.55 &&
          smoothing[i-1]<0.1 &&
          smoothing[i-2]<0.1 &&
          smoothing[i+1]<0.1 &&
          smoothing[i+2]<0.1)
          smoothing[i] = float(0.0);
   }

   outr[0] *= smoothing[0];
   outi[0] *= smoothing[0];
   outr[half] *= smoothing[half];
   outi[half] *= smoothing[half];
   for(i=1; i<half; i++) {
      int j = len - i;
      float smooth = smoothing[i];

      outr[i] *= smooth;
      outi[i] *= smooth;
      outr[j] *= smooth;
      outi[j] *= smooth;
   }

   // Inverse FFT and normalization
   FFT(len, true, outr, outi, inr, ini);
   WindowFunc(3, len, inr); // Hanning window */
   
   for(i=0; i<len; i++)
      buffer[i] = inr[i];

   delete[] inr;
   delete[] ini;
   delete[] outr;
   delete[] outi;
   delete[] power;
   delete[] plog;
}
Beispiel #3
0
void FreqWindow::Recalc()
{
   wxLogMessage(wxT("Starting FreqWindow::Recalc()"));
   if (mProcessed)
      delete[] mProcessed;
   mProcessed = NULL;

   if (!mData) {
      mFreqPlot->Refresh(true);
      return;
   }

   int alg = mAlgChoice->GetSelection();
   int windowFunc = mFuncChoice->GetSelection();
   long windowSize = 0;
   (mSizeChoice->GetStringSelection()).ToLong(&windowSize);

   int f = NumWindowFuncs();

   if (!(windowSize >= 32 && windowSize <= 65536 &&
         alg >= 0 && alg <= 4 && windowFunc >= 0 && windowFunc < f)) {
      mFreqPlot->Refresh(true);
      return;
   }

   mWindowSize = windowSize;

   if (mDataLen < mWindowSize) {
      mFreqPlot->Refresh(true);
      return;
   }

   mProcessed = new float[mWindowSize];

   int i;
   for (i = 0; i < mWindowSize; i++)
      mProcessed[i] = float(0.0);
   int half = mWindowSize / 2;

   float *in = new float[mWindowSize];
   float *in2 = new float[mWindowSize];
   float *out = new float[mWindowSize];
   float *out2 = new float[mWindowSize];
   float *win = new float[mWindowSize];

   // initialize the window
   for(int i=0; i<mWindowSize; i++)
      win[i] = 1.0;
   WindowFunc(windowFunc, mWindowSize, win);
   // Scale window such that an amplitude of 1.0 in the time domain
   // shows an amplitude of 0dB in the frequency domain
   double wss = 0;
   for(int i=0; i<mWindowSize; i++)
      wss += win[i];
   if(wss > 0)
      wss = 4.0 / (wss*wss);
   else
      wss = 1.0;

   //Progress dialog over FFT operation
   wxLogMessage(wxT("Starting progress dialogue in FreqWindow::Recalc()"));
   ProgressDialog *mProgress = new ProgressDialog(_("FreqWindow"),_("Drawing Spectrum"));

   int start = 0;
   int windows = 0;
   while (start + mWindowSize <= mDataLen) {
      for (i = 0; i < mWindowSize; i++)
         in[i] = win[i] * mData[start + i];

      switch (alg) {
      case 0:                  // Spectrum
         PowerSpectrum(mWindowSize, in, out);

         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];
         break;

      case 1:
      case 2:
      case 3:   // Autocorrelation, Cuberoot AC or Enhanced AC

         // Take FFT
#ifdef EXPERIMENTAL_USE_REALFFTF
         RealFFT(mWindowSize, in, out, out2);
#else
         FFT(mWindowSize, false, in, NULL, out, out2);
#endif
         // Compute power
         for (i = 0; i < mWindowSize; i++)
            in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);

         if (alg == 1) {
            for (i = 0; i < mWindowSize; i++)
               in[i] = sqrt(in[i]);
         }
         if (alg == 2 || alg == 3) {
            // Tolonen and Karjalainen recommend taking the cube root
            // of the power, instead of the square root

            for (i = 0; i < mWindowSize; i++)
               in[i] = pow(in[i], 1.0f / 3.0f);
         }
         // Take FFT
#ifdef EXPERIMENTAL_USE_REALFFTF
         RealFFT(mWindowSize, in, out, out2);
#else
         FFT(mWindowSize, false, in, NULL, out, out2);
#endif

         // Take real part of result
         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];
         break;

      case 4:                  // Cepstrum
#ifdef EXPERIMENTAL_USE_REALFFTF
         RealFFT(mWindowSize, in, out, out2);
#else
         FFT(mWindowSize, false, in, NULL, out, out2);
#endif

         // Compute log power
         // Set a sane lower limit assuming maximum time amplitude of 1.0
         float power;
         float minpower = 1e-20*mWindowSize*mWindowSize;
         for (i = 0; i < mWindowSize; i++)
         {
            power = (out[i] * out[i]) + (out2[i] * out2[i]);
            if(power < minpower)
               in[i] = log(minpower);
            else
               in[i] = log(power);
         }
         // Take IFFT
#ifdef EXPERIMENTAL_USE_REALFFTF
         InverseRealFFT(mWindowSize, in, NULL, out);
#else
         FFT(mWindowSize, true, in, NULL, out, out2);
#endif

         // Take real part of result
         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];

         break;
      }                         //switch

      start += half;
      windows++;
      // only update the progress dialogue infrequently to reduce it's overhead
      // If we do it every time, it spends as much time updating X11 as doing
      // the calculations. 10 seems a reasonable compromise on Linux that
      // doesn't make it unresponsive, but avoids the slowdown.
      if ((windows % 10) == 0)
         mProgress->Update(1 - static_cast<float>(mDataLen - start) / mDataLen);
   }

   wxLogMessage(wxT("Finished updating progress dialogue in FreqWindow::Recalc()"));
   switch (alg) {
   double scale;
   case 0:                     // Spectrum
      // Convert to decibels
      mYMin = 1000000.;
      mYMax = -1000000.;
      scale = wss / (double)windows;
      for (i = 0; i < half; i++)
      {
         mProcessed[i] = 10 * log10(mProcessed[i] * scale);
         if(mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if(mProcessed[i] < mYMin)
            mYMin = mProcessed[i];
      }
      if(mYMin < -dBRange)
         mYMin = -dBRange;
      if(mYMax <= -dBRange)
         mYMax = -dBRange + 10.; // it's all out of range, but show a scale.
      else
         mYMax += .5;

      mProcessedSize = half;
      mYStep = 10;
      break;

   case 1:                     // Standard Autocorrelation
   case 2:                     // Cuberoot Autocorrelation
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;

   case 3:                     // Enhanced Autocorrelation
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Peak Pruning as described by Tolonen and Karjalainen, 2000

      // Clip at zero, copy to temp array
      for (i = 0; i < half; i++) {
         if (mProcessed[i] < 0.0)
            mProcessed[i] = float(0.0);
         out[i] = mProcessed[i];
      }

      // Subtract a time-doubled signal (linearly interp.) from the original
      // (clipped) signal
      for (i = 0; i < half; i++)
         if ((i % 2) == 0)
            mProcessed[i] -= out[i / 2];
         else
            mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);

      // Clip at zero again
      for (i = 0; i < half; i++)
         if (mProcessed[i] < 0.0)
            mProcessed[i] = float(0.0);

      // Find new min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;

   case 4:                     // Cepstrum
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max, ignoring first and last few values
      int ignore = 4;
      mYMin = mProcessed[ignore];
      mYMax = mProcessed[ignore];
      for (i = ignore + 1; i < half - ignore; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;
   }

   delete[]in;
   delete[]in2;
   delete[]out;
   delete[]out2;
   delete[]win;

   wxLogMessage(wxT("About to draw plot in FreqWindow::Recalc()"));
   DrawPlot();
   mFreqPlot->Refresh(true);
   delete mProgress;
}
Beispiel #4
0
/**
 * Execute smoothing of a single spectrum.
 * @param inputWS :: A workspace to pick a spectrum from.
 * @param wsIndex :: An index of a spectrum to smooth.
 * @return :: A single-spectrum workspace with the smoothed data.
 */
API::MatrixWorkspace_sptr
WienerSmooth::smoothSingleSpectrum(API::MatrixWorkspace_sptr inputWS,
                                   size_t wsIndex) {
  size_t dataSize = inputWS->blocksize();

  // it won't work for very small workspaces
  if (dataSize < 4) {
    g_log.debug() << "No smoothing, spectrum copied." << std::endl;
    return copyInput(inputWS, wsIndex);
  }

  // Due to the way RealFFT works the input should be even-sized
  const bool isOddSize = dataSize % 2 != 0;
  if (isOddSize) {
    // add a fake value to the end to make size even
    inputWS = copyInput(inputWS, wsIndex);
    wsIndex = 0;
    auto &X = inputWS->dataX(wsIndex);
    auto &Y = inputWS->dataY(wsIndex);
    auto &E = inputWS->dataE(wsIndex);
    double dx = X[dataSize - 1] - X[dataSize - 2];
    X.push_back(X.back() + dx);
    Y.push_back(Y.back());
    E.push_back(E.back());
  }

  // the input vectors
  auto &X = inputWS->readX(wsIndex);
  auto &Y = inputWS->readY(wsIndex);
  auto &E = inputWS->readE(wsIndex);

  // Digital fourier transform works best for data oscillating around 0.
  // Fit a spline with a small number of break points to the data.
  // Make sure that the spline passes through the first and the last points
  // of the data.
  // The fitted spline will be subtracted from the data and the difference
  // will be smoothed with the Wiener filter. After that the spline will be
  // added to the smoothed data to produce the output.

  // number of spline break points, must be smaller than the data size but
  // between 2 and 10
  size_t nbreak = 10;
  if (nbreak * 3 > dataSize)
    nbreak = dataSize / 3;

  // NB. The spline mustn't fit too well to the data. If it does smoothing
  // doesn't happen.
  // TODO: it's possible that the spline is unnecessary and a simple linear
  // function will
  //       do a better job.

  g_log.debug() << "Spline break points " << nbreak << std::endl;

  // define the spline
  API::IFunction_sptr spline =
      API::FunctionFactory::Instance().createFunction("BSpline");
  auto xInterval = getStartEnd(X, inputWS->isHistogramData());
  spline->setAttributeValue("StartX", xInterval.first);
  spline->setAttributeValue("EndX", xInterval.second);
  spline->setAttributeValue("NBreak", static_cast<int>(nbreak));
  // fix the first and last parameters to the first and last data values
  spline->setParameter(0, Y.front());
  spline->fix(0);
  size_t lastParamIndex = spline->nParams() - 1;
  spline->setParameter(lastParamIndex, Y.back());
  spline->fix(lastParamIndex);

  // fit the spline to the data
  auto fit = createChildAlgorithm("Fit");
  fit->initialize();
  fit->setProperty("Function", spline);
  fit->setProperty("InputWorkspace", inputWS);
  fit->setProperty("WorkspaceIndex", static_cast<int>(wsIndex));
  fit->setProperty("CreateOutput", true);
  fit->execute();

  // get the fit output workspace; spectrum 2 contains the difference that is to
  // be smoothed
  API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace");

  // Fourier transform the difference spectrum
  auto fourier = createChildAlgorithm("RealFFT");
  fourier->initialize();
  fourier->setProperty("InputWorkspace", fitOut);
  fourier->setProperty("WorkspaceIndex", 2);
  // we don't require bin linearity as we don't need the exact transform
  fourier->setProperty("IgnoreXBins", true);
  fourier->execute();

  API::MatrixWorkspace_sptr fourierOut =
      fourier->getProperty("OutputWorkspace");

  // spectrum 2 of the transformed workspace has the transform modulus which is
  // a square
  // root of the power spectrum
  auto &powerSpec = fourierOut->dataY(2);
  // convert the modulus to power spectrum wich is the base of the Wiener filter
  std::transform(powerSpec.begin(), powerSpec.end(), powerSpec.begin(),
                 PowerSpectrum());

  // estimate power spectrum's noise as the average of its high frequency half
  size_t n2 = powerSpec.size();
  double noise =
      std::accumulate(powerSpec.begin() + n2 / 2, powerSpec.end(), 0.0);
  noise /= static_cast<double>(n2);

  // index of the maximum element in powerSpec
  const size_t imax = static_cast<size_t>(std::distance(
      powerSpec.begin(), std::max_element(powerSpec.begin(), powerSpec.end())));

  if (noise == 0.0) {
    noise = powerSpec[imax] / guessSignalToNoiseRatio;
  }

  g_log.debug() << "Maximum signal " << powerSpec[imax] << std::endl;
  g_log.debug() << "Noise          " << noise << std::endl;

  // storage for the Wiener filter, initialized with 0.0's
  std::vector<double> wf(n2);

  // The filter consists of two parts:
  //   1) low frequency region, from 0 until the power spectrum falls to the
  //   noise level, filter is calculated
  //      from the power spectrum
  //   2) high frequency noisy region, filter is a smooth function of frequency
  //   decreasing to 0

  // the following code is an adaptation of a fortran routine
  // noise starting index
  size_t i0 = 0;
  // intermediate variables
  double xx = 0.0;
  double xy = 0.0;
  double ym = 0.0;
  // low frequency filter values: the higher the power spectrum the closer the
  // filter to 1.0
  for (size_t i = 0; i < n2; ++i) {
    double cd1 = powerSpec[i] / noise;
    if (cd1 < 1.0 && i > imax) {
      i0 = i;
      break;
    }
    double cd2 = log(cd1);
    wf[i] = cd1 / (1.0 + cd1);
    double j = static_cast<double>(i + 1);
    xx += j * j;
    xy += j * cd2;
    ym += cd2;
  }

  // i0 should always be > 0 but in case something goes wrong make a check
  if (i0 > 0) {
    g_log.debug() << "Noise start index " << i0 << std::endl;

    // high frequency filter values: smooth decreasing function
    double ri0f = static_cast<double>(i0 + 1);
    double xm = (1.0 + ri0f) / 2;
    ym /= ri0f;
    double a1 = (xy - ri0f * xm * ym) / (xx - ri0f * xm * xm);
    double b1 = ym - a1 * xm;

    g_log.debug() << "(a1,b1) = (" << a1 << ',' << b1 << ')' << std::endl;

    const double dblev = -20.0;
    // cut-off index
    double ri1 = floor((dblev / 4 - b1) / a1);
    if (ri1 < static_cast<double>(i0)) {
      g_log.warning() << "Failed to build Wiener filter: no smoothing."
                      << std::endl;
      ri1 = static_cast<double>(i0);
    }
    size_t i1 = static_cast<size_t>(ri1);
    if (i1 > n2)
      i1 = n2;
    for (size_t i = i0; i < i1; ++i) {
      double s = exp(a1 * static_cast<double>(i + 1) + b1);
      wf[i] = s / (1.0 + s);
    }
    // wf[i] for i1 <= i < n2 are 0.0

    g_log.debug() << "Cut-off index " << i1 << std::endl;
  } else {
    g_log.warning() << "Power spectrum has an unexpected shape: no smoothing"
                    << std::endl;
    return copyInput(inputWS, wsIndex);
  }

  // multiply the fourier transform by the filter
  auto &re = fourierOut->dataY(0);
  auto &im = fourierOut->dataY(1);

  std::transform(re.begin(), re.end(), wf.begin(), re.begin(),
                 std::multiplies<double>());
  std::transform(im.begin(), im.end(), wf.begin(), im.begin(),
                 std::multiplies<double>());

  // inverse fourier transform
  fourier = createChildAlgorithm("RealFFT");
  fourier->initialize();
  fourier->setProperty("InputWorkspace", fourierOut);
  fourier->setProperty("IgnoreXBins", true);
  fourier->setPropertyValue("Transform", "Backward");
  fourier->execute();

  API::MatrixWorkspace_sptr out = fourier->getProperty("OutputWorkspace");
  auto &background = fitOut->readY(1);
  auto &y = out->dataY(0);

  if (y.size() != background.size()) {
    throw std::logic_error("Logic error: inconsistent arrays");
  }

  // add the spline "background" to the smoothed data
  std::transform(y.begin(), y.end(), background.begin(), y.begin(),
                 std::plus<double>());

  // copy the x-values and errors from the original spectrum
  // remove the last values for odd-sized inputs
  if (isOddSize) {
    out->dataX(0).assign(X.begin(), X.end() - 1);
    out->dataE(0).assign(E.begin(), E.end() - 1);
    out->dataY(0).resize(Y.size() - 1);
  } else {
    out->setX(0, X);
    out->dataE(0).assign(E.begin(), E.end());
  }

  return out;
}
bool SpectrumAnalyst::Calculate(Algorithm alg, int windowFunc,
                                size_t windowSize, double rate,
                                const float *data, size_t dataLen,
                                float *pYMin, float *pYMax,
                                FreqGauge *progress)
{
   // Wipe old data
   mProcessed.resize(0);
   mRate = 0.0;
   mWindowSize = 0;

   // Validate inputs
   int f = NumWindowFuncs();

   if (!(windowSize >= 32 && windowSize <= 65536 &&
         alg >= SpectrumAnalyst::Spectrum &&
         alg < SpectrumAnalyst::NumAlgorithms &&
         windowFunc >= 0 && windowFunc < f)) {
      return false;
   }

   if (dataLen < windowSize) {
      return false;
   }

   // Now repopulate
   mRate = rate;
   mWindowSize = windowSize;
   mAlg = alg;

   auto half = mWindowSize / 2;
   mProcessed.resize(mWindowSize);

   Floats in{ mWindowSize };
   Floats out{ mWindowSize };
   Floats out2{ mWindowSize };
   Floats win{ mWindowSize };

   for (size_t i = 0; i < mWindowSize; i++) {
      mProcessed[i] = 0.0f;
      win[i] = 1.0f;
   }

   WindowFunc(windowFunc, mWindowSize, win.get());

   // Scale window such that an amplitude of 1.0 in the time domain
   // shows an amplitude of 0dB in the frequency domain
   double wss = 0;
   for (size_t i = 0; i<mWindowSize; i++)
      wss += win[i];
   if(wss > 0)
      wss = 4.0 / (wss*wss);
   else
      wss = 1.0;

   if (progress) {
      progress->SetRange(dataLen);
   }

   size_t start = 0;
   int windows = 0;
   while (start + mWindowSize <= dataLen) {
      for (size_t i = 0; i < mWindowSize; i++)
         in[i] = win[i] * data[start + i];

      switch (alg) {
         case Spectrum:
            PowerSpectrum(mWindowSize, in.get(), out.get());

            for (size_t i = 0; i < half; i++)
               mProcessed[i] += out[i];
            break;

         case Autocorrelation:
         case CubeRootAutocorrelation:
         case EnhancedAutocorrelation:

            // Take FFT
            RealFFT(mWindowSize, in.get(), out.get(), out2.get());
            // Compute power
            for (size_t i = 0; i < mWindowSize; i++)
               in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);

            if (alg == Autocorrelation) {
               for (size_t i = 0; i < mWindowSize; i++)
                  in[i] = sqrt(in[i]);
            }
            if (alg == CubeRootAutocorrelation ||
                alg == EnhancedAutocorrelation) {
               // Tolonen and Karjalainen recommend taking the cube root
               // of the power, instead of the square root

               for (size_t i = 0; i < mWindowSize; i++)
                  in[i] = pow(in[i], 1.0f / 3.0f);
            }
            // Take FFT
            RealFFT(mWindowSize, in.get(), out.get(), out2.get());

            // Take real part of result
            for (size_t i = 0; i < half; i++)
               mProcessed[i] += out[i];
            break;

         case Cepstrum:
            RealFFT(mWindowSize, in.get(), out.get(), out2.get());

            // Compute log power
            // Set a sane lower limit assuming maximum time amplitude of 1.0
            {
               float power;
               float minpower = 1e-20*mWindowSize*mWindowSize;
               for (size_t i = 0; i < mWindowSize; i++)
               {
                  power = (out[i] * out[i]) + (out2[i] * out2[i]);
                  if(power < minpower)
                     in[i] = log(minpower);
                  else
                     in[i] = log(power);
               }
               // Take IFFT
               InverseRealFFT(mWindowSize, in.get(), NULL, out.get());

               // Take real part of result
               for (size_t i = 0; i < half; i++)
                  mProcessed[i] += out[i];
            }

            break;

         default:
            wxASSERT(false);
            break;
      }                         //switch

      // Update the progress bar
      if (progress) {
         progress->SetValue(start);
      }

      start += half;
      windows++;
   }

   if (progress) {
      // Reset for next time
      progress->Reset();
   }

   float mYMin = 1000000, mYMax = -1000000;
   double scale;
   switch (alg) {
   case Spectrum:
      // Convert to decibels
      mYMin = 1000000.;
      mYMax = -1000000.;
      scale = wss / (double)windows;
      for (size_t i = 0; i < half; i++)
      {
         mProcessed[i] = 10 * log10(mProcessed[i] * scale);
         if(mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if(mProcessed[i] < mYMin)
            mYMin = mProcessed[i];
      }
      break;

   case Autocorrelation:
   case CubeRootAutocorrelation:
      for (size_t i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (size_t i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];
      break;

   case EnhancedAutocorrelation:
      for (size_t i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Peak Pruning as described by Tolonen and Karjalainen, 2000

      // Clip at zero, copy to temp array
      for (size_t i = 0; i < half; i++) {
         if (mProcessed[i] < 0.0)
            mProcessed[i] = float(0.0);
         out[i] = mProcessed[i];
      }

      // Subtract a time-doubled signal (linearly interp.) from the original
      // (clipped) signal
      for (size_t i = 0; i < half; i++)
         if ((i % 2) == 0)
            mProcessed[i] -= out[i / 2];
         else
            mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);

      // Clip at zero again
      for (size_t i = 0; i < half; i++)
         if (mProcessed[i] < 0.0)
            mProcessed[i] = float(0.0);

      // Find NEW min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (size_t i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];
      break;

   case Cepstrum:
      for (size_t i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max, ignoring first and last few values
      {
         size_t ignore = 4;
         mYMin = mProcessed[ignore];
         mYMax = mProcessed[ignore];
         for (size_t i = ignore + 1; i + ignore < half; i++)
            if (mProcessed[i] > mYMax)
               mYMax = mProcessed[i];
            else if (mProcessed[i] < mYMin)
               mYMin = mProcessed[i];
      }
      break;

   default:
      wxASSERT(false);
      break;
   }

   if (pYMin)
      *pYMin = mYMin;
   if (pYMax)
      *pYMax = mYMax;

   return true;
}
Beispiel #6
0
void EffectNoiseRemoval::RemoveNoise(sampleCount len,
                                     sampleType *buffer)
{
   float *inr = new float[len];
   float *ini = new float[len];
   float *outr = new float[len];
   float *outi = new float[len];
   float *power = new float[len];
   float *plog = new float[len];
   
   int i;
   
   for(i=0; i<len; i++)
      inr[i] = buffer[i]/32767.;

   // Apply window and FFT
   WindowFunc(3, len, inr); // Hanning window
   FFT(len, false, inr, NULL, outr, outi);

   for(i=0; i<len; i++)
      inr[i] = buffer[i]/32767.;
   WindowFunc(3, len, inr); // Hanning window
   PowerSpectrum(len, inr, power);

   for(i=0; i<=len/2; i++)
      plog[i] = log(power[i]);
    
   int half = len/2;
   for(i=0; i<=half; i++) {
      float smooth;
      
      if (plog[i] < noiseGate[i] + (level/2.0))
         smooth = 0.0;
      else
         smooth = 1.0;
      
      smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5;
   }

   /* try to eliminate tinkle bells */
   for(i=2; i<=half-2; i++) {
      if (smoothing[i]>=0.5 &&
          smoothing[i]<=0.55 &&
          smoothing[i-1]<0.1 &&
          smoothing[i-2]<0.1 &&
          smoothing[i+1]<0.1 &&
          smoothing[i+2]<0.1)
         smoothing[i] = 0.0;
   }

   outr[0] *= smoothing[0];
   outi[0] *= smoothing[0];
   outr[half] *= smoothing[half];
   outi[half] *= smoothing[half];
   for(i=1; i<half; i++) {
      int j = len - i;
      float smooth = smoothing[i];

      outr[i] *= smooth;
      outi[i] *= smooth;
      outr[j] *= smooth;
      outi[j] *= smooth;
   }

   // Inverse FFT and normalization
   FFT(len, true, outr, outi, inr, ini);
   
   for(i=0; i<len; i++)
      buffer[i] = sampleType(inr[i]*32767);

   delete[] inr;
   delete[] ini;
   delete[] outr;
   delete[] outi;
   delete[] power;
   delete[] plog;
}
Beispiel #7
0
bool ComputeSpectrum(float * data, int width, int height,
                     int maxFreq, int windowSize,
                     double rate, float *grayscaleOut,
                     bool autocorrelation)
{
   int windowFunc = 3;

   if (width < windowSize)
      return false;

   if (!data || !grayscaleOut)
      return true;

   float *processed = new float[windowSize];

   int i;
   for (i = 0; i < windowSize; i++)
      processed[i] = float(0.0);
   int half = windowSize / 2;

   float *in = new float[windowSize];
   float *out = new float[windowSize];
   float *out2 = new float[windowSize];

   int start = 0;
   int windows = 0;
   while (start + windowSize <= width) {
      for (i = 0; i < windowSize; i++)
         in[i] = data[start + i];

      WindowFunc(windowFunc, windowSize, in);

      if (autocorrelation) {
         // Take FFT
         FFT(windowSize, false, in, NULL, out, out2);

         // Compute power
         for (i = 0; i < windowSize; i++)
            in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);

         // Tolonen and Karjalainen recommend taking the cube root
         // of the power, instead of the square root

         for (i = 0; i < windowSize; i++)
            in[i] = pow(in[i], 1.0f / 3.0f);

         // Take FFT
         FFT(windowSize, false, in, NULL, out, out2);

         // Take real part of result
         for (i = 0; i < half; i++)
            processed[i] += out[i];
      } else {
         PowerSpectrum(windowSize, in, out);

         for (i = 0; i < half; i++)
            processed[i] += out[i];
      }

      start += half;
      windows++;
   }

   int maxSamples = int (maxFreq * windowSize / rate + 0.5);
   if (maxSamples > half)
      maxSamples = half;

   if (autocorrelation) {
      maxSamples = half;

      // Peak Pruning as described by Tolonen and Karjalainen, 2000

      // Clip at zero, copy to temp array
      for (i = 0; i < maxSamples; i++) {
         if (processed[i] < 0.0)
            processed[i] = float(0.0);
         out[i] = processed[i];
      }

      // Subtract a time-doubled signal (linearly interp.) from the original
      // (clipped) signal
      for (i = 0; i < maxSamples; i++)
         if ((i % 2) == 0)
            processed[i] -= out[i / 2];
         else
            processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);

      // Clip at zero again
      for (i = 0; i < maxSamples; i++)
         if (processed[i] < 0.0)
            processed[i] = float(0.0);

      // Find new max
      float max = 0;
      for (i = 1; i < maxSamples; i++)
         if (processed[i] > max)
            max = processed[i];

      // Reverse and scale
      for (i = 0; i < maxSamples; i++)
         in[i] = processed[i] / (windowSize / 4);
      for (i = 0; i < maxSamples; i++)
         processed[maxSamples - 1 - i] = in[i];
   } else {
      // Convert to decibels
      for (i = 0; i < maxSamples; i++)
         processed[i] = 10 * log10(processed[i] / windowSize / windows);
   }

   // Finally, put it into bins in grayscaleOut[], normalized to a 0.0-1.0 scale

   for (i = 0; i < height; i++) {
      float bin0 = float (i) * maxSamples / height;
      float bin1 = float (i + 1) * maxSamples / height;

      float binwidth = bin1 - bin0;

      float value = float(0.0);

      if (int (bin1) == int (bin0))
         value = processed[int (bin0)];
      else {
         value += processed[int (bin0)] * (int (bin0) + 1 - bin0);
         bin0 = 1 + int (bin0);
         while (bin0 < int (bin1)) {
            value += processed[int (bin0)];
            bin0 += 1.0;
         }
         value += processed[int (bin1)] * (bin1 - int (bin1));

         value /= binwidth;
      }

      if (!autocorrelation) {
         // Last step converts dB to a 0.0-1.0 range     
         value = (value + 80.0) / 80.0;
      }

      if (value > 1.0)
         value = float(1.0);
      if (value < 0.0)
         value = float(0.0);

      grayscaleOut[i] = value;
   }

   delete[]in;
   delete[]out;
   delete[]out2;
   delete[]processed;

   return true;
}
Beispiel #8
0
void FreqWindow::Recalc()
{
   if (mProcessed)
      delete mProcessed;
   mProcessed = NULL;

   if (!mData) {
      mFreqPlot->Refresh(false);
      return;
   }

   int alg = mAlgChoice->GetSelection();
   int windowFunc = mFuncChoice->GetSelection();
   long windowSize = 0;
   (mSizeChoice->GetStringSelection()).ToLong(&windowSize);

   if (!(windowSize >= 32 && windowSize <= 65536 &&
         alg >= 0 && alg <= 3 && windowFunc >= 0 && windowFunc <= 3)) {
      mFreqPlot->Refresh(false);
      return;
   }

   mWindowSize = windowSize;

   if (mDataLen < mWindowSize) {
      mFreqPlot->Refresh(false);
      return;
   }

   mProcessed = new float[mWindowSize];

   int i;
   for (i = 0; i < mWindowSize; i++)
      mProcessed[i] = 0.0;
   int half = mWindowSize / 2;

   float *in = new float[mWindowSize];
   float *in2 = new float[mWindowSize];
   float *out = new float[mWindowSize];
   float *out2 = new float[mWindowSize];

   int start = 0;
   int windows = 0;
   while (start + mWindowSize <= mDataLen) {
      for (i = 0; i < mWindowSize; i++)
         in[i] = mData[start + i];

      WindowFunc(windowFunc, mWindowSize, in);

      switch (alg) {
      case 0:                  // Spectrum
         PowerSpectrum(mWindowSize, in, out);

         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];
         break;

      case 1:
      case 2:
      case 3:                  // Autocorrelation, Cuberoot AC or Enhanced AC

         // Take FFT
         FFT(mWindowSize, false, in, NULL, out, out2);

         // Compute power
         for (i = 0; i < mWindowSize; i++)
            in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);

         if (alg == 1) {
            for (i = 0; i < mWindowSize; i++)
               in[i] = sqrt(in[i]);
         }
         if (alg == 2 || alg == 3) {
            // Tolonen and Karjalainen recommend taking the cube root
            // of the power, instead of the square root

            for (i = 0; i < mWindowSize; i++)
               in[i] = pow(in[i], 1.0 / 3.0);
         }
         // Take FFT
         FFT(mWindowSize, false, in, NULL, out, out2);

         // Take real part of result
         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];
         break;

      case 4:                  // Cepstrum
         FFT(mWindowSize, false, in, NULL, out, out2);

         // Compute log power
         for (i = 0; i < mWindowSize; i++)
            in[i] = log((out[i] * out[i]) + (out2[i] * out2[i]));

         // Take IFFT
         FFT(mWindowSize, true, in, NULL, out, out2);

         // Take real part of result
         for (i = 0; i < half; i++)
            mProcessed[i] += out[i];

         break;
      }                         //switch

      start += half;
      windows++;
   }

   switch (alg) {
   case 0:                     // Spectrum
      // Convert to decibels
      for (i = 0; i < half; i++)
         mProcessed[i] = 10 * log10(mProcessed[i] / mWindowSize / windows);

      mProcessedSize = half;
      mYMin = -90;
      mYMax = 10;
      mYStep = 10;
      break;

   case 1:                     // Standard Autocorrelation
   case 2:                     // Cuberoot Autocorrelation
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;

   case 3:                     // Enhanced Autocorrelation
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Peak Pruning as described by Tolonen and Karjalainen, 2000

      // Clip at zero, copy to temp array
      for (i = 0; i < half; i++) {
         if (mProcessed[i] < 0.0)
            mProcessed[i] = 0.0;
         out[i] = mProcessed[i];
      }

      // Subtract a time-doubled signal (linearly interp.) from the original
      // (clipped) signal
      for (i = 0; i < half; i++)
         if ((i % 2) == 0)
            mProcessed[i] -= out[i / 2];
         else
            mProcessed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);

      // Clip at zero again
      for (i = 0; i < half; i++)
         if (mProcessed[i] < 0.0)
            mProcessed[i] = 0.0;

      // Find new min/max
      mYMin = mProcessed[0];
      mYMax = mProcessed[0];
      for (i = 1; i < half; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;

   case 4:                     // Cepstrum
      for (i = 0; i < half; i++)
         mProcessed[i] = mProcessed[i] / windows;

      // Find min/max, ignoring first and last few values
      int ignore = 4;
      mYMin = mProcessed[ignore];
      mYMax = mProcessed[ignore];
      for (i = ignore + 1; i < half - ignore; i++)
         if (mProcessed[i] > mYMax)
            mYMax = mProcessed[i];
         else if (mProcessed[i] < mYMin)
            mYMin = mProcessed[i];

      mYStep = 1;

      mProcessedSize = half;
      break;
   }

   delete[]in;
   delete[]in2;
   delete[]out;
   delete[]out2;

   mFreqPlot->Refresh(false);
}
/* Mangle a single window. Each output sample (except the first and last
 * half-window) is the result of two distinct calls to this function, 
 * due to overlapping windows. */
static void reduce_noise(chandata_t* chan, float* window, float level)
{
    float *inr   = (float*)calloc(WINDOWSIZE, sizeof(float));
    float *ini   = (float*)calloc(WINDOWSIZE, sizeof(float));
    float *outr  = (float*)calloc(WINDOWSIZE, sizeof(float));
    float *outi  = (float*)calloc(WINDOWSIZE, sizeof(float));
    float *power = (float*)calloc(WINDOWSIZE, sizeof(float));
    float *smoothing = chan->smoothing;
    static int callnum = 0;
    int i;

    callnum ++;

    for (i = 0; i < FREQCOUNT; i ++) {
        assert(smoothing[i] >= 0 && smoothing[i] <= 1);
    }

    memcpy(inr, window, WINDOWSIZE*sizeof(float));

    FFT(WINDOWSIZE, 0, inr, NULL, outr, outi);

    memcpy(inr, window, WINDOWSIZE*sizeof(float));
    WindowFunc(HANNING, WINDOWSIZE, inr);
    PowerSpectrum(WINDOWSIZE, inr, power);

    for(i = 0; i < FREQCOUNT; i ++) {
        float smooth;
        float plog;
        plog = log(power[i]);
        if (power[i] != 0 && plog < chan->noisegate[i] + level*8.0)
            smooth = 0.0;
        else
            smooth = 1.0;

        smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5;
    }

    /* Audacity says this code will eliminate tinkle bells.
     * I have no idea what that means. */
    for (i = 2; i < FREQCOUNT - 2; i ++) {
        if (smoothing[i]>=0.5 &&
            smoothing[i]<=0.55 &&
            smoothing[i-1]<0.1 &&
            smoothing[i-2]<0.1 &&
            smoothing[i+1]<0.1 &&
            smoothing[i+2]<0.1)
            smoothing[i] = 0.0;
    }

    outr[0] *= smoothing[0];
    outi[0] *= smoothing[0];
    outr[FREQCOUNT-1] *= smoothing[FREQCOUNT-1];
    outi[FREQCOUNT-1] *= smoothing[FREQCOUNT-1];
    
    for (i = 1; i < FREQCOUNT-1; i ++) {
        int j = WINDOWSIZE - i;
        float smooth = smoothing[i];

        outr[i] *= smooth;
        outi[i] *= smooth;
        outr[j] *= smooth;
        outi[j] *= smooth;
    }

    FFT(WINDOWSIZE, 1, outr, outi, inr, ini);
    WindowFunc(HANNING, WINDOWSIZE, inr);

    memcpy(window, inr, WINDOWSIZE*sizeof(float));

    free(inr);
    free(ini);
    free(outr);
    free(outi);
    free(power);

    for (i = 0; i < FREQCOUNT; i ++) {
        assert(smoothing[i] >= 0 && smoothing[i] <= 1);
    }
}
Beispiel #10
0
bool ComputeSpectrum(const float * data, int width,
                     int windowSize,
                     double WXUNUSED(rate), float *output,
                     bool autocorrelation, int windowFunc)
{
   if (width < windowSize)
      return false;

   if (!data || !output)
      return true;

   float *processed = new float[windowSize];

   int i;
   for (i = 0; i < windowSize; i++)
      processed[i] = float(0.0);
   int half = windowSize / 2;

   float *in = new float[windowSize];
   float *out = new float[windowSize];
   float *out2 = new float[windowSize];

   int start = 0;
   int windows = 0;
   while (start + windowSize <= width) {
      for (i = 0; i < windowSize; i++)
         in[i] = data[start + i];

      WindowFunc(windowFunc, windowSize, in);

      if (autocorrelation) {
         // Take FFT
         RealFFT(windowSize, in, out, out2);
         // Compute power
         for (i = 0; i < windowSize; i++)
            in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);

         // Tolonen and Karjalainen recommend taking the cube root
         // of the power, instead of the square root

         for (i = 0; i < windowSize; i++)
            in[i] = powf(in[i], 1.0f / 3.0f);

         // Take FFT
         RealFFT(windowSize, in, out, out2);
      }
      else
         PowerSpectrum(windowSize, in, out);

      // Take real part of result
      for (i = 0; i < half; i++)
        processed[i] += out[i];

      start += half;
      windows++;
   }

   if (autocorrelation) {

      // Peak Pruning as described by Tolonen and Karjalainen, 2000
      /*
       Combine most of the calculations in a single for loop.
       It should be safe, as indexes refer only to current and previous elements,
       that have already been clipped, etc...
      */
      for (i = 0; i < half; i++) {
        // Clip at zero, copy to temp array
        if (processed[i] < 0.0)
            processed[i] = float(0.0);
        out[i] = processed[i];
        // Subtract a time-doubled signal (linearly interp.) from the original
        // (clipped) signal
        if ((i % 2) == 0)
           processed[i] -= out[i / 2];
        else
           processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);

        // Clip at zero again
        if (processed[i] < 0.0)
            processed[i] = float(0.0);
      }

      // Reverse and scale
      for (i = 0; i < half; i++)
         in[i] = processed[i] / (windowSize / 4);
      for (i = 0; i < half; i++)
         processed[half - 1 - i] = in[i];
   } else {
      // Convert to decibels
      // But do it safely; -Inf is nobody's friend
      for (i = 0; i < half; i++){
         float temp=(processed[i] / windowSize / windows);
         if (temp > 0.0)
            processed[i] = 10*log10(temp);
         else
            processed[i] = 0;
      }
   }

   for(i=0;i<half;i++)
      output[i] = processed[i];
   delete[]in;
   delete[]out;
   delete[]out2;
   delete[]processed;

   return true;
}