diff -r 000000000000 -r 58be5850fb6c omxilcomp/omxilaudioemulator/pcmrenderer/src/rateconvert.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omxilcomp/omxilaudioemulator/pcmrenderer/src/rateconvert.cpp Thu Sep 02 20:13:57 2010 +0300 @@ -0,0 +1,486 @@ +// Copyright (c) 2002-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: +// include\mmf\utils\rateconvert.cpp +// Note this code used to be in mmfutilities.cpp but split off here to allow +// scaling of descriptors instead of just CMMFBuffers. +// +// + +#include "rateconvertimpl.h" // includes rateconvert.h itself +#include + +const TInt KMaxInt16Bit = 65536 ; + +/* +The rate conversion algorithms used here are extremely basic, using nearest neighbour, not +even interpolation. An increment is created - initially a real, but converted to 16.16 fixed +point notation for efficiency purposes. For example, from 8000 to 11025 this increment is set +at 8000/11025 (~ 0.73). Each increment to the destination buffer conceptually increments the +src pointer by this value (0.73). On each iteration the nearest src sample is used. + +The idea is that successive buffers run on from each other. The index is adjusted so at the end +of the run it is correct for the next buffer, and this is saved from one iteration to the next. +If the client wants to convert separate buffers, it should call Reset(), where the index is reset +to 0. + +Note the algorithm is even then not ideal, as it effectively truncates and not rounds the +fixed-point index. However, a feature of this is that the nearest src sample is always behind the +conceptual fixed-point index. This makes it easy to ensure that processing of the next buffer +never needs data from the previous cycle - except this index value. + +*/ + +enum TPanicCodes + { + EPanicNoDestinationBuffer=1, + EPanicNoSourceConsumed + }; + +#ifdef _DEBUG + +static void Panic(TInt aPanicCode) + { + _LIT(KRateConvert,"RateConvert"); + User::Panic(KRateConvert, aPanicCode); + } + +#endif // _DEBUG + +// +// CChannelAndSampleRateConverter +// + +CChannelAndSampleRateConverter::CChannelAndSampleRateConverter() + { + // constructor does nothing but ensures can't derive from outside dll + } + +// Factory function +CChannelAndSampleRateConverter* CChannelAndSampleRateConverter::CreateL(TInt aFromRate, + TInt aFromChannels, + TInt aToRate, + TInt aToChannels) + { + // check that the params in range so we can assume OK later on + if (aFromChannels <= 0 || aFromChannels > 2 || + aToChannels <= 0 || aToChannels > 2 || + aFromRate <= 0 || aToRate <= 0) + { + User::Leave(KErrArgument); + } + + CChannelAndSampleRateConverterCommon* converter = NULL; + + if (aFromChannels==aToChannels) + { + if (aFromChannels==1) + { + converter = new (ELeave) CMonoToMonoRateConverter; + } + else + { + converter = new (ELeave) CStereoToStereoRateConverter; + } + } + else + { + if (aFromChannels==1) + { + if (aFromRate!=aToRate) + { + converter = new (ELeave) CMonoToStereoRateConverter; + } + else + { + converter = new (ELeave) CMonoToStereoConverter; + } + } + else + { + ASSERT(aFromChannels>1 && aToChannels==1); + if (aFromRate!=aToRate) + { + converter = new (ELeave) CStereoToMonoRateConverter; + } + else + { + converter = new (ELeave) CStereoToMonoConverter; + } + } + } + converter->SetRates(aFromRate,aToRate); + return converter; + } + +// +// CChannelAndSampleRateConverterImpl +// + +CChannelAndSampleRateConverterCommon::CChannelAndSampleRateConverterCommon() + { + } + +void CChannelAndSampleRateConverterCommon::Reset() + { + // default does nothing + } + +void CChannelAndSampleRateConverterCommon::SetRates(TInt /*aFromRate*/, TInt /*aToRate*/) + { + // in default no need to know so don't cache + } + +TInt CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower) + { + // assume aSrcBuffer takes channel change into account + TInt rawValue = aSrcBufferSize; + if (aRoundUpToPower) + { + return NextPowerUp(rawValue); + } + else + { + return rawValue; + } + } + +TInt CChannelAndSampleRateConverterCommon::NextPowerUp(TInt aValue) + { + TInt power = 128; // no need to start lower + while (power(aSrcBuffer.Ptr()); + TInt32* dstPtr = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + const TInt32* srcLimit=srcPtr+LengthBytesTo32Bit(aSrcBuffer.Length()); // ptr+n does *4 for TInt32* ptr + TInt32* dstLimit=dstPtr+LengthBytesTo32Bit(aDstBuffer.MaxLength()); // ditto + + // add left over from last buffer + TUint index = iIndex; + const TInt32* src = srcPtr + (index>>16); + TInt32* dst = dstPtr; + + if (dst>=dstLimit) + { + __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer)); + return 0; + } + + while (src>16); // truncate fix-point index + } + + // get amount by which index exceeded end of buffer + // so that we can add it back to start of next buffer + const TInt32* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration + TInt srcSamplesCopied = conceptualLastSrc - srcPtr; + __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space + iIndex = index - (srcSamplesCopied << 16); + + // return sample byte count and setup output buffer + TInt dstLength = Length32BitToBytes(dst-dstPtr); + aDstBuffer.SetLength(dstLength); //adjust length of destination buffer + return Length32BitToBytes(srcSamplesCopied); + } + +CMonoToStereoRateConverter::CMonoToStereoRateConverter() + { + } + +TInt CMonoToStereoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer) + { + const TInt16* srcPtr = reinterpret_cast(aSrcBuffer.Ptr()); + TInt32* dstPtr = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + const TInt16* srcLimit=srcPtr+LengthBytesTo16Bit(aSrcBuffer.Length()); // as ptr+n does *2 for TInt16* ptr + TInt32* dstLimit=dstPtr+LengthBytesTo32Bit(aDstBuffer.MaxLength()); // ditto but does *4 for TInt32* + + // add left over from last buffer + TUint index = iIndex; + const TInt16* src = srcPtr + (index>>16); + TInt32* dst = dstPtr; + + if (dst>=dstLimit) + { + __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer)); + return 0; + } + + while (src>16); // truncate fix-point index + } + + // get amount by which index exceeded end of buffer + // so that we can add it back to start of next buffer + const TInt16* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration + TInt srcSamplesCopied = conceptualLastSrc - srcPtr; + __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space + iIndex = index - (srcSamplesCopied << 16); + + // return sample byte count and setup output buffer + TInt dstLength = Length32BitToBytes(dst-dstPtr); // size in bytes + aDstBuffer.SetLength(dstLength); //adjust length of destination buffer + return Length16BitToBytes(srcSamplesCopied); + } + + +TInt CMonoToStereoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower) + { + return CChannelAndSampleRateConvert::MaxConvertBufferSize(aSrcBufferSize*2, aRoundUpToPower); + } + +CMonoToMonoRateConverter::CMonoToMonoRateConverter() + { + } + +TInt CMonoToMonoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer) + { + const TInt16* srcPtr = reinterpret_cast(aSrcBuffer.Ptr()); + TInt16* dstPtr = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + const TInt16* srcLimit=srcPtr+LengthBytesTo16Bit(aSrcBuffer.Length()); // ptr+n does *2 for TInt16* ptr + TInt16* dstLimit=dstPtr+LengthBytesTo16Bit(aDstBuffer.MaxLength()); // ditto + + // add left over from last buffer + TUint index = iIndex; + const TInt16* src = srcPtr + (index>>16); + TInt16* dst = dstPtr; + + if (dst>=dstLimit) + { + __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer)); + return 0; + } + + while (src>16); // truncate fix-point index + } + + // get amount by which index exceeded end of buffer + // so that we can add it back to start of next buffer + const TInt16* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration + TInt srcSamplesCopied = conceptualLastSrc - srcPtr; + __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space + iIndex = index - (srcSamplesCopied << 16); + + // return sample byte count and setup output buffer + TInt dstLength = Length16BitToBytes(dst-dstPtr); // size in bytes + aDstBuffer.SetLength(dstLength); //adjust length of destination buffer + return Length16BitToBytes(srcSamplesCopied); + } + +CStereoToMonoRateConverter::CStereoToMonoRateConverter() + { + } + +//This method takes the left and right sample of interleaved PCM and sums it, then divides by 2 +TInt CStereoToMonoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer) + { + const TInt32* srcPtr = reinterpret_cast(aSrcBuffer.Ptr()); + TInt16* dstPtr = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + const TInt32* srcLimit=srcPtr+LengthBytesTo32Bit(aSrcBuffer.Length()); // ptr+n does *4 for TInt32* ptr + TInt16* dstLimit=dstPtr+LengthBytesTo16Bit(aDstBuffer.MaxLength()); // ditto but *2 for TInt16* + + // add left over from last buffer + TUint index = iIndex; + const TInt32* src = srcPtr + (index>>16); + TInt16* dst = dstPtr; + + if (dst>=dstLimit) + { + __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer)); + return 0; + } + + while (src>16); // truncate fix-point index + } + + // get amount by which index exceeded end of buffer + // so that we can add it back to start of next buffer + const TInt32* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration + TInt srcSamplesCopied = conceptualLastSrc - srcPtr; + __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space + iIndex = index - (srcSamplesCopied << 16); + + // return sample byte count and setup output buffer + TInt dstLength = Length16BitToBytes(dst-dstPtr); // size in bytes + aDstBuffer.SetLength(dstLength); //adjust length of destination buffer + return Length32BitToBytes(srcSamplesCopied); + } + + +TInt CStereoToMonoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower) + { + TUint size = aSrcBufferSize/2; + size += aSrcBufferSize & 1; //avoid round down error + return CChannelAndSampleRateConvert::MaxConvertBufferSize(size, aRoundUpToPower); + } + +CStereoToMonoConverter::CStereoToMonoConverter() + { + } + +//This method takes the left and right sample of interleaved PCM and sums it, then divides by 2 +TInt CStereoToMonoConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer) + { + const TInt32* src = reinterpret_cast(aSrcBuffer.Ptr()); + TInt16* dst = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + TInt srcCount = LengthBytesTo32Bit(aSrcBuffer.Length()); + TInt dstCount = LengthBytesTo16Bit(aDstBuffer.MaxLength()); + TInt count = Min(srcCount, dstCount); // if aDstBuffer is short, just copy that much + + for (TUint i=0;i(aSrcBuffer.Ptr()); + TInt32* dst = const_cast(reinterpret_cast(aDstBuffer.Ptr())); + + TInt srcCount = LengthBytesTo16Bit(aSrcBuffer.Length()); + TInt dstCount = LengthBytesTo32Bit(aDstBuffer.MaxLength()); + TInt count = Min(srcCount, dstCount); // if aDstBuffer is short, just copy that much + + for (TUint i=0;i