/*----------------------------------------------------------------------------
*
* File:
* eas_math.c
*
* Contents and purpose:
* Contains common math routines for the various audio engines.
*
*
* Copyright Sonic Network Inc. 2005
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*----------------------------------------------------------------------------
* Revision Control:
* $Revision: 586 $
* $Date: 2007-03-08 20:33:04 -0800 (Thu, 08 Mar 2007) $
*----------------------------------------------------------------------------
*/
#include "eas.h"
#include "eas_math.h"
/* anything less than this converts to a fraction too small to represent in 32-bits */
#define MIN_CENTS -18000
/*----------------------------------------------------------------------------
* EAS_Calculate2toX()
*----------------------------------------------------------------------------
* Purpose:
* Calculate 2^x
*
* Inputs:
* nCents - measured in cents
* psEASData - pointer to overall EAS data structure
*
* Outputs:
* nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
*
* Side Effects:
*
*----------------------------------------------------------------------------
*/
EAS_I32 EAS_Calculate2toX (EAS_I32 nCents)
{
EAS_I32 nDents;
EAS_I32 nExponentInt, nExponentFrac;
EAS_I32 nTemp1, nTemp2;
EAS_I32 nResult;
/* check for minimum value */
if (nCents < MIN_CENTS)
return 0;
/* for the time being, convert cents to dents */
nDents = FMUL_15x15(nCents, CENTS_TO_DENTS);
nExponentInt = GET_DENTS_INT_PART(nDents);
nExponentFrac = GET_DENTS_FRAC_PART(nDents);
/*
implement 2^(fracPart) as a power series
*/
nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3);
nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1);
nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2);
/*
implement 2^(intPart) as
a left shift for intPart >= 0 or
a left shift for intPart < 0
*/
if (nExponentInt >= 0)
{
/* left shift for positive exponents */
/*lint -e{703} <avoid multiply for performance>*/
nResult = nTemp1 << nExponentInt;
}
else
{
/* right shift for negative exponents */
nExponentInt = -nExponentInt;
nResult = nTemp1 >> nExponentInt;
}
return nResult;
}
/*----------------------------------------------------------------------------
* EAS_LogToLinear16()
*----------------------------------------------------------------------------
* Purpose:
* Transform log value to linear gain multiplier using piece-wise linear
* approximation
*
* Inputs:
* nGain - log scale value in 20.10 format. Even though gain is normally
* stored in 6.10 (16-bit) format we use 32-bit numbers here to eliminate
* the need for saturation checking when combining gain values.
*
* Outputs:
* Returns a 16-bit linear value approximately equal to 2^(nGain/1024)
*
* Side Effects:
*
*----------------------------------------------------------------------------
*/
EAS_U16 EAS_LogToLinear16 (EAS_I32 nGain)
{
EAS_INT nExp;
EAS_U16 nTemp;
/* bias to positive */
nGain += 32767;
/* check for infinite attenuation */
if (nGain < 0)
return 0;
/* extract the exponent */
nExp = 31 - (nGain >> 10);
/* check for maximum output */
if (nExp < 0)
return 0x7fff;
/* extract mantissa and restore implied 1 bit */
nTemp = (EAS_U16)((((nGain & 0x3ff) << 4) | 0x4000) >> nExp);
/* use shift to approximate power-of-2 operation */
return nTemp;
}
/*----------------------------------------------------------------------------
* EAS_VolumeToGain()
*----------------------------------------------------------------------------
* Purpose:
* Transform volume control in 1dB increments to gain multiplier
*
* Inputs:
* volume - 100 = 0dB, 99 = -1dB, 0 = -inf
*
* Outputs:
* Returns a 16-bit linear value
*----------------------------------------------------------------------------
*/
EAS_I16 EAS_VolumeToGain (EAS_INT volume)
{
/* check for limits */
if (volume <= 0)
return 0;
if (volume >= 100)
return 0x7fff;
/*lint -e{702} use shift instead of division */
return (EAS_I16) EAS_Calculate2toX((((volume - EAS_MAX_VOLUME) * 204099) >> 10) - 1);
}