os/mm/mmlibs/mmfw/src/utils/audioutils/rateconvert.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    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.
    17 // 
    18 //
    19 
    20 #include "rateconvertimpl.h" // includes rateconvert.h itself
    21 #include <e32const.h>
    22 
    23 const TInt KMaxInt16Bit = 65536 ; 
    24 
    25 /*
    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.
    31 
    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
    35 to 0. 
    36 
    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.
    41 
    42 */
    43 
    44 enum TPanicCodes
    45 	{
    46 	EPanicNoDestinationBuffer=1,
    47 	EPanicNoSourceConsumed
    48 	};
    49 
    50 #ifdef _DEBUG
    51 
    52 static void Panic(TInt aPanicCode)
    53 	{
    54 	_LIT(KRateConvert,"RateConvert");
    55 	User::Panic(KRateConvert, aPanicCode);
    56 	}
    57 	
    58 #endif // _DEBUG
    59 
    60 //
    61 // CChannelAndSampleRateConverter 
    62 //
    63 
    64 CChannelAndSampleRateConverter::CChannelAndSampleRateConverter()
    65 	{
    66 	// constructor does nothing but ensures can't derive from outside dll
    67 	}
    68 
    69 // Factory function
    70 EXPORT_C CChannelAndSampleRateConverter* CChannelAndSampleRateConverter::CreateL(TInt aFromRate,
    71 																				 TInt aFromChannels,
    72 										 										 TInt aToRate,
    73 										 										 TInt aToChannels)
    74 	{
    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)
    79 		{
    80 		User::Leave(KErrArgument);
    81 		}
    82 		
    83 	CChannelAndSampleRateConverterCommon* converter = NULL;
    84 
    85 	if (aFromChannels==aToChannels)
    86 		{
    87 		if (aFromChannels==1)
    88 			{
    89 			converter = new (ELeave) CMonoToMonoRateConverter;			
    90 			}
    91 		else
    92 			{
    93 			converter = new (ELeave) CStereoToStereoRateConverter;
    94 			}
    95 		}
    96 	else
    97 		{
    98 		if (aFromChannels==1)
    99 			{
   100 			if (aFromRate!=aToRate)
   101 				{
   102 				converter = new (ELeave) CMonoToStereoRateConverter;				
   103 				}
   104 			else
   105 				{
   106 				converter = new (ELeave) CMonoToStereoConverter;				
   107 				}
   108 			}
   109 		else
   110 			{
   111             ASSERT(aFromChannels>1 && aToChannels==1);
   112 			if (aFromRate!=aToRate)
   113 				{
   114 				converter = new (ELeave) CStereoToMonoRateConverter;				
   115 				}
   116 			else
   117 				{
   118  				converter = new (ELeave) CStereoToMonoConverter;				
   119 				}
   120 			}
   121 		}
   122 	converter->SetRates(aFromRate,aToRate);
   123 	return converter;
   124 	}
   125 	
   126 //
   127 // CChannelAndSampleRateConverterImpl
   128 //
   129 
   130 CChannelAndSampleRateConverterCommon::CChannelAndSampleRateConverterCommon()
   131 	{
   132 	}
   133 
   134 void CChannelAndSampleRateConverterCommon::Reset()
   135 	{
   136 	// default does nothing
   137 	}
   138 	
   139 void CChannelAndSampleRateConverterCommon::SetRates(TInt /*aFromRate*/, TInt /*aToRate*/)
   140 	{
   141 	// in default no need to know so don't cache
   142 	}
   143 
   144 TInt CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   145 	{
   146 	// assume aSrcBuffer takes channel change into account
   147 	TInt rawValue = aSrcBufferSize;
   148 	if (aRoundUpToPower)
   149 		{
   150 		return NextPowerUp(rawValue); 
   151 		}
   152 	else
   153 		{
   154 		return rawValue;
   155 		}
   156 	}
   157 	
   158 TInt CChannelAndSampleRateConverterCommon::NextPowerUp(TInt aValue)
   159 	{
   160 	TInt power = 128; // no need to start lower
   161 	while (power<aValue)
   162 		{
   163 		power *= 2;
   164 		}
   165 	return power;
   166 	}
   167 	
   168 //
   169 // CChannelAndSampleRateConvert
   170 //
   171 
   172 CChannelAndSampleRateConvert::CChannelAndSampleRateConvert()
   173 	{
   174 	}
   175 
   176 	
   177 TInt CChannelAndSampleRateConvert::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   178 	{
   179 	// take rate conversion into account. Assumed channel mismatch handled by the child class.
   180 	TInt rawValue = aSrcBufferSize;
   181 	if (iFromRate < iToRate)
   182 		{
   183 		TInt result = SizeOfUpsampleBuffer(rawValue);
   184 		return result; // always rounded up to next size
   185 		}
   186 	else
   187 		{
   188 		if (aRoundUpToPower)
   189 			{
   190 			return NextPowerUp(rawValue); 
   191 			}
   192 		else
   193 			{
   194 			return rawValue;
   195 			}
   196 		}
   197 	}
   198 	
   199 void CChannelAndSampleRateConvert::SetRates(TInt aFromRate, TInt aToRate)
   200 	{
   201 	iFromRate=aFromRate;
   202 	iToRate=aToRate;
   203 
   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);
   208 
   209 	Reset();
   210 	}
   211 	
   212 void CChannelAndSampleRateConvert::Reset()
   213 	{
   214 	iIndex = 0;
   215 	}
   216 	
   217 TInt CChannelAndSampleRateConvert::SizeOfUpsampleBuffer(TInt aBufferLength)
   218 	{
   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
   224 	return rawValue;	
   225 	}
   226 
   227 //
   228 // Specific converter code
   229 //
   230 
   231 CStereoToStereoRateConverter::CStereoToStereoRateConverter()
   232 	{
   233 	}
   234 
   235 TInt CStereoToStereoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
   236 	{
   237 	const TInt32* srcPtr = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
   238 	TInt32* dstPtr = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
   239 	
   240 	const TInt32* srcLimit=srcPtr+LengthBytesTo32Bit(aSrcBuffer.Length()); // ptr+n does *4 for TInt32* ptr
   241 	TInt32* dstLimit=dstPtr+LengthBytesTo32Bit(aDstBuffer.MaxLength()); // ditto
   242 
   243 	// add left over from last buffer
   244 	TUint index = iIndex;
   245 	const TInt32* src = srcPtr + (index>>16);
   246 	TInt32* dst = dstPtr;
   247 
   248 	if (dst>=dstLimit)
   249 		{
   250 		__ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
   251 		return 0;
   252 		}
   253 
   254 	while (src<srcLimit && dst<dstLimit)
   255 		{
   256   		*dst++ = *src;
   257 		index += iFraction;
   258 		src = srcPtr + (index>>16); // truncate fix-point index
   259 		}
   260 
   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); 
   267 
   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);
   272 	}
   273 	
   274 CMonoToStereoRateConverter::CMonoToStereoRateConverter()
   275 	{
   276 	}
   277 
   278 TInt CMonoToStereoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
   279 	{
   280 	const TInt16* srcPtr = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
   281 	TInt32* dstPtr = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
   282 	
   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*
   285 
   286 	// add left over from last buffer
   287 	TUint index = iIndex;
   288 	const TInt16* src = srcPtr + (index>>16);
   289 	TInt32* dst = dstPtr;
   290 
   291 	if (dst>=dstLimit)
   292 		{
   293 		__ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
   294 		return 0;
   295 		}
   296 
   297 	while (src<srcLimit && dst<dstLimit-1)
   298 		{
   299 		TInt16 sample = *src;
   300 		TInt32 stereoSample = MonoToStereo(sample);
   301 		*dst++ = stereoSample;
   302 		index += iFraction;
   303 		src = srcPtr + (index>>16); // truncate fix-point index
   304 		}
   305 
   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); 
   312 
   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);
   317 	}	
   318 	
   319 
   320 TInt CMonoToStereoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   321 	{
   322 	return CChannelAndSampleRateConvert::MaxConvertBufferSize(aSrcBufferSize*2, aRoundUpToPower);
   323 	}
   324 	
   325 CMonoToMonoRateConverter::CMonoToMonoRateConverter()
   326 	{
   327 	}
   328 
   329 TInt CMonoToMonoRateConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
   330 	{
   331 	const TInt16* srcPtr = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
   332 	TInt16* dstPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
   333 	
   334 	const TInt16* srcLimit=srcPtr+LengthBytesTo16Bit(aSrcBuffer.Length()); // ptr+n does *2 for TInt16* ptr
   335 	TInt16* dstLimit=dstPtr+LengthBytesTo16Bit(aDstBuffer.MaxLength()); // ditto
   336 
   337 	// add left over from last buffer
   338 	TUint index = iIndex;
   339 	const TInt16* src = srcPtr + (index>>16);
   340 	TInt16* dst = dstPtr;
   341 
   342 	if (dst>=dstLimit)
   343 		{
   344 		__ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
   345 		return 0;
   346 		}
   347 
   348 	while (src<srcLimit && dst<dstLimit)
   349 		{
   350   		*dst++ = *src;
   351 		index += iFraction;
   352 		src = srcPtr + (index>>16); // truncate fix-point index
   353 		}
   354 
   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); 
   361 
   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);
   366 	}	
   367 	
   368 CStereoToMonoRateConverter::CStereoToMonoRateConverter()
   369 	{
   370 	}
   371 
   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)
   374 	{
   375 	const TInt32* srcPtr = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
   376 	TInt16* dstPtr = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
   377 	
   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*
   380 
   381 	// add left over from last buffer
   382 	TUint index = iIndex;
   383 	const TInt32* src = srcPtr + (index>>16);
   384 	TInt16* dst = dstPtr;
   385 
   386 	if (dst>=dstLimit)
   387 		{
   388 		__ASSERT_DEBUG(EFalse,Panic(EPanicNoDestinationBuffer));
   389 		return 0;
   390 		}
   391 
   392 	while (src<srcLimit && dst<dstLimit)
   393 		{
   394 		TInt32 sample = *src;
   395 		TInt16 monoSample = StereoToMono(sample);
   396   		*dst++ =  monoSample;
   397 		index += iFraction;
   398 		src = srcPtr + (index>>16); // truncate fix-point index
   399 		}
   400 
   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); 
   407 
   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);
   412 	}
   413 
   414 
   415 TInt CStereoToMonoRateConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   416 	{
   417 	TUint size = aSrcBufferSize/2;
   418 	size += aSrcBufferSize & 1; //avoid round down error
   419 	return CChannelAndSampleRateConvert::MaxConvertBufferSize(size, aRoundUpToPower);
   420 	}
   421 	
   422 CStereoToMonoConverter::CStereoToMonoConverter()
   423 	{
   424 	}
   425 
   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)
   428 	{
   429 	const TInt32* src = reinterpret_cast<const TInt32*>(aSrcBuffer.Ptr());
   430 	TInt16* dst = const_cast<TInt16*>(reinterpret_cast<const TInt16*>(aDstBuffer.Ptr()));
   431 
   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
   435 	
   436 	for (TUint i=0;i<count;++i)
   437 		{
   438 		TInt32 sample = *src++;
   439 		TInt16 monoSample = StereoToMono(sample);
   440   		*dst++ = monoSample;
   441 		}
   442 		
   443 	aDstBuffer.SetLength(Length16BitToBytes(count)); // *2 because is mono
   444 	return Length32BitToBytes(count); // *4 as is stereo
   445 	}	
   446 
   447 TInt CStereoToMonoConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   448 	{
   449 	TUint size = aSrcBufferSize/2;
   450 	size += aSrcBufferSize & 1; //avoid round down error
   451 	return CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(size, aRoundUpToPower);
   452 	}
   453 	
   454 CMonoToStereoConverter::CMonoToStereoConverter()
   455 	{
   456 	}
   457 
   458 TInt CMonoToStereoConverter::Convert(const TDesC8& aSrcBuffer, TDes8& aDstBuffer)
   459 	{
   460 	const TInt16* src = reinterpret_cast<const TInt16*>(aSrcBuffer.Ptr());
   461 	TInt32* dst = const_cast<TInt32*>(reinterpret_cast<const TInt32*>(aDstBuffer.Ptr()));
   462 
   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
   466 	
   467 	for (TUint i=0;i<count;i++)
   468 		{
   469 		TInt16 sample = *src++;
   470 		TInt32 stereoSample = MonoToStereo(sample);
   471   		*dst++ =  stereoSample;
   472 		}
   473 		
   474 	aDstBuffer.SetLength(Length32BitToBytes(count)); // *4 because is stereo
   475 	return Length16BitToBytes(count); // *2 as is mono
   476 	}	
   477 
   478 TInt CMonoToStereoConverter::MaxConvertBufferSize(TInt aSrcBufferSize, TBool aRoundUpToPower)
   479 	{
   480 	return CChannelAndSampleRateConverterCommon::MaxConvertBufferSize(aSrcBufferSize*2, aRoundUpToPower);
   481 	}
   482 
   483 
   484 
   485 
   486