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".
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 TInt32 sampleValue = static_cast<TInt32>((*sample)*(rampup-(left--)));
407 *sample++ = static_cast<TInt16>(sampleValue/rampup);
415 TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration)
417 // Convert the given duration to a sample count using the current settings
420 const TInt64 KTInt64OneMilion = 1000000;
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);
426 return KMaxTInt; // Ridiculous!
432 // TMdaSimpleToneGenerator
435 void TMdaSimpleToneGenerator::Reset()
440 void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
442 // Store the frequency and duration of the specified sine tone
445 iFrequency = aFrequency;
446 iDuration = aDuration;
450 TInt TMdaSimpleToneGenerator::GetNextTone()
452 // Simple implementation - just sets the supplied frequency and duration
455 // This class only plays one tone for the specified duration
458 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000);
459 iSineWave.SetFrequency(iFrequency,1<<14);
461 iTrailingSilence = 20; // Just to stop clicking
467 // TMdaDualToneGenerator
470 void TMdaDualToneGenerator::Reset()
475 void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
477 // Store the frequencies and duration of the specified dual tone
478 iFrequencyOne = aFrequencyOne;
479 iFrequencyTwo = aFrequencyTwo;
480 iDuration = aDuration;
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.
491 TInt TMdaDualToneGenerator::GetNextTone()
493 // This class only plays one tone for the specified duration
496 iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds);
497 iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2);
499 iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking
507 const TInt KRecalculateToneLengths = KMinTInt;
509 void TMdaDTMFGenerator::Reset()
514 void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn,
515 const TTimeIntervalMicroSeconds32 aOff,
516 const TTimeIntervalMicroSeconds32 aPause)
518 // Setup the DTMF tone durations
519 // aOn can be == -1 indicating should play first tone indefinately
522 ASSERT(aOn.Int() >=-1);
523 ASSERT(aOff.Int()>=0);
524 ASSERT(aPause.Int()>=0);
530 iOnSamples = KRecalculateToneLengths; // Must recalculate these later
533 void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString)
535 // Store the DTMF string to be played
536 // No need to validate it as it will already have been checked
540 iDTMFString = &aDTMFString;
543 const TUint8 KDtmfVolumeTable[4][4]=
545 // Relative strengths to assign to different DTMF tones
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.
552 // The values normally need to be determined using a frequency analyser on
555 // Each column == same low frequency (697, 770, 852, 941 Hz)
556 // Each row == same high frequency (1209, 1336, 1477, 1633 Hz)
558 // The value are interpreted as ratios:
560 // 7f == 50% low, 50% high
570 const TUint8 KDtmfTone697=0x0;
571 const TUint8 KDtmfTone770=0x1;
572 const TUint8 KDtmfTone852=0x2;
573 const TUint8 KDtmfTone941=0x3;
575 const TUint8 KDtmfTone1209=0x00;
576 const TUint8 KDtmfTone1336=0x10;
577 const TUint8 KDtmfTone1477=0x20;
578 const TUint8 KDtmfTone1633=0x30;
580 const TUint8 KDtmfToneTable[16]=
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
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 #
601 TInt TMdaDTMFGenerator::GetNextTone()
603 // Setup frequency/duration/silence settings for next DTMF tone
604 // Supported characters are 0-9 A-F * # , and any kind of white space
607 TBool onlyPlayFirstTone = EFalse;
609 if (iOnSamples == KRecalculateToneLengths)
611 // Must recalculate tone durations as samples
613 // Handle special case where tone on duration negative
614 // - meaning play first character indefinately
616 iOnSamples = DurationToSamples(TInt64(iOn.Int()));
619 onlyPlayFirstTone = ETrue;
623 iOffSamples = DurationToSamples(TInt64(iOff.Int()));
624 iPauseSamples = DurationToSamples(TInt64(iPause.Int()));
629 if (iChar==iDTMFString->Length())
630 return KErrNone; // Finished. Nothing to do
632 TInt highFrequency = 0;
634 TInt lowFrequency = 0;
638 TChar c((*iDTMFString)[iChar++]);
639 if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit())
652 tableIndex=(TUint)c-'0';
656 tableIndex=(TUint)c-'A'+10;
659 TInt high=KDtmfToneTable[tableIndex]&0xf0;
660 TInt low=KDtmfToneTable[tableIndex]&0x0f;
672 default://KDtmfTone1633:
687 default://KDtmfTone941:
692 const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0];
693 TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7;
695 lowVolume = (1<<15)-volume;
697 iTrailingSilence = iOffSamples;
698 iSamplesLeft = iOnSamples;
700 else if ((TUint)c==',')
702 iTrailingSilence = iPauseSamples;
705 else if (c.IsSpace())
707 if (iChar < iDTMFString->Length())
713 if (iOnSamples < 0) // Play only first character for ever
715 iTrailingSilence = 0;
716 iSamplesLeft = iRate * iChannels; // One second of samples
717 iChar = 0; // Reset so this character is played again next time
719 if (!onlyPlayFirstTone)
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
730 iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume);
735 // TMdaSequenceGenerator
739 // Sequence constants
742 //const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2
744 const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8);
745 const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8);
748 const TInt KFixedSequenceFunctionReturn=-1;
749 const TInt KFixedSequenceFunctionStartLoop=-2;
750 const TInt KFixedSequenceFunctionEndLoop=-3;
752 void TMdaSequenceGenerator::Reset()
754 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0]));
755 iInstructionPtr += 2; // Skip signature
759 void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData)
761 // Store the sequence data to be played
762 // No need to validate it as it will already have been checked
765 iSequenceData = &aSequenceData;
766 iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]);
767 iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1;
769 // These are asserts because this should not be called if signature not present
770 ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne);
771 ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo);
773 iInstructionPtr += 2; // Skip signature
778 TInt TMdaSequenceGenerator::GetNextTone()
782 ASSERT(iInstructionPtr); // Sanity check
784 TInt ret = KRequestPending;
785 while (ret == KRequestPending)
787 if (iInstructionPtr > iLastInstruction)
789 else if (*iInstructionPtr<=0)
791 switch (*iInstructionPtr)
793 case KFixedSequenceFunctionReturn: // End of sequence
797 case KFixedSequenceFunctionStartLoop:
798 if (iStackIndex>2) // Validate - can only nest twice
800 else if ((iInstructionPtr+2) > iLastInstruction)
801 ret = KErrCorrupt; // Don't run off end of sequence
804 iStack[iStackIndex++]=(TInt)(iInstructionPtr+2);
805 iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1);
810 case KFixedSequenceFunctionEndLoop:
811 if (iStackIndex==0) // Validate - must already be nested
815 if ((--iStack[iStackIndex-1])!=0)
816 iInstructionPtr=(TInt16*)iStack[iStackIndex-2];
825 default: // Bad sequence
831 if ((iInstructionPtr+5) > iLastInstruction)
832 ret = KErrCorrupt; // Don't run off end of sequence
835 iSamplesLeft = *iInstructionPtr++;
836 TInt freqOne = *iInstructionPtr++;
837 TInt volOne = *iInstructionPtr++;
838 TInt freqTwo = *iInstructionPtr++;
839 TInt volTwo = *iInstructionPtr++;
841 if ((volOne> 1<<15)||(volTwo > 1<<15))
845 iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo);
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()
861 _LIT(KSineFile,"sine.txt");
862 _LIT(KSineIncFile,"sineinc.txt");
865 file.Replace(MdaManager::Fs(),KSineFile,EFileWrite);
866 CleanupClosePushL(file);
869 file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite);
870 CleanupClosePushL(file2);
872 const TReal pi=3.141592653589;
873 const TReal twopi=pi*2;
874 const TReal samples = 256.0;
875 const TReal step = twopi/samples;
877 TBuf8<128> sinebuffer;
878 TBuf8<128> incbuffer;
883 _LIT8(KFormat,"%6d,");
884 _LIT8(KNewLine,"\n");
886 for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors
890 for (int i=0;i<8;i++)
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);
902 sinebuffer.Append(KNewLine);
903 incbuffer.Append(KNewLine);
904 file.Write(sinebuffer);
905 file2.Write(incbuffer);
908 // Write fine difference to incbuffer - differnece between first and last
910 incbuffer.AppendFormat(KFormat,first-last);
911 incbuffer.Append(KNewLine);
912 file2.Write(incbuffer);
914 CleanupStack::PopAndDestroy(2);
917 //-------------------------------