Audacity 3.2.0
ToneGen.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ToneGen.cpp
6
7 Steve Jolly
8 James Crook (Adapted for 'Chirps')
9
10 This class implements a tone generator effect.
11
12*******************************************************************//*******************************************************************/
20#include "ToneGen.h"
21#include "EffectEditor.h"
22#include "LoadEffects.h"
23
24#include <math.h>
25
26#include <wx/choice.h>
27#include <wx/valgen.h>
28
29#include "Project.h"
30#include "ProjectRate.h"
31#include "ShuttleGui.h"
32#include "../widgets/valnum.h"
33#include "../widgets/NumericTextCtrl.h"
34
35const EnumValueSymbol EffectToneGen::kInterStrings[nInterpolations] =
36{
37 // These are acceptable dual purpose internal/visible names
38 { XO("Linear") },
39 { XO("Logarithmic") }
40};
41
43{
44 { XO("Sine") },
45 { XO("Square") },
46 { XO("Sawtooth") },
47 { XO("Square, no alias") },
48 { XC("Triangle", "waveform") }
49};
50
52{
53 static const auto postSet =
54 [](EffectToneGen &, EffectSettings &, EffectToneGen &e, bool updating) {
55 if (updating)
56 e.PostSet();
57 return true;
58 };
61 > chirpParameters{ postSet };
64 > toneParameters{ postSet };
65 if (mChirp)
66 return chirpParameters;
67 else
68 return toneParameters;
69}
70
71//
72// EffectToneGen
73//
74
76{ XO("Chirp") };
77
79
81{ XO("Tone") };
82
84
85BEGIN_EVENT_TABLE(EffectToneGen, wxEvtHandler)
86 EVT_TEXT(wxID_ANY, EffectToneGen::OnControlUpdate)
88
90 : mChirp{ isChirp }
91{
92 Parameters().Reset(*this);
93
94 wxASSERT(nWaveforms == WXSIZEOF(kWaveStrings));
95 wxASSERT(nInterpolations == WXSIZEOF(kInterStrings));
96
97 // Chirp varies over time so must use selected duration.
98 // TODO: When previewing, calculate only the first 'preview length'.
99 if (isChirp)
100 SetLinearEffectFlag(false);
101 else
102 SetLinearEffectFlag(true);
103}
104
106{
107}
108
109// ComponentInterface implementation
110
112{
113 return mChirp
116}
117
119{
120 return mChirp
121 ? XO("Generates an ascending or descending tone of one of four types")
122 : XO("Generates a constant frequency tone of one of four types");
123}
124
126{
127 return mChirp
128 ? L"Chirp"
129 : L"Tone";
130}
131
132// EffectDefinitionInterface implementation
133
135{
136 return EffectTypeGenerate;
137}
138
140{
141 return 1;
142}
143
145 EffectSettings &, double sampleRate, ChannelNames chanMap)
146{
148 mPositionInCycles = 0.0;
149 mSample = 0;
150 return true;
151}
152
154 const float *const *, float *const *outBlock, size_t blockLen)
155{
156 float *buffer = outBlock[0];
157 double throwaway = 0; //passed to modf but never used
158 double f = 0.0;
159 double a, b;
160 int k;
161
162 double frequencyQuantum;
163 double BlendedFrequency;
164 double BlendedAmplitude;
165 double BlendedLogFrequency = 0.0;
166
167 // calculate delta, and reposition from where we left
168 auto doubleSampleCount = mSampleCnt.as_double();
169 auto doubleSample = mSample.as_double();
170 double amplitudeQuantum =
171 (mAmplitude1 - mAmplitude0) / doubleSampleCount;
172 BlendedAmplitude = mAmplitude0 +
173 amplitudeQuantum * doubleSample;
174
175 // precalculations:
176 double pre2PI = 2.0 * M_PI;
177 double pre4divPI = 4.0 / M_PI;
178
179 // initial setup should calculate deltas
181 {
182 // this for log interpolation
183 mLogFrequency[0] = log10(mFrequency0);
184 mLogFrequency[1] = log10(mFrequency1);
185 // calculate delta, and reposition from where we left
186 frequencyQuantum = (mLogFrequency[1] - mLogFrequency[0]) / doubleSampleCount;
187 BlendedLogFrequency = mLogFrequency[0] + frequencyQuantum * doubleSample;
188 BlendedFrequency = pow(10.0, BlendedLogFrequency);
189 }
190 else
191 {
192 // this for regular case, linear interpolation
193 frequencyQuantum = (mFrequency1 - mFrequency0) / doubleSampleCount;
194 BlendedFrequency = mFrequency0 + frequencyQuantum * doubleSample;
195 }
196
197 // synth loop
198 for (decltype(blockLen) i = 0; i < blockLen; i++)
199 {
200 switch (mWaveform)
201 {
202 case kSine:
203 f = sin(pre2PI * mPositionInCycles / mSampleRate);
204 break;
205 case kSquare:
206 f = (modf(mPositionInCycles / mSampleRate, &throwaway) < 0.5) ? 1.0 : -1.0;
207 break;
208 case kSawtooth:
209 f = (2.0 * modf(mPositionInCycles / mSampleRate + 0.5, &throwaway)) - 1.0;
210 break;
211 case kTriangle:
212 f = modf(mPositionInCycles / mSampleRate, &throwaway);
213 if(f < 0.25) {
214 f *= 4.0;
215 } else if(f > 0.75) {
216 f = (f - 1.0) * 4.0;
217 } else { /* f >= 0.25 || f <= 0.75 */
218 f = (0.5 - f) * 4.0;
219 }
220 break;
221 case kSquareNoAlias: // Good down to 110Hz @ 44100Hz sampling.
222 //do fundamental (k=1) outside loop
223 b = (1.0 + cos((pre2PI * BlendedFrequency) / mSampleRate)) / pre4divPI; //scaling
224 f = pre4divPI * sin(pre2PI * mPositionInCycles / mSampleRate);
225 for (k = 3; (k < 200) && (k * BlendedFrequency < mSampleRate / 2.0); k += 2)
226 {
227 //Hann Window in freq domain
228 a = 1.0 + cos((pre2PI * k * BlendedFrequency) / mSampleRate);
229 //calc harmonic, apply window, scale to amplitude of fundamental
230 f += a * sin(pre2PI * mPositionInCycles / mSampleRate * k) / (b * k);
231 }
232 }
233 // insert value in buffer
234 buffer[i] = (float) (BlendedAmplitude * f);
235 // update freq,amplitude
236 mPositionInCycles += BlendedFrequency;
237 BlendedAmplitude += amplitudeQuantum;
239 {
240 BlendedLogFrequency += frequencyQuantum;
241 BlendedFrequency = pow(10.0, BlendedLogFrequency);
242 }
243 else
244 {
245 BlendedFrequency += frequencyQuantum;
246 }
247 }
248
249 // update external placeholder
250 mSample += blockLen;
251
252 return blockLen;
253}
254
256{
257 if (!mChirp) {
260 }
261// double freqMax =
262// (FindProject()
263// ? ProjectRate::Get( *FindProject() ).GetRate()
264// : 44100.0)
265// / 2.0;
266// mFrequency1 = std::clamp<double>(mFrequency1, EndFreq.min, freqMax);
267}
268
269// Effect implementation
270
271std::unique_ptr<EffectEditor> EffectToneGen::PopulateOrExchange(
273 const EffectOutputs *)
274{
275 mUIParent = S.GetParent();
276 wxTextCtrl *t;
277
278 S.StartMultiColumn(2, wxCENTER);
279 {
280 S.Validator<wxGenericValidator>(&mWaveform)
281 .AddChoice(XXO("&Waveform:"),
283
284 if (mChirp)
285 {
286 S.AddFixedText( {} );
287 S.StartHorizontalLay(wxEXPAND);
288 {
289 S.StartHorizontalLay(wxLEFT, 50);
290 {
291 S.AddTitle(XO("Start"));
292 }
293 S.EndHorizontalLay();
294
295 S.StartHorizontalLay(wxLEFT, 50);
296 {
297 S.AddTitle(XO("End"));
298 }
299 S.EndHorizontalLay();
300 }
301 S.EndHorizontalLay();
302
303 S.AddPrompt(XXO("&Frequency (Hz):"));
304 S.StartHorizontalLay(wxEXPAND);
305 {
306 S.StartHorizontalLay(wxLEFT, 50);
307 {
308 t = S.Name(XO("Frequency Hertz Start"))
309 .Validator<FloatingPointValidator<double>>(
310 6, &mFrequency0,
311 NumValidatorStyle::NO_TRAILING_ZEROES,
313 mProjectRate / 2.0 )
314 .AddTextBox( {}, L"", 12);
315 }
316 S.EndHorizontalLay();
317
318 S.StartHorizontalLay(wxLEFT, 50);
319 {
320 t = S.Name(XO("Frequency Hertz End"))
321 .Validator<FloatingPointValidator<double>>(
322 6, &mFrequency1,
323 NumValidatorStyle::NO_TRAILING_ZEROES,
324 EndFreq.min,
325 mProjectRate / 2.0 )
326 .AddTextBox( {}, L"", 12);
327 }
328 S.EndHorizontalLay();
329 }
330 S.EndHorizontalLay();
331
332 S.AddPrompt(XXO("&Amplitude (0-1):"));
333 S.StartHorizontalLay(wxEXPAND);
334 {
335 S.StartHorizontalLay(wxLEFT, 50);
336 {
337 t = S.Name(XO("Amplitude Start"))
338 .Validator<FloatingPointValidator<double>>(
339 6, &mAmplitude0, NumValidatorStyle::NO_TRAILING_ZEROES,
341 .AddTextBox( {}, L"", 12);
342 }
343 S.EndHorizontalLay();
344
345 S.StartHorizontalLay(wxLEFT, 50);
346 {
347 t = S.Name(XO("Amplitude End"))
348 .Validator<FloatingPointValidator<double>>(
349 6, &mAmplitude1, NumValidatorStyle::NO_TRAILING_ZEROES,
351 .AddTextBox( {}, L"", 12);
352 }
353 S.EndHorizontalLay();
354 }
355 S.EndHorizontalLay();
356
357 S.Validator<wxGenericValidator>(&mInterpolation)
358 .AddChoice(XXO("I&nterpolation:"),
360 }
361 else
362 {
363 t = S.Validator<FloatingPointValidator<double>>(
364 6, &mFrequency0, NumValidatorStyle::NO_TRAILING_ZEROES,
366 mProjectRate / 2.0 )
367 .AddTextBox(XXO("&Frequency (Hz):"), L"", 12);
368
369 t = S.Validator<FloatingPointValidator<double>>(
370 6, &mAmplitude0, NumValidatorStyle::NO_TRAILING_ZEROES,
372 .AddTextBox(XXO("&Amplitude (0-1):"), L"", 12);
373 }
374
375 S.AddPrompt(XXO("&Duration:"));
376 auto &extra = access.Get().extra;
379 S.GetParent(), wxID_ANY,
381 extra.GetDurationFormat(),
382 extra.GetDuration(),
384 .AutoPos(true));
385 S.Name(XO("Duration"))
386 .Position(wxALIGN_LEFT | wxALL)
387 .AddWindow(mToneDurationT);
388 }
389 S.EndMultiColumn();
390
391 return nullptr;
392}
393
395{
396 if (!mUIParent->TransferDataToWindow())
397 {
398 return false;
399 }
400
401 mToneDurationT->SetValue(settings.extra.GetDuration());
402 return true;
403}
404
406{
407 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
408 {
409 return false;
410 }
411
412 if (!mChirp)
413 {
416 }
417
418 settings.extra.SetDuration(mToneDurationT->GetValue());
419
420 return true;
421}
422
423// EffectToneGen implementation
424
425void EffectToneGen::OnControlUpdate(wxCommandEvent & WXUNUSED(evt))
426{
428 mUIParent, mUIParent->TransferDataFromWindow()))
429 {
430 return;
431 }
432}
#define M_PI
Definition: Distortion.cpp:30
EffectType
@ EffectTypeGenerate
ChannelName
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define XC(s, c)
Definition: Internat.h:37
#define safenew
Definition: MemoryX.h:9
const NumericConverterType & NumericConverterType_TIME()
an object holding per-project preferred sample rate
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
#define S(N)
Definition: ToChars.cpp:64
END_EVENT_TABLE()
static Settings & settings()
Definition: TrackInfo.cpp:69
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
double mProjectRate
Definition: EffectBase.h:112
static const ComponentInterfaceSymbol Symbol
Definition: ToneGen.h:132
static bool EnableApply(wxWindow *parent, bool enable=true)
Enable or disable the Apply button of the dialog that contains parent.
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
virtual const EffectSettings & Get()=0
An Effect that can generate a sine, square or sawtooth wave. An extended mode of EffectToneGen suppor...
Definition: ToneGen.h:25
double mPositionInCycles
Definition: ToneGen.h:70
int mInterpolation
Definition: ToneGen.h:75
TranslatableString GetDescription() const override
Definition: ToneGen.cpp:118
double mFrequency0
Definition: ToneGen.h:76
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
Definition: ToneGen.cpp:271
double mSampleRate
Definition: ToneGen.h:64
static constexpr EffectParameter Amplitude
Definition: ToneGen.h:121
ComponentInterfaceSymbol GetSymbol() const override
Definition: ToneGen.cpp:111
static constexpr EffectParameter Frequency
Definition: ToneGen.h:119
void OnControlUpdate(wxCommandEvent &evt)
Definition: ToneGen.cpp:425
bool ProcessInitialize(EffectSettings &settings, double sampleRate, ChannelNames chanMap) override
Definition: ToneGen.cpp:144
wxWeakRef< wxWindow > mUIParent
Definition: ToneGen.h:62
double mLogFrequency[2]
Definition: ToneGen.h:80
virtual ~EffectToneGen()
Definition: ToneGen.cpp:105
double mFrequency1
Definition: ToneGen.h:77
static const EnumValueSymbol kWaveStrings[nWaveforms]
Definition: ToneGen.h:99
@ kSquareNoAlias
Definition: ToneGen.h:94
double mAmplitude0
Definition: ToneGen.h:78
static constexpr EffectParameter EndFreq
Definition: ToneGen.h:113
@ nInterpolations
Definition: ToneGen.h:105
static const EnumValueSymbol kInterStrings[nInterpolations]
Definition: ToneGen.h:108
const EffectParameterMethods & Parameters() const override
Definition: ToneGen.cpp:51
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: ToneGen.cpp:125
void PostSet()
Definition: ToneGen.cpp:255
static constexpr EnumParameter Interp
Definition: ToneGen.h:125
NumericTextCtrl * mToneDurationT
Definition: ToneGen.h:82
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: ToneGen.cpp:394
static constexpr EnumParameter Waveform
Definition: ToneGen.h:123
EffectType GetType() const override
Type determines how it behaves.
Definition: ToneGen.cpp:134
double mAmplitude1
Definition: ToneGen.h:79
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: ToneGen.cpp:139
EffectToneGen(bool isChirp)
Definition: ToneGen.cpp:89
int mWaveform
Definition: ToneGen.h:74
static constexpr EffectParameter StartFreq
Definition: ToneGen.h:111
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: ToneGen.cpp:153
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: ToneGen.cpp:405
static constexpr EffectParameter StartAmp
Definition: ToneGen.h:115
const bool mChirp
Definition: ToneGen.h:65
sampleCount mSample
Definition: ToneGen.h:69
static constexpr EffectParameter EndAmp
Definition: ToneGen.h:117
static const ComponentInterfaceSymbol Symbol
Definition: ToneGen.h:141
static FormatterContext SampleRateContext(double sampleRate)
void SetValue(double newValue)
sampleCount mSampleCnt
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
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....
Definition: Validators.h:54
double as_double() const
Definition: SampleCount.h:46
BuiltinEffectsModule::Registration< EffectTone > reg2
Definition: ToneGen.cpp:83
BuiltinEffectsModule::Registration< EffectChirp > reg
Definition: ToneGen.cpp:78
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.
EffectSettingsExtra extra
Options & AutoPos(bool enable)