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
21
22#include "ToneGen.h"
23#include "LoadEffects.h"
24
25#include <math.h>
26
27#include <wx/choice.h>
28#include <wx/intl.h>
29#include <wx/valgen.h>
30
31#include "Project.h"
32#include "ProjectRate.h"
33#include "../ShuttleGui.h"
34#include "../widgets/valnum.h"
35#include "../widgets/NumericTextCtrl.h"
36
37const EnumValueSymbol EffectToneGen::kInterStrings[nInterpolations] =
38{
39 // These are acceptable dual purpose internal/visible names
40 { XO("Linear") },
41 { XO("Logarithmic") }
42};
43
45{
46 { XO("Sine") },
47 { XO("Square") },
48 { XO("Sawtooth") },
49 { XO("Square, no alias") },
50 { XC("Triangle", "waveform") }
51};
52
54{
55 static const auto postSet =
56 [](EffectToneGen &, EffectSettings &, EffectToneGen &e, bool updating) {
57 if (updating)
58 e.PostSet();
59 return true;
60 };
63 > chirpParameters{ postSet };
66 > toneParameters{ postSet };
67 if (mChirp)
68 return chirpParameters;
69 else
70 return toneParameters;
71}
72
73//
74// EffectToneGen
75//
76
78{ XO("Chirp") };
79
81
83{ XO("Tone") };
84
86
87BEGIN_EVENT_TABLE(EffectToneGen, wxEvtHandler)
88 EVT_TEXT(wxID_ANY, EffectToneGen::OnControlUpdate)
90
92 : mChirp{ isChirp }
93{
94 Parameters().Reset(*this);
95
96 wxASSERT(nWaveforms == WXSIZEOF(kWaveStrings));
97 wxASSERT(nInterpolations == WXSIZEOF(kInterStrings));
98
99 // Chirp varies over time so must use selected duration.
100 // TODO: When previewing, calculate only the first 'preview length'.
101 if (isChirp)
102 SetLinearEffectFlag(false);
103 else
104 SetLinearEffectFlag(true);
105}
106
108{
109}
110
111// ComponentInterface implementation
112
114{
115 return mChirp
118}
119
121{
122 return mChirp
123 ? XO("Generates an ascending or descending tone of one of four types")
124 : XO("Generates a constant frequency tone of one of four types");
125}
126
128{
129 return mChirp
130 ? L"Chirp"
131 : L"Tone";
132}
133
134// EffectDefinitionInterface implementation
135
137{
138 return EffectTypeGenerate;
139}
140
142{
143 return 1;
144}
145
147 EffectSettings &, double sampleRate, sampleCount, ChannelNames chanMap)
148{
149 mSampleRate = sampleRate;
150 mPositionInCycles = 0.0;
151 mSample = 0;
152 return true;
153}
154
156 const float *const *, float *const *outBlock, size_t blockLen)
157{
158 float *buffer = outBlock[0];
159 double throwaway = 0; //passed to modf but never used
160 double f = 0.0;
161 double a, b;
162 int k;
163
164 double frequencyQuantum;
165 double BlendedFrequency;
166 double BlendedAmplitude;
167 double BlendedLogFrequency = 0.0;
168
169 // calculate delta, and reposition from where we left
170 auto doubleSampleCount = mSampleCnt.as_double();
171 auto doubleSample = mSample.as_double();
172 double amplitudeQuantum =
173 (mAmplitude1 - mAmplitude0) / doubleSampleCount;
174 BlendedAmplitude = mAmplitude0 +
175 amplitudeQuantum * doubleSample;
176
177 // precalculations:
178 double pre2PI = 2.0 * M_PI;
179 double pre4divPI = 4.0 / M_PI;
180
181 // initial setup should calculate deltas
183 {
184 // this for log interpolation
185 mLogFrequency[0] = log10(mFrequency0);
186 mLogFrequency[1] = log10(mFrequency1);
187 // calculate delta, and reposition from where we left
188 frequencyQuantum = (mLogFrequency[1] - mLogFrequency[0]) / doubleSampleCount;
189 BlendedLogFrequency = mLogFrequency[0] + frequencyQuantum * doubleSample;
190 BlendedFrequency = pow(10.0, BlendedLogFrequency);
191 }
192 else
193 {
194 // this for regular case, linear interpolation
195 frequencyQuantum = (mFrequency1 - mFrequency0) / doubleSampleCount;
196 BlendedFrequency = mFrequency0 + frequencyQuantum * doubleSample;
197 }
198
199 // synth loop
200 for (decltype(blockLen) i = 0; i < blockLen; i++)
201 {
202 switch (mWaveform)
203 {
204 case kSine:
205 f = sin(pre2PI * mPositionInCycles / mSampleRate);
206 break;
207 case kSquare:
208 f = (modf(mPositionInCycles / mSampleRate, &throwaway) < 0.5) ? 1.0 : -1.0;
209 break;
210 case kSawtooth:
211 f = (2.0 * modf(mPositionInCycles / mSampleRate + 0.5, &throwaway)) - 1.0;
212 break;
213 case kTriangle:
214 f = modf(mPositionInCycles / mSampleRate, &throwaway);
215 if(f < 0.25) {
216 f *= 4.0;
217 } else if(f > 0.75) {
218 f = (f - 1.0) * 4.0;
219 } else { /* f >= 0.25 || f <= 0.75 */
220 f = (0.5 - f) * 4.0;
221 }
222 break;
223 case kSquareNoAlias: // Good down to 110Hz @ 44100Hz sampling.
224 //do fundamental (k=1) outside loop
225 b = (1.0 + cos((pre2PI * BlendedFrequency) / mSampleRate)) / pre4divPI; //scaling
226 f = pre4divPI * sin(pre2PI * mPositionInCycles / mSampleRate);
227 for (k = 3; (k < 200) && (k * BlendedFrequency < mSampleRate / 2.0); k += 2)
228 {
229 //Hann Window in freq domain
230 a = 1.0 + cos((pre2PI * k * BlendedFrequency) / mSampleRate);
231 //calc harmonic, apply window, scale to amplitude of fundamental
232 f += a * sin(pre2PI * mPositionInCycles / mSampleRate * k) / (b * k);
233 }
234 }
235 // insert value in buffer
236 buffer[i] = (float) (BlendedAmplitude * f);
237 // update freq,amplitude
238 mPositionInCycles += BlendedFrequency;
239 BlendedAmplitude += amplitudeQuantum;
241 {
242 BlendedLogFrequency += frequencyQuantum;
243 BlendedFrequency = pow(10.0, BlendedLogFrequency);
244 }
245 else
246 {
247 BlendedFrequency += frequencyQuantum;
248 }
249 }
250
251 // update external placeholder
252 mSample += blockLen;
253
254 return blockLen;
255}
256
258{
259 if (!mChirp) {
262 }
263// double freqMax =
264// (FindProject()
265// ? ProjectRate::Get( *FindProject() ).GetRate()
266// : 44100.0)
267// / 2.0;
268// mFrequency1 = std::clamp<double>(mFrequency1, EndFreq.min, freqMax);
269}
270
271// Effect implementation
272
273std::unique_ptr<EffectUIValidator> EffectToneGen::PopulateOrExchange(
275{
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;
378 NumericTextCtrl(S.GetParent(), wxID_ANY,
380 extra.GetDurationFormat(),
381 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 mToneDurationT->SetValue(settings.extra.GetDuration());
397 return true;
398}
399
401{
402 if (!mChirp)
403 {
406 }
407
408 settings.extra.SetDuration(mToneDurationT->GetValue());
409
410 return true;
411}
412
413// EffectToneGen implementation
414
415void EffectToneGen::OnControlUpdate(wxCommandEvent & WXUNUSED(evt))
416{
417 if (!EnableApply(mUIParent->TransferDataFromWindow()))
418 {
419 return;
420 }
421}
#define M_PI
Definition: Distortion.cpp:29
EffectType
@ EffectTypeGenerate
enum ChannelName * ChannelNames
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define XC(s, c)
Definition: Internat.h:37
#define safenew
Definition: MemoryX.h:10
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:87
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
double mProjectRate
Definition: EffectBase.h:99
static const ComponentInterfaceSymbol Symbol
Definition: ToneGen.h:129
bool EnableApply(bool enable=true)
Definition: Effect.cpp:613
wxWindow * mUIParent
Definition: Effect.h:270
Performs effect computation.
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:24
double mPositionInCycles
Definition: ToneGen.h:67
int mInterpolation
Definition: ToneGen.h:72
TranslatableString GetDescription() const override
Definition: ToneGen.cpp:120
double mFrequency0
Definition: ToneGen.h:73
double mSampleRate
Definition: ToneGen.h:61
static constexpr EffectParameter Amplitude
Definition: ToneGen.h:118
ComponentInterfaceSymbol GetSymbol() const override
Definition: ToneGen.cpp:113
static constexpr EffectParameter Frequency
Definition: ToneGen.h:116
void OnControlUpdate(wxCommandEvent &evt)
Definition: ToneGen.cpp:415
double mLogFrequency[2]
Definition: ToneGen.h:77
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
Definition: ToneGen.cpp:273
virtual ~EffectToneGen()
Definition: ToneGen.cpp:107
double mFrequency1
Definition: ToneGen.h:74
static const EnumValueSymbol kWaveStrings[nWaveforms]
Definition: ToneGen.h:96
@ kSquareNoAlias
Definition: ToneGen.h:91
double mAmplitude0
Definition: ToneGen.h:75
static constexpr EffectParameter EndFreq
Definition: ToneGen.h:110
@ nInterpolations
Definition: ToneGen.h:102
static const EnumValueSymbol kInterStrings[nInterpolations]
Definition: ToneGen.h:105
const EffectParameterMethods & Parameters() const override
Definition: ToneGen.cpp:53
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: ToneGen.cpp:127
void PostSet()
Definition: ToneGen.cpp:257
static constexpr EnumParameter Interp
Definition: ToneGen.h:122
NumericTextCtrl * mToneDurationT
Definition: ToneGen.h:79
bool TransferDataToWindow(const EffectSettings &settings) override
Update controls for the settings.
Definition: ToneGen.cpp:394
static constexpr EnumParameter Waveform
Definition: ToneGen.h:120
EffectType GetType() const override
Type determines how it behaves.
Definition: ToneGen.cpp:136
double mAmplitude1
Definition: ToneGen.h:76
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: ToneGen.cpp:141
EffectToneGen(bool isChirp)
Definition: ToneGen.cpp:91
bool ProcessInitialize(EffectSettings &settings, double sampleRate, sampleCount totalLen, ChannelNames chanMap) override
Definition: ToneGen.cpp:146
int mWaveform
Definition: ToneGen.h:71
static constexpr EffectParameter StartFreq
Definition: ToneGen.h:108
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: ToneGen.cpp:155
bool TransferDataFromWindow(EffectSettings &settings) override
Update the given settings from controls.
Definition: ToneGen.cpp:400
static constexpr EffectParameter StartAmp
Definition: ToneGen.h:112
const bool mChirp
Definition: ToneGen.h:62
sampleCount mSample
Definition: ToneGen.h:66
static constexpr EffectParameter EndAmp
Definition: ToneGen.h:114
static const ComponentInterfaceSymbol Symbol
Definition: ToneGen.h:138
void SetValue(double newValue)
sampleCount mSampleCnt
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
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:53
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
double as_double() const
Definition: SampleCount.h:45
BuiltinEffectsModule::Registration< EffectTone > reg2
Definition: ToneGen.cpp:85
BuiltinEffectsModule::Registration< EffectChirp > reg
Definition: ToneGen.cpp:80
const Type min
Minimum value.
Definition: Shuttle.h:30
const Type max
Maximum value.
Definition: Shuttle.h:31
Externalized state of a plug-in.
EffectSettingsExtra extra
Options & AutoPos(bool enable)