os/mm/devsound/devsoundrefplugin/src/sounddevice/ToneGenerator.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 				TInt32 sampleValue =   static_cast<TInt32>((*sample)*(rampup-(left--)));
   407 				*sample++ = static_cast<TInt16>(sampleValue/rampup);
   408 				}
   409 			}
   410 		}
   411 
   412 	return KErrNone;
   413 	}
   414 
   415 TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration)
   416 //
   417 // Convert the given duration to a sample count using the current settings
   418 //
   419 	{
   420 	const TInt64 KTInt64OneMilion = 1000000;
   421 
   422 	// Calculate duration as samples
   423 	TInt64 microSeconds(aDuration.Int64());  // MSVC doesn't like "aDuration.Int64()" in line below
   424 	TInt64 dur = ((TInt64(iRate) * TInt64(iChannels) * microSeconds) / KTInt64OneMilion);
   425 	if (I64HIGH(dur)>0)
   426 		return KMaxTInt; // Ridiculous!
   427 	else
   428 		return I64LOW(dur);
   429 	}
   430 
   431 //
   432 // TMdaSimpleToneGenerator
   433 //
   434 
   435 void TMdaSimpleToneGenerator::Reset()
   436 	{
   437 	iPlayed = EFalse;
   438 	}
   439 
   440 void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
   441 //
   442 // Store the frequency and duration of the specified sine tone
   443 //
   444 	{
   445 	iFrequency = aFrequency;
   446 	iDuration = aDuration;
   447 	iPlayed = EFalse;
   448 	}
   449 
   450 TInt TMdaSimpleToneGenerator::GetNextTone()
   451 //
   452 // Simple implementation - just sets the supplied frequency and duration
   453 //
   454 	{
   455 	// This class only plays one tone for the specified duration
   456 	if (!iPlayed)
   457 		{
   458 		iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000);
   459 		iSineWave.SetFrequency(iFrequency,1<<14);
   460 		iPlayed = ETrue;
   461 		iTrailingSilence = 20; // Just to stop clicking
   462 		}
   463 	return KErrNone;
   464 	}
   465 
   466 //
   467 // TMdaDualToneGenerator
   468 //
   469 
   470 void TMdaDualToneGenerator::Reset()
   471 	{
   472 	iPlayed = EFalse;
   473 	}
   474 
   475 void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
   476 	{
   477 	// Store the frequencies and duration of the specified dual tone
   478 	iFrequencyOne = aFrequencyOne;
   479 	iFrequencyTwo = aFrequencyTwo;
   480 	iDuration = aDuration;
   481 	iPlayed = EFalse;
   482 	}
   483 
   484 // 
   485 // This is called by TMdaToneGenerator::FillBuffer() 
   486 // to calculate the number of samples (iSamplesLeft) that will be needed 
   487 // for the tone to be played and to initialize the sine wave generator.
   488 // If the tone has already been played, then leaves iSamplesLeft 
   489 // unmodified (should be zero) to indicate that it has finished.
   490 //
   491 TInt TMdaDualToneGenerator::GetNextTone()
   492 	{
   493 	// This class only plays one tone for the specified duration
   494 	if (!iPlayed)
   495 		{
   496 		iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds);
   497 		iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2);
   498 		iPlayed = ETrue;
   499 		iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking
   500 		}
   501 	return KErrNone;
   502 	}
   503 //
   504 // TMdaDTMFGenerator
   505 //
   506 
   507 const TInt KRecalculateToneLengths = KMinTInt;
   508 
   509 void TMdaDTMFGenerator::Reset()
   510 	{
   511 	iChar = 0;
   512 	}
   513 
   514 void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn,
   515 							const TTimeIntervalMicroSeconds32 aOff,
   516 							const TTimeIntervalMicroSeconds32 aPause)
   517 //
   518 // Setup the DTMF tone durations
   519 // aOn can be == -1 indicating should play first tone indefinately
   520 //
   521 	{
   522 	ASSERT(aOn.Int() >=-1);
   523 	ASSERT(aOff.Int()>=0);
   524 	ASSERT(aPause.Int()>=0);
   525 
   526 	iOn = aOn;
   527 	iOff = aOff;
   528 	iPause = aPause;
   529 
   530 	iOnSamples = KRecalculateToneLengths; // Must recalculate these later
   531 	}
   532 
   533 void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString)
   534 //
   535 // Store the DTMF string to be played
   536 // No need to validate it as it will already have been checked 
   537 //
   538 	{
   539 	iChar = 0;
   540 	iDTMFString = &aDTMFString;
   541 	}
   542 
   543 const TUint8 KDtmfVolumeTable[4][4]=
   544 //
   545 // Relative strengths to assign to different DTMF tones
   546 //
   547 // This is only important if DTMFs are being played through a speaker
   548 // and need to be machine-recognisable. This table compensates for frequency
   549 // drop-off in the speaker and can boost the relative volume of some 
   550 // frequencies so they are still within tolerance.
   551 // 
   552 // The values normally need to be determined using a frequency analyser on 
   553 // the hardware
   554 // 
   555 // Each column == same low frequency (697, 770, 852, 941 Hz)
   556 // Each row == same high frequency (1209, 1336, 1477, 1633 Hz)
   557 //
   558 // The value are interpreted as ratios:
   559 //		0  == 100% low
   560 //		7f == 50% low, 50% high
   561 //		ff == 100% high
   562 //
   563 	{
   564 	{38,27,29,37},
   565 	{46,36,36,46},
   566 	{62,47,49,58},
   567 	{70,56,60,68}
   568 	};
   569 
   570 const TUint8 KDtmfTone697=0x0;
   571 const TUint8 KDtmfTone770=0x1;
   572 const TUint8 KDtmfTone852=0x2;
   573 const TUint8 KDtmfTone941=0x3;
   574 
   575 const TUint8 KDtmfTone1209=0x00;
   576 const TUint8 KDtmfTone1336=0x10;
   577 const TUint8 KDtmfTone1477=0x20;
   578 const TUint8 KDtmfTone1633=0x30;
   579 
   580 const TUint8 KDtmfToneTable[16]=
   581 	{
   582 	KDtmfTone941|KDtmfTone1336,//0
   583 	KDtmfTone697|KDtmfTone1209,//1
   584 	KDtmfTone697|KDtmfTone1336,//2
   585 	KDtmfTone697|KDtmfTone1477,//3
   586 	KDtmfTone770|KDtmfTone1209,//4
   587 	KDtmfTone770|KDtmfTone1336,//5
   588 	KDtmfTone770|KDtmfTone1477,//6
   589 	KDtmfTone852|KDtmfTone1209,//7
   590 	KDtmfTone852|KDtmfTone1336,//8
   591 	KDtmfTone852|KDtmfTone1477,//9
   592 
   593 	KDtmfTone697|KDtmfTone1633,//A
   594 	KDtmfTone770|KDtmfTone1633,//B
   595 	KDtmfTone852|KDtmfTone1633,//C
   596 	KDtmfTone941|KDtmfTone1633,//D
   597 	KDtmfTone941|KDtmfTone1209,//E or *
   598 	KDtmfTone941|KDtmfTone1477,//F or #
   599 	};
   600 
   601 TInt TMdaDTMFGenerator::GetNextTone()
   602 //
   603 // Setup frequency/duration/silence settings for next DTMF tone
   604 // Supported characters are 0-9 A-F * # , and any kind of white space
   605 //
   606 	{
   607 	TBool onlyPlayFirstTone = EFalse;
   608 
   609 	if (iOnSamples == KRecalculateToneLengths)
   610 		{
   611 		// Must recalculate tone durations as samples
   612 
   613 		// Handle special case where tone on duration negative
   614 		// - meaning play first character indefinately
   615 		if (iOn.Int()>=0)
   616 			iOnSamples = DurationToSamples(TInt64(iOn.Int()));
   617 		else 
   618 			{
   619 			onlyPlayFirstTone = ETrue;
   620 			iOnSamples = -1; 
   621 			}
   622 
   623 		iOffSamples = DurationToSamples(TInt64(iOff.Int()));
   624 		iPauseSamples = DurationToSamples(TInt64(iPause.Int()));
   625 		}
   626 
   627 	ASSERT(iDTMFString);
   628 
   629 	if (iChar==iDTMFString->Length())
   630 		return KErrNone; // Finished. Nothing to do
   631 
   632 	TInt highFrequency = 0;
   633 	TInt highVolume = 0;
   634 	TInt lowFrequency = 0; 
   635 	TInt lowVolume =0;
   636 
   637 Retry:
   638    	TChar c((*iDTMFString)[iChar++]);
   639    	if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit())
   640    		{
   641     	TInt tableIndex;
   642 		switch ((TUint)c)
   643 			{
   644 		case '*':
   645 			tableIndex=14;
   646 			break;
   647 		case '#':
   648 			tableIndex=15;
   649 			break;
   650 		default:
   651 			if (c.IsDigit())
   652     			tableIndex=(TUint)c-'0';
   653 			else //letter
   654 		   		{
   655 				c.UpperCase();
   656     			tableIndex=(TUint)c-'A'+10;
   657 				}
   658 			}
   659 		TInt high=KDtmfToneTable[tableIndex]&0xf0;
   660 		TInt low=KDtmfToneTable[tableIndex]&0x0f;
   661 		switch(high)
   662 			{
   663 		case KDtmfTone1209:
   664 			highFrequency=1209;
   665 			break;
   666 		case KDtmfTone1336:
   667 			highFrequency=1336;
   668 			break;
   669 		case KDtmfTone1477:
   670 			highFrequency=1477;
   671 			break;
   672 		default://KDtmfTone1633:
   673 			highFrequency=1633;
   674 			break;
   675 			}
   676 		switch(low)
   677 			{
   678 		case KDtmfTone697:
   679 			lowFrequency=697;
   680 			break;
   681 		case KDtmfTone770:
   682 			lowFrequency=770;
   683 			break;
   684 		case KDtmfTone852:
   685 			lowFrequency=852;
   686 			break;
   687 		default://KDtmfTone941:
   688 			lowFrequency=941;
   689 			break;
   690 			}
   691 		high>>=4;
   692 		const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0];
   693 		TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7;
   694 		highVolume = volume;
   695 		lowVolume = (1<<15)-volume;
   696 
   697 		iTrailingSilence = iOffSamples;
   698 		iSamplesLeft = iOnSamples;
   699 		}
   700    	else if ((TUint)c==',')
   701 		{
   702   		iTrailingSilence = iPauseSamples;
   703  		iSamplesLeft = 0;
   704     	}
   705 	else if (c.IsSpace())
   706 		{
   707 		if (iChar < iDTMFString->Length())
   708 			goto Retry;
   709 		}
   710 	else
   711 		return KErrCorrupt;
   712 
   713 	if (iOnSamples < 0) // Play only first character for ever
   714 		{
   715 		iTrailingSilence = 0;
   716 		iSamplesLeft = iRate * iChannels; // One second of samples
   717 		iChar = 0; // Reset so this character is played again next time
   718 		iRampDown = EFalse;
   719 		if (!onlyPlayFirstTone)
   720 			{
   721 			iRampUp = EFalse;
   722 			// This is not the first time around so we should not
   723 			// reset the tone generator - it will already have the
   724 			// correct settings and setting them again would cause
   725 			// an audible discontinuity
   726 			return KErrNone; 
   727 			}
   728 		}
   729 
   730 	iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume);
   731 	return KErrNone;
   732 	}
   733 
   734 //
   735 // TMdaSequenceGenerator
   736 //
   737 
   738 //
   739 // Sequence constants
   740 // 
   741 
   742 //const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2 
   743 #ifdef _DEBUG
   744 const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8); 
   745 const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8);
   746 #endif // _DEBUG
   747 
   748 const TInt KFixedSequenceFunctionReturn=-1;
   749 const TInt KFixedSequenceFunctionStartLoop=-2;
   750 const TInt KFixedSequenceFunctionEndLoop=-3;
   751 
   752 void TMdaSequenceGenerator::Reset()
   753 	{
   754 	iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0]));
   755 	iInstructionPtr += 2; // Skip signature
   756 	iStackIndex = 0;
   757 	}
   758 	
   759 void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData)
   760 //
   761 // Store the sequence data to be played
   762 // No need to validate it as it will already have been checked 
   763 //
   764 	{
   765 	iSequenceData = &aSequenceData;
   766 	iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]);
   767 	iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1;
   768 
   769 	// These are asserts because this should not be called if signature not present
   770 	ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne);
   771 	ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo);
   772 
   773 	iInstructionPtr += 2; // Skip signature
   774 
   775 	iStackIndex = 0;
   776 	}
   777 
   778 TInt TMdaSequenceGenerator::GetNextTone()
   779 //
   780 //
   781 	{
   782 	ASSERT(iInstructionPtr); // Sanity check
   783 
   784 	TInt ret = KRequestPending;
   785 	while (ret == KRequestPending)
   786 		{
   787 		if (iInstructionPtr > iLastInstruction)
   788 			ret = KErrCorrupt;
   789 		else if (*iInstructionPtr<=0)
   790 	   		{
   791 	   		switch (*iInstructionPtr)
   792 	   			{
   793 	   		case KFixedSequenceFunctionReturn: // End of sequence
   794 				ret = KErrNone;
   795 				break;
   796 
   797 	   		case KFixedSequenceFunctionStartLoop:
   798 				if (iStackIndex>2) // Validate - can only nest twice
   799 					ret = KErrCorrupt;
   800 				else if ((iInstructionPtr+2) > iLastInstruction)
   801 					ret = KErrCorrupt; // Don't run off end of sequence
   802 				else
   803 					{
   804 		   			iStack[iStackIndex++]=(TInt)(iInstructionPtr+2);
   805 		   			iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1);
   806 	   				iInstructionPtr+=2;
   807 					}
   808 	   			break;
   809 
   810 	   		case KFixedSequenceFunctionEndLoop:
   811 				if (iStackIndex==0) // Validate - must already be nested
   812 					ret = KErrCorrupt;
   813 				else
   814 					{
   815 		   			if ((--iStack[iStackIndex-1])!=0)
   816 		   				iInstructionPtr=(TInt16*)iStack[iStackIndex-2];
   817 		   			else
   818 		   				{
   819 		   				iStackIndex-=2;
   820 		   				iInstructionPtr++;
   821 		   				}
   822 					}
   823 	   			break;
   824 
   825 	   		default: // Bad sequence
   826 				ret = KErrCorrupt;
   827 	   			}
   828 			}
   829 		else
   830 			{
   831 			if ((iInstructionPtr+5) > iLastInstruction)
   832 				ret = KErrCorrupt; // Don't run off end of sequence
   833 			else
   834 				{
   835 				iSamplesLeft = *iInstructionPtr++;
   836 				TInt freqOne = *iInstructionPtr++;
   837 				TInt volOne  = *iInstructionPtr++;
   838 				TInt freqTwo = *iInstructionPtr++;
   839 				TInt volTwo  = *iInstructionPtr++;
   840 
   841 				if ((volOne> 1<<15)||(volTwo > 1<<15))
   842 					ret = KErrCorrupt;
   843 				else	
   844 					{
   845 					iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo);
   846 					ret = KErrNone;
   847 					}
   848 				}
   849 			}
   850 		}
   851 	return ret;
   852 	}
   853 
   854 // ---------------------------------
   855 // Code to generate sine table files used by tone generator
   856 // Optionally called from InitL()
   857 // #define GENERATE_SINE_TABLES 1
   858 #ifdef GENERATE_SINE_TABLES
   859 LOCAL_C GenerateSineTableL()
   860 	{
   861 	_LIT(KSineFile,"sine.txt");
   862 	_LIT(KSineIncFile,"sineinc.txt");
   863 
   864 	RFile file;
   865 	file.Replace(MdaManager::Fs(),KSineFile,EFileWrite);
   866 	CleanupClosePushL(file);
   867 
   868 	RFile file2;
   869 	file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite);
   870 	CleanupClosePushL(file2);
   871 
   872 	const TReal pi=3.141592653589;
   873 	const TReal twopi=pi*2;
   874 	const TReal samples = 256.0;
   875 	const TReal step = twopi/samples;
   876 
   877 	TBuf8<128> sinebuffer;
   878 	TBuf8<128> incbuffer;
   879 	TReal res;
   880 	TInt first=0;
   881 	TInt last=KMaxTInt;
   882 	TInt current;
   883 	_LIT8(KFormat,"%6d,");
   884 	_LIT8(KNewLine,"\n");
   885 
   886 	for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors
   887 		{
   888 		sinebuffer.Zero();
   889 		incbuffer.Zero();
   890 		for (int i=0;i<8;i++)
   891 			{
   892 			User::LeaveIfError(Math::Sin(res,angle));
   893 			current = TInt(KMaxTInt16*res);
   894 			sinebuffer.AppendFormat(KFormat,current);
   895 			if (last != KMaxTInt)
   896 				incbuffer.AppendFormat(KFormat,current-last);
   897 			else
   898 				first = current;
   899 			last = current;
   900 			angle += step;
   901 			}
   902 		sinebuffer.Append(KNewLine);
   903 		incbuffer.Append(KNewLine);
   904 		file.Write(sinebuffer);
   905 		file2.Write(incbuffer);
   906 		}
   907 
   908 	// Write fine difference to incbuffer - differnece between first and last
   909 	incbuffer.Zero();
   910 	incbuffer.AppendFormat(KFormat,first-last);
   911 	incbuffer.Append(KNewLine);
   912 	file2.Write(incbuffer);
   913 
   914 	CleanupStack::PopAndDestroy(2);
   915 	}
   916 #endif
   917 //-------------------------------