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