32#include <wx/checkbox.h>
35#include <wx/spinctrl.h>
36#include <wx/valtext.h>
38#include "../PitchName.h"
42#include "../widgets/valnum.h"
54#undef PACKAGE_BUGREPORT
57#include "SoundTouch.h"
81 EffectChangePitch &e,
bool updating){
83 e.Calc_SemitonesChange_fromPercentChange();
97{
XO(
"Change Pitch") };
101BEGIN_EVENT_TABLE(EffectChangePitch, wxEvtHandler)
102 EVT_CHOICE(ID_FromPitch, EffectChangePitch::OnChoice_FromPitch)
103 EVT_TEXT(ID_FromOctave, EffectChangePitch::OnSpin_FromOctave)
104 EVT_CHOICE(ID_ToPitch, EffectChangePitch::OnChoice_ToPitch)
105 EVT_TEXT(ID_ToOctave, EffectChangePitch::OnSpin_ToOctave)
107 EVT_TEXT(ID_SemitonesChange, EffectChangePitch::OnText_SemitonesChange)
109 EVT_TEXT(ID_FromFrequency, EffectChangePitch::OnText_FromFrequency)
110 EVT_TEXT(ID_ToFrequency, EffectChangePitch::OnText_ToFrequency)
116EffectChangePitch::EffectChangePitch()
120 Parameters().Reset(*
this);
122 m_dSemitonesChange = 0.0;
123 m_dStartFrequency = 0.0;
124 m_bLoopDetect =
false;
129 m_pChoice_FromPitch = NULL;
130 m_pSpin_FromOctave = NULL;
131 m_pChoice_ToPitch = NULL;
132 m_pSpin_ToOctave = NULL;
134 m_pTextCtrl_SemitonesChange = NULL;
136 m_pTextCtrl_FromFrequency = NULL;
137 m_pTextCtrl_ToFrequency = NULL;
139 m_pTextCtrl_PercentChange = NULL;
140 m_pSlider_PercentChange = NULL;
142 SetLinearEffectFlag(
true);
145EffectChangePitch::~EffectChangePitch()
158 return XO(
"Changes the pitch of a track without changing its tempo");
163 return L
"Change_Pitch";
176 return const_cast<EffectChangePitch&
>(*this).DoLoadFactoryDefaults(
settings);
194 double pitchRatio = 1.0 + m_dPercentChange / 100.0;
206 Calc_SemitonesChange_fromPercentChange();
208 auto initer = [&](soundtouch::SoundTouch *soundtouch)
210 soundtouch->setPitchSemiTones((
float)(m_dSemitonesChange));
224 mSemitones = m_dSemitonesChange;
226 return EffectSoundTouch::ProcessWithTimeWarper(initer, warper,
true);
230bool EffectChangePitch::CheckWhetherSkipEffect(
const EffectSettings &)
const
232 return (m_dPercentChange == 0.0);
235std::unique_ptr<EffectEditor> EffectChangePitch::PopulateOrExchange(
239 mUIParent =
S.GetParent();
243 for (
int ii = 0; ii < 12; ++ii)
248 S.StartVerticalLay(0);
250 S.StartVerticalLay();
253 XO(
"Estimated Start Pitch: %s%d (%.3f Hz)")
254 .
Format( pitch[m_nFromPitch], m_nFromOctave, m_FromFrequency) );
259 S.StartStatic(
XO(
"Pitch"));
261 S.StartMultiColumn(6, wxALIGN_CENTER);
263 m_pChoice_FromPitch =
S.Id(ID_FromPitch)
265 .Name(
XC(
"from",
"change pitch"))
266 .MinSize( { 80, -1 } )
268 .AddChoice(
XXC(
"&from",
"change pitch"), pitch);
270 m_pSpin_FromOctave =
S.Id(ID_FromOctave)
271 .Name(
XO(
"from Octave"))
272 .MinSize( { 50, -1 } )
273 .AddSpinCtrl( {}, m_nFromOctave, INT_MAX, INT_MIN);
275 m_pChoice_ToPitch =
S.Id(ID_ToPitch)
277 .Name(
XC(
"to",
"change pitch"))
278 .MinSize( { 80, -1 } )
280 .AddChoice(
XXC(
"&to",
"change pitch"), pitch);
282 m_pSpin_ToOctave =
S.Id(ID_ToOctave)
283 .Name(
XO(
"to Octave"))
284 .MinSize( { 50, -1 } )
285 .AddSpinCtrl( {}, m_nToOctave, INT_MAX, INT_MIN);
289 S.StartHorizontalLay(wxALIGN_CENTER);
291 m_pTextCtrl_SemitonesChange =
S.Id(ID_SemitonesChange)
292 .Name(
XO(
"Semitones (half-steps)"))
293 .Validator<FloatingPointValidator<double>>(
294 2, &m_dSemitonesChange,
295 NumValidatorStyle::TWO_TRAILING_ZEROES
297 .AddTextBox(
XXO(
"&Semitones (half-steps):"),
wxT(
""), 12);
299 S.EndHorizontalLay();
303 S.StartStatic(
XO(
"Frequency"));
305 S.StartMultiColumn(5, wxALIGN_CENTER);
307 m_pTextCtrl_FromFrequency =
S.Id(ID_FromFrequency)
308 .Name(
XO(
"from (Hz)"))
309 .
Validator<FloatingPointValidator<double>>(
311 NumValidatorStyle::THREE_TRAILING_ZEROES,
314 .AddTextBox(
XXO(
"f&rom"),
wxT(
""), 12);
316 m_pTextCtrl_ToFrequency =
S.Id(ID_ToFrequency)
318 .
Validator<FloatingPointValidator<double>>(
320 NumValidatorStyle::THREE_TRAILING_ZEROES,
323 .AddTextBox(
XXO(
"t&o"),
wxT(
""), 12);
325 S.AddUnits(
XO(
"Hz"));
329 S.StartHorizontalLay(wxALIGN_CENTER);
332 .Validator<FloatingPointValidator<double>>(
333 3, &m_dPercentChange,
334 NumValidatorStyle::THREE_TRAILING_ZEROES,
335 Percentage.min, Percentage.max )
336 .AddTextBox(
XXO(
"Percent C&hange:"), L
"", 12);
338 S.EndHorizontalLay();
340 S.StartHorizontalLay(wxEXPAND);
343 .Name(
XO(
"Percent Change"))
344 .Style(wxSL_HORIZONTAL)
345 .AddSlider( {}, 0, (int)
kSliderMax, (
int)Percentage.min);
347 S.EndHorizontalLay();
352 S.StartMultiColumn(2);
354 mUseSBSMSCheckBox =
S.Validator<wxGenericValidator>(&mUseSBSMS)
355 .AddCheckBox(
XXO(
"&Use high quality stretching (slow)"),
366bool EffectChangePitch::TransferDataToWindow(
const EffectSettings &)
368 m_bLoopDetect =
true;
370 if (!mUIParent->TransferDataToWindow())
375 Calc_SemitonesChange_fromPercentChange();
380 Update_Choice_FromPitch();
381 Update_Choice_ToPitch();
382 Update_Spin_FromOctave();
383 Update_Spin_ToOctave();
384 Update_Text_SemitonesChange();
385 Update_Text_FromFrequency();
386 Update_Text_ToFrequency();
387 Update_Text_PercentChange();
388 Update_Slider_PercentChange();
390 m_bLoopDetect =
false;
397 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
403 m_nFromPitch = m_pChoice_FromPitch->GetSelection();
404 m_nFromOctave = m_pSpin_FromOctave->GetValue();
406 m_nToPitch = m_pChoice_ToPitch->GetSelection();
418void EffectChangePitch::DeduceFrequencies()
420 auto FirstTrack = [&]()->
const WaveTrack *{
421 if( IsBatchProcessing() || !inputTracks() )
423 return *(inputTracks()->Selected<
const WaveTrack>()).first;
426 m_dStartFrequency = 261.265;
430 auto track = FirstTrack();
432 double rate = track->GetRate();
438 const size_t windowSize =
440 std::max(256, wxRound(pow(2.0, floor((log(rate / 20.0)/log(2.0)) + 0.5))));
444 const unsigned numWindows =
445 std::max(1, wxRound((
double)(rate / (5.0f * windowSize))));
447 double trackStart = track->GetStartTime();
448 double t0 = mT0 < trackStart? trackStart: mT0;
449 auto start = track->TimeToLongSamples(t0);
451 auto analyzeSize = windowSize * numWindows;
452 Floats buffer{ analyzeSize };
454 Floats freq{ windowSize / 2 };
455 Floats freqa{ windowSize / 2,
true };
458 (*track->Channels().begin())->GetFloats(buffer.get(), start, analyzeSize);
459 for(
unsigned i = 0; i < numWindows; i++) {
461 buffer.get() + i * windowSize, windowSize, windowSize, freq.get(),
463 for(
size_t j = 0; j < windowSize / 2; j++)
467 for(
size_t j = 1; j < windowSize / 2; j++)
468 if (freqa[j] > freqa[argmax])
471 auto lag = (windowSize / 2 - 1) - argmax;
472 m_dStartFrequency = rate / lag;
476 double dToMIDInote = dFromMIDInote + m_dSemitonesChange;
482 m_FromFrequency = m_dStartFrequency;
489void EffectChangePitch::Calc_ToPitch()
491 int nSemitonesChange =
492 (int)(m_dSemitonesChange + ((m_dSemitonesChange < 0.0) ? -0.5 : 0.5));
493 m_nToPitch = (m_nFromPitch + nSemitonesChange) % 12;
498void EffectChangePitch::Calc_ToOctave()
503void EffectChangePitch::Calc_SemitonesChange_fromPitches()
509void EffectChangePitch::Calc_SemitonesChange_fromPercentChange()
513 m_dSemitonesChange = (12.0 * log((100.0 + m_dPercentChange) / 100.0)) / log(2.0);
516void EffectChangePitch::Calc_ToFrequency()
518 m_ToFrequency = (m_FromFrequency * (100.0 + m_dPercentChange)) / 100.0;
521void EffectChangePitch::Calc_PercentChange()
523 m_dPercentChange = 100.0 * (pow(2.0, (m_dSemitonesChange / 12.0)) - 1.0);
528void EffectChangePitch::OnChoice_FromPitch(wxCommandEvent & WXUNUSED(evt))
533 m_nFromPitch = m_pChoice_FromPitch->GetSelection();
534 m_FromFrequency =
PitchToFreq(m_nFromPitch, m_nFromOctave);
540 m_bLoopDetect =
true;
542 Update_Choice_ToPitch();
543 Update_Spin_ToOctave();
544 Update_Text_FromFrequency();
545 Update_Text_ToFrequency();
547 m_bLoopDetect =
false;
550void EffectChangePitch::OnSpin_FromOctave(wxCommandEvent & WXUNUSED(evt))
555 m_nFromOctave = m_pSpin_FromOctave->GetValue();
558 m_FromFrequency =
PitchToFreq(m_nFromPitch, m_nFromOctave);
563 m_bLoopDetect =
true;
565 Update_Spin_ToOctave();
566 Update_Text_FromFrequency();
567 Update_Text_ToFrequency();
569 m_bLoopDetect =
false;
572void EffectChangePitch::OnChoice_ToPitch(wxCommandEvent & WXUNUSED(evt))
577 m_nToPitch = m_pChoice_ToPitch->GetSelection();
579 Calc_SemitonesChange_fromPitches();
580 Calc_PercentChange();
583 m_bLoopDetect =
true;
585 Update_Text_SemitonesChange();
586 Update_Text_ToFrequency();
587 Update_Text_PercentChange();
588 Update_Slider_PercentChange();
590 m_bLoopDetect =
false;
593void EffectChangePitch::OnSpin_ToOctave(wxCommandEvent & WXUNUSED(evt))
598 int nNewValue = m_pSpin_ToOctave->GetValue();
601 if ((nNewValue + 3) < m_nFromOctave)
604 m_pSpin_ToOctave->SetValue(m_nFromOctave - 3);
607 m_nToOctave = nNewValue;
609 m_ToFrequency =
PitchToFreq(m_nToPitch, m_nToOctave);
611 Calc_SemitonesChange_fromPitches();
612 Calc_PercentChange();
614 m_bLoopDetect =
true;
616 Update_Text_SemitonesChange();
617 Update_Text_ToFrequency();
618 Update_Text_PercentChange();
619 Update_Slider_PercentChange();
621 m_bLoopDetect =
false;
624void EffectChangePitch::OnText_SemitonesChange(wxCommandEvent & WXUNUSED(evt))
629 if (!m_pTextCtrl_SemitonesChange->GetValidator()->TransferFromWindow())
635 Calc_PercentChange();
640 m_bLoopDetect =
true;
642 Update_Choice_ToPitch();
643 Update_Spin_ToOctave();
644 Update_Text_ToFrequency();
645 Update_Text_PercentChange();
646 Update_Slider_PercentChange();
648 m_bLoopDetect =
false;
653 bool bIsGoodValue = (m_dSemitonesChange > -80.0) && (m_dSemitonesChange <= 60.0);
657void EffectChangePitch::OnText_FromFrequency(wxCommandEvent & WXUNUSED(evt))
665 if (!m_pTextCtrl_FromFrequency->GetValidator()->TransferFromWindow())
678 m_bLoopDetect =
true;
680 Update_Choice_FromPitch();
681 Update_Spin_FromOctave();
682 Update_Choice_ToPitch();
683 Update_Spin_ToOctave();
684 Update_Text_ToFrequency();
686 m_bLoopDetect =
false;
692void EffectChangePitch::OnText_ToFrequency(wxCommandEvent & WXUNUSED(evt))
700 if (!m_pTextCtrl_ToFrequency->GetValidator()->TransferFromWindow())
706 m_dPercentChange = ((m_ToFrequency * 100.0) / m_FromFrequency) - 100.0;
709 Calc_SemitonesChange_fromPercentChange();
712 m_bLoopDetect =
true;
714 Update_Choice_ToPitch();
715 Update_Spin_ToOctave();
716 Update_Text_SemitonesChange();
717 Update_Text_PercentChange();
718 Update_Slider_PercentChange();
720 m_bLoopDetect =
false;
725 bool bIsGoodValue = (m_dPercentChange > Percentage.min) && (m_dPercentChange <= Percentage.max);
729void EffectChangePitch::OnText_PercentChange(wxCommandEvent & WXUNUSED(evt))
734 if (!m_pTextCtrl_PercentChange->GetValidator()->TransferFromWindow())
740 Calc_SemitonesChange_fromPercentChange();
745 m_bLoopDetect =
true;
747 Update_Choice_ToPitch();
748 Update_Spin_ToOctave();
749 Update_Text_SemitonesChange();
750 Update_Text_ToFrequency();
751 Update_Slider_PercentChange();
753 m_bLoopDetect =
false;
759void EffectChangePitch::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(evt))
764 m_dPercentChange = (double)(m_pSlider_PercentChange->GetValue());
766 if (m_dPercentChange > 0.0)
767 m_dPercentChange = pow(m_dPercentChange,
kSliderWarp);
769 Calc_SemitonesChange_fromPercentChange();
774 m_bLoopDetect =
true;
776 Update_Choice_ToPitch();
777 Update_Spin_ToOctave();
778 Update_Text_SemitonesChange();
779 Update_Text_ToFrequency();
780 Update_Text_PercentChange();
782 m_bLoopDetect =
false;
787void EffectChangePitch::Update_Choice_FromPitch()
789 m_pChoice_FromPitch->SetSelection(m_nFromPitch);
792void EffectChangePitch::Update_Spin_FromOctave()
794 m_pSpin_FromOctave->SetValue(m_nFromOctave);
797void EffectChangePitch::Update_Choice_ToPitch()
799 m_pChoice_ToPitch->SetSelection(m_nToPitch);
802void EffectChangePitch::Update_Spin_ToOctave()
804 m_pSpin_ToOctave->SetValue(m_nToOctave);
807void EffectChangePitch::Update_Text_SemitonesChange()
809 m_pTextCtrl_SemitonesChange->GetValidator()->TransferToWindow();
812void EffectChangePitch::Update_Text_FromFrequency()
814 m_pTextCtrl_FromFrequency->GetValidator()->TransferToWindow();
817void EffectChangePitch::Update_Text_ToFrequency()
819 m_pTextCtrl_ToFrequency->GetValidator()->TransferToWindow();
822void EffectChangePitch::Update_Text_PercentChange()
824 m_pTextCtrl_PercentChange->GetValidator()->TransferToWindow();
827void EffectChangePitch::Update_Slider_PercentChange()
829 double unwarped = m_dPercentChange;
832 unwarped = pow(m_dPercentChange, (1.0 /
kSliderWarp));
835 m_pSlider_PercentChange->SetValue((
int)(unwarped + 0.5));
Change Pitch effect provides raising or lowering the pitch without changing the tempo.
static const double kSliderMax
static const double kSliderWarp
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
XXO("&Cut/Copy/Paste Toolbar")
unsigned int PitchIndex(const double dMIDInote)
double PitchToFreq(const unsigned int nPitchIndex, const int nPitchOctave)
double PitchToMIDInote(const unsigned int nPitchIndex, const int nPitchOctave)
int PitchOctave(const double dMIDInote)
double FreqToMIDInote(const double freq)
TranslatableString PitchName(const double dMIDInote, const PitchNameChoice choice)
bool ComputeSpectrum(const float *data, size_t width, size_t windowSize, float *output, bool autocorrelation, int windowFunc)
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
static Settings & settings()
std::vector< TranslatableString > TranslatableStrings
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
static bool EnableApply(wxWindow *parent, bool enable=true)
Enable or disable the Apply button of the dialog that contains parent.
OptionalMessage LoadFactoryDefaults(EffectSettings &settings) const override
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, SlideType rateSlideType, SlideType pitchSlideType, bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput)
TranslatableString mProxyEffectName
No change to time at all.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Holds a msgid for the translation catalog; may also bind format arguments.
A Validator is an object which checks whether a wxVariant satisfies a certain criterion....
A Track that contains audio waveform data.
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
Externalized state of a plug-in.