diff --git a/lib-src/sbsms/include/sbsms.h b/lib-src/sbsms/include/sbsms.h index 167c9e4be..5cd94a805 100644 --- a/lib-src/sbsms/include/sbsms.h +++ b/lib-src/sbsms/include/sbsms.h @@ -51,6 +51,7 @@ class SBSMSInterface { virtual ~SBSMSInterface() {} virtual long samples(audio *buf, long n) { return 0; } virtual float getStretch(float t)=0; + virtual float getMeanStretch(float t0, float t1)=0; virtual float getPitch(float t)=0; virtual long getPresamples()=0; virtual SampleCountType getSamplesToInput()=0; @@ -127,8 +128,10 @@ class Slide { ~Slide(); float getTotalStretch(); float getStretchedTime(float t); + float getInverseStretchedTime(float t); float getRate(float t); float getStretch(float t); + float getMeanStretch(float t0, float t1); float getRate(); float getStretch(); void step(); @@ -148,6 +151,7 @@ public: SBSMSQuality *quality); virtual ~SBSMSInterfaceSliding(); virtual float getStretch(float t); + virtual float getMeanStretch(float t0, float t1); virtual float getPitch(float t); virtual long getPresamples(); virtual SampleCountType getSamplesToInput(); diff --git a/lib-src/sbsms/src/sbsms.cpp b/lib-src/sbsms/src/sbsms.cpp index 6a8cf0632..111747b4a 100644 --- a/lib-src/sbsms/src/sbsms.cpp +++ b/lib-src/sbsms/src/sbsms.cpp @@ -663,7 +663,8 @@ long SBSMSImp :: write(SBSMSInterface *iface) long nWrite = 0; float t = getInputTime(iface); - float stretch = iface->getStretch(t); + float t1 = (float)(nSamplesInputed + quality->getFrameSize()) / (float)iface->getSamplesToInput(); + float stretch = iface->getMeanStretch(t,t1); float pitch = iface->getPitch(t); long nPresamples = iface->getPresamples(); diff --git a/lib-src/sbsms/src/slide.cpp b/lib-src/sbsms/src/slide.cpp index ce11b18f9..7f5059a06 100644 --- a/lib-src/sbsms/src/slide.cpp +++ b/lib-src/sbsms/src/slide.cpp @@ -11,8 +11,10 @@ public: virtual ~SlideImp() {} virtual float getTotalStretch()=0; virtual float getStretchedTime(float t)=0; + virtual float getInverseStretchedTime(float t)=0; virtual float getRate(float t)=0; virtual float getStretch(float t)=0; + virtual float getMeanStretch(float t0, float t1)=0; virtual float getRate()=0; virtual float getStretch()=0; virtual void step()=0; @@ -28,12 +30,18 @@ public: float getStretchedTime(float t) { return t; } + float getInverseStretchedTime(float t) { + return t; + } float getRate(float t) { return 1.0f; } float getStretch(float t) { return 1.0f; } + float getMeanStretch(float t0, float t1) { + return 1.0f; + } float getRate() { return 1.0f; } @@ -55,12 +63,18 @@ public: float getStretchedTime(float t) { return t / rate; } + float getInverseStretchedTime(float t) { + return rate * t; + } float getRate(float t) { return rate; } float getStretch(float t) { return 1.0f / rate; } + float getMeanStretch(float t0, float t1) { + return 1.0f / rate; + } float getRate() { return rate; } @@ -90,12 +104,18 @@ public: float ratet = getRate(t); return log(ratet / rate0) / (rate1 - rate0); } + float getInverseStretchedTime(float t) { + return (exp((rate1-rate0)*t)-1.0f)*rate0/(rate1-rate0); + } float getRate(float t) { return rate0 + (rate1 - rate0) * t; } float getStretch(float t) { return 1.0f / getRate(t); } + float getMeanStretch(float t0, float t1) { + return log(getRate(t1)/getRate(t0))/((rate1-rate0)*(t1-t0)); + } float getRate() { return (float)val; } @@ -126,12 +146,22 @@ public: float getStretchedTime(float t) { return (sqrt(rate0 * rate0 + (rate1 * rate1 - rate0 * rate0) * t) - rate0) * 2.0f / (rate1 * rate1 - rate0 * rate0); } + float getInverseStretchedTime(float t) { + float r12 = rate1 * rate1 - rate0 * rate0; + float s = 0.5f * r12 * t + rate0; + return (s * s - rate0 * rate0) / r12; + } float getRate(float t) { - return rate0 + (sqrt(rate0 * rate0 + (rate1 * rate1 - rate0 * rate0) * t) - rate0); + return sqrt(rate0 * rate0 + (rate1 * rate1 - rate0 * rate0) * t); } float getStretch(float t) { return 1.0f / getRate(t); } + float getMeanStretch(float t0, float t1) { + float r02 = rate0 * rate0; + float r102 = rate1 * rate1 - r02; + return 2.0f * (sqrt(r02 + r102*t1) - sqrt(r02 + r102 * t0)) / (r102 * (t1 - t0)); + } float getRate() { return getRate((float)val); } @@ -162,12 +192,19 @@ public: float getStretchedTime(float t) { return t / rate0 * (1.0f + 0.5f * t * (rate0 / rate1 - 1.0f)); } + float getInverseStretchedTime(float t) { + float s = 1.0f / rate1 - 1.0f / rate0; + return (-1.0f / rate0 + sqrt(1/(rate0*rate0)-2.0f*t*s)) / s; + } float getRate(float t) { return 1.0f / getStretch(t); } float getStretch(float t) { return (1.0f / rate0 + (1.0f / rate1 - 1.0f / rate0) * t); } + float getMeanStretch(float t0, float t1) { + return ((t1 + t0) * (rate0 - rate1) - 2.0f * rate1) / (2.0f * rate0 * rate1); + } float getRate() { return (float)(1.0 / val); } @@ -200,12 +237,18 @@ public: float getStretchedTime(float t) { return c1 * (pow(c0, t) - 1.0f); } + float getInverseStretchedTime(float t) { + return log(t/c1 + 1.0f) * c1 * rate0; + } float getRate(float t) { return rate0 * pow(c0, -t); } float getStretch(float t) { return pow(c0, t) / rate0; } + float getMeanStretch(float t0, float t1) { + return (pow(c0,t1) - pow(c0,t0)) / (c1 * (t1 - t0)); + } float getRate() { return getRate((float)val); } @@ -226,16 +269,21 @@ public: GeometricInputSlide(float rate0, float rate1, const SampleCountType &n) { this->rate0 = rate0; this->rate1 = rate1; + this->c0 = rate0 / rate1; + this->log01 = log(c0); if(n) { val = rate0; inc = pow((double)rate1 / rate0, 1.0 / (double)n); } } float getTotalStretch() { - return (rate1 - rate0) / (log(rate1 / rate0) * (rate0 * rate1)); + return (rate0 - rate1) / (log01 * (rate0 * rate1)); } float getStretchedTime(float t) { - return (float)(pow(rate0 / rate1, t) - 1.0) / (rate0 * log(rate0 / rate1)); + return (float)(pow(rate0 / rate1, t) - 1.0) / (rate0 * log01); + } + float getInverseStretchedTime(float t) { + return log(t * rate0 * log01 + 1.0f) / log01; } float getRate(float t) { return rate0 * pow(rate1 / rate0, t); @@ -243,6 +291,9 @@ public: float getStretch(float t) { return 1.0f / getRate(t); } + float getMeanStretch(float t0, float t1) { + return (pow(c0,t1) - pow(c0,t0)) / (rate0 * log01 * (t1 - t0)); + } float getRate() { return (float)val; } @@ -253,7 +304,7 @@ public: val *= inc; } protected: - float rate0, rate1; + float rate0, rate1, c0, log01; double val, inc; }; @@ -276,6 +327,9 @@ public: float getStretchedTime(float t) { return log(r10 / rate0 * t + 1.0f) / r10; } + float getInverseStretchedTime(float t) { + return rate0 / r10 * (exp(t * r10) - 1.0f); + } float getRate(float t) { float t1 = getStretchedTime(t) / totalStretch; return rate0 * pow(rate1 / rate0, t1); @@ -283,6 +337,9 @@ public: float getStretch(float t) { return 1.0f / getRate(t); } + float getMeanStretch(float t0, float t1) { + return log((rate0 + r10 * t1)/(rate0 + r10 * t0)) /(r10 * (t1 - t0)); + } float getRate() { return getRate((float)val); } @@ -347,6 +404,16 @@ float Slide :: getStretchedTime(float t) if(t > 1.0f) t = 1.0f; return imp->getStretchedTime(t); } + +float Slide :: getMeanStretch(float t0, float t1) { + if(t0 < 0.0f) t0 = 0.0f; + return imp->getMeanStretch(t0,t1); +} + +float Slide :: getInverseStretchedTime(float t) +{ + return imp->getInverseStretchedTime(t); +} float Slide :: getRate() { @@ -374,6 +441,7 @@ public: SBSMSQuality *quality); ~SBSMSInterfaceSlidingImp() {} inline float getStretch(float t); + inline float getMeanStretch(float t0, float t1); inline float getPitch(float t); inline long getPresamples(); SampleCountType getSamplesToInput(); @@ -388,8 +456,7 @@ protected: SampleCountType samplesToInput; SampleCountType samplesToOutput; }; - - + SBSMSInterfaceSlidingImp :: SBSMSInterfaceSlidingImp(Slide *stretchSlide, Slide *pitchSlide, bool bPitchReferenceInput, @@ -414,7 +481,8 @@ SBSMSInterfaceSlidingImp :: SBSMSInterfaceSlidingImp(Slide *stretchSlide, int inFrameSize = quality->getFrameSize(); while(samplesIn < samplesToInput) { float t = (float)samplesIn / (float)samplesToInput; - stretch = stretchSlide->getStretch(t); + float t1 =(float)(samplesIn + inFrameSize) / (float)samplesToInput; + stretch = stretchSlide->getMeanStretch(t,t1); outFrameSizefloat += stretch * inFrameSize; int outFrameSize = (int) outFrameSizefloat; outFrameSizefloat -= (float) outFrameSize; @@ -432,6 +500,12 @@ float SBSMSInterfaceSlidingImp :: getStretch(float t) return stretchScale * stretchSlide->getStretch(t); } +float SBSMSInterfaceSliding :: getMeanStretch(float t0, float t1) { return imp->getMeanStretch(t0, t1); } +float SBSMSInterfaceSlidingImp :: getMeanStretch(float t0, float t1) +{ + return stretchSlide->getMeanStretch(t0, t1); +} + float SBSMSInterfaceSliding :: getPitch(float t) { return imp->getPitch(t); } float SBSMSInterfaceSlidingImp :: getPitch(float t) { diff --git a/m4/audacity_checklib_libsbsms.m4 b/m4/audacity_checklib_libsbsms.m4 index f4210a6d1..c2f80dddd 100644 --- a/m4/audacity_checklib_libsbsms.m4 +++ b/m4/audacity_checklib_libsbsms.m4 @@ -12,7 +12,7 @@ AC_DEFUN([AUDACITY_CHECKLIB_LIBSBSMS], [ dnl see if sbsms is installed on the system - PKG_CHECK_MODULES(SBSMS, sbsms >= 1.6.0, + PKG_CHECK_MODULES(SBSMS, sbsms >= 2.2.0, LIBSBSMS_SYSTEM_AVAILABLE="yes", LIBSBSMS_SYSTEM_AVAILABLE="no") diff --git a/src/effects/SBSMSEffect.cpp b/src/effects/SBSMSEffect.cpp index 3cbed773b..6eea600ae 100644 --- a/src/effects/SBSMSEffect.cpp +++ b/src/effects/SBSMSEffect.cpp @@ -200,6 +200,18 @@ bool EffectSBSMS::ProcessLabelTrack(Track *t) return true; } +double EffectSBSMS::getInvertedStretchedTime(double rateStart, double rateEnd, SlideType slideType, double outputTime) +{ + Slide slide(slideType,rateStart,rateEnd,0); + return slide.getInverseStretchedTime(outputTime); +} + +double EffectSBSMS::getRate(double rateStart, double rateEnd, SlideType slideType, double t) +{ + Slide slide(slideType,rateStart,rateEnd,0); + return slide.getRate(t); +} + bool EffectSBSMS::Process() { bool bGoodResult = true; @@ -307,6 +319,8 @@ bool EffectSBSMS::Process() bPitchReferenceInput, samplesToProcess,0, NULL); + + } else { rb.bPitch = false; outSlideType = (srProcess==srTrack?SlideIdentity:SlideConstant); @@ -330,7 +344,7 @@ bool EffectSBSMS::Process() samplesToProcess,processPresamples, rb.quality); } - + Resampler resampler(outResampleCB,&rb,outSlideType); audio outBuf[SBSMSOutBlockSize]; diff --git a/src/effects/SBSMSEffect.h b/src/effects/SBSMSEffect.h index 205ece823..14ba2e17c 100644 --- a/src/effects/SBSMSEffect.h +++ b/src/effects/SBSMSEffect.h @@ -28,7 +28,8 @@ public: void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, SlideType rateSlideType, SlideType pitchSlideType, bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput); - + static double getInvertedStretchedTime(double rateStart, double rateEnd, SlideType slideType, double outputTime); + static double getRate(double rateStart, double rateEnd, SlideType slideType, double t); private: bool ProcessLabelTrack(Track *track); double rateStart, rateEnd, pitchStart, pitchEnd; diff --git a/src/effects/TimeScale.cpp b/src/effects/TimeScale.cpp index 103474cb8..225493174 100644 --- a/src/effects/TimeScale.cpp +++ b/src/effects/TimeScale.cpp @@ -72,6 +72,11 @@ EffectTimeScale::EffectTimeScale() m_PitchPercentChangeStart = DEF_PitchPercentStart; m_PitchPercentChangeEnd = DEF_PitchPercentEnd; + slideTypeRate = SlideLinearOutputRate; + slideTypePitch = SlideLinearOutputRate; + bPreview = false; + previewSelectedDuration = 0.0; + SetLinearEffectFlag(true); } @@ -143,13 +148,42 @@ bool EffectTimeScale::Init() return true; } +double EffectTimeScale::CalcPreviewInputLength(double previewLength) +{ + double inputLength = Effect::GetDuration(); + if(inputLength == 0.0) { + return 0.0; + } else { + double rateStart = PercentChangeToRatio(m_RatePercentChangeStart); + double rateEnd = PercentChangeToRatio(m_RatePercentChangeEnd); + double tOut = previewLength/inputLength; + double t = EffectSBSMS::getInvertedStretchedTime(rateStart,rateEnd,slideTypeRate,tOut); + return t * inputLength; + } +} + +void EffectTimeScale::Preview(bool dryOnly) +{ + previewSelectedDuration = Effect::GetDuration(); + bPreview = true; + Effect::Preview(dryOnly); + bPreview = false; +} + bool EffectTimeScale::Process() { double pitchStart = PercentChangeToRatio(m_PitchPercentChangeStart); double pitchEnd = PercentChangeToRatio(m_PitchPercentChangeEnd); double rateStart = PercentChangeToRatio(m_RatePercentChangeStart); double rateEnd = PercentChangeToRatio(m_RatePercentChangeEnd); - EffectSBSMS::setParameters(rateStart,rateEnd,pitchStart,pitchEnd,SlideLinearOutputRate,SlideLinearOutputRate,false,false,false); + + if(bPreview) { + double t = (mT1-mT0) / previewSelectedDuration; + rateEnd = EffectSBSMS::getRate(rateStart,rateEnd,slideTypeRate,t); + pitchEnd = EffectSBSMS::getRate(pitchStart,pitchEnd,slideTypePitch,t); + } + + EffectSBSMS::setParameters(rateStart,rateEnd,pitchStart,pitchEnd,slideTypeRate,slideTypePitch,false,false,false); return EffectSBSMS::Process(); } diff --git a/src/effects/TimeScale.h b/src/effects/TimeScale.h index f684a50d8..fe7852a40 100644 --- a/src/effects/TimeScale.h +++ b/src/effects/TimeScale.h @@ -50,10 +50,12 @@ public: // Effect implementation virtual bool Init(); + virtual void Preview(bool dryOnly); virtual bool Process(); virtual void PopulateOrExchange(ShuttleGui & S); virtual bool TransferDataToWindow(); virtual bool TransferDataFromWindow(); + virtual double CalcPreviewInputLength(double previewLength); private: // EffectTimeScale implementation @@ -82,6 +84,10 @@ private: void Update_Slider_RatePercentChangeEnd(); private: + bool bPreview; + double previewSelectedDuration; + SlideType slideTypeRate; + SlideType slideTypePitch; double m_RatePercentChangeStart; double m_RatePercentChangeEnd; double m_PitchHalfStepsStart;