Add SBSMS option to Change Tempo effect

Thanks to Clayton Otey for his help and patience.
This commit is contained in:
Steve Daulton 2016-08-15 01:27:44 +01:00
parent f4f077a1c6
commit 8e0089c552
2 changed files with 106 additions and 43 deletions

View File

@ -19,6 +19,11 @@
#if USE_SOUNDTOUCH #if USE_SOUNDTOUCH
#if USE_SBSMS
#include "sbsms.h"
#include <wx/valgen.h>
#endif
#include <math.h> #include <math.h>
#include <wx/intl.h> #include <wx/intl.h>
@ -44,6 +49,7 @@ enum
// //
// Name Type Key Def Min Max Scale // Name Type Key Def Min Max Scale
Param( Percentage, double, XO("Percentage"), 0.0, -99.0, 3000.0, 1 ); Param( Percentage, double, XO("Percentage"), 0.0, -99.0, 3000.0, 1 );
Param( UseSBSMS, bool, XO("SBSMS"), false, false, true, 1 );
// We warp the slider to go up to 400%, but user can enter higher values. // We warp the slider to go up to 400%, but user can enter higher values.
static const double kSliderMax = 100.0; // warped above zero to actually go up to 400% static const double kSliderMax = 100.0; // warped above zero to actually go up to 400%
@ -71,6 +77,12 @@ EffectChangeTempo::EffectChangeTempo()
m_bLoopDetect = false; m_bLoopDetect = false;
#if USE_SBSMS
mUseSBSMS = DEF_UseSBSMS;
#else
mUseSBSMS = false;
#endif
SetLinearEffectFlag(true); SetLinearEffectFlag(true);
} }
@ -107,6 +119,7 @@ bool EffectChangeTempo::SupportsAutomation()
bool EffectChangeTempo::GetAutomationParameters(EffectAutomationParameters & parms) bool EffectChangeTempo::GetAutomationParameters(EffectAutomationParameters & parms)
{ {
parms.Write(KEY_Percentage, m_PercentChange); parms.Write(KEY_Percentage, m_PercentChange);
parms.Write(KEY_UseSBSMS, mUseSBSMS);
return true; return true;
} }
@ -114,9 +127,15 @@ bool EffectChangeTempo::GetAutomationParameters(EffectAutomationParameters & par
bool EffectChangeTempo::SetAutomationParameters(EffectAutomationParameters & parms) bool EffectChangeTempo::SetAutomationParameters(EffectAutomationParameters & parms)
{ {
ReadAndVerifyDouble(Percentage); ReadAndVerifyDouble(Percentage);
m_PercentChange = Percentage; m_PercentChange = Percentage;
#if USE_SBSMS
ReadAndVerifyBool(UseSBSMS);
mUseSBSMS = UseSBSMS;
#else
mUseSBSMS = false;
#endif
return true; return true;
} }
@ -146,14 +165,31 @@ bool EffectChangeTempo::Init()
bool EffectChangeTempo::Process() bool EffectChangeTempo::Process()
{ {
mSoundTouch = std::make_unique<SoundTouch>(); bool success = false;
mSoundTouch->setTempoChange(m_PercentChange);
double mT1Dashed = mT0 + (mT1 - mT0)/(m_PercentChange/100.0 + 1.0); #if USE_SBSMS
SetTimeWarper(std::make_unique<RegionTimeWarper>(mT0, mT1, if (mUseSBSMS)
std::make_unique<LinearTimeWarper>(mT0, mT0, mT1, mT1Dashed ))); {
bool success = EffectSoundTouch::Process(); double tempoRatio = 1.0 + m_PercentChange / 100.0;
if( success ) SelectedRegion region(mT0, mT1);
EffectSBSMS proxy;
proxy.setParameters(tempoRatio, 1.0);
success = proxy.DoEffect(mUIParent, mProjectRate, mTracks, mFactory, &region, false);
}
else
#endif
{
mSoundTouch = std::make_unique<SoundTouch>();
mSoundTouch->setTempoChange(m_PercentChange);
double mT1Dashed = mT0 + (mT1 - mT0)/(m_PercentChange/100.0 + 1.0);
SetTimeWarper(std::make_unique<RegionTimeWarper>(mT0, mT1,
std::make_unique<LinearTimeWarper>(mT0, mT0, mT1, mT1Dashed )));
success = EffectSoundTouch::Process();
}
if(success)
mT1 = mT0 + (mT1 - mT0)/(m_PercentChange/100 + 1.); mT1 = mT0 + (mT1 - mT0)/(m_PercentChange/100 + 1.);
return success; return success;
} }
@ -186,50 +222,67 @@ void EffectChangeTempo::PopulateOrExchange(ShuttleGui & S)
} }
S.EndHorizontalLay(); S.EndHorizontalLay();
// S.StartStatic(_("Beats per minute"));
S.StartMultiColumn(5, wxCENTER);
{ {
// S.StartHorizontalLay(wxALIGN_CENTER);
S.AddUnits(_("Beats per minute:")); {
FloatingPointValidator<double> vldFromBPM(3, &m_FromBPM, NUM_VAL_THREE_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK);
m_pTextCtrl_FromBPM = S.Id(ID_FromBPM)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromBPM->SetName(_("From beats per minute"));
m_pTextCtrl_FromBPM->SetValidator(vldFromBPM);
FloatingPointValidator<double> vldFromBPM(3, &m_FromBPM, NUM_VAL_THREE_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK); FloatingPointValidator<double> vldToBPM(3, &m_ToBPM, NUM_VAL_THREE_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK);
m_pTextCtrl_FromBPM = S.Id(ID_FromBPM) m_pTextCtrl_ToBPM = S.Id(ID_ToBPM)
.AddTextBox(_("from"), wxT(""), 12); .AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_FromBPM->SetName(_("From beats per minute")); m_pTextCtrl_ToBPM->SetName(_("To beats per minute"));
m_pTextCtrl_FromBPM->SetValidator(vldFromBPM); m_pTextCtrl_ToBPM->SetValidator(vldToBPM);
}
S.EndHorizontalLay();
}
S.EndStatic();
FloatingPointValidator<double> vldToBPM(3, &m_ToBPM, NUM_VAL_THREE_TRAILING_ZEROES | NUM_VAL_ZERO_AS_BLANK); //
m_pTextCtrl_ToBPM = S.Id(ID_ToBPM) S.StartStatic(_("Length (seconds)"));
.AddTextBox(_("to"), wxT(""), 12); {
m_pTextCtrl_ToBPM->SetName(_("To beats per minute")); S.StartHorizontalLay(wxALIGN_CENTER);
m_pTextCtrl_ToBPM->SetValidator(vldToBPM); {
int precission = 2;
FloatingPointValidator<double> vldFromLength(precission, &m_FromLength, NUM_VAL_TWO_TRAILING_ZEROES);
m_pTextCtrl_FromLength = S.Id(ID_FromLength)
.AddTextBox(_("from"), wxT(""), 12);
m_pTextCtrl_FromLength->SetName(_("From length in seconds"));
m_pTextCtrl_FromLength->SetValidator(vldFromLength);
m_pTextCtrl_FromLength->Enable(false); // Disable because the value comes from the user selection.
// FloatingPointValidator<double> vldToLength(2, &m_ToLength, NUM_VAL_TWO_TRAILING_ZEROES);
S.AddUnits(_("Length (seconds):"));
int precission = 2; // min and max need same precision as what we're validating (bug 963)
FloatingPointValidator<double> vldFromLength(precission, &m_FromLength, NUM_VAL_TWO_TRAILING_ZEROES); double minLength = (m_FromLength * 100.0) / (100.0 + MAX_Percentage);
m_pTextCtrl_FromLength = S.Id(ID_FromLength) double maxLength = (m_FromLength * 100.0) / (100.0 + MIN_Percentage);
.AddTextBox(_("from"), wxT(""), 12); minLength = Internat::CompatibleToDouble(Internat::ToString(minLength, precission));
m_pTextCtrl_FromLength->SetName(_("From length in seconds")); maxLength = Internat::CompatibleToDouble(Internat::ToString(maxLength, precission));
m_pTextCtrl_FromLength->SetValidator(vldFromLength);
m_pTextCtrl_FromLength->Enable(false); // Disable because the value comes from the user selection.
FloatingPointValidator<double> vldToLength(2, &m_ToLength, NUM_VAL_TWO_TRAILING_ZEROES); vldToLength.SetRange(minLength, maxLength);
m_pTextCtrl_ToLength = S.Id(ID_ToLength)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToLength->SetName(_("To length in seconds"));
m_pTextCtrl_ToLength->SetValidator(vldToLength);
}
S.EndHorizontalLay();
}
S.EndStatic();
// min and max need same precision as what we're validating (bug 963) #if USE_SBSMS
double minLength = (m_FromLength * 100.0) / (100.0 + MAX_Percentage); S.StartMultiColumn(2);
double maxLength = (m_FromLength * 100.0) / (100.0 + MIN_Percentage); {
minLength = Internat::CompatibleToDouble(Internat::ToString(minLength, precission)); mUseSBSMSCheckBox = S.AddCheckBox(_("Use high quality stretching (slow)"),
maxLength = Internat::CompatibleToDouble(Internat::ToString(maxLength, precission)); mUseSBSMS? wxT("true") : wxT("false"));
mUseSBSMSCheckBox->SetValidator(wxGenericValidator(&mUseSBSMS));
vldToLength.SetRange(minLength, maxLength);
m_pTextCtrl_ToLength = S.Id(ID_ToLength)
.AddTextBox(_("to"), wxT(""), 12);
m_pTextCtrl_ToLength->SetName(_("To length in seconds"));
m_pTextCtrl_ToLength->SetValidator(vldToLength);
} }
S.EndMultiColumn(); S.EndMultiColumn();
#endif
} }
S.EndVerticalLay(); S.EndVerticalLay();

View File

@ -16,6 +16,11 @@
#ifndef __AUDACITY_EFFECT_CHANGETEMPO__ #ifndef __AUDACITY_EFFECT_CHANGETEMPO__
#define __AUDACITY_EFFECT_CHANGETEMPO__ #define __AUDACITY_EFFECT_CHANGETEMPO__
#if USE_SBSMS
#include "SBSMSEffect.h"
#include <wx/checkbox.h>
#endif
#include <wx/event.h> #include <wx/event.h>
#include <wx/slider.h> #include <wx/slider.h>
#include <wx/string.h> #include <wx/string.h>
@ -75,6 +80,7 @@ private:
void Update_Text_ToLength(); // Use m_FromLength & m_PercentChange to set NEW m_ToLength & control. void Update_Text_ToLength(); // Use m_FromLength & m_PercentChange to set NEW m_ToLength & control.
private: private:
bool mUseSBSMS;
double m_PercentChange; // percent change to apply to tempo double m_PercentChange; // percent change to apply to tempo
// -100% is meaningless, but sky's the upper limit // -100% is meaningless, but sky's the upper limit
double m_FromBPM; // user-set beats-per-minute. Zero means not yet set. double m_FromBPM; // user-set beats-per-minute. Zero means not yet set.
@ -92,6 +98,10 @@ private:
wxTextCtrl * m_pTextCtrl_FromLength; wxTextCtrl * m_pTextCtrl_FromLength;
wxTextCtrl * m_pTextCtrl_ToLength; wxTextCtrl * m_pTextCtrl_ToLength;
#if USE_SBSMS
wxCheckBox * mUseSBSMSCheckBox;
#endif
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
}; };