mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-28 14:18:41 +02:00
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)
|
WaveCache(int len_, double pixelsPerSecond, double rate_, double t0, int dirty_)
|
||||||
: dirty(-1)
|
: dirty(dirty_)
|
||||||
, len(len_)
|
, len(len_)
|
||||||
, start(t0)
|
, start(t0)
|
||||||
, pps(pixelsPerSecond)
|
, pps(pixelsPerSecond)
|
||||||
@ -497,110 +497,137 @@ fillWhere(std::vector<sampleCount> &where, int len, double bias, double correcti
|
|||||||
bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
||||||
double pixelsPerSecond, bool &isLoadingOD)
|
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;
|
int p0 = 0; // least column requiring computation
|
||||||
const double samplesPerPixel = mRate * tstep;
|
int p1 = numPixels; // greatest column requiring computation, plus one
|
||||||
|
|
||||||
// Make a tolerant comparison of the pps values in this wise:
|
float *min;
|
||||||
// accumulated difference of times over the number of pixels is less than
|
float *max;
|
||||||
// a sample period.
|
float *rms;
|
||||||
const bool ppsMatch = mWaveCache &&
|
int *bl;
|
||||||
(fabs(tstep - 1.0 / mWaveCache->pps) * numPixels < (1.0 / mRate));
|
std::vector<sampleCount> *pWhere;
|
||||||
|
|
||||||
const bool match =
|
if (allocated) {
|
||||||
mWaveCache &&
|
// assume ownWhere is filled.
|
||||||
ppsMatch &&
|
min = &display.min[0];
|
||||||
mWaveCache->len > 0 &&
|
max = &display.max[0];
|
||||||
mWaveCache->dirty == mDirty;
|
rms = &display.rms[0];
|
||||||
|
bl = &display.bl[0];
|
||||||
if (match &&
|
pWhere = &display.ownWhere;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Lock the list of invalid regions
|
||||||
|
ODLocker locker(mWaveCacheMutex);
|
||||||
|
|
||||||
std::auto_ptr<WaveCache> oldCache(mWaveCache);
|
const double tstep = 1.0 / pixelsPerSecond;
|
||||||
mWaveCache = 0;
|
const double samplesPerPixel = mRate * tstep;
|
||||||
|
|
||||||
int oldX0 = 0;
|
// Make a tolerant comparison of the pps values in this wise:
|
||||||
double correction = 0.0;
|
// 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;
|
const bool match =
|
||||||
if (match) {
|
mWaveCache &&
|
||||||
findCorrection(oldCache->where, oldCache->len, numPixels,
|
ppsMatch &&
|
||||||
t0, mRate, samplesPerPixel,
|
mWaveCache->len > 0 &&
|
||||||
oldX0, correction);
|
mWaveCache->dirty == mDirty;
|
||||||
// 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))
|
if (match &&
|
||||||
oldCache.reset(0);
|
mWaveCache->start == t0 &&
|
||||||
|
mWaveCache->len >= numPixels) {
|
||||||
|
mWaveCache->LoadInvalidRegions(mSequence, true);
|
||||||
|
mWaveCache->ClearInvalidRegions();
|
||||||
|
|
||||||
mWaveCache = new WaveCache(numPixels, pixelsPerSecond, mRate, t0);
|
// Satisfy the request completely from the cache
|
||||||
float *const min = &mWaveCache->min[0];
|
display.min = &mWaveCache->min[0];
|
||||||
float *const max = &mWaveCache->max[0];
|
display.max = &mWaveCache->max[0];
|
||||||
float *const rms = &mWaveCache->rms[0];
|
display.rms = &mWaveCache->rms[0];
|
||||||
int *const bl = &mWaveCache->bl[0];
|
display.bl = &mWaveCache->bl[0];
|
||||||
std::vector<sampleCount> &where = mWaveCache->where;
|
display.where = &mWaveCache->where[0];
|
||||||
|
isLoadingOD = mWaveCache->numODPixels > 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
fillWhere(where, numPixels, 0.0, correction,
|
std::auto_ptr<WaveCache> oldCache(mWaveCache);
|
||||||
t0, mRate, samplesPerPixel);
|
mWaveCache = 0;
|
||||||
|
|
||||||
// The range of pixels we must fetch from the Sequence:
|
int oldX0 = 0;
|
||||||
const int p0 = (copyBegin > 0) ? 0 : copyEnd;
|
double correction = 0.0;
|
||||||
int p1 = (copyEnd >= numPixels) ? copyBegin : numPixels;
|
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
|
mWaveCache = new WaveCache(numPixels, pixelsPerSecond, mRate, t0, mDirty);
|
||||||
// with the current one, re-use as much of the cache as
|
min = &mWaveCache->min[0];
|
||||||
// possible
|
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
|
// The range of pixels we must fetch from the Sequence:
|
||||||
//necessary. (usually is the case, so no rush.)
|
p0 = (copyBegin > 0) ? 0 : copyEnd;
|
||||||
//also, we should be updating the NEW cache, but here we are patching the old one up.
|
p1 = (copyEnd >= numPixels) ? copyBegin : numPixels;
|
||||||
oldCache->LoadInvalidRegions(mSequence, false);
|
|
||||||
oldCache->ClearInvalidRegions();
|
|
||||||
|
|
||||||
// Copy what we can from the old cache.
|
// Optimization: if the old cache is good and overlaps
|
||||||
const int length = copyEnd - copyBegin;
|
// with the current one, re-use as much of the cache as
|
||||||
const size_t sizeFloats = length * sizeof(float);
|
// possible
|
||||||
const int srcIdx = copyBegin + oldX0;
|
|
||||||
memcpy(&min[copyBegin], &oldCache->min[srcIdx], sizeFloats);
|
if (oldCache.get()) {
|
||||||
memcpy(&max[copyBegin], &oldCache->max[srcIdx], sizeFloats);
|
|
||||||
memcpy(&rms[copyBegin], &oldCache->rms[srcIdx], sizeFloats);
|
//TODO: only load inval regions if
|
||||||
memcpy(&bl[copyBegin], &oldCache->bl[srcIdx], length * sizeof(int));
|
//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) {
|
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 */
|
/* handle values in the append buffer */
|
||||||
|
|
||||||
int numSamples = mSequence->GetNumSamples();
|
int numSamples = mSequence->GetNumSamples();
|
||||||
int a;
|
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.
|
//compute the values that are outside the overlap from scratch.
|
||||||
if (a < p1) {
|
if (a < p1) {
|
||||||
int i;
|
int i;
|
||||||
@ -611,7 +638,7 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
|||||||
sampleCount left;
|
sampleCount left;
|
||||||
left = where[i] - numSamples;
|
left = where[i] - numSamples;
|
||||||
sampleCount right;
|
sampleCount right;
|
||||||
right = where[i+1] - numSamples;
|
right = where[i + 1] - numSamples;
|
||||||
|
|
||||||
//wxCriticalSectionLocker locker(mAppendCriticalSection);
|
//wxCriticalSectionLocker locker(mAppendCriticalSection);
|
||||||
|
|
||||||
@ -664,6 +691,8 @@ bool WaveClip::GetWaveDisplay(WaveDisplay &display, double t0,
|
|||||||
p1 = a;
|
p1 = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Done with append buffer, now fetch the rest of the cache miss
|
||||||
|
// from the sequence
|
||||||
if (p1 > p0) {
|
if (p1 > p0) {
|
||||||
if (!mSequence->GetWaveDisplay(&min[p0],
|
if (!mSequence->GetWaveDisplay(&min[p0],
|
||||||
&max[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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +151,8 @@ class WaveClip;
|
|||||||
WX_DECLARE_USER_EXPORTED_LIST(WaveClip, WaveClipList, AUDACITY_DLL_API);
|
WX_DECLARE_USER_EXPORTED_LIST(WaveClip, WaveClipList, AUDACITY_DLL_API);
|
||||||
WX_DEFINE_USER_EXPORTED_ARRAY_PTR(WaveClip*, WaveClipArray, class 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
|
class WaveDisplay
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -159,11 +161,38 @@ public:
|
|||||||
float *min, *max, *rms;
|
float *min, *max, *rms;
|
||||||
int* bl;
|
int* bl;
|
||||||
|
|
||||||
|
std::vector<sampleCount> ownWhere;
|
||||||
|
std::vector<float> ownMin, ownMax, ownRms;
|
||||||
|
std::vector<int> ownBl;
|
||||||
|
|
||||||
|
public:
|
||||||
WaveDisplay(int w)
|
WaveDisplay(int w)
|
||||||
: width(w), where(0), min(0), max(0), rms(0), bl(0)
|
: 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()
|
~WaveDisplay()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user