Fixes for bugs 2534 and 1215

This commit is contained in:
Leland Lucius 2020-09-17 23:22:00 -05:00
parent 9e41e8fa7d
commit 5bca69ca31
4 changed files with 75 additions and 21 deletions

View File

@ -247,7 +247,7 @@ bool EffectChangePitch::Process()
// eliminate the next line:
mSemitones = m_dSemitonesChange;
#endif
return EffectSoundTouch::ProcessWithTimeWarper(initer, warper);
return EffectSoundTouch::ProcessWithTimeWarper(initer, warper, true);
}
}

View File

@ -217,7 +217,7 @@ bool EffectChangeTempo::Process()
double mT1Dashed = mT0 + (mT1 - mT0)/(m_PercentChange/100.0 + 1.0);
RegionTimeWarper warper{ mT0, mT1,
std::make_unique<LinearTimeWarper>(mT0, mT0, mT1, mT1Dashed ) };
success = EffectSoundTouch::ProcessWithTimeWarper(initer, warper);
success = EffectSoundTouch::ProcessWithTimeWarper(initer, warper, false);
}
if(success)

View File

@ -20,6 +20,7 @@ effect that uses SoundTouch to do its processing (ChangeTempo
#include <math.h>
#include "../LabelTrack.h"
#include "../WaveClip.h"
#include "../WaveTrack.h"
#include "../NoteTrack.h"
#include "TimeWarper.h"
@ -67,7 +68,9 @@ bool EffectSoundTouch::ProcessNoteTrack(NoteTrack *nt, const TimeWarper &warper)
}
#endif
bool EffectSoundTouch::ProcessWithTimeWarper(InitFunction initer, const TimeWarper &warper)
bool EffectSoundTouch::ProcessWithTimeWarper(InitFunction initer,
const TimeWarper &warper,
bool preserveLength)
{
// Assumes that mSoundTouch has already been initialized
// by the subclass for subclass-specific parameters. The
@ -85,6 +88,7 @@ bool EffectSoundTouch::ProcessWithTimeWarper(InitFunction initer, const TimeWarp
this->CopyInputTracks(true);
bool bGoodResult = true;
mPreserveLength = preserveLength;
mCurTrackNum = 0;
m_maxNewLength = 0.0;
@ -107,14 +111,9 @@ bool EffectSoundTouch::ProcessWithTimeWarper(InitFunction initer, const TimeWarp
if (!leftTrack->GetSelected())
return fallthrough();
//Get start and end times from track
mCurT0 = leftTrack->GetStartTime();
mCurT1 = leftTrack->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);
//Get start and end times from selection
mCurT0 = mT0;
mCurT1 = mT1;
// Process only if the right marker is to the right of the left marker
if (mCurT1 > mCurT0) {
@ -250,9 +249,8 @@ bool EffectSoundTouch::ProcessOne(WaveTrack *track,
outputTrack->Flush();
}
// Take the output track and insert it in place of the original
// sample data
track->ClearAndPaste(mCurT0, mCurT1, outputTrack.get(), false, true, &warper);
// Transfer output samples to the original
Finalize(track, outputTrack.get(), warper);
double newLength = outputTrack->GetEndTime();
m_maxNewLength = wxMax(m_maxNewLength, newLength);
@ -345,12 +343,10 @@ bool EffectSoundTouch::ProcessStereo(
outputRightTrack->Flush();
}
// Take the output tracks and insert in place of the original
// sample data.
leftTrack->ClearAndPaste(
mCurT0, mCurT1, outputLeftTrack.get(), false, true, &warper);
rightTrack->ClearAndPaste(
mCurT0, mCurT1, outputRightTrack.get(), false, true, &warper);
// Transfer output samples to the original
Finalize(leftTrack, outputLeftTrack.get(), warper);
Finalize(rightTrack, outputRightTrack.get(), warper);
// Track the longest result length
double newLength = outputLeftTrack->GetEndTime();
@ -384,4 +380,57 @@ bool EffectSoundTouch::ProcessStereoResults(const size_t outputCount,
return true;
}
void EffectSoundTouch::Finalize(WaveTrack* orig, WaveTrack* out, const TimeWarper &warper)
{
if (mPreserveLength) {
auto newLen = out->GetNumSamples();
auto oldLen = out->TimeToLongSamples(mCurT1) - out->TimeToLongSamples(mCurT0);
// Pad output track to original length since SoundTouch may remove samples
if (newLen < oldLen) {
out->InsertSilence(out->LongSamplesToTime(newLen - 1),
out->LongSamplesToTime(oldLen - newLen));
}
// Trim output track to original length since SoundTouch may add extra samples
else if (newLen > oldLen) {
out->Trim(0, out->LongSamplesToTime(oldLen));
}
}
// Silenced samples will be inserted in gaps between clips, so capture where these
// gaps are for later deletion
std::vector<std::pair<double, double>> gaps;
double last = 0.0;
auto clips = orig->SortedClipArray();
auto front = clips.front();
auto back = clips.back();
for (auto &clip : clips) {
auto st = clip->GetStartTime();
auto et = clip->GetEndTime();
if (st >= mCurT0 || et < mCurT1) {
if (mCurT0 < st && clip == front) {
gaps.push_back(std::make_pair(mCurT0, st));
}
if (mCurT1 > et && clip == back) {
gaps.push_back(std::make_pair(et, mCurT1));
}
if (last >= mCurT0) {
gaps.push_back(std::make_pair(last, st));
}
}
last = et;
}
// Take the output track and insert it in place of the original sample data
orig->ClearAndPaste(mCurT0, mCurT1, out, true, true, &warper);
// Finally, recreate the gaps
for (auto gap : gaps) {
auto st = orig->LongSamplesToTime(orig->TimeToLongSamples(gap.first));
auto et = orig->LongSamplesToTime(orig->TimeToLongSamples(gap.second));
orig->SplitDelete(warper.Warp(st), warper.Warp(et));
}
}
#endif // USE_SOUNDTOUCH

View File

@ -49,7 +49,9 @@ protected:
// Effect implementation
using InitFunction = std::function< void(soundtouch::SoundTouch *soundtouch) >;
bool ProcessWithTimeWarper(InitFunction initer, const TimeWarper &warper);
bool ProcessWithTimeWarper(InitFunction initer,
const TimeWarper &warper,
bool preserveLength);
std::unique_ptr<soundtouch::SoundTouch> mSoundTouch;
double mCurT0;
@ -69,6 +71,9 @@ private:
bool ProcessStereoResults(const size_t outputCount,
WaveTrack* outputLeftTrack,
WaveTrack* outputRightTrack);
void Finalize(WaveTrack* orig, WaveTrack* out, const TimeWarper &warper);
bool mPreserveLength;
int mCurTrackNum;