os/mm/devsound/sounddevbt/src/SoundDevice/BtToneGenerator.cpp
changeset 0 bde4ae8d615e
     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 +//-------------------------------