/*---------------------------------------------------------------------------- * * 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); }