25   (
float * __restrict buffer, 
const FFTParam *hFFT,
 
   26    const float * __restrict window, 
size_t len, 
float * __restrict out)
 
   31   for(i = 0; i < len; i++)
 
   32      buffer[i] *= window[i];
 
   33   for( ; i < (hFFT->
Points * 2); i++)
 
   37   float power = buffer[0] * buffer[0];
 
   41      out[0] = 10.0 * log10f(
power);
 
   42   for(i = 1; i < hFFT->
Points; i++) {
 
   44      const float re = buffer[index], im = buffer[index + 1];
 
   45      power = re * re + im * im;
 
   49         out[i] = 10.0*log10f(
power);
 
   54   (
size_t fftLen, 
double rate, 
int frequencyGain, std::vector<float> &gainFactors)
 
   56   if (frequencyGain > 0) {
 
   61      const double factor = ((double)rate / (
double)fftLen) / 1000.0;
 
   63      auto half = fftLen / 2;
 
   64      gainFactors.reserve(half);
 
   66      gainFactors.push_back(frequencyGain*log10(factor));
 
   67      for (
decltype(half) x = 1; x < half; x++) {
 
   68         gainFactors.push_back(frequencyGain*log10(factor * x));
 
   76   int dirty_, 
double samplesPerPixel,
 
   82   const bool sppMatch = (fabs(samplesPerPixel - 
spp) * 
len < 1.0);
 
   96   const int xx, 
double pixelsPerSecond, 
int lowerBoundX, 
int upperBoundX,
 
   97   const std::vector<float>& gainFactors, 
float* __restrict scratch,
 
   98   float* __restrict out)
 const 
  101   const bool reassignment =
 
  103   const size_t windowSizeSetting = 
settings.WindowSize();
 
  110   const auto samplesPerPixel = 
sampleRate / pixelsPerSecond / stretchRatio;
 
  117   else if (xx > (
int)
len)
 
  122   const bool autocorrelation =
 
  124   const size_t zeroPaddingFactorSetting = 
settings.ZeroPaddingFactor();
 
  125   const size_t padding = (windowSizeSetting * (zeroPaddingFactorSetting - 1)) / 2;
 
  126   const size_t fftLen = windowSizeSetting * zeroPaddingFactorSetting;
 
  129   if (from < 0 || from >= numSamples) {
 
  130      if (xx >= 0 && xx < (
int)
len) {
 
  132         float *
const results = &out[nBins * xx];
 
  133         std::fill(results, results + nBins, 0.0f);
 
  140      bool copy = !autocorrelation || (padding > 0) || reassignment;
 
  141      std::vector<float> floats;
 
  142      float* useBuffer = 0;
 
  143      float *adj = scratch + padding;
 
  146         auto myLen = windowSizeSetting;
 
  148         from -= windowSizeSetting >> 1;
 
  152            for (
auto ii = from; ii < 0; ++ii)
 
  159         if (from + myLen >= numSamples) {
 
  162            auto newlen = ( numSamples - from ).as_size_t();
 
  163            for (
decltype(myLen) ii = newlen; ii < myLen; ++ii)
 
  171            constexpr auto mayThrow = 
false; 
 
  174            floats.resize(myLen);
 
  176            useBuffer = floats.data();
 
  179                  memcpy(adj, useBuffer, myLen * 
sizeof(
float));
 
  181                  memset(adj, 0, myLen * 
sizeof(
float));
 
  186      if (
copy || !useBuffer)
 
  189      if (autocorrelation) {
 
  192         float *
const results = &out[nBins * xx];
 
  195            useBuffer, windowSizeSetting, windowSizeSetting, results,
 
  196            autocorrelation, 
settings.windowType);
 
  198      else if (reassignment) {
 
  199         static const double epsilon = 1e-16;
 
  200         const auto hFFT = 
settings.hFFT.get();
 
  202         float *
const scratch2 = scratch + fftLen;
 
  205         float *
const scratch3 = scratch + 2 * fftLen;
 
  209            const float *
const window = 
settings.window.get();
 
  210            for (
size_t ii = 0; ii < fftLen; ++ii)
 
  211               scratch[ii] *= window[ii];
 
  216            const float *
const dWindow = 
settings.dWindow.get();
 
  217            for (
size_t ii = 0; ii < fftLen; ++ii)
 
  218               scratch2[ii] *= dWindow[ii];
 
  223            const float *
const tWindow = 
settings.tWindow.get();
 
  224            for (
size_t ii = 0; ii < fftLen; ++ii)
 
  225               scratch3[ii] *= tWindow[ii];
 
  229         for (
size_t ii = 0; ii < hFFT->Points; ++ii) {
 
  230            const int index = hFFT->BitReversed[ii];
 
  232               denomRe = scratch[index],
 
  233               denomIm = ii == 0 ? 0 : scratch[index + 1];
 
  234            const double power = denomRe * denomRe + denomIm * denomIm;
 
  239            double freqCorrection;
 
  241               const double multiplier = -(fftLen / (2.0f * 
M_PI));
 
  243                  numRe = scratch2[index],
 
  244                  numIm = ii == 0 ? 0 : scratch2[index + 1];
 
  250                  quotIm = (-numRe * denomIm + numIm * denomRe) / 
power;
 
  253               freqCorrection = multiplier * quotIm;
 
  256            const int bin = (int)((
int)ii + freqCorrection + 0.5f);
 
  259            if (bin >= 0 && bin < (
int)hFFT->Points) {
 
  260               double timeCorrection;
 
  263                     numRe = scratch3[index],
 
  264                     numIm = ii == 0 ? 0 : scratch3[index + 1];
 
  269                     (numRe * denomRe + numIm * denomIm) / 
power;
 
  275               int correctedX = (floor(
 
  276                  0.5 + xx + timeCorrection * pixelsPerSecond / 
sampleRate));
 
  277               if (correctedX >= lowerBoundX && correctedX < upperBoundX)
 
  282                  auto ind = (int)nBins * correctedX + bin;
 
  287                  #pragma omp atomic update 
  297         float *
const results = &out[nBins * xx];
 
  307         if (!gainFactors.empty()) {
 
  309            for (
size_t ii = 0; ii < nBins; ++ii)
 
  310               results[ii] += gainFactors[ii];
 
  330   where.resize(len_ + 1);
 
  334   spp = samplesPerPixel;
 
  344   int copyBegin, 
int copyEnd, 
size_t numPixels, 
double pixelsPerSecond)
 
  347   const int &frequencyGainSetting = 
settings.frequencyGain;
 
  348   const size_t windowSizeSetting = 
settings.WindowSize();
 
  349   const bool autocorrelation =
 
  351   const bool reassignment =
 
  353   const size_t zeroPaddingFactorSetting = 
settings.ZeroPaddingFactor();
 
  357   const size_t fftLen = windowSizeSetting * zeroPaddingFactorSetting;
 
  358   const auto nBins = 
settings.NBins();
 
  360   const size_t bufferSize = fftLen;
 
  361   const size_t scratchSize = reassignment ? 3 * bufferSize : bufferSize;
 
  362   std::vector<float> scratch(scratchSize);
 
  364   std::vector<float> gainFactors;
 
  365   if (!autocorrelation)
 
  367         fftLen, 
sampleRate, frequencyGainSetting, gainFactors);
 
  371   for (
int jj = 0; jj < 2; ++jj) {
 
  372      const int lowerBoundX = jj == 0 ? 0 : copyEnd;
 
  373      const int upperBoundX = jj == 0 ? copyBegin : numPixels;
 
  380      struct ThreadLocalStorage {
 
  381         ThreadLocalStorage()  { }
 
  382         ~ThreadLocalStorage() { }
 
  384         void init(SampleTrackCache &waveTrackCache, 
size_t scratchSize) {
 
  386               cache = std::make_unique<SampleTrackCache>(waveTrackCache.GetTrack());
 
  387               scratch.resize(scratchSize);
 
  390         std::unique_ptr<SampleTrackCache> cache;
 
  391         std::vector<float> scratch;
 
  394      #pragma omp parallel for private(tls) 
  396      for (
auto xx = lowerBoundX; xx < upperBoundX; ++xx)
 
  399         tls.init(waveTrackCache, scratchSize);
 
  400         SampleTrackCache& cache = *tls.cache;
 
  401         float* buffer = &tls.scratch[0];
 
  403         float* buffer = &scratch[0];
 
  406            settings, clip, xx, pixelsPerSecond, lowerBoundX, upperBoundX,
 
  407            gainFactors, buffer, &
freq[0]);
 
  414         auto xx = lowerBoundX;
 
  415         const double pixelsPerSample =
 
  417         const int limit = 
std::min((
int)(0.5 + fftLen * pixelsPerSample), 100);
 
  418         for (
int ii = 0; ii < limit; ++ii)
 
  421               settings, clip, --xx, pixelsPerSecond, lowerBoundX, upperBoundX,
 
  422               gainFactors, &scratch[0], &
freq[0]);
 
  428         for (
int ii = 0; ii < limit; ++ii)
 
  431               settings, clip, xx++, pixelsPerSecond, lowerBoundX, upperBoundX,
 
  432               gainFactors, &scratch[0], &
freq[0]);
 
  440         #pragma omp parallel for 
  442         for (xx = lowerBoundX; xx < upperBoundX; ++xx) {
 
  443            float *
const results = &
freq[nBins * xx];
 
  444            for (
size_t ii = 0; ii < nBins; ++ii) {
 
  445               float &
power = results[ii];
 
  451            if (!gainFactors.empty()) {
 
  453               for (
size_t ii = 0; ii < nBins; ++ii)
 
  454                  results[ii] += gainFactors[ii];
 
  464   const sampleCount*& where, 
size_t numPixels, 
double t0,
 
  465   double pixelsPerSecond)
 
  472   const auto samplesPerPixel = 
sampleRate / pixelsPerSecond / stretchRatio;
 
  476   bool match = mSpecCache && mSpecCache->leftTrim == clip.
GetTrimLeft() &&
 
  478                mSpecCache->len > 0 &&
 
  481   if (match && mSpecCache->start == t0 && mSpecCache->len >= numPixels)
 
  483      spectrogram = &mSpecCache->freq[0];
 
  484      where = &mSpecCache->where[0];
 
  498   if (mSpecCache->freq.capacity() > 2.1 * mSpecCache->freq.size() ||
 
  499       mSpecCache->windowSize*mSpecCache->zeroPaddingFactor <
 
  503      mSpecCache = std::make_unique<SpecCache>();
 
  507   double correction = 0.0;
 
  509   int copyBegin = 0, copyEnd = 0;
 
  512         mSpecCache->where, mSpecCache->len, numPixels, t0, 
sampleRate,
 
  513         stretchRatio, samplesPerPixel, oldX0, correction);
 
  517      copyBegin = 
std::min((
int)numPixels, std::max(0, -oldX0));
 
  518      copyEnd = 
std::min((
int)numPixels, std::max(0,
 
  519         (
int)mSpecCache->len - oldX0
 
  524   mSpecCache->Grow(numPixels, 
settings, samplesPerPixel, t0);
 
  532   if (copyEnd > copyBegin)
 
  535      memmove(&mSpecCache->freq[nBins * copyBegin],
 
  536               &mSpecCache->freq[nBins * (copyBegin + oldX0)],
 
  537               nBins * (copyEnd - copyBegin) * 
sizeof(
float));
 
  548         (copyBegin >= 0 && copyEnd == (
int)numPixels) || 
 
  549         (copyBegin == 0 && copyEnd <= (
int)numPixels)    
 
  552      int zeroBegin = copyBegin > 0 ? 0 : copyEnd-copyBegin;
 
  553      int zeroEnd = copyBegin > 0 ? copyBegin : numPixels;
 
  555      memset(&mSpecCache->freq[nBins*zeroBegin], 0, nBins*(zeroEnd-zeroBegin)*
sizeof(
float));
 
  560   constexpr auto addBias = 
true;
 
  562      mSpecCache->where, numPixels, addBias, correction, t0, 
sampleRate,
 
  563      stretchRatio, samplesPerPixel);
 
  565   mSpecCache->Populate(
 
  566      settings, clip, copyBegin, copyEnd, numPixels, pixelsPerSecond);
 
  568   mSpecCache->dirty = 
mDirty;
 
  569   spectrogram = &mSpecCache->freq[0];
 
  570   where = &mSpecCache->where[0];
 
  576   : mSpecCaches(nChannels)
 
  577   , mSpecPxCaches(nChannels)
 
  580      pCache = std::make_unique<SpecCache>();
 
  590   return std::make_unique<WaveClipSpectrumCache>(
mSpecCaches.size());
 
  594   return std::make_unique<WaveClipSpectrumCache>(clip.NChannels());
 
  601      .Attachments::Get< WaveClipSpectrumCache >( 
sKeyS );
 
  613      pCache = std::make_unique<SpecCache>();
 
  620   mSpecCaches.push_back(move(pOther->mSpecCaches[0]));
 
void RealFFTf(fft_type *buffer, const FFTParam *h)
bool ComputeSpectrum(const float *data, size_t width, size_t windowSize, float *output, bool autocorrelation, int windowFunc)
static WaveClip::Attachments::RegisteredFactory sKeyS
static Settings & settings()
sampleCount GetNumSamples() const
unsigned zeroPaddingFactor
void Grow(size_t len_, SpectrogramSettings &settings, double samplesPerPixel, double start)
void Populate(const SpectrogramSettings &settings, const WaveChannelInterval &clip, int copyBegin, int copyEnd, size_t numPixels, double pixelsPerSecond)
bool Matches(int dirty_, double samplesPerPixel, const SpectrogramSettings &settings) const
std::vector< float > freq
bool CalculateOneSpectrum(const SpectrogramSettings &settings, const WaveChannelInterval &clip, const int xx, double pixelsPerSecond, int lowerBoundX, int upperBoundX, const std::vector< float > &gainFactors, float *__restrict scratch, float *__restrict out) const
std::vector< sampleCount > where
std::optional< AudioSegmentSampleView > mSampleCacheHolder
Spectrogram settings, either for one track or as defaults.
size_t GetChannelIndex() const
double GetTrimRight() const
int GetRate() const override
double GetTrimLeft() const
const Sequence & GetSequence() const
double GetStretchRatio() const override
AudioSegmentSampleView GetSampleView(double t0, double t1, bool mayThrow) const
Request interval samples within [t0, t1). t0 and t1 are truncated to the interval start and end....
This allows multiple clips to be a part of one WaveTrack.
Positions or offsets within audio files need a wide type.
long long as_long_long() const
AUDACITY_DLL_API void fillWhere(std::vector< sampleCount > &where, size_t len, bool addBias, double correction, double t0, double sampleRate, double stretchRatio, double samplesPerPixel)
AUDACITY_DLL_API void findCorrection(const std::vector< sampleCount > &oldWhere, size_t oldLen, size_t newLen, double t0, double sampleRate, double stretchRatio, double samplesPerPixel, int &oldX0, double &correction)
constexpr auto sampleRate
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
void ComputeSpectrogramGainFactors(size_t fftLen, double rate, int frequencyGain, std::vector< float > &gainFactors)
static void ComputeSpectrumUsingRealFFTf(float *__restrict buffer, const FFTParam *hFFT, const float *__restrict window, size_t len, float *__restrict out)
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept
void copy(const T *src, T *dst, int32_t n)
ArrayOf< int > BitReversed
void MakeStereo(WaveClipListener &&other, bool aligned) override
std::vector< std::unique_ptr< SpecPxCache > > mSpecPxCaches
void SwapChannels() override
Default implementation does nothing.
bool GetSpectrogram(const WaveChannelInterval &clip, const float *&spectrogram, SpectrogramSettings &spectrogramSettings, const sampleCount *&where, size_t numPixels, double t0, double pixelsPerSecond)
static WaveClipSpectrumCache & Get(const WaveChannelInterval &clip)
~WaveClipSpectrumCache() override
std::unique_ptr< WaveClipListener > Clone() const override
void MarkChanged() noexcept override
void Erase(size_t index) override
WaveClipSpectrumCache(size_t nChannels)
void Invalidate() override
std::vector< std::unique_ptr< SpecCache > > mSpecCaches