diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp index 7d328b3ad..17c6abb53 100644 --- a/src/effects/Amplify.cpp +++ b/src/effects/Amplify.cpp @@ -66,6 +66,8 @@ EffectAmplify::EffectAmplify() mRatio = powf(10.0f, mAmp / 20.0f); mCanClip = false; mPeak = 0.0f; + + SetLinearEffectFlag(true); } EffectAmplify::~EffectAmplify() diff --git a/src/effects/AutoDuck.cpp b/src/effects/AutoDuck.cpp index 4ec4dcb4d..7510d7b1e 100644 --- a/src/effects/AutoDuck.cpp +++ b/src/effects/AutoDuck.cpp @@ -90,6 +90,8 @@ EffectAutoDuck::EffectAutoDuck() mThresholdDb = DEF_ThresholdDb; mMaximumPause = DEF_MaximumPause; + SetLinearEffectFlag(true); + mControlTrack = NULL; mPanel = NULL; diff --git a/src/effects/BassTreble.cpp b/src/effects/BassTreble.cpp index 858508167..1ff376016 100644 --- a/src/effects/BassTreble.cpp +++ b/src/effects/BassTreble.cpp @@ -76,6 +76,8 @@ EffectBassTreble::EffectBassTreble() dB_treble = DEF_Treble; dB_level = DEF_Level; mbNormalize = DEF_Normalize; + + SetLinearEffectFlag(false); } EffectBassTreble::~EffectBassTreble() diff --git a/src/effects/ChangePitch.cpp b/src/effects/ChangePitch.cpp index 29d8eb894..ce3ad7c81 100644 --- a/src/effects/ChangePitch.cpp +++ b/src/effects/ChangePitch.cpp @@ -94,6 +94,8 @@ EffectChangePitch::EffectChangePitch() m_pTextCtrl_PercentChange = NULL; m_pSlider_PercentChange = NULL; + + SetLinearEffectFlag(true); } EffectChangePitch::~EffectChangePitch() diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp index 7209f2003..a7245b876 100644 --- a/src/effects/ChangeSpeed.cpp +++ b/src/effects/ChangeSpeed.cpp @@ -96,6 +96,8 @@ EffectChangeSpeed::EffectChangeSpeed() mToLength = 0.0; mFormat = _("hh:mm:ss + milliseconds"); mbLoopDetect = false; + + SetLinearEffectFlag(true); } EffectChangeSpeed::~EffectChangeSpeed() diff --git a/src/effects/ChangeTempo.cpp b/src/effects/ChangeTempo.cpp index 237ead6a8..31b841e85 100644 --- a/src/effects/ChangeTempo.cpp +++ b/src/effects/ChangeTempo.cpp @@ -70,6 +70,8 @@ EffectChangeTempo::EffectChangeTempo() m_ToLength = 0.0; m_bLoopDetect = false; + + SetLinearEffectFlag(true); } EffectChangeTempo::~EffectChangeTempo() diff --git a/src/effects/ClickRemoval.cpp b/src/effects/ClickRemoval.cpp index b3a04558b..6b164dafa 100644 --- a/src/effects/ClickRemoval.cpp +++ b/src/effects/ClickRemoval.cpp @@ -61,6 +61,8 @@ EffectClickRemoval::EffectClickRemoval() mThresholdLevel = DEF_Threshold; mClickWidth = DEF_Width; + SetLinearEffectFlag(false); + windowSize = 8192; sep = 2049; } diff --git a/src/effects/Compressor.cpp b/src/effects/Compressor.cpp index da7b26bc2..1c637daa8 100644 --- a/src/effects/Compressor.cpp +++ b/src/effects/Compressor.cpp @@ -85,6 +85,8 @@ EffectCompressor::EffectCompressor() mFollow1 = NULL; mFollow2 = NULL; mFollowLen = 0; + + SetLinearEffectFlag(false); } EffectCompressor::~EffectCompressor() diff --git a/src/effects/Echo.cpp b/src/effects/Echo.cpp index 15a88a8ca..b956a4252 100644 --- a/src/effects/Echo.cpp +++ b/src/effects/Echo.cpp @@ -39,6 +39,8 @@ EffectEcho::EffectEcho() { delay = DEF_Delay; decay = DEF_Decay; + + SetLinearEffectFlag(true); } EffectEcho::~EffectEcho() diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index a5fef5cc0..3564ccdfb 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -91,6 +91,7 @@ Effect::Effect() mT0 = 0.0; mT1 = 0.0; mDuration = 0.0; + mIsLinearEffect = false; mNumTracks = 0; mNumGroups = 0; mProgress = NULL; @@ -759,6 +760,7 @@ void Effect::SetDuration(double seconds) } mDuration = seconds; + mSetDuration = mDuration; return; } @@ -1931,6 +1933,11 @@ void Effect::EnableDebug(bool enable) mUIDebug = enable; } +void Effect::SetLinearEffectFlag(bool linearEffectFlag) +{ + mIsLinearEffect = linearEffectFlag; +} + bool Effect::TotalProgress(double frac) { int updateResult = (mProgress ? @@ -2352,6 +2359,11 @@ bool Effect::IsHidden() void Effect::Preview(bool dryOnly) { + if (mIsLinearEffect) + wxLogDebug(wxT("Linear Effect")); + else + wxLogDebug(wxT("Non-linear Effect")); + if (mNumTracks==0) // nothing to preview return; @@ -2363,46 +2375,81 @@ void Effect::Preview(bool dryOnly) double previewLen = 6.0; gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen); - WaveTrack *mixLeft = NULL; - WaveTrack *mixRight = NULL; double rate = mProjectRate; double t0 = mT0; double t1 = t0 + CalcPreviewInputLength(previewLen); - if (t1 > mT1) - t1 = mT1; - // Generators can run without a selection. -// if (!GeneratorPreview() && (t1 <= t0)) -// return; - - bool success = ::MixAndRender(mTracks, mFactory, rate, floatSample, t0, t1, - &mixLeft, &mixRight); - - if (!success) { - return; + if (GetType() == EffectTypeGenerate) { + // If a generator varies over time, it must use the selected duration. + // otherwise set it as a linear effect and process no more than the preview length. + // TODO: When previewing non-linear generate effect, calculate only the first 'preview length'. + double dur = (mIsLinearEffect)? wxMin(mSetDuration, CalcPreviewInputLength(previewLen)) : mSetDuration; + t1 = t0 + dur; + this->SetDuration(dur); } + else if (t1 > mT1) { + t1 = mT1; + } + if (t1 <= t0) + return; + + bool success; + WaveTrack *mixLeft = NULL; + WaveTrack *mixRight = NULL; // Save the original track list TrackList *saveTracks = mTracks; + // Linear Effect preview optimised by pre-mixing to one track. + // Generators need to generate per track. + if (mIsLinearEffect && !(GetType() == EffectTypeGenerate)) { + success = ::MixAndRender(mTracks, mFactory, rate, floatSample, t0, t1, + &mixLeft, &mixRight); + } + // Build new tracklist from rendering tracks mTracks = new TrackList(); - mixLeft->SetSelected(true); - mixLeft->SetDisplay(WaveTrack::NoDisplay); - mTracks->Add(mixLeft); - if (mixRight) { - mixRight->SetSelected(true); - mTracks->Add(mixRight); + + if (mIsLinearEffect && !(GetType() == EffectTypeGenerate)) { + if (!success) { + delete mTracks; + mTracks = saveTracks; + return; + } + + mixLeft->SetSelected(true); + mixLeft->SetDisplay(WaveTrack::NoDisplay); + mTracks->Add(mixLeft); + if (mixRight) { + mixRight->SetSelected(true); + mTracks->Add(mixRight); + } + + // TODO: Don't really think this is necessary, but doesn't hurt + // Reset times + t0 = mixLeft->GetStartTime(); + t1 = mixLeft->GetEndTime(); + } + else { + // Copy all tracks as 'some' effects (AutoDuck) may require non-selected tracks. + TrackListOfKindIterator iter(Track::Wave, saveTracks); + WaveTrack *src = (WaveTrack *) iter.First(); + while (src) + { + WaveTrack *dest; + src->Copy(t0, t1, (Track **) &dest); + dest->SetSelected(src->GetSelected()); + dest->SetDisplay(WaveTrack::NoDisplay); + mTracks->Add(dest); + + src = (WaveTrack *) iter.Next(); + } } // Update track/group counts CountWaveTracks(); - // Reset times - t0 = mixLeft->GetStartTime(); - t1 = mixLeft->GetEndTime(); - double t0save = mT0; double t1save = mT1; mT0 = t0; @@ -2412,36 +2459,26 @@ void Effect::Preview(bool dryOnly) bool bSuccess(true); if (!dryOnly) { - // Effect is already inited; we call Process, End, and then Init - // again, so the state is exactly the way it was before Preview - // was called. mProgress = new ProgressDialog(GetName(), _("Preparing preview"), pdlgHideCancelButton); // Have only "Stop" button. bSuccess = Process(); delete mProgress; mProgress = NULL; - End(); - Init(); } - // Restore original selection - mT0 = t0save; - mT1 = t1save; - if (bSuccess) { WaveTrackArray playbackTracks; WaveTrackArray recordingTracks; - // Probably not the same tracks post-processing, so can't rely on previous values of mixLeft & mixRight. - TrackListOfKindIterator iter(Track::Wave, mTracks); - mixLeft = (WaveTrack*)(iter.First()); - mixRight = (WaveTrack*)(iter.Next()); - playbackTracks.Add(mixLeft); - if (mixRight) - playbackTracks.Add(mixRight); - t1 = wxMin(mixLeft->GetEndTime(), t0 + previewLen); + SelectedTrackListOfKindIterator iter(Track::Wave, mTracks); + WaveTrack *src = (WaveTrack *) iter.First(); + while (src) + { + playbackTracks.Add(src); + src = (WaveTrack *) iter.Next(); + } #ifdef EXPERIMENTAL_MIDI_OUT NoteTrackArray empty; @@ -2452,17 +2489,17 @@ void Effect::Preview(bool dryOnly) #ifdef EXPERIMENTAL_MIDI_OUT empty, #endif - rate, t0, t1); + rate, mT0, mT1); if (token) { int previewing = eProgressSuccess; mProgress = new ProgressDialog(GetName(), - _("Previewing"), pdlgHideCancelButton); + _("Previewing"), pdlgHideCancelButton); while (gAudioIO->IsStreamActive(token) && previewing == eProgressSuccess) { ::wxMilliSleep(100); - previewing = mProgress->Update(gAudioIO->GetStreamTime() - t0, t1 - t0); + previewing = mProgress->Update(gAudioIO->GetStreamTime() - mT0, mT1); } gAudioIO->StopStream(); @@ -2475,10 +2512,14 @@ void Effect::Preview(bool dryOnly) } else { wxMessageBox(_("Error while opening sound device. Please check the playback device settings and the project sample rate."), - _("Error"), wxOK | wxICON_EXCLAMATION, FocusDialog); + _("Error"), wxOK | wxICON_EXCLAMATION, FocusDialog); } } + // Restore original selection + mT0 = t0save; + mT1 = t1save; + if (FocusDialog) { FocusDialog->SetFocus(); } @@ -2490,6 +2531,13 @@ void Effect::Preview(bool dryOnly) delete mTracks; mTracks = saveTracks; + // Effect is already inited; we call Process, End, and then Init + // again, so the state is exactly the way it was before Preview + // was called. + if (!dryOnly) { + End(); + Init(); + } } BEGIN_EVENT_TABLE(EffectDialog, wxDialog) diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 2c08a716c..38a61f0c4 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -316,6 +316,11 @@ protected: void SetTimeWarper(TimeWarper *warper); TimeWarper *GetTimeWarper(); + // Previewing linear effect can be optimised by pre-mixing. However this + // should not be used for non-linear effects such as dynamic processors + // To allow pre-mixing before Preview, set linearEffectFlag to true. + void SetLinearEffectFlag(bool linearEffectFlag); + // Use these two methods to copy the input tracks to mOutputTracks, if // doing the processing on them, and replacing the originals only on success (and not cancel). void CopyInputTracks(int trackType = Track::Wave); @@ -388,7 +393,11 @@ private: bool mIsBatch; + bool mIsLinearEffect; + double mDuration; + // mSetDuration should ONLY be set when SetDuration() is called. + double mSetDuration; bool mUIDebug; diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 55b1ac483..733bed756 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -217,6 +217,8 @@ EffectEqualization::EffectEqualization() mFilterFuncR = new float[windowSize]; mFilterFuncI = new float[windowSize]; + SetLinearEffectFlag(true); + #ifdef EXPERIMENTAL_EQ_SSE_THREADED mEffectEqualization48x=NULL; #endif diff --git a/src/effects/Noise.cpp b/src/effects/Noise.cpp index 2b19a43b3..0b648980e 100644 --- a/src/effects/Noise.cpp +++ b/src/effects/Noise.cpp @@ -57,6 +57,8 @@ EffectNoise::EffectNoise() mType = DEF_Type; mAmp = DEF_Amp; + SetLinearEffectFlag(true); + y = z = buf0 = buf1 = buf2 = buf3 = buf4 = buf5 = buf6 = 0; } diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp index bf1fdb53b..51d486ca1 100644 --- a/src/effects/Normalize.cpp +++ b/src/effects/Normalize.cpp @@ -49,6 +49,8 @@ EffectNormalize::EffectNormalize() mDC = DEF_RemoveDC; mGain = DEF_ApplyGain; mStereoInd = DEF_StereoInd; + + SetLinearEffectFlag(false); } EffectNormalize::~EffectNormalize() diff --git a/src/effects/Paulstretch.cpp b/src/effects/Paulstretch.cpp index 1c8084497..e2e7f77cd 100644 --- a/src/effects/Paulstretch.cpp +++ b/src/effects/Paulstretch.cpp @@ -79,6 +79,8 @@ EffectPaulstretch::EffectPaulstretch() { amount = DEF_Amount; time_resolution = DEF_Time; + + SetLinearEffectFlag(true); } EffectPaulstretch::~EffectPaulstretch() diff --git a/src/effects/Phaser.cpp b/src/effects/Phaser.cpp index 63609d395..c3bc2425b 100644 --- a/src/effects/Phaser.cpp +++ b/src/effects/Phaser.cpp @@ -82,6 +82,8 @@ EffectPhaser::EffectPhaser() mPhase = DEF_Phase; mDepth = DEF_Depth; mFeedback = DEF_Feedback; + + SetLinearEffectFlag(true); } EffectPhaser::~EffectPhaser() diff --git a/src/effects/Repeat.cpp b/src/effects/Repeat.cpp index ac44afcb7..62b2a59ba 100644 --- a/src/effects/Repeat.cpp +++ b/src/effects/Repeat.cpp @@ -47,6 +47,8 @@ END_EVENT_TABLE() EffectRepeat::EffectRepeat() { repeatCount = 10; + + SetLinearEffectFlag(true); } EffectRepeat::~EffectRepeat() diff --git a/src/effects/Reverb.cpp b/src/effects/Reverb.cpp index 5129d9eb6..7ccd3e9e1 100644 --- a/src/effects/Reverb.cpp +++ b/src/effects/Reverb.cpp @@ -119,6 +119,8 @@ EffectReverb::EffectReverb() mParams.mWetOnly = DEF_WetOnly; mProcessingEvent = false; + + SetLinearEffectFlag(true); } EffectReverb::~EffectReverb() diff --git a/src/effects/ScienFilter.cpp b/src/effects/ScienFilter.cpp index e65d965ec..620bce04b 100644 --- a/src/effects/ScienFilter.cpp +++ b/src/effects/ScienFilter.cpp @@ -160,6 +160,8 @@ EffectScienFilter::EffectScienFilter() mRipple = DEF_Passband; mStopbandRipple = DEF_Stopband; + SetLinearEffectFlag(true); + mOrderIndex = mOrder - 1; mdBMin = -30.0; diff --git a/src/effects/Silence.cpp b/src/effects/Silence.cpp index 490941db1..00f2306fe 100644 --- a/src/effects/Silence.cpp +++ b/src/effects/Silence.cpp @@ -21,6 +21,7 @@ EffectSilence::EffectSilence() { + SetLinearEffectFlag(true); } EffectSilence::~EffectSilence() diff --git a/src/effects/TimeScale.cpp b/src/effects/TimeScale.cpp index e370bdb92..c14609752 100644 --- a/src/effects/TimeScale.cpp +++ b/src/effects/TimeScale.cpp @@ -69,6 +69,8 @@ EffectTimeScale::EffectTimeScale() m_PitchHalfStepsEnd = DEF_HalfStepsEnd; m_PitchPercentChangeStart = DEF_PitchPercentStart; m_PitchPercentChangeEnd = DEF_PitchPercentEnd; + + SetLinearEffectFlag(true); } EffectTimeScale::~EffectTimeScale() diff --git a/src/effects/ToneGen.cpp b/src/effects/ToneGen.cpp index fba98a3d2..66a1c7a51 100644 --- a/src/effects/ToneGen.cpp +++ b/src/effects/ToneGen.cpp @@ -105,6 +105,12 @@ EffectToneGen::EffectToneGen(bool isChirp) { mInterpolations.Add(wxGetTranslation(kInterStrings[i])); } + // Chirp varies over time so must use selected duration. + // TODO: When previewing, calculate only the first 'preview length'. + if (isChirp) + SetLinearEffectFlag(false); + else + SetLinearEffectFlag(true); } EffectToneGen::~EffectToneGen() diff --git a/src/effects/TruncSilence.cpp b/src/effects/TruncSilence.cpp index 279c4a122..b29d20c3e 100644 --- a/src/effects/TruncSilence.cpp +++ b/src/effects/TruncSilence.cpp @@ -76,6 +76,8 @@ EffectTruncSilence::EffectTruncSilence() mTruncDbChoiceIndex = DEF_DbIndex; mActionIndex = DEF_ActIndex; + SetLinearEffectFlag(false); + // This used to be changeable via the audacity.cfg/registery. Doubtful that was // ever done. // diff --git a/src/effects/Wahwah.cpp b/src/effects/Wahwah.cpp index 05a76af2c..3d81e487c 100644 --- a/src/effects/Wahwah.cpp +++ b/src/effects/Wahwah.cpp @@ -73,6 +73,8 @@ EffectWahwah::EffectWahwah() mDepth = DEF_Depth; mRes = DEF_Res; mFreqOfs = DEF_FreqOfs; + + SetLinearEffectFlag(true); } EffectWahwah::~EffectWahwah()