mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-28 14:18:41 +02:00
Merge: More reorganization of wave and spectrum caches, and performance...
This commit is contained in:
commit
324816e3fc
@ -1681,14 +1681,13 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
|
||||
float zoomMin, zoomMax;
|
||||
track->GetDisplayBounds(&zoomMin, &zoomMax);
|
||||
|
||||
WaveDisplay display;
|
||||
WaveDisplay display(mid.width);
|
||||
bool isLoadingOD = false;//true if loading on demand block in sequence.
|
||||
|
||||
// The WaveClip class handles the details of computing the shape
|
||||
// of the waveform. The only way GetWaveDisplay will fail is if
|
||||
// there's a serious error, like some of the waveform data can't
|
||||
// be loaded. So if the function returns false, we can just exit.
|
||||
display.Allocate(mid.width);
|
||||
if (!clip->GetWaveDisplay(display,
|
||||
t0, pps, isLoadingOD)) {
|
||||
return;
|
||||
@ -1705,7 +1704,7 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
|
||||
// the envelope and using a colored pen for the selected
|
||||
// part of the waveform
|
||||
DrawWaveformBackground(dc, mid, envValues, zoomMin, zoomMax, dB,
|
||||
display.where, ssel0, ssel1, drawEnvelope,
|
||||
&display.where[0], ssel0, ssel1, drawEnvelope,
|
||||
!track->GetSelected());
|
||||
|
||||
if (!showIndividualSamples) {
|
||||
@ -1824,7 +1823,7 @@ void TrackArtist::DrawSpectrum(WaveTrack *track,
|
||||
}
|
||||
|
||||
static inline float findValue
|
||||
(float *spectrum, float bin0, float bin1, int half,
|
||||
(const float *spectrum, float bin0, float bin1, int half,
|
||||
bool autocorrelation, int gain, int range)
|
||||
{
|
||||
float value;
|
||||
@ -1959,8 +1958,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
|
||||
int windowSize = GetSpectrumWindowSize(!autocorrelation);
|
||||
const int half = windowSize / 2;
|
||||
float *freq = new float[mid.width * half];
|
||||
sampleCount *where = new sampleCount[mid.width+1];
|
||||
const float *freq = 0;
|
||||
const sampleCount *where = 0;
|
||||
|
||||
bool updated = clip->GetSpectrogram(cache, freq, where, mid.width,
|
||||
t0, pps, autocorrelation);
|
||||
@ -2330,8 +2329,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &cache,
|
||||
dc.Blit(mid.x, mid.y, mid.width, mid.height, &memDC, 0, 0, wxCOPY, FALSE);
|
||||
|
||||
delete image;
|
||||
delete[] where;
|
||||
delete[] freq;
|
||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||
delete[] yGrid;
|
||||
#endif //EXPERIMENTAL_FFT_Y_GRID
|
||||
|
708
src/WaveClip.cpp
708
src/WaveClip.cpp
@ -44,53 +44,56 @@ drawing). Cache's the Spectrogram frequency samples.
|
||||
#include <wx/listimpl.cpp>
|
||||
WX_DEFINE_LIST(WaveClipList);
|
||||
|
||||
namespace {
|
||||
inline int CountODPixels(int *bl, int start, int end)
|
||||
{
|
||||
using namespace std;
|
||||
return count_if(bl + start, bl + end, bind2nd(less<int>(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class WaveCache {
|
||||
public:
|
||||
WaveCache(int cacheLen)
|
||||
: len(cacheLen)
|
||||
WaveCache()
|
||||
: dirty(-1)
|
||||
, len(-1)
|
||||
, start(-1)
|
||||
, pps(0)
|
||||
, rate(-1)
|
||||
, where(0)
|
||||
, min(0)
|
||||
, max(0)
|
||||
, rms(0)
|
||||
, bl(0)
|
||||
, numODPixels(0)
|
||||
{
|
||||
dirty = -1;
|
||||
start = -1.0;
|
||||
pps = 0.0;
|
||||
min = len ? new float[len] : 0;
|
||||
max = len ? new float[len] : 0;
|
||||
rms = len ? new float[len] : 0;
|
||||
bl = len ? new int[len] : 0;
|
||||
where = new sampleCount[len+1];
|
||||
where[0] = 0;
|
||||
numODPixels=0;
|
||||
}
|
||||
|
||||
WaveCache(int len_, double pixelsPerSecond, double rate_, double t0)
|
||||
: dirty(-1)
|
||||
, len(len_)
|
||||
, start(t0)
|
||||
, pps(pixelsPerSecond)
|
||||
, rate(rate_)
|
||||
, where(1 + len)
|
||||
, min(len)
|
||||
, max(len)
|
||||
, rms(len)
|
||||
, bl(len)
|
||||
, numODPixels(0)
|
||||
{
|
||||
|
||||
//find the number of OD pixels - the only way to do this is by recounting since we've lost some old cache.
|
||||
numODPixels = CountODPixels(0, len);
|
||||
}
|
||||
|
||||
~WaveCache()
|
||||
{
|
||||
delete[] min;
|
||||
delete[] max;
|
||||
delete[] rms;
|
||||
delete[] bl;
|
||||
delete[] where;
|
||||
|
||||
ClearInvalidRegions();
|
||||
}
|
||||
|
||||
int dirty;
|
||||
const sampleCount len;
|
||||
double start;
|
||||
double pps;
|
||||
int rate;
|
||||
sampleCount *where;
|
||||
float *min;
|
||||
float *max;
|
||||
float *rms;
|
||||
int *bl;
|
||||
const int len; // counts pixels, not samples
|
||||
const double start;
|
||||
const double pps;
|
||||
const int rate;
|
||||
std::vector<sampleCount> where;
|
||||
std::vector<float> min;
|
||||
std::vector<float> max;
|
||||
std::vector<float> rms;
|
||||
std::vector<int> bl;
|
||||
int numODPixels;
|
||||
|
||||
class InvalidRegion
|
||||
@ -223,7 +226,7 @@ public:
|
||||
//before check number of ODPixels
|
||||
int regionODPixels = 0;
|
||||
if (updateODCount)
|
||||
regionODPixels = CountODPixels(bl, invStart, invEnd);
|
||||
regionODPixels = CountODPixels(invStart, invEnd);
|
||||
|
||||
sequence->GetWaveDisplay(&min[invStart],
|
||||
&max[invStart],
|
||||
@ -235,7 +238,7 @@ public:
|
||||
//after check number of ODPixels
|
||||
if (updateODCount)
|
||||
{
|
||||
const int regionODPixelsAfter = CountODPixels(bl, invStart, invEnd);
|
||||
const int regionODPixelsAfter = CountODPixels(invStart, invEnd);
|
||||
numODPixels -= (regionODPixels - regionODPixelsAfter);
|
||||
}
|
||||
}
|
||||
@ -247,6 +250,12 @@ public:
|
||||
LoadInvalidRegion(i, sequence, updateODCount);
|
||||
}
|
||||
|
||||
int CountODPixels(int start, int end)
|
||||
{
|
||||
using namespace std;
|
||||
const int *begin = &bl[0];
|
||||
return count_if(begin + start, begin + end, bind2nd(less<int>(), 0));
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<InvalidRegion*> mRegions;
|
||||
@ -301,10 +310,10 @@ public:
|
||||
// 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)
|
||||
, freq(len * ((windowSize * zeroPaddingFactor) / 2))
|
||||
|
||||
// Sample counts corresponding to the columns, and to one past the end.
|
||||
, where(new sampleCount[len + 1])
|
||||
, where(len + 1)
|
||||
|
||||
, dirty(-1)
|
||||
{
|
||||
@ -313,11 +322,27 @@ public:
|
||||
|
||||
~SpecCache()
|
||||
{
|
||||
delete[] freq;
|
||||
delete[] where;
|
||||
}
|
||||
|
||||
const sampleCount len;
|
||||
bool Matches(int dirty_, bool autocorrelation, double pixelsPerSecond,
|
||||
const SpectrogramSettings &settings) const;
|
||||
|
||||
void CalculateOneSpectrum
|
||||
(const SpectrogramSettings &settings,
|
||||
WaveTrackCache &waveTrackCache,
|
||||
int xx, sampleCount numSamples,
|
||||
double offset, double rate,
|
||||
bool autocorrelation, const std::vector<float> &gainFactors,
|
||||
float *scratch);
|
||||
|
||||
void Populate
|
||||
(const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache,
|
||||
int copyBegin, int copyEnd, int numPixels,
|
||||
sampleCount numSamples,
|
||||
double offset, double rate,
|
||||
bool autocorrelation);
|
||||
|
||||
const int len; // counts pixels, not samples
|
||||
const bool ac;
|
||||
const double pps;
|
||||
const double start;
|
||||
@ -328,8 +353,8 @@ public:
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
const int fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *const freq;
|
||||
sampleCount *const where;
|
||||
std::vector<float> freq;
|
||||
std::vector<sampleCount> where;
|
||||
|
||||
int dirty;
|
||||
};
|
||||
@ -370,7 +395,7 @@ WaveClip::WaveClip(DirManager *projDirManager, sampleFormat format, int rate)
|
||||
mRate = rate;
|
||||
mSequence = new Sequence(projDirManager, format);
|
||||
mEnvelope = new Envelope();
|
||||
mWaveCache = new WaveCache(0);
|
||||
mWaveCache = new WaveCache();
|
||||
mSpecCache = new SpecCache();
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
mAppendBuffer = NULL;
|
||||
@ -392,7 +417,7 @@ WaveClip::WaveClip(const WaveClip& orig, DirManager *projDirManager)
|
||||
mEnvelope->Paste(0.0, orig.mEnvelope);
|
||||
mEnvelope->SetOffset(orig.GetOffset());
|
||||
mEnvelope->SetTrackLen(((double)orig.mSequence->GetNumSamples()) / orig.mRate);
|
||||
mWaveCache = new WaveCache(0);
|
||||
mWaveCache = new WaveCache();
|
||||
mSpecCache = new SpecCache();
|
||||
mSpecPxCache = new SpecPxCache(1);
|
||||
|
||||
@ -494,7 +519,7 @@ void WaveClip::DeleteWaveCache()
|
||||
ODLocker locker(mWaveCacheMutex);
|
||||
if(mWaveCache!=NULL)
|
||||
delete mWaveCache;
|
||||
mWaveCache = new WaveCache(0);
|
||||
mWaveCache = new WaveCache();
|
||||
}
|
||||
|
||||
///Adds an invalid region to the wavecache so it redraws that portion only.
|
||||
@ -508,57 +533,50 @@ void WaveClip::AddInvalidRegion(long startSample, long endSample)
|
||||
namespace {
|
||||
|
||||
inline
|
||||
void findCorrection(const sampleCount oldWhere[], int oldLen, int newLen,
|
||||
void findCorrection(const std::vector<sampleCount> &oldWhere, int oldLen, int newLen,
|
||||
double t0, double rate, double samplesPerPixel,
|
||||
double &oldWhere0, double &denom, long &oldX0, long &oldXLast, double &correction,
|
||||
bool &overlap)
|
||||
int &oldX0, double &correction)
|
||||
{
|
||||
// Mitigate the accumulation of location errors
|
||||
// in copies of copies of ... of caches.
|
||||
// Look at the loop that populates "where" below to understand this.
|
||||
|
||||
// Find the sample position that is the origin in the old cache.
|
||||
oldWhere0 = oldWhere[1] - samplesPerPixel;
|
||||
const double oldWhere0 = oldWhere[1] - samplesPerPixel;
|
||||
const double oldWhereLast = oldWhere0 + oldLen * samplesPerPixel;
|
||||
// Find the length in samples of the old cache.
|
||||
denom = oldWhereLast - oldWhere0;
|
||||
const double denom = oldWhereLast - oldWhere0;
|
||||
|
||||
// What sample would go in where[0] with no correction?
|
||||
const double guessWhere0 = t0 * rate;
|
||||
|
||||
// What integer position in the old cache array does that map to?
|
||||
// (even if it is out of bounds)
|
||||
oldX0 = floor(0.5 + oldLen * (guessWhere0 - oldWhere0) / denom);
|
||||
// What sample count would the old cache have put there?
|
||||
const double where0 = oldWhere0 + double(oldX0) * samplesPerPixel;
|
||||
// What integer position in the old cache array does our last column
|
||||
// map to? (even if out of bounds)
|
||||
oldXLast = floor(0.5 + oldLen * (
|
||||
(where0 + double(newLen) * samplesPerPixel - oldWhere0)
|
||||
/ denom
|
||||
));
|
||||
|
||||
if ( // Skip if old and new are disjoint:
|
||||
oldWhereLast <= guessWhere0 ||
|
||||
guessWhere0 + newLen * samplesPerPixel <= oldWhere0 ||
|
||||
// Skip unless denom rounds off to at least 1.
|
||||
denom < 0.5)
|
||||
{
|
||||
// The computation of oldX0 in the other branch
|
||||
// may underflow and the assertion would be violated.
|
||||
oldX0 = oldLen;
|
||||
correction = 0.0;
|
||||
overlap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// What integer position in the old cache array does that map to?
|
||||
// (even if it is out of bounds)
|
||||
oldX0 = floor(0.5 + oldLen * (guessWhere0 - oldWhere0) / denom);
|
||||
// What sample count would the old cache have put there?
|
||||
const double where0 = oldWhere0 + double(oldX0) * samplesPerPixel;
|
||||
// What correction is needed to align the new cache with the old?
|
||||
const double correction0 = where0 - guessWhere0;
|
||||
correction = std::max(-samplesPerPixel, std::min(samplesPerPixel, correction0));
|
||||
wxASSERT(correction == correction0);
|
||||
overlap = true;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
fillWhere(sampleCount where[], int len, double bias, double correction,
|
||||
fillWhere(std::vector<sampleCount> &where, int len, double bias, double correction,
|
||||
double t0, double rate, double samplesPerPixel)
|
||||
{
|
||||
// Be careful to make the first value non-negative
|
||||
@ -581,33 +599,27 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
double pixelsPerSecond, bool &isLoadingOD)
|
||||
{
|
||||
int numPixels = display.width;
|
||||
float *const min = display.min;
|
||||
float *const max = display.max;
|
||||
float *const rms = display.rms;
|
||||
int *const bl = display.bl;
|
||||
sampleCount *const where = display.where;
|
||||
|
||||
ODLocker locker(mWaveCacheMutex);
|
||||
|
||||
|
||||
const bool match =
|
||||
mWaveCache &&
|
||||
mWaveCache->len > 0 &&
|
||||
mWaveCache->dirty == mDirty &&
|
||||
mWaveCache->pps == pixelsPerSecond;
|
||||
|
||||
if (match &&
|
||||
mWaveCache->start == t0 &&
|
||||
mWaveCache->len >= numPixels) {
|
||||
|
||||
mWaveCache->LoadInvalidRegions(mSequence, true);
|
||||
mWaveCache->ClearInvalidRegions();
|
||||
|
||||
|
||||
memcpy(min, mWaveCache->min, numPixels*sizeof(float));
|
||||
memcpy(max, mWaveCache->max, numPixels*sizeof(float));
|
||||
memcpy(rms, mWaveCache->rms, numPixels*sizeof(float));
|
||||
memcpy(bl, mWaveCache->bl, numPixels*sizeof(int));
|
||||
memcpy(where, mWaveCache->where, (numPixels+1)*sizeof(sampleCount));
|
||||
// Satisfy the request completely from the cache
|
||||
display.min = &mWaveCache->min[0];
|
||||
display.max = &mWaveCache->max[0];
|
||||
display.rms = &mWaveCache->rms[0];
|
||||
display.bl = &mWaveCache->bl[0];
|
||||
display.where = &mWaveCache->where[0];
|
||||
isLoadingOD = mWaveCache->numODPixels > 0;
|
||||
return true;
|
||||
}
|
||||
@ -615,51 +627,48 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
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) {
|
||||
int oldX0 = 0;
|
||||
double correction = 0.0;
|
||||
|
||||
int copyBegin = 0, copyEnd = 0;
|
||||
if (match) {
|
||||
findCorrection(oldCache->where, oldCache->len, numPixels,
|
||||
t0, mRate, samplesPerPixel,
|
||||
oldWhere0, denom, oldX0, oldXLast, correction, overlap);
|
||||
oldX0, correction);
|
||||
// Remember our first pixel maps to oldX0 in the old cache,
|
||||
// possibly out of bounds.
|
||||
// For what range of pixels can data be copied?
|
||||
copyBegin = std::min(numPixels, std::max(0, -oldX0));
|
||||
copyEnd = std::min(numPixels,
|
||||
copyBegin + oldCache->len - std::max(0, oldX0)
|
||||
);
|
||||
}
|
||||
|
||||
if (!overlap)
|
||||
if (!(copyEnd > copyBegin))
|
||||
oldCache.reset(0);
|
||||
|
||||
mWaveCache = new WaveCache(numPixels);
|
||||
mWaveCache->pps = pixelsPerSecond;
|
||||
mWaveCache->rate = mRate;
|
||||
mWaveCache->start = t0;
|
||||
mWaveCache = new WaveCache(numPixels, pixelsPerSecond, mRate, t0);
|
||||
float *const min = &mWaveCache->min[0];
|
||||
float *const max = &mWaveCache->max[0];
|
||||
float *const rms = &mWaveCache->rms[0];
|
||||
int *const bl = &mWaveCache->bl[0];
|
||||
std::vector<sampleCount> &where = mWaveCache->where;
|
||||
|
||||
fillWhere(mWaveCache->where, mWaveCache->len, 0.0, correction,
|
||||
fillWhere(where, numPixels, 0.0, correction,
|
||||
t0, mRate, samplesPerPixel);
|
||||
|
||||
//mchinen: I think s0 - s1 represents the range of samples that we will need to look up. likewise p0-p1 the number of pixels.
|
||||
sampleCount s0 = mWaveCache->where[0];
|
||||
sampleCount s1 = mWaveCache->where[mWaveCache->len];
|
||||
int p0 = 0;
|
||||
int p1 = mWaveCache->len;
|
||||
// The range of pixels we must fetch from the Sequence:
|
||||
const int p0 = (copyBegin > 0) ? 0 : copyEnd;
|
||||
int p1 = (copyEnd >= numPixels) ? copyBegin : numPixels;
|
||||
|
||||
// Optimization: if the old cache is good and overlaps
|
||||
// with the current one, re-use as much of the cache as
|
||||
// possible
|
||||
if (match && overlap &&
|
||||
denom >= 0.5 &&
|
||||
oldX0 < oldCache->len &&
|
||||
oldXLast > oldCache->start) {
|
||||
|
||||
//now we are assuming the entire range is covered by the old cache and reducing s1/s0 as we find out otherwise.
|
||||
s0 = mWaveCache->where[mWaveCache->len]; //mchinen:s0 is the min sample covered up to by the wave cache. will shrink if old doen't overlap
|
||||
s1 = mWaveCache->where[0]; //mchinen - same, but the maximum sample covered.
|
||||
p0 = mWaveCache->len;
|
||||
p1 = 0;
|
||||
if (oldCache.get()) {
|
||||
|
||||
//TODO: only load inval regions if
|
||||
//necessary. (usually is the case, so no rush.)
|
||||
@ -667,30 +676,14 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
oldCache->LoadInvalidRegions(mSequence, false);
|
||||
oldCache->ClearInvalidRegions();
|
||||
|
||||
for (sampleCount x = 0; x < mWaveCache->len; x++)
|
||||
{
|
||||
//if we hit a cached column, load it up.
|
||||
const double whereX = t0 * mRate + ((double)x) * samplesPerPixel;
|
||||
const double oxd = (double(oldCache->len) * (whereX - oldWhere0)) / denom;
|
||||
int ox = floor(0.5 + oxd);
|
||||
|
||||
//below is regular cache access.
|
||||
if (ox >= 0 && ox < oldCache->len) {
|
||||
mWaveCache->min[x] = oldCache->min[ox];
|
||||
mWaveCache->max[x] = oldCache->max[ox];
|
||||
mWaveCache->rms[x] = oldCache->rms[ox];
|
||||
mWaveCache->bl[x] = oldCache->bl[ox];
|
||||
} else {
|
||||
if (mWaveCache->where[x] < s0) {
|
||||
s0 = mWaveCache->where[x];
|
||||
p0 = x;
|
||||
}
|
||||
if (mWaveCache->where[x + 1] > s1) {
|
||||
s1 = mWaveCache->where[x + 1];
|
||||
p1 = x + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy what we can from the old cache.
|
||||
const int length = copyEnd - copyBegin;
|
||||
const size_t sizeFloats = length * sizeof(float);
|
||||
const int srcIdx = copyBegin + oldX0;
|
||||
memcpy(&min[copyBegin], &oldCache->min[srcIdx], sizeFloats);
|
||||
memcpy(&max[copyBegin], &oldCache->max[srcIdx], sizeFloats);
|
||||
memcpy(&rms[copyBegin], &oldCache->rms[srcIdx], sizeFloats);
|
||||
memcpy(&bl[copyBegin], &oldCache->bl[srcIdx], length * sizeof(int));
|
||||
}
|
||||
|
||||
if (p1 > p0) {
|
||||
@ -699,9 +692,8 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
|
||||
int numSamples = mSequence->GetNumSamples();
|
||||
int a;
|
||||
|
||||
for(a=p0; a<p1; a++)
|
||||
if (mWaveCache->where[a+1] > numSamples)
|
||||
for(a = p0; a < p1; ++a)
|
||||
if (where[a+1] > numSamples)
|
||||
break;
|
||||
|
||||
//compute the values that are outside the overlap from scratch.
|
||||
@ -712,9 +704,9 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
bool didUpdate = false;
|
||||
for(i=a; i<p1; i++) {
|
||||
sampleCount left;
|
||||
left = mWaveCache->where[i] - numSamples;
|
||||
left = where[i] - numSamples;
|
||||
sampleCount right;
|
||||
right = mWaveCache->where[i+1] - numSamples;
|
||||
right = where[i+1] - numSamples;
|
||||
|
||||
//wxCriticalSectionLocker locker(mAppendCriticalSection);
|
||||
|
||||
@ -737,22 +729,23 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
(samplePtr)b, floatSample, len);
|
||||
}
|
||||
|
||||
float max = b[0];
|
||||
float min = b[0];
|
||||
float sumsq = b[0] * b[0];
|
||||
|
||||
float theMax, theMin, sumsq;
|
||||
{
|
||||
const float val = b[0];
|
||||
theMax = theMin = val;
|
||||
sumsq = val * val;
|
||||
}
|
||||
for(j=1; j<len; j++) {
|
||||
if (b[j] > max)
|
||||
max = b[j];
|
||||
if (b[j] < min)
|
||||
min = b[j];
|
||||
sumsq += b[j]*b[j];
|
||||
const float val = b[j];
|
||||
theMax = std::max(theMax, val);
|
||||
theMin = std::min(theMin, val);
|
||||
sumsq += val * val;
|
||||
}
|
||||
|
||||
mWaveCache->min[i] = min;
|
||||
mWaveCache->max[i] = max;
|
||||
mWaveCache->rms[i] = (float)sqrt(sumsq / len);
|
||||
mWaveCache->bl[i] = 1; //for now just fake it.
|
||||
min[i] = theMin;
|
||||
max[i] = theMax;
|
||||
rms[i] = (float)sqrt(sumsq / len);
|
||||
bl[i] = 1; //for now just fake it.
|
||||
|
||||
if (seqFormat != floatSample)
|
||||
delete[] b;
|
||||
@ -761,20 +754,18 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
}
|
||||
}
|
||||
|
||||
// So that the sequence doesn't try to write any
|
||||
// of these values
|
||||
//mchinen: but only do this if we've updated pixels in the cache.
|
||||
// Shrink the right end of the range to fetch from Sequence
|
||||
if(didUpdate)
|
||||
p1 = a;
|
||||
}
|
||||
|
||||
if (p1 > p0) {
|
||||
if (!mSequence->GetWaveDisplay(&mWaveCache->min[p0],
|
||||
&mWaveCache->max[p0],
|
||||
&mWaveCache->rms[p0],
|
||||
&mWaveCache->bl[p0],
|
||||
if (!mSequence->GetWaveDisplay(&min[p0],
|
||||
&max[p0],
|
||||
&rms[p0],
|
||||
&bl[p0],
|
||||
p1-p0,
|
||||
&mWaveCache->where[p0]))
|
||||
&where[p0]))
|
||||
{
|
||||
isLoadingOD=false;
|
||||
return false;
|
||||
@ -784,30 +775,27 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||
|
||||
mWaveCache->dirty = mDirty;
|
||||
|
||||
memcpy(min, mWaveCache->min, numPixels*sizeof(float));
|
||||
memcpy(max, mWaveCache->max, numPixels*sizeof(float));
|
||||
memcpy(rms, mWaveCache->rms, numPixels*sizeof(float));
|
||||
memcpy(bl, mWaveCache->bl, numPixels*sizeof(int));
|
||||
memcpy(where, mWaveCache->where, (numPixels+1)*sizeof(sampleCount));
|
||||
|
||||
//find the number of OD pixels - the only way to do this is by recounting since we've lost some old cache.
|
||||
mWaveCache->numODPixels = 0;
|
||||
for(int j=0;j<mWaveCache->len;j++)
|
||||
if(mWaveCache->bl[j]<0)
|
||||
mWaveCache->numODPixels++;
|
||||
|
||||
// Now report the results
|
||||
display.min = min;
|
||||
display.max = max;
|
||||
display.rms = rms;
|
||||
display.bl = bl;
|
||||
display.where = &where[0];
|
||||
isLoadingOD = mWaveCache->numODPixels > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaveClip::ComputeSpectrogramGainFactors(int fftLen, int frequencyGain, std::vector<float> &gainFactors)
|
||||
namespace {
|
||||
|
||||
void ComputeSpectrogramGainFactors
|
||||
(int fftLen, double rate, int frequencyGain, std::vector<float> &gainFactors)
|
||||
{
|
||||
if (frequencyGain > 0) {
|
||||
// Compute a frequency-dependent gain factor
|
||||
// scaled such that 1000 Hz gets a gain of 0dB
|
||||
|
||||
// This is the reciprocal of the bin number of 1000 Hz:
|
||||
const double factor = ((double)mRate / (double)fftLen) / 1000.0;
|
||||
const double factor = ((double)rate / (double)fftLen) / 1000.0;
|
||||
|
||||
const int half = fftLen / 2;
|
||||
gainFactors.reserve(half);
|
||||
@ -819,158 +807,58 @@ void WaveClip::ComputeSpectrogramGainFactors(int fftLen, int frequencyGain, std:
|
||||
}
|
||||
}
|
||||
|
||||
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
float *freq, sampleCount *where,
|
||||
int numPixels,
|
||||
double t0, double pixelsPerSecond,
|
||||
bool autocorrelation)
|
||||
{
|
||||
const SpectrogramSettings &settings = SpectrogramSettings::defaults();
|
||||
}
|
||||
|
||||
bool SpecCache::Matches
|
||||
(int dirty_, bool autocorrelation, double pixelsPerSecond,
|
||||
const SpectrogramSettings &settings) const
|
||||
{
|
||||
return
|
||||
dirty == dirty_ &&
|
||||
windowType == settings.windowType &&
|
||||
windowSize == settings.windowSize &&
|
||||
zeroPaddingFactor == settings.zeroPaddingFactor &&
|
||||
frequencyGain == settings.frequencyGain &&
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftSkipPoints == settings.fftSkipPoints &&
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
ac == autocorrelation &&
|
||||
pps == pixelsPerSecond;
|
||||
}
|
||||
|
||||
void SpecCache::CalculateOneSpectrum
|
||||
(const SpectrogramSettings &settings,
|
||||
WaveTrackCache &waveTrackCache,
|
||||
int xx, sampleCount numSamples,
|
||||
double offset, double rate,
|
||||
bool autocorrelation, const std::vector<float> &gainFactors,
|
||||
float *scratch)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints = settings.fftSkipPoints;
|
||||
int fftSkipPoints1 = fftSkipPoints + 1;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
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
|
||||
const int windowSize = settings.windowSize;
|
||||
sampleCount start = where[xx];
|
||||
const int zeroPaddingFactor = (autocorrelation ? 1 : settings.zeroPaddingFactor);
|
||||
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||
const int fftLen = windowSize * zeroPaddingFactor;
|
||||
const int half = fftLen / 2;
|
||||
const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||
float *const results = &freq[half * xx];
|
||||
|
||||
const bool match =
|
||||
mSpecCache &&
|
||||
mSpecCache->dirty == mDirty &&
|
||||
mSpecCache->windowType == windowType &&
|
||||
mSpecCache->windowSize == windowSize &&
|
||||
mSpecCache->zeroPaddingFactor == zeroPaddingFactor &&
|
||||
mSpecCache->frequencyGain == frequencyGain &&
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mSpecCache->fftSkipPoints == fftSkipPoints &&
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
mSpecCache->ac == autocorrelation &&
|
||||
mSpecCache->pps == pixelsPerSecond;
|
||||
|
||||
if (match &&
|
||||
mSpecCache->start == t0 &&
|
||||
mSpecCache->len >= numPixels) {
|
||||
memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float));
|
||||
memcpy(where, mSpecCache->where, (numPixels+1)*sizeof(sampleCount));
|
||||
return false; //hit cache completely
|
||||
}
|
||||
|
||||
std::auto_ptr<SpecCache> oldCache(mSpecCache);
|
||||
mSpecCache = 0;
|
||||
|
||||
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;
|
||||
|
||||
// To do: eliminate duplicate logic with the wave clip code for cache
|
||||
// reuse and finding corrections
|
||||
double oldWhere0 = 0;
|
||||
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, numPixels,
|
||||
t0, mRate, samplesPerPixel,
|
||||
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 && overlap &&
|
||||
denom >= 0.5 &&
|
||||
oldX0 < oldCache->len &&
|
||||
oldXLast > oldCache->start) {
|
||||
for (sampleCount x = 0; x < mSpecCache->len; x++) {
|
||||
//if we hit a cached column, load it up.
|
||||
const double whereX = t0 * mRate + ((double)x) * samplesPerPixel;
|
||||
const double oxd = (double(oldCache->len) * (whereX - oldWhere0)) / denom;
|
||||
int ox = floor(0.5 + oxd);
|
||||
|
||||
//below is regular cache access.
|
||||
if (ox >= 0 && ox < oldCache->len) {
|
||||
if (mSpecCache->where[x] >= oldCache->where[0] &&
|
||||
mSpecCache->where[x] <= oldCache->where[oldCache->len]) {
|
||||
for (sampleCount i = 0; i < (sampleCount)half; i++)
|
||||
mSpecCache->freq[half * x + i] = oldCache->freq[half * ox + i];
|
||||
recalc[x] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float *useBuffer = 0;
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
float *buffer = new float[fftLen*fftSkipPoints1];
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<float> gainFactors;
|
||||
ComputeSpectrogramGainFactors(fftLen, frequencyGain, gainFactors);
|
||||
|
||||
for (sampleCount x = 0; x < mSpecCache->len; x++)
|
||||
if (recalc[x]) {
|
||||
|
||||
sampleCount start = mSpecCache->where[x];
|
||||
sampleCount len = windowSize;
|
||||
sampleCount i;
|
||||
|
||||
if (start <= 0 || start >= mSequence->GetNumSamples()) {
|
||||
|
||||
for (i = 0; i < (sampleCount)half; i++)
|
||||
mSpecCache->freq[half * x + i] = 0;
|
||||
|
||||
if (start <= 0 || start >= numSamples) {
|
||||
std::fill(results, results + half, 0.0f);
|
||||
}
|
||||
else {
|
||||
bool copy = !autocorrelation || (padding > 0);
|
||||
float *adj = buffer + padding;
|
||||
float *useBuffer = 0;
|
||||
float *adj = scratch + padding;
|
||||
start -= windowSize >> 1;
|
||||
|
||||
if (start < 0) {
|
||||
for (i = start; i < 0; i++)
|
||||
for (sampleCount ii = start; ii < 0; ++ii)
|
||||
*adj++ = 0;
|
||||
len += start;
|
||||
start = 0;
|
||||
@ -978,17 +866,17 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
}
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
copy = true;
|
||||
if (start + len*fftSkipPoints1 > mSequence->GetNumSamples()) {
|
||||
int newlen = (mSequence->GetNumSamples() - start)/fftSkipPoints1;
|
||||
for (i = newlen*fftSkipPoints1; i < (sampleCount)len*fftSkipPoints1; i++)
|
||||
if (start + len*fftSkipPoints1 > numSamples) {
|
||||
int newlen = (numSamples - start) / fftSkipPoints1;
|
||||
for (int i = newlen*fftSkipPoints1; i < (sampleCount)len*fftSkipPoints1; i++)
|
||||
adj[i] = 0;
|
||||
len = newlen;
|
||||
}
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
if (start + len > mSequence->GetNumSamples()) {
|
||||
int newlen = mSequence->GetNumSamples() - start;
|
||||
for (i = newlen; i < (sampleCount)len; i++)
|
||||
adj[i] = 0;
|
||||
if (start + len > numSamples) {
|
||||
int newlen = numSamples - start;
|
||||
for (sampleCount ii = newlen; ii < (sampleCount)len; ++ii)
|
||||
adj[ii] = 0;
|
||||
len = newlen;
|
||||
copy = true;
|
||||
}
|
||||
@ -997,9 +885,8 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
if (len > 0) {
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
useBuffer = (float*)(waveTrackCache.Get(floatSample,
|
||||
floor(0.5 + start + mOffset * mRate),
|
||||
len * fftSkipPoints1));
|
||||
memmove(adj, useBuffer, len * fftSkipPoints1 * sizeof(float));
|
||||
floor(0.5 + start + offset * rate), len*fftSkipPoints1));
|
||||
memcpy(adj, useBuffer, len * fftSkipPoints1 * sizeof(float));
|
||||
if (fftSkipPoints) {
|
||||
// TODO: (maybe) alternatively change Get to include skipping of points
|
||||
int j = 0;
|
||||
@ -1010,42 +897,187 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
}
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
useBuffer = (float*)(waveTrackCache.Get(floatSample,
|
||||
floor(0.5 + start + mOffset * mRate), len));
|
||||
floor(0.5 + start + offset * rate), len));
|
||||
if (copy)
|
||||
memmove(adj, useBuffer, len * sizeof(float));
|
||||
memcpy(adj, useBuffer, len * sizeof(float));
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
}
|
||||
|
||||
if (copy)
|
||||
useBuffer = buffer;
|
||||
useBuffer = scratch;
|
||||
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
if(autocorrelation) {
|
||||
if (autocorrelation)
|
||||
ComputeSpectrum(useBuffer, windowSize, windowSize,
|
||||
mRate, &mSpecCache->freq[half * x],
|
||||
autocorrelation, windowType);
|
||||
} else {
|
||||
ComputeSpectrumUsingRealFFTf(useBuffer, hFFT, window, fftLen, &mSpecCache->freq[half * x]);
|
||||
}
|
||||
rate, results,
|
||||
autocorrelation, settings.windowType);
|
||||
else
|
||||
ComputeSpectrumUsingRealFFTf
|
||||
(useBuffer, settings.hFFT, settings.window, fftLen, results);
|
||||
#else // EXPERIMENTAL_USE_REALFFTF
|
||||
ComputeSpectrum(buffer, windowSize, windowSize,
|
||||
mRate, &mSpecCache->freq[half * x],
|
||||
autocorrelation, windowType);
|
||||
rate, results,
|
||||
autocorrelation, settings.windowType);
|
||||
#endif // EXPERIMENTAL_USE_REALFFTF
|
||||
if (!gainFactors.empty()) {
|
||||
// Apply a frequency-dependent gain factor
|
||||
for(i=0; i<half; i++)
|
||||
mSpecCache->freq[half * x + i] += gainFactors[i];
|
||||
// Apply a frequency-dependant gain factor
|
||||
for (int ii = 0; ii < half; ++ii)
|
||||
results[ii] += gainFactors[ii];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[]buffer;
|
||||
delete[]recalc;
|
||||
void SpecCache::Populate
|
||||
(const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache,
|
||||
int copyBegin, int copyEnd, int numPixels,
|
||||
sampleCount numSamples,
|
||||
double offset, double rate,
|
||||
bool autocorrelation)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||
settings.CacheWindows();
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints = settings.fftSkipPoints;
|
||||
int fftSkipPoints1 = fftSkipPoints + 1;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
const int &frequencyGain = settings.frequencyGain;
|
||||
const int &windowSize = settings.windowSize;
|
||||
#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
|
||||
const int &zeroPaddingFactor = autocorrelation ? 1 : settings.zeroPaddingFactor;
|
||||
#else
|
||||
const int zeroPaddingFactor = 1;
|
||||
#endif
|
||||
|
||||
// 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 padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
|
||||
|
||||
std::vector<float> buffer(
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
fftLen*fftSkipPoints1
|
||||
#else //!EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<float> gainFactors;
|
||||
ComputeSpectrogramGainFactors(fftLen, rate, frequencyGain, gainFactors);
|
||||
|
||||
// Loop over the ranges before and after the copied portion and compute anew.
|
||||
// One of the ranges may be empty.
|
||||
for (sampleCount xx = 0; xx < copyBegin; ++xx)
|
||||
CalculateOneSpectrum(
|
||||
settings, waveTrackCache, xx, numSamples,
|
||||
offset, rate, autocorrelation, gainFactors, &buffer[0]);
|
||||
|
||||
for (sampleCount xx = copyEnd; xx < numPixels; ++xx)
|
||||
CalculateOneSpectrum(
|
||||
settings, waveTrackCache, xx, numSamples,
|
||||
offset, rate, autocorrelation, gainFactors, &buffer[0]);
|
||||
}
|
||||
|
||||
bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
|
||||
const float *& spectrogram, const sampleCount *& where,
|
||||
int numPixels,
|
||||
double t0, double pixelsPerSecond,
|
||||
bool autocorrelation)
|
||||
{
|
||||
const SpectrogramSettings &settings = SpectrogramSettings::defaults();
|
||||
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
int fftSkipPoints = settings.fftSkipPoints;
|
||||
#endif //EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
|
||||
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
|
||||
|
||||
// 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 bool match =
|
||||
mSpecCache &&
|
||||
mSpecCache->len > 0 &&
|
||||
mSpecCache->Matches(mDirty, autocorrelation, pixelsPerSecond, settings);
|
||||
|
||||
if (match &&
|
||||
mSpecCache->start == t0 &&
|
||||
mSpecCache->len >= numPixels) {
|
||||
spectrogram = &mSpecCache->freq[0];
|
||||
where = &mSpecCache->where[0];
|
||||
return false; //hit cache completely
|
||||
}
|
||||
|
||||
std::auto_ptr<SpecCache> oldCache(mSpecCache);
|
||||
mSpecCache = 0;
|
||||
|
||||
const double tstep = 1.0 / pixelsPerSecond;
|
||||
const double samplesPerPixel = mRate * tstep;
|
||||
|
||||
int oldX0 = 0;
|
||||
double correction = 0.0;
|
||||
|
||||
int copyBegin = 0, copyEnd = 0;
|
||||
if (match) {
|
||||
findCorrection(oldCache->where, oldCache->len, numPixels,
|
||||
t0, mRate, samplesPerPixel,
|
||||
oldX0, correction);
|
||||
// Remember our first pixel maps to oldX0 in the old cache,
|
||||
// possibly out of bounds.
|
||||
// For what range of pixels can data be copied?
|
||||
copyBegin = std::min(numPixels, std::max(0, -oldX0));
|
||||
copyEnd = std::min(numPixels,
|
||||
copyBegin + oldCache->len - std::max(0, oldX0)
|
||||
);
|
||||
}
|
||||
|
||||
if (!(copyEnd > copyBegin))
|
||||
oldCache.reset(0);
|
||||
|
||||
mSpecCache = new SpecCache(
|
||||
numPixels, autocorrelation, pixelsPerSecond, t0,
|
||||
windowType, windowSize, zeroPaddingFactor, frequencyGain
|
||||
#ifdef EXPERIMENTAL_FFT_SKIP_POINTS
|
||||
, fftSkipPoints
|
||||
#endif
|
||||
);
|
||||
|
||||
fillWhere(mSpecCache->where, numPixels, 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 (oldCache.get()) {
|
||||
memcpy(&mSpecCache->freq[half * copyBegin],
|
||||
&oldCache->freq[half * (copyBegin + oldX0)],
|
||||
half * (copyEnd - copyBegin) * sizeof(float));
|
||||
}
|
||||
|
||||
mSpecCache->Populate
|
||||
(settings, waveTrackCache, copyBegin, copyEnd, numPixels,
|
||||
mSequence->GetNumSamples(), mOffset, mRate, autocorrelation);
|
||||
|
||||
mSpecCache->dirty = mDirty;
|
||||
memcpy(freq, mSpecCache->freq, numPixels*half*sizeof(float));
|
||||
memcpy(where, mSpecCache->where, (numPixels+1)*sizeof(sampleCount));
|
||||
spectrogram = &mSpecCache->freq[0];
|
||||
where = &mSpecCache->where[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1695,7 +1727,7 @@ bool WaveClip::Resample(int rate, ProgressDialog *progress)
|
||||
delete mWaveCache;
|
||||
mWaveCache = NULL;
|
||||
}
|
||||
mWaveCache = new WaveCache(0);
|
||||
mWaveCache = new WaveCache();
|
||||
// Invalidate the spectrum display cache
|
||||
if (mSpecCache)
|
||||
delete mSpecCache;
|
||||
|
@ -72,41 +72,13 @@ public:
|
||||
float *min, *max, *rms;
|
||||
int* bl;
|
||||
|
||||
WaveDisplay()
|
||||
: width(0), where(0), min(0), max(0), rms(0), bl(0)
|
||||
WaveDisplay(int w)
|
||||
: width(w), where(0), min(0), max(0), rms(0), bl(0)
|
||||
{
|
||||
}
|
||||
|
||||
~WaveDisplay()
|
||||
{
|
||||
Deallocate();
|
||||
}
|
||||
|
||||
void Allocate(int w)
|
||||
{
|
||||
width = w;
|
||||
|
||||
// One more to hold the past-the-end sample count:
|
||||
where = new sampleCount[1 + width];
|
||||
|
||||
min = new float[width];
|
||||
max = new float[width];
|
||||
rms = new float[width];
|
||||
bl = new int[width];
|
||||
}
|
||||
|
||||
void Deallocate()
|
||||
{
|
||||
delete[] where;
|
||||
where = 0;
|
||||
delete[] min;
|
||||
min = 0;
|
||||
delete[] max;
|
||||
max = 0;
|
||||
delete[] rms;
|
||||
rms = 0;
|
||||
delete[] bl;
|
||||
bl = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -193,13 +165,8 @@ public:
|
||||
* calculations and Contrast */
|
||||
bool GetWaveDisplay(WaveDisplay &display,
|
||||
double t0, double pixelsPerSecond, bool &isLoadingOD);
|
||||
void ComputeSpectrogramGainFactors(
|
||||
int fftLen,
|
||||
int frequencyGain, // db/decade
|
||||
std::vector<float> &gainFactors
|
||||
);
|
||||
bool GetSpectrogram(WaveTrackCache &cache,
|
||||
float *buffer, sampleCount *where,
|
||||
const float *& spectrogram, const sampleCount *& where,
|
||||
int numPixels,
|
||||
double t0, double pixelsPerSecond,
|
||||
bool autocorrelation);
|
||||
|
Loading…
x
Reference in New Issue
Block a user