Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptclib / dtmf.cxx
bloba80a12dbb3b567481f9566ace35b509801c52975
1 /*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
9 * Extract DTMF signals from 16 bit PCM audio
11 * Originally written by Poul-Henning Kamp <phk@freebsd.org>
12 * Made into a C++ class by Roger Hardiman <roger@freebsd.org>, January 2002
14 * $Log$
15 * Revision 1.18 2007/07/19 08:10:32 csoutheren
16 * Add detection of CNG
18 * Revision 1.17 2006/12/13 04:56:03 csoutheren
19 * Applied 1613270 - fixed for dtmfEncoder
20 * Thanks to Frederic Heem
22 * Revision 1.16 2006/11/11 15:23:37 hfriederich
23 * Use correct GetSize() to avoid allocation problems
25 * Revision 1.15 2006/10/25 08:18:22 rjongbloed
26 * Major upgrade of tone generation subsystem.
28 * Revision 1.14 2005/11/30 12:47:41 csoutheren
29 * Removed tabs, reformatted some code, and changed tags for Doxygen
31 * Revision 1.13 2005/01/25 06:35:27 csoutheren
32 * Removed warnings under MSVC
34 * Revision 1.12 2004/11/17 10:13:14 csoutheren
35 * Fixed compilation with gcc 4.0.0
37 * Revision 1.11 2004/09/09 23:50:49 csoutheren
38 * Fixed problem with duplicate definition of sinetab causing problems
40 * Revision 1.10 2004/09/09 05:23:38 dereksmithies
41 * Add utility function to report on dtmf characters used.
43 * Revision 1.9 2004/09/09 04:22:46 csoutheren
44 * Added sine table for DTMF encoder
46 * Revision 1.8 2004/09/09 04:00:01 csoutheren
47 * Added DTMF encoding functions
49 * Revision 1.7 2003/03/17 07:39:25 robertj
50 * Fixed possible invalid value causing DTMF detector to crash.
52 * Revision 1.6 2002/02/20 02:59:34 yurik
53 * Added end of line to trace statement
55 * Revision 1.5 2002/02/12 10:21:56 rogerh
56 * Stop sending '?' when a bad DTMF tone is detected.
58 * Revision 1.4 2002/01/24 11:14:45 rogerh
59 * Back out robert's change. It did not work (no sign extending)
60 * and replace it with a better solution which should be happy on both big
61 * endian and little endian systems.
63 * Revision 1.3 2002/01/24 10:40:17 rogerh
64 * Add version log
69 #ifdef __GNUC__
70 #pragma implementation "dtmf.h"
71 #endif
73 #include <ptlib.h>
74 #include <ptclib/dtmf.h>
76 #include <math.h>
78 /* Integer math scaling factor */
79 #define FSC (1<<12)
81 /* This is the Q of the filter (pole radius) */
82 #define POLRAD .99
84 #define P2 ((int)(POLRAD*POLRAD*FSC))
88 PDTMFDecoder::PDTMFDecoder()
90 // Initialise the class
91 int i,kk;
92 for (kk = 0; kk < NumTones; kk++) {
93 y[kk] = h[kk] = k[kk] = 0;
96 nn = 0;
97 ia = 0;
98 so = 0;
100 for (i = 0; i < 256; i++) {
101 key[i] = '?';
104 /* We encode the tones in 8 bits, translate those to symbol */
105 key[0x11] = '1'; key[0x12] = '4'; key[0x14] = '7'; key[0x18] = '*';
106 key[0x21] = '2'; key[0x22] = '5'; key[0x24] = '8'; key[0x28] = '0';
107 key[0x41] = '3'; key[0x42] = '6'; key[0x44] = '9'; key[0x48] = '#';
108 key[0x81] = 'A'; key[0x82] = 'B'; key[0x84] = 'C'; key[0x88] = 'D';
110 /* The frequencies we're trying to detect */
111 /* These are precalculated to save processing power */
112 /* static int dtmf[9] = {697, 770, 852, 941, 1209, 1336, 1477, 1633, 1100}; */
113 /* p1[kk] = (-cos(2 * 3.141592 * dtmf[kk] / 8000.0) * FSC) */
114 p1[0] = -3497; p1[1] = -3369; p1[2] = -3212; p1[3] = -3027;
115 p1[4] = -2384; p1[5] = -2040; p1[6] = -1635; p1[7] = -1164;
116 p1[9] = -2660;
120 PString PDTMFDecoder::Decode(const short * sampleData, PINDEX numSamples)
122 int x;
123 int s, kk;
124 int c, d, f, n;
126 PString keyString;
128 PINDEX pos;
129 for (pos = 0; pos < numSamples; pos++) {
131 /* Read (and scale) the next 16 bit sample */
132 x = ((int)(*sampleData++)) / (32768/FSC);
134 /* Input amplitude */
135 if (x > 0)
136 ia += (x - ia) / 128;
137 else
138 ia += (-x - ia) / 128;
140 /* For each tone */
141 s = 0;
142 for(kk = 0; kk < NumTones; kk++) {
144 /* Turn the crank */
145 c = (P2 * (x - k[kk])) / FSC;
146 d = x + c;
147 f = (p1[kk] * (d - h[kk])) / FSC;
148 n = x - k[kk] - c;
149 k[kk] = h[kk] + f;
150 h[kk] = f + d;
152 /* Detect and Average */
153 if (n > 0)
154 y[kk] += (n - y[kk]) / 64;
155 else
156 y[kk] += (-n - y[kk]) / 64;
158 /* Threshold */
159 if (y[kk] > FSC/10 && y[kk] > ia) {
160 if (kk < 8)
161 s |= 1 << kk;
162 else if (kk == 8)
163 s = 0x100;
167 /* Hysteresis and noise supressor */
168 if (s != so) {
169 nn = 0;
170 so = s;
171 } else if (nn++ == 520) {
172 if (s < 256) {
173 if (key[s] != '?') {
174 PTRACE(3,"DTMF\tDetected '" << key[s] << "' in PCM-16 stream");
175 keyString += key[s];
178 else if (s == 0x100) {
179 PTRACE(3,"DTMF\tDetected CNG in PCM-16 stream");
180 keyString += 'X';
184 return keyString;
187 ////////////////////////////////////////////////////////////////////////////////////////////
189 static int sine(int angle)
191 static int sinArray[PTones::MaxFrequency] = {
192 0,0,1,2,3,3,4,5,6,7,7,8,9,10,10,11,12,13,14,14,15,16,17,18,18,19,20,21,21,22,
193 23,24,25,25,26,27,28,29,29,30,31,32,32,33,34,35,36,36,37,38,39,40,40,41,42,43,43,44,45,46,
194 47,47,48,49,50,51,51,52,53,54,54,55,56,57,58,58,59,60,61,62,62,63,64,65,65,66,67,68,69,69,
195 70,71,72,72,73,74,75,76,76,77,78,79,80,80,81,82,83,83,84,85,86,87,87,88,89,90,90,91,92,93,
196 94,94,95,96,97,98,98,99,100,101,101,102,103,104,105,105,106,107,108,108,109,110,111,112,112,113,114,115,115,116,
197 117,118,119,119,120,121,122,122,123,124,125,126,126,127,128,129,130,130,131,132,133,133,134,135,136,137,137,138,139,140,
198 140,141,142,143,144,144,145,146,147,147,148,149,150,151,151,152,153,154,154,155,156,157,157,158,159,160,161,161,162,163,
199 164,164,165,166,167,168,168,169,170,171,171,172,173,174,175,175,176,177,178,178,179,180,181,181,182,183,184,185,185,186,
200 187,188,188,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200,201,202,202,203,204,205,205,206,207,208,208,209,
201 210,211,212,212,213,214,215,215,216,217,218,218,219,220,221,221,222,223,224,225,225,226,227,228,228,229,230,231,231,232,
202 233,234,234,235,236,237,238,238,239,240,241,241,242,243,244,244,245,246,247,247,248,249,250,250,251,252,253,254,254,255,
203 256,257,257,258,259,260,260,261,262,263,263,264,265,266,266,267,268,269,269,270,271,272,272,273,274,275,275,276,277,278,
204 278,279,280,281,282,282,283,284,285,285,286,287,288,288,289,290,291,291,292,293,294,294,295,296,297,297,298,299,300,300,
205 301,302,303,303,304,305,306,306,307,308,309,309,310,311,312,312,313,314,314,315,316,317,317,318,319,320,320,321,322,323,
206 323,324,325,326,326,327,328,329,329,330,331,332,332,333,334,335,335,336,337,337,338,339,340,340,341,342,343,343,344,345,
207 346,346,347,348,349,349,350,351,352,352,353,354,354,355,356,357,357,358,359,360,360,361,362,363,363,364,365,365,366,367,
208 368,368,369,370,371,371,372,373,373,374,375,376,376,377,378,379,379,380,381,381,382,383,384,384,385,386,387,387,388,389,
209 389,390,391,392,392,393,394,394,395,396,397,397,398,399,400,400,401,402,402,403,404,405,405,406,407,407,408,409,410,410,
210 411,412,412,413,414,415,415,416,417,417,418,419,420,420,421,422,422,423,424,425,425,426,427,427,428,429,430,430,431,432,
211 432,433,434,434,435,436,437,437,438,439,439,440,441,442,442,443,444,444,445,446,446,447,448,449,449,450,451,451,452,453,
212 453,454,455,456,456,457,458,458,459,460,460,461,462,463,463,464,465,465,466,467,467,468,469,470,470,471,472,472,473,474,
213 474,475,476,476,477,478,478,479,480,481,481,482,483,483,484,485,485,486,487,487,488,489,489,490,491,492,492,493,494,494,
214 495,496,496,497,498,498,499,500,500,501,502,502,503,504,504,505,506,507,507,508,509,509,510,511,511,512,513,513,514,515,
215 515,516,517,517,518,519,519,520,521,521,522,523,523,524,525,525,526,527,527,528,529,529,530,531,531,532,533,533,534,535,
216 535,536,537,537,538,539,539,540,541,541,542,543,543,544,545,545,546,547,547,548,549,549,550,550,551,552,552,553,554,554,
217 555,556,556,557,558,558,559,560,560,561,562,562,563,564,564,565,565,566,567,567,568,569,569,570,571,571,572,573,573,574,
218 575,575,576,576,577,578,578,579,580,580,581,582,582,583,583,584,585,585,586,587,587,588,589,589,590,590,591,592,592,593,
219 594,594,595,596,596,597,597,598,599,599,600,601,601,602,602,603,604,604,605,606,606,607,607,608,609,609,610,611,611,612,
220 612,613,614,614,615,616,616,617,617,618,619,619,620,620,621,622,622,623,624,624,625,625,626,627,627,628,628,629,630,630,
221 631,631,632,633,633,634,635,635,636,636,637,638,638,639,639,640,641,641,642,642,643,644,644,645,645,646,647,647,648,648,
222 649,650,650,651,651,652,653,653,654,654,655,655,656,657,657,658,658,659,660,660,661,661,662,663,663,664,664,665,666,666,
223 667,667,668,668,669,670,670,671,671,672,673,673,674,674,675,675,676,677,677,678,678,679,679,680,681,681,682,682,683,683,
224 684,685,685,686,686,687,687,688,689,689,690,690,691,691,692,693,693,694,694,695,695,696,697,697,698,698,699,699,700,700,
225 701,702,702,703,703,704,704,705,705,706,707,707,708,708,709,709,710,710,711,712,712,713,713,714,714,715,715,716,717,717,
226 718,718,719,719,720,720,721,721,722,723,723,724,724,725,725,726,726,727,727,728,728,729,730,730,731,731,732,732,733,733,
227 734,734,735,735,736,736,737,738,738,739,739,740,740,741,741,742,742,743,743,744,744,745,745,746,746,747,748,748,749,749,
228 750,750,751,751,752,752,753,753,754,754,755,755,756,756,757,757,758,758,759,759,760,760,761,761,762,762,763,763,764,764,
229 765,765,766,766,767,768,768,769,769,770,770,771,771,772,772,773,773,774,774,774,775,775,776,776,777,777,778,778,779,779,
230 780,780,781,781,782,782,783,783,784,784,785,785,786,786,787,787,788,788,789,789,790,790,791,791,792,792,793,793,793,794,
231 794,795,795,796,796,797,797,798,798,799,799,800,800,801,801,802,802,802,803,803,804,804,805,805,806,806,807,807,808,808,
232 809,809,809,810,810,811,811,812,812,813,813,814,814,814,815,815,816,816,817,817,818,818,819,819,819,820,820,821,821,822,
233 822,823,823,823,824,824,825,825,826,826,827,827,827,828,828,829,829,830,830,831,831,831,832,832,833,833,834,834,834,835,
234 835,836,836,837,837,837,838,838,839,839,840,840,840,841,841,842,842,843,843,843,844,844,845,845,846,846,846,847,847,848,
235 848,848,849,849,850,850,850,851,851,852,852,853,853,853,854,854,855,855,855,856,856,857,857,857,858,858,859,859,859,860,
236 860,861,861,861,862,862,863,863,863,864,864,865,865,865,866,866,867,867,867,868,868,869,869,869,870,870,870,871,871,872,
237 872,872,873,873,874,874,874,875,875,875,876,876,877,877,877,878,878,878,879,879,880,880,880,881,881,881,882,882,883,883,
238 883,884,884,884,885,885,885,886,886,887,887,887,888,888,888,889,889,889,890,890,891,891,891,892,892,892,893,893,893,894,
239 894,894,895,895,895,896,896,896,897,897,898,898,898,899,899,899,900,900,900,901,901,901,902,902,902,903,903,903,904,904,
240 904,905,905,905,906,906,906,907,907,907,908,908,908,909,909,909,910,910,910,911,911,911,912,912,912,913,913,913,913,914,
241 914,914,915,915,915,916,916,916,917,917,917,918,918,918,918,919,919,919,920,920,920,921,921,921,922,922,922,922,923,923,
242 923,924,924,924,925,925,925,925,926,926,926,927,927,927,928,928,928,928,929,929,929,930,930,930,930,931,931,931,932,932,
243 932,932,933,933,933,934,934,934,934,935,935,935,935,936,936,936,937,937,937,937,938,938,938,939,939,939,939,940,940,940,
244 940,941,941,941,941,942,942,942,942,943,943,943,944,944,944,944,945,945,945,945,946,946,946,946,947,947,947,947,948,948,
245 948,948,949,949,949,949,950,950,950,950,951,951,951,951,952,952,952,952,952,953,953,953,953,954,954,954,954,955,955,955,
246 955,956,956,956,956,956,957,957,957,957,958,958,958,958,958,959,959,959,959,960,960,960,960,960,961,961,961,961,962,962,
247 962,962,962,963,963,963,963,963,964,964,964,964,964,965,965,965,965,965,966,966,966,966,967,967,967,967,967,967,968,968,
248 968,968,968,969,969,969,969,969,970,970,970,970,970,971,971,971,971,971,972,972,972,972,972,972,973,973,973,973,973,973,
249 974,974,974,974,974,975,975,975,975,975,975,976,976,976,976,976,976,977,977,977,977,977,977,978,978,978,978,978,978,979,
250 979,979,979,979,979,980,980,980,980,980,980,980,981,981,981,981,981,981,981,982,982,982,982,982,982,983,983,983,983,983,
251 983,983,984,984,984,984,984,984,984,984,985,985,985,985,985,985,985,986,986,986,986,986,986,986,986,987,987,987,987,987,
252 987,987,987,988,988,988,988,988,988,988,988,989,989,989,989,989,989,989,989,989,990,990,990,990,990,990,990,990,990,990,
253 991,991,991,991,991,991,991,991,991,992,992,992,992,992,992,992,992,992,992,992,993,993,993,993,993,993,993,993,993,993,
254 993,994,994,994,994,994,994,994,994,994,994,994,994,995,995,995,995,995,995,995,995,995,995,995,995,995,995,996,996,996,
255 996,996,996,996,996,996,996,996,996,996,996,996,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,
256 998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,999,999,999,999,999,999,
257 999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,
258 999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999
261 int quadrant = angle / PTones::MaxFrequency;
262 int offset = angle % PTones::MaxFrequency;
264 switch (quadrant) {
265 case 0:
266 return sinArray[offset];
267 case 1:
268 return sinArray[PTones::MaxFrequency-1-offset];
269 case 2:
270 return -sinArray[offset];
271 default:
272 return -sinArray[PTones::MaxFrequency-1-offset];
277 ////////////////////////////////////////////////////////////////////////
280 PTones::PTones(unsigned volume):
281 PShortArray(),
282 masterVolume(volume),
283 lastOperation(0),
284 lastFrequency1(0),
285 lastFrequency2(0),
286 angle1(0),
287 angle2(0)
292 PTones::PTones(const PString & descriptor, unsigned volume)
293 : masterVolume(volume)
295 if (!Generate(descriptor)) {
296 PTRACE(1,"DTMF\tCannot encode tone \"" << descriptor << '"');
301 bool PTones::Generate(const PString & descriptor)
303 PStringArray toneChunks = descriptor.Tokenise('/');
304 if (toneChunks.IsEmpty())
305 return false;
307 for (PINDEX chunk = 0; chunk < toneChunks.GetSize(); chunk++) {
308 // split frequency and cadence
309 PINDEX pos = toneChunks[chunk].Find(':');
310 if (pos == P_MAX_INDEX)
311 return false;
313 PString frequencyStr = toneChunks[chunk].Left(pos).Trim();
314 PString cadenceStr = toneChunks[chunk].Mid(pos+1).Trim();
316 if (cadenceStr.IsEmpty())
317 return false;
319 // Do we have a volume?
320 unsigned volume = 100;
321 if ((pos = frequencyStr.Find('%')) != P_MAX_INDEX) {
322 volume = frequencyStr.Left(pos).AsUnsigned();
323 if (volume < 1 || volume > 100)
324 return false;
325 frequencyStr.Delete(0, pos+1);
328 if (frequencyStr.IsEmpty())
329 return false;
331 // Parse the frequencies
332 unsigned frequency1, frequency2;
333 char operation;
334 if ((pos = frequencyStr.FindOneOf("+-x")) != P_MAX_INDEX) {
335 frequency1 = frequencyStr.Left(pos).AsUnsigned();
336 frequency2 = frequencyStr.Mid(pos+1).AsUnsigned();
337 operation = frequencyStr[pos];
339 else {
340 frequency1 = frequency2 = frequencyStr.AsUnsigned();
341 operation = '-';
344 // Parse the cadence
345 double duration = cadenceStr.AsReal();
347 // First one
348 if (!Generate(operation, frequency1, frequency2, (unsigned)(duration*1000), volume))
349 return false;
351 char originalOperation = operation;
352 operation = ' ';
354 pos = 0;
355 while ((pos = cadenceStr.Find('-', pos)) != P_MAX_INDEX) {
356 duration = cadenceStr.Mid(++pos).AsReal();
357 if (duration < 0 || duration > 60)
358 return false;
360 if (!Generate(operation, frequency1, frequency2, (unsigned)(duration*1000), volume))
361 return false;
363 // Alternate between the tone and silence
364 operation = operation == ' ' ? originalOperation : ' ';
368 return true;
372 bool PTones::Generate(char operation, unsigned frequency1, unsigned frequency2, unsigned milliseconds, unsigned volume)
374 if (lastOperation != operation ||
375 lastFrequency1 != frequency1 ||
376 lastFrequency2 != frequency2) {
377 lastOperation = operation;
378 lastFrequency1 = frequency1;
379 lastFrequency2 = frequency2;
381 angle1 = 0;
382 angle2 = 0;
385 switch (operation) {
386 case '+':
387 return Juxtapose(frequency1, frequency2, milliseconds, volume);
389 case 'x':
390 return Modulate(frequency1, frequency2, milliseconds, volume);
392 case '-':
393 return PureTone(frequency1, milliseconds, volume);
395 case ' ':
396 return Silence(milliseconds);
399 return false;
403 bool PTones::Juxtapose(unsigned frequency1, unsigned frequency2, unsigned milliseconds, unsigned volume)
405 if (frequency1 < MinFrequency || frequency1 > MaxFrequency ||
406 frequency2 < MinFrequency || frequency2 > MaxFrequency)
407 return false;
409 // TODO this gived 8000 samples for 100 ms !!!
410 //unsigned samples = CalcSamples(milliseconds, frequency1, frequency2);
411 unsigned samples = milliseconds * SampleRate / 1000;
412 while (samples-- > 0) {
413 int a1 = sine(angle1);
414 int a2 = sine(angle2);
416 AddSample((a1 + a2) / 2, volume);
418 angle1 += frequency1;
419 if (angle1 >= SampleRate)
420 angle1 -= SampleRate;
422 angle2 += frequency2;
423 if (angle2 >= SampleRate)
424 angle2 -= SampleRate;
426 return true;
430 bool PTones::Modulate(unsigned frequency1, unsigned modulator, unsigned milliseconds, unsigned volume)
432 if (frequency1 < MinFrequency || frequency1 > MaxFrequency || modulator < MinModulation || modulator >= frequency1/2)
433 return false;
435 unsigned samples = CalcSamples(milliseconds, frequency1, modulator);
437 while (samples-- > 0) {
438 int a1 = sine(angle1); // -999 to 999
439 int a2 = sine(angle2); // -999 to 999
441 AddSample((a1 * (a2 + SineScale)) / SineScale / 2, volume);
443 angle1 += frequency1;
444 if (angle1 >= SampleRate)
445 angle1 -= SampleRate;
447 angle2 += modulator;
448 if (angle2 >= SampleRate)
449 angle2 -= SampleRate;
451 return true;
455 bool PTones::PureTone(unsigned frequency1, unsigned milliseconds, unsigned volume)
457 if (frequency1 < MinFrequency || frequency1 > MaxFrequency)
458 return false;
460 unsigned samples = CalcSamples(milliseconds, frequency1);
461 while (samples-- > 0) {
462 AddSample(sine(angle1), volume);
464 angle1 += frequency1;
465 if (angle1 >= SampleRate)
466 angle1 -= SampleRate;
468 return true;
472 bool PTones::Silence(unsigned milliseconds)
474 unsigned samples = milliseconds * SampleRate/1000;
475 while (samples-- > 0)
476 AddSample(0, 0);
477 return true;
481 unsigned PTones::CalcSamples(unsigned ms, unsigned f1, unsigned f2)
483 // firstly, find the minimum time to repeat the waveform
484 unsigned v1 = 1;
485 unsigned v2 = 1;
487 if (f2 > 0)
489 while (v1*f2 != v2*f1) {
490 if (v1*f2 < v2*f1)
491 v1++;
492 else
493 v2++;
497 // v1 repetitions of f1 == v2 repetitions of f2
498 //cout << v1 << " cycles of " << f1 << "hz = " << v2 << " samples of " << f2 << "hz" << endl;
500 // now find the number of times we need to repeat this to match the sampling rate
501 unsigned n1 = 1;
502 unsigned n2 = 1;
503 while (n1*SampleRate*v1 != n2*f1) {
504 if (n1*SampleRate*v1 < n2*f1)
505 n1++;
506 else
507 n2++;
510 // v1 repetitions of t == v2 repetitions sample frequency
511 //cout << n1*v1 << " cycles at " << f1 << "hz = "
512 // << n1*v2 << " cycles at " << f2 << "hz = "
513 // << n2 << " samples at " << SampleRate << "hz" << endl;
515 // Make sure we round up the number of milliseconds to even multiple of cycles
516 return ms == 0 ? n2 : ((ms * SampleRate/1000 + n2 - 1)/n2*n2);
520 void PTones::AddSample(int sample, unsigned volume)
522 // Sample added is value from -1000 to 1000, rescale to short range -32767 to +32767
523 PINDEX length = GetSize();
524 SetSize(length + 1);
525 sample *= volume;
526 sample *= masterVolume;
527 sample /= SineScale*100*100/SHRT_MAX;
528 SetAt(length, (short)sample);
532 ////////////////////////////////////////////////////////////////////////
534 PDTMFEncoder::PDTMFEncoder(const char * dtmf, unsigned milliseconds) :
535 PTones()
537 AddTone(dtmf, milliseconds);
540 PDTMFEncoder::PDTMFEncoder(char digit, unsigned milliseconds) :
541 PTones()
543 AddTone(digit, milliseconds);
546 void PDTMFEncoder::AddTone(const char * str, unsigned milliseconds)
548 if (str == NULL)
549 return;
551 while (*str != '\0')
552 AddTone(*str++, milliseconds);
556 void PDTMFEncoder::AddTone(char digit, unsigned milliseconds)
558 // DTMF frequencies as per http://www.commlinx.com.au/DTMF_frequencies.htm
560 static unsigned const dtmfFreqs[16][2] = {
561 { 941,1336 }, // 0
562 { 697,1209 }, // 1
563 { 697,1336 }, // 2
564 { 697,1477 }, // 3
565 { 770,1209 }, // 4
566 { 770,1336 }, // 5
567 { 770,1477 }, // 6
568 { 852,1209 }, // 7
569 { 852,1336 }, // 8
570 { 852,1477 }, // 9
571 { 697,1633 }, // A
572 { 770,1633 }, // B
573 { 852,1633 }, // C
574 { 941,1633 }, // D
575 { 941,1209 }, // *
576 { 941,1477 } // #
579 digit = (char)toupper(digit);
580 PINDEX index;
581 if ('0' <= digit && digit <= '9')
582 index = digit - '0';
583 else if ('A' <= digit && digit <= 'D')
584 index = digit + 10 - 'A';
585 else if (digit == '*')
586 index = 14;
587 else if (digit == '#')
588 index = 15;
589 else
590 return;
592 Generate('+', dtmfFreqs[index][0], dtmfFreqs[index][1], milliseconds);
596 void PDTMFEncoder::AddTone(double f1, double f2, unsigned milliseconds)
598 if (f1 > 0 && f1 < MaxFrequency && f2 > 0 && f2 < MaxFrequency){
599 Generate('+', (unsigned)f1, (unsigned)f2, milliseconds);
600 } else {
601 PAssertAlways(PInvalidParameter);
606 char PDTMFEncoder::DtmfChar(PINDEX i)
608 PAssert(i < 16, "Only 16 dtmf symbols. Index too large");
610 static char dtmfSymbols[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','*','#' };
611 return dtmfSymbols[i];
615 ////////////////////////////////////////////////////////////////////////////