mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 08:09:32 +02:00
Keep FFT windows for Spectrograms in one place in SpectrogramSettings...
... not redundantly in each WaveClip.
This commit is contained in:
parent
952a22c8b1
commit
afa2fe9fb4
@ -2,15 +2,15 @@
|
|||||||
#define __realfftf_h
|
#define __realfftf_h
|
||||||
|
|
||||||
#define fft_type float
|
#define fft_type float
|
||||||
typedef struct FFTParamType {
|
struct FFTParam {
|
||||||
int *BitReversed;
|
int *BitReversed;
|
||||||
fft_type *SinTable;
|
fft_type *SinTable;
|
||||||
int Points;
|
int Points;
|
||||||
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
||||||
int pow2Bits;
|
int pow2Bits;
|
||||||
#endif
|
#endif
|
||||||
} FFTParam;
|
};
|
||||||
#define HFFT FFTParam *
|
typedef FFTParam * HFFT;
|
||||||
|
|
||||||
HFFT InitializeFFT(int);
|
HFFT InitializeFFT(int);
|
||||||
void EndFFT(HFFT);
|
void EndFFT(HFFT);
|
||||||
|
108
src/WaveClip.cpp
108
src/WaveClip.cpp
@ -336,7 +336,7 @@ public:
|
|||||||
|
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
#include "FFT.h"
|
#include "FFT.h"
|
||||||
static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, float *window, int len, float *out)
|
static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, const float *window, int len, float *out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if(len > hFFT->Points*2)
|
if(len > hFFT->Points*2)
|
||||||
@ -371,13 +371,6 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate)
|
|||||||
mSequence = new Sequence(projDirManager, format);
|
mSequence = new Sequence(projDirManager, format);
|
||||||
mEnvelope = new Envelope();
|
mEnvelope = new Envelope();
|
||||||
mWaveCache = new WaveCache(0);
|
mWaveCache = new WaveCache(0);
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
|
||||||
mWindowType = -1;
|
|
||||||
mWindowSize = -1;
|
|
||||||
hFFT = NULL;
|
|
||||||
mWindow = NULL;
|
|
||||||
#endif
|
|
||||||
mZeroPaddingFactor = 1;
|
|
||||||
mSpecCache = new SpecCache();
|
mSpecCache = new SpecCache();
|
||||||
mSpecPxCache = new SpecPxCache(1);
|
mSpecPxCache = new SpecPxCache(1);
|
||||||
mAppendBuffer = NULL;
|
mAppendBuffer = NULL;
|
||||||
@ -400,13 +393,6 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager)
|
|||||||
mEnvelope->SetOffset(orig.GetOffset());
|
mEnvelope->SetOffset(orig.GetOffset());
|
||||||
mEnvelope->SetTrackLen(((double)orig.mSequence->GetNumSamples()) / orig.mRate);
|
mEnvelope->SetTrackLen(((double)orig.mSequence->GetNumSamples()) / orig.mRate);
|
||||||
mWaveCache = new WaveCache(0);
|
mWaveCache = new WaveCache(0);
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
|
||||||
mWindowType = -1;
|
|
||||||
mWindowSize = -1;
|
|
||||||
hFFT = NULL;
|
|
||||||
mWindow = NULL;
|
|
||||||
#endif
|
|
||||||
mZeroPaddingFactor = 1;
|
|
||||||
mSpecCache = new SpecCache();
|
mSpecCache = new SpecCache();
|
||||||
mSpecPxCache = new SpecPxCache(1);
|
mSpecPxCache = new SpecPxCache(1);
|
||||||
|
|
||||||
@ -429,12 +415,6 @@ WaveClip::~WaveClip()
|
|||||||
delete mWaveCache;
|
delete mWaveCache;
|
||||||
delete mSpecCache;
|
delete mSpecCache;
|
||||||
delete mSpecPxCache;
|
delete mSpecPxCache;
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
|
||||||
if(hFFT != NULL)
|
|
||||||
EndFFT(hFFT);
|
|
||||||
if(mWindow != NULL)
|
|
||||||
delete[] mWindow;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mAppendBuffer)
|
if (mAppendBuffer)
|
||||||
DeleteSamples(mAppendBuffer);
|
DeleteSamples(mAppendBuffer);
|
||||||
@ -820,67 +800,6 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
enum { WINDOW, TWINDOW, DWINDOW };
|
|
||||||
void RecreateWindow(
|
|
||||||
float *&window, int which, int fftLen,
|
|
||||||
int padding, int windowType, int windowSize, double &scale)
|
|
||||||
{
|
|
||||||
if (window != NULL)
|
|
||||||
delete[] window;
|
|
||||||
// Create the requested window function
|
|
||||||
window = new float[fftLen];
|
|
||||||
int ii;
|
|
||||||
|
|
||||||
wxASSERT(windowSize % 2 == 0);
|
|
||||||
const int endOfWindow = padding + windowSize;
|
|
||||||
// Left and right padding
|
|
||||||
for (ii = 0; ii < padding; ++ii) {
|
|
||||||
window[ii] = 0.0;
|
|
||||||
window[fftLen - ii - 1] = 0.0;
|
|
||||||
}
|
|
||||||
// Default rectangular window in the middle
|
|
||||||
for (; ii < endOfWindow; ++ii)
|
|
||||||
window[ii] = 1.0;
|
|
||||||
// Overwrite middle as needed
|
|
||||||
switch (which) {
|
|
||||||
case WINDOW:
|
|
||||||
WindowFunc(windowType, windowSize, window + padding);
|
|
||||||
// NewWindowFunc(windowType, windowSize, extra, window + padding);
|
|
||||||
break;
|
|
||||||
case TWINDOW:
|
|
||||||
wxASSERT(false);
|
|
||||||
#if 0
|
|
||||||
// Future, reassignment
|
|
||||||
NewWindowFunc(windowType, windowSize, extra, window + padding);
|
|
||||||
for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier)
|
|
||||||
window[ii] *= multiplier;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case DWINDOW:
|
|
||||||
wxASSERT(false);
|
|
||||||
#if 0
|
|
||||||
// Future, reassignment
|
|
||||||
DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
wxASSERT(false);
|
|
||||||
}
|
|
||||||
// Scale the window function to give 0dB spectrum for 0dB sine tone
|
|
||||||
if (which == WINDOW) {
|
|
||||||
scale = 0.0;
|
|
||||||
for (ii = padding; ii < endOfWindow; ++ii)
|
|
||||||
scale += window[ii];
|
|
||||||
if (scale > 0)
|
|
||||||
scale = 2.0 / scale;
|
|
||||||
}
|
|
||||||
for (ii = padding; ii < endOfWindow; ++ii)
|
|
||||||
window[ii] *= scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaveClip::ComputeSpectrogramGainFactors(int fftLen, int frequencyGain, std::vector<float> &gainFactors)
|
void WaveClip::ComputeSpectrogramGainFactors(int fftLen, int frequencyGain, std::vector<float> &gainFactors)
|
||||||
{
|
{
|
||||||
if (frequencyGain > 0) {
|
if (frequencyGain > 0) {
|
||||||
@ -921,6 +840,11 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
#else
|
#else
|
||||||
const int zeroPaddingFactor = 1;
|
const int zeroPaddingFactor = 1;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
|
settings.CacheWindows();
|
||||||
|
const HFFT &hFFT = settings.hFFT;
|
||||||
|
const float *const &window = settings.window;
|
||||||
|
#endif
|
||||||
|
|
||||||
// FFT length may be longer than the window of samples that affect results
|
// FFT length may be longer than the window of samples that affect results
|
||||||
// because of zero padding done for increased frequency resolution
|
// because of zero padding done for increased frequency resolution
|
||||||
@ -928,24 +852,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
const int half = fftLen / 2;
|
const int half = fftLen / 2;
|
||||||
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
|
||||||
// Update the FFT and window if necessary
|
|
||||||
if((mWindowType != windowType) || (mWindowSize != windowSize)
|
|
||||||
|| (hFFT == NULL) || (mWindow == NULL) || (fftLen != hFFT->Points * 2)
|
|
||||||
|| (mZeroPaddingFactor != zeroPaddingFactor)) {
|
|
||||||
mWindowType = windowType;
|
|
||||||
mWindowSize = windowSize;
|
|
||||||
if(hFFT != NULL)
|
|
||||||
EndFFT(hFFT);
|
|
||||||
hFFT = InitializeFFT(fftLen);
|
|
||||||
double scale;
|
|
||||||
RecreateWindow(mWindow, WINDOW, fftLen, padding, mWindowType, mWindowSize, scale);
|
|
||||||
}
|
|
||||||
#endif // EXPERIMENTAL_USE_REALFFTF
|
|
||||||
|
|
||||||
|
|
||||||
mZeroPaddingFactor = zeroPaddingFactor;
|
|
||||||
|
|
||||||
const bool match =
|
const bool match =
|
||||||
mSpecCache &&
|
mSpecCache &&
|
||||||
mSpecCache->dirty == mDirty &&
|
mSpecCache->dirty == mDirty &&
|
||||||
@ -1119,7 +1025,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
mRate, &mSpecCache->freq[half * x],
|
mRate, &mSpecCache->freq[half * x],
|
||||||
autocorrelation, windowType);
|
autocorrelation, windowType);
|
||||||
} else {
|
} else {
|
||||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, fftLen, &mSpecCache->freq[half * x]);
|
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, window, fftLen, &mSpecCache->freq[half * x]);
|
||||||
}
|
}
|
||||||
#else // EXPERIMENTAL_USE_REALFFTF
|
#else // EXPERIMENTAL_USE_REALFFTF
|
||||||
ComputeSpectrum(buffer, windowSize, windowSize,
|
ComputeSpectrum(buffer, windowSize, windowSize,
|
||||||
|
@ -307,14 +307,6 @@ protected:
|
|||||||
WaveCache *mWaveCache;
|
WaveCache *mWaveCache;
|
||||||
ODLock mWaveCacheMutex;
|
ODLock mWaveCacheMutex;
|
||||||
SpecCache *mSpecCache;
|
SpecCache *mSpecCache;
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
|
||||||
// Variables used for computing the spectrum
|
|
||||||
HFFT hFFT;
|
|
||||||
float *mWindow;
|
|
||||||
int mWindowType;
|
|
||||||
int mWindowSize;
|
|
||||||
#endif
|
|
||||||
int mZeroPaddingFactor;
|
|
||||||
samplePtr mAppendBuffer;
|
samplePtr mAppendBuffer;
|
||||||
sampleCount mAppendBufferLen;
|
sampleCount mAppendBufferLen;
|
||||||
|
|
||||||
|
@ -370,6 +370,8 @@ BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
|
|||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
SpectrogramSettings::SpectrogramSettings()
|
SpectrogramSettings::SpectrogramSettings()
|
||||||
|
: hFFT(0)
|
||||||
|
, window(0)
|
||||||
{
|
{
|
||||||
UpdatePrefs();
|
UpdatePrefs();
|
||||||
}
|
}
|
||||||
@ -382,6 +384,8 @@ SpectrogramSettings& SpectrogramSettings::defaults()
|
|||||||
|
|
||||||
void SpectrogramSettings::UpdatePrefs()
|
void SpectrogramSettings::UpdatePrefs()
|
||||||
{
|
{
|
||||||
|
bool destroy = false;
|
||||||
|
|
||||||
minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L);
|
minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L);
|
||||||
maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
|
maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
|
||||||
|
|
||||||
@ -401,13 +405,26 @@ void SpectrogramSettings::UpdatePrefs()
|
|||||||
gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
|
gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
|
||||||
frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
|
frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
|
||||||
|
|
||||||
windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
const int newWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||||
|
if (newWindowSize != windowSize) {
|
||||||
|
destroy = true;
|
||||||
|
windowSize = newWindowSize;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
zeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
const int newZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
||||||
|
if (newZeroPaddingFactor != zeroPaddingFactor) {
|
||||||
|
destroy = true;
|
||||||
|
zeroPaddingFactor = newZeroPaddingFactor;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
int newWindowType;
|
||||||
|
gPrefs->Read(wxT("/Spectrum/WindowType"), &newWindowType, 3);
|
||||||
|
if (newWindowType != windowType) {
|
||||||
|
destroy = true;
|
||||||
|
windowType = newWindowType;
|
||||||
|
}
|
||||||
|
|
||||||
isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
||||||
|
|
||||||
@ -425,4 +442,105 @@ void SpectrogramSettings::UpdatePrefs()
|
|||||||
numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
|
numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
|
||||||
findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
|
findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
|
||||||
#endif //EXPERIMENTAL_FIND_NOTES
|
#endif //EXPERIMENTAL_FIND_NOTES
|
||||||
|
|
||||||
|
if (destroy)
|
||||||
|
DestroyWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
SpectrogramSettings::~SpectrogramSettings()
|
||||||
|
{
|
||||||
|
DestroyWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpectrogramSettings::DestroyWindows()
|
||||||
|
{
|
||||||
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
|
if (hFFT != NULL) {
|
||||||
|
EndFFT(hFFT);
|
||||||
|
hFFT = NULL;
|
||||||
|
}
|
||||||
|
if (window != NULL) {
|
||||||
|
delete[] window;
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum { WINDOW, TWINDOW, DWINDOW };
|
||||||
|
void RecreateWindow(
|
||||||
|
float *&window, int which, int fftLen,
|
||||||
|
int padding, int windowType, int windowSize, double &scale)
|
||||||
|
{
|
||||||
|
if (window != NULL)
|
||||||
|
delete[] window;
|
||||||
|
// Create the requested window function
|
||||||
|
window = new float[fftLen];
|
||||||
|
int ii;
|
||||||
|
|
||||||
|
wxASSERT(windowSize % 2 == 0);
|
||||||
|
const int endOfWindow = padding + windowSize;
|
||||||
|
// Left and right padding
|
||||||
|
for (ii = 0; ii < padding; ++ii) {
|
||||||
|
window[ii] = 0.0;
|
||||||
|
window[fftLen - ii - 1] = 0.0;
|
||||||
|
}
|
||||||
|
// Default rectangular window in the middle
|
||||||
|
for (; ii < endOfWindow; ++ii)
|
||||||
|
window[ii] = 1.0;
|
||||||
|
// Overwrite middle as needed
|
||||||
|
switch (which) {
|
||||||
|
case WINDOW:
|
||||||
|
WindowFunc(windowType, windowSize, window + padding);
|
||||||
|
// NewWindowFunc(windowType, windowSize, extra, window + padding);
|
||||||
|
break;
|
||||||
|
case TWINDOW:
|
||||||
|
wxASSERT(false);
|
||||||
|
#if 0
|
||||||
|
// Future, reassignment
|
||||||
|
NewWindowFunc(windowType, windowSize, extra, window + padding);
|
||||||
|
for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier)
|
||||||
|
window[ii] *= multiplier;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case DWINDOW:
|
||||||
|
wxASSERT(false);
|
||||||
|
#if 0
|
||||||
|
// Future, reassignment
|
||||||
|
DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
wxASSERT(false);
|
||||||
|
}
|
||||||
|
// Scale the window function to give 0dB spectrum for 0dB sine tone
|
||||||
|
if (which == WINDOW) {
|
||||||
|
scale = 0.0;
|
||||||
|
for (ii = padding; ii < endOfWindow; ++ii)
|
||||||
|
scale += window[ii];
|
||||||
|
if (scale > 0)
|
||||||
|
scale = 2.0 / scale;
|
||||||
|
}
|
||||||
|
for (ii = padding; ii < endOfWindow; ++ii)
|
||||||
|
window[ii] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpectrogramSettings::CacheWindows() const
|
||||||
|
{
|
||||||
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
|
if (hFFT == NULL || window == NULL) {
|
||||||
|
|
||||||
|
double scale;
|
||||||
|
const int fftLen = windowSize * zeroPaddingFactor;
|
||||||
|
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||||
|
|
||||||
|
if (hFFT != NULL)
|
||||||
|
EndFFT(hFFT);
|
||||||
|
hFFT = InitializeFFT(fftLen);
|
||||||
|
RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale);
|
||||||
|
}
|
||||||
|
#endif // EXPERIMENTAL_USE_REALFFTF
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "PrefsPanel.h"
|
#include "PrefsPanel.h"
|
||||||
|
|
||||||
|
struct FFTParam;
|
||||||
|
|
||||||
class SpectrumPrefs:public PrefsPanel
|
class SpectrumPrefs:public PrefsPanel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -76,8 +78,11 @@ struct SpectrogramSettings
|
|||||||
{
|
{
|
||||||
static SpectrogramSettings &defaults();
|
static SpectrogramSettings &defaults();
|
||||||
SpectrogramSettings();
|
SpectrogramSettings();
|
||||||
|
~SpectrogramSettings();
|
||||||
|
|
||||||
void UpdatePrefs();
|
void UpdatePrefs();
|
||||||
|
void DestroyWindows();
|
||||||
|
void CacheWindows() const;
|
||||||
|
|
||||||
int minFreq;
|
int minFreq;
|
||||||
int maxFreq;
|
int maxFreq;
|
||||||
@ -111,6 +116,14 @@ struct SpectrogramSettings
|
|||||||
bool numberOfMaxima;
|
bool numberOfMaxima;
|
||||||
bool findNotesQuantize;
|
bool findNotesQuantize;
|
||||||
#endif //EXPERIMENTAL_FIND_NOTES
|
#endif //EXPERIMENTAL_FIND_NOTES
|
||||||
|
|
||||||
|
// Following fields are derived from preferences.
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
|
// Variables used for computing the spectrum
|
||||||
|
mutable FFTParam *hFFT;
|
||||||
|
mutable float *window;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user