From 84ee685ee9c3ac07641d7d2ebc79568464300bce Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 4 Jun 2015 12:55:47 -0400 Subject: [PATCH] reassignment, internals, implementing time correction, but -- ... ... it does not yet interact correctly with caching, so results may be slightly wrong if you scroll the view by less than a screen. --- src/TrackArtist.cpp | 4 +- src/WaveClip.cpp | 84 ++++++++++++++++++++----------- src/WaveClip.h | 5 +- src/prefs/SpectrogramSettings.cpp | 11 ++-- src/prefs/SpectrogramSettings.h | 2 - 5 files changed, 65 insertions(+), 41 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 802f066a3..e8fb61653 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -2375,7 +2375,9 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache, (settings, waveTrackCache, 0, 0, numPixels, clip->GetNumSamples(), - tOffset, rate); + tOffset, rate, + 0 //FIXME -- make reassignment work with fisheye + ); } int correctedX = leftOffset - hiddenLeftOffset; diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index 59ddf03ff..9f6891488 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -788,7 +788,8 @@ void SpecCache::CalculateOneSpectrum (const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int xx, sampleCount numSamples, - double offset, double rate, + double offset, double rate, double pixelsPerSecond, + int lowerBoundX, int upperBoundX, const std::vector &gainFactors, float *scratch) { @@ -864,6 +865,9 @@ void SpecCache::CalculateOneSpectrum float *const scratch2 = scratch + fftLen; std::copy(scratch, scratch2, scratch2); + float *const scratch3 = scratch + 2 * fftLen; + std::copy(scratch, scratch2, scratch3); + { const float *const window = settings.window; for (int ii = 0; ii < fftLen; ++ii) @@ -878,7 +882,13 @@ void SpecCache::CalculateOneSpectrum RealFFTf(scratch2, hFFT); } - const double multiplier = -fftLen / (2.0f * M_PI); + { + const float *const tWindow = settings.tWindow; + for (int ii = 0; ii < fftLen; ++ii) + scratch3[ii] *= tWindow[ii]; + RealFFTf(scratch3, hFFT); + } + for (int ii = 0; ii < hFFT->Points; ++ii) { const int index = hFFT->BitReversed[ii]; const float @@ -889,30 +899,41 @@ void SpecCache::CalculateOneSpectrum // Avoid dividing by near-zero below continue; - const float - numRe = scratch2[index], - numIm = ii == 0 ? 0 : scratch2[index + 1]; - // Find complex quotient -- - // Which means, multiply numerator by conjugate of denominator, - // then divide by norm squared of denominator -- - // Then just take its imaginary part. - const double - quotIm = (-numRe * denomIm + numIm * denomRe) / power; - // With appropriate multiplier, that becomes the correction of - // the frequency bin. - const double correction = multiplier * quotIm; - const int bin = int(ii + correction + 0.5f); - if (bin >= 0 && bin < hFFT->Points) - freq[half * xx + bin] += power; - } + double freqCorrection; + { + const double multiplier = -fftLen / (2.0f * M_PI); + const float + numRe = scratch2[index], + numIm = ii == 0 ? 0 : scratch2[index + 1]; + // Find complex quotient -- + // Which means, multiply numerator by conjugate of denominator, + // then divide by norm squared of denominator -- + // Then just take its imaginary part. + const double + quotIm = (-numRe * denomIm + numIm * denomRe) / power; + // With appropriate multiplier, that becomes the correction of + // the frequency bin. + freqCorrection = multiplier * quotIm; + } - // Now Convert to dB terms - for (int ii = 0; ii < hFFT->Points; ++ii) { - float &power = freq[half * xx + ii]; - if (power <= 0) - power = -160.0; - else - power = 10.0*log10f(power); + const int bin = int(ii + freqCorrection + 0.5f); + if (bin >= 0 && bin < hFFT->Points) { + double timeCorrection; + { + const float + numRe = scratch3[index], + numIm = ii == 0 ? 0 : scratch3[index + 1]; + // Find another complex quotient -- + // Then just take its real part. + // The result has sample interval as unit. + timeCorrection = + (numRe * denomRe + numIm * denomIm) / power; + } + + int correctedX = (floor(0.5 + xx + timeCorrection * pixelsPerSecond / rate)); + if (correctedX >= lowerBoundX && correctedX < upperBoundX) + freq[half * correctedX + bin] += power; + } } } else { @@ -945,7 +966,7 @@ void SpecCache::Populate (const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int copyBegin, int copyEnd, int numPixels, sampleCount numSamples, - double offset, double rate) + double offset, double rate, double pixelsPerSecond) { #ifdef EXPERIMENTAL_USE_REALFFTF settings.CacheWindows(); @@ -970,7 +991,7 @@ void SpecCache::Populate const size_t bufferSize = fftLen; - std::vector buffer(reassignment ? 2 * bufferSize : bufferSize); + std::vector buffer(reassignment ? 3 * bufferSize : bufferSize); std::vector gainFactors; if (!autocorrelation) @@ -983,8 +1004,10 @@ void SpecCache::Populate const int upperBoundX = jj == 0 ? copyBegin : numPixels; for (sampleCount xx = lowerBoundX; xx < upperBoundX; ++xx) CalculateOneSpectrum( - settings, waveTrackCache, xx, numSamples, - offset, rate, gainFactors, &buffer[0]); + settings, waveTrackCache, xx, numSamples, + offset, rate, pixelsPerSecond, + lowerBoundX, upperBoundX, + gainFactors, &buffer[0]); if (reassignment) { // Now Convert to dB terms. Do this only after accumulating @@ -1092,7 +1115,8 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache, mSpecCache->Populate (settings, waveTrackCache, copyBegin, copyEnd, numPixels, - mSequence->GetNumSamples(), mOffset, mRate); + mSequence->GetNumSamples(), + mOffset, mRate, pixelsPerSecond); mSpecCache->dirty = mDirty; spectrogram = &mSpecCache->freq[0]; diff --git a/src/WaveClip.h b/src/WaveClip.h index 09de9c8f0..9995b0f62 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -96,7 +96,8 @@ public: (const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int xx, sampleCount numSamples, - double offset, double rate, + double offset, double rate, double pixelsPerSecond, + int lowerBoundX, int upperBoundX, const std::vector &gainFactors, float *scratch); @@ -104,7 +105,7 @@ public: (const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int copyBegin, int copyEnd, int numPixels, sampleCount numSamples, - double offset, double rate); + double offset, double rate, double pixelsPerSecond); const int len; // counts pixels, not samples const int algorithm; diff --git a/src/prefs/SpectrogramSettings.cpp b/src/prefs/SpectrogramSettings.cpp index 805ab5270..ef0b6227d 100644 --- a/src/prefs/SpectrogramSettings.cpp +++ b/src/prefs/SpectrogramSettings.cpp @@ -57,6 +57,7 @@ SpectrogramSettings::SpectrogramSettings() : hFFT(0) , window(0) , dWindow(0) + , tWindow(0) { LoadPrefs(); } @@ -93,9 +94,7 @@ SpectrogramSettings::SpectrogramSettings(const SpectrogramSettings &other) // Do not copy these! , hFFT(0) , window(0) -#if 0 , tWindow(0) -#endif , dWindow(0) { } @@ -397,6 +396,10 @@ void SpectrogramSettings::DestroyWindows() delete[] dWindow; dWindow = NULL; } + if (tWindow != NULL) { + delete[] tWindow; + tWindow = NULL; + } #endif } @@ -433,14 +436,12 @@ namespace case WINDOW: NewWindowFunc(windowType, windowSize, extra, window + padding); break; -#if 0 // Future, reassignment case TWINDOW: NewWindowFunc(windowType, windowSize, extra, window + padding); for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier) window[ii] *= multiplier; break; -#endif case DWINDOW: DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding); break; @@ -474,9 +475,7 @@ void SpectrogramSettings::CacheWindows() const hFFT = InitializeFFT(fftLen); RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale); if (algorithm == algReassignment) { -#if 0 RecreateWindow(tWindow, TWINDOW, fftLen, padding, windowType, windowSize, scale); -#endif RecreateWindow(dWindow, DWINDOW, fftLen, padding, windowType, windowSize, scale); } } diff --git a/src/prefs/SpectrogramSettings.h b/src/prefs/SpectrogramSettings.h index ddddbe636..5077a188f 100644 --- a/src/prefs/SpectrogramSettings.h +++ b/src/prefs/SpectrogramSettings.h @@ -156,9 +156,7 @@ public: mutable float *window; // Two other windows for computing reassigned spectrogram -#if 0 mutable float *tWindow; // Window times time parameter -#endif mutable float *dWindow; // Derivative of window #endif