From e35e019e179f9ef7651986301409352e6399573d Mon Sep 17 00:00:00 2001 From: businessmanprogrammersteve Date: Tue, 16 Feb 2010 20:50:38 +0000 Subject: [PATCH] Change lots of code that uses linking to use the new scheme. --- src/LabelTrack.cpp | 68 ++++---- src/LabelTrack.h | 8 +- src/Menus.cpp | 81 +++------ src/Project.cpp | 42 ++--- src/Project.h | 2 +- src/Track.cpp | 28 +++ src/Track.h | 4 + src/WaveTrack.cpp | 286 +++++++++---------------------- src/WaveTrack.h | 11 +- src/effects/ChangeSpeed.cpp | 55 +++--- src/effects/ChangeSpeed.h | 4 +- src/effects/Effect.cpp | 27 +-- src/effects/Generator.cpp | 20 +-- src/effects/Repeat.cpp | 45 ++--- src/effects/Reverse.cpp | 42 ++--- src/effects/SBSMSEffect.cpp | 48 +++--- src/effects/SoundTouchEffect.cpp | 58 ++++--- src/effects/SoundTouchEffect.h | 7 +- src/effects/StereoToMono.cpp | 2 +- src/effects/TruncSilence.cpp | 11 +- src/effects/nyquist/Nyquist.cpp | 18 +- src/toolbars/ControlToolBar.cpp | 7 - 22 files changed, 344 insertions(+), 530 deletions(-) diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index ce7abd14d..1780d81cc 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -90,6 +90,7 @@ LabelTrack::LabelTrack(DirManager * projDirManager): mSelIndex(-1), mMouseOverLabelLeft(-1), mMouseOverLabelRight(-1), + mClipLen(0.0), mIsAdjustingLabel(false) { SetDefaultName(_("Label Track")); @@ -114,6 +115,7 @@ LabelTrack::LabelTrack(const LabelTrack &orig) : mSelIndex(-1), mMouseOverLabelLeft(-1), mMouseOverLabelRight(-1), + mClipLen(0.0), mIsAdjustingLabel(false) { int len = orig.mLabels.Count(); @@ -149,7 +151,7 @@ void LabelTrack::SetOffset(double dOffset) } } -void LabelTrack::ShiftLabelsOnClear(double b, double e) +bool LabelTrack::Clear(double b, double e) { for (size_t i=0;it >= e){//label is after deletion region @@ -169,10 +171,12 @@ void LabelTrack::ShiftLabelsOnClear(double b, double e) //nothing } } + + return true; } //used when we want to use clear only on the labels -void LabelTrack::ChangeLabelsOnClear(double b, double e) +bool LabelTrack::SplitDelete(double b, double e) { for (size_t i=0;it >= b && mLabels[i]->t1 <= e){//deletion region encloses label @@ -186,6 +190,8 @@ void LabelTrack::ChangeLabelsOnClear(double b, double e) mLabels[i]->t1 = b; } } + + return true; } void LabelTrack::ShiftLabelsOnInsert(double length, double pt) { @@ -2135,7 +2141,17 @@ bool LabelTrack::Save(wxTextFile * out, bool overwrite) } #endif -bool LabelTrack::Cut(double t0, double t1, Track ** dest) +bool LabelTrack::Cut(double t0, double t1, Track **dest) +{ + if (!SplitCut(t0, t1, dest)) + return false; + if (!Clear(t0, t1)) + return false; + + return true; +} + +bool LabelTrack::SplitCut(double t0, double t1, Track ** dest) { *dest = new LabelTrack(GetDirManager()); int len = mLabels.Count(); @@ -2182,7 +2198,7 @@ bool LabelTrack::Copy(double t0, double t1, Track ** dest) } -bool LabelTrack::Paste(double t, Track * src) +bool LabelTrack::PasteOver(double t, Track * src) { if (src->GetKind() != Track::Label) return false; @@ -2206,11 +2222,20 @@ bool LabelTrack::Paste(double t, Track * src) return true; } +bool LabelTrack::Paste(double t, Track *src) +{ + if (src->GetKind() != Track::Label) + return false; + + LabelTrack *lt = (LabelTrack *)src; + + double shiftAmt = lt->mClipLen > 0.0 ? lt->mClipLen : lt->GetEndTime(); + + ShiftLabelsOnInsert(shiftAmt, t); + return PasteOver(t, src); +} + // This repeats the labels in a time interval a specified number of times. -// Like Paste(), it does not shift existing labels over -// - It assumes that you've already called ShiftLabelsOnInsert(), because -// sometimes with linking enabled that's hard to avoid. -// - It assumes that you inserted the necessary extra time at t1, not t0. bool LabelTrack::Repeat(double t0, double t1, int n) { // Sanity-check the arguments @@ -2218,6 +2243,9 @@ bool LabelTrack::Repeat(double t0, double t1, int n) double tLen = t1 - t0; + // Insert space for the repetitions + ShiftLabelsOnInsert(tLen * n, t1); + for (unsigned int i = 0; i < mLabels.GetCount(); i++) { if (mLabels[i]->t >= t0 && mLabels[i]->t <= t1 && @@ -2254,30 +2282,6 @@ bool LabelTrack::Repeat(double t0, double t1, int n) return true; } -bool LabelTrack::Clear(double t0, double t1) -{ - AudacityProject *p = GetActiveProject(); - if (p && p->IsSticky()){ - TrackGroupIterator grpIter(p->GetTracks()); - Track *t = grpIter.First(this); - // If this track is part of a group, find a Wave track in the group and do - // the clear from there to ensure proper group behavior - while (t) { - if (t->GetKind() == Track::Wave) { - return t->Clear(t0, t1); - } - t = grpIter.Next(); - } - - // Fallback: shift labels in this track - ShiftLabelsOnClear(t0, t1); - } - else - ChangeLabelsOnClear(t0, t1); - - return true; -} - bool LabelTrack::Silence(double t0, double t1) { int len = mLabels.Count(); diff --git a/src/LabelTrack.h b/src/LabelTrack.h index 97c92b0b6..a6d235b5d 100644 --- a/src/LabelTrack.h +++ b/src/LabelTrack.h @@ -175,8 +175,10 @@ class LabelTrack:public Track { void MayAdjustLabel( int iLabel, int iEdge, bool bAllowSwapping, double fNewTime); void MayMoveLabel( int iLabel, int iEdge, double fNewTime); - void ShiftLabelsOnClear(double b, double e); - void ChangeLabelsOnClear(double b, double e); + // This pastes labels without shifting existing ones + bool PasteOver(double t, Track *src); + bool SplitCut(double b, double e, Track **dest); + bool SplitDelete(double b, double e); void ShiftLabelsOnInsert(double length, double pt); void ChangeLabelsOnReverse(double b, double e); void ScaleLabels(double b, double e, double change); @@ -221,7 +223,7 @@ class LabelTrack:public Track { bool mRightDragging; /// flag to tell if it's a valid dragging bool mDrawCursor; /// flag to tell if drawing the cursor or not - // Used only for a LabelTrack on the clipboard + // Set in copied label tracks double mClipLen; void ComputeLayout(const wxRect & r, double h, double pps); diff --git a/src/Menus.cpp b/src/Menus.cpp index 42a011933..228fd1d07 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -2992,7 +2992,7 @@ void AudacityProject::OnRedo() void AudacityProject::OnCut() { - TrackAndGroupIterator iter(mTracks); + TrackListIterator iter(mTracks); Track *n = iter.First(); Track *dest; @@ -3042,7 +3042,8 @@ void AudacityProject::OnCut() n = iter.First(); while (n) { - if (n->GetSelected()) { + // We clear from selected and synchro-selected tracks + if (n->GetSelected() || n->IsSynchroSelected()) { switch (n->GetKind()) { #if defined(USE_MIDI) @@ -3064,12 +3065,7 @@ void AudacityProject::OnCut() break; } } - // Selected wave and label tracks may need group iteration - if (IsSticky() && n->GetSelected() && - (n->GetKind() == Track::Wave || n->GetKind() == Track::Label)) - n = iter.NextGroup(); - else - n = iter.Next(); + n = iter.Next(); } msClipLen = (mViewInfo.sel1 - mViewInfo.sel0); @@ -3299,10 +3295,6 @@ void AudacityProject::OnPaste() bool trackTypeMismatch = false; bool advanceClipboard = true; - // Keeps track of whether n would be the first WaveTrack in its group to - // receive data from the paste. - bool firstInGroup = true; - while (n && c) { if (n->GetSelected()) { advanceClipboard = true; @@ -3329,8 +3321,6 @@ void AudacityProject::OnPaste() c = tmpC; while (n && (c->GetKind() != n->GetKind()) ) { - if (n && n->GetKind() == Track::Label) - firstInGroup = true; n = iter.Next(); } if (!n) c = NULL; @@ -3368,25 +3358,19 @@ void AudacityProject::OnPaste() { // If not the first in group we set useHandlePaste to true pastedSomething = ((WaveTrack*)n)->ClearAndPaste(t0, t1, - (WaveTrack*)c, true, true, NULL, false, !firstInGroup); - firstInGroup = firstInGroup && !pastedSomething; + (WaveTrack*)c, true, true); } else if (c->GetKind() == Track::Label && n && n->GetKind() == Track::Label) { - // AWD: LabelTrack::Paste() doesn't shift future labels (and - // WaveTrack::HandleGroupPaste() doesn't adjust selected group - // tracks, so some other track's paste hasn't done it either). To - // be (sort of) consistent with Clear behavior, we'll only shift - // them if linking is on and we have already pasted into a wave - // track in this group. - if (IsSticky() && !firstInGroup) - { - ((LabelTrack *)n)->ShiftLabelsOnClear(t0, t1); - ((LabelTrack *)n)->ShiftLabelsOnInsert(msClipLen, t0); - } + ((LabelTrack *)n)->Clear(t0, t1); - pastedSomething = n->Paste(t0, c); + // To be (sort of) consistent with Clear behavior, we'll only shift + // them if linking is on + if (IsSticky()) + ((LabelTrack *)n)->ShiftLabelsOnInsert(msClipLen, t0); + + pastedSomething = ((LabelTrack *)n)->PasteOver(t0, c); } else { @@ -3405,17 +3389,7 @@ void AudacityProject::OnPaste() ((WaveTrack *) n)->Clear(t0, t1); } - // firstInGroup should always be false here, unless pasting to - // the first channel failed - if (firstInGroup) - { - pastedSomething = ((WaveTrack *)n)->Paste(t0, c); - firstInGroup = !pastedSomething; - } - else - { - pastedSomething = ((WaveTrack *)n)->HandlePaste(t0, c); - } + pastedSomething = ((WaveTrack *)n)->Paste(t0, c); } else { n->Clear(t0, t1); @@ -3430,10 +3404,12 @@ void AudacityProject::OnPaste() prev = c; c = clipIter.Next(); } + } // if (n->GetSelected()) + else if (n->IsSynchroSelected()) + { + n->SyncAdjust(t1, t0 + msClipLen); } - if (n && n->GetKind() == Track::Label) - firstInGroup = true; n = iter.Next(); } @@ -3450,8 +3426,7 @@ void AudacityProject::OnPaste() if (n->GetSelected() && n->GetKind()==Track::Wave){ if (c && c->GetKind() == Track::Wave){ pastedSomething = ((WaveTrack *)n)->ClearAndPaste(t0, t1, - (WaveTrack *)c, true, true, NULL, false, !firstInGroup); - firstInGroup = firstInGroup && !pastedSomething; + (WaveTrack *)c, true, true); }else{ WaveTrack *tmp; tmp = mTrackFactory->NewWaveTrack( ((WaveTrack*)n)->GetSampleFormat(), ((WaveTrack*)n)->GetRate()); @@ -3459,24 +3434,24 @@ void AudacityProject::OnPaste() tmp->Flush(); pastedSomething = ((WaveTrack *)n)->ClearAndPaste(t0, t1, - tmp, true, true, NULL, false, !firstInGroup); - firstInGroup = firstInGroup && !pastedSomething; + tmp, true, true); delete tmp; } } - else if (n->GetSelected() && n->GetKind() == Track::Label) + else if (n->GetKind() == Track::Label && n->GetSelected()) { - // Make room in label tracks as necessary - if (IsSticky() && !firstInGroup) - { - ((LabelTrack *)n)->ShiftLabelsOnClear(t0, t1); + ((LabelTrack *)n)->Clear(t0, t1); + + // As above, only shift labels if linking is on + if (IsSticky()) ((LabelTrack *)n)->ShiftLabelsOnInsert(msClipLen, t0); - } + } + else if (n->IsSynchroSelected()) + { + n->SyncAdjust(t1, t0 + msClipLen); } - if (n && n->GetKind() == Track::Label) - firstInGroup = true; n = iter.Next(); } } diff --git a/src/Project.cpp b/src/Project.cpp index 7e6821a0c..a3359841d 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3671,18 +3671,20 @@ void AudacityProject::ClearClipboard() void AudacityProject::Clear() { - TrackAndGroupIterator iter(mTracks); + TrackListIterator iter(mTracks); Track *n = iter.First(); while (n) { - if (n->GetSelected()) { - n->Clear(mViewInfo.sel0, mViewInfo.sel1); - // Wave and Label tracks have group behaviour - if (IsSticky() && (n->GetKind() == Track::Wave || n->GetKind() == Track::Label)) n = iter.NextGroup(); - else n = iter.Next(); + if (n->GetSelected() || n->IsSynchroSelected()) { + // AWD: Preserve traditional label track behavior: only shift time in + // linked mode + if (n->GetKind() == Track::Label && IsSticky()) + ((LabelTrack *)n)->SplitDelete(mViewInfo.sel0, mViewInfo.sel1); + else + n->Clear(mViewInfo.sel0, mViewInfo.sel1); } - else n = iter.Next(); + n = iter.Next(); } double seconds = mViewInfo.sel1 - mViewInfo.sel0; @@ -3981,10 +3983,11 @@ void AudacityProject::GetRegionsByLabel( Regions ®ions ) //Executes the edit function on all selected wave tracks with //regions specified by selected labels //If No tracks selected, function is applied on all tracks -//If the function deletes audio, groupIteration should probably be set to true, -// so it won't delete too many times. +//If the function replaces the selection with audio of a different length +// syncTracks should be set true to perform the same action on sync-selected +// tracks. void AudacityProject::EditByLabel( WaveTrack::EditFunction action, - bool groupIteration ) + bool syncTracks ) { Regions regions; @@ -3992,7 +3995,7 @@ void AudacityProject::EditByLabel( WaveTrack::EditFunction action, if( regions.GetCount() == 0 ) return; - TrackAndGroupIterator iter( mTracks ); + TrackListIterator iter( mTracks ); Track *n; bool allTracks = true; @@ -4011,23 +4014,14 @@ void AudacityProject::EditByLabel( WaveTrack::EditFunction action, n = iter.First(); while (n) { - if( n->GetKind() == Track::Wave && ( allTracks || n->GetSelected() ) ) + if( n->GetKind() == Track::Wave && ( allTracks || n->GetSelected() || + (syncTracks && n->IsSynchroSelected()) ) ) { WaveTrack *wt = ( WaveTrack* )n; for( int i = ( int )regions.GetCount() - 1; i >= 0; i-- ) ( wt->*action )( regions.Item( i )->start, regions.Item( i )->end ); - - // Tracks operated on may need group iteration - if (IsSticky() && groupIteration) - n = iter.NextGroup(); - else - n = iter.Next(); - } - else - { - // Tracks not operated on need normal iteration - n = iter.Next(); } + n = iter.Next(); } //delete label regions @@ -4440,7 +4434,7 @@ bool AudacityProject::GetSnapTo() bool AudacityProject::IsSticky() { #ifdef EXPERIMENTAL_LINKING - return (GetStickyFlag() && (mLastFlags & LabelTracksExistFlag)); + return GetStickyFlag(); #else return false; #endif diff --git a/src/Project.h b/src/Project.h index 4a513f468..4e5492952 100644 --- a/src/Project.h +++ b/src/Project.h @@ -280,7 +280,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame, void Rewind(bool shift); void SkipEnd(bool shift); void SetStop(bool bStopped); - void EditByLabel( WaveTrack::EditFunction action, bool groupIteration ); + void EditByLabel( WaveTrack::EditFunction action, bool syncTracks ); void EditClipboardByLabel( WaveTrack::EditDestFunction action ); bool IsSticky(); bool GetStickyFlag() { return mStickyFlag; }; diff --git a/src/Track.cpp b/src/Track.cpp index 8df9036cd..0584e48f6 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -229,6 +229,34 @@ bool Track::IsSynchroSelected() return false; } +bool Track::SyncAdjust(double oldT1, double newT1) +{ + if (newT1 > oldT1) { + // Insert space within the track + + if (oldT1 > GetEndTime()) + return true; + + Track *tmp; + bool ret; + + ret = Cut(oldT1, GetEndTime(), &tmp); + if (!ret) return false; + + ret = Paste(newT1, tmp); + + delete tmp; + return ret; + } + else if (newT1 < oldT1) { + // Remove from the track + return Clear(newT1, oldT1); + } + + // fall-through: no change + return true; +} + // TrackListIterator TrackListIterator::TrackListIterator(TrackList * val) { diff --git a/src/Track.h b/src/Track.h index 4e7ecdd48..062ff1e9a 100644 --- a/src/Track.h +++ b/src/Track.h @@ -162,6 +162,10 @@ class AUDACITY_DLL_API Track: public XMLTagHandler virtual bool Clear(double t0, double t1) {return false;} virtual bool Paste(double t, Track * src) {return false;} + // This can be used to adjust a synchro-selected track when the selection + // is replaced by one of a different length. + virtual bool SyncAdjust(double oldT1, double newT1); + virtual bool Silence(double t0, double t1) {return false;} virtual bool InsertSilence(double t, double len) {return false;} diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 74261cbfa..075ddaf79 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -270,23 +270,14 @@ bool WaveTrack::IsEmpty(double t0, double t1) } bool WaveTrack::Cut(double t0, double t1, Track **dest) -{ - return Cut(t0, t1, dest, true); -} - -bool WaveTrack::Cut(double t0, double t1, Track **dest, bool groupCut) { if (t1 < t0) return false; - // Cut is the same as 'Copy', then 'Delete' if (!Copy(t0, t1, dest)) return false; - if (groupCut) - return Clear(t0, t1); - else - return HandleClear(t0, t1, false, false); + return Clear(t0, t1); } bool WaveTrack::SplitCut(double t0, double t1, Track **dest) @@ -325,47 +316,44 @@ bool WaveTrack::Trim (double t0, double t1) WaveClipList::compatibility_iterator it; for(it = GetClipIterator(); it; it = it->GetNext()) - { - - WaveClip * clip = it->GetData(); + { + WaveClip * clip = it->GetData(); - //Find the first clip greater than the offset. - //If we end up clipping the entire track, this is useful. - if(firstGreaterOffset < 0 && + //Find the first clip greater than the offset. + //If we end up clipping the entire track, this is useful. + if(firstGreaterOffset < 0 && clip->GetStartTime() >= t0) - firstGreaterOffset = clip->GetStartTime(); + firstGreaterOffset = clip->GetStartTime(); - if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime()) - { - if (!clip->Clear(t1,clip->GetEndTime())) - return false; - inside1 = true; - } - - if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime()) - { - if (!clip->Clear(clip->GetStartTime(),t0)) - return false; - clip->SetOffset(t0); - inside0 = true; - } + if(t1 > clip->GetStartTime() && t1 < clip->GetEndTime()) + { + if (!clip->Clear(t1,clip->GetEndTime())) + return false; + inside1 = true; } + if(t0 > clip->GetStartTime() && t0 < clip->GetEndTime()) + { + if (!clip->Clear(clip->GetStartTime(),t0)) + return false; + clip->SetOffset(t0); + inside0 = true; + } + } + //if inside0 is false, then the left selector was between //clips, so delete everything to its left. if(false == inside1) - { - if (!Clear(t1,GetEndTime())) - return false; - } + { + if (!Clear(t1,GetEndTime())) + return false; + } if(false == inside0) - { - if (!Clear(0,t0)) - return false; - //Reset the track offset to be at the point of the first remaining clip. - SetOffset(firstGreaterOffset ); - } + { + if (!SplitDelete(0,t0)) + return false; + } return true; } @@ -462,45 +450,15 @@ bool WaveTrack::Copy(double t0, double t1, Track **dest) return true; } -bool WaveTrack::Paste(double t0, Track *src) -{ - return Paste(t0, src, NULL, false); -} - -bool WaveTrack::Paste(double t0, Track *src, TrackList* tracks, bool relativeLabels) -{ - AudacityProject *p = GetActiveProject(); - if( p && p->IsSticky() && GetNode() ) - return HandleGroupPaste(t0, src, tracks, relativeLabels); - else - return HandlePaste(t0, src); -} bool WaveTrack::Clear(double t0, double t1) { - return Clear(t0, t1, NULL); -} - -bool WaveTrack::Clear(double t0, double t1, TrackList* tracks) -{ - bool addCutLines = false; - bool split = false; - AudacityProject *p = GetActiveProject(); - if( p && p->IsSticky() && GetNode() ) - return HandleGroupClear(t0, t1, addCutLines, split, tracks); - else - return HandleClear(t0, t1, addCutLines, split); + return HandleClear(t0, t1, false, false); } bool WaveTrack::ClearAndAddCutLine(double t0, double t1) { - bool addCutLines = true; - bool split = false; - AudacityProject *p = GetActiveProject(); - if( p && p->IsSticky() ) - return HandleGroupClear(t0, t1, addCutLines, split); - else - return HandleClear(t0, t1, addCutLines, split); + return HandleClear(t0, t1, true, false); } // @@ -522,9 +480,6 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear Track *src, // What to paste bool preserve, // Whether to reinsert splits/cuts bool merge, // Whether to remove 'extra' splits - TrackList* tracks, // Used in Paste - bool relativeLabels, // Whether to handle labels - bool useHandlePaste, // Which pasting method TimeWarper *effectWarper // How does time change ) { @@ -537,10 +492,7 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // If duration is 0, then it's just a plain paste if (dur == 0.0) { - if (useHandlePaste) - return HandlePaste(t0, src); - else - return Paste(t0, src, tracks, relativeLabels); + return Paste(t0, src); } // If provided time warper was NULL, use a default one that does nothing @@ -601,15 +553,8 @@ bool WaveTrack::ClearAndPaste(double t0, // Start of time to clear // Now, clear the selection if (HandleClear(t0, t1, false, false)) { - // The pasting method depends on how this method was called - bool pasteResult; - if (useHandlePaste) - pasteResult = HandlePaste(t0, src); - else - pasteResult = Paste(t0, src, tracks, relativeLabels); - // And paste in the new data - if (pasteResult) { + if (Paste(t0, src)) { unsigned int i; // First, merge the new clip(s) in with the existing clips @@ -722,36 +667,6 @@ void WaveTrack::AddClip(WaveClip* clip) mClips.Append(clip); } -bool WaveTrack::HandleGroupClear(double t0, double t1, bool addCutLines, bool split, TrackList* tracks) -{ - // get tracks - AudacityProject *p = GetActiveProject(); - - if (p) { - if (!tracks) tracks = p->GetTracks(); - } - else return false; - - TrackGroupIterator it(tracks); - Track *t = it.First(this); - if (t == NULL) - // the present track is in a project with groups but doesn't belong to any of them - return HandleClear(t0, t1, addCutLines, split); - - for( ; t; t = it.Next() ) { - if (t->GetKind() == Track::Wave) { - if ( !( ( (WaveTrack *) t)->HandleClear(t0, t1, addCutLines, split) ) ) - return false; - } - else if (t->GetKind() == Track::Label) { - if (!split) - ( (LabelTrack *)t )->ShiftLabelsOnClear(t0, t1); - } - } - - return true; -} - bool WaveTrack::HandleClear(double t0, double t1, bool addCutLines, bool split) { @@ -878,102 +793,57 @@ bool WaveTrack::HandleClear(double t0, double t1, return true; } -bool WaveTrack::HandleGroupPaste(double t0, Track *src, TrackList* tracks, bool relativeLabels) +bool WaveTrack::SyncAdjust(double oldT1, double newT1) { - // get tracks - AudacityProject *p = GetActiveProject(); + if (newT1 > oldT1) { + // Insert space within the track - if (p) { - if (!tracks) tracks = p->GetTracks(); - } - else return false; - - double length = src->GetEndTime(); - ViewInfo *info = &p->mViewInfo; - double sel_len = max(info->sel1 - max(info->sel0, t0), 0.0); - - TrackGroupIterator it(tracks); - Track *t = it.First(this); - if (t == NULL) - // the present track is in a project with groups but doesn't belong to any of them - return HandlePaste(t0, src); + if (oldT1 > GetEndTime()) + return true; - // False return from this function causes its changes to not be pushed to - // the undo stack. So we paste into this track first, so any failure - // (usually from "clips can't move" mode) comes before other changes. - // Failures to paste to the group tracks should not cause this function to - // return false; the result might be OK with the user, and if not he can - // easily undo it - if (!HandlePaste(t0, src)) - { - return false; - } + // If track is empty at oldT1 insert whitespace; otherwise, silence + if (IsEmpty(oldT1, oldT1)) + { + bool ret = false; - for( ; t; t = it.Next() ) { - if (t->GetKind() == Track::Wave) { - WaveTrack *wt = (WaveTrack *)t; - if (t==this) { - // This track has already been pasted; if it's a stereo track skip - // over the other channel as well. - if (t->GetLinked()) t=it.Next(); - } - else { - if (! (t->GetSelected()) ) { - if ( sel_len > length ) - // if selection is bigger than the content to add then we - // need to clear the extra length in the group tracks - wt->HandleClear(t0+length, t0+sel_len, false, false); - else if (sel_len < length) { - // if selection is smaller than the content to add then we - // need to add extra space in the group tracks. If the track - // is empty at this point insert whitespace; otherwise, - // silence - if (wt->IsEmpty(t0+sel_len, t0+sel_len)) - { - // Have to check if clips can move in this case - bool clipsCanMove = true; - gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove); - if (clipsCanMove) - { - Track *tmp = NULL; - wt->Cut(t0 + sel_len, - wt->GetEndTime()+1.0/wt->GetRate(), &tmp, false); - wt->HandlePaste(t0 + length, tmp); - delete tmp; - } - } - else - { - TrackFactory *factory = p->GetTrackFactory(); - WaveTrack *tmp = factory->NewWaveTrack( wt->GetSampleFormat(), wt->GetRate()); - tmp->InsertSilence(0.0, length-sel_len); - tmp->Flush(); - wt->HandlePaste(t0+sel_len, tmp); - } - } - } + // Check if clips can move + bool clipsCanMove = true; + gPrefs->Read(wxT("/GUI/EditClipCanMove"), &clipsCanMove); + if (clipsCanMove) { + Track *tmp = NULL; + ret = Cut (oldT1, GetEndTime() + 1.0/GetRate(), &tmp); + if (!ret) return false; + + ret = Paste(newT1, tmp); + delete tmp; } + + return ret; } - else if (t->GetKind() == Track::Label) { - LabelTrack *lt = (LabelTrack *)t; - if (!t->GetSelected()) - { - if (relativeLabels && (sel_len != 0.0)) - lt->ScaleLabels(info->sel0, info->sel1, length/sel_len); - else { - if ((length - sel_len) > 0.0) - lt->ShiftLabelsOnInsert(length-sel_len, t0); - else if ((length - sel_len) < 0.0) - lt->ShiftLabelsOnClear(info->sel0+length, info->sel1); - } - } + else { + // AWD: Could just use InsertSilence() on its own here, but it doesn't + // follow EditClipCanMove rules (Paste() does it right) + AudacityProject *p = GetActiveProject(); + if (!p) return false; + TrackFactory *f = p->GetTrackFactory(); + if (!f) return false; + WaveTrack *tmp = f->NewWaveTrack(GetSampleFormat(), GetRate()); + + tmp->InsertSilence(0.0, newT1 - oldT1); + tmp->Flush(); + Paste(oldT1, tmp); + delete tmp; } } + else if (newT1 < oldT1) { + return Clear(newT1, oldT1); + } + // fall-through: no change return true; } -bool WaveTrack::HandlePaste(double t0, Track *src) +bool WaveTrack::Paste(double t0, Track *src) { bool editClipCanMove = true; gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove); @@ -1032,8 +902,8 @@ bool WaveTrack::HandlePaste(double t0, Track *src) // move everything to the right, then try to paste again if (!IsEmpty(t0, GetEndTime())) { Track *tmp = NULL; - Cut(t0, GetEndTime()+1.0/mRate, &tmp, false); - HandlePaste(t0 + insertDuration, tmp); + Cut(t0, GetEndTime()+1.0/mRate, &tmp); + Paste(t0 + insertDuration, tmp); delete tmp; } } else @@ -1197,11 +1067,13 @@ bool WaveTrack::InsertSilence(double t, double len) for (WaveClipList::compatibility_iterator it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); - if (clip->GetStartTime() > t) + if (clip->BeforeClip(t)) clip->Offset(len); - else if (clip->GetEndTime() > t) + else if (clip->WithinClip(t)) { - return clip->InsertSilence(t, len); + if (!clip->InsertSilence(t, len)) { + return false; + } } } diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 380934d9c..1823c3155 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -133,9 +133,6 @@ class AUDACITY_DLL_API WaveTrack: public Track { Track *src, bool preserve = true, bool merge = true, - TrackList* tracks = NULL, - bool relativeLabels = false, - bool useHandlePaste = false, TimeWarper *effectWarper = NULL); virtual bool Silence(double t0, double t1); @@ -156,15 +153,9 @@ class AUDACITY_DLL_API WaveTrack: public Track { virtual bool Trim (double t0, double t1); - bool Clear(double t0, double t1, TrackList* tracks); - bool HandleGroupClear(double t0, double t1, bool addCutLines, bool split, TrackList* tracks = NULL); bool HandleClear(double t0, double t1, bool addCutLines, bool split); - bool Paste(double t0, Track *src, TrackList* tracks, bool relativeLabels = false); - bool HandleGroupPaste(double t0, Track *src, TrackList* tracks, bool relativeLabels); - bool HandlePaste(double t0, Track *src); - - bool Cut(double t0, double t1, Track **dest, bool groupCut); + virtual bool SyncAdjust(double oldT1, double newT1); // Returns true if there are no WaveClips in that region bool IsEmpty(double t0, double t1); diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index d8d158e43..d2a4e38d5 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -89,9 +89,9 @@ bool EffectChangeSpeed::TransferParameters( Shuttle & shuttle ) // the region are shifted along according to how the region size changed. bool EffectChangeSpeed::ProcessLabelTrack(Track *t) { - SetTimeWarper(new RegionTimeWarper(mCurT0, mCurT1, - new LinearTimeWarper(mCurT0, mCurT0, - mCurT1, mCurT0 + (mCurT1-mCurT0)*mFactor))); + SetTimeWarper(new RegionTimeWarper(mT0, mT1, + new LinearTimeWarper(mT0, mT0, + mT1, mT0 + (mT1-mT0)*mFactor))); LabelTrack *lt = (LabelTrack*)t; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); @@ -108,42 +108,28 @@ bool EffectChangeSpeed::Process() bool bGoodResult = true; TrackListIterator iter(mOutputTracks); - // go to first wavetrack Track* t; - for (t = iter.First(); t->GetKind() != Track::Wave; t = iter.Next()); - if (!t) - return false; - WaveTrack* pOutWaveTrack = (WaveTrack*)t; mCurTrackNum = 0; m_maxNewLength = 0.0; mFactor = 100.0 / (100.0 + m_PercentChange); - //Get start and end times from track - mCurT0 = pOutWaveTrack->GetStartTime(); - mCurT1 = pOutWaveTrack->GetEndTime(); - - //Set the current bounds to whichever left marker is - //greater and whichever right marker is less: - mCurT0 = wxMax(mT0, mCurT0); - mCurT1 = wxMin(mT1, mCurT1); - - // we only do a "group change" in the first selected track of the group. - // ClearAndPaste has a call to Paste that does changes to the group tracks - bool first = true; - + t = iter.First(); while (t != NULL) { if (t->GetKind() == Track::Label) { - first = true; - if (t->GetSelected() && !ProcessLabelTrack(t)) + if (t->GetSelected() || t->IsSynchroSelected()) { - bGoodResult = false; - break; + if (!ProcessLabelTrack(t)) { + bGoodResult = false; + break; + } } } - else if (t->GetKind() == Track::Wave && t->GetSelected()) { - pOutWaveTrack = (WaveTrack*)t; + else if (t->GetKind() == Track::Wave && + (t->GetSelected() || t->IsSynchroSelected())) + { + WaveTrack *pOutWaveTrack = (WaveTrack*)t; //Get start and end times from track mCurT0 = pOutWaveTrack->GetStartTime(); mCurT1 = pOutWaveTrack->GetEndTime(); @@ -160,15 +146,18 @@ bool EffectChangeSpeed::Process() sampleCount end = pOutWaveTrack->TimeToLongSamples(mCurT1); //ProcessOne() (implemented below) processes a single track - if (!ProcessOne(pOutWaveTrack, start, end, first)) + if (!ProcessOne(pOutWaveTrack, start, end)) { bGoodResult = false; break; } - first = false; } mCurTrackNum++; } + else if (t->IsSynchroSelected() && !t->GetSelected()) + { + t->SyncAdjust(mT1, mT0 + (mT1 - mT0) * mFactor); + } //Iterate to the next track t=iter.Next(); @@ -185,7 +174,7 @@ bool EffectChangeSpeed::Process() // ProcessOne() takes a track, transforms it to bunch of buffer-blocks, // and calls libsamplerate code on these blocks. bool EffectChangeSpeed::ProcessOne(WaveTrack * track, - sampleCount start, sampleCount end, bool first) + sampleCount start, sampleCount end) { if (track == NULL) return false; @@ -268,8 +257,10 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track, // sample data double newLength = outputTrack->GetEndTime(); if (bLoopSuccess) { - SetTimeWarper(new LinearTimeWarper(mCurT0, mCurT0, mCurT1, mCurT0 + newLength )); - track->ClearAndPaste(mCurT0, mCurT1, outputTrack, true, false, mOutputTracks, true, first, GetTimeWarper()); + SetTimeWarper(new LinearTimeWarper( + mCurT0, mCurT0, mCurT1, mCurT0 + newLength )); + track->ClearAndPaste(mCurT0, mCurT1, outputTrack, true, false, + GetTimeWarper()); } if (newLength > m_maxNewLength) diff --git a/src/effects/ChangeSpeed.h b/src/effects/ChangeSpeed.h index f6f89c84f..d8cc6008d 100644 --- a/src/effects/ChangeSpeed.h +++ b/src/effects/ChangeSpeed.h @@ -57,13 +57,13 @@ class EffectChangeSpeed : public Effect { virtual bool Process(); private: - bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end, bool first); + bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end); bool ProcessLabelTrack(Track *t); private: // track related int mCurTrackNum; - double m_maxNewLength; + double m_maxNewLength; double mCurT0; double mCurT1; diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index dc87d840e..e3d755089 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -247,31 +247,12 @@ void Effect::CopyInputTracks(int trackType) TrackListOfKindIterator aIt(trackType, mTracks); t2bHash added; - //for each track that is selected for (Track *aTrack = aIt.First(); aTrack; aTrack = aIt.Next()) { - if (!aTrack->GetSelected()) { - continue; - } - TrackGroupIterator gIt(mTracks); - Track *gTrack = gIt.First(aTrack); - - //if the track is part of a group - if (trackType == Track::All && gTrack != NULL) { - //go to the project tracks and add all the tracks in the same group - for( ; gTrack; gTrack = gIt.Next() ) { - // only add if the track was not added before - if (added.find(gTrack) == added.end()) { - added[gTrack]=true; - Track *o = gTrack->Duplicate(); - mOutputTracks->Add(o); - mIMap.Add(gTrack); - mOMap.Add(o); - } - } - } - //otherwise just add the track - else { + // Include selected tracks, plus sync-selected tracks for Track::All) + if (aTrack->GetSelected() || + (trackType == Track::All && aTrack->IsSynchroSelected())) + { Track *o = aTrack->Duplicate(); mOutputTracks->Add(o); mIMap.Add(aTrack); diff --git a/src/effects/Generator.cpp b/src/effects/Generator.cpp index 668fa370b..ba3d7eaf2 100644 --- a/src/effects/Generator.cpp +++ b/src/effects/Generator.cpp @@ -26,8 +26,7 @@ bool Generator::Process() BeforeGenerate(); - // Set up mOutputTracks. This effect needs Track::All because it uses ClearAndPaste - // that need to have label tracks. + // Set up mOutputTracks. This effect needs Track::All for grouping this->CopyInputTracks(Track::All); // Iterate over the tracks @@ -36,15 +35,9 @@ bool Generator::Process() TrackListIterator iter(mOutputTracks); Track* t = iter.First(); - // we only do a "group change" in the first selected track of the group. - // ClearAndPaste has a call to Paste that does changes to the group tracks - bool first = true; - while (t != NULL) { - if (t->GetKind() == Track::Label) - first = true; - else if (t->GetKind() == Track::Wave && t->GetSelected()) { + if (t->GetKind() == Track::Wave && t->GetSelected()) { WaveTrack* track = (WaveTrack*)t; bool editClipCanMove; @@ -76,11 +69,7 @@ bool Generator::Process() tmp->Flush(); SetTimeWarper(new StepTimeWarper(mT1, mDuration-mT1)); bGoodResult = track->ClearAndPaste(mT0, mT1, tmp, true, - false, mOutputTracks, - false, !first, GetTimeWarper()); - if (first) { - first = false; - } + false, GetTimeWarper()); delete tmp; } @@ -98,6 +87,9 @@ bool Generator::Process() ntrack++; } + else if (t->IsSynchroSelected()) { + t->SyncAdjust(mT1, mT0 + mDuration); + } // Move on to the next track t = iter.Next(); } diff --git a/src/effects/Repeat.cpp b/src/effects/Repeat.cpp index ef50292b8..e03347159 100644 --- a/src/effects/Repeat.cpp +++ b/src/effects/Repeat.cpp @@ -110,44 +110,28 @@ bool EffectRepeat::TransferParameters( Shuttle & shuttle ) bool EffectRepeat::Process() { - // Set up mOutputTracks. This effect needs Track::All because it uses Paste that needs to have label tracks. + // Set up mOutputTracks. This effect needs Track::All for grouping this->CopyInputTracks(Track::All); int nTrack = 0; bool bGoodResult = true; double maxDestLen = 0.0; // used to change selection to generated bit - // Is linking enabled? - AudacityProject *p = GetActiveProject(); - bool isSticky = ( p && p->IsSticky()); - TrackListIterator iter(mOutputTracks); - // we only do a "group change" in the first selected track of the group. - // Paste call does changes to the group tracks - bool first = true; - for (Track *t = iter.First(); t && bGoodResult; t = iter.Next()) { if (t->GetKind() == Track::Label) { - // We repeat labels if linking is enabled and a WaveTrack before this - // has been repeated, or if the label track is selected - if (t->GetSelected() || (isSticky && !first)) + if (t->GetSelected() || t->IsSynchroSelected()) { LabelTrack* track = (LabelTrack*)t; - // If this track isn't selected, ShiftLabelsOnInsert() has - // already been called - if (t->GetSelected()) - track->ShiftLabelsOnInsert((mT1 - mT0) * repeatCount, mT1); - if (!track->Repeat(mT0, mT1, repeatCount)) { bGoodResult = false; break; } } - first = true; } else if (t->GetKind() == Track::Wave && t->GetSelected()) { @@ -166,30 +150,23 @@ bool EffectRepeat::Process() track->Copy(mT0, mT1, &dest); for(int j=0; jPaste(tc, dest, mOutputTracks) || - TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. - { - bGoodResult = false; - break; - } - } - else { - if (!track->HandlePaste(tc, dest) || - TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. - { - bGoodResult = false; - break; - } + if (!track->Paste(tc, dest) || + TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. + { + bGoodResult = false; + break; } tc += tLen; } - first = false; if (tc > maxDestLen) maxDestLen = tc; delete dest; nTrack++; } + else if (t->IsSynchroSelected()) + { + t->SyncAdjust(mT1, mT1 + (mT1 - mT0) * repeatCount); + } } if (bGoodResult) diff --git a/src/effects/Reverse.cpp b/src/effects/Reverse.cpp index 9bec37124..13d30d7cf 100644 --- a/src/effects/Reverse.cpp +++ b/src/effects/Reverse.cpp @@ -36,41 +36,33 @@ bool EffectReverse::Process() //Track::All is needed because Reverse should move the labels too this->CopyInputTracks(Track::All); // Set up mOutputTracks. bool bGoodResult = true; - Track *lastGroup = NULL; // First track of group of last acted-on WaveTrack - TrackGroupIterator gIt(mOutputTracks); TrackListIterator iter(mOutputTracks); Track *t = iter.First(); int count = 0; while (t) { - if (t->GetKind() == Track::Wave) { + if (t->GetKind() == Track::Wave && + (t->GetSelected() || t->IsSynchroSelected())) + { WaveTrack *track = (WaveTrack*)t; - - if (track->GetSelected()) { - if (mT1 > mT0) { - sampleCount start = track->TimeToLongSamples(mT0); - sampleCount end = track->TimeToLongSamples(mT1); - sampleCount len = (sampleCount)(end - start); - if (!ProcessOneWave(count, track, start, len)) - { - bGoodResult = false; - break; - } + if (mT1 > mT0) { + sampleCount start = track->TimeToLongSamples(mT0); + sampleCount end = track->TimeToLongSamples(mT1); + sampleCount len = (sampleCount)(end - start); + + if (!ProcessOneWave(count, track, start, len)) + { + bGoodResult = false; + break; } - - // Update grouping variables - lastGroup = gIt.First(t); } } - else if (t->GetKind() == Track::Label) { - AudacityProject *p = GetActiveProject(); - if ((p && p->IsSticky() && gIt.First(t) == lastGroup) || - t->GetSelected()) - { - LabelTrack *track = (LabelTrack*)t; - track->ChangeLabelsOnReverse(mT0, mT1); - } + else if (t->GetKind() == Track::Label && + (t->GetSelected() || t->IsSynchroSelected())) + { + LabelTrack *track = (LabelTrack*)t; + track->ChangeLabelsOnReverse(mT0, mT1); } t = iter.Next(); count++; diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index d853fea06..7d794eea3 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -156,14 +156,14 @@ bool EffectSBSMS::ProcessLabelTrack(Track *t) TimeWarper *warper = NULL; if (rateStart == rateEnd) { - warper = new LinearTimeWarper(mCurT0, mCurT0, - mCurT1, mCurT0+(mCurT1-mCurT0)*mTotalStretch); + warper = new LinearTimeWarper(mT0, mT0, + mT1, mT0+(mT1-mT0)*mTotalStretch); } else { - warper = new LogarithmicTimeWarper(mCurT0, mCurT1, + warper = new LogarithmicTimeWarper(mT0, mT1, rateStart, rateEnd); } - SetTimeWarper(new RegionTimeWarper(mCurT0, mCurT1, warper)); + SetTimeWarper(new RegionTimeWarper(mT0, mT1, warper)); LabelTrack *lt = (LabelTrack*)t; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); @@ -183,11 +183,7 @@ bool EffectSBSMS::Process() //Track::All is needed because this effect needs to introduce silence in the group tracks to keep sync this->CopyInputTracks(Track::All); // Set up mOutputTracks. TrackListIterator iter(mOutputTracks); - // go to first wavetrack Track* t; - for (t = iter.First(); t->GetKind() != Track::Wave; t = iter.Next()); - if (!t) - return false; mCurTrackNum = 0; double maxDuration = 0.0; @@ -197,21 +193,25 @@ bool EffectSBSMS::Process() else mTotalStretch = 1.0/(rateEnd-rateStart)*log(rateEnd/rateStart); + // Must sync if selection length will change + bool mustSync = (mTotalStretch != 1.0); - // we only do a "group change" in the first selected track of the group. - // ClearAndPaste has a call to Paste that does changes to the group tracks - bool first = true; - + t = iter.First(); while (t != NULL) { - if (t->GetKind() == Track::Label) { - first = true; - if (t->GetSelected() && !ProcessLabelTrack(t)) + if (t->GetKind() == Track::Label && + (t->GetSelected() || (mustSync && t->IsSynchroSelected())) ) + { + if (t->GetSelected() || t->IsSynchroSelected()) { - bGoodResult = false; - break; + if (!ProcessLabelTrack(t)) { + bGoodResult = false; + break; + } } } - else if (t->GetKind() == Track::Wave && t->GetSelected()) { + else if (t->GetKind() == Track::Wave && + (t->GetSelected() || (mustSync && t->IsSynchroSelected())) ) + { WaveTrack* leftTrack = (WaveTrack*)t; //Get start and end times from track @@ -396,16 +396,20 @@ bool EffectSBSMS::Process() if(rightTrack) rb.outputRightTrack->Flush(); - leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack, true, false, NULL, true, first, GetTimeWarper()); + leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack, + true, false, GetTimeWarper()); if(rightTrack) { - rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack, true, false, NULL, true, false, GetTimeWarper()); + rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack, + true, false, GetTimeWarper()); } - - first = false; } mCurTrackNum++; } + else if (mustSync && t->IsSynchroSelected()) + { + t->SyncAdjust(mCurT1, mCurT0 + (mCurT1 - mCurT0) * mTotalStretch); + } //Iterate to the next track t = iter.Next(); } diff --git a/src/effects/SoundTouchEffect.cpp b/src/effects/SoundTouchEffect.cpp index 8dbac38c0..26c86d3bd 100644 --- a/src/effects/SoundTouchEffect.cpp +++ b/src/effects/SoundTouchEffect.cpp @@ -18,9 +18,9 @@ effect that uses SoundTouch to do its processing (ChangeTempo #include -#include "SoundTouchEffect.h" #include "../WaveTrack.h" #include "../Project.h" +#include "SoundTouchEffect.h" #include "TimeWarper.h" bool EffectSoundTouch::ProcessLabelTrack(Track *track) @@ -37,37 +37,40 @@ bool EffectSoundTouch::ProcessLabelTrack(Track *track) bool EffectSoundTouch::Process() { // Assumes that mSoundTouch has already been initialized - // by the subclass for subclass-specific parameters. + // by the subclass for subclass-specific parameters. The + // time warper should also be set. + + // Check if this effect will alter the selection length; if so, we need + // to operate on sync-selected tracks + bool mustSync = true; + if (mT1 == GetTimeWarper()->Warp(mT1)) { + mustSync = false; + } //Iterate over each track - //Track::All is needed because this effect needs to introduce silence in the group tracks to keep sync - this->CopyInputTracks(Track::All); // Set up mOutputTracks. + //Track::All is needed for group behavior + this->CopyInputTracks(Track::All); bool bGoodResult = true; TrackListIterator iter(mOutputTracks); - // go to first wavetrack Track* t; - for (t = iter.First(); t->GetKind() != Track::Wave; t = iter.Next()); - if (!t) - return false; - WaveTrack* leftTrack = (WaveTrack*)t; mCurTrackNum = 0; - m_maxNewLength = 0.0; - - // we only do a "group change" in the first selected track of the group. - // ClearAndPaste has a call to Paste that does changes to the group tracks - bool first = true; + m_maxNewLength = 0.0; + t = iter.First(); while (t != NULL) { - if (t->GetKind() == Track::Label) { - first = true; - if (t->GetSelected() && !ProcessLabelTrack(t)) + if (t->GetKind() == Track::Label && + (t->GetSelected() || (mustSync && t->IsSynchroSelected())) ) + { + if (!ProcessLabelTrack(t)) { bGoodResult = false; break; } } - else if (t->GetKind() == Track::Wave && t->GetSelected()) { + else if (t->GetKind() == Track::Wave && + (t->GetSelected() || (mustSync && t->IsSynchroSelected())) ) + { WaveTrack* leftTrack = (WaveTrack*)t; //Get start and end times from track mCurT0 = leftTrack->GetStartTime(); @@ -102,7 +105,7 @@ bool EffectSoundTouch::Process() mSoundTouch->setChannels(2); //ProcessStereo() (implemented below) processes a stereo track - if (!ProcessStereo(leftTrack, rightTrack, start, end, first)) + if (!ProcessStereo(leftTrack, rightTrack, start, end)) { bGoodResult = false; break; @@ -117,16 +120,19 @@ bool EffectSoundTouch::Process() mSoundTouch->setChannels(1); //ProcessOne() (implemented below) processes a single track - if (!ProcessOne(leftTrack, start, end, first)) + if (!ProcessOne(leftTrack, start, end)) { bGoodResult = false; break; } } - first = false; } mCurTrackNum++; } + else if (mustSync && t->IsSynchroSelected()) { + t->SyncAdjust(mT1, GetTimeWarper()->Warp(mT1)); + } + //Iterate to the next track t = iter.Next(); } @@ -146,7 +152,7 @@ bool EffectSoundTouch::Process() //ProcessOne() takes a track, transforms it to bunch of buffer-blocks, //and executes ProcessSoundTouch on these blocks bool EffectSoundTouch::ProcessOne(WaveTrack *track, - sampleCount start, sampleCount end, bool first) + sampleCount start, sampleCount end) { WaveTrack *outputTrack; sampleCount s; @@ -217,7 +223,7 @@ bool EffectSoundTouch::ProcessOne(WaveTrack *track, // Take the output track and insert it in place of the original // sample data - track->ClearAndPaste(mCurT0, mCurT1, outputTrack, true, false, NULL, true, first, GetTimeWarper()); + track->ClearAndPaste(mCurT0, mCurT1, outputTrack, true, false, GetTimeWarper()); double newLength = outputTrack->GetEndTime(); m_maxNewLength = wxMax(m_maxNewLength, newLength); @@ -230,7 +236,7 @@ bool EffectSoundTouch::ProcessOne(WaveTrack *track, } bool EffectSoundTouch::ProcessStereo(WaveTrack* leftTrack, WaveTrack* rightTrack, - sampleCount start, sampleCount end, bool first) + sampleCount start, sampleCount end) { mSoundTouch->setSampleRate((unsigned int)(leftTrack->GetRate()+0.5)); @@ -321,8 +327,8 @@ bool EffectSoundTouch::ProcessStereo(WaveTrack* leftTrack, WaveTrack* rightTrack // Take the output tracks and insert in place of the original // sample data. - leftTrack->ClearAndPaste(mCurT0, mCurT1, outputLeftTrack, true, false, NULL, true, first, GetTimeWarper()); - rightTrack->ClearAndPaste(mCurT0, mCurT1, outputRightTrack, true, false, NULL, true, false, GetTimeWarper()); + leftTrack->ClearAndPaste(mCurT0, mCurT1, outputLeftTrack, true, false, GetTimeWarper()); + rightTrack->ClearAndPaste(mCurT0, mCurT1, outputRightTrack, true, false, GetTimeWarper()); // Track the longest result length double newLength = outputLeftTrack->GetEndTime(); diff --git a/src/effects/SoundTouchEffect.h b/src/effects/SoundTouchEffect.h index 4df5990e3..97aefb351 100644 --- a/src/effects/SoundTouchEffect.h +++ b/src/effects/SoundTouchEffect.h @@ -44,17 +44,16 @@ class EffectSoundTouch:public Effect { private: bool ProcessLabelTrack(Track *track); - bool ProcessOne(WaveTrack * t, - sampleCount start, sampleCount end, bool first); + bool ProcessOne(WaveTrack * t, sampleCount start, sampleCount end); bool ProcessStereo(WaveTrack* leftTrack, WaveTrack* rightTrack, - sampleCount start, sampleCount end, bool first); + sampleCount start, sampleCount end); bool ProcessStereoResults(const unsigned int outputCount, WaveTrack* outputLeftTrack, WaveTrack* outputRightTrack); int mCurTrackNum; - double m_maxNewLength; + double m_maxNewLength; }; #endif diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp index cf9453560..142d54460 100644 --- a/src/effects/StereoToMono.cpp +++ b/src/effects/StereoToMono.cpp @@ -96,7 +96,7 @@ bool EffectStereoToMono::ProcessOne(int count) double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime()); mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime()); mOutTrack->Flush(); - mLeftTrack->HandlePaste(minStart, mOutTrack); + mLeftTrack->Paste(minStart, mOutTrack); mLeftTrack->SetLinked(false); mRightTrack->SetLinked(false); mLeftTrack->SetChannel(Track::MonoChannel); diff --git a/src/effects/TruncSilence.cpp b/src/effects/TruncSilence.cpp index 93fd0fae2..a87bd2ff9 100644 --- a/src/effects/TruncSilence.cpp +++ b/src/effects/TruncSilence.cpp @@ -421,13 +421,10 @@ bool EffectTruncSilence::Process() // Remove stale data at end of output tracks. if (!cancelled && (outTrackOffset < end)) { t = (WaveTrack *) iterOut.First(); - if( p->IsSticky() ) - t->Clear(outTrackOffset / rate, t1, mOutputTracks); - else - while(t) { - t->Clear(outTrackOffset / rate, t1, mOutputTracks); - t = (WaveTrack *) iterOut.Next(); - } + while(t) { + t->Clear(outTrackOffset / rate, t1); + t = (WaveTrack *) iterOut.Next(); + } t1 = outTrackOffset / rate; } diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index 05998839d..1e309b530 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -508,6 +508,8 @@ bool EffectNyquist::Process() mDebugOutput = ""; // Keep track of whether the current track is first selected in its group + // (we have no idea what the length of the returned audio will be, so we have + // to handle group behavior the "old" way). mFirstInGroup = true; Track *gtLast = NULL; @@ -775,9 +777,19 @@ bool EffectNyquist::ProcessOne() out = mOutputTrack[0]; } - // If this track is not first in its group we set useHandlePaste - mCurTrack[i]->ClearAndPaste(mT0, mT1, out, false, false, - NULL, false, !mFirstInGroup); + mCurTrack[i]->ClearAndPaste(mT0, mT1, out, false, false); + // If we were first in the group adjust non-selected group tracks + if (mFirstInGroup) { + TrackGroupIterator git(mOutputTracks); + Track *t; + for (t = git.First(mCurTrack[i]); t; t = git.Next()) + { + if (!t->GetSelected() && t->IsSynchroSelected()) { + t->SyncAdjust(mT1, mT0 + out->GetEndTime()); + } + } + } + // Only the first channel can be first in its group mFirstInGroup = false; } diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 814c8dc0b..8a091eb9a 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1000,10 +1000,6 @@ void ControlToolBar::SetupCutPreviewTracks(double playStart, double cutStart, if (track1) { - // Temporarily disable sticky track handling - bool sticky = p->GetStickyFlag(); - p->SetStickyFlag(false); - // Duplicate and change tracks track1 = track1->Duplicate(); track1->Clear(cutStart, cutEnd); @@ -1017,9 +1013,6 @@ void ControlToolBar::SetupCutPreviewTracks(double playStart, double cutStart, mCutPreviewTracks->Add(track1); if (track2) mCutPreviewTracks->Add(track2); - - // Reinstate sticky track handling - p->SetStickyFlag(sticky); } } }