// 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; }
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 ); }
// 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; }
bool WaveTrack::Paste(double t0, Track *src) { //printf("paste: entering WaveTrack::Paste\n"); if (src->GetKind() != Track::Wave) return false; //printf("paste: we have a wave track\n"); WaveTrack* other = (WaveTrack*)src; // // Pasting is a bit complicated, because with the existence of multiclip mode, // we must guess the behaviour the user wants. // // Currently, two modes are implemented: // // - If a single clip should be pasted, and it should be pasted inside another // clip, no new clips are generated. The audio is simply inserted. // This resembles the old (pre-multiclip support) behaviour. However, if // the clip is pasted outside of any clip, a new clip is generated. This is // the only behaviour which is different to what was done before, but it // shouldn't confuse users too much. // // - If multiple clips should be pasted, these are always pasted as single // clips, and the current clip is splitted, when necessary. This may seem // strange at first, but it probably is better than trying to auto-merge // anything. The user can still merge the clips by hand (which should be // a simple command reachable by a hotkey or single mouse click). // if (other->GetNumClips() == 0) return false; //printf("paste: we have at least one clip\n"); double insertDuration = other->GetEndTime(); WaveClipList::Node* it; //printf("Check if we need to make room for the pasted data\n"); // Make room for the pasted data, unless the space being pasted in is empty of // any clips if (!IsEmpty(t0, t0+insertDuration-1.0/mRate)) { for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); //printf("paste: offsetting already existing clip %i by %f seconds\n", //(int)clip, insertDuration); if (clip->GetStartTime() > t0-(1.0/mRate)) clip->Offset(insertDuration); } } if (other->GetNumClips() == 1) { // Single clip mode // printf("paste: checking for single clip mode!\n"); WaveClip *insideClip = NULL; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); // The 1.0/mRate is the time for one sample - kind of a fudge factor, // because an overlap of less than a sample should not trigger // traditional behaviour. if (t0+src->GetEndTime()-1.0/mRate > clip->GetStartTime() && t0 < clip->GetEndTime() - 1.0/mRate) { //printf("t0=%.6f: inside clip is %.6f ... %.6f\n", // t0, clip->GetStartTime(), clip->GetEndTime()); insideClip = clip; break; } } if (insideClip) { // Exhibit traditional behaviour //printf("paste: traditional behaviour\n"); return insideClip->Paste(t0, other->GetClipByIndex(0)); } // Just fall through and exhibit new behaviour } // Insert new clips //printf("paste: multi clip mode!\n"); for (it=other->GetClipIterator(); it; it=it->GetNext()) { WaveClip* clip = it->GetData(); WaveClip* newClip = new WaveClip(*clip, mDirManager); newClip->Offset(t0); newClip->MarkChanged(); mClips.Append(newClip); } return true; }
void SnapManager::Reinit() { int snapTo = mProject->GetSnapTo(); double rate = mProject->GetRate(); wxString format = mProject->GetSelectionFormat(); // No need to reinit if these are still the same if (snapTo == mSnapTo && rate == mRate && format == mFormat) { return; } // Save NEW settings mSnapTo = snapTo; mRate = rate; mFormat = format; mSnapPoints.clear(); // Grab time-snapping prefs (unless otherwise requested) mSnapToTime = false; // Look up the format string if (mSnapTo != SNAP_OFF && !mNoTimeSnap) { mSnapToTime = true; mConverter.SetSampleRate(mRate); mConverter.SetFormatName(mFormat); } // Add a SnapPoint at t=0 mSnapPoints.push_back(SnapPoint{}); TrackListIterator iter(mTracks); for (Track *track = iter.First(); track; track = iter.Next()) { if (mTrackExclusions && mTrackExclusions->Index(track) != wxNOT_FOUND) { continue; } if (track->GetKind() == Track::Label) { LabelTrack *labelTrack = (LabelTrack *)track; for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) { const LabelStruct *label = labelTrack->GetLabel(i); const double t0 = label->getT0(); const double t1 = label->getT1(); CondListAdd(t0, labelTrack); if (t1 != t0) { CondListAdd(t1, labelTrack); } } } else if (track->GetKind() == Track::Wave) { WaveTrack *waveTrack = (WaveTrack *)track; WaveClipList::compatibility_iterator it; for (it = waveTrack->GetClipIterator(); it; it = it->GetNext()) { WaveClip *clip = it->GetData(); if (mClipExclusions) { bool skip = false; for (size_t j = 0, cnt = mClipExclusions->GetCount(); j < cnt; ++j) { if (mClipExclusions->Item(j).track == waveTrack && mClipExclusions->Item(j).clip == clip) { skip = true; break; } } if (skip) { continue; } } CondListAdd(clip->GetStartTime(), waveTrack); CondListAdd(clip->GetEndTime(), waveTrack); } } #ifdef USE_MIDI else if (track->GetKind() == Track::Note) { CondListAdd(track->GetStartTime(), track); CondListAdd(track->GetEndTime(), track); } #endif } // Sort all by time std::sort(mSnapPoints.begin(), mSnapPoints.end()); }
SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions, double zoom, int pixelTolerance, bool noTimeSnap) { int i; // Grab time-snapping prefs (unless otherwise requested) mSnapToTime = false; AudacityProject *p = GetActiveProject(); wxASSERT(p); if (p) { // Look up the format string if (p->GetSnapTo() && !noTimeSnap) { mSnapToTime = true; mConverter.SetSampleRate(p->GetRate()); mConverter.SetFormatName(p->GetSelectionFormat()); } } mSnapPoints = new SnapPointArray(CompareSnapPoints); if (zoom > 0 && pixelTolerance > 0) mTolerance = pixelTolerance / zoom; else { // This shouldn't happen, but we don't want to crash if we get // illegal values. The net effect of this is to never snap. mTolerance = 0.0; } // Two time points closer than this are considered the same mEpsilon = 1 / 44100.0; // Add a SnapPoint at t=0 mSnapPoints->Add(new SnapPoint(0.0, NULL)); TrackListIterator iter(tracks); Track *track = iter.First(); while (track) { if (track->GetKind() == Track::Label) { LabelTrack *labelTrack = (LabelTrack *)track; for(i = 0; i < labelTrack->GetNumLabels(); i++) { const LabelStruct *label = labelTrack->GetLabel(i); CondListAdd(label->t, labelTrack); if (label->t1 != label->t) { CondListAdd(label->t1, labelTrack); } } } else if (track->GetKind() == Track::Wave) { WaveTrack *waveTrack = (WaveTrack *)track; WaveClipList::compatibility_iterator it; for (it=waveTrack->GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (exclusions) { bool skip = false; for(int j=0; j<(int)exclusions->GetCount(); j++) { if ((*exclusions)[j].track == waveTrack && (*exclusions)[j].clip == clip) skip = true; } if (skip) continue; } CondListAdd(clip->GetStartTime(), waveTrack); CondListAdd(clip->GetEndTime(), waveTrack); } } #ifdef USE_MIDI else if (track->GetKind() == Track::Note) { CondListAdd(track->GetStartTime(), track); CondListAdd(track->GetEndTime(), track); } #endif track = iter.Next(); } }