Fix for bugs 943, 942, 941, 843 and 775.

Non-linear effects now process tracks before mixing.
This will be slower when multiple tracks are selected
but the preview should now match the applied effect.
SetLinearEffectFlag(true) allows linear effects to
preview more quickly when multiple tracks selected, by
pre-mixing selected tracks.
Simple generators like Tone and Noise may be marked as
'linear' so that they only preview a few seconds.
Generators that vary over time (such as Chirp) must use
the full duration that is set. As this currently
requires calculating the full duration, preview for
'non-linear' generators are not limited to the preview
length.
This commit is contained in:
Steve Daulton 2015-05-15 12:47:51 +01:00
parent c85bf1c531
commit d9f3c432d4
24 changed files with 148 additions and 44 deletions

View File

@ -66,6 +66,8 @@ EffectAmplify::EffectAmplify()
mRatio = powf(10.0f, mAmp / 20.0f);
mCanClip = false;
mPeak = 0.0f;
SetLinearEffectFlag(true);
}
EffectAmplify::~EffectAmplify()

View File

@ -90,6 +90,8 @@ EffectAutoDuck::EffectAutoDuck()
mThresholdDb = DEF_ThresholdDb;
mMaximumPause = DEF_MaximumPause;
SetLinearEffectFlag(true);
mControlTrack = NULL;
mPanel = NULL;

View File

@ -76,6 +76,8 @@ EffectBassTreble::EffectBassTreble()
dB_treble = DEF_Treble;
dB_level = DEF_Level;
mbNormalize = DEF_Normalize;
SetLinearEffectFlag(false);
}
EffectBassTreble::~EffectBassTreble()

View File

@ -94,6 +94,8 @@ EffectChangePitch::EffectChangePitch()
m_pTextCtrl_PercentChange = NULL;
m_pSlider_PercentChange = NULL;
SetLinearEffectFlag(true);
}
EffectChangePitch::~EffectChangePitch()

View File

@ -96,6 +96,8 @@ EffectChangeSpeed::EffectChangeSpeed()
mToLength = 0.0;
mFormat = _("hh:mm:ss + milliseconds");
mbLoopDetect = false;
SetLinearEffectFlag(true);
}
EffectChangeSpeed::~EffectChangeSpeed()

View File

@ -70,6 +70,8 @@ EffectChangeTempo::EffectChangeTempo()
m_ToLength = 0.0;
m_bLoopDetect = false;
SetLinearEffectFlag(true);
}
EffectChangeTempo::~EffectChangeTempo()

View File

@ -61,6 +61,8 @@ EffectClickRemoval::EffectClickRemoval()
mThresholdLevel = DEF_Threshold;
mClickWidth = DEF_Width;
SetLinearEffectFlag(false);
windowSize = 8192;
sep = 2049;
}

View File

@ -85,6 +85,8 @@ EffectCompressor::EffectCompressor()
mFollow1 = NULL;
mFollow2 = NULL;
mFollowLen = 0;
SetLinearEffectFlag(false);
}
EffectCompressor::~EffectCompressor()

View File

@ -39,6 +39,8 @@ EffectEcho::EffectEcho()
{
delay = DEF_Delay;
decay = DEF_Decay;
SetLinearEffectFlag(true);
}
EffectEcho::~EffectEcho()

View File

@ -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)

View File

@ -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;

View File

@ -217,6 +217,8 @@ EffectEqualization::EffectEqualization()
mFilterFuncR = new float[windowSize];
mFilterFuncI = new float[windowSize];
SetLinearEffectFlag(true);
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
mEffectEqualization48x=NULL;
#endif

View File

@ -57,6 +57,8 @@ EffectNoise::EffectNoise()
mType = DEF_Type;
mAmp = DEF_Amp;
SetLinearEffectFlag(true);
y = z = buf0 = buf1 = buf2 = buf3 = buf4 = buf5 = buf6 = 0;
}

View File

@ -49,6 +49,8 @@ EffectNormalize::EffectNormalize()
mDC = DEF_RemoveDC;
mGain = DEF_ApplyGain;
mStereoInd = DEF_StereoInd;
SetLinearEffectFlag(false);
}
EffectNormalize::~EffectNormalize()

View File

@ -79,6 +79,8 @@ EffectPaulstretch::EffectPaulstretch()
{
amount = DEF_Amount;
time_resolution = DEF_Time;
SetLinearEffectFlag(true);
}
EffectPaulstretch::~EffectPaulstretch()

View File

@ -82,6 +82,8 @@ EffectPhaser::EffectPhaser()
mPhase = DEF_Phase;
mDepth = DEF_Depth;
mFeedback = DEF_Feedback;
SetLinearEffectFlag(true);
}
EffectPhaser::~EffectPhaser()

View File

@ -47,6 +47,8 @@ END_EVENT_TABLE()
EffectRepeat::EffectRepeat()
{
repeatCount = 10;
SetLinearEffectFlag(true);
}
EffectRepeat::~EffectRepeat()

View File

@ -119,6 +119,8 @@ EffectReverb::EffectReverb()
mParams.mWetOnly = DEF_WetOnly;
mProcessingEvent = false;
SetLinearEffectFlag(true);
}
EffectReverb::~EffectReverb()

View File

@ -160,6 +160,8 @@ EffectScienFilter::EffectScienFilter()
mRipple = DEF_Passband;
mStopbandRipple = DEF_Stopband;
SetLinearEffectFlag(true);
mOrderIndex = mOrder - 1;
mdBMin = -30.0;

View File

@ -21,6 +21,7 @@
EffectSilence::EffectSilence()
{
SetLinearEffectFlag(true);
}
EffectSilence::~EffectSilence()

View File

@ -69,6 +69,8 @@ EffectTimeScale::EffectTimeScale()
m_PitchHalfStepsEnd = DEF_HalfStepsEnd;
m_PitchPercentChangeStart = DEF_PitchPercentStart;
m_PitchPercentChangeEnd = DEF_PitchPercentEnd;
SetLinearEffectFlag(true);
}
EffectTimeScale::~EffectTimeScale()

View File

@ -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()

View File

@ -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.
//

View File

@ -73,6 +73,8 @@ EffectWahwah::EffectWahwah()
mDepth = DEF_Depth;
mRes = DEF_Res;
mFreqOfs = DEF_FreqOfs;
SetLinearEffectFlag(true);
}
EffectWahwah::~EffectWahwah()