1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-23 23:03:55 +02:00

Migrating the remaining effects

This brings the builtin, LV2, and VAMP effects inline with the
Audio Units, LADSPA, and VST effects.  All effects now share
a common UI.

This gives all effects (though not implemented for all):

User and factory preset capability
Preset import/export capability
Shared or private configuration options

Builtin effects can now be migrated to RTP, depending on algorithm.
LV2 effects now support graphical interfaces if the plugin supplies one.
Nyquist prompt enhanced to provide some features of the Nyquist Workbench.

It may not look like it, but this was a LOT of work, so trust me, there
WILL be problems and everything effect related should be suspect.  Keep
a sharp eye (or two) open.
This commit is contained in:
Leland Lucius
2015-04-16 22:53:42 -05:00
parent 40e6bcc56a
commit 8fbfa460c4
140 changed files with 17288 additions and 20367 deletions

View File

@@ -11,64 +11,139 @@
\class EffectChangeSpeed
\brief An Effect that affects both pitch & speed.
*//****************************************************************//**
\class ChangeSpeedDialog
\brief Dialog used with EffectChangeSpeed
*//*******************************************************************/
#include "../Audacity.h"
#include <math.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/valtext.h>
#include <wx/intl.h>
#include "../Audacity.h"
#include "../LabelTrack.h"
#include "../Envelope.h"
#include "../LabelTrack.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../Resample.h"
#include "../ShuttleGui.h"
#include "../widgets/valnum.h"
#include "ChangeSpeed.h"
#include "TimeWarper.h"
enum
{
ID_PercentChange = 10000,
ID_Multiplier,
ID_FromVinyl,
ID_ToVinyl,
ID_ToLength
};
// the standard vinyl rpm choices
// If the percent change is not one of these ratios, the choice control gets "n/a".
enum {
enum kVinyl
{
kVinyl_33AndAThird = 0,
kVinyl_45,
kVinyl_78,
kVinyl_NA
kVinyl_NA,
kNumVinyl
};
static const wxChar *kVinylStrings[kNumVinyl] =
{
wxT("33 1/3"),
wxT("45"),
wxT("78"),
/* i18n-hint: n/a is an English abbreviation meaning "not applicable". */
wxTRANSLATE("n/a"),
};
// Soundtouch is not reasonable below -99% or above 3000%.
// Define keys, defaults, minimums, and maximums for the effect parameters
//
// Name Type Key Def Min Max Scale
Param( Percentage, double, wxTRANSLATE("Percentage"), 0.0, -99.0, 4900.0, 1 );
// 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 kSliderWarp = 1.30105; // warp power takes max from 100 to 400.
//
// EffectChangeSpeed
//
BEGIN_EVENT_TABLE(EffectChangeSpeed, wxEvtHandler)
EVT_TEXT(ID_PercentChange, EffectChangeSpeed::OnText_PercentChange)
EVT_TEXT(ID_Multiplier, EffectChangeSpeed::OnText_Multiplier)
EVT_SLIDER(ID_PercentChange, EffectChangeSpeed::OnSlider_PercentChange)
EVT_CHOICE(ID_FromVinyl, EffectChangeSpeed::OnChoice_Vinyl)
EVT_CHOICE(ID_ToVinyl, EffectChangeSpeed::OnChoice_Vinyl)
EVT_TEXT(ID_ToLength, EffectChangeSpeed::OnTimeCtrl_ToLength)
EVT_COMMAND(ID_ToLength, EVT_TIMETEXTCTRL_UPDATED, EffectChangeSpeed::OnTimeCtrlUpdate)
END_EVENT_TABLE()
EffectChangeSpeed::EffectChangeSpeed()
{
// Retrieve last used control values
gPrefs->Read(wxT("/Effects/ChangeSpeed/PercentChange"), &m_PercentChange, 0);
// default format "4" is the same as the Selection toolbar: "hh:mm:ss + milliseconds";
gPrefs->Read(wxT("/Effects/ChangeSpeed/TimeFormat"), &mTimeCtrlFormat, 4);
// effect parameters
m_PercentChange = DEF_Percentage;
gPrefs->Read(wxT("/Effects/ChangeSpeed/VinylChoice"), &mFromVinyl, 0);
if (mFromVinyl == kVinyl_NA) {
mFromVinyl = kVinyl_33AndAThird;
}
mFromVinyl = kVinyl_33AndAThird;
mToVinyl = kVinyl_33AndAThird;
mFromLength = 0.0;
mToLength = 0.0;
mFormat = _("hh:mm:ss + milliseconds");
mbLoopDetect = false;
}
wxString EffectChangeSpeed::GetEffectDescription() {
// Note: This is useful only after change amount has been set.
return wxString::Format(_("Applied effect: %s %.3f%%"),
this->GetEffectName().c_str(),
m_PercentChange);
EffectChangeSpeed::~EffectChangeSpeed()
{
}
// IdentInterface implementation
wxString EffectChangeSpeed::GetSymbol()
{
return CHANGESPEED_PLUGIN_SYMBOL;
}
wxString EffectChangeSpeed::GetDescription()
{
return wxTRANSLATE("Change the speed of a track, also changing its pitch");
}
// EffectIdentInterface implementation
EffectType EffectChangeSpeed::GetType()
{
return EffectTypeProcess;
}
// EffectClientInterface implementation
bool EffectChangeSpeed::GetAutomationParameters(EffectAutomationParameters & parms)
{
parms.Write(KEY_Percentage, m_PercentChange);
return true;
}
bool EffectChangeSpeed::SetAutomationParameters(EffectAutomationParameters & parms)
{
ReadAndVerifyDouble(Percentage);
m_PercentChange = Percentage;
return true;
}
// Effect implementation
bool EffectChangeSpeed::CheckWhetherSkipEffect()
{
return (m_PercentChange == 0.0);
}
double EffectChangeSpeed::CalcPreviewInputLength(double previewLength)
@@ -76,30 +151,43 @@ double EffectChangeSpeed::CalcPreviewInputLength(double previewLength)
return previewLength * (100.0 + m_PercentChange) / 100.0;
}
bool EffectChangeSpeed::PromptUser()
bool EffectChangeSpeed::Startup()
{
ChangeSpeedDialog dlog(this, mParent);
dlog.m_PercentChange = m_PercentChange;
dlog.mFromVinyl = mFromVinyl;
dlog.mFromLength = mFromLength;
dlog.mTimeCtrlFormat = mTimeCtrlFormat;
// Don't need to call TransferDataToWindow, although other
// Audacity dialogs (from which I derived this one) do it, because
// ShowModal calls stuff that eventually calls wxWindowBase::OnInitDialog,
// which calls dlog.TransferDataToWindow();
dlog.CentreOnParent();
dlog.ShowModal();
wxString base = wxT("/Effects/ChangeSpeed/");
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
// Migrate settings from 2.1.0 or before
m_PercentChange = dlog.m_PercentChange;
mFromVinyl = dlog.mFromVinyl;
mTimeCtrlFormat = dlog.mTimeCtrlFormat;
// Already migrated, so bail
if (gPrefs->Exists(base + wxT("Migrated")))
{
return true;
}
// Load the old "current" settings
if (gPrefs->Exists(base))
{
// Retrieve last used control values
gPrefs->Read(base + wxT("PercentChange"), &m_PercentChange, 0);
// default format "4" is the same as the Selection toolbar: "hh:mm:ss + milliseconds";
gPrefs->Read(base + wxT("TimeFormat"), &mFormat, _("hh:mm:ss + milliseconds"));
gPrefs->Read(base + wxT("VinylChoice"), &mFromVinyl, 0);
if (mFromVinyl == kVinyl_NA)
{
mFromVinyl = kVinyl_33AndAThird;
}
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat);
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
SaveUserPreset(GetCurrentSettingsGroup());
// Do not migrate again
gPrefs->Write(base + wxT("Migrated"), true);
gPrefs->Flush();
}
gPrefs->Write(wxT("/Effects/ChangeSpeed/PercentChange"), m_PercentChange);
gPrefs->Write(wxT("/Effects/ChangeSpeed/TimeFormat"), mTimeCtrlFormat);
gPrefs->Flush();
return true;
}
@@ -111,25 +199,6 @@ bool EffectChangeSpeed::Init()
return true;
}
// Labels are time-scaled linearly inside the affected region, and labels after
// the region are shifted along according to how the region size changed.
bool EffectChangeSpeed::ProcessLabelTrack(Track *t)
{
SetTimeWarper(new RegionTimeWarper(mT0, mT1,
new LinearTimeWarper(mT0, mT0,
mT1, mT0 + (mT1-mT0)*mFactor)));
LabelTrack *lt = (LabelTrack*)t;
if (lt == NULL) return false;
lt->WarpLabels(*GetTimeWarper());
return true;
}
bool EffectChangeSpeed::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferDouble(wxT("Percentage"),m_PercentChange,0.0);
return true;
}
bool EffectChangeSpeed::Process()
{
// Similar to EffectSoundTouch::Process()
@@ -137,7 +206,7 @@ bool EffectChangeSpeed::Process()
// Iterate over each track.
// Track::All is needed because this effect needs to introduce
// silence in the sync-lock group tracks to keep sync
this->CopyInputTracks(Track::All); // Set up mOutputTracks.
CopyInputTracks(Track::All); // Set up mOutputTracks.
bool bGoodResult = true;
TrackListIterator iter(mOutputTracks);
@@ -204,6 +273,185 @@ bool EffectChangeSpeed::Process()
return bGoodResult;
}
void EffectChangeSpeed::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.StartVerticalLay(0);
{
S.AddSpace(0, 5);
S.AddTitle(_("Change Speed, affecting both Tempo and Pitch"));
S.AddSpace(0, 10);
// Speed multiplier and percent change controls.
S.StartMultiColumn(4, wxCENTER);
{
FloatingPointValidator<double> vldMultiplier(3, &mMultiplier, NUM_VAL_NO_TRAILING_ZEROES);
vldMultiplier.SetRange(MIN_Percentage / 100.0, MAX_Percentage / 100.0);
mpTextCtrl_Multiplier =
S.Id(ID_Multiplier).AddTextBox(_("Speed Multiplier:"), wxT(""), 12);
mpTextCtrl_Multiplier->SetValidator(vldMultiplier);
FloatingPointValidator<double> vldPercentage(3, &m_PercentChange, NUM_VAL_NO_TRAILING_ZEROES);
vldPercentage.SetRange(MIN_Percentage, MAX_Percentage);
mpTextCtrl_PercentChange =
S.Id(ID_PercentChange).AddTextBox(_("Percent Change:"), wxT(""), 12);
mpTextCtrl_PercentChange->SetValidator(vldPercentage);
}
S.EndMultiColumn();
// Percent change slider.
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mpSlider_PercentChange =
S.Id(ID_PercentChange).AddSlider(wxT(""), 0, (int)kSliderMax, (int)MIN_Percentage);
mpSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
// Vinyl rpm controls.
S.StartMultiColumn(5, wxCENTER);
{
/* i18n-hint: "rpm" is an English abbreviation meaning "revolutions per minute". */
S.AddUnits(_("Standard Vinyl rpm:"));
wxASSERT(kNumVinyl == WXSIZEOF(kVinylStrings));
wxArrayString vinylChoices;
for (int i = 0; i < kNumVinyl; i++)
{
if (i == kVinyl_NA)
{
vinylChoices.Add(wxGetTranslation(kVinylStrings[i]));
}
else
{
vinylChoices.Add(kVinylStrings[i]);
}
}
mpChoice_FromVinyl =
S.Id(ID_FromVinyl).AddChoice(_("from"), wxT(""), &vinylChoices);
mpChoice_FromVinyl->SetName(_("From rpm"));
mpChoice_FromVinyl->SetSizeHints(100, -1);
mpChoice_ToVinyl =
S.Id(ID_ToVinyl).AddChoice(_("to"), wxT(""), &vinylChoices);
mpChoice_ToVinyl->SetName(_("To rpm"));
mpChoice_ToVinyl->SetSizeHints(100, -1);
}
S.EndMultiColumn();
// From/To time controls.
S.StartStatic(_("Selection Length"), 0);
{
S.StartMultiColumn(2, wxCENTER);
{
S.AddPrompt(_("Current Length:"));
mpFromLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
wxID_ANY,
mFormat,
mFromLength,
mProjectRate);
mpFromLengthCtrl->SetName(_("from"));
mpFromLengthCtrl->SetToolTip(_("Current length of selection."));
mpFromLengthCtrl->SetReadOnly(true);
mpFromLengthCtrl->EnableMenu(false);
S.AddWindow(mpFromLengthCtrl, wxALIGN_LEFT);
S.AddPrompt(_("New Length:"));
mpToLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME,
S.GetParent(),
ID_ToLength,
mFormat,
mToLength,
mProjectRate);
mpToLengthCtrl->SetName(_("to"));
mpToLengthCtrl->EnableMenu();
S.AddWindow(mpToLengthCtrl, wxALIGN_LEFT);
}
S.EndMultiColumn();
}
S.EndStatic();
}
S.EndVerticalLay();
}
bool EffectChangeSpeed::TransferDataToWindow()
{
mbLoopDetect = true;
if (!mUIParent->TransferDataToWindow())
{
return false;
}
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat, mFormat);
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl, mFromVinyl);
if (mFromVinyl == kVinyl_NA)
{
mFromVinyl = kVinyl_33AndAThird;
}
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_TimeCtrl_ToLength();
// Set from/to Vinyl controls - mFromVinyl must be set first.
mpChoice_FromVinyl->SetSelection(mFromVinyl);
// Then update to get correct mToVinyl.
Update_Vinyl();
// Then update ToVinyl control.
mpChoice_ToVinyl->SetSelection(mToVinyl);
// Set From Length control.
// Set the format first so we can get sample accuracy.
mpFromLengthCtrl->SetFormatName(mFormat);
mpFromLengthCtrl->SetValue(mFromLength);
mbLoopDetect = false;
return true;
}
bool EffectChangeSpeed::TransferDataFromWindow()
{
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
{
return false;
}
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("TimeFormat"), mFormat);
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
return true;
}
// EffectChangeSpeed implementation
// Labels are time-scaled linearly inside the affected region, and labels after
// the region are shifted along according to how the region size changed.
bool EffectChangeSpeed::ProcessLabelTrack(Track *t)
{
SetTimeWarper(new RegionTimeWarper(mT0, mT1,
new LinearTimeWarper(mT0, mT0,
mT1, mT0 + (mT1-mT0)*mFactor)));
LabelTrack *lt = (LabelTrack*)t;
if (lt == NULL) return false;
lt->WarpLabels(*GetTimeWarper());
return true;
}
// ProcessOne() takes a track, transforms it to bunch of buffer-blocks,
// and calls libsamplerate code on these blocks.
bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
@@ -304,237 +552,42 @@ bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
return bResult;
}
// handler implementations for EffectChangeSpeed
//
// ChangeSpeedDialog
//
// -99 for PERCENTCHANGE_MIN because -100% is nonsensical.
#define PERCENTCHANGE_MIN -99
#define PERCENTCHANGE_MAX 100 // warped above zero to actually go up to 400%
#define PERCENTCHANGE_MAX_TEXT 4900 // maximum allowed by text entry (= 50 times)
#define PERCENTCHANGE_SLIDER_WARP 1.30105 // warp power takes max from 100 to 400.
enum {
ID_TEXT_PERCENTCHANGE = 10001,
ID_TEXT_MULTIPLIER,
ID_SLIDER_PERCENTCHANGE,
ID_CHOICE_FROMVINYL,
ID_CHOICE_TOVINYL,
ID_TIMECTRL_TOLENGTH
};
// event table for ChangeSpeedDialog
BEGIN_EVENT_TABLE(ChangeSpeedDialog, EffectDialog)
EVT_TEXT(ID_TEXT_PERCENTCHANGE, ChangeSpeedDialog::OnText_PercentChange)
EVT_TEXT(ID_TEXT_MULTIPLIER, ChangeSpeedDialog::OnText_Multiplier)
EVT_SLIDER(ID_SLIDER_PERCENTCHANGE, ChangeSpeedDialog::OnSlider_PercentChange)
EVT_CHOICE(ID_CHOICE_FROMVINYL, ChangeSpeedDialog::OnChoice_Vinyl)
EVT_CHOICE(ID_CHOICE_TOVINYL, ChangeSpeedDialog::OnChoice_Vinyl)
EVT_TEXT(ID_TIMECTRL_TOLENGTH, ChangeSpeedDialog::OnTimeCtrl_ToLength)
EVT_COMMAND(ID_TIMECTRL_TOLENGTH, EVT_TIMETEXTCTRL_UPDATED, ChangeSpeedDialog::OnTimeCtrlUpdate)
EVT_BUTTON(ID_EFFECT_PREVIEW, ChangeSpeedDialog::OnPreview)
END_EVENT_TABLE()
ChangeSpeedDialog::ChangeSpeedDialog(EffectChangeSpeed *effect, wxWindow *parent)
: EffectDialog(parent,
/* i18n-hint: Audacity's change speed effect changes the speed and pitch.*/
_("Change Speed"),
PROCESS_EFFECT),
mEffect(effect)
{
mbLoopDetect = false;
// effect parameters
m_PercentChange = 0.0;
mFromVinyl = kVinyl_33AndAThird;
mToVinyl = kVinyl_33AndAThird;
mFromLength = 0.0;
mToLength = 0.0;
mFormat = wxT("");
mTimeCtrlFormat = 0;
Init();
}
void ChangeSpeedDialog::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(5);
S.AddSpace(0, 5);
S.AddTitle(_("Change Speed, affecting both Tempo and Pitch"));
S.AddSpace(0, 10);
// Speed multiplier and percent change controls.
S.StartMultiColumn(4, wxLEFT);
{
wxTextValidator validator(wxFILTER_NUMERIC);
mpTextCtrl_Multiplier =
S.Id(ID_TEXT_MULTIPLIER).AddTextBox(_("Speed Multiplier:"), wxT(""), 12);
mpTextCtrl_Multiplier->SetValidator(validator);
mpTextCtrl_PercentChange =
S.Id(ID_TEXT_PERCENTCHANGE).AddTextBox(_("Percent Change:"), wxT(""), 12);
mpTextCtrl_PercentChange->SetValidator(validator);
}
S.EndMultiColumn();
// Percent change slider.
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
mpSlider_PercentChange =
S.Id(ID_SLIDER_PERCENTCHANGE).AddSlider(wxT(""), 0, (int)PERCENTCHANGE_MAX, (int)PERCENTCHANGE_MIN);
mpSlider_PercentChange->SetName(_("Percent Change"));
}
S.EndHorizontalLay();
// Vinyl rpm controls.
S.StartMultiColumn(5, wxCENTER);
{
/* i18n-hint: "rpm" is an English abbreviation meaning "revolutions per minute". */
S.AddUnits(_("Standard Vinyl rpm:"));
wxArrayString rpmStrings;
rpmStrings.Add(wxT("33 1/3"));
rpmStrings.Add(wxT("45"));
rpmStrings.Add(wxT("78"));
/* i18n-hint: n/a is an English abbreviation meaning "not applicable". */
rpmStrings.Add(_("n/a"));
mpChoice_FromVinyl =
S.Id(ID_CHOICE_FROMVINYL).AddChoice(_("from"), wxT(""), &rpmStrings);
mpChoice_FromVinyl->SetName(_("From rpm"));
mpChoice_FromVinyl->SetSizeHints(100, -1);
mpChoice_ToVinyl =
S.Id(ID_CHOICE_TOVINYL).AddChoice(_("to"), wxT(""), &rpmStrings);
mpChoice_ToVinyl->SetName(_("To rpm"));
mpChoice_ToVinyl->SetSizeHints(100, -1);
}
S.EndMultiColumn();
// From/To time controls.
S.StartStatic(_("Selection Length"), 0);
{
S.StartMultiColumn(2, wxLEFT);
{
S.AddPrompt(_("Current Length") + wxString(wxT(":")));
mpFromLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME, this,
wxID_ANY,
mFormat,
mFromLength,
mEffect->mProjectRate);
mpFromLengthCtrl->SetName(_("from"));
S.AddWindow(mpFromLengthCtrl, wxALIGN_LEFT);
#if wxUSE_TOOLTIPS
wxString tip(_("Current length of selection."));
mpFromLengthCtrl->SetToolTip(tip);
#endif
mpFromLengthCtrl->SetReadOnly(true);
mpFromLengthCtrl->EnableMenu(false);
S.AddPrompt(_("New Length") + wxString(wxT(":")));
mpToLengthCtrl = new
NumericTextCtrl(NumericConverter::TIME, this,
ID_TIMECTRL_TOLENGTH,
mFormat,
mToLength,
mEffect->mProjectRate);
mpToLengthCtrl->SetName(_("to"));
S.AddWindow(mpToLengthCtrl, wxALIGN_LEFT);
mpToLengthCtrl->EnableMenu();
}
S.EndMultiColumn();
}
S.EndStatic();
}
bool ChangeSpeedDialog::TransferDataToWindow()
{
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_TimeCtrl_ToLength();
// Set from/to Vinyl controls - mFromVinyl must be set first.
mpChoice_FromVinyl->SetSelection(mFromVinyl);
// Then update to get correct mToVinyl.
this->Update_Vinyl();
// Then update ToVinyl control.
mpChoice_ToVinyl->SetSelection(mToVinyl);
// Set From Length control.
// Set the format first so we can get sample accuracy.
mpFromLengthCtrl->SetFormatName(mFormat);
mpFromLengthCtrl->SetValue(mFromLength);
mbLoopDetect = false;
return true;
}
bool ChangeSpeedDialog::Validate()
{
TransferDataFromWindow();
m_PercentChange = TrapDouble(m_PercentChange, PERCENTCHANGE_MIN, PERCENTCHANGE_MAX_TEXT);
return true;
}
// handler implementations for ChangeSpeedDialog
void ChangeSpeedDialog::OnText_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnText_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
double newValue = 0;
wxString str = mpTextCtrl_PercentChange->GetValue();
str.ToDouble(&newValue);
m_PercentChange = newValue;
this->UpdateUI();
mpTextCtrl_PercentChange->GetValidator()->TransferFromWindow();
UpdateUI();
mbLoopDetect = true;
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnText_Multiplier(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnText_Multiplier(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
double newValue = 0;
wxString str = mpTextCtrl_Multiplier->GetValue();
str.ToDouble(&newValue);
m_PercentChange = 100 * (newValue - 1);
this->UpdateUI();
mpTextCtrl_Multiplier->GetValidator()->TransferFromWindow();
m_PercentChange = 100 * (mMultiplier - 1);
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Slider_PercentChange();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
@@ -542,18 +595,18 @@ void ChangeSpeedDialog::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(event))
m_PercentChange = (double)(mpSlider_PercentChange->GetValue());
// Warp positive values to actually go up faster & further than negatives.
if (m_PercentChange > 0.0)
m_PercentChange = pow(m_PercentChange, PERCENTCHANGE_SLIDER_WARP);
this->UpdateUI();
m_PercentChange = pow(m_PercentChange, kSliderWarp);
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Vinyl();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Vinyl();
Update_TimeCtrl_ToLength();
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(evt))
{
// Treat mpChoice_FromVinyl and mpChoice_ToVinyl as one control since we need
// both to calculate Percent Change.
@@ -561,8 +614,7 @@ void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
mToVinyl = mpChoice_ToVinyl->GetSelection();
// Use this as the 'preferred' choice.
if (mFromVinyl != kVinyl_NA) {
gPrefs->Write(wxT("/Effects/ChangeSpeed/VinylChoice"), mFromVinyl);
gPrefs->Flush();
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl);
}
// If mFromVinyl & mToVinyl are set, then there's a new percent change.
@@ -583,94 +635,74 @@ void ChangeSpeedDialog::OnChoice_Vinyl(wxCommandEvent & WXUNUSED(event))
case kVinyl_78: toRPM = 78; break;
}
m_PercentChange = ((toRPM * 100.0) / fromRPM) - 100.0;
this->UpdateUI();
UpdateUI();
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_TimeCtrl_ToLength();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_TimeCtrl_ToLength();
}
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnTimeCtrl_ToLength(wxCommandEvent & WXUNUSED(event))
void EffectChangeSpeed::OnTimeCtrl_ToLength(wxCommandEvent & WXUNUSED(evt))
{
if (mbLoopDetect)
return;
mToLength = mpToLengthCtrl->GetValue();
m_PercentChange = ((mFromLength * 100.0) / mToLength) - 100.0;
this->UpdateUI();
mToLength = mpToLengthCtrl->GetValue();
m_PercentChange = ((mFromLength * 100.0) / mToLength) - 100.0;
UpdateUI();
mbLoopDetect = true;
mbLoopDetect = true;
this->Update_Text_PercentChange();
this->Update_Text_Multiplier();
this->Update_Slider_PercentChange();
this->Update_Vinyl();
Update_Text_PercentChange();
Update_Text_Multiplier();
Update_Slider_PercentChange();
Update_Vinyl();
mbLoopDetect = false;
mbLoopDetect = false;
}
void ChangeSpeedDialog::OnTimeCtrlUpdate(wxCommandEvent &evt)
void EffectChangeSpeed::OnTimeCtrlUpdate(wxCommandEvent & evt)
{
mTimeCtrlFormat = evt.GetInt();
mFormat = evt.GetString();
mFormat = mpToLengthCtrl->GetBuiltinName(mTimeCtrlFormat);
mpFromLengthCtrl->SetFormatName(mFormat);
// Update From/To Length controls (precision has changed).
mpToLengthCtrl->SetValue(mToLength);
mpFromLengthCtrl->SetValue(mFromLength);
}
void ChangeSpeedDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
{
TransferDataFromWindow();
// Save & restore parameters around Preview, because we didn't do OK.
double oldPercentChange = mEffect->m_PercentChange;
// bug 773 allows effects to bypass greyed out OK button,
// but validate() should now catch that.
wxASSERT((m_PercentChange >= PERCENTCHANGE_MIN) && (m_PercentChange <= PERCENTCHANGE_MAX_TEXT));
mEffect->m_PercentChange = m_PercentChange;
mEffect->Preview();
mEffect->m_PercentChange = oldPercentChange;
}
// helper functions
void ChangeSpeedDialog::Update_Text_PercentChange()
void EffectChangeSpeed::Update_Text_PercentChange()
// Update Text Percent control from percent change.
{
wxString str;
str.Printf(wxT("%.3f"), m_PercentChange);
mpTextCtrl_PercentChange->SetValue(str);
mpTextCtrl_PercentChange->GetValidator()->TransferToWindow();
}
void ChangeSpeedDialog::Update_Text_Multiplier()
void EffectChangeSpeed::Update_Text_Multiplier()
// Update Multiplier control from percent change.
{
wxString str;
str.Printf(wxT("%.3f"), 1 + (m_PercentChange) / 100.0);
mpTextCtrl_Multiplier->SetValue(str);
mMultiplier = 1 + (m_PercentChange) / 100.0;
mpTextCtrl_Multiplier->GetValidator()->TransferToWindow();
}
void ChangeSpeedDialog::Update_Slider_PercentChange()
void EffectChangeSpeed::Update_Slider_PercentChange()
// Update Slider Percent control from percent change.
{
double unwarped = m_PercentChange;
if (unwarped > 0.0)
// Un-warp values above zero to actually go up to PERCENTCHANGE_MAX.
unwarped = pow(m_PercentChange, (1.0 / PERCENTCHANGE_SLIDER_WARP));
// Un-warp values above zero to actually go up to kSliderMax.
unwarped = pow(m_PercentChange, (1.0 / kSliderWarp));
// Add 0.5 to unwarped so trunc -> round.
mpSlider_PercentChange->SetValue((int)(unwarped + 0.5));
}
void ChangeSpeedDialog::Update_Vinyl()
void EffectChangeSpeed::Update_Vinyl()
// Update Vinyl controls from percent change.
{
// Match Vinyl rpm when within 0.01% of a standard ratio.
@@ -684,7 +716,7 @@ void ChangeSpeedDialog::Update_Vinyl()
mpChoice_ToVinyl->SetSelection(mpChoice_FromVinyl->GetSelection());
} else {
// Use the last saved option.
gPrefs->Read(wxT("/Effects/ChangeSpeed/VinylChoice"), &mFromVinyl, 0);
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("VinylChoice"), mFromVinyl, 0);
mpChoice_FromVinyl->SetSelection(mFromVinyl);
mpChoice_ToVinyl->SetSelection(mFromVinyl);
}
@@ -721,13 +753,12 @@ void ChangeSpeedDialog::Update_Vinyl()
mToVinyl = mpChoice_ToVinyl->GetSelection();
}
void ChangeSpeedDialog::Update_TimeCtrl_ToLength()
void EffectChangeSpeed::Update_TimeCtrl_ToLength()
// Update ToLength control from percent change.
{
mToLength = (mFromLength * 100.0) / (100.0 + m_PercentChange);
// Set the format first so we can get sample accuracy.
mFormat = mpToLengthCtrl->GetBuiltinName(mTimeCtrlFormat);
mpToLengthCtrl->SetFormatName(mFormat);
// Negative times do not make sense.
// 359999 = 99h:59m:59s which is a little less disturbing than overflow characters
@@ -736,11 +767,8 @@ void ChangeSpeedDialog::Update_TimeCtrl_ToLength()
mpToLengthCtrl->SetValue(mToLength);
}
void ChangeSpeedDialog::UpdateUI()
void EffectChangeSpeed::UpdateUI()
// Disable OK and Preview if not in sensible range.
{
bool enabled = (m_PercentChange < PERCENTCHANGE_MIN ||
m_PercentChange > PERCENTCHANGE_MAX_TEXT)? false : true;
FindWindow(wxID_OK)->Enable(enabled);
FindWindow(ID_EFFECT_PREVIEW)->Enable(enabled);
EnableApply(m_PercentChange >= MIN_Percentage && m_PercentChange <= MAX_Percentage);
}