1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/SoundDevice/BtToneGenerator.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,866 @@
1.4 +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// This file contains an implementation of the ToneGenerator interface
1.18 +// that converts all tone generation requests in to sampled audio
1.19 +// data to be played through the normal local sampled audio interface
1.20 +//
1.21 +//
1.22 +
1.23 +#include "BtToneGenerator.h"
1.24 +
1.25 +#include <e32math.h>
1.26 +#include <mda/common/resource.h>
1.27 +
1.28 +/******************************************************************************
1.29 +* Tone Generators
1.30 +*
1.31 +* The following classes are used to generate simple frequency/duration tones,
1.32 +* DTMF, and SymbianOS tone sequences in a WINS environment. The below code
1.33 +* should only be considered for WINS.
1.34 +******************************************************************************/
1.35 +
1.36 +// this defines the maximum possible amplitude allowed for TSineGen::SetFrequency()
1.37 +const TInt KMaxAmplitude = 0x8000;
1.38 +
1.39 +// default number of samples for trailing silence following a Tone
1.40 +const TInt KDefaultTrailingSilenceSamples = 20;
1.41 +
1.42 +//
1.43 +// Sine tone generator
1.44 +//
1.45 +
1.46 +const TInt16 TSineGen::SineTable[KMaxSineTable] =
1.47 + {
1.48 + 0, 804, 1607, 2410, 3211, 4011, 4807, 5601,
1.49 + 6392, 7179, 7961, 8739, 9511, 10278, 11038, 11792,
1.50 + 12539, 13278, 14009, 14732, 15446, 16150, 16845, 17530,
1.51 + 18204, 18867, 19519, 20159, 20787, 21402, 22004, 22594,
1.52 + 23169, 23731, 24278, 24811, 25329, 25831, 26318, 26789,
1.53 + 27244, 27683, 28105, 28510, 28897, 29268, 29621, 29955,
1.54 + 30272, 30571, 30851, 31113, 31356, 31580, 31785, 31970,
1.55 + 32137, 32284, 32412, 32520, 32609, 32678, 32727, 32757,
1.56 + 32767, 32757, 32727, 32678, 32609, 32520, 32412, 32284,
1.57 + 32137, 31970, 31785, 31580, 31356, 31113, 30851, 30571,
1.58 + 30272, 29955, 29621, 29268, 28897, 28510, 28105, 27683,
1.59 + 27244, 26789, 26318, 25831, 25329, 24811, 24278, 23731,
1.60 + 23169, 22594, 22004, 21402, 20787, 20159, 19519, 18867,
1.61 + 18204, 17530, 16845, 16150, 15446, 14732, 14009, 13278,
1.62 + 12539, 11792, 11038, 10278, 9511, 8739, 7961, 7179,
1.63 + 6392, 5601, 4807, 4011, 3211, 2410, 1607, 804,
1.64 + 0, -804, -1607, -2410, -3211, -4011, -4807, -5601,
1.65 + -6392, -7179, -7961, -8739, -9511,-10278,-11038,-11792,
1.66 + -12539,-13278,-14009,-14732,-15446,-16150,-16845,-17530,
1.67 + -18204,-18867,-19519,-20159,-20787,-21402,-22004,-22594,
1.68 + -23169,-23731,-24278,-24811,-25329,-25831,-26318,-26789,
1.69 + -27244,-27683,-28105,-28510,-28897,-29268,-29621,-29955,
1.70 + -30272,-30571,-30851,-31113,-31356,-31580,-31785,-31970,
1.71 + -32137,-32284,-32412,-32520,-32609,-32678,-32727,-32757,
1.72 + -32767,-32757,-32727,-32678,-32609,-32520,-32412,-32284,
1.73 + -32137,-31970,-31785,-31580,-31356,-31113,-30851,-30571,
1.74 + -30272,-29955,-29621,-29268,-28897,-28510,-28105,-27683,
1.75 + -27244,-26789,-26318,-25831,-25329,-24811,-24278,-23731,
1.76 + -23169,-22594,-22004,-21402,-20787,-20159,-19519,-18867,
1.77 + -18204,-17530,-16845,-16150,-15446,-14732,-14009,-13278,
1.78 + -12539,-11792,-11038,-10278, -9511, -8739, -7961, -7179,
1.79 + -6392, -5601, -4807, -4011, -3211, -2410, -1607, -804,
1.80 + };
1.81 +
1.82 +const TInt16 TSineGen::IncTable[KMaxSineTable] =
1.83 + {
1.84 + 804, 803, 803, 801, 800, 796, 794,
1.85 + 791, 787, 782, 778, 772, 767, 760, 754,
1.86 + 747, 739, 731, 723, 714, 704, 695, 685,
1.87 + 674, 663, 652, 640, 628, 615, 602, 590,
1.88 + 575, 562, 547, 533, 518, 502, 487, 471,
1.89 + 455, 439, 422, 405, 387, 371, 353, 334,
1.90 + 317, 299, 280, 262, 243, 224, 205, 185,
1.91 + 167, 147, 128, 108, 89, 69, 49, 30,
1.92 + 10, -10, -30, -49, -69, -89, -108, -128,
1.93 + -147, -167, -185, -205, -224, -243, -262, -280,
1.94 + -299, -317, -334, -353, -371, -387, -405, -422,
1.95 + -439, -455, -471, -487, -502, -518, -533, -547,
1.96 + -562, -575, -590, -602, -615, -628, -640, -652,
1.97 + -663, -674, -685, -695, -704, -714, -723, -731,
1.98 + -739, -747, -754, -760, -767, -772, -778, -782,
1.99 + -787, -791, -794, -796, -800, -801, -803, -803,
1.100 + -804, -804, -803, -803, -801, -800, -796, -794,
1.101 + -791, -787, -782, -778, -772, -767, -760, -754,
1.102 + -747, -739, -731, -723, -714, -704, -695, -685,
1.103 + -674, -663, -652, -640, -628, -615, -602, -590,
1.104 + -575, -562, -547, -533, -518, -502, -487, -471,
1.105 + -455, -439, -422, -405, -387, -371, -353, -334,
1.106 + -317, -299, -280, -262, -243, -224, -205, -185,
1.107 + -167, -147, -128, -108, -89, -69, -49, -30,
1.108 + -10, 10, 30, 49, 69, 89, 108, 128,
1.109 + 147, 167, 185, 205, 224, 243, 262, 280,
1.110 + 299, 317, 334, 353, 371, 387, 405, 422,
1.111 + 439, 455, 471, 487, 502, 518, 533, 547,
1.112 + 562, 575, 590, 602, 615, 628, 640, 652,
1.113 + 663, 674, 685, 695, 704, 714, 723, 731,
1.114 + 739, 747, 754, 760, 767, 772, 778, 782,
1.115 + 787, 791, 794, 796, 800, 801, 803, 803,
1.116 + 804
1.117 + };
1.118 +
1.119 +void TSineGen::SetFrequency(TInt aFrequency,TInt aAmplitude)
1.120 +//
1.121 +// Given the frequency set iStep.
1.122 +// Reset iPosition to the equivalent of 0 degrees.
1.123 +// In the special case of aFrequency==4KHz set iPosition to 90 degrees.
1.124 +//
1.125 + {
1.126 +
1.127 + if (aAmplitude>(1<<15))
1.128 + iAmplitude=(1<<15);
1.129 + else if (aAmplitude<-(1<<15))
1.130 + iAmplitude=-(1<<15);
1.131 + else
1.132 + iAmplitude=aAmplitude;
1.133 +//
1.134 +// There are 256 entries in the sine table to traverse 360 degrees.
1.135 +// The codec requires samples at a rate of 8000 per second.
1.136 +// Thus for a 1Hz tone the step will be 256/8000 or 4/125.
1.137 +// Now we need need the integer part of the result to end up in
1.138 +// the MSB so we need to multiply by 2^24. This gives the formula
1.139 +// step = (f*4*2^24)/125 or (f*2^26)/125.
1.140 +// Our highest frequency is 4KHz so that the term (f*2^26) exceeds
1.141 +// a 32 bit result by 4000/2^6 (2^6 is the number of significant bits
1.142 +// left after a multiply by 2^26). i.e. 6 bits. We overcome this by
1.143 +// having 6 bits less in the fraction, so the new formula becomes
1.144 +// ((f*2^20)/125)*2^6. This still gives us 20 significant bits in the
1.145 +// fraction.
1.146 +//
1.147 +
1.148 + iStep=(((TUint)aFrequency<<20)/125)<<6;
1.149 + iPosition=(aFrequency==4000 ? 0x40000000 : 0);
1.150 + }
1.151 +
1.152 +TInt TSineGen::NextSample()
1.153 +//
1.154 +// Generate the next sample using linear interpolation
1.155 +//
1.156 + {
1.157 + TUint pos=iPosition>>24;
1.158 + TInt amp=((IncTable[pos]*((iPosition&0x00ffffff)>>20)));
1.159 + amp>>=4;
1.160 + amp+=SineTable[pos];
1.161 + amp=(amp*iAmplitude)>>15;
1.162 + iPosition+=iStep;
1.163 + return(amp);
1.164 + }
1.165 +
1.166 +void TSineWave::Generate(TInt16* aDest,TInt aCount)
1.167 +//
1.168 +// Called when more samples need to be generated.
1.169 +//
1.170 + {
1.171 + while (aCount--)
1.172 + {
1.173 + *aDest++=STATIC_CAST(TInt16,iGen1.NextSample()+iGen2.NextSample());
1.174 + }
1.175 + }
1.176 +
1.177 +void TSineWave::SetFrequency(TInt aFrequency,TInt aAmplitude)
1.178 +//
1.179 +// Set to generate a single frequency
1.180 +//
1.181 + {
1.182 + SetFrequency(aFrequency,aAmplitude,0,0);
1.183 + }
1.184 +
1.185 +void TSineWave::SetFrequency(TInt aFrequency1,TInt aAmplitude1,TInt aFrequency2,TInt aAmplitude2)
1.186 +//
1.187 +// Set to generate two frequencies
1.188 +//
1.189 + {
1.190 + iGen1.SetFrequency(aFrequency1,aAmplitude1);
1.191 + iGen2.SetFrequency(aFrequency2,aAmplitude2);
1.192 + }
1.193 +
1.194 +
1.195 +//
1.196 +// TMdaToneGenerator
1.197 +//
1.198 +
1.199 +void TMdaToneGenerator::Configure(TInt aRate, TInt aChannels, TInt aRepeats, TInt aSilence, TInt aRampUp)
1.200 +//
1.201 +// Set up this tone generator to generate data at the desired sample rate
1.202 +// and number of channels (typically mono/stereo)
1.203 +//
1.204 + {
1.205 + iRate = aRate;
1.206 + iChannels = aChannels;
1.207 + iSamplesLeft = 0;
1.208 + iRampUp = ETrue; // Default ramping to on as it is normally useful
1.209 + iRampDown = ETrue;
1.210 + iRepeats = aRepeats;
1.211 + iSilenceBetweenRepeats = aSilence;
1.212 + iRampUpCount = aRampUp;
1.213 + iRampUpLeft = aRampUp;
1.214 + iAfterRepeatSilence = EFalse;
1.215 + }
1.216 +
1.217 +LOCAL_C void RampVolume(TInt16* aData,TInt aCount,TInt aStartVol,TInt aEndVol)
1.218 +//
1.219 +// Simple function to ramp down the volume of some samples
1.220 +// Typically used to prevent "clicking" artifacts at the beginning/end of tones
1.221 +//
1.222 + {
1.223 + TInt step = (aEndVol - aStartVol)/aCount;
1.224 + while (aCount--)
1.225 + {
1.226 + TInt data = TInt(*aData) * aStartVol;
1.227 + *aData++ = TInt16(data>>15);
1.228 + aStartVol += step;
1.229 + }
1.230 + }
1.231 +
1.232 +TInt TMdaToneGenerator::FillBuffer(TDes8& aBuffer)
1.233 +//
1.234 +// Fill the supplied buffer with tone data
1.235 +// Sets the buffer length to zero if there is no more data to play
1.236 +// The buffer must have a max length of at least one sample * channels
1.237 +// e.g. 2 bytes mono, 4 bytes stereo
1.238 +//
1.239 + {
1.240 + ASSERT(aBuffer.MaxLength()>= (iChannels<<1));
1.241 + aBuffer.SetMax();
1.242 +
1.243 + TBool silence;
1.244 + TInt samples = 0; //
1.245 + TInt used = 0; // Data used
1.246 + TInt avail = aBuffer.Length(); // Data filled
1.247 + TInt count = 0; // Data to be converted
1.248 + TBool rampUp = EFalse;
1.249 +
1.250 + TMdaPtr8 fill;
1.251 + fill.Set(aBuffer); // Pointer to data left to be filled
1.252 +
1.253 + //
1.254 + // The rest of this function will loop around continually until the buffer
1.255 + // is filled or there is no more data to play
1.256 + //
1.257 +
1.258 +Restart:
1.259 + silence = EFalse; // Reset
1.260 + if (iSamplesLeft == 0)
1.261 + {
1.262 + if (iTrailingSilence == 0)
1.263 + {
1.264 + TInt error = GetNextTone();
1.265 + if (error)
1.266 + return error;
1.267 +
1.268 + rampUp = ETrue;
1.269 + if ((iSamplesLeft==0)&&(iTrailingSilence==0))
1.270 + {
1.271 + if ((iSilenceBetweenRepeats)&&(!iAfterRepeatSilence))
1.272 + {
1.273 + iTrailingSilence = iSilenceBetweenRepeats;
1.274 + iAfterRepeatSilence = ETrue;
1.275 + goto Restart;
1.276 + }
1.277 + else
1.278 + {
1.279 + if ((iRepeats>0)||(iRepeats==KMdaRepeatForever))
1.280 + {
1.281 + iAfterRepeatSilence = EFalse;
1.282 + if (iRepeats>0)
1.283 + iRepeats--;
1.284 +
1.285 + Reset();
1.286 + goto Restart;
1.287 + }
1.288 + }
1.289 + // No more to play
1.290 + goto Finished;
1.291 + }
1.292 + goto Restart;
1.293 + }
1.294 + else
1.295 + {
1.296 + silence = ETrue;
1.297 + samples = iTrailingSilence;
1.298 + }
1.299 + }
1.300 + else
1.301 + samples = iSamplesLeft;
1.302 +
1.303 + count = Min(samples,avail>>1);
1.304 + fill.SetLength(count<<1);
1.305 +
1.306 + if (!silence)
1.307 + { // Generate wave
1.308 + iSineWave.Generate(REINTERPRET_CAST(TInt16*,&fill[0]),count);
1.309 + if (iRampUp)
1.310 + { // Ramp up volume at beginning of tone
1.311 + const TInt KRampUpSamples = 50;
1.312 + if (rampUp)
1.313 + { // Fade in first few samples
1.314 + TInt fadeInLength = Min(Min(KRampUpSamples,iSamplesLeft),(fill.Length()>>1));
1.315 + RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&fill[0]))),fadeInLength,0,1<<15);
1.316 + }
1.317 + }
1.318 + if (iRampDown)
1.319 + { // Ramp down volume at end of tone
1.320 + const TInt KRampDownSamples = 50;
1.321 + if ((iSamplesLeft-count) < KRampDownSamples)
1.322 + { // Fade out last few samples
1.323 + TInt fadeOutLength = Min(Min(KRampDownSamples,iSamplesLeft),(fill.Length()>>1));
1.324 + RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&(fill.Right(fadeOutLength<<1))[0]))),fadeOutLength,1<<15,0);
1.325 + }
1.326 + }
1.327 + iSamplesLeft -= count;
1.328 + }
1.329 + else
1.330 + { // Generate silence
1.331 + fill.FillZ(count<<1);
1.332 + iTrailingSilence -= count;
1.333 + }
1.334 +
1.335 + used += count<<1;
1.336 + avail -= count<<1;
1.337 + fill.Shift(count<<1);
1.338 +
1.339 + if (avail>(iChannels<<1))
1.340 + goto Restart;
1.341 +
1.342 +Finished:
1.343 +
1.344 + aBuffer.SetLength(used);
1.345 +
1.346 + // Do any ramp up that is required
1.347 + if (iRampUpLeft>0)
1.348 + {
1.349 + TInt words = iRampUpLeft * iChannels;
1.350 + words = Min(words,used>>1);
1.351 + if (words>0) // In case buffer has zero length...
1.352 + {
1.353 + TInt left = iRampUpLeft * iChannels;
1.354 + TInt rampup = iRampUpCount * iChannels;
1.355 + iRampUpLeft -= words/iChannels;
1.356 + TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer[0]);
1.357 + while (words--)
1.358 + {
1.359 + *sample++ = STATIC_CAST(TInt16,(TInt32(*sample)*(rampup-(left--)))/rampup);
1.360 + }
1.361 + }
1.362 + }
1.363 +
1.364 + return KErrNone;
1.365 + }
1.366 +
1.367 +TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration)
1.368 +//
1.369 +// Convert the given duration to a sample count using the current settings
1.370 +//
1.371 + {
1.372 + const TInt64 KTInt64OneMilion = 1000000;
1.373 +
1.374 + // Calculate duration as samples
1.375 + TInt64 microSeconds(aDuration.Int64()); // MSVC doesn't like "aDuration.Int64()" in line below
1.376 + TInt64 dur = ((TInt64(iRate) * TInt64(iChannels) * microSeconds) / KTInt64OneMilion);
1.377 + if (I64HIGH(dur)>0)
1.378 + return KMaxTInt; // Ridiculous!
1.379 + else
1.380 + return I64LOW(dur);
1.381 + }
1.382 +
1.383 +//
1.384 +// TMdaSimpleToneGenerator
1.385 +//
1.386 +
1.387 +void TMdaSimpleToneGenerator::Reset()
1.388 + {
1.389 + iPlayed = EFalse;
1.390 + }
1.391 +
1.392 +void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
1.393 +//
1.394 +// Store the frequency and duration of the specified sine tone
1.395 +//
1.396 + {
1.397 + iFrequency = aFrequency;
1.398 + iDuration = aDuration;
1.399 + iPlayed = EFalse;
1.400 + }
1.401 +
1.402 +TInt TMdaSimpleToneGenerator::GetNextTone()
1.403 +//
1.404 +// Simple implementation - just sets the supplied frequency and duration
1.405 +//
1.406 + {
1.407 + // This class only plays one tone for the specified duration
1.408 + if (!iPlayed)
1.409 + {
1.410 + iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000);
1.411 + iSineWave.SetFrequency(iFrequency,1<<14);
1.412 + iPlayed = ETrue;
1.413 + iTrailingSilence = 20; // Just to stop clicking
1.414 + }
1.415 + return KErrNone;
1.416 + }
1.417 +
1.418 +//
1.419 +// TMdaDualToneGenerator
1.420 +//
1.421 +
1.422 +void TMdaDualToneGenerator::Reset()
1.423 + {
1.424 + iPlayed = EFalse;
1.425 + }
1.426 +
1.427 +void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
1.428 + {
1.429 + // Store the frequencies and duration of the specified dual tone
1.430 + iFrequencyOne = aFrequencyOne;
1.431 + iFrequencyTwo = aFrequencyTwo;
1.432 + iDuration = aDuration;
1.433 + iPlayed = EFalse;
1.434 + }
1.435 +
1.436 +//
1.437 +// This is called by TMdaToneGenerator::FillBuffer()
1.438 +// to calculate the number of samples (iSamplesLeft) that will be needed
1.439 +// for the tone to be played and to initialize the sine wave generator.
1.440 +// If the tone has already been played, then leaves iSamplesLeft
1.441 +// unmodified (should be zero) to indicate that it has finished.
1.442 +//
1.443 +TInt TMdaDualToneGenerator::GetNextTone()
1.444 + {
1.445 + // This class only plays one tone for the specified duration
1.446 + if (!iPlayed)
1.447 + {
1.448 + iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds);
1.449 + iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2);
1.450 + iPlayed = ETrue;
1.451 + iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking
1.452 + }
1.453 + return KErrNone;
1.454 + }
1.455 +//
1.456 +// TMdaDTMFGenerator
1.457 +//
1.458 +
1.459 +const TInt KRecalculateToneLengths = KMinTInt;
1.460 +
1.461 +void TMdaDTMFGenerator::Reset()
1.462 + {
1.463 + iChar = 0;
1.464 + }
1.465 +
1.466 +void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn,
1.467 + const TTimeIntervalMicroSeconds32 aOff,
1.468 + const TTimeIntervalMicroSeconds32 aPause)
1.469 +//
1.470 +// Setup the DTMF tone durations
1.471 +// aOn can be == -1 indicating should play first tone indefinately
1.472 +//
1.473 + {
1.474 + ASSERT(aOn.Int() >=-1);
1.475 + ASSERT(aOff.Int()>=0);
1.476 + ASSERT(aPause.Int()>=0);
1.477 +
1.478 + iOn = aOn;
1.479 + iOff = aOff;
1.480 + iPause = aPause;
1.481 +
1.482 + iOnSamples = KRecalculateToneLengths; // Must recalculate these later
1.483 + }
1.484 +
1.485 +void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString)
1.486 +//
1.487 +// Store the DTMF string to be played
1.488 +// No need to validate it as it will already have been checked
1.489 +//
1.490 + {
1.491 + iChar = 0;
1.492 + iDTMFString = &aDTMFString;
1.493 + }
1.494 +
1.495 +const TUint8 KDtmfVolumeTable[4][4]=
1.496 +//
1.497 +// Relative strengths to assign to different DTMF tones
1.498 +//
1.499 +// This is only important if DTMFs are being played through a speaker
1.500 +// and need to be machine-recognisable. This table compensates for frequency
1.501 +// drop-off in the speaker and can boost the relative volume of some
1.502 +// frequencies so they are still within tolerance.
1.503 +//
1.504 +// The values normally need to be determined using a frequency analyser on
1.505 +// the hardware
1.506 +//
1.507 +// Each column == same low frequency (697, 770, 852, 941 Hz)
1.508 +// Each row == same high frequency (1209, 1336, 1477, 1633 Hz)
1.509 +//
1.510 +// The value are interpreted as ratios:
1.511 +// 0 == 100% low
1.512 +// 7f == 50% low, 50% high
1.513 +// ff == 100% high
1.514 +//
1.515 + {
1.516 + {38,27,29,37},
1.517 + {46,36,36,46},
1.518 + {62,47,49,58},
1.519 + {70,56,60,68}
1.520 + };
1.521 +
1.522 +const TUint8 KDtmfTone697=0x0;
1.523 +const TUint8 KDtmfTone770=0x1;
1.524 +const TUint8 KDtmfTone852=0x2;
1.525 +const TUint8 KDtmfTone941=0x3;
1.526 +
1.527 +const TUint8 KDtmfTone1209=0x00;
1.528 +const TUint8 KDtmfTone1336=0x10;
1.529 +const TUint8 KDtmfTone1477=0x20;
1.530 +const TUint8 KDtmfTone1633=0x30;
1.531 +
1.532 +const TUint8 KDtmfToneTable[16]=
1.533 + {
1.534 + KDtmfTone941|KDtmfTone1336,//0
1.535 + KDtmfTone697|KDtmfTone1209,//1
1.536 + KDtmfTone697|KDtmfTone1336,//2
1.537 + KDtmfTone697|KDtmfTone1477,//3
1.538 + KDtmfTone770|KDtmfTone1209,//4
1.539 + KDtmfTone770|KDtmfTone1336,//5
1.540 + KDtmfTone770|KDtmfTone1477,//6
1.541 + KDtmfTone852|KDtmfTone1209,//7
1.542 + KDtmfTone852|KDtmfTone1336,//8
1.543 + KDtmfTone852|KDtmfTone1477,//9
1.544 +
1.545 + KDtmfTone697|KDtmfTone1633,//A
1.546 + KDtmfTone770|KDtmfTone1633,//B
1.547 + KDtmfTone852|KDtmfTone1633,//C
1.548 + KDtmfTone941|KDtmfTone1633,//D
1.549 + KDtmfTone941|KDtmfTone1209,//E or *
1.550 + KDtmfTone941|KDtmfTone1477,//F or #
1.551 + };
1.552 +
1.553 +TInt TMdaDTMFGenerator::GetNextTone()
1.554 +//
1.555 +// Setup frequency/duration/silence settings for next DTMF tone
1.556 +// Supported characters are 0-9 A-F * # , and any kind of white space
1.557 +//
1.558 + {
1.559 + TBool onlyPlayFirstTone = EFalse;
1.560 +
1.561 + if (iOnSamples == KRecalculateToneLengths)
1.562 + {
1.563 + // Must recalculate tone durations as samples
1.564 +
1.565 + // Handle special case where tone on duration negative
1.566 + // - meaning play first character indefinately
1.567 + if (iOn.Int()>=0)
1.568 + iOnSamples = DurationToSamples(TInt64(iOn.Int()));
1.569 + else
1.570 + {
1.571 + onlyPlayFirstTone = ETrue;
1.572 + iOnSamples = -1;
1.573 + }
1.574 +
1.575 + iOffSamples = DurationToSamples(TInt64(iOff.Int()));
1.576 + iPauseSamples = DurationToSamples(TInt64(iPause.Int()));
1.577 + }
1.578 +
1.579 + ASSERT(iDTMFString);
1.580 +
1.581 + if (iChar==iDTMFString->Length())
1.582 + return KErrNone; // Finished. Nothing to do
1.583 +
1.584 + TInt highFrequency = 0;
1.585 + TInt highVolume = 0;
1.586 + TInt lowFrequency = 0;
1.587 + TInt lowVolume =0;
1.588 +
1.589 +Retry:
1.590 + TChar c((*iDTMFString)[iChar++]);
1.591 + if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit())
1.592 + {
1.593 + TInt tableIndex;
1.594 + switch ((TUint)c)
1.595 + {
1.596 + case '*':
1.597 + tableIndex=14;
1.598 + break;
1.599 + case '#':
1.600 + tableIndex=15;
1.601 + break;
1.602 + default:
1.603 + if (c.IsDigit())
1.604 + tableIndex=(TUint)c-'0';
1.605 + else //letter
1.606 + {
1.607 + c.UpperCase();
1.608 + tableIndex=(TUint)c-'A'+10;
1.609 + }
1.610 + }
1.611 + TInt high=KDtmfToneTable[tableIndex]&0xf0;
1.612 + TInt low=KDtmfToneTable[tableIndex]&0x0f;
1.613 + switch(high)
1.614 + {
1.615 + case KDtmfTone1209:
1.616 + highFrequency=1209;
1.617 + break;
1.618 + case KDtmfTone1336:
1.619 + highFrequency=1336;
1.620 + break;
1.621 + case KDtmfTone1477:
1.622 + highFrequency=1477;
1.623 + break;
1.624 + default://KDtmfTone1633:
1.625 + highFrequency=1633;
1.626 + break;
1.627 + }
1.628 + switch(low)
1.629 + {
1.630 + case KDtmfTone697:
1.631 + lowFrequency=697;
1.632 + break;
1.633 + case KDtmfTone770:
1.634 + lowFrequency=770;
1.635 + break;
1.636 + case KDtmfTone852:
1.637 + lowFrequency=852;
1.638 + break;
1.639 + default://KDtmfTone941:
1.640 + lowFrequency=941;
1.641 + break;
1.642 + }
1.643 + high>>=4;
1.644 + const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0];
1.645 + TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7;
1.646 + highVolume = volume;
1.647 + lowVolume = (1<<15)-volume;
1.648 +
1.649 + iTrailingSilence = iOffSamples;
1.650 + iSamplesLeft = iOnSamples;
1.651 + }
1.652 + else if ((TUint)c==',')
1.653 + {
1.654 + iTrailingSilence = iPauseSamples;
1.655 + iSamplesLeft = 0;
1.656 + }
1.657 + else if (c.IsSpace())
1.658 + {
1.659 + if (iChar < iDTMFString->Length())
1.660 + goto Retry;
1.661 + }
1.662 + else
1.663 + return KErrCorrupt;
1.664 +
1.665 + if (iOnSamples < 0) // Play only first character for ever
1.666 + {
1.667 + iTrailingSilence = 0;
1.668 + iSamplesLeft = iRate * iChannels; // One second of samples
1.669 + iChar = 0; // Reset so this character is played again next time
1.670 + iRampDown = EFalse;
1.671 + if (!onlyPlayFirstTone)
1.672 + {
1.673 + iRampUp = EFalse;
1.674 + // This is not the first time around so we should not
1.675 + // reset the tone generator - it will already have the
1.676 + // correct settings and setting them again would cause
1.677 + // an audible discontinuity
1.678 + return KErrNone;
1.679 + }
1.680 + }
1.681 +
1.682 + iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume);
1.683 + return KErrNone;
1.684 + }
1.685 +
1.686 +//
1.687 +// TMdaSequenceGenerator
1.688 +//
1.689 +
1.690 +//
1.691 +// Sequence constants
1.692 +//
1.693 +
1.694 +//const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2
1.695 +#ifdef _DEBUG
1.696 +const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8);
1.697 +const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8);
1.698 +#endif // _DEBUG
1.699 +
1.700 +const TInt KFixedSequenceFunctionReturn=-1;
1.701 +const TInt KFixedSequenceFunctionStartLoop=-2;
1.702 +const TInt KFixedSequenceFunctionEndLoop=-3;
1.703 +
1.704 +void TMdaSequenceGenerator::Reset()
1.705 + {
1.706 + iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0]));
1.707 + iInstructionPtr += 2; // Skip signature
1.708 + iStackIndex = 0;
1.709 + }
1.710 +
1.711 +void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData)
1.712 +//
1.713 +// Store the sequence data to be played
1.714 +// No need to validate it as it will already have been checked
1.715 +//
1.716 + {
1.717 + iSequenceData = &aSequenceData;
1.718 + iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]);
1.719 + iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1;
1.720 +
1.721 + // These are asserts because this should not be called if signature not present
1.722 + ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne);
1.723 + ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo);
1.724 +
1.725 + iInstructionPtr += 2; // Skip signature
1.726 +
1.727 + iStackIndex = 0;
1.728 + }
1.729 +
1.730 +TInt TMdaSequenceGenerator::GetNextTone()
1.731 +//
1.732 +//
1.733 + {
1.734 + ASSERT(iInstructionPtr); // Sanity check
1.735 +
1.736 + TInt ret = KRequestPending;
1.737 + while (ret == KRequestPending)
1.738 + {
1.739 + if (iInstructionPtr > iLastInstruction)
1.740 + ret = KErrCorrupt;
1.741 + else if (*iInstructionPtr<=0)
1.742 + {
1.743 + switch (*iInstructionPtr)
1.744 + {
1.745 + case KFixedSequenceFunctionReturn: // End of sequence
1.746 + ret = KErrNone;
1.747 + break;
1.748 +
1.749 + case KFixedSequenceFunctionStartLoop:
1.750 + if (iStackIndex>2) // Validate - can only nest twice
1.751 + ret = KErrCorrupt;
1.752 + else if ((iInstructionPtr+2) > iLastInstruction)
1.753 + ret = KErrCorrupt; // Don't run off end of sequence
1.754 + else
1.755 + {
1.756 + iStack[iStackIndex++]=(TInt)(iInstructionPtr+2);
1.757 + iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1);
1.758 + iInstructionPtr+=2;
1.759 + }
1.760 + break;
1.761 +
1.762 + case KFixedSequenceFunctionEndLoop:
1.763 + if (iStackIndex==0) // Validate - must already be nested
1.764 + ret = KErrCorrupt;
1.765 + else
1.766 + {
1.767 + if ((--iStack[iStackIndex-1])!=0)
1.768 + iInstructionPtr=(TInt16*)iStack[iStackIndex-2];
1.769 + else
1.770 + {
1.771 + iStackIndex-=2;
1.772 + iInstructionPtr++;
1.773 + }
1.774 + }
1.775 + break;
1.776 +
1.777 + default: // Bad sequence
1.778 + ret = KErrCorrupt;
1.779 + }
1.780 + }
1.781 + else
1.782 + {
1.783 + if ((iInstructionPtr+5) > iLastInstruction)
1.784 + ret = KErrCorrupt; // Don't run off end of sequence
1.785 + else
1.786 + {
1.787 + iSamplesLeft = *iInstructionPtr++;
1.788 + TInt freqOne = *iInstructionPtr++;
1.789 + TInt volOne = *iInstructionPtr++;
1.790 + TInt freqTwo = *iInstructionPtr++;
1.791 + TInt volTwo = *iInstructionPtr++;
1.792 +
1.793 + if ((volOne> 1<<15)||(volTwo > 1<<15))
1.794 + ret = KErrCorrupt;
1.795 + else
1.796 + {
1.797 + iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo);
1.798 + ret = KErrNone;
1.799 + }
1.800 + }
1.801 + }
1.802 + }
1.803 + return ret;
1.804 + }
1.805 +
1.806 +// ---------------------------------
1.807 +// Code to generate sine table files used by tone generator
1.808 +// Optionally called from InitL()
1.809 +// #define GENERATE_SINE_TABLES 1
1.810 +#ifdef GENERATE_SINE_TABLES
1.811 +LOCAL_C GenerateSineTableL()
1.812 + {
1.813 + _LIT(KSineFile,"sine.txt");
1.814 + _LIT(KSineIncFile,"sineinc.txt");
1.815 +
1.816 + RFile file;
1.817 + file.Replace(MdaManager::Fs(),KSineFile,EFileWrite);
1.818 + CleanupClosePushL(file);
1.819 +
1.820 + RFile file2;
1.821 + file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite);
1.822 + CleanupClosePushL(file2);
1.823 +
1.824 + const TReal pi=3.141592653589;
1.825 + const TReal twopi=pi*2;
1.826 + const TReal samples = 256.0;
1.827 + const TReal step = twopi/samples;
1.828 +
1.829 + TBuf8<128> sinebuffer;
1.830 + TBuf8<128> incbuffer;
1.831 + TReal res;
1.832 + TInt first=0;
1.833 + TInt last=KMaxTInt;
1.834 + TInt current;
1.835 + _LIT8(KFormat,"%6d,");
1.836 + _LIT8(KNewLine,"\n");
1.837 +
1.838 + for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors
1.839 + {
1.840 + sinebuffer.Zero();
1.841 + incbuffer.Zero();
1.842 + for (int i=0;i<8;i++)
1.843 + {
1.844 + User::LeaveIfError(Math::Sin(res,angle));
1.845 + current = TInt(KMaxTInt16*res);
1.846 + sinebuffer.AppendFormat(KFormat,current);
1.847 + if (last != KMaxTInt)
1.848 + incbuffer.AppendFormat(KFormat,current-last);
1.849 + else
1.850 + first = current;
1.851 + last = current;
1.852 + angle += step;
1.853 + }
1.854 + sinebuffer.Append(KNewLine);
1.855 + incbuffer.Append(KNewLine);
1.856 + file.Write(sinebuffer);
1.857 + file2.Write(incbuffer);
1.858 + }
1.859 +
1.860 + // Write fine difference to incbuffer - differnece between first and last
1.861 + incbuffer.Zero();
1.862 + incbuffer.AppendFormat(KFormat,first-last);
1.863 + incbuffer.Append(KNewLine);
1.864 + file2.Write(incbuffer);
1.865 +
1.866 + CleanupStack::PopAndDestroy(2);
1.867 + }
1.868 +#endif
1.869 +//-------------------------------