mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-07 15:49:42 +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
|
||||
#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
|
||||
|
@ -1803,6 +1803,7 @@ static float sumFreqValues(
|
||||
|
||||
// Helper function to decide on which color set to use.
|
||||
// dashCount counts both dashes and the spaces between them.
|
||||
inline
|
||||
AColor::ColorGradientChoice ChooseColorSet( float bin0, float bin1, float selBinLo,
|
||||
float selBinCenter, float selBinHi, int dashCount, bool isSpectral )
|
||||
{
|
||||
@ -1959,8 +1960,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
if (!image)return;
|
||||
unsigned char *data = image->GetData();
|
||||
|
||||
int windowSize = GetSpectrumWindowSize();
|
||||
int half = windowSize/2;
|
||||
int windowSize = GetSpectrumWindowSize(!autocorrelation);
|
||||
const int half = windowSize / 2;
|
||||
float *freq = new float[mid.width * half];
|
||||
sampleCount *where = new sampleCount[mid.width+1];
|
||||
|
||||
@ -2106,7 +2107,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
|
||||
AColor::ColorGradientChoice selected =
|
||||
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)
|
||||
{
|
||||
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
||||
@ -2220,7 +2221,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
|
||||
AColor::ColorGradientChoice selected =
|
||||
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)
|
||||
{
|
||||
bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
|
||||
@ -3029,6 +3030,9 @@ void TrackArtist::UpdatePrefs()
|
||||
mLogMinFreq = 1;
|
||||
|
||||
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);
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
@ -3070,9 +3074,14 @@ int TrackArtist::GetSpectrumLogMaxFreq(int deffreq)
|
||||
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
|
||||
|
@ -73,7 +73,7 @@ class AUDACITY_DLL_API TrackArtist {
|
||||
int GetSpectrumMaxFreq(int deffreq);
|
||||
int GetSpectrumLogMinFreq(int deffreq);
|
||||
int GetSpectrumLogMaxFreq(int deffreq);
|
||||
int GetSpectrumWindowSize();
|
||||
int GetSpectrumWindowSize(bool includeZeroPadding);
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int GetSpectrumFftSkipPoints();
|
||||
@ -184,6 +184,9 @@ class AUDACITY_DLL_API TrackArtist {
|
||||
int mMaxFreq; // "/Spectrum/MaxFreq"
|
||||
int mMinFreq; // "/Spectrum/MinFreq"
|
||||
int mWindowSize; // "/Spectrum/FFTSize"
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
int mZeroPaddingFactor; // "/Spectrum/ZeroPaddingFactor"
|
||||
#endif
|
||||
bool mIsGrayscale; // "/Spectrum/Grayscale"
|
||||
bool mbShowTrackNameInWaveform; // "/GUI/ShowTrackNameInWaveform"
|
||||
|
||||
|
@ -2977,7 +2977,8 @@ inline double findMaxRatio(double center, double rate)
|
||||
|
||||
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 nyq = rate / 2.0;
|
||||
const double binFrequency = rate / windowSize;
|
||||
@ -3038,7 +3039,10 @@ void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
|
||||
|
||||
// Use same settings as are now used for spectrogram display,
|
||||
// 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)
|
||||
windowSize >>= 1;
|
||||
int windowType;
|
||||
@ -4714,7 +4718,9 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
max = mTrackArtist->GetSpectrumMaxFreq(8000);
|
||||
if(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
|
||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
@ -4729,7 +4735,9 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
max = mTrackArtist->GetSpectrumLogMaxFreq(lrint(rate/2.));
|
||||
if(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
|
||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
128
src/WaveClip.cpp
128
src/WaveClip.cpp
@ -226,6 +226,7 @@ public:
|
||||
rangeOld = -1;
|
||||
windowTypeOld = -1;
|
||||
windowSizeOld = -1;
|
||||
zeroPaddingFactorOld = 1;
|
||||
frequencyGainOld = false;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPointsOld = -1;
|
||||
@ -252,6 +253,7 @@ public:
|
||||
int rangeOld;
|
||||
int windowTypeOld;
|
||||
int windowSizeOld;
|
||||
int zeroPaddingFactorOld;
|
||||
int frequencyGainOld;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPointsOld;
|
||||
@ -284,8 +286,9 @@ static void ComputeSpectrumUsingRealFFTf(float *buffer, HFFT hFFT, float *window
|
||||
else
|
||||
out[0] = 10.0*log10(power);
|
||||
for(i=1;i<hFFT->Points;i++) {
|
||||
power = (buffer[hFFT->BitReversed[i] ]*buffer[hFFT->BitReversed[i] ])
|
||||
+ (buffer[hFFT->BitReversed[i]+1]*buffer[hFFT->BitReversed[i]+1]);
|
||||
const int index = hFFT->BitReversed[i];
|
||||
const float re = buffer[index], im = buffer[index + 1];
|
||||
power = re * re + im * im;
|
||||
if(power <= 0)
|
||||
out[i] = -160.0;
|
||||
else
|
||||
@ -307,6 +310,7 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate)
|
||||
hFFT = NULL;
|
||||
mWindow = NULL;
|
||||
#endif
|
||||
mZeroPaddingFactor = 1;
|
||||
mSpecCache = new SpecCache(0, 1, false);
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
mAppendBuffer = NULL;
|
||||
@ -335,6 +339,7 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager)
|
||||
hFFT = NULL;
|
||||
mWindow = NULL;
|
||||
#endif
|
||||
mZeroPaddingFactor = 1;
|
||||
mSpecCache = new SpecCache(0, 1, false);
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
|
||||
@ -754,6 +759,67 @@ bool WaveClip::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
|
||||
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,
|
||||
float *freq, sampleCount *where,
|
||||
int numPixels,
|
||||
@ -771,37 +837,34 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||
int fftSkipPoints1 = fftSkipPoints+1;
|
||||
#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);
|
||||
|
||||
// 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
|
||||
// Update the FFT and window if necessary
|
||||
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;
|
||||
mWindowSize = windowSize;
|
||||
if(hFFT != NULL)
|
||||
EndFFT(hFFT);
|
||||
hFFT = InitializeFFT(mWindowSize);
|
||||
if(mWindow != NULL) delete[] mWindow;
|
||||
// Create the requested window function
|
||||
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;
|
||||
}
|
||||
hFFT = InitializeFFT(fftLen);
|
||||
double scale;
|
||||
RecreateWindow(mWindow, WINDOW, fftLen, padding, mWindowType, mWindowSize, scale);
|
||||
}
|
||||
#endif // EXPERIMENTAL_USE_REALFFTF
|
||||
|
||||
|
||||
mZeroPaddingFactor = zeroPaddingFactor;
|
||||
|
||||
const bool match =
|
||||
mSpecCache &&
|
||||
mSpecCache->dirty == mDirty &&
|
||||
@ -811,6 +874,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
mSpecCache->gainOld == gain &&
|
||||
mSpecCache->windowTypeOld == windowType &&
|
||||
mSpecCache->windowSizeOld == windowSize &&
|
||||
mSpecCache->zeroPaddingFactorOld == zeroPaddingFactor &&
|
||||
mSpecCache->frequencyGainOld == frequencygain &&
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mSpecCache->fftSkipPointsOld == fftSkipPoints &&
|
||||
@ -914,19 +978,26 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
}
|
||||
}
|
||||
|
||||
float *useBuffer;
|
||||
float *useBuffer = 0;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *buffer = new float[windowSize*fftSkipPoints1];
|
||||
float *buffer = new float[fftLen*fftSkipPoints1];
|
||||
mSpecCache->fftSkipPointsOld = fftSkipPoints;
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *buffer = new float[windowSize];
|
||||
float *buffer = new float[fftLen];
|
||||
#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->maxFreqOld = maxFreq;
|
||||
mSpecCache->gainOld = gain;
|
||||
mSpecCache->rangeOld = range;
|
||||
mSpecCache->windowTypeOld = windowType;
|
||||
mSpecCache->windowSizeOld = windowSize;
|
||||
mSpecCache->zeroPaddingFactorOld = zeroPaddingFactor;
|
||||
mSpecCache->frequencyGainOld = frequencygain;
|
||||
|
||||
float *gainfactor = NULL;
|
||||
@ -953,10 +1024,9 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
mSpecCache->freq[half * x + i] = 0;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool copy = !autocorrelation;
|
||||
float *adj = buffer;
|
||||
else {
|
||||
bool copy = !autocorrelation || (padding > 0);
|
||||
float *adj = buffer + padding;
|
||||
start -= windowSize >> 1;
|
||||
|
||||
if (start < 0) {
|
||||
@ -1015,7 +1085,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
mRate, &mSpecCache->freq[half * x],
|
||||
autocorrelation, windowType);
|
||||
} else {
|
||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, mWindowSize, &mSpecCache->freq[half * x]);
|
||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, fftLen, &mSpecCache->freq[half * x]);
|
||||
}
|
||||
#else // EXPERIMENTAL_USE_REALFFTF
|
||||
ComputeSpectrum(buffer, windowSize, windowSize,
|
||||
|
@ -257,6 +257,7 @@ protected:
|
||||
int mWindowType;
|
||||
int mWindowSize;
|
||||
#endif
|
||||
int mZeroPaddingFactor;
|
||||
samplePtr mAppendBuffer;
|
||||
sampleCount mAppendBufferLen;
|
||||
|
||||
|
@ -29,14 +29,24 @@
|
||||
SpectrumPrefs::SpectrumPrefs(wxWindow * parent)
|
||||
: PrefsPanel(parent, _("Spectrograms"))
|
||||
{
|
||||
Populate();
|
||||
int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||
Populate(windowSize);
|
||||
}
|
||||
|
||||
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(wxT("16"));
|
||||
@ -52,9 +62,13 @@ void SpectrumPrefs::Populate()
|
||||
mSizeChoices.Add(wxT("16384"));
|
||||
mSizeChoices.Add(_("32768 - most narrowband"));
|
||||
|
||||
int lastCode = 0;
|
||||
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++) {
|
||||
mTypeChoices.Add(WindowFuncName(i));
|
||||
@ -71,6 +85,48 @@ void SpectrumPrefs::Populate()
|
||||
// ----------------------- 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)
|
||||
{
|
||||
S.SetBorder(2);
|
||||
@ -79,7 +135,7 @@ void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
||||
{
|
||||
S.StartMultiColumn(2);
|
||||
{
|
||||
S.TieChoice(_("Window &size:"),
|
||||
S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
|
||||
wxT("/Spectrum/FFTSize"),
|
||||
256,
|
||||
mSizeChoices,
|
||||
@ -92,6 +148,15 @@ void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
|
||||
mTypeChoices,
|
||||
mTypeCodes);
|
||||
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();
|
||||
}
|
||||
@ -289,3 +354,15 @@ bool SpectrumPrefs::Apply()
|
||||
|
||||
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();
|
||||
|
||||
private:
|
||||
void Populate();
|
||||
void Populate(int windowSize);
|
||||
void PopulatePaddingChoices(int windowSize);
|
||||
void PopulateOrExchange(ShuttleGui & S);
|
||||
|
||||
void OnWindowSize(wxCommandEvent &event);
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
wxTextCtrl *mMinFreq;
|
||||
wxTextCtrl *mMaxFreq;
|
||||
wxTextCtrl *mGain;
|
||||
@ -51,6 +55,12 @@ class SpectrumPrefs:public PrefsPanel
|
||||
wxArrayString mSizeChoices;
|
||||
wxArrayInt mSizeCodes;
|
||||
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
int mZeroPaddingChoice;
|
||||
wxArrayString mZeroPaddingChoices;
|
||||
wxArrayInt mZeroPaddingCodes;
|
||||
#endif
|
||||
|
||||
wxArrayString mTypeChoices;
|
||||
wxArrayInt mTypeCodes;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user