BlockArray *WaveTrack::Blockify(sampleType * buffer, sampleCount len) { BlockArray *list = new BlockArray(); list->Alloc(10); if (len == 0) return list; int num = (len + (maxSamples - 1)) / maxSamples; for (int i = 0; i < num; i++) { WaveBlock *b = NewInitedWaveBlock(); b->start = i * len / num; b->len = ((i + 1) * len / num) - b->start; FirstWrite(&buffer[b->start], b, b->len); list->Add(b); } return list; }
BlockArray *Sequence::Blockify(samplePtr buffer, sampleCount len) { BlockArray *list = new BlockArray(); list->Alloc(10); if (len == 0) return list; int num = (len + (mMaxSamples - 1)) / mMaxSamples; for (int i = 0; i < num; i++) { SeqBlock *b = new SeqBlock(); b->start = i * len / num; int newLen = ((i + 1) * len / num) - b->start; samplePtr bufStart = buffer + (b->start * SAMPLE_SIZE(mSampleFormat)); b->f = mDirManager->NewSimpleBlockFile(bufStart, newLen, mSampleFormat); list->Add(b); } return list; }
BlockArray *Sequence::Blockify(samplePtr buffer, sampleCount len) { BlockArray *list = new BlockArray(); list->Alloc(10); if (len == 0) return list; int num = (len + (mMaxSamples - 1)) / mMaxSamples; for (int i = 0; i < num; i++) { SeqBlock *b = NewInitedSeqBlock(); b->start = i * len / num; b->len = ((i + 1) * len / num) - b->start; FirstWrite(buffer + (b->start * SAMPLE_SIZE(mSampleFormat)), b, b->len); list->Add(b); } return list; }
bool Sequence::Paste(sampleCount s, const Sequence *src) { if (s < 0) s = 0; if (s >= mNumSamples) s = mNumSamples; // Quick check to make sure that it doesn't overflow if (((double)mNumSamples) + ((double)src->mNumSamples) > wxLL(9223372036854775807)) return false; BlockArray *srcBlock = src->mBlock; sampleCount addedLen = src->mNumSamples; unsigned int srcNumBlocks = srcBlock->Count(); int sampleSize = SAMPLE_SIZE(mSampleFormat); if (addedLen == 0 || srcNumBlocks == 0) return true; unsigned int b = FindBlock(s); unsigned int numBlocks = mBlock->Count(); if (numBlocks == 0 || (s == mNumSamples && mBlock->Item(numBlocks-1)->f->GetLength() >= mMinSamples)) { // Special case: this track is currently empty, or it's safe to append // onto the end because the current last block is longer than the // minimum size for (unsigned int i = 0; i < srcNumBlocks; i++) AppendBlock(srcBlock->Item(i)); return ConsistencyCheck(wxT("Paste branch one")); } if (b >= 0 && b < numBlocks && mBlock->Item(b)->f->GetLength() + addedLen < mMaxSamples) { // Special case: we can fit all of the new samples inside of // one block! samplePtr buffer = NewSamples(mMaxSamples, mSampleFormat); int splitPoint = s - mBlock->Item(b)->start; Read(buffer, mSampleFormat, mBlock->Item(b), 0, splitPoint); src->Get(buffer + splitPoint*sampleSize, mSampleFormat, 0, addedLen); Read(buffer + (splitPoint + addedLen)*sampleSize, mSampleFormat, mBlock->Item(b), splitPoint, mBlock->Item(b)->f->GetLength() - splitPoint); SeqBlock *largerBlock = new SeqBlock(); largerBlock->start = mBlock->Item(b)->start; int largerBlockLen = mBlock->Item(b)->f->GetLength() + addedLen; if (largerBlockLen > mMaxSamples) largerBlockLen = mMaxSamples; // Prevent overruns, per NGS report for UmixIt. largerBlock->f = mDirManager->NewSimpleBlockFile(buffer, largerBlockLen, mSampleFormat); mDirManager->Deref(mBlock->Item(b)->f); delete mBlock->Item(b); mBlock->Item(b) = largerBlock; for (unsigned int i = b + 1; i < numBlocks; i++) mBlock->Item(i)->start += addedLen; mNumSamples += addedLen; DeleteSamples(buffer); return ConsistencyCheck(wxT("Paste branch two")); } // Case two: if we are inserting four or fewer blocks, // it's simplest to just lump all the data together // into one big block along with the split block, // then resplit it all unsigned int i; BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks + srcNumBlocks + 2); int newNumBlocks = 0; for (i = 0; i < b; i++) { newBlock->Add(mBlock->Item(i)); newNumBlocks++; } SeqBlock *splitBlock = mBlock->Item(b); sampleCount splitLen = mBlock->Item(b)->f->GetLength(); int splitPoint = s - splitBlock->start; if (srcNumBlocks <= 4) { sampleCount sum = splitLen + addedLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); Read(sumBuffer, mSampleFormat, splitBlock, 0, splitPoint); src->Get(sumBuffer + splitPoint * sampleSize, mSampleFormat, 0, addedLen); Read(sumBuffer + (splitPoint + addedLen) * sampleSize, mSampleFormat, splitBlock, splitPoint, splitBlock->f->GetLength() - splitPoint); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(sumBuffer); } else { // The final case is that we're inserting at least five blocks. // We divide these into three groups: the first two get merged // with the first half of the split block, the middle ones get // copied in as is, and the last two get merged with the last // half of the split block. sampleCount srcFirstTwoLen = srcBlock->Item(0)->f->GetLength() + srcBlock->Item(1)->f->GetLength(); sampleCount leftLen = splitPoint + srcFirstTwoLen; samplePtr leftBuffer = NewSamples(leftLen, mSampleFormat); Read(leftBuffer, mSampleFormat, splitBlock, 0, splitPoint); src->Get(leftBuffer + splitPoint*sampleSize, mSampleFormat, 0, srcFirstTwoLen); BlockArray *split = Blockify(leftBuffer, leftLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(leftBuffer); for (i = 2; i < srcNumBlocks - 2; i++) { SeqBlock *insertBlock = new SeqBlock(); insertBlock->start = srcBlock->Item(i)->start + s; insertBlock->f = mDirManager->CopyBlockFile(srcBlock->Item(i)->f); if (!insertBlock->f) { // TODO error: Could not paste! (Out of disk space?) return false; } newBlock->Add(insertBlock); newNumBlocks++; } sampleCount srcLastTwoLen = srcBlock->Item(srcNumBlocks - 2)->f->GetLength() + srcBlock->Item(srcNumBlocks - 1)->f->GetLength(); sampleCount rightSplit = splitBlock->f->GetLength() - splitPoint; sampleCount rightLen = rightSplit + srcLastTwoLen; samplePtr rightBuffer = NewSamples(rightLen, mSampleFormat); sampleCount lastStart = srcBlock->Item(srcNumBlocks - 2)->start; src->Get(rightBuffer, mSampleFormat, lastStart, srcLastTwoLen); Read(rightBuffer + srcLastTwoLen * sampleSize, mSampleFormat, splitBlock, splitPoint, rightSplit); sampleCount pos = s + lastStart; split = Blockify(rightBuffer, rightLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += pos; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(rightBuffer); } mDirManager->Deref(splitBlock->f); delete splitBlock; // Copy remaining blocks to new block array and // swap the new block array in for the old for (i = b + 1; i < numBlocks; i++) { mBlock->Item(i)->start += addedLen; newBlock->Add(mBlock->Item(i)); newNumBlocks++; } delete mBlock; mBlock = newBlock; mNumSamples += addedLen; return ConsistencyCheck(wxT("Paste branch three")); }
bool Sequence::Delete(sampleCount start, sampleCount len) { if (len == 0) return true; if (len < 0 || start < 0 || start >= mNumSamples) return false; //TODO: add a ref-deref mechanism to SeqBlock/BlockArray so we don't have to make this a critical section. //On-demand threads iterate over the mBlocks and the GUI thread deletes them, so for now put a mutex here over //both functions, LockDeleteUpdateMutex(); unsigned int numBlocks = mBlock->Count(); unsigned int newNumBlocks = 0; unsigned int b0 = FindBlock(start); unsigned int b1 = FindBlock(start + len - 1); int sampleSize = SAMPLE_SIZE(mSampleFormat); // Special case: if the samples to delete are all within a single // block and the resulting length is not too small, perform the // deletion within this block: if (b0 == b1 && mBlock->Item(b0)->f->GetLength() - len >= mMinSamples) { SeqBlock *b = mBlock->Item(b0); sampleCount pos = start - b->start; sampleCount newLen = b->f->GetLength() - len; samplePtr buffer = NewSamples(newLen, mSampleFormat); Read(buffer, mSampleFormat, b, 0, pos); Read(buffer + (pos * sampleSize), mSampleFormat, b, pos + len, newLen - pos); SeqBlock *newBlock = new SeqBlock(); newBlock->start = b->start; newBlock->f = mDirManager->NewSimpleBlockFile(buffer, newLen, mSampleFormat); mBlock->Item(b0) = newBlock; for (unsigned int j = b0 + 1; j < numBlocks; j++) mBlock->Item(j)->start -= len; DeleteSamples(buffer); mDirManager->Deref(b->f); delete b; mNumSamples -= len; UnlockDeleteUpdateMutex(); return ConsistencyCheck(wxT("Delete - branch one")); } // Create a new array of blocks BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks - (b1 - b0) + 2); // Copy the blocks before the deletion point over to // the new array unsigned int i; for (i = 0; i < b0; i++) { newBlock->Add(mBlock->Item(i)); newNumBlocks++; } // First grab the samples in block b0 before the deletion point // into preBuffer. If this is enough samples for its own block, // or if this would be the first block in the array, write it out. // Otherwise combine it with the previous block (splitting them // 50/50 if necessary). SeqBlock *preBlock = mBlock->Item(b0); sampleCount preBufferLen = start - preBlock->start; if (preBufferLen) { if (preBufferLen >= mMinSamples || b0 == 0) { SeqBlock *insBlock = new SeqBlock(); insBlock->start = preBlock->start; samplePtr preBuffer = NewSamples(preBufferLen, mSampleFormat); Read(preBuffer, mSampleFormat, preBlock, 0, preBufferLen); insBlock->f = mDirManager->NewSimpleBlockFile(preBuffer, preBufferLen, mSampleFormat); DeleteSamples(preBuffer); newBlock->Add(insBlock); newNumBlocks++; if (b0 != b1) { mDirManager->Deref(preBlock->f); delete preBlock; } } else { SeqBlock *prepreBlock = mBlock->Item(b0 - 1); sampleCount prepreLen = prepreBlock->f->GetLength(); sampleCount sum = prepreLen + preBufferLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); Read(sumBuffer, mSampleFormat, prepreBlock, 0, prepreLen); Read(sumBuffer + prepreLen*sampleSize, mSampleFormat, preBlock, 0, preBufferLen); 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++) { split->Item(i)->start += prepreBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(sumBuffer); mDirManager->Deref(prepreBlock->f); delete prepreBlock; if (b0 != b1) { mDirManager->Deref(preBlock->f); delete preBlock; } } } else { // The sample where we begin deletion happens to fall // right on the beginning of a block. if (b0 != b1) { mDirManager->Deref(mBlock->Item(b0)->f); delete mBlock->Item(b0); } } // Next, delete blocks strictly between b0 and b1 for (i = b0 + 1; i < b1; i++) { mDirManager->Deref(mBlock->Item(i)->f); delete mBlock->Item(i); } // Now, symmetrically, grab the samples in block b1 after the // deletion point into postBuffer. If this is enough samples // for its own block, or if this would be the last block in // the array, write it out. Otherwise combine it with the // subsequent block (splitting them 50/50 if necessary). SeqBlock *postBlock = mBlock->Item(b1); sampleCount postBufferLen = (postBlock->start + postBlock->f->GetLength()) - (start + len); if (postBufferLen) { if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) { SeqBlock *insBlock = new SeqBlock(); insBlock->start = start; samplePtr postBuffer = NewSamples(postBufferLen, mSampleFormat); sampleCount pos = (start + len) - postBlock->start; Read(postBuffer, mSampleFormat, postBlock, pos, postBufferLen); insBlock->f = mDirManager->NewSimpleBlockFile(postBuffer, postBufferLen, mSampleFormat); DeleteSamples(postBuffer); newBlock->Add(insBlock); newNumBlocks++; mDirManager->Deref(postBlock->f); delete postBlock; } else { SeqBlock *postpostBlock = mBlock->Item(b1 + 1); sampleCount postpostLen = postpostBlock->f->GetLength(); sampleCount sum = postpostLen + postBufferLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); sampleCount pos = (start + len) - postBlock->start; Read(sumBuffer, mSampleFormat, postBlock, pos, postBufferLen); Read(sumBuffer + (postBufferLen * sampleSize), mSampleFormat, postpostBlock, 0, postpostLen); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; b1++; DeleteSamples(sumBuffer); mDirManager->Deref(postpostBlock->f); delete postpostBlock; mDirManager->Deref(postBlock->f); delete postBlock; } } else { // The sample where we begin deletion happens to fall // right on the end of a block. mDirManager->Deref(mBlock->Item(b1)->f); delete mBlock->Item(b1); } // Copy the remaining blocks over from the old array for (i = b1 + 1; i < numBlocks; i++) { mBlock->Item(i)->start -= len; newBlock->Add(mBlock->Item(i)); newNumBlocks++; } // Substitute our new array for the old one delete mBlock; mBlock = newBlock; // Update total number of samples and do a consistency check. mNumSamples -= len; UnlockDeleteUpdateMutex(); return ConsistencyCheck(wxT("Delete - branch two")); }
void WaveTrack::Paste(double t, VTrack * src) { wxASSERT(src->GetKind() == WaveTrack::Wave); envelope.ExpandRegion(t, src->GetMaxLen()); #if wxUSE_THREADS wxMutexLocker lock(*blockMutex); #endif sampleCount s = (sampleCount) ((t - tOffset) * rate + 0.5); if (s < 0) s = 0; if (s >= numSamples) s = numSamples; BlockArray *srcBlock = ((WaveTrack *) src)->GetBlockArray(); int addedLen = ((WaveTrack *) src)->numSamples; int srcNumBlocks = srcBlock->Count(); if (addedLen == 0 || srcNumBlocks == 0) return; int b = FindBlock(s); int numBlocks = block->Count(); if (numBlocks == 0) { // Special case: this track is currently empty. for (int i = 0; i < srcNumBlocks; i++) AppendBlock(srcBlock->Item(i)); envelope.SetTrackLen(numSamples / rate); ConsistencyCheck("Paste branch one"); return; } if (b >= 0 && b < numBlocks && block->Item(b)->len + addedLen < maxSamples) { // Special case: we can fit all of the new samples inside of // one block! sampleType *buffer = new sampleType[maxSamples]; int splitPoint = s - block->Item(b)->start; Read(buffer, block->Item(b), 0, splitPoint); ((WaveTrack *) src)->Get(&buffer[splitPoint], 0, addedLen); Read(&buffer[splitPoint + addedLen], block->Item(b), splitPoint, block->Item(b)->len - splitPoint); WaveBlock *largerBlock = new WaveBlock(); largerBlock->start = block->Item(b)->start; largerBlock->len = block->Item(b)->len + addedLen; largerBlock->f = dirManager->NewBlockFile(); bool inited = InitBlock(largerBlock); wxASSERT(inited); FirstWrite(buffer, largerBlock, largerBlock->len); dirManager->Deref(block->Item(b)->f); delete block->Item(b); block->Item(b) = largerBlock; for (int i = b + 1; i < numBlocks; i++) block->Item(i)->start += addedLen; numSamples += addedLen; delete[]buffer; envelope.SetTrackLen(numSamples / rate); ConsistencyCheck("Paste branch two"); return; } // Case two: if we are inserting four or fewer blocks, // it's simplest to just lump all the data together // into one big block along with the split block, // then resplit it all int i; BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks + srcNumBlocks + 2); int newNumBlocks = 0; for (i = 0; i < b; i++) { newBlock->Add(block->Item(i)); newNumBlocks++; } WaveBlock *splitBlock = block->Item(b); sampleCount splitLen = block->Item(b)->len; int splitPoint = s - splitBlock->start; if (srcNumBlocks <= 4) { sampleCount sum = splitLen + addedLen; sampleType *sumBuffer = new sampleType[sum]; Read(sumBuffer, splitBlock, 0, splitPoint); ((WaveTrack *) src)->Get(&sumBuffer[splitPoint], 0, addedLen); Read(&sumBuffer[splitPoint + addedLen], splitBlock, splitPoint, splitBlock->len - splitPoint); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; delete[]sumBuffer; } else { // The final case is that we're inserting at least five blocks. // We divide these into three groups: the first two get merged // with the first half of the split block, the middle ones get // copied in as is, and the last two get merged with the last // half of the split block. sampleCount srcFirstTwoLen = srcBlock->Item(0)->len + srcBlock->Item(1)->len; sampleCount leftLen = splitPoint + srcFirstTwoLen; sampleType *leftBuffer = new sampleType[leftLen]; Read(leftBuffer, splitBlock, 0, splitPoint); ((WaveTrack *) src)->Get(&leftBuffer[splitPoint], 0, srcFirstTwoLen); BlockArray *split = Blockify(leftBuffer, leftLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; delete[]leftBuffer; for (i = 2; i < srcNumBlocks - 2; i++) { WaveBlock *insertBlock = new WaveBlock(); insertBlock->start = srcBlock->Item(i)->start + s; insertBlock->len = srcBlock->Item(i)->len; insertBlock->min = srcBlock->Item(i)->min; insertBlock->max = srcBlock->Item(i)->max; insertBlock->f = dirManager->CopyBlockFile(srcBlock->Item(i)->f); if (!insertBlock->f) { wxMessageBox("Could not paste! (Out of disk space?)"); } newBlock->Add(insertBlock); newNumBlocks++; } sampleCount srcLastTwoLen = srcBlock->Item(srcNumBlocks - 2)->len + srcBlock->Item(srcNumBlocks - 1)->len; sampleCount rightSplit = splitBlock->len - splitPoint; sampleCount rightLen = rightSplit + srcLastTwoLen; sampleType *rightBuffer = new sampleType[rightLen]; sampleCount lastStart = srcBlock->Item(srcNumBlocks - 2)->start; ((WaveTrack *) src)->Get(rightBuffer, lastStart, srcLastTwoLen); Read(&rightBuffer[srcLastTwoLen], splitBlock, splitPoint, rightSplit); sampleCount pos = s + lastStart; split = Blockify(rightBuffer, rightLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += pos; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; delete[]rightBuffer; } dirManager->Deref(splitBlock->f); delete splitBlock; // Copy remaining blocks to new block array and // swap the new block array in for the old for (i = b + 1; i < numBlocks; i++) { block->Item(i)->start += addedLen; newBlock->Add(block->Item(i)); newNumBlocks++; } delete block; block = newBlock; numSamples += addedLen; envelope.SetTrackLen(numSamples / rate); ConsistencyCheck("Paste branch three"); }
void WaveTrack::Delete(sampleCount start, sampleCount len) { if (len == 0) return; int numBlocks = block->Count(); int newNumBlocks = 0; #if wxUSE_THREADS wxMutexLocker lock(*blockMutex); #endif int b0 = FindBlock(start); int b1 = FindBlock(start + len - 1); // Special case: if the samples to delete are all within a single // block and the resulting length is not too small, perform the // deletion within this block: if (b0 == b1 && block->Item(b0)->len - len >= minSamples) { WaveBlock *b = block->Item(b0); sampleCount pos = start - b->start; sampleCount newLen = b->len - len; sampleType *buffer = new sampleType[newLen]; Read(buffer, b, 0, pos); Read(&buffer[pos], b, pos + len, newLen - pos); WaveBlock *newBlock = NewInitedWaveBlock(); newBlock->start = b->start; newBlock->len = newLen; FirstWrite(buffer, newBlock, newLen); block->Item(b0) = newBlock; for (int j = b0 + 1; j < numBlocks; j++) block->Item(j)->start -= len; delete[]buffer; dirManager->Deref(b->f); delete b; numSamples -= len; envelope.SetTrackLen(numSamples / rate); ConsistencyCheck("Delete - branch one"); return; } // Create a new array of blocks BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks - (b1 - b0) + 2); // Copy the blocks before the deletion point over to // the new array int i; for (i = 0; i < b0; i++) { newBlock->Add(block->Item(i)); newNumBlocks++; } // First grab the samples in block b0 before the deletion point // into preBuffer. If this is enough samples for its own block, // or if this would be the first block in the array, write it out. // Otherwise combine it with the previous block (splitting them // 50/50 if necessary). WaveBlock *preBlock = block->Item(b0); sampleCount preBufferLen = start - preBlock->start; if (preBufferLen) { if (preBufferLen >= minSamples || b0 == 0) { WaveBlock *insBlock = NewInitedWaveBlock(); insBlock->len = preBufferLen; insBlock->start = preBlock->start; sampleType *preBuffer = new sampleType[preBufferLen]; Read(preBuffer, preBlock, 0, preBufferLen); FirstWrite(preBuffer, insBlock, preBufferLen); delete[]preBuffer; newBlock->Add(insBlock); newNumBlocks++; if (b0 != b1) { dirManager->Deref(preBlock->f); delete preBlock; } } else { WaveBlock *prepreBlock = block->Item(b0 - 1); sampleCount prepreLen = prepreBlock->len; sampleCount sum = prepreLen + preBufferLen; sampleType *sumBuffer = new sampleType[sum]; Read(sumBuffer, prepreBlock, 0, prepreLen); Read(&sumBuffer[prepreLen], preBlock, 0, preBufferLen); 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++) { split->Item(i)->start += prepreBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; delete[]sumBuffer; dirManager->Deref(prepreBlock->f); delete prepreBlock; if (b0 != b1) { dirManager->Deref(preBlock->f); delete preBlock; } } } else { // The sample where we begin deletion happens to fall // right on the beginning of a block. if (b0 != b1) { dirManager->Deref(block->Item(b0)->f); delete block->Item(b0); } } // Next, delete blocks strictly between b0 and b1 for (i = b0 + 1; i < b1; i++) { dirManager->Deref(block->Item(i)->f); delete block->Item(i); } // Now, symmetrically, grab the samples in block b1 after the // deletion point into postBuffer. If this is enough samples // for its own block, or if this would be the last block in // the array, write it out. Otherwise combine it with the // subsequent block (splitting them 50/50 if necessary). WaveBlock *postBlock = block->Item(b1); sampleCount postBufferLen = (postBlock->start + postBlock->len) - (start + len); if (postBufferLen) { if (postBufferLen >= minSamples || b1 == numBlocks - 1) { WaveBlock *insBlock = NewInitedWaveBlock(); insBlock->len = postBufferLen; insBlock->start = start; sampleType *postBuffer = new sampleType[postBufferLen]; sampleCount pos = (start + len) - postBlock->start; Read(postBuffer, postBlock, pos, postBufferLen); FirstWrite(postBuffer, insBlock, postBufferLen); delete[]postBuffer; newBlock->Add(insBlock); newNumBlocks++; dirManager->Deref(postBlock->f); delete postBlock; } else { WaveBlock *postpostBlock = block->Item(b1 + 1); sampleCount postpostLen = postpostBlock->len; sampleCount sum = postpostLen + postBufferLen; sampleType *sumBuffer = new sampleType[sum]; sampleCount pos = (start + len) - postBlock->start; Read(sumBuffer, postBlock, pos, postBufferLen); Read(&sumBuffer[postBufferLen], postpostBlock, 0, postpostLen); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; b1++; delete[]sumBuffer; dirManager->Deref(postpostBlock->f); delete postpostBlock; dirManager->Deref(postBlock->f); delete postBlock; } } else { // The sample where we begin deletion happens to fall // right on the end of a block. if (b0 != b1) { dirManager->Deref(block->Item(b1)->f); delete block->Item(b1); } } // Copy the remaining blocks over from the old array for (i = b1 + 1; i < numBlocks; i++) { block->Item(i)->start -= len; newBlock->Add(block->Item(i)); newNumBlocks++; } // Substitute our new array for the old one delete block; block = newBlock; // Update total number of samples, update the envelope, // and do a consistency check. numSamples -= len; envelope.SetTrackLen(numSamples / rate); ConsistencyCheck("Delete - branch two"); }