mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-10 17:11:17 +02:00
Zero-padded spectrograms preference.
A new drop-down in Spectrogram preferences. The choice of padding factor is lmited so that the product of it and window size is not more than the mximum allowed window size (32767). When you choose more than 1, zero-padding before fft results in interpolation in the frequency domain. You do not get the finer frequency resolution of a longer window, but you do get a smoothing of the spectrogram, with more and narrower bands of colors.
This commit is contained in:
commit
1410081345
@ -198,5 +198,10 @@
|
|||||||
#undef EXPERIMENTAL_CRASH_REPORT
|
#undef EXPERIMENTAL_CRASH_REPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Paul Licameli (PRL) 31 May 2015
|
||||||
|
// Zero-padding factor for spectrograms can smooth the display of spectrograms by
|
||||||
|
// interpolating in frequency domain.
|
||||||
|
#define EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1803,6 +1803,7 @@ static float sumFreqValues(
|
|||||||
|
|
||||||
// Helper function to decide on which color set to use.
|
// Helper function to decide on which color set to use.
|
||||||
// dashCount counts both dashes and the spaces between them.
|
// dashCount counts both dashes and the spaces between them.
|
||||||
|
inline
|
||||||
AColor::ColorGradientChoice ChooseColorSet( float bin0, float bin1, float selBinLo,
|
AColor::ColorGradientChoice ChooseColorSet( float bin0, float bin1, float selBinLo,
|
||||||
float selBinCenter, float selBinHi, int dashCount, bool isSpectral )
|
float selBinCenter, float selBinHi, int dashCount, bool isSpectral )
|
||||||
{
|
{
|
||||||
@ -1959,8 +1960,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
|||||||
if (!image)return;
|
if (!image)return;
|
||||||
unsigned char *data = image->GetData();
|
unsigned char *data = image->GetData();
|
||||||
|
|
||||||
int windowSize = GetSpectrumWindowSize();
|
int windowSize = GetSpectrumWindowSize(!autocorrelation);
|
||||||
int half = windowSize/2;
|
const int half = windowSize / 2;
|
||||||
float *freq = new float[mid.width * half];
|
float *freq = new float[mid.width * half];
|
||||||
sampleCount *where = new sampleCount[mid.width+1];
|
sampleCount *where = new sampleCount[mid.width+1];
|
||||||
|
|
||||||
@ -2106,7 +2107,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
|||||||
|
|
||||||
AColor::ColorGradientChoice selected =
|
AColor::ColorGradientChoice selected =
|
||||||
AColor::ColorGradientUnselected;
|
AColor::ColorGradientUnselected;
|
||||||
// If we are in the time selected range, then we may use a differnt color set.
|
// If we are in the time selected range, then we may use a different color set.
|
||||||
if (ssel0 <= w0 && w1 < ssel1)
|
if (ssel0 <= w0 && w1 < ssel1)
|
||||||
{
|
{
|
||||||
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
||||||
@ -2220,7 +2221,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
|||||||
|
|
||||||
AColor::ColorGradientChoice selected =
|
AColor::ColorGradientChoice selected =
|
||||||
AColor::ColorGradientUnselected;
|
AColor::ColorGradientUnselected;
|
||||||
// If we are in the time selected range, then we may use a differnt color set.
|
// If we are in the time selected range, then we may use a different color set.
|
||||||
if (ssel0 <= w0 && w1 < ssel1)
|
if (ssel0 <= w0 && w1 < ssel1)
|
||||||
{
|
{
|
||||||
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
||||||
@ -3029,6 +3030,9 @@ void TrackArtist::UpdatePrefs()
|
|||||||
mLogMinFreq = 1;
|
mLogMinFreq = 1;
|
||||||
|
|
||||||
mWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
mWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
mZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
||||||
|
#endif
|
||||||
mIsGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
mIsGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||||
@ -3070,9 +3074,14 @@ int TrackArtist::GetSpectrumLogMaxFreq(int deffreq)
|
|||||||
return mLogMaxFreq < 0 ? deffreq : mLogMaxFreq;
|
return mLogMaxFreq < 0 ? deffreq : mLogMaxFreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TrackArtist::GetSpectrumWindowSize()
|
int TrackArtist::GetSpectrumWindowSize(bool includeZeroPadding)
|
||||||
{
|
{
|
||||||
return mWindowSize;
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
if (includeZeroPadding)
|
||||||
|
return mWindowSize * mZeroPaddingFactor;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return mWindowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
|
@ -73,7 +73,7 @@ class AUDACITY_DLL_API TrackArtist {
|
|||||||
int GetSpectrumMaxFreq(int deffreq);
|
int GetSpectrumMaxFreq(int deffreq);
|
||||||
int GetSpectrumLogMinFreq(int deffreq);
|
int GetSpectrumLogMinFreq(int deffreq);
|
||||||
int GetSpectrumLogMaxFreq(int deffreq);
|
int GetSpectrumLogMaxFreq(int deffreq);
|
||||||
int GetSpectrumWindowSize();
|
int GetSpectrumWindowSize(bool includeZeroPadding);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
int GetSpectrumFftSkipPoints();
|
int GetSpectrumFftSkipPoints();
|
||||||
@ -184,6 +184,9 @@ class AUDACITY_DLL_API TrackArtist {
|
|||||||
int mMaxFreq; // "/Spectrum/MaxFreq"
|
int mMaxFreq; // "/Spectrum/MaxFreq"
|
||||||
int mMinFreq; // "/Spectrum/MinFreq"
|
int mMinFreq; // "/Spectrum/MinFreq"
|
||||||
int mWindowSize; // "/Spectrum/FFTSize"
|
int mWindowSize; // "/Spectrum/FFTSize"
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
int mZeroPaddingFactor; // "/Spectrum/ZeroPaddingFactor"
|
||||||
|
#endif
|
||||||
bool mIsGrayscale; // "/Spectrum/Grayscale"
|
bool mIsGrayscale; // "/Spectrum/Grayscale"
|
||||||
bool mbShowTrackNameInWaveform; // "/GUI/ShowTrackNameInWaveform"
|
bool mbShowTrackNameInWaveform; // "/GUI/ShowTrackNameInWaveform"
|
||||||
|
|
||||||
|
@ -2977,7 +2977,8 @@ inline double findMaxRatio(double center, double rate)
|
|||||||
|
|
||||||
void TrackPanel::SnapCenterOnce(WaveTrack *pTrack, bool up)
|
void TrackPanel::SnapCenterOnce(WaveTrack *pTrack, bool up)
|
||||||
{
|
{
|
||||||
const int windowSize = mTrackArtist->GetSpectrumWindowSize();
|
// Always spectrogram, never pitch view, pass true
|
||||||
|
const int windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||||
const double rate = pTrack->GetRate();
|
const double rate = pTrack->GetRate();
|
||||||
const double nyq = rate / 2.0;
|
const double nyq = rate / 2.0;
|
||||||
const double binFrequency = rate / windowSize;
|
const double binFrequency = rate / windowSize;
|
||||||
@ -3038,7 +3039,10 @@ void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
|
|||||||
|
|
||||||
// Use same settings as are now used for spectrogram display,
|
// Use same settings as are now used for spectrogram display,
|
||||||
// except, shrink the window as needed so we get some answers
|
// except, shrink the window as needed so we get some answers
|
||||||
int windowSize = mTrackArtist->GetSpectrumWindowSize();
|
|
||||||
|
// Always spectrogram, never pitch view, pass true
|
||||||
|
int windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||||
|
|
||||||
while(windowSize > effectiveLength)
|
while(windowSize > effectiveLength)
|
||||||
windowSize >>= 1;
|
windowSize >>= 1;
|
||||||
int windowType;
|
int windowType;
|
||||||
@ -4714,7 +4718,9 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
|||||||
max = mTrackArtist->GetSpectrumMaxFreq(8000);
|
max = mTrackArtist->GetSpectrumMaxFreq(8000);
|
||||||
if(max > rate/2.)
|
if(max > rate/2.)
|
||||||
max = rate/2.;
|
max = rate/2.;
|
||||||
windowSize = mTrackArtist->GetSpectrumWindowSize();
|
|
||||||
|
// Always spectrogram, never pitch view, pass true
|
||||||
|
windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
@ -4729,7 +4735,9 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
|||||||
max = mTrackArtist->GetSpectrumLogMaxFreq(lrint(rate/2.));
|
max = mTrackArtist->GetSpectrumLogMaxFreq(lrint(rate/2.));
|
||||||
if(max > rate/2.)
|
if(max > rate/2.)
|
||||||
max = rate/2.;
|
max = rate/2.;
|
||||||
windowSize = mTrackArtist->GetSpectrumWindowSize();
|
|
||||||
|
// Always spectrogram, never pitch view, pass true
|
||||||
|
windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
|
128
src/WaveClip.cpp
128
src/WaveClip.cpp
@ -226,6 +226,7 @@ public:
|
|||||||
rangeOld = -1;
|
rangeOld = -1;
|
||||||
windowTypeOld = -1;
|
windowTypeOld = -1;
|
||||||
windowSizeOld = -1;
|
windowSizeOld = -1;
|
||||||
|
zeroPaddingFactorOld = 1;
|
||||||
frequencyGainOld = false;
|
frequencyGainOld = false;
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
fftSkipPointsOld = -1;
|
fftSkipPointsOld = -1;
|
||||||
@ -252,6 +253,7 @@ public:
|
|||||||
int rangeOld;
|
int rangeOld;
|
||||||
int windowTypeOld;
|
int windowTypeOld;
|
||||||
int windowSizeOld;
|
int windowSizeOld;
|
||||||
|
int zeroPaddingFactorOld;
|
||||||
int frequencyGainOld;
|
int frequencyGainOld;
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
int fftSkipPointsOld;
|
int fftSkipPointsOld;
|
||||||
@ -284,8 +286,9 @@ static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, float *window
|
|||||||
else
|
else
|
||||||
out[0] = 10.0*log10(power);
|
out[0] = 10.0*log10(power);
|
||||||
for(i=1;i<hFFT->Points;i++) {
|
for(i=1;i<hFFT->Points;i++) {
|
||||||
power = (buffer[hFFT->BitReversed[i] ]*buffer[hFFT->BitReversed[i] ])
|
const int index = hFFT->BitReversed[i];
|
||||||
+ (buffer[hFFT->BitReversed[i]+1]*buffer[hFFT->BitReversed[i]+1]);
|
const float re = buffer[index], im = buffer[index + 1];
|
||||||
|
power = re * re + im * im;
|
||||||
if(power <= 0)
|
if(power <= 0)
|
||||||
out[i] = -160.0;
|
out[i] = -160.0;
|
||||||
else
|
else
|
||||||
@ -307,6 +310,7 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate)
|
|||||||
hFFT = NULL;
|
hFFT = NULL;
|
||||||
mWindow = NULL;
|
mWindow = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
mZeroPaddingFactor = 1;
|
||||||
mSpecCache = new SpecCache(0, 1, false);
|
mSpecCache = new SpecCache(0, 1, false);
|
||||||
mSpecPxCache = new SpecPxCache(1);
|
mSpecPxCache = new SpecPxCache(1);
|
||||||
mAppendBuffer = NULL;
|
mAppendBuffer = NULL;
|
||||||
@ -335,6 +339,7 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager)
|
|||||||
hFFT = NULL;
|
hFFT = NULL;
|
||||||
mWindow = NULL;
|
mWindow = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
mZeroPaddingFactor = 1;
|
||||||
mSpecCache = new SpecCache(0, 1, false);
|
mSpecCache = new SpecCache(0, 1, false);
|
||||||
mSpecPxCache = new SpecPxCache(1);
|
mSpecPxCache = new SpecPxCache(1);
|
||||||
|
|
||||||
@ -754,6 +759,67 @@ bool WaveClip::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||||
float *freq, sampleCount *where,
|
float *freq, sampleCount *where,
|
||||||
int numPixels,
|
int numPixels,
|
||||||
@ -771,37 +837,34 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||||
int fftSkipPoints1 = fftSkipPoints+1;
|
int fftSkipPoints1 = fftSkipPoints+1;
|
||||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
int half = windowSize/2;
|
const int zeroPaddingFactor =
|
||||||
|
autocorrelation ? 1 : gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
||||||
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
||||||
|
|
||||||
|
// FFT length may be longer than the window of samples that affect results
|
||||||
|
// because of zero padding done for increased frequency resolution
|
||||||
|
const int fftLen = windowSize * zeroPaddingFactor;
|
||||||
|
const int half = fftLen / 2;
|
||||||
|
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
// Update the FFT and window if necessary
|
// Update the FFT and window if necessary
|
||||||
if((mWindowType != windowType) || (mWindowSize != windowSize)
|
if((mWindowType != windowType) || (mWindowSize != windowSize)
|
||||||
|| (hFFT == NULL) || (mWindow == NULL) || (mWindowSize != hFFT->Points*2) ) {
|
|| (hFFT == NULL) || (mWindow == NULL) || (fftLen != hFFT->Points * 2)
|
||||||
|
|| (mZeroPaddingFactor != zeroPaddingFactor)) {
|
||||||
mWindowType = windowType;
|
mWindowType = windowType;
|
||||||
mWindowSize = windowSize;
|
mWindowSize = windowSize;
|
||||||
if(hFFT != NULL)
|
if(hFFT != NULL)
|
||||||
EndFFT(hFFT);
|
EndFFT(hFFT);
|
||||||
hFFT = InitializeFFT(mWindowSize);
|
hFFT = InitializeFFT(fftLen);
|
||||||
if(mWindow != NULL) delete[] mWindow;
|
double scale;
|
||||||
// Create the requested window function
|
RecreateWindow(mWindow, WINDOW, fftLen, padding, mWindowType, mWindowSize, scale);
|
||||||
mWindow = new float[mWindowSize];
|
|
||||||
int i;
|
|
||||||
for(i=0; i<windowSize; i++)
|
|
||||||
mWindow[i]=1.0;
|
|
||||||
WindowFunc(mWindowType, mWindowSize, mWindow);
|
|
||||||
// Scale the window function to give 0dB spectrum for 0dB sine tone
|
|
||||||
double ws=0;
|
|
||||||
for(i=0; i<windowSize; i++)
|
|
||||||
ws += mWindow[i];
|
|
||||||
if(ws > 0) {
|
|
||||||
ws = 2.0/ws;
|
|
||||||
for(i=0; i<windowSize; i++)
|
|
||||||
mWindow[i] *= ws;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // EXPERIMENTAL_USE_REALFFTF
|
#endif // EXPERIMENTAL_USE_REALFFTF
|
||||||
|
|
||||||
|
|
||||||
|
mZeroPaddingFactor = zeroPaddingFactor;
|
||||||
|
|
||||||
const bool match =
|
const bool match =
|
||||||
mSpecCache &&
|
mSpecCache &&
|
||||||
mSpecCache->dirty == mDirty &&
|
mSpecCache->dirty == mDirty &&
|
||||||
@ -811,6 +874,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
mSpecCache->gainOld == gain &&
|
mSpecCache->gainOld == gain &&
|
||||||
mSpecCache->windowTypeOld == windowType &&
|
mSpecCache->windowTypeOld == windowType &&
|
||||||
mSpecCache->windowSizeOld == windowSize &&
|
mSpecCache->windowSizeOld == windowSize &&
|
||||||
|
mSpecCache->zeroPaddingFactorOld == zeroPaddingFactor &&
|
||||||
mSpecCache->frequencyGainOld == frequencygain &&
|
mSpecCache->frequencyGainOld == frequencygain &&
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
mSpecCache->fftSkipPointsOld == fftSkipPoints &&
|
mSpecCache->fftSkipPointsOld == fftSkipPoints &&
|
||||||
@ -914,19 +978,26 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float *useBuffer;
|
float *useBuffer = 0;
|
||||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
float *buffer = new float[windowSize*fftSkipPoints1];
|
float *buffer = new float[fftLen*fftSkipPoints1];
|
||||||
mSpecCache->fftSkipPointsOld = fftSkipPoints;
|
mSpecCache->fftSkipPointsOld = fftSkipPoints;
|
||||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
float *buffer = new float[windowSize];
|
float *buffer = new float[fftLen];
|
||||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||||
|
// Initialize zero padding in the buffer
|
||||||
|
for (int ii = 0; ii < padding; ++ii) {
|
||||||
|
buffer[ii] = 0.0;
|
||||||
|
buffer[fftLen - ii - 1] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
mSpecCache->minFreqOld = minFreq;
|
mSpecCache->minFreqOld = minFreq;
|
||||||
mSpecCache->maxFreqOld = maxFreq;
|
mSpecCache->maxFreqOld = maxFreq;
|
||||||
mSpecCache->gainOld = gain;
|
mSpecCache->gainOld = gain;
|
||||||
mSpecCache->rangeOld = range;
|
mSpecCache->rangeOld = range;
|
||||||
mSpecCache->windowTypeOld = windowType;
|
mSpecCache->windowTypeOld = windowType;
|
||||||
mSpecCache->windowSizeOld = windowSize;
|
mSpecCache->windowSizeOld = windowSize;
|
||||||
|
mSpecCache->zeroPaddingFactorOld = zeroPaddingFactor;
|
||||||
mSpecCache->frequencyGainOld = frequencygain;
|
mSpecCache->frequencyGainOld = frequencygain;
|
||||||
|
|
||||||
float *gainfactor = NULL;
|
float *gainfactor = NULL;
|
||||||
@ -953,10 +1024,9 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
|||||||
mSpecCache->freq[half * x + i] = 0;
|
mSpecCache->freq[half * x + i] = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
bool copy = !autocorrelation || (padding > 0);
|
||||||
bool copy = !autocorrelation;
|
float *adj = buffer + padding;
|
||||||
float *adj = buffer;
|
|
||||||
start -= windowSize >> 1;
|
start -= windowSize >> 1;
|
||||||
|
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
@ -1015,7 +1085,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, mWindowSize, &mSpecCache->freq[half * x]);
|
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, fftLen, &mSpecCache->freq[half * x]);
|
||||||
}
|
}
|
||||||
#else // EXPERIMENTAL_USE_REALFFTF
|
#else // EXPERIMENTAL_USE_REALFFTF
|
||||||
ComputeSpectrum(buffer, windowSize, windowSize,
|
ComputeSpectrum(buffer, windowSize, windowSize,
|
||||||
|
@ -257,6 +257,7 @@ protected:
|
|||||||
int mWindowType;
|
int mWindowType;
|
||||||
int mWindowSize;
|
int mWindowSize;
|
||||||
#endif
|
#endif
|
||||||
|
int mZeroPaddingFactor;
|
||||||
samplePtr mAppendBuffer;
|
samplePtr mAppendBuffer;
|
||||||
sampleCount mAppendBufferLen;
|
sampleCount mAppendBufferLen;
|
||||||
|
|
||||||
|
@ -29,14 +29,24 @@
|
|||||||
SpectrumPrefs::SpectrumPrefs(wxWindow * parent)
|
SpectrumPrefs::SpectrumPrefs(wxWindow * parent)
|
||||||
: PrefsPanel(parent, _("Spectrograms"))
|
: PrefsPanel(parent, _("Spectrograms"))
|
||||||
{
|
{
|
||||||
Populate();
|
int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||||
|
Populate(windowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectrumPrefs::~SpectrumPrefs()
|
SpectrumPrefs::~SpectrumPrefs()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumPrefs::Populate()
|
enum { maxWindowSize = 32768 };
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ID_WINDOW_SIZE = 10001,
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
ID_PADDING_SIZE = 10002,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void SpectrumPrefs::Populate(int windowSize)
|
||||||
{
|
{
|
||||||
mSizeChoices.Add(_("8 - most wideband"));
|
mSizeChoices.Add(_("8 - most wideband"));
|
||||||
mSizeChoices.Add(wxT("16"));
|
mSizeChoices.Add(wxT("16"));
|
||||||
@ -52,9 +62,13 @@ void SpectrumPrefs::Populate()
|
|||||||
mSizeChoices.Add(wxT("16384"));
|
mSizeChoices.Add(wxT("16384"));
|
||||||
mSizeChoices.Add(_("32768 - most narrowband"));
|
mSizeChoices.Add(_("32768 - most narrowband"));
|
||||||
|
|
||||||
|
int lastCode = 0;
|
||||||
for (size_t i = 0; i < mSizeChoices.GetCount(); i++) {
|
for (size_t i = 0; i < mSizeChoices.GetCount(); i++) {
|
||||||
mSizeCodes.Add(1 << (i + 3));
|
mSizeCodes.Add(lastCode = 1 << (i + 3));
|
||||||
}
|
}
|
||||||
|
wxASSERT(lastCode == maxWindowSize);
|
||||||
|
|
||||||
|
PopulatePaddingChoices(windowSize);
|
||||||
|
|
||||||
for (int i = 0; i < NumWindowFuncs(); i++) {
|
for (int i = 0; i < NumWindowFuncs(); i++) {
|
||||||
mTypeChoices.Add(WindowFuncName(i));
|
mTypeChoices.Add(WindowFuncName(i));
|
||||||
@ -71,6 +85,48 @@ void SpectrumPrefs::Populate()
|
|||||||
// ----------------------- End of main section --------------
|
// ----------------------- End of main section --------------
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumPrefs::PopulatePaddingChoices(int windowSize)
|
||||||
|
{
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
mZeroPaddingChoice = 1;
|
||||||
|
|
||||||
|
// The choice of window size restricts the choice of padding.
|
||||||
|
// So the padding menu might grow or shrink.
|
||||||
|
|
||||||
|
// If pPaddingSizeControl is NULL, we have not yet tied the choice control.
|
||||||
|
// If it is not NULL, we rebuild the control by hand.
|
||||||
|
// I don't yet know an easier way to do this with ShuttleGUI functions.
|
||||||
|
// PRL
|
||||||
|
wxChoice *const pPaddingSizeControl =
|
||||||
|
static_cast<wxChoice*>(wxWindow::FindWindowById(ID_PADDING_SIZE, this));
|
||||||
|
|
||||||
|
if (pPaddingSizeControl) {
|
||||||
|
mZeroPaddingChoice = pPaddingSizeControl->GetSelection();
|
||||||
|
pPaddingSizeControl->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
mZeroPaddingCodes.Clear();
|
||||||
|
|
||||||
|
int padding = 1;
|
||||||
|
int numChoices = 0;
|
||||||
|
while (windowSize <= maxWindowSize) {
|
||||||
|
const wxString numeral = wxString::Format(wxT("%d"), padding);
|
||||||
|
mZeroPaddingChoices.Add(numeral);
|
||||||
|
mZeroPaddingCodes.Add(padding);
|
||||||
|
if (pPaddingSizeControl)
|
||||||
|
pPaddingSizeControl->Append(numeral);
|
||||||
|
windowSize <<= 1;
|
||||||
|
padding <<= 1;
|
||||||
|
++numChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
mZeroPaddingChoice = std::min(mZeroPaddingChoice, numChoices - 1);
|
||||||
|
|
||||||
|
if (pPaddingSizeControl)
|
||||||
|
pPaddingSizeControl->SetSelection(mZeroPaddingChoice);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
||||||
{
|
{
|
||||||
S.SetBorder(2);
|
S.SetBorder(2);
|
||||||
@ -79,7 +135,7 @@ void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
|||||||
{
|
{
|
||||||
S.StartMultiColumn(2);
|
S.StartMultiColumn(2);
|
||||||
{
|
{
|
||||||
S.TieChoice(_("Window &size:"),
|
S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
|
||||||
wxT("/Spectrum/FFTSize"),
|
wxT("/Spectrum/FFTSize"),
|
||||||
256,
|
256,
|
||||||
mSizeChoices,
|
mSizeChoices,
|
||||||
@ -92,6 +148,15 @@ void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
|||||||
mTypeChoices,
|
mTypeChoices,
|
||||||
mTypeCodes);
|
mTypeCodes);
|
||||||
S.SetSizeHints(mTypeChoices);
|
S.SetSizeHints(mTypeChoices);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")),
|
||||||
|
wxT("/Spectrum/ZeroPaddingFactor"),
|
||||||
|
mZeroPaddingChoice,
|
||||||
|
mZeroPaddingChoices,
|
||||||
|
mZeroPaddingCodes);
|
||||||
|
S.SetSizeHints(mZeroPaddingChoices);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
S.EndMultiColumn();
|
S.EndMultiColumn();
|
||||||
}
|
}
|
||||||
@ -289,3 +354,15 @@ bool SpectrumPrefs::Apply()
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpectrumPrefs::OnWindowSize(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
wxChoice *const pWindowSizeControl =
|
||||||
|
static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
|
||||||
|
int windowSize = 1 << (pWindowSizeControl->GetSelection() + 3);
|
||||||
|
PopulatePaddingChoices(windowSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
|
||||||
|
EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
@ -39,9 +39,13 @@ class SpectrumPrefs:public PrefsPanel
|
|||||||
virtual bool Validate();
|
virtual bool Validate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Populate();
|
void Populate(int windowSize);
|
||||||
|
void PopulatePaddingChoices(int windowSize);
|
||||||
void PopulateOrExchange(ShuttleGui & S);
|
void PopulateOrExchange(ShuttleGui & S);
|
||||||
|
|
||||||
|
void OnWindowSize(wxCommandEvent &event);
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
wxTextCtrl *mMinFreq;
|
wxTextCtrl *mMinFreq;
|
||||||
wxTextCtrl *mMaxFreq;
|
wxTextCtrl *mMaxFreq;
|
||||||
wxTextCtrl *mGain;
|
wxTextCtrl *mGain;
|
||||||
@ -51,6 +55,12 @@ class SpectrumPrefs:public PrefsPanel
|
|||||||
wxArrayString mSizeChoices;
|
wxArrayString mSizeChoices;
|
||||||
wxArrayInt mSizeCodes;
|
wxArrayInt mSizeCodes;
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||||
|
int mZeroPaddingChoice;
|
||||||
|
wxArrayString mZeroPaddingChoices;
|
||||||
|
wxArrayInt mZeroPaddingCodes;
|
||||||
|
#endif
|
||||||
|
|
||||||
wxArrayString mTypeChoices;
|
wxArrayString mTypeChoices;
|
||||||
wxArrayInt mTypeCodes;
|
wxArrayInt mTypeCodes;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user