From 1be3187b991b7ed6317e59abf6f5963b338f49a5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 11 Apr 2017 17:55:19 -0400 Subject: [PATCH] Use TrackIterRange::Visit --- src/Menus.cpp | 261 +++++++++++++------------------ src/Project.cpp | 72 ++++----- src/Snap.cpp | 36 ++--- src/effects/ChangeSpeed.cpp | 39 ++--- src/effects/Effect.cpp | 246 +++++++++++++++-------------- src/effects/Generator.cpp | 42 ++--- src/effects/Repeat.cpp | 37 ++--- src/effects/Reverse.cpp | 28 ++-- src/effects/SBSMSEffect.cpp | 75 +++++---- src/effects/SoundTouchEffect.cpp | 59 +++---- src/effects/TruncSilence.cpp | 44 +++--- 11 files changed, 414 insertions(+), 525 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index e3bca4eb6..0e7aca038 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -2289,13 +2289,12 @@ CommandFlag MenuCommandHandler::GetUpdateFlags if (!selectedRegion.isPoint()) flags |= TimeSelectedFlag; - TrackListIterator iter(project.GetTracks()); - Track *t = iter.First(); - while (t) { + auto tracks = project.GetTracks(); + auto trackRange = tracks->Any(); + if ( trackRange ) flags |= TracksExistFlag; - if (t->GetKind() == Track::Label) { - LabelTrack *lt = (LabelTrack *) t; - + trackRange.Visit( + [&](LabelTrack *lt) { flags |= LabelTracksExistFlag; if (lt->GetSelected()) { @@ -2313,8 +2312,8 @@ CommandFlag MenuCommandHandler::GetUpdateFlags if (lt->IsTextSelected()) { flags |= CutCopyAvailableFlag; } - } - else if (t->GetKind() == Track::Wave) { + }, + [&](WaveTrack *t) { flags |= WaveTracksExistFlag; flags |= PlayableTracksExistFlag; if (t->GetSelected()) { @@ -2331,9 +2330,8 @@ CommandFlag MenuCommandHandler::GetUpdateFlags flags |= HasWaveDataFlag; } #if defined(USE_MIDI) - else if (t->GetKind() == Track::Note) { - NoteTrack *nt = (NoteTrack *) t; - + , + [&](NoteTrack *nt) { flags |= NoteTracksExistFlag; #ifdef EXPERIMENTAL_MIDI_OUT flags |= PlayableTracksExistFlag; @@ -2346,8 +2344,7 @@ CommandFlag MenuCommandHandler::GetUpdateFlags } } #endif - t = iter.Next(); - } + ); if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0) flags |= ClipboardFlag; @@ -5589,24 +5586,21 @@ void MenuCommandHandler::OnCut(const CommandContext &context) auto pNewClipboard = TrackList::Create(); auto &newClipboard = *pNewClipboard; - n = iter.First(); - while (n) { - if (n->GetSelected()) { - Track::Holder dest; + tracks->Selected().Visit( #if defined(USE_MIDI) - if (n->GetKind() == Track::Note) - // Since portsmf has a built-in cut operator, we use that instead - dest = n->Cut(selectedRegion.t0(), - selectedRegion.t1()); - else + [&](NoteTrack *n) { + // Since portsmf has a built-in cut operator, we use that instead + auto dest = n->Cut(selectedRegion.t0(), + selectedRegion.t1()); + FinishCopy(n, std::move(dest), newClipboard); + }, #endif - dest = n->Copy(selectedRegion.t0(), - selectedRegion.t1()); - + [&](Track *n) { + auto dest = n->Copy(selectedRegion.t0(), + selectedRegion.t1()); FinishCopy(n, std::move(dest), newClipboard); } - n = iter.Next(); - } + ); // Survived possibility of exceptions. Commit changes to the clipboard now. newClipboard.Swap(*AudacityProject::msClipboard); @@ -5614,35 +5608,28 @@ void MenuCommandHandler::OnCut(const CommandContext &context) // Proceed to change the project. If this throws, the project will be // rolled back by the top level handler. - n = iter.First(); - while (n) { - // We clear from selected and sync-lock selected tracks. - if (n->GetSelected() || n->IsSyncLockSelected()) { - switch (n->GetKind()) - { + (tracks->Any() + &Track::IsSelectedOrSyncLockSelected).Visit( #if defined(USE_MIDI) - case Track::Note: - //if NoteTrack, it was cut, so do not clear anything - break; + [](NoteTrack*) { + //if NoteTrack, it was cut, so do not clear anything + + // PRL: But what if it was sync lock selected only, not selected? + }, #endif - case Track::Wave: - if (gPrefs->Read(wxT("/GUI/EnableCutLines"), (long)0)) { - ((WaveTrack*)n)->ClearAndAddCutLine( - selectedRegion.t0(), - selectedRegion.t1()); - break; - } - - // Fall through - - default: - n->Clear(selectedRegion.t0(), - selectedRegion.t1()); - break; + [&](WaveTrack *wt, const Track::Fallthrough &fallthrough) { + if (gPrefs->Read(wxT("/GUI/EnableCutLines"), (long)0)) { + wt->ClearAndAddCutLine( + selectedRegion.t0(), + selectedRegion.t1()); } + else + fallthrough(); + }, + [&](Track *n) { + n->Clear(selectedRegion.t0(), + selectedRegion.t1()); } - n = iter.Next(); - } + ); AudacityProject::msClipT0 = selectedRegion.t0(); AudacityProject::msClipT1 = selectedRegion.t1(); @@ -5670,35 +5657,30 @@ void MenuCommandHandler::OnSplitCut(const CommandContext &context) auto &selectedRegion = project.GetViewInfo().selectedRegion; auto historyWindow = project.GetHistoryWindow(); - TrackListIterator iter(tracks); - Track *n = iter.First(); - AudacityProject::ClearClipboard(); auto pNewClipboard = TrackList::Create(); auto &newClipboard = *pNewClipboard; - while (n) { - if (n->GetSelected()) { - Track::Holder dest; - if (n->GetKind() == Track::Wave) - { - dest = ((WaveTrack*)n)->SplitCut( - selectedRegion.t0(), - selectedRegion.t1()); - } - else - { - dest = n->Copy(selectedRegion.t0(), + Track::Holder dest; + + tracks->Selected().Visit( + [&](WaveTrack *n) { + dest = n->SplitCut( + selectedRegion.t0(), + selectedRegion.t1()); + if (dest) + FinishCopy(n, std::move(dest), newClipboard); + }, + [&](Track *n) { + dest = n->Copy(selectedRegion.t0(), + selectedRegion.t1()); + n->Silence(selectedRegion.t0(), selectedRegion.t1()); - n->Silence(selectedRegion.t0(), - selectedRegion.t1()); - } if (dest) FinishCopy(n, std::move(dest), newClipboard); } - n = iter.Next(); - } + ); // Survived possibility of exceptions. Commit changes to the clipboard now. newClipboard.Swap(*AudacityProject::msClipboard); @@ -6255,32 +6237,19 @@ void MenuCommandHandler::OnTrim(const CommandContext &context) if (selectedRegion.isPoint()) return; - TrackListIterator iter(tracks); - Track *n = iter.First(); - - while (n) { - if (n->GetSelected()) { - switch (n->GetKind()) - { -#if defined(USE_MIDI) - case Track::Note: - ((NoteTrack*)n)->Trim(selectedRegion.t0(), - selectedRegion.t1()); - break; + tracks->Selected().Visit( +#ifdef USE_MIDI + [&](NoteTrack *nt) { + nt->Trim(selectedRegion.t0(), + selectedRegion.t1()); + }, #endif - - case Track::Wave: - //Delete the section before the left selector - ((WaveTrack*)n)->Trim(selectedRegion.t0(), - selectedRegion.t1()); - break; - - default: - break; - } + [&](WaveTrack *wt) { + //Delete the section before the left selector + wt->Trim(selectedRegion.t0(), + selectedRegion.t1()); } - n = iter.Next(); - } + ); project.PushState( wxString::Format( @@ -6303,24 +6272,16 @@ void MenuCommandHandler::OnSplitDelete(const CommandContext &context) auto tracks = project.GetTracks(); auto &selectedRegion = project.GetViewInfo().selectedRegion; - TrackListIterator iter(tracks); - - Track *n = iter.First(); - - while (n) { - if (n->GetSelected()) { - if (n->GetKind() == Track::Wave) - { - ((WaveTrack*)n)->SplitDelete(selectedRegion.t0(), - selectedRegion.t1()); - } - else { - n->Silence(selectedRegion.t0(), - selectedRegion.t1()); - } + tracks->Selected().Visit( + [&](WaveTrack *wt) { + wt->SplitDelete(selectedRegion.t0(), + selectedRegion.t1()); + }, + [&](Track *n) { + n->Silence(selectedRegion.t0(), + selectedRegion.t1()); } - n = iter.Next(); - } + ); project.PushState( wxString::Format(_("Split-deleted %.2f seconds at t=%.2f"), @@ -6713,39 +6674,43 @@ void MenuCommandHandler::OnSplitNew(const CommandContext &context) auto tracks = project.GetTracks(); auto &selectedRegion = project.GetViewInfo().selectedRegion; - TrackListIterator iter(tracks); - Track *l = iter.Last(); + Track::Holder dest; - for (Track *n = iter.First(); n; n = iter.Next()) { - if (n->GetSelected()) { - Track::Holder dest; - double newt0 = 0, newt1 = 0; - double offset = n->GetOffset(); - if (n->GetKind() == Track::Wave) { - const auto wt = static_cast(n); + // This iteration is unusual because we add to the list inside the loop + auto range = tracks->Selected(); + auto last = *range.rbegin(); + for (auto track : range) { + track->TypeSwitch( + [&](WaveTrack *wt) { // Clips must be aligned to sample positions or the NEW clip will not fit in the gap where it came from + double offset = wt->GetOffset(); offset = wt->LongSamplesToTime(wt->TimeToLongSamples(offset)); - newt0 = wt->LongSamplesToTime(wt->TimeToLongSamples(selectedRegion.t0())); - newt1 = wt->LongSamplesToTime(wt->TimeToLongSamples(selectedRegion.t1())); + double newt0 = wt->LongSamplesToTime(wt->TimeToLongSamples( + selectedRegion.t0())); + double newt1 = wt->LongSamplesToTime(wt->TimeToLongSamples( + selectedRegion.t1())); dest = wt->SplitCut(newt0, newt1); + if (dest) { + dest->SetOffset(wxMax(newt0, offset)); + FinishCopy(wt, std::move(dest), *tracks); + } } #if 0 + , // LL: For now, just skip all non-wave tracks since the other do not // yet support proper splitting. - else { - dest = n->Cut(selectedRegion.t0(), - selectedRegion.t1()); + [&](Track *n) { + dest = n->Cut(viewInfo.selectedRegion.t0(), + viewInfo.selectedRegion.t1()); + if (dest) { + dest->SetOffset(wxMax(0, n->GetOffset())); + FinishCopy(n, std::move(dest), *tracks); + } } #endif - if (dest) { - dest->SetOffset(wxMax(newt0, offset)); - FinishCopy(n, std::move(dest), *tracks); - } - } - - if (n == l) { + ); + if (track == last) break; - } } project.PushState(_("Split to new track"), _("Split New")); @@ -8928,29 +8893,25 @@ void MenuCommandHandler::OnScoreAlign(const CommandContext &context) auto tracks = project.GetTracks(); const auto rate = project.GetRate(); - TrackListIterator iter(tracks); - Track *t = iter.First(); int numWaveTracksSelected = 0; int numNoteTracksSelected = 0; int numOtherTracksSelected = 0; - NoteTrack *nt; double endTime = 0.0; // Iterate through once to make sure that there is exactly // one WaveTrack and one NoteTrack selected. - while (t) { - if (t->GetSelected()) { - if (t->GetKind() == Track::Wave) { - numWaveTracksSelected++; - WaveTrack *wt = (WaveTrack *) t; - endTime = endTime > wt->GetEndTime() ? endTime : wt->GetEndTime(); - } else if(t->GetKind() == Track::Note) { - numNoteTracksSelected++; - nt = (NoteTrack *) t; - } else numOtherTracksSelected++; + GetTracks()->Selected().Visit( + [&](WaveTrack *wt) { + numWaveTracksSelected++; + endTime = endTime > wt->GetEndTime() ? endTime : wt->GetEndTime(); + }, + [&](NoteTrack *) { + numNoteTracksSelected++; + }, + [&](Track*) { + numOtherTracksSelected++; } - t = iter.Next(); - } + ); if(numWaveTracksSelected == 0 || numNoteTracksSelected != 1 || diff --git a/src/Project.cpp b/src/Project.cpp index 104be1704..43f2e2f79 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3821,55 +3821,45 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCopy) mTags->WriteXML(xmlFile); - const Track *t; - WaveTrack* pWaveTrack; - TrackListConstIterator iter(GetTracks()); - t = iter.First(); unsigned int ndx = 0; - while (t) { - if ((t->GetKind() == Track::Wave) && bWantSaveCopy) - { - auto wt = static_cast(t); + GetTracks()->Any().Visit( + [&](WaveTrack *pWaveTrack) { + if (bWantSaveCopy) { + if (!pWaveTrack->IsLeader()) + return; - //vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML(). - xmlFile.StartTag(wxT("import")); - xmlFile.WriteAttr(wxT("filename"), mStrOtherNamesArray[ndx]); // Assumes mTracks order hasn't changed! + //vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML(). + xmlFile.StartTag(wxT("import")); + xmlFile.WriteAttr(wxT("filename"), mStrOtherNamesArray[ndx]); // Assumes mTracks order hasn't changed! - // Don't store "channel" and "linked" tags because the importer can figure that out, - // e.g., from stereo Ogg files. - // xmlFile.WriteAttr(wxT("channel"), t->GetChannel()); - // xmlFile.WriteAttr(wxT("linked"), t->GetLinked()); + // Don't store "channel" and "linked" tags because the importer can figure that out, + // e.g., from stereo Ogg files. + // xmlFile.WriteAttr(wxT("channel"), t->GetChannel()); + // xmlFile.WriteAttr(wxT("linked"), t->GetLinked()); - xmlFile.WriteAttr(wxT("offset"), t->GetOffset(), 8); - xmlFile.WriteAttr(wxT("mute"), wt->GetMute()); - xmlFile.WriteAttr(wxT("solo"), wt->GetSolo()); - xmlFile.WriteAttr(wxT("height"), t->GetActualHeight()); - xmlFile.WriteAttr(wxT("minimized"), t->GetMinimized()); + xmlFile.WriteAttr(wxT("offset"), pWaveTrack->GetOffset(), 8); + xmlFile.WriteAttr(wxT("mute"), pWaveTrack->GetMute()); + xmlFile.WriteAttr(wxT("solo"), pWaveTrack->GetSolo()); + xmlFile.WriteAttr(wxT("height"), pWaveTrack->GetActualHeight()); + xmlFile.WriteAttr(wxT("minimized"), pWaveTrack->GetMinimized()); - pWaveTrack = (WaveTrack*)t; - // Don't store "rate" tag because the importer can figure that out. - // xmlFile.WriteAttr(wxT("rate"), pWaveTrack->GetRate()); - xmlFile.WriteAttr(wxT("gain"), (double)pWaveTrack->GetGain()); - xmlFile.WriteAttr(wxT("pan"), (double)pWaveTrack->GetPan()); - xmlFile.EndTag(wxT("import")); + // Don't store "rate" tag because the importer can figure that out. + // xmlFile.WriteAttr(wxT("rate"), pWaveTrack->GetRate()); + xmlFile.WriteAttr(wxT("gain"), (double)pWaveTrack->GetGain()); + xmlFile.WriteAttr(wxT("pan"), (double)pWaveTrack->GetPan()); + xmlFile.EndTag(wxT("import")); - ndx++; - if (t->GetLinked()) - t = iter.Next(); - } - else if (t->GetKind() == Track::Wave) - { - pWaveTrack = (WaveTrack*)t; - pWaveTrack->SetAutoSaveIdent(mAutoSaving ? ++ndx : 0); + ndx++; + } + else { + pWaveTrack->SetAutoSaveIdent(mAutoSaving ? ++ndx : 0); + pWaveTrack->WriteXML(xmlFile); + } + }, + [&](Track *t) { t->WriteXML(xmlFile); } - else - { - t->WriteXML(xmlFile); - } - - t = iter.Next(); - } + ); if (!mAutoSaving) { diff --git a/src/Snap.cpp b/src/Snap.cpp index e77c7698a..843b30aad 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -16,6 +16,7 @@ #include "Project.h" #include "LabelTrack.h" +#include "NoteTrack.h" #include "WaveTrack.h" inline bool operator < (SnapPoint s1, SnapPoint s2) @@ -100,19 +101,14 @@ void SnapManager::Reinit() // Add a SnapPoint at t=0 mSnapPoints.push_back(SnapPoint{}); - TrackListConstIterator iter(mTracks); - for (const Track *track = iter.First(); track; track = iter.Next()) - { - if (mTrackExclusions && - mTrackExclusions->end() != - std::find(mTrackExclusions->begin(), mTrackExclusions->end(), track)) - { - continue; - } - - if (track->GetKind() == Track::Label) - { - LabelTrack *labelTrack = (LabelTrack *)track; + auto trackRange = + mTracks->Any() + - [&](const Track *pTrack){ + return mTrackExclusions && + make_iterator_range( *mTrackExclusions ).contains( pTrack ); + }; + trackRange.Visit( + [&](const LabelTrack *labelTrack) { for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) { const LabelStruct *label = labelTrack->GetLabel(i); @@ -124,10 +120,8 @@ void SnapManager::Reinit() CondListAdd(t1, labelTrack); } } - } - else if (track->GetKind() == Track::Wave) - { - auto waveTrack = static_cast(track); + }, + [&](const WaveTrack *waveTrack) { for (const auto &clip: waveTrack->GetClips()) { if (mClipExclusions) @@ -144,9 +138,7 @@ void SnapManager::Reinit() } if (skip) - { continue; - } } CondListAdd(clip->GetStartTime(), waveTrack); @@ -154,13 +146,13 @@ void SnapManager::Reinit() } } #ifdef USE_MIDI - else if (track->GetKind() == Track::Note) - { + , + [&](const NoteTrack *track) { CondListAdd(track->GetStartTime(), track); CondListAdd(track->GetEndTime(), track); } #endif - } + ); // Sort all by time std::sort(mSnapPoints.begin(), mSnapPoints.end()); diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index 3c7d00003..b0268397a 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -229,28 +229,23 @@ bool EffectChangeSpeed::Process() CopyInputTracks(Track::All); // Set up mOutputTracks. bool bGoodResult = true; - TrackListIterator iter(mOutputTracks.get()); - Track* t; mCurTrackNum = 0; mMaxNewLength = 0.0; mFactor = 100.0 / (100.0 + m_PercentChange); - t = iter.First(); - while (t != NULL) - { - if (t->GetKind() == Track::Label) { - if (t->GetSelected() || t->IsSyncLockSelected()) + mOutputTracks->Any().VisitWhile( bGoodResult, + [&](LabelTrack *lt) { + if (lt->GetSelected() || lt->IsSyncLockSelected()) { - if (!ProcessLabelTrack(static_cast(t))) { + if (!ProcessLabelTrack(lt)) bGoodResult = false; - break; - } } - } - else if (t->GetKind() == Track::Wave && t->GetSelected()) - { - WaveTrack *pOutWaveTrack = (WaveTrack*)t; + }, + [&](WaveTrack *pOutWaveTrack, const Track::Fallthrough &fallthrough) { + if (!pOutWaveTrack->GetSelected()) + return fallthrough(); + //Get start and end times from track mCurT0 = pOutWaveTrack->GetStartTime(); mCurT1 = pOutWaveTrack->GetEndTime(); @@ -268,21 +263,15 @@ bool EffectChangeSpeed::Process() //ProcessOne() (implemented below) processes a single track if (!ProcessOne(pOutWaveTrack, start, end)) - { bGoodResult = false; - break; - } } mCurTrackNum++; + }, + [&](Track *t) { + if (t->IsSyncLockSelected()) + t->SyncLockAdjust(mT1, mT0 + (mT1 - mT0) * mFactor); } - else if (t->IsSyncLockSelected()) - { - t->SyncLockAdjust(mT1, mT0 + (mT1 - mT0) * mFactor); - } - - //Iterate to the next track - t=iter.Next(); - } + ); if (bGoodResult) ReplaceProcessedTracks(bGoodResult); diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index d95a86cf0..e3694f1a0 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1348,154 +1348,152 @@ bool Effect::ProcessPass() mBufferSize = 0; mBlockSize = 0; - TrackListIterator iter(mOutputTracks.get()); int count = 0; bool clear = false; - Track* t = iter.First(); - for (t = iter.First(); t; t = iter.Next()) - { - if (t->GetKind() != Track::Wave || !t->GetSelected()) - { - if (t->IsSyncLockSelected()) - { - t->SyncLockAdjust(mT1, mT0 + mDuration); - } - continue; - } + const bool multichannel = mNumAudioIn > 1; + auto range = multichannel + ? mOutputTracks->Leaders() + : mOutputTracks->Any(); + range.VisitWhile( bGoodResult, + [&](WaveTrack *left, const Track::Fallthrough &fallthrough) { + if (!left->GetSelected()) + return fallthrough(); - WaveTrack *left = (WaveTrack *)t; - WaveTrack *right; - sampleCount len; - sampleCount leftStart; - sampleCount rightStart; + WaveTrack *right; + sampleCount len; + sampleCount leftStart; + sampleCount rightStart; - if (!isGenerator) - { - GetSamples(left, &leftStart, &len); - mSampleCnt = len; - } - else - { - len = 0; - leftStart = 0; - mSampleCnt = left->TimeToLongSamples(mDuration); - } - - mNumChannels = 1; - - if (left->GetChannel() == Track::LeftChannel) - { - map[0] = ChannelNameFrontLeft; - } - else if (left->GetChannel() == Track::RightChannel) - { - map[0] = ChannelNameFrontRight; - } - else - { - map[0] = ChannelNameMono; - } - map[1] = ChannelNameEOL; - - right = NULL; - rightStart = 0; - if (left->GetLinked() && mNumAudioIn > 1) - { - // Assume linked track is wave - right = static_cast(iter.Next()); if (!isGenerator) { - GetSamples(right, &rightStart, &len); - } - clear = false; - mNumChannels = 2; - - if (right->GetChannel() == Track::LeftChannel) - { - map[1] = ChannelNameFrontLeft; - } - else if (right->GetChannel() == Track::RightChannel) - { - map[1] = ChannelNameFrontRight; + GetSamples(left, &leftStart, &len); + mSampleCnt = len; } else { - map[1] = ChannelNameMono; + len = 0; + leftStart = 0; + mSampleCnt = left->TimeToLongSamples(mDuration); } - map[2] = ChannelNameEOL; - } - // Let the client know the sample rate - SetSampleRate(left->GetRate()); + mNumChannels = 1; - // Get the block size the client wants to use - auto max = left->GetMaxBlockSize() * 2; - mBlockSize = SetBlockSize(max); + if (left->GetChannel() == Track::LeftChannel) + { + map[0] = ChannelNameFrontLeft; + } + else if (left->GetChannel() == Track::RightChannel) + { + map[0] = ChannelNameFrontRight; + } + else + { + map[0] = ChannelNameMono; + } + map[1] = ChannelNameEOL; - // Calculate the buffer size to be at least the max rounded up to the clients - // selected block size. - const auto prevBufferSize = mBufferSize; - mBufferSize = ((max + (mBlockSize - 1)) / mBlockSize) * mBlockSize; + right = NULL; + rightStart = 0; + if (left->GetLinked() && multichannel) + { + // Assume linked track is wave + right = static_cast(left->GetLink()); + if (!isGenerator) + { + GetSamples(right, &rightStart, &len); + } + clear = false; + mNumChannels = 2; - // If the buffer size has changed, then (re)allocate the buffers - if (prevBufferSize != mBufferSize) - { - // Always create the number of input buffers the client expects even if we don't have - // the same number of channels. - inBufPos.reinit( mNumAudioIn ); - inBuffer.reinit( mNumAudioIn, mBufferSize ); + if (right->GetChannel() == Track::LeftChannel) + { + map[1] = ChannelNameFrontLeft; + } + else if (right->GetChannel() == Track::RightChannel) + { + map[1] = ChannelNameFrontRight; + } + else + { + map[1] = ChannelNameMono; + } + map[2] = ChannelNameEOL; + } - // We won't be using more than the first 2 buffers, so clear the rest (if any) - for (size_t i = 2; i < mNumAudioIn; i++) + // Let the client know the sample rate + SetSampleRate(left->GetRate()); + + // Get the block size the client wants to use + auto max = left->GetMaxBlockSize() * 2; + mBlockSize = SetBlockSize(max); + + // Calculate the buffer size to be at least the max rounded up to the clients + // selected block size. + const auto prevBufferSize = mBufferSize; + mBufferSize = ((max + (mBlockSize - 1)) / mBlockSize) * mBlockSize; + + // If the buffer size has changed, then (re)allocate the buffers + if (prevBufferSize != mBufferSize) + { + // Always create the number of input buffers the client expects even if we don't have + // the same number of channels. + inBufPos.reinit( mNumAudioIn ); + inBuffer.reinit( mNumAudioIn, mBufferSize ); + + // We won't be using more than the first 2 buffers, so clear the rest (if any) + for (size_t i = 2; i < mNumAudioIn; i++) + { + for (size_t j = 0; j < mBufferSize; j++) + { + inBuffer[i][j] = 0.0; + } + } + + // Always create the number of output buffers the client expects even if we don't have + // the same number of channels. + outBufPos.reinit( mNumAudioOut ); + // Output buffers get an extra mBlockSize worth to give extra room if + // the plugin adds latency + outBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize ); + } + + // (Re)Set the input buffer positions + for (size_t i = 0; i < mNumAudioIn; i++) + { + inBufPos[i] = inBuffer[i].get(); + } + + // (Re)Set the output buffer positions + for (size_t i = 0; i < mNumAudioOut; i++) + { + outBufPos[i] = outBuffer[i].get(); + } + + // Clear unused input buffers + if (!right && !clear && mNumAudioIn > 1) { for (size_t j = 0; j < mBufferSize; j++) { - inBuffer[i][j] = 0.0; + inBuffer[1][j] = 0.0; } + clear = true; } - // Always create the number of output buffers the client expects even if we don't have - // the same number of channels. - // Output buffers get an extra mBlockSize worth to give extra room if - // the plugin adds latency - outBufPos.reinit( mNumAudioOut ); - outBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize ); - } + // Go process the track(s) + bGoodResult = ProcessTrack( + count, map, left, right, leftStart, rightStart, len, + inBuffer, outBuffer, inBufPos, outBufPos); + if (!bGoodResult) + return; - // (Re)Set the input buffer positions - for (size_t i = 0; i < mNumAudioIn; i++) - { - inBufPos[i] = inBuffer[i].get(); + count++; + }, + [&](Track *t) { + if (t->IsSyncLockSelected()) + t->SyncLockAdjust(mT1, mT0 + mDuration); } - - // (Re)Set the output buffer positions - for (size_t i = 0; i < mNumAudioOut; i++) - { - outBufPos[i] = outBuffer[i].get(); - } - - // Clear unused input buffers - if (!right && !clear && mNumAudioIn > 1) - { - for (size_t j = 0; j < mBufferSize; j++) - { - inBuffer[1][j] = 0.0; - } - clear = true; - } - - // Go process the track(s) - bGoodResult = ProcessTrack( - count, map, left, right, leftStart, rightStart, len, - inBuffer, outBuffer, inBufPos, outBufPos); - if (!bGoodResult) - { - break; - } - - count++; - } + ); if (bGoodResult && GetType() == EffectTypeGenerate) { diff --git a/src/effects/Generator.cpp b/src/effects/Generator.cpp index 5b79c2a0c..c84b0a8c2 100644 --- a/src/effects/Generator.cpp +++ b/src/effects/Generator.cpp @@ -38,14 +38,11 @@ bool Generator::Process() // Iterate over the tracks bool bGoodResult = true; int ntrack = 0; - TrackListIterator iter(mOutputTracks.get()); - Track* t = iter.First(); - - while (t != NULL) - { - if (t->GetKind() == Track::Wave && t->GetSelected()) { - WaveTrack* track = (WaveTrack*)t; + mOutputTracks->Any().VisitWhile( bGoodResult, + [&](WaveTrack *track, const Track::Fallthrough &fallthrough) { + if (!track->GetSelected()) + return fallthrough(); bool editClipCanMove = gPrefs->GetEditClipsCanMove(); //if we can't move clips, and we're generating into an empty space, @@ -59,7 +56,8 @@ bool Generator::Process() wxICON_STOP, _("Error")); Failure(); - return false; + bGoodResult = false; + return; } if (GetDuration() > 0.0) @@ -87,7 +85,7 @@ bool Generator::Process() if (!bGoodResult) { Failure(); - return false; + return; } } else @@ -98,21 +96,23 @@ bool Generator::Process() } ntrack++; + }, + [&](Track *t) { + if (t->IsSyncLockSelected()) { + t->SyncLockAdjust(mT1, mT0 + GetDuration()); + } } - else if (t->IsSyncLockSelected()) { - t->SyncLockAdjust(mT1, mT0 + GetDuration()); - } - // Move on to the next track - t = iter.Next(); + ); + + if (bGoodResult) { + Success(); + + this->ReplaceProcessedTracks(bGoodResult); + + mT1 = mT0 + GetDuration(); // Update selection. } - Success(); - - this->ReplaceProcessedTracks(bGoodResult); - - mT1 = mT0 + GetDuration(); // Update selection. - - return true; + return bGoodResult; } bool BlockGenerator::GenerateTrack(WaveTrack *tmp, diff --git a/src/effects/Repeat.cpp b/src/effects/Repeat.cpp index bc83c3445..a1b2ab3cd 100644 --- a/src/effects/Repeat.cpp +++ b/src/effects/Repeat.cpp @@ -113,27 +113,19 @@ bool EffectRepeat::Process() bool bGoodResult = true; double maxDestLen = 0.0; // used to change selection to generated bit - TrackListIterator iter(mOutputTracks.get()); - - for (Track *t = iter.First(); t && bGoodResult; t = iter.Next()) - { - if (t->GetKind() == Track::Label) + mOutputTracks->Any().VisitWhile( bGoodResult, + [&](LabelTrack *track) { - if (t->GetSelected() || t->IsSyncLockSelected()) + if (track->GetSelected() || track->IsSyncLockSelected()) { - LabelTrack* track = (LabelTrack*)t; - if (!track->Repeat(mT0, mT1, repeatCount)) - { bGoodResult = false; - break; - } } - } - else if (t->GetKind() == Track::Wave && t->GetSelected()) + }, + [&](WaveTrack *track, const Track::Fallthrough &fallthrough) { - WaveTrack* track = (WaveTrack*)t; - + if (!track->GetSelected()) + return fallthrough(); // Fall through to next lambda auto start = track->TimeToLongSamples(mT0); auto end = track->TimeToLongSamples(mT1); auto len = end - start; @@ -141,9 +133,7 @@ bool EffectRepeat::Process() double tc = mT0 + tLen; if (len <= 0) - { - continue; - } + return; auto dest = track->Copy(mT0, mT1); for(int j=0; jPaste(tc, dest.get()); tc += tLen; @@ -159,12 +149,13 @@ bool EffectRepeat::Process() if (tc > maxDestLen) maxDestLen = tc; nTrack++; - } - else if (t->IsSyncLockSelected()) + }, + [&](Track *t) { - t->SyncLockAdjust(mT1, mT1 + (mT1 - mT0) * repeatCount); + if( t->IsSyncLockSelected() ) + t->SyncLockAdjust(mT1, mT1 + (mT1 - mT0) * repeatCount); } - } + ); if (bGoodResult) { diff --git a/src/effects/Reverse.cpp b/src/effects/Reverse.cpp index 0c361defc..794d9ed26 100644 --- a/src/effects/Reverse.cpp +++ b/src/effects/Reverse.cpp @@ -67,37 +67,27 @@ bool EffectReverse::Process() //Track::All is needed because Reverse should move the labels too this->CopyInputTracks(Track::All); // Set up mOutputTracks. bool bGoodResult = true; - - TrackListIterator iter(mOutputTracks.get()); - Track *t = iter.First(); int count = 0; - while (t) { - if (t->GetKind() == Track::Wave && - (t->GetSelected() || t->IsSyncLockSelected())) - { - WaveTrack *track = (WaveTrack*)t; + auto trackRange = + mOutputTracks->Any() + &Track::IsSelectedOrSyncLockSelected; + trackRange.VisitWhile( bGoodResult, + [&](WaveTrack * track) { if (mT1 > mT0) { auto start = track->TimeToLongSamples(mT0); auto end = track->TimeToLongSamples(mT1); auto len = end - start; if (!ProcessOneWave(count, track, start, len)) - { bGoodResult = false; - break; - } } - } - else if (t->GetKind() == Track::Label && - (t->GetSelected() || t->IsSyncLockSelected())) - { - LabelTrack *track = (LabelTrack*)t; + count++; + }, + [&](LabelTrack * track) { track->ChangeLabelsOnReverse(mT0, mT1); + count++; } - t = iter.Next(); - count++; - } + ); this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 6e1c3f895..b2c237605 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -217,8 +217,6 @@ bool EffectSBSMS::Process() //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. - TrackListIterator iter(mOutputTracks.get()); - Track* t; mCurTrackNum = 0; double maxDuration = 0.0; @@ -229,19 +227,16 @@ bool EffectSBSMS::Process() Slide pitchSlide(pitchSlideType,pitchStart,pitchEnd); mTotalStretch = rateSlide.getTotalStretch(); - t = iter.First(); - while (bGoodResult && t != NULL) { - if (t->GetKind() == Track::Label && - (t->GetSelected() || (mustSync && t->IsSyncLockSelected())) ) - { - if (!ProcessLabelTrack(static_cast(t))) { + mOutputTracks->Leaders().VisitWhile( bGoodResult, + [&](LabelTrack *lt, const Track::Fallthrough &fallthrough) { + if (!(lt->GetSelected() || (mustSync && lt->IsSyncLockSelected()))) + return fallthrough(); + if (!ProcessLabelTrack(lt)) bGoodResult = false; - break; - } - } - else if (t->GetKind() == Track::Wave && t->GetSelected() ) - { - WaveTrack* leftTrack = (WaveTrack*)t; + }, + [&](WaveTrack *leftTrack, const Track::Fallthrough &fallthrough) { + if (!leftTrack->GetSelected()) + return fallthrough(); //Get start and end times from track mCurT0 = leftTrack->GetStartTime(); @@ -261,7 +256,7 @@ bool EffectSBSMS::Process() if (leftTrack->GetLinked()) { double t; // Assume linked track is wave or null - rightTrack = static_cast(iter.Next()); + rightTrack = static_cast(leftTrack->GetLink()); //Adjust bounds by the right tracks markers t = rightTrack->GetStartTime(); @@ -321,7 +316,8 @@ bool EffectSBSMS::Process() ( samplesToProcess.as_long_long() ), 0, nullptr); - } else { + } + else { rb.bPitch = false; outSlideType = (srProcess==srTrack?SlideIdentity:SlideConstant); outResampleCB = postResampleCB; @@ -414,8 +410,10 @@ bool EffectSBSMS::Process() frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once. } } - if (TrackProgress(nWhichTrack, frac)) - return false; + if (TrackProgress(nWhichTrack, frac)) { + bGoodResult = false; + return; + } } { @@ -425,35 +423,34 @@ bool EffectSBSMS::Process() std::rethrow_exception(pException); } - if (bGoodResult) { - rb.outputLeftTrack->Flush(); - if(rightTrack) - rb.outputRightTrack->Flush(); + rb.outputLeftTrack->Flush(); + if(rightTrack) + rb.outputRightTrack->Flush(); - leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack.get(), - true, false, warper.get()); + leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack.get(), + true, false, warper.get()); - if(rightTrack) - rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack.get(), - true, false, warper.get()); - } + if(rightTrack) + rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack.get(), + true, false, warper.get()); } mCurTrackNum++; + }, + [&](Track *t) { + if (mustSync && t->IsSyncLockSelected()) + { + t->SyncLockAdjust(mCurT1, mCurT0 + (mCurT1 - mCurT0) * mTotalStretch); + } } - else if (mustSync && t->IsSyncLockSelected()) - { - t->SyncLockAdjust(mCurT1, mCurT0 + (mCurT1 - mCurT0) * mTotalStretch); - } - //Iterate to the next track - t = iter.Next(); - } + ); - if (bGoodResult) + if (bGoodResult) { ReplaceProcessedTracks(bGoodResult); - // Update selection - mT0 = mCurT0; - mT1 = mCurT0 + maxDuration; + // Update selection + mT0 = mCurT0; + mT1 = mCurT0 + maxDuration; + } return bGoodResult; } diff --git a/src/effects/SoundTouchEffect.cpp b/src/effects/SoundTouchEffect.cpp index d57f39cf5..3e68abb30 100644 --- a/src/effects/SoundTouchEffect.cpp +++ b/src/effects/SoundTouchEffect.cpp @@ -86,36 +86,28 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) this->CopyInputTracks(Track::All); bool bGoodResult = true; - TrackListIterator iter(mOutputTracks.get()); - Track* t; mCurTrackNum = 0; m_maxNewLength = 0.0; - t = iter.First(); - while (t != NULL) { - if (t->GetKind() == Track::Label && - (t->GetSelected() || (mustSync && t->IsSyncLockSelected())) ) - { - if (!ProcessLabelTrack(static_cast(t), warper)) - { + mOutputTracks->Leaders().VisitWhile( bGoodResult, + [&]( LabelTrack *lt, const Track::Fallthrough &fallthrough ) { + if ( !(lt->GetSelected() || (mustSync && lt->IsSyncLockSelected())) ) + return fallthrough(); + if (!ProcessLabelTrack(lt, warper)) bGoodResult = false; - break; - } - } + }, #ifdef USE_MIDI - else if (t->GetKind() == Track::Note && - (t->GetSelected() || (mustSync && t->IsSyncLockSelected()))) - { - if (!ProcessNoteTrack(static_cast(t), warper)) - { + [&]( NoteTrack *nt, const Track::Fallthrough &fallthrough ) { + if ( !(nt->GetSelected() || (mustSync && nt->IsSyncLockSelected())) ) + return fallthrough(); + if (!ProcessNoteTrack(nt, warper)) bGoodResult = false; - break; - } - } + }, #endif - else if (t->GetKind() == Track::Wave && t->GetSelected()) - { - WaveTrack* leftTrack = (WaveTrack*)t; + [&]( WaveTrack *leftTrack, const Track::Fallthrough &fallthrough ) { + if (!leftTrack->GetSelected()) + return fallthrough(); + //Get start and end times from track mCurT0 = leftTrack->GetStartTime(); mCurT1 = leftTrack->GetEndTime(); @@ -131,7 +123,7 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) if (leftTrack->GetLinked()) { double t; // Assume linked track is wave - WaveTrack* rightTrack = static_cast(iter.Next()); + WaveTrack* rightTrack = static_cast(leftTrack->GetLink()); //Adjust bounds by the right tracks markers t = rightTrack->GetStartTime(); @@ -150,10 +142,7 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) //ProcessStereo() (implemented below) processes a stereo track if (!ProcessStereo(leftTrack, rightTrack, start, end, warper)) - { bGoodResult = false; - break; - } mCurTrackNum++; // Increment for rightTrack, too. } else { //Transform the marker timepoints to samples @@ -165,21 +154,17 @@ bool EffectSoundTouch::ProcessWithTimeWarper(const TimeWarper &warper) //ProcessOne() (implemented below) processes a single track if (!ProcessOne(leftTrack, start, end, warper)) - { bGoodResult = false; - break; - } } } mCurTrackNum++; + }, + [&]( Track *t ) { + if (mustSync && t->IsSyncLockSelected()) { + t->SyncLockAdjust(mT1, warper.Warp(mT1)); + } } - else if (mustSync && t->IsSyncLockSelected()) { - t->SyncLockAdjust(mT1, warper.Warp(mT1)); - } - - //Iterate to the next track - t = iter.Next(); - } + ); if (bGoodResult) ReplaceProcessedTracks(bGoodResult); diff --git a/src/effects/TruncSilence.cpp b/src/effects/TruncSilence.cpp index 5b4d111be..ec3ca642c 100644 --- a/src/effects/TruncSilence.cpp +++ b/src/effects/TruncSilence.cpp @@ -523,31 +523,26 @@ bool EffectTruncSilence::DoRemoval mTruncLongestAllowedSilence); } - double cutLen = std::max(0.0, inLength - outLength); + const double cutLen = std::max(0.0, inLength - outLength); + // Don't waste time cutting nothing. + if( cutLen == 0.0 ) + continue; + totalCutLen += cutLen; - TrackListIterator iterOut(mOutputTracks.get()); - bool lastSeen = false; - for (Track *t = iterOut.StartWith(firstTrack); t && !lastSeen; t = iterOut.Next()) - { - lastSeen = (t == lastTrack); - if (!(t->GetSelected() || t->IsSyncLockSelected())) - continue; + double cutStart = (r->start + r->end - cutLen) / 2; + double cutEnd = cutStart + cutLen; + (mOutputTracks->Any() + .StartingWith(firstTrack).EndingAfter(lastTrack) + + &Track::IsSelectedOrSyncLockSelected + - [&](const Track *pTrack) { return + // Don't waste time past the end of a track + pTrack->GetEndTime() < r->start; + } + ).Visit( + [&](WaveTrack *wt) { - // Don't waste time past the end of a track - if (t->GetEndTime() < r->start) - continue; - - // Don't waste time cutting nothing. - if( cutLen == 0.0 ) - continue; - - double cutStart = (r->start + r->end - cutLen) / 2; - double cutEnd = cutStart + cutLen; - if (t->GetKind() == Track::Wave) - { // In WaveTracks, clear with a cross-fade - WaveTrack *const wt = static_cast(t); auto blendFrames = mBlendFrameCount; // Round start/end times to frame boundaries cutStart = wt->LongSamplesToTime(wt->TimeToLongSamples(cutStart)); @@ -580,11 +575,12 @@ bool EffectTruncSilence::DoRemoval // Write cross-faded data wt->Set((samplePtr)buf1.get(), floatSample, t1, blendFrames); - } - else + }, + [&](Track *t) { // Non-wave tracks: just do a sync-lock adjust t->SyncLockAdjust(cutEnd, cutStart); - } + } + ); ++whichReg; }