diff -r 000000000000 -r 40261b775718 devsound/sounddevbt/src/SoundDevice/BtToneGenerator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/sounddevbt/src/SoundDevice/BtToneGenerator.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,866 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// This file contains an implementation of the ToneGenerator interface +// that converts all tone generation requests in to sampled audio +// data to be played through the normal local sampled audio interface +// +// + +#include "BtToneGenerator.h" + +#include +#include + +/****************************************************************************** +* Tone Generators +* +* The following classes are used to generate simple frequency/duration tones, +* DTMF, and SymbianOS tone sequences in a WINS environment. The below code +* should only be considered for WINS. +******************************************************************************/ + +// this defines the maximum possible amplitude allowed for TSineGen::SetFrequency() +const TInt KMaxAmplitude = 0x8000; + +// default number of samples for trailing silence following a Tone +const TInt KDefaultTrailingSilenceSamples = 20; + +// +// Sine tone generator +// + +const TInt16 TSineGen::SineTable[KMaxSineTable] = + { + 0, 804, 1607, 2410, 3211, 4011, 4807, 5601, + 6392, 7179, 7961, 8739, 9511, 10278, 11038, 11792, + 12539, 13278, 14009, 14732, 15446, 16150, 16845, 17530, + 18204, 18867, 19519, 20159, 20787, 21402, 22004, 22594, + 23169, 23731, 24278, 24811, 25329, 25831, 26318, 26789, + 27244, 27683, 28105, 28510, 28897, 29268, 29621, 29955, + 30272, 30571, 30851, 31113, 31356, 31580, 31785, 31970, + 32137, 32284, 32412, 32520, 32609, 32678, 32727, 32757, + 32767, 32757, 32727, 32678, 32609, 32520, 32412, 32284, + 32137, 31970, 31785, 31580, 31356, 31113, 30851, 30571, + 30272, 29955, 29621, 29268, 28897, 28510, 28105, 27683, + 27244, 26789, 26318, 25831, 25329, 24811, 24278, 23731, + 23169, 22594, 22004, 21402, 20787, 20159, 19519, 18867, + 18204, 17530, 16845, 16150, 15446, 14732, 14009, 13278, + 12539, 11792, 11038, 10278, 9511, 8739, 7961, 7179, + 6392, 5601, 4807, 4011, 3211, 2410, 1607, 804, + 0, -804, -1607, -2410, -3211, -4011, -4807, -5601, + -6392, -7179, -7961, -8739, -9511,-10278,-11038,-11792, + -12539,-13278,-14009,-14732,-15446,-16150,-16845,-17530, + -18204,-18867,-19519,-20159,-20787,-21402,-22004,-22594, + -23169,-23731,-24278,-24811,-25329,-25831,-26318,-26789, + -27244,-27683,-28105,-28510,-28897,-29268,-29621,-29955, + -30272,-30571,-30851,-31113,-31356,-31580,-31785,-31970, + -32137,-32284,-32412,-32520,-32609,-32678,-32727,-32757, + -32767,-32757,-32727,-32678,-32609,-32520,-32412,-32284, + -32137,-31970,-31785,-31580,-31356,-31113,-30851,-30571, + -30272,-29955,-29621,-29268,-28897,-28510,-28105,-27683, + -27244,-26789,-26318,-25831,-25329,-24811,-24278,-23731, + -23169,-22594,-22004,-21402,-20787,-20159,-19519,-18867, + -18204,-17530,-16845,-16150,-15446,-14732,-14009,-13278, + -12539,-11792,-11038,-10278, -9511, -8739, -7961, -7179, + -6392, -5601, -4807, -4011, -3211, -2410, -1607, -804, + }; + +const TInt16 TSineGen::IncTable[KMaxSineTable] = + { + 804, 803, 803, 801, 800, 796, 794, + 791, 787, 782, 778, 772, 767, 760, 754, + 747, 739, 731, 723, 714, 704, 695, 685, + 674, 663, 652, 640, 628, 615, 602, 590, + 575, 562, 547, 533, 518, 502, 487, 471, + 455, 439, 422, 405, 387, 371, 353, 334, + 317, 299, 280, 262, 243, 224, 205, 185, + 167, 147, 128, 108, 89, 69, 49, 30, + 10, -10, -30, -49, -69, -89, -108, -128, + -147, -167, -185, -205, -224, -243, -262, -280, + -299, -317, -334, -353, -371, -387, -405, -422, + -439, -455, -471, -487, -502, -518, -533, -547, + -562, -575, -590, -602, -615, -628, -640, -652, + -663, -674, -685, -695, -704, -714, -723, -731, + -739, -747, -754, -760, -767, -772, -778, -782, + -787, -791, -794, -796, -800, -801, -803, -803, + -804, -804, -803, -803, -801, -800, -796, -794, + -791, -787, -782, -778, -772, -767, -760, -754, + -747, -739, -731, -723, -714, -704, -695, -685, + -674, -663, -652, -640, -628, -615, -602, -590, + -575, -562, -547, -533, -518, -502, -487, -471, + -455, -439, -422, -405, -387, -371, -353, -334, + -317, -299, -280, -262, -243, -224, -205, -185, + -167, -147, -128, -108, -89, -69, -49, -30, + -10, 10, 30, 49, 69, 89, 108, 128, + 147, 167, 185, 205, 224, 243, 262, 280, + 299, 317, 334, 353, 371, 387, 405, 422, + 439, 455, 471, 487, 502, 518, 533, 547, + 562, 575, 590, 602, 615, 628, 640, 652, + 663, 674, 685, 695, 704, 714, 723, 731, + 739, 747, 754, 760, 767, 772, 778, 782, + 787, 791, 794, 796, 800, 801, 803, 803, + 804 + }; + +void TSineGen::SetFrequency(TInt aFrequency,TInt aAmplitude) +// +// Given the frequency set iStep. +// Reset iPosition to the equivalent of 0 degrees. +// In the special case of aFrequency==4KHz set iPosition to 90 degrees. +// + { + + if (aAmplitude>(1<<15)) + iAmplitude=(1<<15); + else if (aAmplitude<-(1<<15)) + iAmplitude=-(1<<15); + else + iAmplitude=aAmplitude; +// +// There are 256 entries in the sine table to traverse 360 degrees. +// The codec requires samples at a rate of 8000 per second. +// Thus for a 1Hz tone the step will be 256/8000 or 4/125. +// Now we need need the integer part of the result to end up in +// the MSB so we need to multiply by 2^24. This gives the formula +// step = (f*4*2^24)/125 or (f*2^26)/125. +// Our highest frequency is 4KHz so that the term (f*2^26) exceeds +// a 32 bit result by 4000/2^6 (2^6 is the number of significant bits +// left after a multiply by 2^26). i.e. 6 bits. We overcome this by +// having 6 bits less in the fraction, so the new formula becomes +// ((f*2^20)/125)*2^6. This still gives us 20 significant bits in the +// fraction. +// + + iStep=(((TUint)aFrequency<<20)/125)<<6; + iPosition=(aFrequency==4000 ? 0x40000000 : 0); + } + +TInt TSineGen::NextSample() +// +// Generate the next sample using linear interpolation +// + { + TUint pos=iPosition>>24; + TInt amp=((IncTable[pos]*((iPosition&0x00ffffff)>>20))); + amp>>=4; + amp+=SineTable[pos]; + amp=(amp*iAmplitude)>>15; + iPosition+=iStep; + return(amp); + } + +void TSineWave::Generate(TInt16* aDest,TInt aCount) +// +// Called when more samples need to be generated. +// + { + while (aCount--) + { + *aDest++=STATIC_CAST(TInt16,iGen1.NextSample()+iGen2.NextSample()); + } + } + +void TSineWave::SetFrequency(TInt aFrequency,TInt aAmplitude) +// +// Set to generate a single frequency +// + { + SetFrequency(aFrequency,aAmplitude,0,0); + } + +void TSineWave::SetFrequency(TInt aFrequency1,TInt aAmplitude1,TInt aFrequency2,TInt aAmplitude2) +// +// Set to generate two frequencies +// + { + iGen1.SetFrequency(aFrequency1,aAmplitude1); + iGen2.SetFrequency(aFrequency2,aAmplitude2); + } + + +// +// TMdaToneGenerator +// + +void TMdaToneGenerator::Configure(TInt aRate, TInt aChannels, TInt aRepeats, TInt aSilence, TInt aRampUp) +// +// Set up this tone generator to generate data at the desired sample rate +// and number of channels (typically mono/stereo) +// + { + iRate = aRate; + iChannels = aChannels; + iSamplesLeft = 0; + iRampUp = ETrue; // Default ramping to on as it is normally useful + iRampDown = ETrue; + iRepeats = aRepeats; + iSilenceBetweenRepeats = aSilence; + iRampUpCount = aRampUp; + iRampUpLeft = aRampUp; + iAfterRepeatSilence = EFalse; + } + +LOCAL_C void RampVolume(TInt16* aData,TInt aCount,TInt aStartVol,TInt aEndVol) +// +// Simple function to ramp down the volume of some samples +// Typically used to prevent "clicking" artifacts at the beginning/end of tones +// + { + TInt step = (aEndVol - aStartVol)/aCount; + while (aCount--) + { + TInt data = TInt(*aData) * aStartVol; + *aData++ = TInt16(data>>15); + aStartVol += step; + } + } + +TInt TMdaToneGenerator::FillBuffer(TDes8& aBuffer) +// +// Fill the supplied buffer with tone data +// Sets the buffer length to zero if there is no more data to play +// The buffer must have a max length of at least one sample * channels +// e.g. 2 bytes mono, 4 bytes stereo +// + { + ASSERT(aBuffer.MaxLength()>= (iChannels<<1)); + aBuffer.SetMax(); + + TBool silence; + TInt samples = 0; // + TInt used = 0; // Data used + TInt avail = aBuffer.Length(); // Data filled + TInt count = 0; // Data to be converted + TBool rampUp = EFalse; + + TMdaPtr8 fill; + fill.Set(aBuffer); // Pointer to data left to be filled + + // + // The rest of this function will loop around continually until the buffer + // is filled or there is no more data to play + // + +Restart: + silence = EFalse; // Reset + if (iSamplesLeft == 0) + { + if (iTrailingSilence == 0) + { + TInt error = GetNextTone(); + if (error) + return error; + + rampUp = ETrue; + if ((iSamplesLeft==0)&&(iTrailingSilence==0)) + { + if ((iSilenceBetweenRepeats)&&(!iAfterRepeatSilence)) + { + iTrailingSilence = iSilenceBetweenRepeats; + iAfterRepeatSilence = ETrue; + goto Restart; + } + else + { + if ((iRepeats>0)||(iRepeats==KMdaRepeatForever)) + { + iAfterRepeatSilence = EFalse; + if (iRepeats>0) + iRepeats--; + + Reset(); + goto Restart; + } + } + // No more to play + goto Finished; + } + goto Restart; + } + else + { + silence = ETrue; + samples = iTrailingSilence; + } + } + else + samples = iSamplesLeft; + + count = Min(samples,avail>>1); + fill.SetLength(count<<1); + + if (!silence) + { // Generate wave + iSineWave.Generate(REINTERPRET_CAST(TInt16*,&fill[0]),count); + if (iRampUp) + { // Ramp up volume at beginning of tone + const TInt KRampUpSamples = 50; + if (rampUp) + { // Fade in first few samples + TInt fadeInLength = Min(Min(KRampUpSamples,iSamplesLeft),(fill.Length()>>1)); + RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&fill[0]))),fadeInLength,0,1<<15); + } + } + if (iRampDown) + { // Ramp down volume at end of tone + const TInt KRampDownSamples = 50; + if ((iSamplesLeft-count) < KRampDownSamples) + { // Fade out last few samples + TInt fadeOutLength = Min(Min(KRampDownSamples,iSamplesLeft),(fill.Length()>>1)); + RampVolume(CONST_CAST(TInt16*,REINTERPRET_CAST(const TInt16*,(&(fill.Right(fadeOutLength<<1))[0]))),fadeOutLength,1<<15,0); + } + } + iSamplesLeft -= count; + } + else + { // Generate silence + fill.FillZ(count<<1); + iTrailingSilence -= count; + } + + used += count<<1; + avail -= count<<1; + fill.Shift(count<<1); + + if (avail>(iChannels<<1)) + goto Restart; + +Finished: + + aBuffer.SetLength(used); + + // Do any ramp up that is required + if (iRampUpLeft>0) + { + TInt words = iRampUpLeft * iChannels; + words = Min(words,used>>1); + if (words>0) // In case buffer has zero length... + { + TInt left = iRampUpLeft * iChannels; + TInt rampup = iRampUpCount * iChannels; + iRampUpLeft -= words/iChannels; + TInt16* sample = REINTERPRET_CAST(TInt16*,&aBuffer[0]); + while (words--) + { + *sample++ = STATIC_CAST(TInt16,(TInt32(*sample)*(rampup-(left--)))/rampup); + } + } + } + + return KErrNone; + } + +TInt TMdaToneGenerator::DurationToSamples(const TTimeIntervalMicroSeconds& aDuration) +// +// Convert the given duration to a sample count using the current settings +// + { + const TInt64 KTInt64OneMilion = 1000000; + + // Calculate duration as samples + TInt64 microSeconds(aDuration.Int64()); // MSVC doesn't like "aDuration.Int64()" in line below + TInt64 dur = ((TInt64(iRate) * TInt64(iChannels) * microSeconds) / KTInt64OneMilion); + if (I64HIGH(dur)>0) + return KMaxTInt; // Ridiculous! + else + return I64LOW(dur); + } + +// +// TMdaSimpleToneGenerator +// + +void TMdaSimpleToneGenerator::Reset() + { + iPlayed = EFalse; + } + +void TMdaSimpleToneGenerator::SetFrequencyAndDuration(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration) +// +// Store the frequency and duration of the specified sine tone +// + { + iFrequency = aFrequency; + iDuration = aDuration; + iPlayed = EFalse; + } + +TInt TMdaSimpleToneGenerator::GetNextTone() +// +// Simple implementation - just sets the supplied frequency and duration +// + { + // This class only plays one tone for the specified duration + if (!iPlayed) + { + iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/1000000); + iSineWave.SetFrequency(iFrequency,1<<14); + iPlayed = ETrue; + iTrailingSilence = 20; // Just to stop clicking + } + return KErrNone; + } + +// +// TMdaDualToneGenerator +// + +void TMdaDualToneGenerator::Reset() + { + iPlayed = EFalse; + } + +void TMdaDualToneGenerator::SetFrequencyAndDuration(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration) + { + // Store the frequencies and duration of the specified dual tone + iFrequencyOne = aFrequencyOne; + iFrequencyTwo = aFrequencyTwo; + iDuration = aDuration; + iPlayed = EFalse; + } + +// +// This is called by TMdaToneGenerator::FillBuffer() +// to calculate the number of samples (iSamplesLeft) that will be needed +// for the tone to be played and to initialize the sine wave generator. +// If the tone has already been played, then leaves iSamplesLeft +// unmodified (should be zero) to indicate that it has finished. +// +TInt TMdaDualToneGenerator::GetNextTone() + { + // This class only plays one tone for the specified duration + if (!iPlayed) + { + iSamplesLeft = I64LOW((iDuration.Int64() * TInt64(iRate))/KOneMillionMicroSeconds); + iSineWave.SetFrequency(iFrequencyOne, KMaxAmplitude/2, iFrequencyTwo, KMaxAmplitude/2); + iPlayed = ETrue; + iTrailingSilence = KDefaultTrailingSilenceSamples; // Just to stop clicking + } + return KErrNone; + } +// +// TMdaDTMFGenerator +// + +const TInt KRecalculateToneLengths = KMinTInt; + +void TMdaDTMFGenerator::Reset() + { + iChar = 0; + } + +void TMdaDTMFGenerator::SetToneDurations(const TTimeIntervalMicroSeconds32 aOn, + const TTimeIntervalMicroSeconds32 aOff, + const TTimeIntervalMicroSeconds32 aPause) +// +// Setup the DTMF tone durations +// aOn can be == -1 indicating should play first tone indefinately +// + { + ASSERT(aOn.Int() >=-1); + ASSERT(aOff.Int()>=0); + ASSERT(aPause.Int()>=0); + + iOn = aOn; + iOff = aOff; + iPause = aPause; + + iOnSamples = KRecalculateToneLengths; // Must recalculate these later + } + +void TMdaDTMFGenerator::SetString(const TDesC& aDTMFString) +// +// Store the DTMF string to be played +// No need to validate it as it will already have been checked +// + { + iChar = 0; + iDTMFString = &aDTMFString; + } + +const TUint8 KDtmfVolumeTable[4][4]= +// +// Relative strengths to assign to different DTMF tones +// +// This is only important if DTMFs are being played through a speaker +// and need to be machine-recognisable. This table compensates for frequency +// drop-off in the speaker and can boost the relative volume of some +// frequencies so they are still within tolerance. +// +// The values normally need to be determined using a frequency analyser on +// the hardware +// +// Each column == same low frequency (697, 770, 852, 941 Hz) +// Each row == same high frequency (1209, 1336, 1477, 1633 Hz) +// +// The value are interpreted as ratios: +// 0 == 100% low +// 7f == 50% low, 50% high +// ff == 100% high +// + { + {38,27,29,37}, + {46,36,36,46}, + {62,47,49,58}, + {70,56,60,68} + }; + +const TUint8 KDtmfTone697=0x0; +const TUint8 KDtmfTone770=0x1; +const TUint8 KDtmfTone852=0x2; +const TUint8 KDtmfTone941=0x3; + +const TUint8 KDtmfTone1209=0x00; +const TUint8 KDtmfTone1336=0x10; +const TUint8 KDtmfTone1477=0x20; +const TUint8 KDtmfTone1633=0x30; + +const TUint8 KDtmfToneTable[16]= + { + KDtmfTone941|KDtmfTone1336,//0 + KDtmfTone697|KDtmfTone1209,//1 + KDtmfTone697|KDtmfTone1336,//2 + KDtmfTone697|KDtmfTone1477,//3 + KDtmfTone770|KDtmfTone1209,//4 + KDtmfTone770|KDtmfTone1336,//5 + KDtmfTone770|KDtmfTone1477,//6 + KDtmfTone852|KDtmfTone1209,//7 + KDtmfTone852|KDtmfTone1336,//8 + KDtmfTone852|KDtmfTone1477,//9 + + KDtmfTone697|KDtmfTone1633,//A + KDtmfTone770|KDtmfTone1633,//B + KDtmfTone852|KDtmfTone1633,//C + KDtmfTone941|KDtmfTone1633,//D + KDtmfTone941|KDtmfTone1209,//E or * + KDtmfTone941|KDtmfTone1477,//F or # + }; + +TInt TMdaDTMFGenerator::GetNextTone() +// +// Setup frequency/duration/silence settings for next DTMF tone +// Supported characters are 0-9 A-F * # , and any kind of white space +// + { + TBool onlyPlayFirstTone = EFalse; + + if (iOnSamples == KRecalculateToneLengths) + { + // Must recalculate tone durations as samples + + // Handle special case where tone on duration negative + // - meaning play first character indefinately + if (iOn.Int()>=0) + iOnSamples = DurationToSamples(TInt64(iOn.Int())); + else + { + onlyPlayFirstTone = ETrue; + iOnSamples = -1; + } + + iOffSamples = DurationToSamples(TInt64(iOff.Int())); + iPauseSamples = DurationToSamples(TInt64(iPause.Int())); + } + + ASSERT(iDTMFString); + + if (iChar==iDTMFString->Length()) + return KErrNone; // Finished. Nothing to do + + TInt highFrequency = 0; + TInt highVolume = 0; + TInt lowFrequency = 0; + TInt lowVolume =0; + +Retry: + TChar c((*iDTMFString)[iChar++]); + if ((TUint)c=='#' || (TUint)c=='*' || c.IsHexDigit()) + { + TInt tableIndex; + switch ((TUint)c) + { + case '*': + tableIndex=14; + break; + case '#': + tableIndex=15; + break; + default: + if (c.IsDigit()) + tableIndex=(TUint)c-'0'; + else //letter + { + c.UpperCase(); + tableIndex=(TUint)c-'A'+10; + } + } + TInt high=KDtmfToneTable[tableIndex]&0xf0; + TInt low=KDtmfToneTable[tableIndex]&0x0f; + switch(high) + { + case KDtmfTone1209: + highFrequency=1209; + break; + case KDtmfTone1336: + highFrequency=1336; + break; + case KDtmfTone1477: + highFrequency=1477; + break; + default://KDtmfTone1633: + highFrequency=1633; + break; + } + switch(low) + { + case KDtmfTone697: + lowFrequency=697; + break; + case KDtmfTone770: + lowFrequency=770; + break; + case KDtmfTone852: + lowFrequency=852; + break; + default://KDtmfTone941: + lowFrequency=941; + break; + } + high>>=4; + const TUint8* dtmfVolumes=&KDtmfVolumeTable[0][0]; + TInt volume=dtmfVolumes[((low)<<2)+(high)]<<7; + highVolume = volume; + lowVolume = (1<<15)-volume; + + iTrailingSilence = iOffSamples; + iSamplesLeft = iOnSamples; + } + else if ((TUint)c==',') + { + iTrailingSilence = iPauseSamples; + iSamplesLeft = 0; + } + else if (c.IsSpace()) + { + if (iChar < iDTMFString->Length()) + goto Retry; + } + else + return KErrCorrupt; + + if (iOnSamples < 0) // Play only first character for ever + { + iTrailingSilence = 0; + iSamplesLeft = iRate * iChannels; // One second of samples + iChar = 0; // Reset so this character is played again next time + iRampDown = EFalse; + if (!onlyPlayFirstTone) + { + iRampUp = EFalse; + // This is not the first time around so we should not + // reset the tone generator - it will already have the + // correct settings and setting them again would cause + // an audible discontinuity + return KErrNone; + } + } + + iSineWave.SetFrequency(highFrequency,highVolume,lowFrequency,lowVolume); + return KErrNone; + } + +// +// TMdaSequenceGenerator +// + +// +// Sequence constants +// + +//const TInt KMaxFixedSequenceStack=KMaxSequenceStack;//Max nesting level of FixedSequences * 2 +#ifdef _DEBUG +const TInt16 KFixedSequenceSignatureOne='S'+('Q'<<8); +const TInt16 KFixedSequenceSignatureTwo='N'+('C'<<8); +#endif // _DEBUG + +const TInt KFixedSequenceFunctionReturn=-1; +const TInt KFixedSequenceFunctionStartLoop=-2; +const TInt KFixedSequenceFunctionEndLoop=-3; + +void TMdaSequenceGenerator::Reset() + { + iInstructionPtr = REINTERPRET_CAST(const TInt16*,&((*iSequenceData)[0])); + iInstructionPtr += 2; // Skip signature + iStackIndex = 0; + } + +void TMdaSequenceGenerator::SetSequenceData(const TDesC8& aSequenceData) +// +// Store the sequence data to be played +// No need to validate it as it will already have been checked +// + { + iSequenceData = &aSequenceData; + iInstructionPtr = REINTERPRET_CAST(const TInt16*,&aSequenceData[0]); + iLastInstruction = iInstructionPtr + (iSequenceData->Length()>>1) - 1; + + // These are asserts because this should not be called if signature not present + ASSERT(*iInstructionPtr == KFixedSequenceSignatureOne); + ASSERT(*(iInstructionPtr+1) == KFixedSequenceSignatureTwo); + + iInstructionPtr += 2; // Skip signature + + iStackIndex = 0; + } + +TInt TMdaSequenceGenerator::GetNextTone() +// +// + { + ASSERT(iInstructionPtr); // Sanity check + + TInt ret = KRequestPending; + while (ret == KRequestPending) + { + if (iInstructionPtr > iLastInstruction) + ret = KErrCorrupt; + else if (*iInstructionPtr<=0) + { + switch (*iInstructionPtr) + { + case KFixedSequenceFunctionReturn: // End of sequence + ret = KErrNone; + break; + + case KFixedSequenceFunctionStartLoop: + if (iStackIndex>2) // Validate - can only nest twice + ret = KErrCorrupt; + else if ((iInstructionPtr+2) > iLastInstruction) + ret = KErrCorrupt; // Don't run off end of sequence + else + { + iStack[iStackIndex++]=(TInt)(iInstructionPtr+2); + iStack[iStackIndex++]=(TInt)*(iInstructionPtr+1); + iInstructionPtr+=2; + } + break; + + case KFixedSequenceFunctionEndLoop: + if (iStackIndex==0) // Validate - must already be nested + ret = KErrCorrupt; + else + { + if ((--iStack[iStackIndex-1])!=0) + iInstructionPtr=(TInt16*)iStack[iStackIndex-2]; + else + { + iStackIndex-=2; + iInstructionPtr++; + } + } + break; + + default: // Bad sequence + ret = KErrCorrupt; + } + } + else + { + if ((iInstructionPtr+5) > iLastInstruction) + ret = KErrCorrupt; // Don't run off end of sequence + else + { + iSamplesLeft = *iInstructionPtr++; + TInt freqOne = *iInstructionPtr++; + TInt volOne = *iInstructionPtr++; + TInt freqTwo = *iInstructionPtr++; + TInt volTwo = *iInstructionPtr++; + + if ((volOne> 1<<15)||(volTwo > 1<<15)) + ret = KErrCorrupt; + else + { + iSineWave.SetFrequency(freqOne,volOne,freqTwo,volTwo); + ret = KErrNone; + } + } + } + } + return ret; + } + +// --------------------------------- +// Code to generate sine table files used by tone generator +// Optionally called from InitL() +// #define GENERATE_SINE_TABLES 1 +#ifdef GENERATE_SINE_TABLES +LOCAL_C GenerateSineTableL() + { + _LIT(KSineFile,"sine.txt"); + _LIT(KSineIncFile,"sineinc.txt"); + + RFile file; + file.Replace(MdaManager::Fs(),KSineFile,EFileWrite); + CleanupClosePushL(file); + + RFile file2; + file2.Replace(MdaManager::Fs(),KSineIncFile,EFileWrite); + CleanupClosePushL(file2); + + const TReal pi=3.141592653589; + const TReal twopi=pi*2; + const TReal samples = 256.0; + const TReal step = twopi/samples; + + TBuf8<128> sinebuffer; + TBuf8<128> incbuffer; + TReal res; + TInt first=0; + TInt last=KMaxTInt; + TInt current; + _LIT8(KFormat,"%6d,"); + _LIT8(KNewLine,"\n"); + + for(TReal angle=0.0;angle<=(twopi-step);) // Copes with rounding errors + { + sinebuffer.Zero(); + incbuffer.Zero(); + for (int i=0;i<8;i++) + { + User::LeaveIfError(Math::Sin(res,angle)); + current = TInt(KMaxTInt16*res); + sinebuffer.AppendFormat(KFormat,current); + if (last != KMaxTInt) + incbuffer.AppendFormat(KFormat,current-last); + else + first = current; + last = current; + angle += step; + } + sinebuffer.Append(KNewLine); + incbuffer.Append(KNewLine); + file.Write(sinebuffer); + file2.Write(incbuffer); + } + + // Write fine difference to incbuffer - differnece between first and last + incbuffer.Zero(); + incbuffer.AppendFormat(KFormat,first-last); + incbuffer.Append(KNewLine); + file2.Write(incbuffer); + + CleanupStack::PopAndDestroy(2); + } +#endif +//-------------------------------