Audacity 3.2.0
ChangeTempo.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ChangeTempo.cpp
6
7 Vaughan Johnson,
8 Dominic Mazzoni
9
10*******************************************************************//*******************************************************************/
17#if USE_SOUNDTOUCH
18#include "ChangeTempo.h"
19#include "EffectEditor.h"
20
21#if USE_SBSMS
22#include <wx/valgen.h>
23#endif
24
25#include <wx/checkbox.h>
26#include <wx/slider.h>
27
28#include "ShuttleGui.h"
29#include "../widgets/valnum.h"
30
31#include "LoadEffects.h"
32
33enum
34{
35 ID_PercentChange = 10000,
36 ID_FromBPM,
37 ID_ToBPM,
38 ID_FromLength,
40};
41
42// We warp the slider to go up to 400%, but user can enter higher values.
43static const double kSliderMax = 100.0; // warped above zero to actually go up to 400%
44static const double kSliderWarp = 1.30105; // warp power takes max from 100 to 400.
45
47
48BEGIN_EVENT_TABLE(EffectChangeTempo, wxEvtHandler)
49 EVT_TEXT(ID_PercentChange, EffectChangeTempo::OnText_PercentChange)
50 EVT_SLIDER(ID_PercentChange, EffectChangeTempo::OnSlider_PercentChange)
51 EVT_TEXT(ID_FromBPM, EffectChangeTempo::OnText_FromBPM)
52 EVT_TEXT(ID_ToBPM, EffectChangeTempo::OnText_ToBPM)
53 EVT_TEXT(ID_ToLength, EffectChangeTempo::OnText_ToLength)
55
56std::unique_ptr<EffectEditor> EffectChangeTempo::PopulateOrExchange(
58 const EffectOutputs *)
59{
60 mUIParent = S.GetParent();
61
62 enum { precision = 2 };
63
64 S.StartVerticalLay(0);
65 {
66 //
67 S.StartMultiColumn(2, wxCENTER);
68 {
69 m_pTextCtrl_PercentChange = S.Id(ID_PercentChange)
70 .Validator<FloatingPointValidator<double>>(
71 3, &m_PercentChange, NumValidatorStyle::THREE_TRAILING_ZEROES,
72 Percentage.min, Percentage.max )
73 .AddTextBox(XXO("Percent C&hange:"), L"", 12);
74 }
75 S.EndMultiColumn();
76
77 //
78 S.StartHorizontalLay(wxEXPAND);
79 {
80 m_pSlider_PercentChange = S.Id(ID_PercentChange)
81 .Name(XO("Percent Change"))
82 .Style(wxSL_HORIZONTAL)
83 .AddSlider( {}, 0, (int)kSliderMax, (int)Percentage.min);
84 }
85 S.EndHorizontalLay();
86
87 S.StartStatic(XO("Beats per minute"));
88 {
89 S.StartHorizontalLay(wxALIGN_CENTER);
90 {
91 m_pTextCtrl_FromBPM = S.Id(ID_FromBPM)
92 /* i18n-hint: changing tempo "from" one value "to" another */
93 .Name(XO("Beats per minute, from"))
94 .Validator<FloatingPointValidator<double>>(
95 3, &m_FromBPM,
96 NumValidatorStyle::THREE_TRAILING_ZEROES
97 | NumValidatorStyle::ZERO_AS_BLANK)
98 /* i18n-hint: changing tempo "from" one value "to" another */
99 .AddTextBox(XXC("&from", "change tempo"), wxT(""), 12);
100
101 m_pTextCtrl_ToBPM = S.Id(ID_ToBPM)
102 /* i18n-hint: changing tempo "from" one value "to" another */
103 .Name(XO("Beats per minute, to"))
104 .Validator<FloatingPointValidator<double>>(
105 3, &m_ToBPM,
106 NumValidatorStyle::THREE_TRAILING_ZEROES
107 | NumValidatorStyle::ZERO_AS_BLANK)
108 /* i18n-hint: changing tempo "from" one value "to" another */
109 .AddTextBox(XXC("&to", "change tempo"), wxT(""), 12);
110 }
111 S.EndHorizontalLay();
112 }
113 S.EndStatic();
114
115 //
116 S.StartStatic(XO("Length (seconds)"));
117 {
118 S.StartHorizontalLay(wxALIGN_CENTER);
119 {
120 m_pTextCtrl_FromLength = S.Id(ID_FromLength)
121 .Disable() // Disable because the value comes from the
122 // user selection.
123 .Validator<FloatingPointValidator<double>>(
124 precision, &m_FromLength,
125 NumValidatorStyle::TWO_TRAILING_ZEROES)
126 /* i18n-hint: changing tempo "from" one value "to" another */
127 .AddTextBox(XXC("from", "change tempo"), wxT(""), 12);
128 m_pTextCtrl_ToLength = S.Id(ID_ToLength)
129 .Validator<FloatingPointValidator<double>>(
130 2, &m_ToLength, NumValidatorStyle::TWO_TRAILING_ZEROES,
131 // min and max need same precision as what we're validating (bug 963)
132 RoundValue( precision,
133 (m_FromLength * 100.0) / (100.0 + Percentage.max) ),
134 RoundValue( precision,
135 (m_FromLength * 100.0) / (100.0 + Percentage.min) ) )
136 /* i18n-hint: changing tempo "from" one value "to" another */
137 .AddTextBox(XXC("t&o", "change tempo"), wxT(""), 12);
138 }
139 S.EndHorizontalLay();
140 }
141 S.EndStatic();
142
143#if USE_SBSMS
144 S.StartMultiColumn(2);
145 {
146 mUseSBSMSCheckBox = S.Validator<wxGenericValidator>(&mUseSBSMS)
147 .AddCheckBox(XXO("&Use high quality stretching (slow)"),
148 mUseSBSMS);
149 }
150 S.EndMultiColumn();
151#endif
152
153 }
154 S.EndVerticalLay();
155
156 return nullptr;
157}
158
159bool EffectChangeTempo::TransferDataToWindow(const EffectSettings &)
160{
161 // Reset from length because it can be changed by Preview
162 m_FromLength = mT1 - mT0;
163
164 m_bLoopDetect = true;
165
166 if (!mUIParent->TransferDataToWindow())
167 {
168 return false;
169 }
170
171 // percent change controls
172 Update_Slider_PercentChange();
173 Update_Text_ToBPM();
174 Update_Text_ToLength();
175
176 m_bLoopDetect = false;
177
178 // Set the accessibility name here because we need m_pTextCtrl_FromLength to have had its value set
179 m_pTextCtrl_ToLength->SetName(
180 wxString::Format( _("Length in seconds from %s, to"),
181 m_pTextCtrl_FromLength->GetValue() ) );
182
183 return true;
184}
185
186bool EffectChangeTempo::TransferDataFromWindow(EffectSettings &)
187{
188 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
189 {
190 return false;
191 }
192
193 return true;
194}
195
196// handler implementations for EffectChangeTempo
197
198void EffectChangeTempo::OnText_PercentChange(wxCommandEvent & WXUNUSED(evt))
199{
200 if (m_bLoopDetect)
201 return;
202
203 m_pTextCtrl_PercentChange->GetValidator()->TransferFromWindow();
204
205 m_bLoopDetect = true;
206 Update_Slider_PercentChange();
207 Update_Text_ToBPM();
208 Update_Text_ToLength();
209 m_bLoopDetect = false;
210}
211
212void EffectChangeTempo::OnSlider_PercentChange(wxCommandEvent & WXUNUSED(evt))
213{
214 if (m_bLoopDetect)
215 return;
216
217 m_PercentChange = (double)(m_pSlider_PercentChange->GetValue());
218 // Warp positive values to actually go up faster & further than negatives.
219 if (m_PercentChange > 0.0)
220 m_PercentChange = pow(m_PercentChange, kSliderWarp);
221
222 m_bLoopDetect = true;
223 Update_Text_PercentChange();
224 Update_Text_ToBPM();
225 Update_Text_ToLength();
226 m_bLoopDetect = false;
227}
228
229void EffectChangeTempo::OnText_FromBPM(wxCommandEvent & WXUNUSED(evt))
230{
231 if (m_bLoopDetect)
232 return;
233
234 m_pTextCtrl_FromBPM->GetValidator()->TransferFromWindow();
235
236 m_bLoopDetect = true;
237
238 Update_Text_ToBPM();
239
240 m_bLoopDetect = false;
241}
242
243void EffectChangeTempo::OnText_ToBPM(wxCommandEvent & WXUNUSED(evt))
244{
245 if (m_bLoopDetect)
246 return;
247
248 m_pTextCtrl_ToBPM->GetValidator()->TransferFromWindow();
249
250 m_bLoopDetect = true;
251
252 // If FromBPM has already been set, then there's a NEW percent change.
253 if (m_FromBPM != 0.0 && m_ToBPM != 0.0)
254 {
255 m_PercentChange = ((m_ToBPM * 100.0) / m_FromBPM) - 100.0;
256
257 Update_Text_PercentChange();
258 Update_Slider_PercentChange();
259
260 Update_Text_ToLength();
261 }
262
263 m_bLoopDetect = false;
264}
265
266void EffectChangeTempo::OnText_ToLength(wxCommandEvent & WXUNUSED(evt))
267{
268 if (m_bLoopDetect)
269 return;
270
271 m_pTextCtrl_ToLength->GetValidator()->TransferFromWindow();
272
273 if (m_ToLength != 0.0)
274 {
275 m_PercentChange = ((m_FromLength * 100.0) / m_ToLength) - 100.0;
276 }
277
278 m_bLoopDetect = true;
279
280 Update_Text_PercentChange();
281 Update_Slider_PercentChange();
282
283 Update_Text_ToBPM();
284
285 m_bLoopDetect = false;
286}
287
288// helper fns
289
290void EffectChangeTempo::Update_Text_PercentChange()
291{
292 m_pTextCtrl_PercentChange->GetValidator()->TransferToWindow();
293}
294
295void EffectChangeTempo::Update_Slider_PercentChange()
296{
297 double unwarped = m_PercentChange;
298 if (unwarped > 0.0)
299 // Un-warp values above zero to actually go up to kSliderMax.
300 unwarped = pow(m_PercentChange, (1.0 / kSliderWarp));
301
302 // Add 0.5 to unwarped so trunc -> round.
303 m_pSlider_PercentChange->SetValue((int)(unwarped + 0.5));
304}
305
306void EffectChangeTempo::Update_Text_ToBPM()
307// Use m_FromBPM & m_PercentChange to set NEW m_ToBPM & control.
308{
309 m_ToBPM = (((m_FromBPM * (100.0 + m_PercentChange)) / 100.0));
310 m_pTextCtrl_ToBPM->GetValidator()->TransferToWindow();
311}
312
313void EffectChangeTempo::Update_Text_ToLength()
314// Use m_FromLength & m_PercentChange to set NEW m_ToLength & control.
315{
316 m_ToLength = (m_FromLength * 100.0) / (100.0 + m_PercentChange);
317 m_pTextCtrl_ToLength->GetValidator()->TransferToWindow();
318}
319
320#endif // USE_SOUNDTOUCH
wxT("CloseDown"))
END_EVENT_TABLE()
@ ID_ToLength
Definition: ChangeSpeed.cpp:37
@ ID_PercentChange
Definition: ChangeSpeed.cpp:33
static const double kSliderMax
Definition: ChangeSpeed.cpp:49
static const double kSliderWarp
Definition: ChangeSpeed.cpp:50
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define XXC(s, c)
Definition: Internat.h:47
#define _(s)
Definition: Internat.h:73
#define S(N)
Definition: ToChars.cpp:64
A SoundTouchBase provides speeding up or slowing down tempo without changing pitch.
Performs effect computation.
Hold values to send to effect output meters.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
A Validator is an object which checks whether a wxVariant satisfies a certain criterion....
Definition: Validators.h:54
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
STL namespace.
Externalized state of a plug-in.