// True = success bool FindDependencies(AudacityProject *project, AliasedFileArray *outAliasedFiles) { sampleFormat format = project->GetDefaultFormat(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); AliasedFileHash aliasedFileHash; BoolBlockFileHash blockFileHash; int i; for(i=0; i<(int)blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && !blockFileHash[f]) { blockFileHash[f] = true; // Don't count the same blockfile twice AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFile(); wxString fileNameStr = fileName.GetFullPath(); int blockBytes = (SAMPLE_SIZE(format) * aliasBlockFile->GetLength()); if (aliasedFileHash[fileNameStr]) aliasedFileHash[fileNameStr]->bytes += blockBytes; else { outAliasedFiles->Add(AliasedFile(fileName, blockBytes)); aliasedFileHash[fileNameStr] = &((*outAliasedFiles)[outAliasedFiles->GetCount()-1]); } } } return true; }
// get the sum of the sizes of all blocks this track list // references. However, if a block is referred to multiple // times it is only counted once. Return value is in bytes. wxLongLong UndoManager::CalculateSpaceUsage(int index) { TrackListOfKindIterator iter(Track::Wave); WaveTrack *wt; WaveClipList::compatibility_iterator it; BlockArray *blocks; unsigned int i; // get a map of all blocks referenced in this TrackList std::map<BlockFile*, wxLongLong> cur; wt = (WaveTrack *) iter.First(stack[index]->tracks); while (wt) { for (it = wt->GetClipIterator(); it; it = it->GetNext()) { blocks = it->GetData()->GetSequenceBlockArray(); for (i = 0; i < blocks->GetCount(); i++) { BlockFile* pBlockFile = blocks->Item(i)->f; if (pBlockFile->GetFileName().FileExists()) cur[pBlockFile] = pBlockFile->GetSpaceUsage(); } } wt = (WaveTrack *) iter.Next(); } if (index > 0) { // get a set of all blocks referenced in all prev TrackList std::set<BlockFile*> prev; while (--index) { wt = (WaveTrack *) iter.First(stack[index]->tracks); while (wt) { for (it = wt->GetClipIterator(); it; it = it->GetNext()) { blocks = it->GetData()->GetSequenceBlockArray(); for (i = 0; i < blocks->GetCount(); i++) { prev.insert(blocks->Item(i)->f); } } wt = (WaveTrack *) iter.Next(); } } // remove all blocks in prevBlockFiles from curBlockFiles std::set<BlockFile*>::const_iterator prevIter; for (prevIter = prev.begin(); prevIter != prev.end(); prevIter++) { cur.erase(*prevIter); } } // sum the sizes of the blocks remaining in curBlockFiles; wxLongLong bytes = 0; std::map<BlockFile*, wxLongLong>::const_iterator curIter; for (curIter = cur.begin(); curIter != cur.end(); curIter++) { bytes += curIter->second; } return bytes; }
void UndoManager::CalculateSpaceUsage() { TIMER_START( "CalculateSpaceUsage", space_calc ); TrackListOfKindIterator iter(Track::Wave); space.Clear(); space.Add(0, stack.GetCount()); Set s1, s2; Set *prev = &s1; Set *cur = &s2; for (size_t i = 0, cnt = stack.GetCount(); i < cnt; i++) { // Swap map pointers std::swap(cur, prev); // And clean out the NEW current map cur->clear(); // Scan all tracks at current level WaveTrack *wt = (WaveTrack *) iter.First(stack[i]->tracks); while (wt) { // Scan all clips within current track WaveClipList::compatibility_iterator it = wt->GetClipIterator(); while (it) { // Scan all blockfiles within current clip BlockArray *blocks = it->GetData()->GetSequenceBlockArray(); for (size_t b = 0, cnt = blocks->size(); b < cnt; b++) { BlockFile *file = (*blocks)[b].f; // Accumulate space used by the file if the file didn't exist // in the previous level if (prev->count(file) == 0 && cur->count(file) == 0) { space[i] += file->GetSpaceUsage().GetValue(); } // Add file to current set cur->insert(file); } it = it->GetNext(); } wt = (WaveTrack *) iter.Next(); } } TIMER_STOP( space_calc ); }
///by default creates the order of the wavetrack to load. void ODDecodeTask::Update() { std::vector<ODDecodeBlockFile*> tempBlocks; mWaveTrackMutex.Lock(); for(size_t j=0;j<mWaveTracks.size();j++) { if(mWaveTracks[j]) { WaveClip *clip; BlockArray *blocks; Sequence *seq; //gather all the blockfiles that we should process in the wavetrack. WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator(); while(node) { clip = node->GetData(); seq = clip->GetSequence(); //TODO:this lock is way to big since the whole file is one sequence. find a way to break it down. seq->LockDeleteUpdateMutex(); //See Sequence::Delete() for why need this for now.. blocks = clip->GetSequenceBlockArray(); int i; int insertCursor; insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n) for(i=0; i<(int)blocks->GetCount(); i++) { //since we have more than one ODBlockFile, we will need type flags to cast. if(!blocks->Item(i)->f->IsDataAvailable() && ((ODDecodeBlockFile*)blocks->Item(i)->f)->GetDecodeType()==this->GetODType()) { blocks->Item(i)->f->Ref(); ((ODDecodeBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start); ((ODDecodeBlockFile*)blocks->Item(i)->f)->SetClipOffset((sampleCount)(clip->GetStartTime()*clip->GetRate())); //these will always be linear within a sequence-lets take advantage of this by keeping a cursor. while(insertCursor<(int)tempBlocks.size()&& (sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) < (sampleCount)(((ODDecodeBlockFile*)blocks->Item(i)->f)->GetStart()+((ODDecodeBlockFile*)blocks->Item(i)->f)->GetClipOffset())) insertCursor++; tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODDecodeBlockFile*)blocks->Item(i)->f); } } seq->UnlockDeleteUpdateMutex(); node = node->GetNext(); } } } mWaveTrackMutex.Unlock(); //get the new order. OrderBlockFiles(tempBlocks); }
// Converts an array of blocks back to a single 2D array // This is the inverse of "split_into_blocks()" // The array of blocks might represent slices or codeblocks const Array2D merge_blocks(const BlockArray& blocks) { // First find picture dimensions int pictureHeight = 0; int pictureWidth = 0; const int yBlocks = blocks.shape()[0]; const int xBlocks = blocks.shape()[1]; for (int y=0; y<yBlocks; ++y) pictureHeight += blocks[y][0].shape()[0]; for (int x=0; x<xBlocks; ++x) pictureWidth += blocks[0][x].shape()[1]; // Define Array2D pictureHeight by PictureWidth Array2D picture(extents[pictureHeight][pictureWidth]); // Now merge the block together // Note Range(top, bottom) and Range(left, right) define half open ranges either // [top, bottom) or [left, right), i.e. the bottom/rightmost element is not included int bottom; for (int y=0, top=0; y<yBlocks; ++y, top=bottom) { bottom = top + blocks[y][0].shape()[0]; int right; for (int x=0, left=0; x<xBlocks; ++x, left=right) { right = left + blocks[0][x].shape()[1]; // Copy block into a view of the picture picture[indices[Range(top,bottom)][Range(left,right)]] = blocks[y][x]; } } return picture; }
void FindDependencies(AudacityProject *project, AliasedFileArray *outAliasedFiles) { sampleFormat format = project->GetDefaultFormat(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); AliasedFileHash aliasedFileHash; BoolBlockFileHash blockFileHash; int i; for (i = 0; i < (int)blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && (blockFileHash.count(f) == 0)) { // f is an alias block we have not yet counted. blockFileHash[f] = true; // Don't count the same blockfile twice. AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFileName(); // In DirManager::ProjectFSCK(), if the user has chosen to // "Replace missing audio with silence", the code there puts in an empty wxFileName. // Don't count those in dependencies. if (!fileName.IsOk()) continue; wxString fileNameStr = fileName.GetFullPath(); int blockBytes = (SAMPLE_SIZE(format) * aliasBlockFile->GetLength()); if (aliasedFileHash.count(fileNameStr) > 0) // Already put this AliasBlockFile in aliasedFileHash. // Update block count. aliasedFileHash[fileNameStr]->mByteCount += blockBytes; else { // Haven't counted this AliasBlockFile yet. // Add to return array and internal hash. outAliasedFiles->Add(AliasedFile(fileName, blockBytes, fileName.FileExists())); aliasedFileHash[fileNameStr] = &((*outAliasedFiles)[outAliasedFiles->GetCount()-1]); } } } }
// get the sum of the sizes of all blocks this track list // references. However, if a block is referred to multiple // times it is only counted once. Return value is in bytes unsigned int TrackList::GetSpaceUsage() { // the map guarantees that I only count each block once std::map<BlockFile*,unsigned int> blockFiles; for (TrackListNode *p = head; p; p = p->next) { if (p->t->GetKind() == Track::Wave) { BlockArray *blocks = ((WaveTrack*)p->t)->GetSequence()->GetBlockArray(); for (unsigned int i = 0; i < blocks->GetCount(); i++) blockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage(); } } std::map<BlockFile*,unsigned int>::const_iterator bfIter; unsigned int bytes = 0; for (bfIter = blockFiles.begin(); bfIter != blockFiles.end(); bfIter++) bytes += bfIter->second; return bytes; }
///by default creates the order of the wavetrack to load. void ODComputeSummaryTask::Update() { std::vector<ODPCMAliasBlockFile*> tempBlocks; mWaveTrackMutex.Lock(); if(mWaveTrack) { WaveClip *clip; BlockArray *blocks; Sequence *seq; //gather all the blockfiles that we should process in the wavetrack. WaveClipList::Node* node = mWaveTrack->GetClipIterator(); while(node) { clip = node->GetData(); seq = clip->GetSequence(); //TODO:this lock is way to big since the whole file is one sequence. find a way to break it down. seq->LockDeleteUpdateMutex(); //See Sequence::Delete() for why need this for now.. blocks = clip->GetSequenceBlockArray(); int i; for(i=0; i<(int)blocks->GetCount(); i++) { //in the future if we have more than one ODBlockFile, we will need type flags to cast. if(!blocks->Item(i)->f->IsSummaryAvailable()) { blocks->Item(i)->f->Ref(); tempBlocks.push_back((ODPCMAliasBlockFile*)blocks->Item(i)->f); } } seq->UnlockDeleteUpdateMutex(); node = node->GetNext(); } } mWaveTrackMutex.Unlock(); //get the new order. OrderBlockFiles(tempBlocks); }
// Given an Audacity project and a hash mapping aliased block // files to un-aliased block files, walk through all of the // tracks and replace each aliased block file with its replacement. // Note that this code respects reference-counting and thus the // process of making a project self-contained is actually undoable. void ReplaceBlockFiles(AudacityProject *project, ReplacedBlockFileHash &hash) { DirManager *dirManager = project->GetDirManager(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); int i; for (i = 0; i < (int)blocks.GetCount(); i++) { if (hash.count(blocks[i]->f) > 0) { BlockFile *src = blocks[i]->f; BlockFile *dst = hash[src]; dirManager->Deref(src); dirManager->Ref(dst); blocks[i]->f = dst; } } }
// Find out how much additional space was used to execute // this operation. // // Computed by getting a list of all blocks referenced by // *this* TrackList and removing all blocks referenced by // any previous TrackList. wxLongLong TrackList::GetAdditionalSpaceUsage(UndoStack *stack) { TrackListNode *p; // get a map of all blocks referenced in this TrackList std::map<BlockFile*,wxLongLong> curBlockFiles; for (p = head; p; p = p->next) { if (p->t->GetKind() == Track::Wave) { WaveTrack* track = ((WaveTrack*)p->t); for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); BlockArray *blocks = clip->GetSequenceBlockArray(); for (unsigned int i = 0; i < blocks->GetCount(); i++) curBlockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage(); } } } // get a set of all blocks referenced in all prev TrackList std::set<BlockFile*> prevBlockFiles; unsigned int undoStackIdx = 0; for (; undoStackIdx < stack->GetCount(); undoStackIdx++) { UndoStackElem *stackElem = stack->Item(undoStackIdx); if (stackElem->tracks == this) break; for (p = stackElem->tracks->head; p; p = p->next) { if (p->t->GetKind() == Track::Wave) { WaveTrack* track = ((WaveTrack*)p->t); for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); BlockArray *blocks = clip->GetSequenceBlockArray(); for (unsigned int i = 0; i < blocks->GetCount(); i++) prevBlockFiles.insert(blocks->Item(i)->f); } } } } // remove all blocks in prevBlockFiles from curBlockFiles std::set<BlockFile*>::const_iterator prevIter = prevBlockFiles.begin(); for (; prevIter != prevBlockFiles.end(); prevIter++) curBlockFiles.erase(*prevIter); // sum the sizes of the blocks remaining in curBlockFiles; std::map<BlockFile*,wxLongLong>::const_iterator curBfIter = curBlockFiles.begin(); wxLongLong bytes = 0; for (;curBfIter != curBlockFiles.end(); curBfIter++) bytes += curBfIter->second; return bytes; }
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; }
// Given a project, returns a single array of all SeqBlocks // in the current set of tracks. Enumerating that array allows // you to process all block files in the current set. void GetAllSeqBlocks(AudacityProject *project, BlockArray *outBlocks) { TrackList *tracks = project->GetTracks(); TrackListIterator iter(tracks); Track *t = iter.First(); while (t) { if (t->GetKind() == Track::Wave) { WaveTrack *waveTrack = (WaveTrack *)t; WaveClipList::compatibility_iterator node = waveTrack->GetClipIterator(); while(node) { WaveClip *clip = node->GetData(); Sequence *sequence = clip->GetSequence(); BlockArray *blocks = sequence->GetBlockArray(); int i; for (i = 0; i < (int)blocks->GetCount(); i++) outBlocks->Add(blocks->Item(i)); node = node->GetNext(); } } t = iter.Next(); } }
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; }
// get the sum of the sizes of all blocks this track list // references. However, if a block is referred to multiple // times it is only counted once. Return value is in bytes wxLongLong TrackList::GetSpaceUsage() { // the map guarantees that I only count each block once std::map<BlockFile*,wxLongLong> blockFiles; for (TrackListNode *p = head; p; p = p->next) { if (p->t->GetKind() == Track::Wave) { WaveTrack* track = ((WaveTrack*)p->t); for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); BlockArray *blocks = clip->GetSequenceBlockArray(); for (unsigned int i = 0; i < blocks->GetCount(); i++) blockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage(); } } } std::map<BlockFile*,wxLongLong>::const_iterator bfIter; wxLongLong bytes = 0; for (bfIter = blockFiles.begin(); bfIter != blockFiles.end(); bfIter++) bytes += bfIter->second; return bytes; }
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; }
// Given a project and a list of aliased files that should no // longer be external dependencies (selected by the user), replace // all of those alias block files with disk block files. void RemoveDependencies(AudacityProject *project, AliasedFileArray *aliasedFiles) { DirManager *dirManager = project->GetDirManager(); ProgressDialog *progress = new ProgressDialog(_("Removing Dependencies"), _("Copying audio data into project...")); int updateResult = eProgressSuccess; // Hash aliasedFiles based on their full paths and // count total number of bytes to process. AliasedFileHash aliasedFileHash; wxLongLong totalBytesToProcess = 0; unsigned int i; for (i = 0; i < aliasedFiles->GetCount(); i++) { totalBytesToProcess += aliasedFiles->Item(i).mByteCount; wxString fileNameStr = aliasedFiles->Item(i).mFileName.GetFullPath(); aliasedFileHash[fileNameStr] = &aliasedFiles->Item(i); } BlockArray blocks; GetAllSeqBlocks(project, &blocks); const sampleFormat format = project->GetDefaultFormat(); ReplacedBlockFileHash blockFileHash; wxLongLong completedBytes = 0; for (i = 0; i < blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && (blockFileHash.count(f) == 0)) { // f is an alias block we have not yet processed. AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFileName(); wxString fileNameStr = fileName.GetFullPath(); if (aliasedFileHash.count(fileNameStr) == 0) // This aliased file was not selected to be replaced. Skip it. continue; // Convert it from an aliased file to an actual file in the project. unsigned int len = aliasBlockFile->GetLength(); samplePtr buffer = NewSamples(len, format); f->ReadData(buffer, format, 0, len); BlockFile *newBlockFile = dirManager->NewSimpleBlockFile(buffer, len, format); DeleteSamples(buffer); // Update our hash so we know what block files we've done blockFileHash[f] = newBlockFile; // Update the progress bar completedBytes += SAMPLE_SIZE(format) * len; updateResult = progress->Update(completedBytes, totalBytesToProcess); if (updateResult != eProgressSuccess) break; } } // Above, we created a SimpleBlockFile contained in our project // to go with each AliasBlockFile that we wanted to migrate. // However, that didn't actually change any references to these // blockfiles in the Sequences, so we do that next... ReplaceBlockFiles(project, blockFileHash); // Subtract one from reference count of new block files; they're // now all referenced the proper number of times by the Sequences ReplacedBlockFileHash::iterator it; for( it = blockFileHash.begin(); it != blockFileHash.end(); ++it ) { BlockFile *f = it->second; dirManager->Deref(f); } delete progress; }
const Shape2D shape(const BlockArray& arg) { const Shape2D result = {{static_cast<Index>(arg.shape()[0]), static_cast<Index>(arg.shape()[1])}}; return result; }
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"); }
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"); }
///creates the order of the wavetrack to load. ///by default left to right, or frome the point the user has clicked. void ODComputeSummaryTask::Update() { std::vector<ODPCMAliasBlockFile*> tempBlocks; mWaveTrackMutex.Lock(); for(size_t j=0;j<mWaveTracks.size();j++) { if(mWaveTracks[j]) { WaveClip *clip; BlockArray *blocks; Sequence *seq; //gather all the blockfiles that we should process in the wavetrack. WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator(); while(node) { clip = node->GetData(); seq = clip->GetSequence(); //This lock may be way too big since the whole file is one sequence. //TODO: test for large files and find a way to break it down. Sequence::DeleteUpdateMutexLocker locker(*seq); //See Sequence::Delete() for why need this for now.. //We don't need the mBlockFilesMutex here because it is only for the vector list. //These are existing blocks, and its wavetrack or blockfiles won't be deleted because //of the respective mWaveTrackMutex lock and LockDeleteUpdateMutex() call. blocks = clip->GetSequenceBlockArray(); int i; int insertCursor; insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n) for(i=0; i<(int)blocks->size(); i++) { //if there is data but no summary, this blockfile needs summarizing. SeqBlock &block = (*blocks)[i]; BlockFile *const file = block.f; if(file->IsDataAvailable() && !file->IsSummaryAvailable()) { file->Ref(); ODPCMAliasBlockFile *const odpcmaFile = static_cast<ODPCMAliasBlockFile*>(file); odpcmaFile->SetStart(block.start); odpcmaFile->SetClipOffset((sampleCount)(clip->GetStartTime()*clip->GetRate())); //these will always be linear within a sequence-lets take advantage of this by keeping a cursor. while(insertCursor<(int)tempBlocks.size()&& (sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) < (sampleCount)(odpcmaFile->GetStart()+odpcmaFile->GetClipOffset())) insertCursor++; tempBlocks.insert(tempBlocks.begin() + insertCursor++, odpcmaFile); } } node = node->GetNext(); } } } mWaveTrackMutex.Unlock(); //get the NEW order. mBlockFilesMutex.Lock(); OrderBlockFiles(tempBlocks); mBlockFilesMutex.Unlock(); MarkUpdateRan(); }
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")); }
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")); }
// Given a project and a list of aliased files that should no // longer be self-contained (selected by the user), replace // all of those alias block files with disk block files bool RemoveDependencies(AudacityProject *project, AliasedFileArray *aliasedFiles) { DirManager *dirManager = project->GetDirManager(); GetActiveProject()->ProgressShow(_("Removing Dependencies"), _("Copying audio data into project...")); AliasedFileHash aliasedFileHash; ReplacedBlockFileHash blockFileHash; double totalBytesToProcess = 0.0; double completedBytes = 0.0; unsigned int i; for(i=0; i<aliasedFiles->GetCount(); i++) { totalBytesToProcess += (double)aliasedFiles->Item(i).bytes; wxString fileNameStr = aliasedFiles->Item(i).fileName.GetFullPath(); aliasedFileHash[fileNameStr] = &aliasedFiles->Item(i); } sampleFormat format = project->GetDefaultFormat(); BlockArray blocks; GetAllSeqBlocks(project, &blocks); for(i=0; i<blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && !blockFileHash[f]) { AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFile(); wxString fileNameStr = fileName.GetFullPath(); if (!aliasedFileHash[fileNameStr]) continue; // Convert it from an aliased file to an actual file in the project unsigned int len = aliasBlockFile->GetLength(); samplePtr buffer = NewSamples(len, format); f->ReadData(buffer, format, 0, len); BlockFile *newBlockFile = dirManager->NewSimpleBlockFile(buffer, len, format); DeleteSamples(buffer); // Update our hash so we know what block files we've done blockFileHash[f] = newBlockFile; // Update the progress bar completedBytes += (double)SAMPLE_SIZE(format) * len; int progressValue = (int)(completedBytes * 1000.0 / totalBytesToProcess); GetActiveProject()->ProgressUpdate(progressValue); } } // Above, we created a SimpleBlockFile contained in our project // to go with each AliasBlockFile that we wanted to migrate. // However, that didn't actually change any references to these // blockfiles in the Sequences, so we do that next... ReplaceBlockFiles(project, blockFileHash); // Subtract one from reference count of new block files; they're // now all referenced the proper number of times by the Sequences ReplacedBlockFileHash::iterator it; for( it = blockFileHash.begin(); it != blockFileHash.end(); ++it ) { BlockFile *f = it->second; dirManager->Deref(f); } GetActiveProject()->ProgressHide(); return true; }