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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user