From 8664c877ba3ba4f3cf5182a6a86f6a7f9759e757 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 9 Jun 2015 14:12:28 -0400 Subject: [PATCH] WaveDisplay may or may not manage its own memory. --- src/WaveClip.cpp | 217 +++++++++++++++++++++++++++-------------------- src/WaveClip.h | 29 +++++++ 2 files changed, 156 insertions(+), 90 deletions(-) diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index ff27c7b40..762683782 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -55,8 +55,8 @@ public: { } - WaveCache(int len_, double pixelsPerSecond, double rate_, double t0) - : dirty(-1) + WaveCache(int len_, double pixelsPerSecond, double rate_, double t0, int dirty_) + : dirty(dirty_) , len(len_) , start(t0) , pps(pixelsPerSecond) @@ -497,110 +497,137 @@ fillWhere(std::vector &where, int len, double bias, double correcti bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, double pixelsPerSecond, bool &isLoadingOD) { - int numPixels = display.width; + const bool allocated = (display.where != 0); - ODLocker locker(mWaveCacheMutex); + const int numPixels = display.width; - const double tstep = 1.0 / pixelsPerSecond; - const double samplesPerPixel = mRate * tstep; + int p0 = 0; // least column requiring computation + int p1 = numPixels; // greatest column requiring computation, plus one - // Make a tolerant comparison of the pps values in this wise: - // accumulated difference of times over the number of pixels is less than - // a sample period. - const bool ppsMatch = mWaveCache && - (fabs(tstep - 1.0 / mWaveCache->pps) * numPixels < (1.0 / mRate)); + float *min; + float *max; + float *rms; + int *bl; + std::vector *pWhere; - const bool match = - mWaveCache && - ppsMatch && - mWaveCache->len > 0 && - mWaveCache->dirty == mDirty; - - if (match && - mWaveCache->start == t0 && - mWaveCache->len >= numPixels) { - mWaveCache->LoadInvalidRegions(mSequence, true); - mWaveCache->ClearInvalidRegions(); - - // 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; + if (allocated) { + // assume ownWhere is filled. + min = &display.min[0]; + max = &display.max[0]; + rms = &display.rms[0]; + bl = &display.bl[0]; + pWhere = &display.ownWhere; } + else { + // Lock the list of invalid regions + ODLocker locker(mWaveCacheMutex); - std::auto_ptr oldCache(mWaveCache); - mWaveCache = 0; + const double tstep = 1.0 / pixelsPerSecond; + const double samplesPerPixel = mRate * tstep; - int oldX0 = 0; - double correction = 0.0; + // Make a tolerant comparison of the pps values in this wise: + // accumulated difference of times over the number of pixels is less than + // a sample period. + const bool ppsMatch = mWaveCache && + (fabs(tstep - 1.0 / mWaveCache->pps) * numPixels < (1.0 / mRate)); - 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) - ); - } + const bool match = + mWaveCache && + ppsMatch && + mWaveCache->len > 0 && + mWaveCache->dirty == mDirty; - if (!(copyEnd > copyBegin)) - oldCache.reset(0); + if (match && + mWaveCache->start == t0 && + mWaveCache->len >= numPixels) { + mWaveCache->LoadInvalidRegions(mSequence, true); + mWaveCache->ClearInvalidRegions(); - 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 &where = mWaveCache->where; + // 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; + } - fillWhere(where, numPixels, 0.0, correction, - t0, mRate, samplesPerPixel); + std::auto_ptr oldCache(mWaveCache); + mWaveCache = 0; - // The range of pixels we must fetch from the Sequence: - const int p0 = (copyBegin > 0) ? 0 : copyEnd; - int p1 = (copyEnd >= numPixels) ? copyBegin : numPixels; + 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); - // Optimization: if the old cache is good and overlaps - // with the current one, re-use as much of the cache as - // possible + mWaveCache = new WaveCache(numPixels, pixelsPerSecond, mRate, t0, mDirty); + min = &mWaveCache->min[0]; + max = &mWaveCache->max[0]; + rms = &mWaveCache->rms[0]; + bl = &mWaveCache->bl[0]; + pWhere = &mWaveCache->where; - if (oldCache.get()) { + fillWhere(*pWhere, numPixels, 0.0, correction, + t0, mRate, samplesPerPixel); - //TODO: only load inval regions if - //necessary. (usually is the case, so no rush.) - //also, we should be updating the NEW cache, but here we are patching the old one up. - oldCache->LoadInvalidRegions(mSequence, false); - oldCache->ClearInvalidRegions(); + // The range of pixels we must fetch from the Sequence: + p0 = (copyBegin > 0) ? 0 : copyEnd; + p1 = (copyEnd >= numPixels) ? copyBegin : numPixels; - // 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)); + // 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()) { + + //TODO: only load inval regions if + //necessary. (usually is the case, so no rush.) + //also, we should be updating the NEW cache, but here we are patching the old one up. + oldCache->LoadInvalidRegions(mSequence, false); + oldCache->ClearInvalidRegions(); + + // 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) { + // Cache was not used or did not satisfy the whole request + std::vector &where = *pWhere; /* handle values in the append buffer */ int numSamples = mSequence->GetNumSamples(); int a; - for(a = p0; a < p1; ++a) - if (where[a+1] > numSamples) - break; + // Not all of the required columns might be in the sequence. + // Some might be in the append buffer. + for (a = p0; a < p1; ++a) { + if (where[a + 1] > numSamples) + break; + } + + // Handle the columns that land in the append buffer. //compute the values that are outside the overlap from scratch. if (a < p1) { int i; @@ -611,7 +638,7 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, sampleCount left; left = where[i] - numSamples; sampleCount right; - right = where[i+1] - numSamples; + right = where[i + 1] - numSamples; //wxCriticalSectionLocker locker(mAppendCriticalSection); @@ -664,6 +691,8 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, p1 = a; } + // Done with append buffer, now fetch the rest of the cache miss + // from the sequence if (p1 > p0) { if (!mSequence->GetWaveDisplay(&min[p0], &max[p0], @@ -678,15 +707,23 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0, } } - mWaveCache->dirty = mDirty; + //find the number of OD pixels - the only way to do this is by recounting + if (!allocated) { + // Now report the results + display.min = min; + display.max = max; + display.rms = rms; + display.bl = bl; + display.where = &(*pWhere)[0]; + isLoadingOD = mWaveCache->numODPixels > 0; + } + else { + using namespace std; + isLoadingOD = + count_if(display.ownBl.begin(), display.ownBl.end(), + bind2nd(less(), 0)) > 0; + } - // 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; } diff --git a/src/WaveClip.h b/src/WaveClip.h index 1f55bbf55..07bd5230b 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -151,6 +151,8 @@ class WaveClip; WX_DECLARE_USER_EXPORTED_LIST(WaveClip, WaveClipList, AUDACITY_DLL_API); WX_DEFINE_USER_EXPORTED_ARRAY_PTR(WaveClip*, WaveClipArray, class AUDACITY_DLL_API); +// A bundle of arrays needed for drawing waveforms. The object may or may not +// own the storage for those arrays. If it does, it destroys them. class WaveDisplay { public: @@ -159,11 +161,38 @@ public: float *min, *max, *rms; int* bl; + std::vector ownWhere; + std::vector ownMin, ownMax, ownRms; + std::vector ownBl; + +public: WaveDisplay(int w) : width(w), where(0), min(0), max(0), rms(0), bl(0) { } + // Create "own" arrays. + void Allocate() + { + ownWhere.resize(width + 1); + ownMin.resize(width); + ownMax.resize(width); + ownRms.resize(width); + ownBl.resize(width); + + where = &ownWhere[0]; + if (width > 0) { + min = &ownMin[0]; + max = &ownMax[0]; + rms = &ownRms[0]; + bl = &ownBl[0]; + } + else { + min = max = rms = 0; + bl = 0; + } + } + ~WaveDisplay() { }