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 // EffectDefinitionInterface 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
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 }
233  S.SHUTTLE_PARAM( dtmfSequence, Sequence );
234  S.SHUTTLE_PARAM( dtmfDutyCycle, DutyCycle );
235  S.SHUTTLE_PARAM( dtmfAmplitude, Amplitude );
236  return true;
237 }
238 
240 {
241  parms.Write(KEY_Sequence, dtmfSequence);
242  parms.Write(KEY_DutyCycle, dtmfDutyCycle);
243  parms.Write(KEY_Amplitude, dtmfAmplitude);
244 
245  return true;
246 }
247 
249 {
250  ReadAndVerifyDouble(DutyCycle);
251  ReadAndVerifyDouble(Amplitude);
253 
254  wxString symbols;
255  for (unsigned int i = 0; i < WXSIZEOF(kSymbols); i++)
256  {
257  symbols += kSymbols[i];
258  }
259 
260  if (Sequence.find_first_not_of(symbols) != wxString::npos)
261  {
262  return false;
263  }
264 
265  dtmfDutyCycle = DutyCycle;
266  dtmfAmplitude = Amplitude;
268 
269  Recalculate();
270 
271  return true;
272 }
273 
274 // Effect implementation
275 
277 {
278  wxString base = wxT("/Effects/DtmfGen/");
279 
280  // Migrate settings from 2.1.0 or before
281 
282  // Already migrated, so bail
283  if (gPrefs->Exists(base + wxT("Migrated")))
284  {
285  return true;
286  }
287 
288  // Load the old "current" settings
289  if (gPrefs->Exists(base))
290  {
291  gPrefs->Read(base + wxT("String"), &dtmfSequence, wxT(SHORT_APP_NAME));
292  gPrefs->Read(base + wxT("DutyCycle"), &dtmfDutyCycle, 550L);
293  gPrefs->Read(base + wxT("Amplitude"), &dtmfAmplitude, 0.8f);
294 
296 
297  // Do not migrate again
298  gPrefs->Write(base + wxT("Migrated"), true);
299  gPrefs->Flush();
300  }
301 
302  return true;
303 }
304 
306 {
307  Recalculate();
308 
309  return true;
310 }
311 
313 {
314  // dialog will be passed values from effect
315  // Effect retrieves values from saved config
316  // Dialog will take care of using them to initialize controls
317  // If there is a selection, use that duration, otherwise use
318  // value from saved config: this is useful is user wants to
319  // replace selection with dtmf sequence
320 
321  S.AddSpace(0, 5);
322  S.StartMultiColumn(2, wxCENTER);
323  {
324  wxTextValidator vldDtmf(wxFILTER_INCLUDE_CHAR_LIST, &dtmfSequence);
325  vldDtmf.SetIncludes(wxArrayString(WXSIZEOF(kSymbols), kSymbols));
326  mDtmfSequenceT = S.Id(ID_Sequence).AddTextBox(_("DTMF sequence:"), wxT(""), 10);
327  mDtmfSequenceT->SetValidator(vldDtmf);
328 
329  FloatingPointValidator<double> vldAmp(3, &dtmfAmplitude, NumValidatorStyle::NO_TRAILING_ZEROES);
330  vldAmp.SetRange(MIN_Amplitude, MAX_Amplitude);
331  S.Id(ID_Amplitude).AddTextBox(_("Amplitude (0-1):"), wxT(""), 10)->SetValidator(vldAmp);
332 
333  S.AddPrompt(_("Duration:"));
338  GetDuration(),
339  mProjectRate,
341  .AutoPos(true));
342  mDtmfDurationT->SetName(_("Duration"));
344 
345  S.AddFixedText(_("Tone/silence ratio:"), false);
346  S.SetStyle(wxSL_HORIZONTAL | wxEXPAND);
348  dtmfDutyCycle * SCL_DutyCycle,
349  MAX_DutyCycle * SCL_DutyCycle,
350  MIN_DutyCycle * SCL_DutyCycle);
351  S.SetSizeHints(-1,-1);
352  }
353  S.EndMultiColumn();
354 
355  S.StartMultiColumn(2, wxCENTER);
356  {
357  S.AddFixedText(_("Duty cycle:"), false);
358  mDtmfDutyT = S.AddVariableText(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle), false);
359 
360  S.AddFixedText(_("Tone duration:"), false);
361  mDtmfSilenceT = S.AddVariableText(wxString::Format(wxString(wxT("%.0f ")) + _("ms"), dtmfTone * 1000.0), false);
362 
363  S.AddFixedText(_("Silence duration:"), false);
364  mDtmfToneT = S.AddVariableText(wxString::Format(wxString(wxT("%0.f ")) + _("ms"), dtmfSilence * 1000.0), false);
365  }
366  S.EndMultiColumn();
367 }
368 
370 {
371  Recalculate();
372 
373  if (!mUIParent->TransferDataToWindow())
374  {
375  return false;
376  }
377 
378  mDtmfDutyCycleS->SetValue(dtmfDutyCycle * SCL_DutyCycle);
379 
381 
382  UpdateUI();
383 
384  return true;
385 }
386 
388 {
389  if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
390  {
391  return false;
392  }
393 
394  dtmfDutyCycle = (double) mDtmfDutyCycleS->GetValue() / SCL_DutyCycle;
396 
397  // recalculate to make sure all values are up-to-date. This is especially
398  // important if the user did not change any values in the dialog
399  Recalculate();
400 
401  return true;
402 }
403 
404 // EffectDtmf implementation
405 
407 {
408  // remember that dtmfDutyCycle is in range (0.0-100.0)
409 
410  dtmfNTones = (int) dtmfSequence.Length();
411 
412  if (dtmfNTones==0) {
413  // no tones, all zero: don't do anything
414  // this should take care of the case where user got an empty
415  // dtmf sequence into the generator: track won't be generated
416  SetDuration(0.0);
417  dtmfTone = 0;
418  dtmfSilence = 0;
419  } else {
420  if (dtmfNTones==1) {
421  // single tone, as long as the sequence
422  dtmfTone = GetDuration();
423  dtmfSilence = 0;
424  } else {
425  // Don't be fooled by the fact that you divide the sequence into dtmfNTones:
426  // the last slot will only contain a tone, not ending with silence.
427  // Given this, the right thing to do is to divide the sequence duration
428  // by dtmfNTones tones and (dtmfNTones-1) silences each sized according to the duty
429  // cycle: original division was:
430  // slot=mDuration / (dtmfNTones*(dtmfDutyCycle/MAX_DutyCycle)+(dtmfNTones-1)*(1.0-dtmfDutyCycle/MAX_DutyCycle))
431  // which can be simplified in the one below.
432  // Then just take the part that belongs to tone or silence.
433  //
434  double slot = GetDuration() / ((double)dtmfNTones + (dtmfDutyCycle / 100.0) - 1);
435  dtmfTone = slot * (dtmfDutyCycle / 100.0); // seconds
436  dtmfSilence = slot * (1.0 - (dtmfDutyCycle / 100.0)); // seconds
437 
438  // Note that in the extremes we have:
439  // - dutyCycle=100%, this means no silence, so each tone will measure mDuration/dtmfNTones
440  // - dutyCycle=0%, this means no tones, so each silence slot will measure mDuration/(NTones-1)
441  // But we always count:
442  // - dtmfNTones tones
443  // - dtmfNTones-1 silences
444  }
445  }
446 }
447 
448 bool EffectDtmf::MakeDtmfTone(float *buffer, size_t len, float fs, wxChar tone, sampleCount last, sampleCount total, float amplitude)
449 {
450 /*
451  --------------------------------------------
452  1209 Hz 1336 Hz 1477 Hz 1633 Hz
453 
454  ABC DEF
455  697 Hz 1 2 3 A
456 
457  GHI JKL MNO
458  770 Hz 4 5 6 B
459 
460  PQRS TUV WXYZ
461  852 Hz 7 8 9 C
462 
463  oper
464  941 Hz * 0 # D
465  --------------------------------------------
466  Essentially we need to generate two sin with
467  frequencies according to this table, and sum
468  them up.
469  sin wave is generated by:
470  s(n)=sin(2*pi*n*f/fs)
471 
472  We will precalculate:
473  A= 2*pi*f1/fs
474  B= 2*pi*f2/fs
475 
476  And use two switch statements to select the frequency
477 
478  Note: added support for letters, like those on the keypad
479  This support is only for lowercase letters: uppercase
480  are still considered to be the 'military'/carrier extra
481  tones.
482 */
483 
484  float f1, f2=0.0;
485  double A,B;
486 
487  // select low tone: left column
488  switch (tone) {
489  case '1': case '2': case '3': case 'A':
490  case 'a': case 'b': case 'c':
491  case 'd': case 'e': case 'f':
492  f1=697;
493  break;
494  case '4': case '5': case '6': case 'B':
495  case 'g': case 'h': case 'i':
496  case 'j': case 'k': case 'l':
497  case 'm': case 'n': case 'o':
498  f1=770;
499  break;
500  case '7': case '8': case '9': case 'C':
501  case 'p': case 'q': case 'r': case 's':
502  case 't': case 'u': case 'v':
503  case 'w': case 'x': case 'y': case 'z':
504  f1=852;
505  break;
506  case '*': case '0': case '#': case 'D':
507  f1=941;
508  break;
509  default:
510  f1=0;
511  }
512 
513  // select high tone: top row
514  switch (tone) {
515  case '1': case '4': case '7': case '*':
516  case 'g': case 'h': case 'i':
517  case 'p': case 'q': case 'r': case 's':
518  f2=1209;
519  break;
520  case '2': case '5': case '8': case '0':
521  case 'a': case 'b': case 'c':
522  case 'j': case 'k': case 'l':
523  case 't': case 'u': case 'v':
524  f2=1336;
525  break;
526  case '3': case '6': case '9': case '#':
527  case 'd': case 'e': case 'f':
528  case 'm': case 'n': case 'o':
529  case 'w': case 'x': case 'y': case 'z':
530  f2=1477;
531  break;
532  case 'A': case 'B': case 'C': case 'D':
533  f2=1633;
534  break;
535  default:
536  f2=0;
537  }
538 
539  // precalculations
540  A=B=2*M_PI/fs;
541  A*=f1;
542  B*=f2;
543 
544  // now generate the wave: 'last' is used to avoid phase errors
545  // when inside the inner for loop of the Process() function.
546  for(decltype(len) i = 0; i < len; i++) {
547  buffer[i] = amplitude * 0.5 *
548  (sin( A * (i + last).as_double() ) +
549  sin( B * (i + last).as_double() ));
550  }
551 
552  // generate a fade-in of duration 1/250th of second
553  if (last == 0) {
554  A = (fs / kFadeInOut);
555  for(size_t i = 0; i < A; i++) {
556  buffer[i] *= i/A;
557  }
558  }
559 
560  // generate a fade-out of duration 1/250th of second
561  if (last == total - len) {
562  // we are at the last buffer of 'len' size, so, offset is to
563  // backup 'A' samples, from 'len'
564  A = (fs / kFadeInOut);
565  auto offset = long(len) - long(fs / kFadeInOut);
566  // protect against negative offset, which can occur if too a
567  // small selection is made
568  if (offset >= 0) {
569  for(size_t i = 0; i < A; i++) {
570  buffer[i + offset] *= (1 - (i / A));
571  }
572  }
573  }
574  return true;
575 }
576 
578 {
579  mDtmfDutyT->SetLabel(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle));
580  mDtmfDutyT->SetName(mDtmfDutyT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
581 
582  mDtmfSilenceT->SetLabel(wxString::Format(_("%.0f ms"), dtmfTone * 1000.0));
583  mDtmfSilenceT->SetName(mDtmfSilenceT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
584 
585  mDtmfToneT->SetLabel(wxString::Format(_("%.0f ms"), dtmfSilence * 1000.0));
586  mDtmfToneT->SetName(mDtmfToneT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
587 }
588 
589 void EffectDtmf::OnSequence(wxCommandEvent & WXUNUSED(evt))
590 {
591  dtmfSequence = mDtmfSequenceT->GetValue();
592  Recalculate();
593  UpdateUI();
594 }
595 
596 void EffectDtmf::OnAmplitude(wxCommandEvent & WXUNUSED(evt))
597 {
598  if (!mDtmfAmplitudeT->GetValidator()->TransferFromWindow())
599  {
600  return;
601  }
602  Recalculate();
603  UpdateUI();
604 }
605 void EffectDtmf::OnDuration(wxCommandEvent & WXUNUSED(evt))
606 {
608  Recalculate();
609  UpdateUI();
610 }
611 
612 void EffectDtmf::OnDutyCycle(wxCommandEvent & evt)
613 {
614  dtmfDutyCycle = (double) evt.GetInt() / SCL_DutyCycle;
615  Recalculate();
616  UpdateUI();
617 }
#define SHORT_APP_NAME
Definition: DtmfGen.cpp:41
void OnAmplitude(wxCommandEvent &evt)
Definition: DtmfGen.cpp:596
void SetSizeHints(int minX, int minY)
Used to modify an already placed Window.
Definition: ShuttleGui.cpp:194
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxStaticText * mDtmfToneT
Definition: DtmfGen.h:99
bool SaveUserPreset(const wxString &name) override
Definition: Effect.cpp:600
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:409
double GetDuration() override
Definition: Effect.cpp:722
wxString GetCurrentSettingsGroup() override
Definition: Effect.cpp:801
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:288
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:54
wxStaticText * mDtmfDutyT
Definition: DtmfGen.h:101
wxSlider * mDtmfDutyCycleS
Definition: DtmfGen.h:97
void OnDutyCycle(wxCommandEvent &evt)
Definition: DtmfGen.cpp:612
void Recalculate()
Definition: DtmfGen.cpp:406
void EndMultiColumn()
IdentInterfaceSymbol GetSymbol() override
Definition: DtmfGen.cpp:94
NumericFormatId GetDurationFormat() override
Definition: Effect.cpp:732
sampleCount numSamplesSilence
Definition: DtmfGen.h:81
Shuttle that deals with parameters. This is a base class with lots of virtual functions that do nothi...
Definition: Shuttle.h:60
bool Startup() override
Definition: DtmfGen.cpp:276
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:82
#define safenew
Definition: Audacity.h:230
#define DTMFTONES_PLUGIN_SYMBOL
Definition: DtmfGen.h:28
wxString dtmfSequence
Definition: DtmfGen.h:88
int curSeqPos
Definition: DtmfGen.h:86
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
wxTextCtrl * mDtmfSequenceT
Definition: DtmfGen.h:95
void AddPrompt(const wxString &Prompt)
Right aligned text string.
Definition: ShuttleGui.cpp:239
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
Definition: DtmfGen.cpp:123
static const double kFadeInOut
Definition: DtmfGen.cpp:51
void OnSequence(wxCommandEvent &evt)
Definition: DtmfGen.cpp:589
void OnDuration(wxCommandEvent &evt)
Definition: DtmfGen.cpp:605
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:540
void PopulateOrExchange(ShuttleGui &S) override
Definition: DtmfGen.cpp:312
bool DefineParams(ShuttleParams &S) override
Definition: DtmfGen.cpp:232
wxWindow * GetParent()
Definition: ShuttleGui.h:294
unsigned GetAudioOutCount() override
Definition: DtmfGen.cpp:118
double dtmfAmplitude
Definition: DtmfGen.h:93
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
bool TransferDataToWindow() override
Definition: DtmfGen.cpp:369
sampleCount numRemaining
Definition: DtmfGen.h:83
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the Shuttle cla...
ShuttleGui & Id(int id)
sampleCount numSamplesSequence
Definition: DtmfGen.h:79
void SetStyle(int Style)
Definition: ShuttleGui.h:287
#define ReadAndVerifyDouble(name)
Definition: Effect.h:798
double dtmfSilence
Definition: DtmfGen.h:91
bool MakeDtmfTone(float *buffer, size_t len, float fs, wxChar tone, sampleCount last, sampleCount total, float amplitude)
Definition: DtmfGen.cpp:448
void UpdateUI()
Definition: DtmfGen.cpp:577
void AddFixedText(const wxString &Str, bool bCenter=false)
Definition: ShuttleGui.cpp:397
void SetDuration(double duration) override
Definition: Effect.cpp:742
wxTextCtrl * mDtmfAmplitudeT
Definition: DtmfGen.h:96
IdentInterfaceSymbol pairs a persistent string identifier used internally with an optional...
enum ChannelName * ChannelNames
wxStaticText * mDtmfSilenceT
Definition: DtmfGen.h:100
bool Init() override
Definition: DtmfGen.cpp:305
void SetValue(double newValue)
sampleCount curTonePos
Definition: DtmfGen.h:84
wxWindow * mUIParent
Definition: Effect.h:472
double mProjectRate
Definition: Effect.h:453
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
EffectType GetType() override
Definition: DtmfGen.cpp:111
bool SetAutomationParameters(CommandParameters &parms) override
Definition: DtmfGen.cpp:248
EffectType
bool TransferDataFromWindow() override
Definition: DtmfGen.cpp:387
#define M_PI
Definition: Distortion.cpp:28
An effect that generates DTMF tones.
Definition: DtmfGen.h:30
#define ReadAndVerifyString(name)
Definition: Effect.h:801
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:414
double dtmfDutyCycle
Definition: DtmfGen.h:92
int dtmfNTones
Definition: DtmfGen.h:89
NumericTextCtrl * mDtmfDurationT
Definition: DtmfGen.h:98
sampleCount numSamplesTone
Definition: DtmfGen.h:80
Options & AutoPos(bool value)
wxString GetDescription() override
Definition: DtmfGen.cpp:99
bool GetAutomationParameters(CommandParameters &parms) override
Definition: DtmfGen.cpp:239
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
virtual ~EffectDtmf()
Definition: DtmfGen.cpp:88
double dtmfTone
Definition: DtmfGen.h:90
wxString ManualPage() override
Definition: DtmfGen.cpp:104
bool isTone
Definition: DtmfGen.h:85
double mT0
Definition: Effect.h:460
wxSlider * AddSlider(const wxString &Prompt, int pos, int Max, int Min=0)
Definition: ShuttleGui.cpp:497