Audacity  2.2.2
DtmfGen.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  DtmfGen.cpp
6 
7  Salvo Ventura - Dec 2006
8 
9 *******************************************************************//*******************************************************************/
15 
16 #include "../Audacity.h"
17 #include "../Experimental.h"
18 #include "DtmfGen.h"
19 
20 #include <wx/intl.h>
21 #include <wx/valgen.h>
22 #include <wx/valtext.h>
23 
24 #include "../Prefs.h"
25 #include "../ShuttleGui.h"
26 #include "../widgets/valnum.h"
27 
28 
29 enum
30 {
35 };
36 
37 // DA: DTMF for Audacity uses a different string.
38 #ifdef EXPERIMENTAL_DA
39 #define SHORT_APP_NAME "darkaudacity"
40 #else
41 #define SHORT_APP_NAME "audacity"
42 #endif
43 
44 // Define keys, defaults, minimums, and maximums for the effect parameters
45 //
46 // Name Type Key Def Min Max Scale
47 Param( Sequence, wxString, wxT("Sequence"), wxT(SHORT_APP_NAME), wxT(""), wxT(""), wxT(""));
48 Param( DutyCycle, double, wxT("Duty Cycle"), 55.0, 0.0, 100.0, 10.0 );
49 Param( Amplitude, double, wxT("Amplitude"), 0.8, 0.001, 1.0, 1 );
50 
51 static const double kFadeInOut = 250.0; // used for fadein/out needed to remove clicking noise
52 
53 const static wxChar *kSymbols[] =
54 {
55  wxT("0"), wxT("1"), wxT("2"), wxT("3"),
56  wxT("4"), wxT("5"), wxT("6"), wxT("7"),
57  wxT("8"), wxT("9"), wxT("*"), wxT("#"),
58  wxT("A"), wxT("B"), wxT("C"), wxT("D"),
59  wxT("a"), wxT("b"), wxT("c"), wxT("d"),
60  wxT("e"), wxT("f"), wxT("g"), wxT("h"),
61  wxT("i"), wxT("j"), wxT("k"), wxT("l"),
62  wxT("m"), wxT("n"), wxT("o"), wxT("p"),
63  wxT("q"), wxT("r"), wxT("s"), wxT("t"),
64  wxT("u"), wxT("v"), wxT("w"), wxT("x"),
65  wxT("y"), wxT("z")
66 };
67 
68 //
69 // EffectDtmf
70 //
71 
72 BEGIN_EVENT_TABLE(EffectDtmf, wxEvtHandler)
73  EVT_TEXT(ID_Sequence, EffectDtmf::OnSequence)
74  EVT_TEXT(ID_DutyCycle, EffectDtmf::OnAmplitude)
75  EVT_TEXT(ID_Duration, EffectDtmf::OnDuration)
76  EVT_SLIDER(ID_DutyCycle, EffectDtmf::OnDutyCycle)
78 
80 {
81  dtmfDutyCycle = DEF_DutyCycle;
82  dtmfAmplitude = DEF_Amplitude;
83  dtmfSequence = DEF_Sequence;
84  dtmfTone = 0.0;
85  dtmfSilence = 0.0;
86 }
87 
89 {
90 }
91 
92 // IdentInterface implementation
93 
95 {
97 }
98 
100 {
101  return _("Generates dual-tone multi-frequency (DTMF) tones like those produced by the keypad on telephones");
102 }
103 
105 {
106  return wxT("DTMF_Tones");
107 }
108 
109 // EffectIdentInterface implementation
110 
112 {
113  return EffectTypeGenerate;
114 }
115 
116 // EffectClientInterface implementation
117 
119 {
120  return 1;
121 }
122 
123 bool EffectDtmf::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
124 {
125  double duration = GetDuration();
126 
127  // all dtmf sequence durations in samples from seconds
128  // MJS: Note that mDuration is in seconds but will have been quantised to the units of the TTC.
129  // If this was 'samples' and the project rate was lower than the track rate,
130  // extra samples may get created as mDuration may now be > mT1 - mT0;
131  // However we are making our best efforts at creating what was asked for.
132 
133  auto nT0 = (sampleCount)floor(mT0 * mSampleRate + 0.5);
134  auto nT1 = (sampleCount)floor((mT0 + duration) * mSampleRate + 0.5);
135  numSamplesSequence = nT1 - nT0; // needs to be exact number of samples selected
136 
137  //make under-estimates if anything, and then redistribute the few remaining samples
138  numSamplesTone = sampleCount( floor(dtmfTone * mSampleRate) );
139  numSamplesSilence = sampleCount( floor(dtmfSilence * mSampleRate) );
140 
141  // recalculate the sum, and spread the difference - due to approximations.
142  // Since diff should be in the order of "some" samples, a division (resulting in zero)
143  // is not sufficient, so we add the additional remaining samples in each tone/silence block,
144  // at least until available.
146  while (diff > 2*dtmfNTones - 1) { // more than one per thingToBeGenerated
147  // in this case, both numSamplesTone and numSamplesSilence would change, so it makes sense
148  // to recalculate diff here, otherwise just keep the value we already have
149 
150  // should always be the case that dtmfNTones>1, as if 0, we don't even start processing,
151  // and with 1 there is no difference to spread (no silence slot)...
152  wxASSERT(dtmfNTones > 1);
156  }
157  wxASSERT(diff >= 0); // should never be negative
158 
159  curSeqPos = -1; // pointer to string in dtmfSequence
160  isTone = false;
161  numRemaining = 0;
162 
163  return true;
164 }
165 
166 size_t EffectDtmf::ProcessBlock(float **WXUNUSED(inbuf), float **outbuf, size_t size)
167 {
168  float *buffer = outbuf[0];
169  decltype(size) processed = 0;
170 
171  // for the whole dtmf sequence, we will be generating either tone or silence
172  // according to a bool value, and this might be done in small chunks of size
173  // 'block', as a single tone might sometimes be larger than the block
174  // tone and silence generally have different duration, thus two generation blocks
175  //
176  // Note: to overcome a 'clicking' noise introduced by the abrupt transition from/to
177  // silence, I added a fade in/out of 1/250th of a second (4ms). This can still be
178  // tweaked but gives excellent results at 44.1kHz: I haven't tried other freqs.
179  // A problem might be if the tone duration is very short (<10ms)... (?)
180  //
181  // One more problem is to deal with the approximations done when calculating the duration
182  // of both tone and silence: in some cases the final sum might not be same as the initial
183  // duration. So, to overcome this, we had a redistribution block up, and now we will spread
184  // the remaining samples in every bin in order to achieve the full duration: test case was
185  // to generate an 11 tone DTMF sequence, in 4 seconds, and with DutyCycle=75%: after generation
186  // you ended up with 3.999s or in other units: 3 seconds and 44097 samples.
187  //
188  while (size)
189  {
190  if (numRemaining == 0)
191  {
192  isTone = !isTone;
193 
194  if (isTone)
195  {
196  curSeqPos++;
198  curTonePos = 0;
199  }
200  else
201  {
203  }
204 
205  // the statement takes care of extracting one sample from the diff bin and
206  // adding it into the current block until depletion
207  numRemaining += (diff-- > 0 ? 1 : 0);
208  }
209 
210  const auto len = limitSampleBufferSize( size, numRemaining );
211 
212  if (isTone)
213  {
214  // generate the tone and append
216  curTonePos += len;
217  }
218  else
219  {
220  memset(buffer, 0, sizeof(float) * len);
221  }
222 
223  numRemaining -= len;
224 
225  buffer += len;
226  size -= len;
227  processed += len;
228  }
229 
230  return processed;
231 }
232 
233 bool EffectDtmf::GetAutomationParameters(EffectAutomationParameters & parms)
234 {
235  parms.Write(KEY_Sequence, dtmfSequence);
236  parms.Write(KEY_DutyCycle, dtmfDutyCycle);
237  parms.Write(KEY_Amplitude, dtmfAmplitude);
238 
239  return true;
240 }
241 
242 bool EffectDtmf::SetAutomationParameters(EffectAutomationParameters & parms)
243 {
244  ReadAndVerifyDouble(DutyCycle);
245  ReadAndVerifyDouble(Amplitude);
247 
248  wxString symbols;
249  for (unsigned int i = 0; i < WXSIZEOF(kSymbols); i++)
250  {
251  symbols += kSymbols[i];
252  }
253 
254  if (Sequence.find_first_not_of(symbols) != wxString::npos)
255  {
256  return false;
257  }
258 
259  dtmfDutyCycle = DutyCycle;
260  dtmfAmplitude = Amplitude;
262 
263  Recalculate();
264 
265  return true;
266 }
267 
268 // Effect implementation
269 
271 {
272  wxString base = wxT("/Effects/DtmfGen/");
273 
274  // Migrate settings from 2.1.0 or before
275 
276  // Already migrated, so bail
277  if (gPrefs->Exists(base + wxT("Migrated")))
278  {
279  return true;
280  }
281 
282  // Load the old "current" settings
283  if (gPrefs->Exists(base))
284  {
285  gPrefs->Read(base + wxT("String"), &dtmfSequence, wxT(SHORT_APP_NAME));
286  gPrefs->Read(base + wxT("DutyCycle"), &dtmfDutyCycle, 550L);
287  gPrefs->Read(base + wxT("Amplitude"), &dtmfAmplitude, 0.8f);
288 
290 
291  // Do not migrate again
292  gPrefs->Write(base + wxT("Migrated"), true);
293  gPrefs->Flush();
294  }
295 
296  return true;
297 }
298 
300 {
301  Recalculate();
302 
303  return true;
304 }
305 
307 {
308  // dialog will be passed values from effect
309  // Effect retrieves values from saved config
310  // Dialog will take care of using them to initialize controls
311  // If there is a selection, use that duration, otherwise use
312  // value from saved config: this is useful is user wants to
313  // replace selection with dtmf sequence
314 
315  S.AddSpace(0, 5);
316  S.StartMultiColumn(2, wxCENTER);
317  {
318  wxTextValidator vldDtmf(wxFILTER_INCLUDE_CHAR_LIST, &dtmfSequence);
319  vldDtmf.SetIncludes(wxArrayString(WXSIZEOF(kSymbols), kSymbols));
320  mDtmfSequenceT = S.Id(ID_Sequence).AddTextBox(_("DTMF sequence:"), wxT(""), 10);
321  mDtmfSequenceT->SetValidator(vldDtmf);
322 
323  FloatingPointValidator<double> vldAmp(3, &dtmfAmplitude, NUM_VAL_NO_TRAILING_ZEROES);
324  vldAmp.SetRange(MIN_Amplitude, MAX_Amplitude);
325  S.Id(ID_Amplitude).AddTextBox(_("Amplitude (0-1):"), wxT(""), 10)->SetValidator(vldAmp);
326 
327  S.AddPrompt(_("Duration:"));
330  S.GetParent(),
331  ID_Duration,
333  GetDuration(),
334  mProjectRate,
335  wxDefaultPosition,
336  wxDefaultSize,
337  true);
338  mDtmfDurationT->SetName(_("Duration"));
341 
342  S.AddFixedText(_("Tone/silence ratio:"), false);
343  S.SetStyle(wxSL_HORIZONTAL | wxEXPAND);
345  dtmfDutyCycle * SCL_DutyCycle,
346  MAX_DutyCycle * SCL_DutyCycle,
347  MIN_DutyCycle * SCL_DutyCycle);
348  S.SetSizeHints(-1,-1);
349  }
350  S.EndMultiColumn();
351 
352  S.StartMultiColumn(2, wxCENTER);
353  {
354  S.AddFixedText(_("Duty cycle:"), false);
355  mDtmfDutyT = S.AddVariableText(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle), false);
356 
357  S.AddFixedText(_("Tone duration:"), false);
358  mDtmfSilenceT = S.AddVariableText(wxString::Format(wxString(wxT("%.0f ")) + _("ms"), dtmfTone * 1000.0), false);
359 
360  S.AddFixedText(_("Silence duration:"), false);
361  mDtmfToneT = S.AddVariableText(wxString::Format(wxString(wxT("%0.f ")) + _("ms"), dtmfSilence * 1000.0), false);
362  }
363  S.EndMultiColumn();
364 }
365 
367 {
368  Recalculate();
369 
370  if (!mUIParent->TransferDataToWindow())
371  {
372  return false;
373  }
374 
375  mDtmfDutyCycleS->SetValue(dtmfDutyCycle * SCL_DutyCycle);
376 
378 
379  UpdateUI();
380 
381  return true;
382 }
383 
385 {
386  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
387  {
388  return false;
389  }
390 
391  dtmfDutyCycle = (double) mDtmfDutyCycleS->GetValue() / SCL_DutyCycle;
393 
394  // recalculate to make sure all values are up-to-date. This is especially
395  // important if the user did not change any values in the dialog
396  Recalculate();
397 
398  return true;
399 }
400 
401 // EffectDtmf implementation
402 
404 {
405  // remember that dtmfDutyCycle is in range (0.0-100.0)
406 
407  dtmfNTones = (int) dtmfSequence.Length();
408 
409  if (dtmfNTones==0) {
410  // no tones, all zero: don't do anything
411  // this should take care of the case where user got an empty
412  // dtmf sequence into the generator: track won't be generated
413  SetDuration(0.0);
414  dtmfTone = 0;
415  dtmfSilence = 0;
416  } else {
417  if (dtmfNTones==1) {
418  // single tone, as long as the sequence
419  dtmfTone = GetDuration();
420  dtmfSilence = 0;
421  } else {
422  // Don't be fooled by the fact that you divide the sequence into dtmfNTones:
423  // the last slot will only contain a tone, not ending with silence.
424  // Given this, the right thing to do is to divide the sequence duration
425  // by dtmfNTones tones and (dtmfNTones-1) silences each sized according to the duty
426  // cycle: original division was:
427  // slot=mDuration / (dtmfNTones*(dtmfDutyCycle/MAX_DutyCycle)+(dtmfNTones-1)*(1.0-dtmfDutyCycle/MAX_DutyCycle))
428  // which can be simplified in the one below.
429  // Then just take the part that belongs to tone or silence.
430  //
431  double slot = GetDuration() / ((double)dtmfNTones + (dtmfDutyCycle / 100.0) - 1);
432  dtmfTone = slot * (dtmfDutyCycle / 100.0); // seconds
433  dtmfSilence = slot * (1.0 - (dtmfDutyCycle / 100.0)); // seconds
434 
435  // Note that in the extremes we have:
436  // - dutyCycle=100%, this means no silence, so each tone will measure mDuration/dtmfNTones
437  // - dutyCycle=0%, this means no tones, so each silence slot will measure mDuration/(NTones-1)
438  // But we always count:
439  // - dtmfNTones tones
440  // - dtmfNTones-1 silences
441  }
442  }
443 }
444 
445 bool EffectDtmf::MakeDtmfTone(float *buffer, size_t len, float fs, wxChar tone, sampleCount last, sampleCount total, float amplitude)
446 {
447 /*
448  --------------------------------------------
449  1209 Hz 1336 Hz 1477 Hz 1633 Hz
450 
451  ABC DEF
452  697 Hz 1 2 3 A
453 
454  GHI JKL MNO
455  770 Hz 4 5 6 B
456 
457  PQRS TUV WXYZ
458  852 Hz 7 8 9 C
459 
460  oper
461  941 Hz * 0 # D
462  --------------------------------------------
463  Essentially we need to generate two sin with
464  frequencies according to this table, and sum
465  them up.
466  sin wave is generated by:
467  s(n)=sin(2*pi*n*f/fs)
468 
469  We will precalculate:
470  A= 2*pi*f1/fs
471  B= 2*pi*f2/fs
472 
473  And use two switch statements to select the frequency
474 
475  Note: added support for letters, like those on the keypad
476  This support is only for lowercase letters: uppercase
477  are still considered to be the 'military'/carrier extra
478  tones.
479 */
480 
481  float f1, f2=0.0;
482  double A,B;
483 
484  // select low tone: left column
485  switch (tone) {
486  case '1': case '2': case '3': case 'A':
487  case 'a': case 'b': case 'c':
488  case 'd': case 'e': case 'f':
489  f1=697;
490  break;
491  case '4': case '5': case '6': case 'B':
492  case 'g': case 'h': case 'i':
493  case 'j': case 'k': case 'l':
494  case 'm': case 'n': case 'o':
495  f1=770;
496  break;
497  case '7': case '8': case '9': case 'C':
498  case 'p': case 'q': case 'r': case 's':
499  case 't': case 'u': case 'v':
500  case 'w': case 'x': case 'y': case 'z':
501  f1=852;
502  break;
503  case '*': case '0': case '#': case 'D':
504  f1=941;
505  break;
506  default:
507  f1=0;
508  }
509 
510  // select high tone: top row
511  switch (tone) {
512  case '1': case '4': case '7': case '*':
513  case 'g': case 'h': case 'i':
514  case 'p': case 'q': case 'r': case 's':
515  f2=1209;
516  break;
517  case '2': case '5': case '8': case '0':
518  case 'a': case 'b': case 'c':
519  case 'j': case 'k': case 'l':
520  case 't': case 'u': case 'v':
521  f2=1336;
522  break;
523  case '3': case '6': case '9': case '#':
524  case 'd': case 'e': case 'f':
525  case 'm': case 'n': case 'o':
526  case 'w': case 'x': case 'y': case 'z':
527  f2=1477;
528  break;
529  case 'A': case 'B': case 'C': case 'D':
530  f2=1633;
531  break;
532  default:
533  f2=0;
534  }
535 
536  // precalculations
537  A=B=2*M_PI/fs;
538  A*=f1;
539  B*=f2;
540 
541  // now generate the wave: 'last' is used to avoid phase errors
542  // when inside the inner for loop of the Process() function.
543  for(decltype(len) i = 0; i < len; i++) {
544  buffer[i] = amplitude * 0.5 *
545  (sin( A * (i + last).as_double() ) +
546  sin( B * (i + last).as_double() ));
547  }
548 
549  // generate a fade-in of duration 1/250th of second
550  if (last == 0) {
551  A = (fs / kFadeInOut);
552  for(size_t i = 0; i < A; i++) {
553  buffer[i] *= i/A;
554  }
555  }
556 
557  // generate a fade-out of duration 1/250th of second
558  if (last == total - len) {
559  // we are at the last buffer of 'len' size, so, offset is to
560  // backup 'A' samples, from 'len'
561  A = (fs / kFadeInOut);
562  auto offset = long(len) - long(fs / kFadeInOut);
563  // protect against negative offset, which can occur if too a
564  // small selection is made
565  if (offset >= 0) {
566  for(size_t i = 0; i < A; i++) {
567  buffer[i + offset] *= (1 - (i / A));
568  }
569  }
570  }
571  return true;
572 }
573 
575 {
576  mDtmfDutyT->SetLabel(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle));
577  mDtmfDutyT->SetName(mDtmfDutyT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
578 
579  mDtmfSilenceT->SetLabel(wxString::Format(_("%.0f ms"), dtmfTone * 1000.0));
580  mDtmfSilenceT->SetName(mDtmfSilenceT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
581 
582  mDtmfToneT->SetLabel(wxString::Format(_("%.0f ms"), dtmfSilence * 1000.0));
583  mDtmfToneT->SetName(mDtmfToneT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
584 }
585 
586 void EffectDtmf::OnSequence(wxCommandEvent & WXUNUSED(evt))
587 {
588  dtmfSequence = mDtmfSequenceT->GetValue();
589  Recalculate();
590  UpdateUI();
591 }
592 
593 void EffectDtmf::OnAmplitude(wxCommandEvent & WXUNUSED(evt))
594 {
595  if (!mDtmfAmplitudeT->GetValidator()->TransferFromWindow())
596  {
597  return;
598  }
599  Recalculate();
600  UpdateUI();
601 }
602 void EffectDtmf::OnDuration(wxCommandEvent & WXUNUSED(evt))
603 {
605  Recalculate();
606  UpdateUI();
607 }
608 
609 void EffectDtmf::OnDutyCycle(wxCommandEvent & evt)
610 {
611  dtmfDutyCycle = (double) evt.GetInt() / SCL_DutyCycle;
612  Recalculate();
613  UpdateUI();
614 }
#define SHORT_APP_NAME
Definition: DtmfGen.cpp:41
void OnAmplitude(wxCommandEvent &evt)
Definition: DtmfGen.cpp:593
wxStaticText * mDtmfToneT
Definition: DtmfGen.h:98
bool SaveUserPreset(const wxString &name) override
Definition: Effect.cpp:615
wxString GetSymbol() override
Definition: DtmfGen.cpp:94
static const wxChar * kSymbols[]
Definition: DtmfGen.cpp:53
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
double GetDuration() override
Definition: Effect.cpp:737
bool GetAutomationParameters(EffectAutomationParameters &parms) override
Definition: DtmfGen.cpp:233
wxString GetCurrentSettingsGroup() override
Definition: Effect.cpp:814
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:257
wxString GetDurationFormat() override
Definition: Effect.cpp:747
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:55
wxStaticText * mDtmfDutyT
Definition: DtmfGen.h:100
wxSlider * mDtmfDutyCycleS
Definition: DtmfGen.h:96
void OnDutyCycle(wxCommandEvent &evt)
Definition: DtmfGen.cpp:609
void Recalculate()
Definition: DtmfGen.cpp:403
void EndMultiColumn()
void EnableMenu(bool enable=true)
sampleCount numSamplesSilence
Definition: DtmfGen.h:80
bool Startup() override
Definition: DtmfGen.cpp:270
Param(Sequence, wxString, wxT("Sequence"), wxT(SHORT_APP_NAME), wxT(""), wxT(""), wxT(""))
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: DtmfGen.cpp:166
double mSampleRate
Definition: Effect.h:455
sampleCount diff
Definition: DtmfGen.h:81
#define safenew
Definition: Audacity.h:223
#define DTMFTONES_PLUGIN_SYMBOL
Definition: DtmfGen.h:28
wxString dtmfSequence
Definition: DtmfGen.h:87
int curSeqPos
Definition: DtmfGen.h:85
wxTextCtrl * mDtmfSequenceT
Definition: DtmfGen.h:94
void AddPrompt(const wxString &Prompt)
Right aligned text string.
Definition: ShuttleGui.cpp:215
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
Definition: DtmfGen.cpp:123
static const double kFadeInOut
Definition: DtmfGen.cpp:51
void SetSizeHints(int minX=-1, int minY=-1)
void OnSequence(wxCommandEvent &evt)
Definition: DtmfGen.cpp:586
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
void OnDuration(wxCommandEvent &evt)
Definition: DtmfGen.cpp:602
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:493
void PopulateOrExchange(ShuttleGui &S) override
Definition: DtmfGen.cpp:306
wxWindow * GetParent()
Definition: ShuttleGui.h:259
unsigned GetAudioOutCount() override
Definition: DtmfGen.cpp:118
double dtmfAmplitude
Definition: DtmfGen.h:92
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:998
bool TransferDataToWindow() override
Definition: DtmfGen.cpp:366
sampleCount numRemaining
Definition: DtmfGen.h:82
ShuttleGui & Id(int id)
sampleCount numSamplesSequence
Definition: DtmfGen.h:78
void SetStyle(int Style)
Definition: ShuttleGui.h:252
#define ReadAndVerifyDouble(name)
Definition: Effect.h:787
double dtmfSilence
Definition: DtmfGen.h:90
bool MakeDtmfTone(float *buffer, size_t len, float fs, wxChar tone, sampleCount last, sampleCount total, float amplitude)
Definition: DtmfGen.cpp:445
void UpdateUI()
Definition: DtmfGen.cpp:574
void AddFixedText(const wxString &Str, bool bCenter=false)
Definition: ShuttleGui.cpp:356
void SetDuration(double duration) override
Definition: Effect.cpp:757
wxTextCtrl * mDtmfAmplitudeT
Definition: DtmfGen.h:95
wxStaticText * mDtmfSilenceT
Definition: DtmfGen.h:99
bool Init() override
Definition: DtmfGen.cpp:299
void SetValue(double newValue)
sampleCount curTonePos
Definition: DtmfGen.h:83
wxWindow * mUIParent
Definition: Effect.h:471
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
double mProjectRate
Definition: Effect.h:453
EffectType GetType() override
Definition: DtmfGen.cpp:111
bool TransferDataFromWindow() override
Definition: DtmfGen.cpp:384
#define M_PI
Definition: Distortion.cpp:28
An effect that generates DTMF tones.
Definition: DtmfGen.h:30
#define ReadAndVerifyString(name)
Definition: Effect.h:790
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:373
double dtmfDutyCycle
Definition: DtmfGen.h:91
int dtmfNTones
Definition: DtmfGen.h:88
NumericTextCtrl * mDtmfDurationT
Definition: DtmfGen.h:97
sampleCount numSamplesTone
Definition: DtmfGen.h:79
wxString GetDescription() override
Definition: DtmfGen.cpp:99
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
virtual ~EffectDtmf()
Definition: DtmfGen.cpp:88
double dtmfTone
Definition: DtmfGen.h:89
bool SetAutomationParameters(EffectAutomationParameters &parms) override
Definition: DtmfGen.cpp:242
wxString ManualPage() override
Definition: DtmfGen.cpp:104
bool isTone
Definition: DtmfGen.h:84
double mT0
Definition: Effect.h:459
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:456