WaveDisplay may or may not manage its own memory.
This commit is contained in:
parent
c14b326913
commit
8664c877ba
217
src/WaveClip.cpp
217
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<sampleCount> &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<sampleCount> *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<WaveCache> 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<sampleCount> &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<WaveCache> 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<sampleCount> &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<int>(), 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<sampleCount> ownWhere;
|
||||
std::vector<float> ownMin, ownMax, ownRms;
|
||||
std::vector<int> 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()
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user