omxilcomp/omxilaudioemulator/pcmrenderer/src/rateconvert.cpp
changeset 0 58be5850fb6c
equal deleted inserted replaced
-1:000000000000 0:58be5850fb6c
       
     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 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 fudge factor just in case
       
   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