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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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
20 #include "ToneGenerator.h"
22 #include <mda/common/resource.h>
24 /******************************************************************************
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 ******************************************************************************/
32 // this defines the maximum possible amplitude allowed for TSineGen::SetFrequency()
33 const TInt KMaxAmplitude = 0x8000;
35 // default number of samples for trailing silence following a Tone
36 const TInt KDefaultTrailingSilenceSamples = 20;
39 // Sine tone generator
42 const TInt16 TSineGen::SineTable[KMaxSineTable] =
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,
78 const TInt16 TSineGen::IncTable[KMaxSineTable] =
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,
115 void TSineGen::SetFrequency(TInt aFrequency,TInt aAmplitude)
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.
123 if (aAmplitude>(1<<15))
125 else if (aAmplitude<-(1<<15))
128 iAmplitude=aAmplitude;
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
144 iStep=(((TUint)aFrequency<<20)/125)<<6;
145 iPosition=(aFrequency==4000 ? 0x40000000 : 0);
148 TInt TSineGen::NextSample()
150 // Generate the next sample using linear interpolation
153 TUint pos=iPosition>>24;
154 TInt amp=((IncTable[pos]*((iPosition&0x00ffffff)>>20)));
157 amp=(amp*iAmplitude)>>15;
162 void TSineWave::Generate(TInt16* aDest,TInt aCount)
164 // Called when more samples need to be generated.
169 *aDest++=STATIC_CAST(TInt16,iGen1.NextSample()+iGen2.NextSample());
173 void TSineWave::SetFrequency(TInt aFrequency,TInt aAmplitude)
175 // Set to generate a single frequency
178 SetFrequency(aFrequency,aAmplitude,0,0);
181 void TSineWave::SetFrequency(TInt aFrequency1,TInt aAmplitude1,TInt aFrequency2,TInt aAmplitude2)
183 // Set to generate two frequencies
186 iGen1.SetFrequency(aFrequency1,aAmplitude1);
187 iGen2.SetFrequency(aFrequency2,aAmplitude2);
194 void TMdaToneGenerator::Configure(TInt aRate, TInt aChannels, TInt aRepeats, TInt aSilence, TInt aRampUp)
196 // Set up this tone generator to generate data at the desired sample rate
197 // and number of channels (typically mono/stereo)
201 iChannels = aChannels;
203 iIncompleteVolume = 0;
204 iRampUpRemainder = 0;
205 iRampUp = ETrue; // Default ramping to on as it is normally useful
207 iIncompleteRampDown = EFalse;
208 iIncompleteRampUp = EFalse;
210 iSilenceBetweenRepeats = aSilence;
211 iRampUpCount = aRampUp;
212 iRampUpLeft = aRampUp;
213 iAfterRepeatSilence = EFalse;
216 LOCAL_C void RampVolume(TInt16* aData,TInt aCount,TInt aStartVol,TInt aEndVol)
218 // Simple function to ramp down the volume of some samples
219 // Typically used to prevent "clicking" artifacts at the beginning/end of tones
222 TInt step = (aEndVol - aStartVol)/aCount;
225 TInt data = TInt(*aData) * aStartVol;
226 *aData++ = TInt16(data>>15);
231 TInt TMdaToneGenerator::FillBuffer(TDes8& aBuffer)
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
239 const TInt KRampUpSamples = 50;
240 const TInt KRampDownSamples = 50;
242 ASSERT(aBuffer.MaxLength()>= (iChannels<<1));
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;
253 fill.Set(aBuffer); // Pointer to data left to be filled
256 // The rest of this function will loop around continually until the buffer
257 // is filled or there is no more data to play
261 silence = EFalse; // Reset
262 if (iSamplesLeft == 0)
264 if (iTrailingSilence == 0)
266 TInt error = GetNextTone();
271 if ((iSamplesLeft==0)&&(iTrailingSilence==0))
273 if ((iSilenceBetweenRepeats)&&(!iAfterRepeatSilence))
275 iTrailingSilence = iSilenceBetweenRepeats;
276 iAfterRepeatSilence = ETrue;
281 if ((iRepeats>0)||(iRepeats==KMdaRepeatForever))
283 iAfterRepeatSilence = EFalse;
299 samples = iTrailingSilence;
303 samples = iSamplesLeft;
305 count = Min(samples,avail>>1);
306 fill.SetLength(count<<1);
310 iSineWave.Generate(REINTERPRET_CAST(TInt16*,&fill[0]),count);
314 // Ramp up volume at beginning of tone
316 { // Fade in first few samples
317 if(count < KRampUpSamples)
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;
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;
334 else if (iIncompleteRampUp)
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;
343 { // Ramp down volume at end of tone
344 if ((iSamplesLeft-count) < KRampDownSamples)
346 if(iSamplesLeft-count == 0)
348 // Fade out last few samples
349 TInt startVolume = 1<<15;;
350 TInt fadeOutLength = Min(Min(KRampDownSamples,iSamplesLeft),(fill.Length()>>1));
352 if(iIncompleteRampDown)
354 // Completing partial rampdown at the start of a new buffer
355 startVolume -= iIncompleteVolume;
356 iIncompleteRampDown = EFalse;
359 RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&(fill.Right(fadeOutLength<<1))[0]))),fadeOutLength,startVolume,0);
361 else if(iSamplesLeft-count > 0)
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);
368 RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&(fill.Right(fadeOutLength<<1))[0]))),fadeOutLength,1<<15,(1<<15)-iIncompleteVolume);
370 iIncompleteRampDown = ETrue;
374 iSamplesLeft -= count;
377 { // Generate silence
378 fill.FillZ(count<<1);
379 iTrailingSilence -= count;
384 fill.Shift(count<<1);
386 if (avail>(iChannels<<1))
391 aBuffer.SetLength(used);
393 // Do any ramp up that is required
396 TInt words = iRampUpLeft * iChannels;
397 words = Min(words,used>>1);
398 if (words>0) // In case buffer has zero length...
400 TInt left = iRampUpLeft * iChannels;
401 TInt rampup = iRampUpCount * iChannels;
402 iRampUpLeft -= words/iChannels;
403 TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer[0]);
406 *sample++ = STATIC_CAST(TInt16,(TInt32(*sample)*(rampup-(left--)))/rampup);
414 TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration)
416 // Convert the given duration to a sample count using the current settings
419 const TInt64 KTInt64OneMilion = 1000000;
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);
425 return KMaxTInt; // Ridiculous!
431 // TMdaSimpleToneGenerator
434 void TMdaSimpleToneGenerator::Reset()
439 void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
441 // Store the frequency and duration of the specified sine tone
444 iFrequency = aFrequency;
445 iDuration = aDuration;
449 TInt TMdaSimpleToneGenerator::GetNextTone()
451 // Simple implementation - just sets the supplied frequency and duration
454 // This class only plays one tone for the specified duration
457 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000);
458 iSineWave.SetFrequency(iFrequency,1<<14);
460 iTrailingSilence = 20; // Just to stop clicking
466 // TMdaDualToneGenerator
469 void TMdaDualToneGenerator::Reset()
474 void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
476 // Store the frequencies and duration of the specified dual tone
477 iFrequencyOne = aFrequencyOne;
478 iFrequencyTwo = aFrequencyTwo;
479 iDuration = aDuration;
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.
490 TInt TMdaDualToneGenerator::GetNextTone()
492 // This class only plays one tone for the specified duration
495 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds);
496 iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2);
498 iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking
506 const TInt KRecalculateToneLengths = KMinTInt;
508 void TMdaDTMFGenerator::Reset()
513 void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn,
514 const TTimeIntervalMicroSeconds32 aOff,
515 const TTimeIntervalMicroSeconds32 aPause)
517 // Setup the DTMF tone durations
518 // aOn can be == -1 indicating should play first tone indefinately
521 ASSERT(aOn.Int() >=-1);
522 ASSERT(aOff.Int()>=0);
523 ASSERT(aPause.Int()>=0);
529 iOnSamples = KRecalculateToneLengths; // Must recalculate these later
532 void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString)
534 // Store the DTMF string to be played
535 // No need to validate it as it will already have been checked
539 iDTMFString = &aDTMFString;
542 const TUint8 KDtmfVolumeTable[4][4]=
544 // Relative strengths to assign to different DTMF tones
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.
551 // The values normally need to be determined using a frequency analyser on
554 // Each column == same low frequency (697, 770, 852, 941 Hz)
555 // Each row == same high frequency (1209, 1336, 1477, 1633 Hz)
557 // The value are interpreted as ratios:
559 // 7f == 50% low, 50% high
569 const TUint8 KDtmfTone697=0x0;
570 const TUint8 KDtmfTone770=0x1;
571 const TUint8 KDtmfTone852=0x2;
572 const TUint8 KDtmfTone941=0x3;
574 const TUint8 KDtmfTone1209=0x00;
575 const TUint8 KDtmfTone1336=0x10;
576 const TUint8 KDtmfTone1477=0x20;
577 const TUint8 KDtmfTone1633=0x30;
579 const TUint8 KDtmfToneTable[16]=
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
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 #
600 TInt TMdaDTMFGenerator::GetNextTone()
602 // Setup frequency/duration/silence settings for next DTMF tone
603 // Supported characters are 0-9 A-F * # , and any kind of white space
606 TBool onlyPlayFirstTone = EFalse;
608 if (iOnSamples == KRecalculateToneLengths)
610 // Must recalculate tone durations as samples
612 // Handle special case where tone on duration negative
613 // - meaning play first character indefinately
615 iOnSamples = DurationToSamples(TInt64(iOn.Int()));
618 onlyPlayFirstTone = ETrue;
622 iOffSamples = DurationToSamples(TInt64(iOff.Int()));
623 iPauseSamples = DurationToSamples(TInt64(iPause.Int()));
628 if (iChar==iDTMFString->Length())
629 return KErrNone; // Finished. Nothing to do
631 TInt highFrequency = 0;
633 TInt lowFrequency = 0;
637 TChar c((*iDTMFString)[iChar++]);
638 if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit())
651 tableIndex=(TUint)c-'0';
655 tableIndex=(TUint)c-'A'+10;
658 TInt high=KDtmfToneTable[tableIndex]&0xf0;
659 TInt low=KDtmfToneTable[tableIndex]&0x0f;
671 default://KDtmfTone1633:
686 default://KDtmfTone941:
691 const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0];
692 TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7;
694 lowVolume = (1<<15)-volume;
696 iTrailingSilence = iOffSamples;
697 iSamplesLeft = iOnSamples;
699 else if ((TUint)c==',')
701 iTrailingSilence = iPauseSamples;
704 else if (c.IsSpace())
706 if (iChar < iDTMFString->Length())
712 if (iOnSamples < 0) // Play only first character for ever
714 iTrailingSilence = 0;
715 iSamplesLeft = iRate * iChannels; // One second of samples
716 iChar = 0; // Reset so this character is played again next time
718 if (!onlyPlayFirstTone)
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
729 iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume);
734 // TMdaSequenceGenerator
738 // Sequence constants
741 //const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2
743 const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8);
744 const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8);
747 const TInt KFixedSequenceFunctionReturn=-1;
748 const TInt KFixedSequenceFunctionStartLoop=-2;
749 const TInt KFixedSequenceFunctionEndLoop=-3;
751 void TMdaSequenceGenerator::Reset()
753 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0]));
754 iInstructionPtr += 2; // Skip signature
758 void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData)
760 // Store the sequence data to be played
761 // No need to validate it as it will already have been checked
764 iSequenceData = &aSequenceData;
765 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]);
766 iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1;
768 // These are asserts because this should not be called if signature not present
769 ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne);
770 ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo);
772 iInstructionPtr += 2; // Skip signature
777 TInt TMdaSequenceGenerator::GetNextTone()
781 ASSERT(iInstructionPtr); // Sanity check
783 TInt ret = KRequestPending;
784 while (ret == KRequestPending)
786 if (iInstructionPtr > iLastInstruction)
788 else if (*iInstructionPtr<=0)
790 switch (*iInstructionPtr)
792 case KFixedSequenceFunctionReturn: // End of sequence
796 case KFixedSequenceFunctionStartLoop:
797 if (iStackIndex>2) // Validate - can only nest twice
799 else if ((iInstructionPtr+2) > iLastInstruction)
800 ret = KErrCorrupt; // Don't run off end of sequence
803 iStack[iStackIndex++]=(TInt)(iInstructionPtr+2);
804 iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1);
809 case KFixedSequenceFunctionEndLoop:
810 if (iStackIndex==0) // Validate - must already be nested
814 if ((--iStack[iStackIndex-1])!=0)
815 iInstructionPtr=(TInt16*)iStack[iStackIndex-2];
824 default: // Bad sequence
830 if ((iInstructionPtr+5) > iLastInstruction)
831 ret = KErrCorrupt; // Don't run off end of sequence
834 iSamplesLeft = *iInstructionPtr++;
835 TInt freqOne = *iInstructionPtr++;
836 TInt volOne = *iInstructionPtr++;
837 TInt freqTwo = *iInstructionPtr++;
838 TInt volTwo = *iInstructionPtr++;
840 if ((volOne> 1<<15)||(volTwo > 1<<15))
844 iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo);
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()
860 _LIT(KSineFile,"sine.txt");
861 _LIT(KSineIncFile,"sineinc.txt");
864 file.Replace(MdaManager::Fs(),KSineFile,EFileWrite);
865 CleanupClosePushL(file);
868 file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite);
869 CleanupClosePushL(file2);
871 const TReal pi=3.141592653589;
872 const TReal twopi=pi*2;
873 const TReal samples = 256.0;
874 const TReal step = twopi/samples;
876 TBuf8<128> sinebuffer;
877 TBuf8<128> incbuffer;
882 _LIT8(KFormat,"%6d,");
883 _LIT8(KNewLine,"\n");
885 for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors
889 for (int i=0;i<8;i++)
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);
901 sinebuffer.Append(KNewLine);
902 incbuffer.Append(KNewLine);
903 file.Write(sinebuffer);
904 file2.Write(incbuffer);
907 // Write fine difference to incbuffer - differnece between first and last
909 incbuffer.AppendFormat(KFormat,first-last);
910 incbuffer.Append(KNewLine);
911 file2.Write(incbuffer);
913 CleanupStack::PopAndDestroy(2);
916 //-------------------------------