// 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; }
// 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; }
// 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; }
///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); }
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(); ((ODPCMAliasBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start); 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; } } }
// 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(); } }
// 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; }
// 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; }
// 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; }
///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. seq->LockDeleteUpdateMutex(); //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->GetCount(); i++) { //if there is data but no summary, this blockfile needs summarizing. if(blocks->Item(i)->f->IsDataAvailable() && !blocks->Item(i)->f->IsSummaryAvailable()) { blocks->Item(i)->f->Ref(); ((ODPCMAliasBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start); ((ODPCMAliasBlockFile*)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)(((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetStart()+((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetClipOffset())) insertCursor++; tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODPCMAliasBlockFile*)blocks->Item(i)->f); } } seq->UnlockDeleteUpdateMutex(); node = node->GetNext(); } } } mWaveTrackMutex.Unlock(); //get the new order. mBlockFilesMutex.Lock(); OrderBlockFiles(tempBlocks); mBlockFilesMutex.Unlock(); MarkUpdateRan(); }