Update contrib.
1 // Copyright (c) 2002-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 // include\mmf\utils\rateconvert.cpp
15 // Note this code used to be in mmfutilities.cpp but split off here to allow
16 // scaling of descriptors instead of just CMMFBuffers.
20 #include "rateconvertimpl.h" // includes rateconvert.h itself
23 const TInt KMaxInt16Bit = 65536 ;
26 The rate conversion algorithms used here are extremely basic, using nearest neighbour, not
27 even interpolation. An increment is created - initially a real, but converted to 16.16 fixed
28 point notation for efficiency purposes. For example, from 8000 to 11025 this increment is set
29 at 8000/11025 (~ 0.73). Each increment to the destination buffer conceptually increments the
30 src pointer by this value (0.73). On each iteration the nearest src sample is used.
32 The idea is that successive buffers run on from each other. The index is adjusted so at the end
33 of the run it is correct for the next buffer, and this is saved from one iteration to the next.
34 If the client wants to convert separate buffers, it should call Reset(), where the index is reset
37 Note the algorithm is even then not ideal, as it effectively truncates and not rounds the
38 fixed-point index. However, a feature of this is that the nearest src sample is always behind the
39 conceptual fixed-point index. This makes it easy to ensure that processing of the next buffer
40 never needs data from the previous cycle - except this index value.
46 EPanicNoDestinationBuffer=1,
47 EPanicNoSourceConsumed
52 static void Panic(TInt aPanicCode)
54 _LIT(KRateConvert,"RateConvert");
55 User::Panic(KRateConvert, aPanicCode);
61 // CChannelAndSampleRateConverter
64 CChannelAndSampleRateConverter::CChannelAndSampleRateConverter()
66 // constructor does nothing but ensures can't derive from outside dll
70 EXPORT_C CChannelAndSampleRateConverter* CChannelAndSampleRateConverter::CreateL(TInt aFromRate,
75 // check that the params in range so we can assume OK later on
76 if (aFromChannels <= 0 || aFromChannels > 2 ||
77 aToChannels <= 0 || aToChannels > 2 ||
78 aFromRate <= 0 || aToRate <= 0)
80 User::Leave(KErrArgument);
83 CChannelAndSampleRateConverterCommon* converter = NULL;
85 if (aFromChannels==aToChannels)
89 converter = new (ELeave) CMonoToMonoRateConverter;
93 converter = new (ELeave) CStereoToStereoRateConverter;
100 if (aFromRate!=aToRate)
102 converter = new (ELeave) CMonoToStereoRateConverter;
106 converter = new (ELeave) CMonoToStereoConverter;
111 ASSERT(aFromChannels>1 && aToChannels==1);
112 if (aFromRate!=aToRate)
114 converter = new (ELeave) CStereoToMonoRateConverter;
118 converter = new (ELeave) CStereoToMonoConverter;
122 converter->SetRates(aFromRate,aToRate);
127 // CChannelAndSampleRateConverterImpl
130 CChannelAndSampleRateConverterCommon::CChannelAndSampleRateConverterCommon()
134 void CChannelAndSampleRateConverterCommon::Reset()
136 // default does nothing
139 void CChannelAndSampleRateConverterCommon::SetRates(TInt /*aFromRate*/, TInt /*aToRate*/)
141 // in default no need to know so don't cache
144 TInt CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
146 // assume aSrcBuffer takes channel change into account
147 TInt rawValue = aSrcBufferSize;
150 return NextPowerUp(rawValue);
158 TInt CChannelAndSampleRateConverterCommon::NextPowerUp(TInt aValue)
160 TInt power = 128; // no need to start lower
169 // CChannelAndSampleRateConvert
172 CChannelAndSampleRateConvert::CChannelAndSampleRateConvert()
177 TInt CChannelAndSampleRateConvert::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
179 // take rate conversion into account. Assumed channel mismatch handled by the child class.
180 TInt rawValue = aSrcBufferSize;
181 if (iFromRate < iToRate)
183 TInt result = SizeOfUpsampleBuffer(rawValue);
184 return result; // always rounded up to next size
190 return NextPowerUp(rawValue);
199 void CChannelAndSampleRateConvert::SetRates(TInt aFromRate, TInt aToRate)
204 TReal ratio = TReal(aFromRate) / TReal(aToRate);
205 TInt quotient = TInt(ratio);
206 TReal remainder = ratio - TReal(quotient);
207 iFraction = (quotient << 16) + TInt32(remainder * KMaxInt16Bit);
212 void CChannelAndSampleRateConvert::Reset()
217 TInt CChannelAndSampleRateConvert::SizeOfUpsampleBuffer(TInt aBufferLength)
219 TInt rawValue = aBufferLength;
220 ASSERT(iFromRate < iToRate); // should not be called otherwise
221 // upsample - will generate more data. use floats to avoid extra round error
222 rawValue = TInt(rawValue * TReal(iToRate) / TReal(iFromRate) + 0.5) + 4*sizeof(TInt16); // add some buffer extra buffer
223 rawValue = NextPowerUp(rawValue); // when upscaling always give nice power
228 // Specific converter code
231 CStereoToStereoRateConverter::CStereoToStereoRateConverter()
235 TInt CStereoToStereoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
237 const TInt32* srcPtr = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
238 TInt32* dstPtr = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
240 const TInt32* srcLimit=srcPtr+LengthBytesTo32Bit(aSrcBuffer.Length()); // ptr+n does *4 for TInt32* ptr
241 TInt32* dstLimit=dstPtr+LengthBytesTo32Bit(aDstBuffer.MaxLength()); // ditto
243 // add left over from last buffer
244 TUint index = iIndex;
245 const TInt32* src = srcPtr + (index>>16);
246 TInt32* dst = dstPtr;
250 __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
254 while (src<srcLimit && dst<dstLimit)
258 src = srcPtr + (index>>16); // truncate fix-point index
261 // get amount by which index exceeded end of buffer
262 // so that we can add it back to start of next buffer
263 const TInt32* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration
264 TInt srcSamplesCopied = conceptualLastSrc - srcPtr;
265 __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space
266 iIndex = index - (srcSamplesCopied << 16);
268 // return sample byte count and setup output buffer
269 TInt dstLength = Length32BitToBytes(dst-dstPtr);
270 aDstBuffer.SetLength(dstLength); //adjust length of destination buffer
271 return Length32BitToBytes(srcSamplesCopied);
274 CMonoToStereoRateConverter::CMonoToStereoRateConverter()
278 TInt CMonoToStereoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
280 const TInt16* srcPtr = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
281 TInt32* dstPtr = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
283 const TInt16* srcLimit=srcPtr+LengthBytesTo16Bit(aSrcBuffer.Length()); // as ptr+n does *2 for TInt16* ptr
284 TInt32* dstLimit=dstPtr+LengthBytesTo32Bit(aDstBuffer.MaxLength()); // ditto but does *4 for TInt32*
286 // add left over from last buffer
287 TUint index = iIndex;
288 const TInt16* src = srcPtr + (index>>16);
289 TInt32* dst = dstPtr;
293 __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
297 while (src<srcLimit && dst<dstLimit-1)
299 TInt16 sample = *src;
300 TInt32 stereoSample = MonoToStereo(sample);
301 *dst++ = stereoSample;
303 src = srcPtr + (index>>16); // truncate fix-point index
306 // get amount by which index exceeded end of buffer
307 // so that we can add it back to start of next buffer
308 const TInt16* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration
309 TInt srcSamplesCopied = conceptualLastSrc - srcPtr;
310 __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space
311 iIndex = index - (srcSamplesCopied << 16);
313 // return sample byte count and setup output buffer
314 TInt dstLength = Length32BitToBytes(dst-dstPtr); // size in bytes
315 aDstBuffer.SetLength(dstLength); //adjust length of destination buffer
316 return Length16BitToBytes(srcSamplesCopied);
320 TInt CMonoToStereoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
322 return CChannelAndSampleRateConvert::MaxConvertBufferSize(aSrcBufferSize*2, aRoundUpToPower);
325 CMonoToMonoRateConverter::CMonoToMonoRateConverter()
329 TInt CMonoToMonoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
331 const TInt16* srcPtr = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
332 TInt16* dstPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
334 const TInt16* srcLimit=srcPtr+LengthBytesTo16Bit(aSrcBuffer.Length()); // ptr+n does *2 for TInt16* ptr
335 TInt16* dstLimit=dstPtr+LengthBytesTo16Bit(aDstBuffer.MaxLength()); // ditto
337 // add left over from last buffer
338 TUint index = iIndex;
339 const TInt16* src = srcPtr + (index>>16);
340 TInt16* dst = dstPtr;
344 __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
348 while (src<srcLimit && dst<dstLimit)
352 src = srcPtr + (index>>16); // truncate fix-point index
355 // get amount by which index exceeded end of buffer
356 // so that we can add it back to start of next buffer
357 const TInt16* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration
358 TInt srcSamplesCopied = conceptualLastSrc - srcPtr;
359 __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space
360 iIndex = index - (srcSamplesCopied << 16);
362 // return sample byte count and setup output buffer
363 TInt dstLength = Length16BitToBytes(dst-dstPtr); // size in bytes
364 aDstBuffer.SetLength(dstLength); //adjust length of destination buffer
365 return Length16BitToBytes(srcSamplesCopied);
368 CStereoToMonoRateConverter::CStereoToMonoRateConverter()
372 //This method takes the left and right sample of interleaved PCM and sums it, then divides by 2
373 TInt CStereoToMonoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
375 const TInt32* srcPtr = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
376 TInt16* dstPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
378 const TInt32* srcLimit=srcPtr+LengthBytesTo32Bit(aSrcBuffer.Length()); // ptr+n does *4 for TInt32* ptr
379 TInt16* dstLimit=dstPtr+LengthBytesTo16Bit(aDstBuffer.MaxLength()); // ditto but *2 for TInt16*
381 // add left over from last buffer
382 TUint index = iIndex;
383 const TInt32* src = srcPtr + (index>>16);
384 TInt16* dst = dstPtr;
388 __ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
392 while (src<srcLimit && dst<dstLimit)
394 TInt32 sample = *src;
395 TInt16 monoSample = StereoToMono(sample);
398 src = srcPtr + (index>>16); // truncate fix-point index
401 // get amount by which index exceeded end of buffer
402 // so that we can add it back to start of next buffer
403 const TInt32* conceptualLastSrc = Min(src, srcLimit); // ptr to last src we have we'd _not_ used next iteration
404 TInt srcSamplesCopied = conceptualLastSrc - srcPtr;
405 __ASSERT_DEBUG(srcSamplesCopied>0, Panic(EPanicNoSourceConsumed)); // should always be ok if we have some destination space
406 iIndex = index - (srcSamplesCopied << 16);
408 // return sample byte count and setup output buffer
409 TInt dstLength = Length16BitToBytes(dst-dstPtr); // size in bytes
410 aDstBuffer.SetLength(dstLength); //adjust length of destination buffer
411 return Length32BitToBytes(srcSamplesCopied);
415 TInt CStereoToMonoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
417 TUint size = aSrcBufferSize/2;
418 size += aSrcBufferSize & 1; //avoid round down error
419 return CChannelAndSampleRateConvert::MaxConvertBufferSize(size, aRoundUpToPower);
422 CStereoToMonoConverter::CStereoToMonoConverter()
426 //This method takes the left and right sample of interleaved PCM and sums it, then divides by 2
427 TInt CStereoToMonoConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
429 const TInt32* src = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
430 TInt16* dst = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
432 TInt srcCount = LengthBytesTo32Bit(aSrcBuffer.Length());
433 TInt dstCount = LengthBytesTo16Bit(aDstBuffer.MaxLength());
434 TInt count = Min(srcCount, dstCount); // if aDstBuffer is short, just copy that much
436 for (TUint i=0;i<count;++i)
438 TInt32 sample = *src++;
439 TInt16 monoSample = StereoToMono(sample);
443 aDstBuffer.SetLength(Length16BitToBytes(count)); // *2 because is mono
444 return Length32BitToBytes(count); // *4 as is stereo
447 TInt CStereoToMonoConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
449 TUint size = aSrcBufferSize/2;
450 size += aSrcBufferSize & 1; //avoid round down error
451 return CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(size, aRoundUpToPower);
454 CMonoToStereoConverter::CMonoToStereoConverter()
458 TInt CMonoToStereoConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
460 const TInt16* src = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
461 TInt32* dst = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
463 TInt srcCount = LengthBytesTo16Bit(aSrcBuffer.Length());
464 TInt dstCount = LengthBytesTo32Bit(aDstBuffer.MaxLength());
465 TInt count = Min(srcCount, dstCount); // if aDstBuffer is short, just copy that much
467 for (TUint i=0;i<count;i++)
469 TInt16 sample = *src++;
470 TInt32 stereoSample = MonoToStereo(sample);
471 *dst++ = stereoSample;
474 aDstBuffer.SetLength(Length32BitToBytes(count)); // *4 because is stereo
475 return Length16BitToBytes(count); // *2 as is mono
478 TInt CMonoToStereoConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
480 return CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(aSrcBufferSize*2, aRoundUpToPower);