mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-02 00:29:41 +02:00
Merge: more drawing code reorganizations...
Fix compilation of some disabled experimental branches for spectrograms ... Keep FFT windows for Spectrograms in one place in SpectrogramSettings... Created a global structure to hold spectrogram preferences... Don't invalidate SpecCache for changes of min, max, gain or range...
This commit is contained in:
commit
cf54b4c314
@ -2,15 +2,15 @@
|
||||
#define __realfftf_h
|
||||
|
||||
#define fft_type float
|
||||
typedef struct FFTParamType {
|
||||
struct FFTParam {
|
||||
int *BitReversed;
|
||||
fft_type *SinTable;
|
||||
int Points;
|
||||
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
|
||||
int pow2Bits;
|
||||
#endif
|
||||
} FFTParam;
|
||||
#define HFFT FFTParam *
|
||||
};
|
||||
typedef FFTParam * HFFT;
|
||||
|
||||
HFFT InitializeFFT(int);
|
||||
void EndFFT(HFFT);
|
||||
|
@ -173,6 +173,7 @@ audio tracks.
|
||||
#include "LabelTrack.h"
|
||||
#include "TimeTrack.h"
|
||||
#include "Prefs.h"
|
||||
#include "prefs/SpectrumPrefs.h"
|
||||
#include "Sequence.h"
|
||||
#include "Spectrum.h"
|
||||
#include "ViewInfo.h"
|
||||
@ -270,14 +271,6 @@ TrackArtist::TrackArtist()
|
||||
|
||||
SetColours();
|
||||
vruler = new Ruler();
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
fftYGridOld=true;
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
fftFindNotesOld=false;
|
||||
#endif
|
||||
}
|
||||
|
||||
TrackArtist::~TrackArtist()
|
||||
@ -672,6 +665,10 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & r)
|
||||
|
||||
void TrackArtist::UpdateVRuler(Track *t, wxRect & r)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
const int fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
// Label tracks do not have a vruler
|
||||
if (t->GetKind() == Track::Label) {
|
||||
return;
|
||||
@ -811,14 +808,14 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & r)
|
||||
|
||||
int maxFreq = GetSpectrumMaxFreq(freq);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
maxFreq/=(mFftSkipPoints+1);
|
||||
maxFreq/=(fftSkipPoints+1);
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
if(maxFreq > freq)
|
||||
maxFreq = freq;
|
||||
|
||||
int minFreq = GetSpectrumMinFreq(0);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
minFreq/=(mFftSkipPoints+1);
|
||||
minFreq/=(fftSkipPoints+1);
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
if(minFreq < 0)
|
||||
minFreq = 0;
|
||||
@ -857,14 +854,14 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & r)
|
||||
|
||||
int maxFreq = GetSpectrumLogMaxFreq(freq);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
maxFreq/=(mFftSkipPoints+1);
|
||||
maxFreq/=(fftSkipPoints+1);
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
if(maxFreq > freq)
|
||||
maxFreq = freq;
|
||||
|
||||
int minFreq = GetSpectrumLogMinFreq(freq/1000.0);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
minFreq/=(mFftSkipPoints+1);
|
||||
minFreq/=(fftSkipPoints+1);
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
if(minFreq < 1)
|
||||
minFreq = 1;
|
||||
@ -1936,9 +1933,19 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
}
|
||||
#endif
|
||||
|
||||
int range = gPrefs->Read(wxT("/Spectrum/Range"), 80L);
|
||||
int gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
|
||||
|
||||
const SpectrogramSettings &settings = SpectrogramSettings::defaults();
|
||||
const bool &isGrayscale = settings.isGrayscale;
|
||||
const int &range = settings.range;
|
||||
const int &gain = settings.gain;
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
const bool &fftFindNotes = settings.fftFindNotes;
|
||||
const bool &findNotesMinA = settings.findNotesMinA;
|
||||
const bool &numberOfMaxima = settings.numberOfMaxima;
|
||||
const bool &findNotesQuantize = settings.findNotesQuantize;
|
||||
#endif
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
const bool &fftYGrid = settings.fftYGrid;
|
||||
#endif
|
||||
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
|
||||
@ -1959,7 +1966,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
t0, pps, autocorrelation);
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||
int fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints;
|
||||
int fftSkipPoints1 = fftSkipPoints + 1;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
@ -2009,8 +2016,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
for (int y = 0; y < mid.height; y++) {
|
||||
float n = (float(y) / mid.height*scale2 - lmin2) * 12;
|
||||
float n2 = (float(y + 1) / mid.height*scale2 - lmin2) * 12;
|
||||
float f = float(minFreq) / (mFftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2);
|
||||
float f2 = float(minFreq) / (mFftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2);
|
||||
float f = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2);
|
||||
float f2 = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2);
|
||||
n = logf(f / 440) / log2 * 12;
|
||||
n2 = logf(f2 / 440) / log2 * 12;
|
||||
if (floor(n) < floor(n2))
|
||||
@ -2021,14 +2028,16 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
if (!updated && clip->mSpecPxCache->valid && (clip->mSpecPxCache->len == mid.height * mid.width)
|
||||
&& gain == clip->mSpecPxCache->gain
|
||||
&& range == clip->mSpecPxCache->range
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
&& mFftYGrid==fftYGridOld
|
||||
&& fftYGrid==fftYGridOld
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
&& mFftFindNotes==fftFindNotesOld
|
||||
&& mFindNotesMinA==findNotesMinAOld
|
||||
&& mNumberOfMaxima==findNotesNOld
|
||||
&& mFindNotesQuantize==findNotesQuantizeOld
|
||||
&& fftFindNotes==fftFindNotesOld
|
||||
&& findNotesMinA==findNotesMinAOld
|
||||
&& numberOfMaxima==findNotesNOld
|
||||
&& findNotesQuantize==findNotesQuantizeOld
|
||||
#endif
|
||||
) {
|
||||
// cache is up to date
|
||||
@ -2037,21 +2046,23 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
delete clip->mSpecPxCache;
|
||||
clip->mSpecPxCache = new SpecPxCache(mid.width * mid.height);
|
||||
clip->mSpecPxCache->valid = true;
|
||||
clip->mSpecPxCache->gain = gain;
|
||||
clip->mSpecPxCache->range = range;
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
fftFindNotesOld=mFftFindNotes;
|
||||
findNotesMinAOld=mFindNotesMinA;
|
||||
findNotesNOld=mNumberOfMaxima;
|
||||
findNotesQuantizeOld=mFindNotesQuantize;
|
||||
fftFindNotesOld = fftFindNotes;
|
||||
findNotesMinAOld = findNotesMinA;
|
||||
findNotesNOld = numberOfMaxima;
|
||||
findNotesQuantizeOld = findNotesQuantize;
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
const float
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
lmins = logf(float(minFreq) / (mFftSkipPoints + 1)),
|
||||
lmaxs = logf(float(maxFreq) / (mFftSkipPoints + 1)),
|
||||
const float
|
||||
lmins = logf(float(minFreq) / (fftSkipPoints + 1)),
|
||||
lmaxs = logf(float(maxFreq) / (fftSkipPoints + 1))
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
lmins = lmin,
|
||||
lmaxs = lmax,
|
||||
lmaxs = lmax
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
;
|
||||
#endif //EXPERIMENTAL_FIND_NOTES
|
||||
@ -2061,7 +2072,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
float maxima0[128], maxima1[128];
|
||||
const float
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
f2bin = half / (rate / 2.0f / (mFftSkipPoints + 1)),
|
||||
f2bin = half / (rate / 2.0f / (fftSkipPoints + 1)),
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
f2bin = half / (rate / 2.0f),
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
@ -2088,13 +2099,14 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
else {
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
int maximas=0;
|
||||
if (!usePxCache && mFftFindNotes) {
|
||||
const int x0 = half * x;
|
||||
if (fftFindNotes) {
|
||||
for (int i = maxTableSize-1; i >= 0; i--)
|
||||
indexes[i]=-1;
|
||||
|
||||
// Build a table of (most) values, put the index in it.
|
||||
for (int i = int(i0); i < int(i1); i++) {
|
||||
float freqi=freq[x0+int(i)];
|
||||
float freqi=freq[x0 + int(i)];
|
||||
int value=int((freqi+gain+range)/range*(maxTableSize-1));
|
||||
if (value < 0)
|
||||
value=0;
|
||||
@ -2103,29 +2115,29 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
indexes[value]=i;
|
||||
}
|
||||
// Build from the indices an array of maxima.
|
||||
for (int i = maxTableSize-1; i >= 0; i--) {
|
||||
int index=indexes[i];
|
||||
for (int i = maxTableSize - 1; i >= 0; i--) {
|
||||
int index = indexes[i];
|
||||
if (index >= 0) {
|
||||
float freqi=freq[x0+index];
|
||||
if (freqi < mFindNotesMinA)
|
||||
float freqi = freq[x0 + index];
|
||||
if (freqi < findNotesMinA)
|
||||
break;
|
||||
|
||||
bool ok=true;
|
||||
for (int m=0; m < maximas; m++) {
|
||||
bool ok = true;
|
||||
for (int m = 0; m < maximas; m++) {
|
||||
// Avoid to store very close maxima.
|
||||
float maxm = maxima[m];
|
||||
if (maxm/index < minDistance && index/maxm < minDistance) {
|
||||
ok=false;
|
||||
if (maxm / index < minDistance && index / maxm < minDistance) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
maxima[maximas++] = index;
|
||||
if (maximas >= mNumberOfMaxima)
|
||||
if (maximas >= numberOfMaxima)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The f2pix helper macro converts a frequency into a pixel coordinate.
|
||||
#define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*mid.height
|
||||
@ -2134,7 +2146,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
for (int i=0; i < maximas; i++) {
|
||||
int index=maxima[i];
|
||||
float f = float(index)*bin2f;
|
||||
if (mFindNotesQuantize)
|
||||
if (findNotesQuantize)
|
||||
{ f = expf(int(log(f/440)/log2*12-0.5)/12.0f*log2)*440;
|
||||
maxima[i] = f*f2bin;
|
||||
}
|
||||
@ -2168,7 +2180,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
float value;
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
if (mFftFindNotes) {
|
||||
if (fftFindNotes) {
|
||||
if (it < maximas) {
|
||||
float i0=maxima0[it];
|
||||
if (yy >= i0)
|
||||
@ -2177,11 +2189,9 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
if (inMaximum) {
|
||||
float i1=maxima1[it];
|
||||
if (yy+1 <= i1) {
|
||||
value=sumFreqValues(freq, x0, bin0, bin1);
|
||||
if (value < mFindNotesMinA)
|
||||
value=findValue(freq + x0, bin0, bin1, half, autocorrelation, gain, range);
|
||||
if (value < findNotesMinA)
|
||||
value = minColor;
|
||||
else
|
||||
value = (value + gain + range) / (double)range;
|
||||
} else {
|
||||
it++;
|
||||
inMaximum = false;
|
||||
@ -2249,7 +2259,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
unsigned char rv, gv, bv;
|
||||
const float value =
|
||||
clip->mSpecPxCache->values[x * mid.height + yy];
|
||||
GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv);
|
||||
GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
|
||||
int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
|
||||
data[px++] = rv;
|
||||
data[px++] = gv;
|
||||
@ -2289,10 +2299,10 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
yy2 = yy2_base;
|
||||
|
||||
unsigned char rv, gv, bv;
|
||||
GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv);
|
||||
GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
if (mFftYGrid && yGrid[yy]) {
|
||||
if (fftYGrid && yGrid[yy]) {
|
||||
rv /= 1.1f;
|
||||
gv /= 1.1f;
|
||||
bv /= 1.1f;
|
||||
@ -2325,9 +2335,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
delete[] yGrid;
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
delete[] indexes;
|
||||
#endif //EXPERIMENTAL_FIND_NOTES
|
||||
}
|
||||
|
||||
void TrackArtist::InvalidateSpectrumCache(TrackList *tracks)
|
||||
@ -3039,99 +3046,74 @@ void TrackArtist::UpdatePrefs()
|
||||
mdBrange = gPrefs->Read(wxT("/GUI/EnvdBRange"), mdBrange);
|
||||
mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping);
|
||||
|
||||
// mMaxFreq should have the same default as in SpectrumPrefs.
|
||||
mMaxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
|
||||
mMinFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1);
|
||||
mLogMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1);
|
||||
if( mLogMaxFreq < 0 )
|
||||
mLogMaxFreq = mMaxFreq;
|
||||
mLogMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1);
|
||||
if( mLogMinFreq < 0 )
|
||||
mLogMinFreq = mMinFreq;
|
||||
if (mLogMinFreq < 1)
|
||||
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
|
||||
mFftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0);
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
mFftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0);
|
||||
mFindNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0);
|
||||
mNumberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
|
||||
mFindNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
|
||||
#endif //EXPERIMENTAL_FIND_NOTES
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mFftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
gPrefs->Flush();
|
||||
}
|
||||
|
||||
// Get various preference values
|
||||
int TrackArtist::GetSpectrumMinFreq(int deffreq)
|
||||
{
|
||||
return mMinFreq < 0 ? deffreq : mMinFreq;
|
||||
const int &minFreq = SpectrogramSettings::defaults().minFreq;
|
||||
return minFreq < 0 ? deffreq : minFreq;
|
||||
}
|
||||
|
||||
int TrackArtist::GetSpectrumMaxFreq(int deffreq)
|
||||
{
|
||||
return mMaxFreq < 0 ? deffreq : mMaxFreq;
|
||||
const int &maxFreq = SpectrogramSettings::defaults().maxFreq;
|
||||
return maxFreq < 0 ? deffreq : maxFreq;
|
||||
}
|
||||
|
||||
int TrackArtist::GetSpectrumLogMinFreq(int deffreq)
|
||||
{
|
||||
return mLogMinFreq < 0 ? deffreq : mLogMinFreq;
|
||||
const int &logMinFreq = SpectrogramSettings::defaults().logMinFreq;
|
||||
return logMinFreq < 0 ? deffreq : logMinFreq;
|
||||
}
|
||||
|
||||
int TrackArtist::GetSpectrumLogMaxFreq(int deffreq)
|
||||
{
|
||||
return mLogMaxFreq < 0 ? deffreq : mLogMaxFreq;
|
||||
const int &logMaxFreq = SpectrogramSettings::defaults().logMaxFreq;
|
||||
return logMaxFreq < 0 ? deffreq : logMaxFreq;
|
||||
}
|
||||
|
||||
int TrackArtist::GetSpectrumWindowSize(bool includeZeroPadding)
|
||||
{
|
||||
includeZeroPadding;
|
||||
const int &windowSize = SpectrogramSettings::defaults().windowSize;
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
if (includeZeroPadding)
|
||||
return mWindowSize * mZeroPaddingFactor;
|
||||
if (includeZeroPadding) {
|
||||
const int &zeroPaddingFactor = SpectrogramSettings::defaults().zeroPaddingFactor;
|
||||
return windowSize * zeroPaddingFactor;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return mWindowSize;
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int TrackArtist::GetSpectrumFftSkipPoints()
|
||||
{
|
||||
return mFftSkipPoints;
|
||||
return SpectrogramSettings::defaults().fftSkipPoints;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set various preference values
|
||||
void TrackArtist::SetSpectrumMinFreq(int freq)
|
||||
{
|
||||
mMinFreq = freq;
|
||||
SpectrogramSettings::defaults().minFreq = freq;
|
||||
}
|
||||
|
||||
void TrackArtist::SetSpectrumMaxFreq(int freq)
|
||||
{
|
||||
mMaxFreq = freq;
|
||||
SpectrogramSettings::defaults().maxFreq = freq;
|
||||
}
|
||||
|
||||
void TrackArtist::SetSpectrumLogMinFreq(int freq)
|
||||
{
|
||||
mLogMinFreq = freq;
|
||||
SpectrogramSettings::defaults().logMinFreq = freq;
|
||||
}
|
||||
|
||||
void TrackArtist::SetSpectrumLogMaxFreq(int freq)
|
||||
{
|
||||
mLogMaxFreq = freq;
|
||||
SpectrogramSettings::defaults().logMaxFreq = freq;
|
||||
}
|
||||
|
||||
// Draws the sync-lock bitmap, tiled; always draws stationary relative to the DC
|
||||
|
@ -173,32 +173,8 @@ class AUDACITY_DLL_API TrackArtist {
|
||||
// Preference values
|
||||
float mdBrange; // "/GUI/EnvdBRange"
|
||||
long mShowClipping; // "/GUI/ShowClipping"
|
||||
int mLogMaxFreq; // "/SpectrumLog/MaxFreq"
|
||||
int mLogMinFreq; // "/SpectrumLog/MinFreq"
|
||||
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"
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int mFftSkipPoints; // "/Spectrum/FFTSkipPoints"
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
bool mFftYGrid; // "/Spectrum/FFTYGrid"
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
bool mFftFindNotes; // "/Spectrum/FFTFindNotes"
|
||||
float mFindNotesMinA; // "/Spectrum/FindNotesMinA"
|
||||
int mNumberOfMaxima; // "/Spectrum/FindNotesN"
|
||||
bool mFindNotesQuantize; // "/Spectrum/FindNotesQuantize")
|
||||
#endif //EXPERIMENTAL_FIND_NOTES
|
||||
|
||||
int mInsetLeft;
|
||||
int mInsetTop;
|
||||
int mInsetRight;
|
||||
|
@ -214,6 +214,8 @@ is time to refresh some aspect of the screen.
|
||||
|
||||
#include "ondemand/ODManager.h"
|
||||
|
||||
#include "prefs/SpectrumPrefs.h"
|
||||
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/ToolManager.h"
|
||||
#include "toolbars/ToolsToolBar.h"
|
||||
@ -3045,8 +3047,7 @@ void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
|
||||
|
||||
while(windowSize > effectiveLength)
|
||||
windowSize >>= 1;
|
||||
int windowType;
|
||||
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
||||
const int windowType = SpectrogramSettings::defaults().windowType;
|
||||
mFrequencySnapper->Calculate(
|
||||
SpectrumAnalyst::Spectrum, windowType, windowSize, rate,
|
||||
&frequencySnappingData[0], length);
|
||||
@ -4722,7 +4723,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
// Always spectrogram, never pitch view, pass true
|
||||
windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||
fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
binSize = rate / windowSize;
|
||||
minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
|
||||
@ -4739,7 +4740,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
// Always spectrogram, never pitch view, pass true
|
||||
windowSize = mTrackArtist->GetSpectrumWindowSize(true);
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPoints = mTrackArtist->GetSpectrumFftSkipPoints();
|
||||
fftSkipPoints = SpectrogramSettings::defaults().fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
binSize = rate / windowSize;
|
||||
minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
|
||||
|
324
src/WaveClip.cpp
324
src/WaveClip.cpp
@ -39,6 +39,8 @@ drawing). Cache's the Spectrogram frequency samples.
|
||||
#include "Resample.h"
|
||||
#include "Project.h"
|
||||
|
||||
#include "prefs/SpectrumPrefs.h"
|
||||
|
||||
#include <wx/listimpl.cpp>
|
||||
WX_DEFINE_LIST(WaveClipList);
|
||||
|
||||
@ -254,26 +256,58 @@ protected:
|
||||
|
||||
class SpecCache {
|
||||
public:
|
||||
SpecCache(int cacheLen, int half, bool autocorrelation)
|
||||
{
|
||||
minFreqOld = -1;
|
||||
maxFreqOld = -1;
|
||||
gainOld = -1;
|
||||
rangeOld = -1;
|
||||
windowTypeOld = -1;
|
||||
windowSizeOld = -1;
|
||||
zeroPaddingFactorOld = 1;
|
||||
frequencyGainOld = false;
|
||||
|
||||
// Make invalid cache
|
||||
SpecCache()
|
||||
: len(-1)
|
||||
, ac(false)
|
||||
, pps(-1.0)
|
||||
, start(-1.0)
|
||||
, windowType(-1)
|
||||
, windowSize(-1)
|
||||
, zeroPaddingFactor(-1)
|
||||
, frequencyGain(-1)
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPointsOld = -1;
|
||||
, fftSkipPoints(-1)
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
dirty = -1;
|
||||
start = -1.0;
|
||||
pps = 0.0;
|
||||
len = cacheLen;
|
||||
ac = autocorrelation;
|
||||
freq = len ? new float[len*half] : 0;
|
||||
where = new sampleCount[len+1];
|
||||
|
||||
, freq(NULL)
|
||||
, where(NULL)
|
||||
|
||||
, dirty(-1)
|
||||
{
|
||||
}
|
||||
|
||||
// Make valid cache, to be filled in
|
||||
SpecCache(int cacheLen, bool autocorrelation,
|
||||
double pps_, double start_, int windowType_, int windowSize_,
|
||||
int zeroPaddingFactor_, int frequencyGain_
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
, int fftSkipPoints_
|
||||
#endif
|
||||
)
|
||||
: len(cacheLen)
|
||||
, ac(autocorrelation)
|
||||
, pps(pps_)
|
||||
, start(start_)
|
||||
, windowType(windowType_)
|
||||
, windowSize(windowSize_)
|
||||
, zeroPaddingFactor(zeroPaddingFactor_)
|
||||
, frequencyGain(frequencyGain_)
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
, fftSkipPoints(fftSkipPoints_)
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
// len columns, and so many rows, column-major.
|
||||
// Don't take column literally -- this isn't pixel data yet, it's the
|
||||
// raw data to be mapped onto the display.
|
||||
, freq(len ? new float[len * ((windowSize * zeroPaddingFactor) / 2)] : 0)
|
||||
|
||||
// Sample counts corresponding to the columns, and to one past the end.
|
||||
, where(new sampleCount[len + 1])
|
||||
|
||||
, dirty(-1)
|
||||
{
|
||||
where[0] = 0;
|
||||
}
|
||||
|
||||
@ -283,29 +317,26 @@ public:
|
||||
delete[] where;
|
||||
}
|
||||
|
||||
int minFreqOld;
|
||||
int maxFreqOld;
|
||||
int gainOld;
|
||||
int rangeOld;
|
||||
int windowTypeOld;
|
||||
int windowSizeOld;
|
||||
int zeroPaddingFactorOld;
|
||||
int frequencyGainOld;
|
||||
const sampleCount len;
|
||||
const bool ac;
|
||||
const double pps;
|
||||
const double start;
|
||||
const int windowType;
|
||||
const int windowSize;
|
||||
const int zeroPaddingFactor;
|
||||
const int frequencyGain;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPointsOld;
|
||||
const int fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *const freq;
|
||||
sampleCount *const where;
|
||||
|
||||
int dirty;
|
||||
bool ac;
|
||||
sampleCount len;
|
||||
double start;
|
||||
double pps;
|
||||
sampleCount *where;
|
||||
float *freq;
|
||||
};
|
||||
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
#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;
|
||||
if(len > hFFT->Points*2)
|
||||
@ -340,14 +371,7 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate)
|
||||
mSequence = new Sequence(projDirManager, format);
|
||||
mEnvelope = new Envelope();
|
||||
mWaveCache = new WaveCache(0);
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
mWindowType = -1;
|
||||
mWindowSize = -1;
|
||||
hFFT = NULL;
|
||||
mWindow = NULL;
|
||||
#endif
|
||||
mZeroPaddingFactor = 1;
|
||||
mSpecCache = new SpecCache(0, 1, false);
|
||||
mSpecCache = new SpecCache();
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
mAppendBuffer = NULL;
|
||||
mAppendBufferLen = 0;
|
||||
@ -369,14 +393,7 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager)
|
||||
mEnvelope->SetOffset(orig.GetOffset());
|
||||
mEnvelope->SetTrackLen(((double)orig.mSequence->GetNumSamples()) / orig.mRate);
|
||||
mWaveCache = new WaveCache(0);
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
mWindowType = -1;
|
||||
mWindowSize = -1;
|
||||
hFFT = NULL;
|
||||
mWindow = NULL;
|
||||
#endif
|
||||
mZeroPaddingFactor = 1;
|
||||
mSpecCache = new SpecCache(0, 1, false);
|
||||
mSpecCache = new SpecCache();
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
|
||||
for (WaveClipList::compatibility_iterator it=orig.mCutLines.GetFirst(); it; it=it->GetNext())
|
||||
@ -398,12 +415,6 @@ WaveClip::~WaveClip()
|
||||
delete mWaveCache;
|
||||
delete mSpecCache;
|
||||
delete mSpecPxCache;
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
if(hFFT != NULL)
|
||||
EndFFT(hFFT);
|
||||
if(mWindow != NULL)
|
||||
delete[] mWindow;
|
||||
#endif
|
||||
|
||||
if (mAppendBuffer)
|
||||
DeleteSamples(mAppendBuffer);
|
||||
@ -499,7 +510,8 @@ namespace {
|
||||
inline
|
||||
void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen,
|
||||
double t0, double rate, double samplesPerPixel,
|
||||
double &oldWhere0, double &denom, long &oldX0, long &oldXLast, double &correction)
|
||||
double &oldWhere0, double &denom, long &oldX0, long &oldXLast, double &correction,
|
||||
bool &overlap)
|
||||
{
|
||||
// Mitigate the accumulation of location errors
|
||||
// in copies of copies of ... of caches.
|
||||
@ -533,6 +545,7 @@ void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen,
|
||||
denom < 0.5)
|
||||
{
|
||||
correction = 0.0;
|
||||
overlap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -540,6 +553,7 @@ void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen,
|
||||
const double correction0 = where0 - guessWhere0;
|
||||
correction = std::max(-samplesPerPixel, std::min(samplesPerPixel, correction0));
|
||||
wxASSERT(correction == correction0);
|
||||
overlap = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,26 +612,32 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
return true;
|
||||
}
|
||||
|
||||
WaveCache *oldCache = mWaveCache;
|
||||
|
||||
mWaveCache = new WaveCache(numPixels);
|
||||
mWaveCache->pps = pixelsPerSecond;
|
||||
mWaveCache->rate = mRate;
|
||||
mWaveCache->start = t0;
|
||||
double tstep = 1.0 / pixelsPerSecond;
|
||||
double samplesPerPixel = mRate * tstep;
|
||||
std::auto_ptr<WaveCache> oldCache(mWaveCache);
|
||||
mWaveCache = 0;
|
||||
|
||||
double oldWhere0 = 0;
|
||||
double denom = 0;
|
||||
long oldX0 = 0, oldXLast = 0;
|
||||
double correction = 0.0;
|
||||
bool overlap = false;
|
||||
const double tstep = 1.0 / pixelsPerSecond;
|
||||
const double samplesPerPixel = mRate * tstep;
|
||||
|
||||
if (match &&
|
||||
oldCache->len > 0) {
|
||||
findCorrection(oldCache->where, oldCache->len, mWaveCache->len,
|
||||
findCorrection(oldCache->where, oldCache->len, numPixels,
|
||||
t0, mRate, samplesPerPixel,
|
||||
oldWhere0, denom, oldX0, oldXLast, correction);
|
||||
oldWhere0, denom, oldX0, oldXLast, correction, overlap);
|
||||
}
|
||||
|
||||
if (!overlap)
|
||||
oldCache.reset(0);
|
||||
|
||||
mWaveCache = new WaveCache(numPixels);
|
||||
mWaveCache->pps = pixelsPerSecond;
|
||||
mWaveCache->rate = mRate;
|
||||
mWaveCache->start = t0;
|
||||
|
||||
fillWhere(mWaveCache->where, mWaveCache->len, 0.0, correction,
|
||||
t0, mRate, samplesPerPixel);
|
||||
|
||||
@ -630,7 +650,7 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
// Optimization: if the old cache is good and overlaps
|
||||
// with the current one, re-use as much of the cache as
|
||||
// possible
|
||||
if (match &&
|
||||
if (match && overlap &&
|
||||
denom >= 0.5 &&
|
||||
oldX0 < oldCache->len &&
|
||||
oldXLast > oldCache->start) {
|
||||
@ -763,7 +783,6 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
}
|
||||
|
||||
mWaveCache->dirty = mDirty;
|
||||
delete oldCache;
|
||||
|
||||
memcpy(min, mWaveCache->min, numPixels*sizeof(float));
|
||||
memcpy(max, mWaveCache->max, numPixels*sizeof(float));
|
||||
@ -781,67 +800,6 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
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)
|
||||
{
|
||||
if (frequencyGain > 0) {
|
||||
@ -867,20 +825,26 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
double t0, double pixelsPerSecond,
|
||||
bool autocorrelation)
|
||||
{
|
||||
int minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
|
||||
int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
|
||||
int range = gPrefs->Read(wxT("/Spectrum/Range"), 80L);
|
||||
int gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
|
||||
int frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
|
||||
int windowType;
|
||||
int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||
const SpectrogramSettings &settings = SpectrogramSettings::defaults();
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||
int fftSkipPoints1 = fftSkipPoints+1;
|
||||
int fftSkipPoints = settings.fftSkipPoints;
|
||||
int fftSkipPoints1 = fftSkipPoints + 1;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
const int zeroPaddingFactor =
|
||||
autocorrelation ? 1 : gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
||||
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
||||
|
||||
const int &frequencyGain = settings.frequencyGain;
|
||||
const int &windowSize = settings.windowSize;
|
||||
const int &windowType = settings.windowType;
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
const int &zeroPaddingFactor = autocorrelation ? 1 : settings.zeroPaddingFactor;
|
||||
#else
|
||||
const int zeroPaddingFactor = 1;
|
||||
#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
|
||||
// because of zero padding done for increased frequency resolution
|
||||
@ -888,37 +852,15 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
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) || (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 =
|
||||
mSpecCache &&
|
||||
mSpecCache->dirty == mDirty &&
|
||||
mSpecCache->minFreqOld == minFreq &&
|
||||
mSpecCache->maxFreqOld == maxFreq &&
|
||||
mSpecCache->rangeOld == range &&
|
||||
mSpecCache->gainOld == gain &&
|
||||
mSpecCache->windowTypeOld == windowType &&
|
||||
mSpecCache->windowSizeOld == windowSize &&
|
||||
mSpecCache->zeroPaddingFactorOld == zeroPaddingFactor &&
|
||||
mSpecCache->frequencyGainOld == frequencyGain &&
|
||||
mSpecCache->windowType == windowType &&
|
||||
mSpecCache->windowSize == windowSize &&
|
||||
mSpecCache->zeroPaddingFactor == zeroPaddingFactor &&
|
||||
mSpecCache->frequencyGain == frequencyGain &&
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mSpecCache->fftSkipPointsOld == fftSkipPoints &&
|
||||
mSpecCache->fftSkipPoints == fftSkipPoints &&
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mSpecCache->ac == autocorrelation &&
|
||||
mSpecCache->pps == pixelsPerSecond;
|
||||
@ -931,14 +873,11 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
return false; //hit cache completely
|
||||
}
|
||||
|
||||
SpecCache *oldCache = mSpecCache;
|
||||
std::auto_ptr<SpecCache> oldCache(mSpecCache);
|
||||
mSpecCache = 0;
|
||||
|
||||
mSpecCache = new SpecCache(numPixels, half, autocorrelation);
|
||||
mSpecCache->pps = pixelsPerSecond;
|
||||
mSpecCache->start = t0;
|
||||
|
||||
bool *recalc = new bool[mSpecCache->len + 1];
|
||||
std::fill(&recalc[0], &recalc[mSpecCache->len + 1], true);
|
||||
bool *recalc = new bool[numPixels + 1];
|
||||
std::fill(&recalc[0], &recalc[numPixels + 1], true);
|
||||
|
||||
const double tstep = 1.0 / pixelsPerSecond;
|
||||
const double samplesPerPixel = mRate * tstep;
|
||||
@ -949,21 +888,33 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
double denom = 0;
|
||||
long oldX0 = 0, oldXLast = 0;
|
||||
double correction = 0.0;
|
||||
bool overlap = false;
|
||||
|
||||
if (match &&
|
||||
oldCache->len > 0) {
|
||||
findCorrection(oldCache->where, oldCache->len, mSpecCache->len,
|
||||
findCorrection(oldCache->where, oldCache->len, numPixels,
|
||||
t0, mRate, samplesPerPixel,
|
||||
oldWhere0, denom, oldX0, oldXLast, correction);
|
||||
oldWhere0, denom, oldX0, oldXLast, correction, overlap);
|
||||
}
|
||||
|
||||
if (!overlap)
|
||||
oldCache.reset(0);
|
||||
|
||||
mSpecCache = new SpecCache(
|
||||
numPixels, autocorrelation, pixelsPerSecond, t0,
|
||||
windowType, windowSize, zeroPaddingFactor, frequencyGain
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
, fftSkipPoints
|
||||
#endif
|
||||
);
|
||||
|
||||
fillWhere(mSpecCache->where, mSpecCache->len, 0.5, correction,
|
||||
t0, mRate, samplesPerPixel);
|
||||
|
||||
// Optimization: if the old cache is good and overlaps
|
||||
// with the current one, re-use as much of the cache as
|
||||
// possible
|
||||
if (match &&
|
||||
if (match && overlap &&
|
||||
denom >= 0.5 &&
|
||||
oldX0 < oldCache->len &&
|
||||
oldXLast > oldCache->start) {
|
||||
@ -988,7 +939,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
float *useBuffer = 0;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *buffer = new float[fftLen*fftSkipPoints1];
|
||||
mSpecCache->fftSkipPointsOld = fftSkipPoints;
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *buffer = new float[fftLen];
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
@ -998,15 +948,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
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;
|
||||
|
||||
std::vector<float> gainFactors;
|
||||
ComputeSpectrogramGainFactors(fftLen, frequencyGain, gainFactors);
|
||||
|
||||
@ -1084,7 +1025,7 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
mRate, &mSpecCache->freq[half * x],
|
||||
autocorrelation, windowType);
|
||||
} else {
|
||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, mWindow, fftLen, &mSpecCache->freq[half * x]);
|
||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, window, fftLen, &mSpecCache->freq[half * x]);
|
||||
}
|
||||
#else // EXPERIMENTAL_USE_REALFFTF
|
||||
ComputeSpectrum(buffer, windowSize, windowSize,
|
||||
@ -1101,7 +1042,6 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
|
||||
delete[]buffer;
|
||||
delete[]recalc;
|
||||
delete oldCache;
|
||||
|
||||
mSpecCache->dirty = mDirty;
|
||||
memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float));
|
||||
@ -1759,7 +1699,7 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
// Invalidate the spectrum display cache
|
||||
if (mSpecCache)
|
||||
delete mSpecCache;
|
||||
mSpecCache = new SpecCache(0, 1, false);
|
||||
mSpecCache = new SpecCache();
|
||||
}
|
||||
|
||||
return !error;
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
len = cacheLen;
|
||||
values = new float[len];
|
||||
valid = false;
|
||||
range = gain = -1;
|
||||
}
|
||||
|
||||
~SpecPxCache()
|
||||
@ -53,6 +54,9 @@ public:
|
||||
sampleCount len;
|
||||
float *values;
|
||||
bool valid;
|
||||
|
||||
int range;
|
||||
int gain;
|
||||
};
|
||||
|
||||
class WaveClip;
|
||||
@ -303,14 +307,6 @@ protected:
|
||||
WaveCache *mWaveCache;
|
||||
ODLock mWaveCacheMutex;
|
||||
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;
|
||||
sampleCount mAppendBufferLen;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
*//*******************************************************************/
|
||||
|
||||
#include "../Audacity.h"
|
||||
#include "SpectrumPrefs.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/intl.h>
|
||||
@ -23,7 +24,6 @@
|
||||
#include "../Prefs.h"
|
||||
#include "../Project.h"
|
||||
#include "../ShuttleGui.h"
|
||||
#include "SpectrumPrefs.h"
|
||||
#include "../FFT.h"
|
||||
|
||||
SpectrumPrefs::SpectrumPrefs(wxWindow * parent)
|
||||
@ -352,10 +352,12 @@ bool SpectrumPrefs::Apply()
|
||||
ShuttleGui S(this, eIsSavingToPrefs);
|
||||
PopulateOrExchange(S);
|
||||
|
||||
SpectrogramSettings::defaults().UpdatePrefs();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpectrumPrefs::OnWindowSize(wxCommandEvent &event)
|
||||
void SpectrumPrefs::OnWindowSize(wxCommandEvent &)
|
||||
{
|
||||
wxChoice *const pWindowSizeControl =
|
||||
static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
|
||||
@ -366,3 +368,179 @@ void SpectrumPrefs::OnWindowSize(wxCommandEvent &event)
|
||||
BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
|
||||
EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
SpectrogramSettings::SpectrogramSettings()
|
||||
: hFFT(0)
|
||||
, window(0)
|
||||
{
|
||||
UpdatePrefs();
|
||||
}
|
||||
|
||||
SpectrogramSettings& SpectrogramSettings::defaults()
|
||||
{
|
||||
static SpectrogramSettings instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void SpectrogramSettings::UpdatePrefs()
|
||||
{
|
||||
bool destroy = false;
|
||||
|
||||
minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L);
|
||||
maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
|
||||
|
||||
// These preferences are not written anywhere in the program as of now,
|
||||
// but I keep this legacy here. Who knows, someone might edit prefs files
|
||||
// directly. PRL
|
||||
logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1);
|
||||
if (logMaxFreq < 0)
|
||||
logMaxFreq = maxFreq;
|
||||
logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1);
|
||||
if (logMinFreq < 0)
|
||||
logMinFreq = minFreq;
|
||||
if (logMinFreq < 1)
|
||||
logMinFreq = 1;
|
||||
|
||||
range = gPrefs->Read(wxT("/Spectrum/Range"), 80L);
|
||||
gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
|
||||
frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
|
||||
|
||||
const int newWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
|
||||
if (newWindowSize != windowSize) {
|
||||
destroy = true;
|
||||
windowSize = newWindowSize;
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
const int newZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
|
||||
if (newZeroPaddingFactor != zeroPaddingFactor) {
|
||||
destroy = true;
|
||||
zeroPaddingFactor = newZeroPaddingFactor;
|
||||
}
|
||||
#endif
|
||||
|
||||
int newWindowType;
|
||||
gPrefs->Read(wxT("/Spectrum/WindowType"), &newWindowType, 3);
|
||||
if (newWindowType != windowType) {
|
||||
destroy = true;
|
||||
windowType = newWindowType;
|
||||
}
|
||||
|
||||
isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPoints = gPrefs->Read(wxT("/Spectrum/FFTSkipPoints"), 0L);
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
fftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0);
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
fftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0);
|
||||
findNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0);
|
||||
numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
|
||||
findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
|
||||
#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"
|
||||
|
||||
struct FFTParam;
|
||||
|
||||
class SpectrumPrefs:public PrefsPanel
|
||||
{
|
||||
public:
|
||||
@ -71,4 +73,57 @@ class SpectrumPrefs:public PrefsPanel
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct SpectrogramSettings
|
||||
{
|
||||
static SpectrogramSettings &defaults();
|
||||
SpectrogramSettings();
|
||||
~SpectrogramSettings();
|
||||
|
||||
void UpdatePrefs();
|
||||
void DestroyWindows();
|
||||
void CacheWindows() const;
|
||||
|
||||
int minFreq;
|
||||
int maxFreq;
|
||||
|
||||
int logMinFreq;
|
||||
int logMaxFreq;
|
||||
|
||||
int range;
|
||||
int gain;
|
||||
int frequencyGain;
|
||||
|
||||
int windowType;
|
||||
int windowSize;
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
int zeroPaddingFactor;
|
||||
#endif
|
||||
|
||||
bool isGrayscale;
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints;
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
bool fftYGrid;
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
bool fftFindNotes;
|
||||
bool findNotesMinA;
|
||||
bool numberOfMaxima;
|
||||
bool findNotesQuantize;
|
||||
#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
|
||||
|
Loading…
x
Reference in New Issue
Block a user