os/mm/mmhais/refacladapt/src/tonehwdevice/ToneGenerator.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 //-------------------------------