mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-17 08:30:06 +02:00
(bug 451, p2)
Correct Sequence::ConvertToSampleFormat() errors resulting in wrong block file sizes, per offline discussions with Martyn and James. In WaveClip::ConvertToSampleFormat(), distinguish between failure and no change. Changed deprecated calls to wxArray::Count() to GetCount(), In Sequence::Blockify(), no reason to call Alloc() if we know we have no samples, so rearranged that code.
This commit is contained in:
parent
df53d2de52
commit
2f043dfb0f
169
src/Sequence.cpp
169
src/Sequence.cpp
@ -86,7 +86,7 @@ Sequence::Sequence(const Sequence &orig, DirManager *projDirManager)
|
||||
|
||||
Sequence::~Sequence()
|
||||
{
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++) {
|
||||
for (unsigned int i = 0; i < mBlock->GetCount(); i++) {
|
||||
if (mBlock->Item(i)->f)
|
||||
mDirManager->Deref(mBlock->Item(i)->f);
|
||||
delete mBlock->Item(i);
|
||||
@ -108,7 +108,7 @@ sampleCount Sequence::GetIdealBlockSize() const
|
||||
|
||||
bool Sequence::Lock()
|
||||
{
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++)
|
||||
for (unsigned int i = 0; i < mBlock->GetCount(); i++)
|
||||
mBlock->Item(i)->f->Lock();
|
||||
|
||||
return true;
|
||||
@ -116,7 +116,7 @@ bool Sequence::Lock()
|
||||
|
||||
bool Sequence::CloseLock()
|
||||
{
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++)
|
||||
for (unsigned int i = 0; i < mBlock->GetCount(); i++)
|
||||
mBlock->Item(i)->f->CloseLock();
|
||||
|
||||
return true;
|
||||
@ -124,7 +124,7 @@ bool Sequence::CloseLock()
|
||||
|
||||
bool Sequence::Unlock()
|
||||
{
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++)
|
||||
for (unsigned int i = 0; i < mBlock->GetCount(); i++)
|
||||
mBlock->Item(i)->f->Unlock();
|
||||
|
||||
return true;
|
||||
@ -137,59 +137,126 @@ sampleFormat Sequence::GetSampleFormat() const
|
||||
|
||||
bool Sequence::SetSampleFormat(sampleFormat format)
|
||||
{
|
||||
if (mBlock->Count() > 0 || mNumSamples > 0)
|
||||
if (mBlock->GetCount() > 0 || mNumSamples > 0)
|
||||
return false;
|
||||
|
||||
mSampleFormat = format;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sequence::ConvertToSampleFormat(sampleFormat format)
|
||||
bool Sequence::ConvertToSampleFormat(sampleFormat format, bool* pbChanged)
|
||||
{
|
||||
wxASSERT(pbChanged);
|
||||
*pbChanged = false;
|
||||
|
||||
// Caller should check this no-change case before calling; we ignore it here.
|
||||
if (format == mSampleFormat)
|
||||
return true;
|
||||
|
||||
if (mBlock->Count() == 0) {
|
||||
if (mBlock->GetCount() == 0)
|
||||
{
|
||||
mSampleFormat = format;
|
||||
*pbChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
sampleFormat oldFormat = mSampleFormat;
|
||||
mSampleFormat = format;
|
||||
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++) {
|
||||
SeqBlock *b = mBlock->Item(i);
|
||||
BlockFile *oldBlock = b->f;
|
||||
sampleCount len = b->f->GetLength();
|
||||
wxASSERT(len <= mMaxSamples); // FIX-ME: Want to enforce mMaxSamples in this case, or adjust it?
|
||||
sampleCount oldMaxSamples = mMaxSamples;
|
||||
// These are the same calculations as in the constructor.
|
||||
mMinSamples = sMaxDiskBlockSize / SAMPLE_SIZE(mSampleFormat) / 2;
|
||||
mMaxSamples = mMinSamples * 2;
|
||||
|
||||
// FIX-ME: So we do nothing if the block is an alias? Shouldn't the user be alerted?
|
||||
if (!oldBlock->IsAlias()) {
|
||||
BlockFile *newBlock;
|
||||
BlockArray* pNewBlockArray = new BlockArray();
|
||||
// Use the ratio of old to new mMaxSamples to make a reasonable guess at allocation.
|
||||
pNewBlockArray->Alloc(mBlock->GetCount() * ((float)oldMaxSamples / (float)mMaxSamples));
|
||||
|
||||
samplePtr buffer1 = NewSamples(len, oldFormat);
|
||||
samplePtr buffer2 = NewSamples(len, mSampleFormat);
|
||||
bool bSuccess = true;
|
||||
for (size_t i = 0; (i < mBlock->GetCount() && bSuccess); i++)
|
||||
{
|
||||
SeqBlock* pOldSeqBlock = mBlock->Item(i);
|
||||
BlockFile* pOldBlockFile = pOldSeqBlock->f;
|
||||
|
||||
oldBlock->ReadData(buffer1, oldFormat, 0, len);
|
||||
CopySamples(buffer1, oldFormat,
|
||||
buffer2, mSampleFormat, len);
|
||||
newBlock = mDirManager->NewSimpleBlockFile(buffer2, len, mSampleFormat);
|
||||
if (pOldBlockFile->IsAlias())
|
||||
{
|
||||
// No conversion of aliased data.
|
||||
//vvvvv Should the user be alerted, as we're not actually converting the aliased file?
|
||||
// James (2011-12-01, offlist) believes this is okay because we are assuring
|
||||
// the user we'll do the format conversion if we turn this into a non-aliased block.
|
||||
// TO-DO: Confirm that.
|
||||
pNewBlockArray->Add(pOldSeqBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
sampleCount len = pOldSeqBlock->f->GetLength();
|
||||
samplePtr bufferOld = NewSamples(len, oldFormat);
|
||||
samplePtr bufferNew = NewSamples(len, mSampleFormat);
|
||||
|
||||
mBlock->Item(i)->f = newBlock;
|
||||
mDirManager->Deref(oldBlock);
|
||||
bSuccess = (pOldBlockFile->ReadData(bufferOld, oldFormat, 0, len) > 0);
|
||||
if (!bSuccess)
|
||||
break;
|
||||
|
||||
DeleteSamples(buffer2);
|
||||
DeleteSamples(buffer1);
|
||||
CopySamples(bufferOld, oldFormat, bufferNew, mSampleFormat, len);
|
||||
|
||||
// Note this fix for http://bugzilla.audacityteam.org/show_bug.cgi?id=451,
|
||||
// using Blockify, allows (len < mMinSamples).
|
||||
// This will happen consistently when going from more bytes per sample to fewer...
|
||||
// This will create a block that's smaller than mMinSamples, which
|
||||
// shouldn't be allowed, but we agreed it's okay for now.
|
||||
//vvvvv ANSWER-ME: Does this cause any bugs, or failures on write, elsewhere?
|
||||
// If so, need to special-case (len < mMinSamples) and start combining data
|
||||
// from the old blocks... Oh no!
|
||||
|
||||
// Using Blockify will handle the cases where len > the new mMaxSamples. Previous code did not.
|
||||
BlockArray* pSplitBlockArray = Blockify(bufferNew, len);
|
||||
bSuccess = (pSplitBlockArray->GetCount() > 0);
|
||||
if (bSuccess)
|
||||
{
|
||||
for (size_t j = 0; j < pSplitBlockArray->GetCount(); j++)
|
||||
{
|
||||
pSplitBlockArray->Item(j)->start += mBlock->Item(i)->start;
|
||||
pNewBlockArray->Add(pSplitBlockArray->Item(j));
|
||||
}
|
||||
*pbChanged = true;
|
||||
}
|
||||
delete pSplitBlockArray;
|
||||
|
||||
DeleteSamples(bufferNew);
|
||||
DeleteSamples(bufferOld);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if (bSuccess)
|
||||
{
|
||||
// Invalidate all the old block files.
|
||||
for (size_t i = 0; (i < mBlock->GetCount() && bSuccess); i++)
|
||||
{
|
||||
SeqBlock* pOldSeqBlock = mBlock->Item(i);
|
||||
mDirManager->Deref(pOldSeqBlock->f);
|
||||
pOldSeqBlock->f = NULL; // ...so we don't delete the file when we delete mBlock, next.
|
||||
}
|
||||
delete mBlock;
|
||||
|
||||
// Replace with new blocks.
|
||||
mBlock = pNewBlockArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pNewBlockArray; // Failed. Throw out the scratch array.
|
||||
*pbChanged = false; // Revert overall change flag, in case we had some partial success in the loop.
|
||||
}
|
||||
|
||||
//vvvvv bSuccess &= ConsistencyCheck(wxT("Sequence::ConvertToSampleFormat()"));
|
||||
ConsistencyCheck(wxT("Sequence::ConvertToSampleFormat()"));
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
bool Sequence::GetMinMax(sampleCount start, sampleCount len,
|
||||
float * outMin, float * outMax) const
|
||||
{
|
||||
if (len == 0 || mBlock->Count() == 0) {
|
||||
if (len == 0 || mBlock->GetCount() == 0) {
|
||||
*outMin = float(0.0);
|
||||
*outMax = float(0.0);
|
||||
return true;
|
||||
@ -271,7 +338,7 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
|
||||
float * outRMS) const
|
||||
{
|
||||
wxASSERT(len <= mMaxSamples); // Vaughan, 2011-10-19
|
||||
if (len == 0 || mBlock->Count() == 0) {
|
||||
if (len == 0 || mBlock->GetCount() == 0) {
|
||||
*outRMS = float(0.0);
|
||||
return true;
|
||||
}
|
||||
@ -338,7 +405,7 @@ bool Sequence::Copy(sampleCount s0, sampleCount s1, Sequence **dest)
|
||||
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0)
|
||||
return false;
|
||||
|
||||
int numBlocks = mBlock->Count();
|
||||
int numBlocks = mBlock->GetCount();
|
||||
int b0 = FindBlock(s0);
|
||||
int b1 = FindBlock(s1);
|
||||
|
||||
@ -426,14 +493,14 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
||||
|
||||
BlockArray *srcBlock = src->mBlock;
|
||||
sampleCount addedLen = src->mNumSamples;
|
||||
unsigned int srcNumBlocks = srcBlock->Count();
|
||||
unsigned int srcNumBlocks = srcBlock->GetCount();
|
||||
int sampleSize = SAMPLE_SIZE(mSampleFormat);
|
||||
|
||||
if (addedLen == 0 || srcNumBlocks == 0)
|
||||
return true;
|
||||
|
||||
unsigned int b = FindBlock(s);
|
||||
unsigned int numBlocks = mBlock->Count();
|
||||
unsigned int numBlocks = mBlock->GetCount();
|
||||
|
||||
if (numBlocks == 0 ||
|
||||
(s == mNumSamples && mBlock->Item(numBlocks-1)->f->GetLength() >= mMinSamples)) {
|
||||
@ -523,7 +590,7 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
||||
splitBlock->f->GetLength() - splitPoint);
|
||||
|
||||
BlockArray *split = Blockify(sumBuffer, sum);
|
||||
for (i = 0; i < split->Count(); i++) {
|
||||
for (i = 0; i < split->GetCount(); i++) {
|
||||
split->Item(i)->start += splitBlock->start;
|
||||
newBlock->Add(split->Item(i));
|
||||
newNumBlocks++;
|
||||
@ -548,7 +615,7 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
||||
mSampleFormat, 0, srcFirstTwoLen);
|
||||
|
||||
BlockArray *split = Blockify(leftBuffer, leftLen);
|
||||
for (i = 0; i < split->Count(); i++) {
|
||||
for (i = 0; i < split->GetCount(); i++) {
|
||||
split->Item(i)->start += splitBlock->start;
|
||||
newBlock->Add(split->Item(i));
|
||||
newNumBlocks++;
|
||||
@ -727,7 +794,7 @@ bool Sequence::AppendBlock(SeqBlock * b)
|
||||
unsigned int Sequence::GetODFlags()
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
for (unsigned int i = 0; i < mBlock->Count(); i++){
|
||||
for (unsigned int i = 0; i < mBlock->GetCount(); i++){
|
||||
if(!mBlock->Item(i)->f->IsDataAvailable())
|
||||
ret = ret|((ODDecodeBlockFile*)mBlock->Item(i)->f)->GetDecodeType();
|
||||
else if(!mBlock->Item(i)->f->IsSummaryAvailable())
|
||||
@ -743,7 +810,7 @@ sampleCount Sequence::GetBestBlockSize(sampleCount start) const
|
||||
// sample. The value returned will always be nonzero and will be no larger
|
||||
// than the value of GetMaxBlockSize();
|
||||
int b = FindBlock(start);
|
||||
int numBlocks = mBlock->Count();
|
||||
int numBlocks = mBlock->GetCount();
|
||||
|
||||
sampleCount result = (mBlock->Item(b)->start + mBlock->Item(b)->f->GetLength() - start);
|
||||
|
||||
@ -882,11 +949,11 @@ void Sequence::HandleXMLEndTag(const wxChar *tag)
|
||||
// Make sure that the sequence is valid.
|
||||
// First, replace missing blockfiles with SilentBlockFiles
|
||||
unsigned int b;
|
||||
for (b = 0; b < mBlock->Count(); b++) {
|
||||
for (b = 0; b < mBlock->GetCount(); b++) {
|
||||
if (!mBlock->Item(b)->f) {
|
||||
sampleCount len;
|
||||
|
||||
if (b < mBlock->Count()-1)
|
||||
if (b < mBlock->GetCount()-1)
|
||||
len = mBlock->Item(b+1)->start - mBlock->Item(b)->start;
|
||||
else
|
||||
len = mNumSamples - mBlock->Item(b)->start;
|
||||
@ -910,7 +977,7 @@ void Sequence::HandleXMLEndTag(const wxChar *tag)
|
||||
|
||||
// Next, make sure that start times and lengths are consistent
|
||||
sampleCount numSamples = 0;
|
||||
for (b = 0; b < mBlock->Count(); b++) {
|
||||
for (b = 0; b < mBlock->GetCount(); b++) {
|
||||
if (mBlock->Item(b)->start != numSamples) {
|
||||
wxString sFileAndExtension = mBlock->Item(b)->f->GetFileName().GetFullName();
|
||||
if (sFileAndExtension.IsEmpty())
|
||||
@ -957,7 +1024,7 @@ void Sequence::WriteXML(XMLWriter &xmlFile)
|
||||
xmlFile.WriteAttr(wxT("sampleformat"), mSampleFormat);
|
||||
xmlFile.WriteAttr(wxT("numsamples"), mNumSamples);
|
||||
|
||||
for (b = 0; b < mBlock->Count(); b++) {
|
||||
for (b = 0; b < mBlock->GetCount(); b++) {
|
||||
SeqBlock *bb = mBlock->Item(b);
|
||||
|
||||
// See http://bugzilla.audacityteam.org/show_bug.cgi?id=451.
|
||||
@ -1007,7 +1074,7 @@ int Sequence::FindBlock(sampleCount pos) const
|
||||
{
|
||||
wxASSERT(pos >= 0 && pos <= mNumSamples);
|
||||
|
||||
int numBlocks = mBlock->Count();
|
||||
int numBlocks = mBlock->GetCount();
|
||||
|
||||
if (pos == 0)
|
||||
return 0;
|
||||
@ -1329,7 +1396,7 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
|
||||
|
||||
srcX += num * divisor;
|
||||
|
||||
if (b >= mBlock->Count())
|
||||
if (b >= mBlock->GetCount())
|
||||
break;
|
||||
|
||||
srcX = mBlock->Item(b)->start;
|
||||
@ -1364,7 +1431,7 @@ bool Sequence::GetWaveDisplay(float *min, float *max, float *rms,int* bl,
|
||||
|
||||
sampleCount Sequence::GetIdealAppendLen()
|
||||
{
|
||||
int numBlocks = mBlock->Count();
|
||||
int numBlocks = mBlock->GetCount();
|
||||
sampleCount max = GetMaxBlockSize();
|
||||
sampleCount lastBlockLen;
|
||||
|
||||
@ -1386,7 +1453,7 @@ bool Sequence::Append(samplePtr buffer, sampleFormat format,
|
||||
return false;
|
||||
|
||||
// If the last block is not full, we need to add samples to it
|
||||
int numBlocks = mBlock->Count();
|
||||
int numBlocks = mBlock->GetCount();
|
||||
if (numBlocks > 0 && mBlock->Item(numBlocks - 1)->f->GetLength() < mMinSamples) {
|
||||
SeqBlock *lastBlock = mBlock->Item(numBlocks - 1);
|
||||
sampleCount addLen;
|
||||
@ -1476,11 +1543,11 @@ bool Sequence::Append(samplePtr buffer, sampleFormat format,
|
||||
BlockArray *Sequence::Blockify(samplePtr buffer, sampleCount len)
|
||||
{
|
||||
BlockArray *list = new BlockArray();
|
||||
list->Alloc(10);
|
||||
|
||||
if (len == 0)
|
||||
if (len <= 0)
|
||||
return list;
|
||||
|
||||
list->Alloc(10);
|
||||
|
||||
int num = (len + (mMaxSamples - 1)) / mMaxSamples;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
@ -1512,7 +1579,7 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
|
||||
//both functions,
|
||||
LockDeleteUpdateMutex();
|
||||
|
||||
unsigned int numBlocks = mBlock->Count();
|
||||
unsigned int numBlocks = mBlock->GetCount();
|
||||
unsigned int newNumBlocks = 0;
|
||||
|
||||
unsigned int b0 = FindBlock(start);
|
||||
@ -1607,7 +1674,7 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
|
||||
BlockArray *split = Blockify(sumBuffer, sum);
|
||||
split->Item(0)->start += prepreBlock->start;
|
||||
newBlock->Item(b0 - 1) = split->Item(0);
|
||||
for (i = 1; i < split->Count(); i++) {
|
||||
for (i = 1; i < split->GetCount(); i++) {
|
||||
split->Item(i)->start += prepreBlock->start;
|
||||
newBlock->Add(split->Item(i));
|
||||
newNumBlocks++;
|
||||
@ -1678,7 +1745,7 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
|
||||
postpostBlock, 0, postpostLen);
|
||||
|
||||
BlockArray *split = Blockify(sumBuffer, sum);
|
||||
for (i = 0; i < split->Count(); i++) {
|
||||
for (i = 0; i < split->GetCount(); i++) {
|
||||
split->Item(i)->start += start;
|
||||
newBlock->Add(split->Item(i));
|
||||
newNumBlocks++;
|
||||
@ -1722,7 +1789,7 @@ bool Sequence::ConsistencyCheck(const wxChar *whereStr)
|
||||
{
|
||||
unsigned int i;
|
||||
sampleCount pos = 0;
|
||||
unsigned int numBlocks = mBlock->Count();
|
||||
unsigned int numBlocks = mBlock->GetCount();
|
||||
bool bError = false;
|
||||
|
||||
for (i = 0; i < numBlocks; i++) {
|
||||
@ -1750,7 +1817,7 @@ void Sequence::DebugPrintf(wxString *dest)
|
||||
unsigned int i;
|
||||
int pos = 0;
|
||||
|
||||
for (i = 0; i < mBlock->Count(); i++) {
|
||||
for (i = 0; i < mBlock->GetCount(); i++) {
|
||||
*dest += wxString::Format
|
||||
(wxT(" Block %3d: start %8d len %8d refs %d %s"),
|
||||
i,
|
||||
|
@ -136,7 +136,7 @@ class Sequence: public XMLTagHandler {
|
||||
|
||||
sampleFormat GetSampleFormat() const;
|
||||
bool SetSampleFormat(sampleFormat format);
|
||||
bool ConvertToSampleFormat(sampleFormat format);
|
||||
bool ConvertToSampleFormat(sampleFormat format, bool* pbChanged);
|
||||
|
||||
//
|
||||
// Retrieving summary info
|
||||
|
@ -993,10 +993,11 @@ bool WaveClip::GetRMS(float *rms, double t0,
|
||||
|
||||
void WaveClip::ConvertToSampleFormat(sampleFormat format)
|
||||
{
|
||||
bool bResult = mSequence->ConvertToSampleFormat(format);
|
||||
if (bResult)
|
||||
bool bChanged;
|
||||
bool bResult = mSequence->ConvertToSampleFormat(format, &bChanged);
|
||||
if (bResult && bChanged)
|
||||
MarkChanged();
|
||||
wxASSERT(bResult);
|
||||
wxASSERT(bResult); // TO-DO: Throw an actual error.
|
||||
}
|
||||
|
||||
void WaveClip::UpdateEnvelopeTrackLen()
|
||||
|
Loading…
x
Reference in New Issue
Block a user