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