|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // This file contains an implementation of the ToneGenerator interface |
|
15 // that converts all tone generation requests in to sampled audio |
|
16 // data to be played through the normal local sampled audio interface |
|
17 // |
|
18 // |
|
19 |
|
20 #include "BtToneGenerator.h" |
|
21 |
|
22 #include <e32math.h> |
|
23 #include <mda/common/resource.h> |
|
24 |
|
25 /****************************************************************************** |
|
26 * Tone Generators |
|
27 * |
|
28 * The following classes are used to generate simple frequency/duration tones, |
|
29 * DTMF, and SymbianOS tone sequences in a WINS environment. The below code |
|
30 * should only be considered for WINS. |
|
31 ******************************************************************************/ |
|
32 |
|
33 // this defines the maximum possible amplitude allowed for TSineGen::SetFrequency() |
|
34 const TInt KMaxAmplitude = 0x8000; |
|
35 |
|
36 // default number of samples for trailing silence following a Tone |
|
37 const TInt KDefaultTrailingSilenceSamples = 20; |
|
38 |
|
39 // |
|
40 // Sine tone generator |
|
41 // |
|
42 |
|
43 const TInt16 TSineGen::SineTable[KMaxSineTable] = |
|
44 { |
|
45 0, 804, 1607, 2410, 3211, 4011, 4807, 5601, |
|
46 6392, 7179, 7961, 8739, 9511, 10278, 11038, 11792, |
|
47 12539, 13278, 14009, 14732, 15446, 16150, 16845, 17530, |
|
48 18204, 18867, 19519, 20159, 20787, 21402, 22004, 22594, |
|
49 23169, 23731, 24278, 24811, 25329, 25831, 26318, 26789, |
|
50 27244, 27683, 28105, 28510, 28897, 29268, 29621, 29955, |
|
51 30272, 30571, 30851, 31113, 31356, 31580, 31785, 31970, |
|
52 32137, 32284, 32412, 32520, 32609, 32678, 32727, 32757, |
|
53 32767, 32757, 32727, 32678, 32609, 32520, 32412, 32284, |
|
54 32137, 31970, 31785, 31580, 31356, 31113, 30851, 30571, |
|
55 30272, 29955, 29621, 29268, 28897, 28510, 28105, 27683, |
|
56 27244, 26789, 26318, 25831, 25329, 24811, 24278, 23731, |
|
57 23169, 22594, 22004, 21402, 20787, 20159, 19519, 18867, |
|
58 18204, 17530, 16845, 16150, 15446, 14732, 14009, 13278, |
|
59 12539, 11792, 11038, 10278, 9511, 8739, 7961, 7179, |
|
60 6392, 5601, 4807, 4011, 3211, 2410, 1607, 804, |
|
61 0, -804, -1607, -2410, -3211, -4011, -4807, -5601, |
|
62 -6392, -7179, -7961, -8739, -9511,-10278,-11038,-11792, |
|
63 -12539,-13278,-14009,-14732,-15446,-16150,-16845,-17530, |
|
64 -18204,-18867,-19519,-20159,-20787,-21402,-22004,-22594, |
|
65 -23169,-23731,-24278,-24811,-25329,-25831,-26318,-26789, |
|
66 -27244,-27683,-28105,-28510,-28897,-29268,-29621,-29955, |
|
67 -30272,-30571,-30851,-31113,-31356,-31580,-31785,-31970, |
|
68 -32137,-32284,-32412,-32520,-32609,-32678,-32727,-32757, |
|
69 -32767,-32757,-32727,-32678,-32609,-32520,-32412,-32284, |
|
70 -32137,-31970,-31785,-31580,-31356,-31113,-30851,-30571, |
|
71 -30272,-29955,-29621,-29268,-28897,-28510,-28105,-27683, |
|
72 -27244,-26789,-26318,-25831,-25329,-24811,-24278,-23731, |
|
73 -23169,-22594,-22004,-21402,-20787,-20159,-19519,-18867, |
|
74 -18204,-17530,-16845,-16150,-15446,-14732,-14009,-13278, |
|
75 -12539,-11792,-11038,-10278, -9511, -8739, -7961, -7179, |
|
76 -6392, -5601, -4807, -4011, -3211, -2410, -1607, -804, |
|
77 }; |
|
78 |
|
79 const TInt16 TSineGen::IncTable[KMaxSineTable] = |
|
80 { |
|
81 804, 803, 803, 801, 800, 796, 794, |
|
82 791, 787, 782, 778, 772, 767, 760, 754, |
|
83 747, 739, 731, 723, 714, 704, 695, 685, |
|
84 674, 663, 652, 640, 628, 615, 602, 590, |
|
85 575, 562, 547, 533, 518, 502, 487, 471, |
|
86 455, 439, 422, 405, 387, 371, 353, 334, |
|
87 317, 299, 280, 262, 243, 224, 205, 185, |
|
88 167, 147, 128, 108, 89, 69, 49, 30, |
|
89 10, -10, -30, -49, -69, -89, -108, -128, |
|
90 -147, -167, -185, -205, -224, -243, -262, -280, |
|
91 -299, -317, -334, -353, -371, -387, -405, -422, |
|
92 -439, -455, -471, -487, -502, -518, -533, -547, |
|
93 -562, -575, -590, -602, -615, -628, -640, -652, |
|
94 -663, -674, -685, -695, -704, -714, -723, -731, |
|
95 -739, -747, -754, -760, -767, -772, -778, -782, |
|
96 -787, -791, -794, -796, -800, -801, -803, -803, |
|
97 -804, -804, -803, -803, -801, -800, -796, -794, |
|
98 -791, -787, -782, -778, -772, -767, -760, -754, |
|
99 -747, -739, -731, -723, -714, -704, -695, -685, |
|
100 -674, -663, -652, -640, -628, -615, -602, -590, |
|
101 -575, -562, -547, -533, -518, -502, -487, -471, |
|
102 -455, -439, -422, -405, -387, -371, -353, -334, |
|
103 -317, -299, -280, -262, -243, -224, -205, -185, |
|
104 -167, -147, -128, -108, -89, -69, -49, -30, |
|
105 -10, 10, 30, 49, 69, 89, 108, 128, |
|
106 147, 167, 185, 205, 224, 243, 262, 280, |
|
107 299, 317, 334, 353, 371, 387, 405, 422, |
|
108 439, 455, 471, 487, 502, 518, 533, 547, |
|
109 562, 575, 590, 602, 615, 628, 640, 652, |
|
110 663, 674, 685, 695, 704, 714, 723, 731, |
|
111 739, 747, 754, 760, 767, 772, 778, 782, |
|
112 787, 791, 794, 796, 800, 801, 803, 803, |
|
113 804 |
|
114 }; |
|
115 |
|
116 void TSineGen::SetFrequency(TInt aFrequency,TInt aAmplitude) |
|
117 // |
|
118 // Given the frequency set iStep. |
|
119 // Reset iPosition to the equivalent of 0 degrees. |
|
120 // In the special case of aFrequency==4KHz set iPosition to 90 degrees. |
|
121 // |
|
122 { |
|
123 |
|
124 if (aAmplitude>(1<<15)) |
|
125 iAmplitude=(1<<15); |
|
126 else if (aAmplitude<-(1<<15)) |
|
127 iAmplitude=-(1<<15); |
|
128 else |
|
129 iAmplitude=aAmplitude; |
|
130 // |
|
131 // There are 256 entries in the sine table to traverse 360 degrees. |
|
132 // The codec requires samples at a rate of 8000 per second. |
|
133 // Thus for a 1Hz tone the step will be 256/8000 or 4/125. |
|
134 // Now we need need the integer part of the result to end up in |
|
135 // the MSB so we need to multiply by 2^24. This gives the formula |
|
136 // step = (f*4*2^24)/125 or (f*2^26)/125. |
|
137 // Our highest frequency is 4KHz so that the term (f*2^26) exceeds |
|
138 // a 32 bit result by 4000/2^6 (2^6 is the number of significant bits |
|
139 // left after a multiply by 2^26). i.e. 6 bits. We overcome this by |
|
140 // having 6 bits less in the fraction, so the new formula becomes |
|
141 // ((f*2^20)/125)*2^6. This still gives us 20 significant bits in the |
|
142 // fraction. |
|
143 // |
|
144 |
|
145 iStep=(((TUint)aFrequency<<20)/125)<<6; |
|
146 iPosition=(aFrequency==4000 ? 0x40000000 : 0); |
|
147 } |
|
148 |
|
149 TInt TSineGen::NextSample() |
|
150 // |
|
151 // Generate the next sample using linear interpolation |
|
152 // |
|
153 { |
|
154 TUint pos=iPosition>>24; |
|
155 TInt amp=((IncTable[pos]*((iPosition&0x00ffffff)>>20))); |
|
156 amp>>=4; |
|
157 amp+=SineTable[pos]; |
|
158 amp=(amp*iAmplitude)>>15; |
|
159 iPosition+=iStep; |
|
160 return(amp); |
|
161 } |
|
162 |
|
163 void TSineWave::Generate(TInt16* aDest,TInt aCount) |
|
164 // |
|
165 // Called when more samples need to be generated. |
|
166 // |
|
167 { |
|
168 while (aCount--) |
|
169 { |
|
170 *aDest++=STATIC_CAST(TInt16,iGen1.NextSample()+iGen2.NextSample()); |
|
171 } |
|
172 } |
|
173 |
|
174 void TSineWave::SetFrequency(TInt aFrequency,TInt aAmplitude) |
|
175 // |
|
176 // Set to generate a single frequency |
|
177 // |
|
178 { |
|
179 SetFrequency(aFrequency,aAmplitude,0,0); |
|
180 } |
|
181 |
|
182 void TSineWave::SetFrequency(TInt aFrequency1,TInt aAmplitude1,TInt aFrequency2,TInt aAmplitude2) |
|
183 // |
|
184 // Set to generate two frequencies |
|
185 // |
|
186 { |
|
187 iGen1.SetFrequency(aFrequency1,aAmplitude1); |
|
188 iGen2.SetFrequency(aFrequency2,aAmplitude2); |
|
189 } |
|
190 |
|
191 |
|
192 // |
|
193 // TMdaToneGenerator |
|
194 // |
|
195 |
|
196 void TMdaToneGenerator::Configure(TInt aRate, TInt aChannels, TInt aRepeats, TInt aSilence, TInt aRampUp) |
|
197 // |
|
198 // Set up this tone generator to generate data at the desired sample rate |
|
199 // and number of channels (typically mono/stereo) |
|
200 // |
|
201 { |
|
202 iRate = aRate; |
|
203 iChannels = aChannels; |
|
204 iSamplesLeft = 0; |
|
205 iRampUp = ETrue; // Default ramping to on as it is normally useful |
|
206 iRampDown = ETrue; |
|
207 iRepeats = aRepeats; |
|
208 iSilenceBetweenRepeats = aSilence; |
|
209 iRampUpCount = aRampUp; |
|
210 iRampUpLeft = aRampUp; |
|
211 iAfterRepeatSilence = EFalse; |
|
212 } |
|
213 |
|
214 LOCAL_C void RampVolume(TInt16* aData,TInt aCount,TInt aStartVol,TInt aEndVol) |
|
215 // |
|
216 // Simple function to ramp down the volume of some samples |
|
217 // Typically used to prevent "clicking" artifacts at the beginning/end of tones |
|
218 // |
|
219 { |
|
220 TInt step = (aEndVol - aStartVol)/aCount; |
|
221 while (aCount--) |
|
222 { |
|
223 TInt data = TInt(*aData) * aStartVol; |
|
224 *aData++ = TInt16(data>>15); |
|
225 aStartVol += step; |
|
226 } |
|
227 } |
|
228 |
|
229 TInt TMdaToneGenerator::FillBuffer(TDes8& aBuffer) |
|
230 // |
|
231 // Fill the supplied buffer with tone data |
|
232 // Sets the buffer length to zero if there is no more data to play |
|
233 // The buffer must have a max length of at least one sample * channels |
|
234 // e.g. 2 bytes mono, 4 bytes stereo |
|
235 // |
|
236 { |
|
237 ASSERT(aBuffer.MaxLength()>= (iChannels<<1)); |
|
238 aBuffer.SetMax(); |
|
239 |
|
240 TBool silence; |
|
241 TInt samples = 0; // |
|
242 TInt used = 0; // Data used |
|
243 TInt avail = aBuffer.Length(); // Data filled |
|
244 TInt count = 0; // Data to be converted |
|
245 TBool rampUp = EFalse; |
|
246 |
|
247 TMdaPtr8 fill; |
|
248 fill.Set(aBuffer); // Pointer to data left to be filled |
|
249 |
|
250 // |
|
251 // The rest of this function will loop around continually until the buffer |
|
252 // is filled or there is no more data to play |
|
253 // |
|
254 |
|
255 Restart: |
|
256 silence = EFalse; // Reset |
|
257 if (iSamplesLeft == 0) |
|
258 { |
|
259 if (iTrailingSilence == 0) |
|
260 { |
|
261 TInt error = GetNextTone(); |
|
262 if (error) |
|
263 return error; |
|
264 |
|
265 rampUp = ETrue; |
|
266 if ((iSamplesLeft==0)&&(iTrailingSilence==0)) |
|
267 { |
|
268 if ((iSilenceBetweenRepeats)&&(!iAfterRepeatSilence)) |
|
269 { |
|
270 iTrailingSilence = iSilenceBetweenRepeats; |
|
271 iAfterRepeatSilence = ETrue; |
|
272 goto Restart; |
|
273 } |
|
274 else |
|
275 { |
|
276 if ((iRepeats>0)||(iRepeats==KMdaRepeatForever)) |
|
277 { |
|
278 iAfterRepeatSilence = EFalse; |
|
279 if (iRepeats>0) |
|
280 iRepeats--; |
|
281 |
|
282 Reset(); |
|
283 goto Restart; |
|
284 } |
|
285 } |
|
286 // No more to play |
|
287 goto Finished; |
|
288 } |
|
289 goto Restart; |
|
290 } |
|
291 else |
|
292 { |
|
293 silence = ETrue; |
|
294 samples = iTrailingSilence; |
|
295 } |
|
296 } |
|
297 else |
|
298 samples = iSamplesLeft; |
|
299 |
|
300 count = Min(samples,avail>>1); |
|
301 fill.SetLength(count<<1); |
|
302 |
|
303 if (!silence) |
|
304 { // Generate wave |
|
305 iSineWave.Generate(REINTERPRET_CAST(TInt16*,&fill[0]),count); |
|
306 if (iRampUp) |
|
307 { // Ramp up volume at beginning of tone |
|
308 const TInt KRampUpSamples = 50; |
|
309 if (rampUp) |
|
310 { // Fade in first few samples |
|
311 TInt fadeInLength = Min(Min(KRampUpSamples,iSamplesLeft),(fill.Length()>>1)); |
|
312 RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&fill[0]))),fadeInLength,0,1<<15); |
|
313 } |
|
314 } |
|
315 if (iRampDown) |
|
316 { // Ramp down volume at end of tone |
|
317 const TInt KRampDownSamples = 50; |
|
318 if ((iSamplesLeft-count) < KRampDownSamples) |
|
319 { // Fade out last few samples |
|
320 TInt fadeOutLength = Min(Min(KRampDownSamples,iSamplesLeft),(fill.Length()>>1)); |
|
321 RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&(fill.Right(fadeOutLength<<1))[0]))),fadeOutLength,1<<15,0); |
|
322 } |
|
323 } |
|
324 iSamplesLeft -= count; |
|
325 } |
|
326 else |
|
327 { // Generate silence |
|
328 fill.FillZ(count<<1); |
|
329 iTrailingSilence -= count; |
|
330 } |
|
331 |
|
332 used += count<<1; |
|
333 avail -= count<<1; |
|
334 fill.Shift(count<<1); |
|
335 |
|
336 if (avail>(iChannels<<1)) |
|
337 goto Restart; |
|
338 |
|
339 Finished: |
|
340 |
|
341 aBuffer.SetLength(used); |
|
342 |
|
343 // Do any ramp up that is required |
|
344 if (iRampUpLeft>0) |
|
345 { |
|
346 TInt words = iRampUpLeft * iChannels; |
|
347 words = Min(words,used>>1); |
|
348 if (words>0) // In case buffer has zero length... |
|
349 { |
|
350 TInt left = iRampUpLeft * iChannels; |
|
351 TInt rampup = iRampUpCount * iChannels; |
|
352 iRampUpLeft -= words/iChannels; |
|
353 TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer[0]); |
|
354 while (words--) |
|
355 { |
|
356 *sample++ = STATIC_CAST(TInt16,(TInt32(*sample)*(rampup-(left--)))/rampup); |
|
357 } |
|
358 } |
|
359 } |
|
360 |
|
361 return KErrNone; |
|
362 } |
|
363 |
|
364 TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration) |
|
365 // |
|
366 // Convert the given duration to a sample count using the current settings |
|
367 // |
|
368 { |
|
369 const TInt64 KTInt64OneMilion = 1000000; |
|
370 |
|
371 // Calculate duration as samples |
|
372 TInt64 microSeconds(aDuration.Int64()); // MSVC doesn't like "aDuration.Int64()" in line below |
|
373 TInt64 dur = ((TInt64(iRate) * TInt64(iChannels) * microSeconds) / KTInt64OneMilion); |
|
374 if (I64HIGH(dur)>0) |
|
375 return KMaxTInt; // Ridiculous! |
|
376 else |
|
377 return I64LOW(dur); |
|
378 } |
|
379 |
|
380 // |
|
381 // TMdaSimpleToneGenerator |
|
382 // |
|
383 |
|
384 void TMdaSimpleToneGenerator::Reset() |
|
385 { |
|
386 iPlayed = EFalse; |
|
387 } |
|
388 |
|
389 void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration) |
|
390 // |
|
391 // Store the frequency and duration of the specified sine tone |
|
392 // |
|
393 { |
|
394 iFrequency = aFrequency; |
|
395 iDuration = aDuration; |
|
396 iPlayed = EFalse; |
|
397 } |
|
398 |
|
399 TInt TMdaSimpleToneGenerator::GetNextTone() |
|
400 // |
|
401 // Simple implementation - just sets the supplied frequency and duration |
|
402 // |
|
403 { |
|
404 // This class only plays one tone for the specified duration |
|
405 if (!iPlayed) |
|
406 { |
|
407 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000); |
|
408 iSineWave.SetFrequency(iFrequency,1<<14); |
|
409 iPlayed = ETrue; |
|
410 iTrailingSilence = 20; // Just to stop clicking |
|
411 } |
|
412 return KErrNone; |
|
413 } |
|
414 |
|
415 // |
|
416 // TMdaDualToneGenerator |
|
417 // |
|
418 |
|
419 void TMdaDualToneGenerator::Reset() |
|
420 { |
|
421 iPlayed = EFalse; |
|
422 } |
|
423 |
|
424 void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration) |
|
425 { |
|
426 // Store the frequencies and duration of the specified dual tone |
|
427 iFrequencyOne = aFrequencyOne; |
|
428 iFrequencyTwo = aFrequencyTwo; |
|
429 iDuration = aDuration; |
|
430 iPlayed = EFalse; |
|
431 } |
|
432 |
|
433 // |
|
434 // This is called by TMdaToneGenerator::FillBuffer() |
|
435 // to calculate the number of samples (iSamplesLeft) that will be needed |
|
436 // for the tone to be played and to initialize the sine wave generator. |
|
437 // If the tone has already been played, then leaves iSamplesLeft |
|
438 // unmodified (should be zero) to indicate that it has finished. |
|
439 // |
|
440 TInt TMdaDualToneGenerator::GetNextTone() |
|
441 { |
|
442 // This class only plays one tone for the specified duration |
|
443 if (!iPlayed) |
|
444 { |
|
445 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds); |
|
446 iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2); |
|
447 iPlayed = ETrue; |
|
448 iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking |
|
449 } |
|
450 return KErrNone; |
|
451 } |
|
452 // |
|
453 // TMdaDTMFGenerator |
|
454 // |
|
455 |
|
456 const TInt KRecalculateToneLengths = KMinTInt; |
|
457 |
|
458 void TMdaDTMFGenerator::Reset() |
|
459 { |
|
460 iChar = 0; |
|
461 } |
|
462 |
|
463 void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn, |
|
464 const TTimeIntervalMicroSeconds32 aOff, |
|
465 const TTimeIntervalMicroSeconds32 aPause) |
|
466 // |
|
467 // Setup the DTMF tone durations |
|
468 // aOn can be == -1 indicating should play first tone indefinately |
|
469 // |
|
470 { |
|
471 ASSERT(aOn.Int() >=-1); |
|
472 ASSERT(aOff.Int()>=0); |
|
473 ASSERT(aPause.Int()>=0); |
|
474 |
|
475 iOn = aOn; |
|
476 iOff = aOff; |
|
477 iPause = aPause; |
|
478 |
|
479 iOnSamples = KRecalculateToneLengths; // Must recalculate these later |
|
480 } |
|
481 |
|
482 void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString) |
|
483 // |
|
484 // Store the DTMF string to be played |
|
485 // No need to validate it as it will already have been checked |
|
486 // |
|
487 { |
|
488 iChar = 0; |
|
489 iDTMFString = &aDTMFString; |
|
490 } |
|
491 |
|
492 const TUint8 KDtmfVolumeTable[4][4]= |
|
493 // |
|
494 // Relative strengths to assign to different DTMF tones |
|
495 // |
|
496 // This is only important if DTMFs are being played through a speaker |
|
497 // and need to be machine-recognisable. This table compensates for frequency |
|
498 // drop-off in the speaker and can boost the relative volume of some |
|
499 // frequencies so they are still within tolerance. |
|
500 // |
|
501 // The values normally need to be determined using a frequency analyser on |
|
502 // the hardware |
|
503 // |
|
504 // Each column == same low frequency (697, 770, 852, 941 Hz) |
|
505 // Each row == same high frequency (1209, 1336, 1477, 1633 Hz) |
|
506 // |
|
507 // The value are interpreted as ratios: |
|
508 // 0 == 100% low |
|
509 // 7f == 50% low, 50% high |
|
510 // ff == 100% high |
|
511 // |
|
512 { |
|
513 {38,27,29,37}, |
|
514 {46,36,36,46}, |
|
515 {62,47,49,58}, |
|
516 {70,56,60,68} |
|
517 }; |
|
518 |
|
519 const TUint8 KDtmfTone697=0x0; |
|
520 const TUint8 KDtmfTone770=0x1; |
|
521 const TUint8 KDtmfTone852=0x2; |
|
522 const TUint8 KDtmfTone941=0x3; |
|
523 |
|
524 const TUint8 KDtmfTone1209=0x00; |
|
525 const TUint8 KDtmfTone1336=0x10; |
|
526 const TUint8 KDtmfTone1477=0x20; |
|
527 const TUint8 KDtmfTone1633=0x30; |
|
528 |
|
529 const TUint8 KDtmfToneTable[16]= |
|
530 { |
|
531 KDtmfTone941|KDtmfTone1336,//0 |
|
532 KDtmfTone697|KDtmfTone1209,//1 |
|
533 KDtmfTone697|KDtmfTone1336,//2 |
|
534 KDtmfTone697|KDtmfTone1477,//3 |
|
535 KDtmfTone770|KDtmfTone1209,//4 |
|
536 KDtmfTone770|KDtmfTone1336,//5 |
|
537 KDtmfTone770|KDtmfTone1477,//6 |
|
538 KDtmfTone852|KDtmfTone1209,//7 |
|
539 KDtmfTone852|KDtmfTone1336,//8 |
|
540 KDtmfTone852|KDtmfTone1477,//9 |
|
541 |
|
542 KDtmfTone697|KDtmfTone1633,//A |
|
543 KDtmfTone770|KDtmfTone1633,//B |
|
544 KDtmfTone852|KDtmfTone1633,//C |
|
545 KDtmfTone941|KDtmfTone1633,//D |
|
546 KDtmfTone941|KDtmfTone1209,//E or * |
|
547 KDtmfTone941|KDtmfTone1477,//F or # |
|
548 }; |
|
549 |
|
550 TInt TMdaDTMFGenerator::GetNextTone() |
|
551 // |
|
552 // Setup frequency/duration/silence settings for next DTMF tone |
|
553 // Supported characters are 0-9 A-F * # , and any kind of white space |
|
554 // |
|
555 { |
|
556 TBool onlyPlayFirstTone = EFalse; |
|
557 |
|
558 if (iOnSamples == KRecalculateToneLengths) |
|
559 { |
|
560 // Must recalculate tone durations as samples |
|
561 |
|
562 // Handle special case where tone on duration negative |
|
563 // - meaning play first character indefinately |
|
564 if (iOn.Int()>=0) |
|
565 iOnSamples = DurationToSamples(TInt64(iOn.Int())); |
|
566 else |
|
567 { |
|
568 onlyPlayFirstTone = ETrue; |
|
569 iOnSamples = -1; |
|
570 } |
|
571 |
|
572 iOffSamples = DurationToSamples(TInt64(iOff.Int())); |
|
573 iPauseSamples = DurationToSamples(TInt64(iPause.Int())); |
|
574 } |
|
575 |
|
576 ASSERT(iDTMFString); |
|
577 |
|
578 if (iChar==iDTMFString->Length()) |
|
579 return KErrNone; // Finished. Nothing to do |
|
580 |
|
581 TInt highFrequency = 0; |
|
582 TInt highVolume = 0; |
|
583 TInt lowFrequency = 0; |
|
584 TInt lowVolume =0; |
|
585 |
|
586 Retry: |
|
587 TChar c((*iDTMFString)[iChar++]); |
|
588 if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit()) |
|
589 { |
|
590 TInt tableIndex; |
|
591 switch ((TUint)c) |
|
592 { |
|
593 case '*': |
|
594 tableIndex=14; |
|
595 break; |
|
596 case '#': |
|
597 tableIndex=15; |
|
598 break; |
|
599 default: |
|
600 if (c.IsDigit()) |
|
601 tableIndex=(TUint)c-'0'; |
|
602 else //letter |
|
603 { |
|
604 c.UpperCase(); |
|
605 tableIndex=(TUint)c-'A'+10; |
|
606 } |
|
607 } |
|
608 TInt high=KDtmfToneTable[tableIndex]&0xf0; |
|
609 TInt low=KDtmfToneTable[tableIndex]&0x0f; |
|
610 switch(high) |
|
611 { |
|
612 case KDtmfTone1209: |
|
613 highFrequency=1209; |
|
614 break; |
|
615 case KDtmfTone1336: |
|
616 highFrequency=1336; |
|
617 break; |
|
618 case KDtmfTone1477: |
|
619 highFrequency=1477; |
|
620 break; |
|
621 default://KDtmfTone1633: |
|
622 highFrequency=1633; |
|
623 break; |
|
624 } |
|
625 switch(low) |
|
626 { |
|
627 case KDtmfTone697: |
|
628 lowFrequency=697; |
|
629 break; |
|
630 case KDtmfTone770: |
|
631 lowFrequency=770; |
|
632 break; |
|
633 case KDtmfTone852: |
|
634 lowFrequency=852; |
|
635 break; |
|
636 default://KDtmfTone941: |
|
637 lowFrequency=941; |
|
638 break; |
|
639 } |
|
640 high>>=4; |
|
641 const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0]; |
|
642 TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7; |
|
643 highVolume = volume; |
|
644 lowVolume = (1<<15)-volume; |
|
645 |
|
646 iTrailingSilence = iOffSamples; |
|
647 iSamplesLeft = iOnSamples; |
|
648 } |
|
649 else if ((TUint)c==',') |
|
650 { |
|
651 iTrailingSilence = iPauseSamples; |
|
652 iSamplesLeft = 0; |
|
653 } |
|
654 else if (c.IsSpace()) |
|
655 { |
|
656 if (iChar < iDTMFString->Length()) |
|
657 goto Retry; |
|
658 } |
|
659 else |
|
660 return KErrCorrupt; |
|
661 |
|
662 if (iOnSamples < 0) // Play only first character for ever |
|
663 { |
|
664 iTrailingSilence = 0; |
|
665 iSamplesLeft = iRate * iChannels; // One second of samples |
|
666 iChar = 0; // Reset so this character is played again next time |
|
667 iRampDown = EFalse; |
|
668 if (!onlyPlayFirstTone) |
|
669 { |
|
670 iRampUp = EFalse; |
|
671 // This is not the first time around so we should not |
|
672 // reset the tone generator - it will already have the |
|
673 // correct settings and setting them again would cause |
|
674 // an audible discontinuity |
|
675 return KErrNone; |
|
676 } |
|
677 } |
|
678 |
|
679 iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume); |
|
680 return KErrNone; |
|
681 } |
|
682 |
|
683 // |
|
684 // TMdaSequenceGenerator |
|
685 // |
|
686 |
|
687 // |
|
688 // Sequence constants |
|
689 // |
|
690 |
|
691 //const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2 |
|
692 #ifdef _DEBUG |
|
693 const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8); |
|
694 const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8); |
|
695 #endif // _DEBUG |
|
696 |
|
697 const TInt KFixedSequenceFunctionReturn=-1; |
|
698 const TInt KFixedSequenceFunctionStartLoop=-2; |
|
699 const TInt KFixedSequenceFunctionEndLoop=-3; |
|
700 |
|
701 void TMdaSequenceGenerator::Reset() |
|
702 { |
|
703 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0])); |
|
704 iInstructionPtr += 2; // Skip signature |
|
705 iStackIndex = 0; |
|
706 } |
|
707 |
|
708 void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData) |
|
709 // |
|
710 // Store the sequence data to be played |
|
711 // No need to validate it as it will already have been checked |
|
712 // |
|
713 { |
|
714 iSequenceData = &aSequenceData; |
|
715 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]); |
|
716 iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1; |
|
717 |
|
718 // These are asserts because this should not be called if signature not present |
|
719 ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne); |
|
720 ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo); |
|
721 |
|
722 iInstructionPtr += 2; // Skip signature |
|
723 |
|
724 iStackIndex = 0; |
|
725 } |
|
726 |
|
727 TInt TMdaSequenceGenerator::GetNextTone() |
|
728 // |
|
729 // |
|
730 { |
|
731 ASSERT(iInstructionPtr); // Sanity check |
|
732 |
|
733 TInt ret = KRequestPending; |
|
734 while (ret == KRequestPending) |
|
735 { |
|
736 if (iInstructionPtr > iLastInstruction) |
|
737 ret = KErrCorrupt; |
|
738 else if (*iInstructionPtr<=0) |
|
739 { |
|
740 switch (*iInstructionPtr) |
|
741 { |
|
742 case KFixedSequenceFunctionReturn: // End of sequence |
|
743 ret = KErrNone; |
|
744 break; |
|
745 |
|
746 case KFixedSequenceFunctionStartLoop: |
|
747 if (iStackIndex>2) // Validate - can only nest twice |
|
748 ret = KErrCorrupt; |
|
749 else if ((iInstructionPtr+2) > iLastInstruction) |
|
750 ret = KErrCorrupt; // Don't run off end of sequence |
|
751 else |
|
752 { |
|
753 iStack[iStackIndex++]=(TInt)(iInstructionPtr+2); |
|
754 iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1); |
|
755 iInstructionPtr+=2; |
|
756 } |
|
757 break; |
|
758 |
|
759 case KFixedSequenceFunctionEndLoop: |
|
760 if (iStackIndex==0) // Validate - must already be nested |
|
761 ret = KErrCorrupt; |
|
762 else |
|
763 { |
|
764 if ((--iStack[iStackIndex-1])!=0) |
|
765 iInstructionPtr=(TInt16*)iStack[iStackIndex-2]; |
|
766 else |
|
767 { |
|
768 iStackIndex-=2; |
|
769 iInstructionPtr++; |
|
770 } |
|
771 } |
|
772 break; |
|
773 |
|
774 default: // Bad sequence |
|
775 ret = KErrCorrupt; |
|
776 } |
|
777 } |
|
778 else |
|
779 { |
|
780 if ((iInstructionPtr+5) > iLastInstruction) |
|
781 ret = KErrCorrupt; // Don't run off end of sequence |
|
782 else |
|
783 { |
|
784 iSamplesLeft = *iInstructionPtr++; |
|
785 TInt freqOne = *iInstructionPtr++; |
|
786 TInt volOne = *iInstructionPtr++; |
|
787 TInt freqTwo = *iInstructionPtr++; |
|
788 TInt volTwo = *iInstructionPtr++; |
|
789 |
|
790 if ((volOne> 1<<15)||(volTwo > 1<<15)) |
|
791 ret = KErrCorrupt; |
|
792 else |
|
793 { |
|
794 iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo); |
|
795 ret = KErrNone; |
|
796 } |
|
797 } |
|
798 } |
|
799 } |
|
800 return ret; |
|
801 } |
|
802 |
|
803 // --------------------------------- |
|
804 // Code to generate sine table files used by tone generator |
|
805 // Optionally called from InitL() |
|
806 // #define GENERATE_SINE_TABLES 1 |
|
807 #ifdef GENERATE_SINE_TABLES |
|
808 LOCAL_C GenerateSineTableL() |
|
809 { |
|
810 _LIT(KSineFile,"sine.txt"); |
|
811 _LIT(KSineIncFile,"sineinc.txt"); |
|
812 |
|
813 RFile file; |
|
814 file.Replace(MdaManager::Fs(),KSineFile,EFileWrite); |
|
815 CleanupClosePushL(file); |
|
816 |
|
817 RFile file2; |
|
818 file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite); |
|
819 CleanupClosePushL(file2); |
|
820 |
|
821 const TReal pi=3.141592653589; |
|
822 const TReal twopi=pi*2; |
|
823 const TReal samples = 256.0; |
|
824 const TReal step = twopi/samples; |
|
825 |
|
826 TBuf8<128> sinebuffer; |
|
827 TBuf8<128> incbuffer; |
|
828 TReal res; |
|
829 TInt first=0; |
|
830 TInt last=KMaxTInt; |
|
831 TInt current; |
|
832 _LIT8(KFormat,"%6d,"); |
|
833 _LIT8(KNewLine,"\n"); |
|
834 |
|
835 for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors |
|
836 { |
|
837 sinebuffer.Zero(); |
|
838 incbuffer.Zero(); |
|
839 for (int i=0;i<8;i++) |
|
840 { |
|
841 User::LeaveIfError(Math::Sin(res,angle)); |
|
842 current = TInt(KMaxTInt16*res); |
|
843 sinebuffer.AppendFormat(KFormat,current); |
|
844 if (last != KMaxTInt) |
|
845 incbuffer.AppendFormat(KFormat,current-last); |
|
846 else |
|
847 first = current; |
|
848 last = current; |
|
849 angle += step; |
|
850 } |
|
851 sinebuffer.Append(KNewLine); |
|
852 incbuffer.Append(KNewLine); |
|
853 file.Write(sinebuffer); |
|
854 file2.Write(incbuffer); |
|
855 } |
|
856 |
|
857 // Write fine difference to incbuffer - differnece between first and last |
|
858 incbuffer.Zero(); |
|
859 incbuffer.AppendFormat(KFormat,first-last); |
|
860 incbuffer.Append(KNewLine); |
|
861 file2.Write(incbuffer); |
|
862 |
|
863 CleanupStack::PopAndDestroy(2); |
|
864 } |
|
865 #endif |
|
866 //------------------------------- |