blob: 2126e47cdd3cf927b48149661ad8e82f18e445b8 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* 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.
* -------------------------------------------------------------------
*/
/*
Filename: sbr_generate_high_freq.c
------------------------------------------------------------------------------
REVISION HISTORY
Who: Date: MM/DD/YYYY
Description:
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
HF generator with built-in QMF bank inverse filtering function
------------------------------------------------------------------------------
REQUIREMENTS
------------------------------------------------------------------------------
REFERENCES
SC 29 Software Copyright Licencing Disclaimer:
This software module was originally developed by
Coding Technologies
and edited by
-
in the course of development of the ISO/IEC 13818-7 and ISO/IEC 14496-3
standards for reference purposes and its performance may not have been
optimized. This software module is an implementation of one or more tools as
specified by the ISO/IEC 13818-7 and ISO/IEC 14496-3 standards.
ISO/IEC gives users free license to this software module or modifications
thereof for use in products claiming conformance to audiovisual and
image-coding related ITU Recommendations and/or ISO/IEC International
Standards. ISO/IEC gives users the same free license to this software module or
modifications thereof for research purposes and further ISO/IEC standardisation.
Those intending to use this software module in products are advised that its
use may infringe existing patents. ISO/IEC have no liability for use of this
software module or modifications thereof. Copyright is not released for
products that do not conform to audiovisual and image-coding related ITU
Recommendations and/or ISO/IEC International Standards.
The original developer retains full right to modify and use the code for its
own purpose, assign or donate the code to a third party and to inhibit third
parties from using the code for products that do not conform to audiovisual and
image-coding related ITU Recommendations and/or ISO/IEC International Standards.
This copyright notice must be included in all copies or derivative works.
Copyright (c) ISO/IEC 2002.
------------------------------------------------------------------------------
PSEUDO-CODE
------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#ifdef AAC_PLUS
#include "sbr_generate_high_freq.h"
#include "calc_auto_corr.h"
#include "sbr_inv_filt_levelemphasis.h"
#include "pv_div.h"
#include "fxp_mul32.h"
#include "aac_mem_funcs.h"
#include "sbr_constants.h"
/*----------------------------------------------------------------------------
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; DEFINES
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; Function Prototype declaration
----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C"
{
#endif
void high_freq_coeff_LC(Int32 sourceBufferReal[][32],
Int32 *alphar[2],
Int32 *degreeAlias,
Int32 *v_k_master,
Int32 *scratch_mem);
void high_freq_generation_LC(Int32 sourceBufferReal[][32],
Int32 *targetBufferReal,
Int32 *alphar[2],
Int32 *degreeAlias,
Int32 *invFiltBandTable,
Int32 targetStopBand,
Int32 patchDistance,
Int32 numBandsInPatch,
Int32 startSample,
Int32 slopeLength,
Int32 stopSample,
Int32 *BwVector,
Int32 sbrStartFreqOffset);
#ifdef HQ_SBR
void high_freq_coeff(Int32 sourceBufferReal[][32],
Int32 sourceBufferImag[][32],
Int32 *alphar[2],
Int32 *alphai[2],
Int32 *v_k_master);
void high_freq_generation(Int32 sourceBufferReal[][32],
Int32 sourceBufferImag[][32],
Int32 *targetBufferReal,
Int32 *targetBufferImag,
Int32 *alphar[2],
Int32 *alphai[2],
Int32 *invFiltBandTable,
Int32 targetStopBand,
Int32 patchDistance,
Int32 numBandsInPatch,
Int32 startSample,
Int32 slopeLength,
Int32 stopSample,
Int32 *BwVector,
Int32 sbrStartFreqOffset);
#endif
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
; LOCAL STORE/BUFFER/POINTER DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; EXTERNAL FUNCTION REFERENCES
; Declare functions defined elsewhere and referenced in this module
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES
; Declare variables used in this module but defined elsewhere
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void sbr_generate_high_freq(Int32 sourceBufferReal[][32],
Int32 sourceBufferImag[][32],
Int32 *targetBufferReal,
Int32 *targetBufferImag,
INVF_MODE *invFiltMode,
INVF_MODE *prevInvFiltMode,
Int32 *invFiltBandTable,
Int32 noInvFiltBands,
Int32 highBandStartSb,
Int32 *v_k_master,
Int32 numMaster,
Int32 fs,
Int32 *frameInfo,
Int32 *degreeAlias,
Int32 scratch_mem[][64],
Int32 BwVector[MAX_NUM_PATCHES],
Int32 BwVectorOld[MAX_NUM_PATCHES],
struct PATCH *Patch,
Int32 LC_flag,
Int32 *highBandStopSb)
{
Int32 i;
Int32 patch;
Int32 startSample;
Int32 stopSample;
Int32 goalSb;
Int32 targetStopBand;
Int32 sourceStartBand;
Int32 patchDistance;
Int32 numBandsInPatch;
Int32 sbrStartFreqOffset;
Int32 *alphar[2];
Int32 *alphai[2];
Int32 lsb = v_k_master[0]; /* Lowest subband related to the synthesis filterbank */
Int32 usb = v_k_master[numMaster]; /* Stop subband related to the synthesis filterbank */
Int32 xoverOffset = highBandStartSb - v_k_master[0]; /* Calculate distance in subbands between k0 and kx */
Int slopeLength = 0;
Int32 firstSlotOffs = frameInfo[1];
Int32 lastSlotOffs = frameInfo[frameInfo[0] + 1] - 16;
alphar[0] = scratch_mem[0];
alphar[1] = scratch_mem[1];
alphai[0] = scratch_mem[2];
alphai[1] = scratch_mem[3];
startSample = (firstSlotOffs << 1);
stopSample = (lastSlotOffs << 1) + 32;
sbr_inv_filt_levelemphasis(invFiltMode,
prevInvFiltMode,
noInvFiltBands,
BwVector,
BwVectorOld);
if (LC_flag == ON)
{
/* Set subbands to zero */
pv_memset((void *)&targetBufferReal[startSample*SBR_NUM_BANDS],
0,
(stopSample - startSample)*SBR_NUM_BANDS*sizeof(targetBufferReal[0]));
high_freq_coeff_LC(sourceBufferReal,
alphar,
degreeAlias,
v_k_master,
scratch_mem[4]);
}
#ifdef HQ_SBR
else
{
/* Set subbands to zero */
pv_memset((void *)&targetBufferReal[startSample*SBR_NUM_BANDS],
0,
(stopSample - startSample)*SBR_NUM_BANDS*sizeof(targetBufferReal[0]));
pv_memset((void *)&targetBufferImag[startSample*SBR_NUM_BANDS],
0,
(stopSample - startSample)*SBR_NUM_BANDS*sizeof(targetBufferImag[0]));
high_freq_coeff(sourceBufferReal,
sourceBufferImag,
alphar,
alphai,
v_k_master);
}
#endif /* #ifdef HQ_SBR */
/*
* Initialize the patching parameter
*/
switch (fs)
{
/*
* goalSb = (int)( 2.048e6f / fs + 0.5f );
*/
case 48000:
goalSb = 43; /* 16 kHz band */
break;
case 32000:
goalSb = 64; /* 16 kHz band */
break;
case 24000:
goalSb = 85; /* 16 kHz band */
break;
case 22050:
goalSb = 93; /* 16 kHz band */
break;
case 16000:
goalSb = 128; /* 16 kHz band */
break;
case 44100:
default:
goalSb = 46; /* 16 kHz band */
break;
}
i = 0;
if (goalSb > v_k_master[0])
{
if (goalSb < v_k_master[numMaster])
{
while (v_k_master[i] < goalSb)
{
i++;
}
}
else
{
i = numMaster;
}
}
goalSb = v_k_master[i];
/* First patch */
sourceStartBand = xoverOffset + 1;
targetStopBand = lsb + xoverOffset;
/* even (odd) numbered channel must be patched to even (odd) numbered channel */
patch = 0;
sbrStartFreqOffset = targetStopBand;
while (targetStopBand < usb)
{
Patch->targetStartBand[patch] = targetStopBand;
numBandsInPatch = goalSb - targetStopBand; /* get the desired range of the patch */
if (numBandsInPatch >= lsb - sourceStartBand)
{
/* desired number bands are not available -> patch whole source range */
patchDistance = targetStopBand - sourceStartBand; /* get the targetOffset */
patchDistance = patchDistance & ~1; /* rounding off odd numbers and make all even */
numBandsInPatch = lsb - (targetStopBand - patchDistance);
if (targetStopBand + numBandsInPatch > v_k_master[0])
{
i = numMaster;
if (targetStopBand + numBandsInPatch < v_k_master[numMaster])
{
while (v_k_master[i] > targetStopBand + numBandsInPatch)
{
i--;
}
}
}
else
{
i = 0;
}
numBandsInPatch = v_k_master[i] - targetStopBand;
}
/* desired number bands are available -> get the minimal even patching distance */
patchDistance = numBandsInPatch + targetStopBand - lsb; /* get minimal distance */
patchDistance = (patchDistance + 1) & ~1; /* rounding up odd numbers and make all even */
/* All patches but first */
sourceStartBand = 1;
/* Check if we are close to goalSb */
if (goalSb - (targetStopBand + numBandsInPatch) < 3)
{ /* MPEG doc */
goalSb = usb;
}
if ((numBandsInPatch < 3) && (patch > 0))
{
if (LC_flag == ON)
{
pv_memset((void *) &degreeAlias[targetStopBand], 0, numBandsInPatch*sizeof(*degreeAlias));
}
break;
}
if (numBandsInPatch <= 0)
{
continue;
}
/*
* High Frequency generation
*/
if (LC_flag == ON)
{
high_freq_generation_LC(sourceBufferReal,
(Int32 *)targetBufferReal,
alphar,
degreeAlias,
invFiltBandTable,
targetStopBand,
patchDistance,
numBandsInPatch,
startSample,
slopeLength,
stopSample,
BwVector,
sbrStartFreqOffset);
}
#ifdef HQ_SBR
else
{
high_freq_generation(sourceBufferReal,
sourceBufferImag,
(Int32 *)targetBufferReal,
(Int32 *)targetBufferImag,
alphar,
alphai,
invFiltBandTable,
targetStopBand,
patchDistance,
numBandsInPatch,
startSample,
slopeLength,
stopSample,
BwVector,
sbrStartFreqOffset);
}
#endif
targetStopBand += numBandsInPatch;
patch++;
} /* targetStopBand */
Patch->noOfPatches = patch;
pv_memmove(BwVectorOld, BwVector, noInvFiltBands*sizeof(BwVector[0]));
*highBandStopSb = goalSb;
}
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void high_freq_coeff_LC(Int32 sourceBufferReal[][32],
Int32 *alphar[2],
Int32 *degreeAlias,
Int32 *v_k_master,
Int32 *scratch_mem)
{
Int32 fac;
Int32 *k1;
struct ACORR_COEFS ac;
struct intg_div quotient;
Int32 temp1;
Int32 temp2;
Int32 temp3;
Int32 autoCorrLength;
Int32 loBand;
k1 = scratch_mem;
autoCorrLength = 38;
for (loBand = 1; loBand < v_k_master[0]; loBand++)
{
calc_auto_corr_LC(&ac,
sourceBufferReal,
loBand,
autoCorrLength);
if (ac.r11r && ac.det)
{
pv_div(ac.r01r, ac.r11r, &quotient);
fac = -(quotient.quotient >> 2); /* Q28 */
if (quotient.shift_factor > 0)
{
fac >>= quotient.shift_factor; /* Q28 */
}
else if (quotient.shift_factor < 0)
{
if (quotient.shift_factor > -4) /* |fac| < 8 */
{
fac <<= (-quotient.shift_factor); /* Q28 */
}
else
{
fac = 0x80000000; /* overshoot possible fac = -8 */
}
}
/*
* prevent for overflow of reflection coefficients
*/
if (quotient.shift_factor > 0)
{
k1[loBand] = - quotient.quotient >> quotient.shift_factor;
}
else if (quotient.shift_factor == 0)
{
if (quotient.quotient >= 0x40000000)
{
k1[loBand] = (Int32)0xC0000000; /* -1.0 in Q30 */
}
else if (quotient.quotient <= (Int32)0xC0000000)
{
k1[loBand] = 0x40000000; /* 1.0 in Q30 */
}
else
{
k1[loBand] = -quotient.quotient;
}
}
else
{
if (quotient.quotient > 0)
{
k1[loBand] = (Int32)0xC0000000; /* -1.0 in Q30 */
}
else
{
k1[loBand] = 0x40000000; /* 1.0 in Q30 */
}
}
/*
* alphar[1][loBand] = ( ac.r01r * ac.r12r - ac.r02r * ac.r11r ) / ac.det;
*/
temp1 = -fxp_mul32_Q30(ac.r02r, ac.r11r);
temp1 = fxp_mac32_Q30(ac.r01r, ac.r12r, temp1);
temp2 = ac.det;
temp3 = temp1 > 0 ? temp1 : -temp1;
temp2 = temp2 > 0 ? temp2 : -temp2;
/* prevent for shootovers */
if ((temp3 >> 2) >= temp2 || fac == (Int32)0x80000000)
{
alphar[0][loBand] = 0;
alphar[1][loBand] = 0;
}
else
{
pv_div(temp1, ac.det, &quotient);
/*
* alphar[1][loBand] is lesser than 4.0
*/
alphar[1][loBand] = quotient.quotient;
quotient.shift_factor += 2; /* Q28 */
if (quotient.shift_factor > 0)
{
alphar[1][loBand] >>= quotient.shift_factor; /* Q28 */
}
else if (quotient.shift_factor < 0) /* at this point can only be -1 */
{
alphar[1][loBand] <<= (-quotient.shift_factor); /* Q28 */
}
/*
* alphar[0][loBand] = - ( ac.r01r + alphar[1][loBand] * ac.r12r ) / ac.r11r;
*/
pv_div(ac.r12r, ac.r11r, &quotient);
temp3 = (quotient.quotient >> 2); /* Q28 */
if (quotient.shift_factor > 0)
{
temp3 >>= quotient.shift_factor; /* Q28 */
}
else if (quotient.shift_factor < 0)
{
temp3 <<= (-quotient.shift_factor); /* Q28 */
}
alphar[0][loBand] = fac - fxp_mul32_Q28(alphar[1][loBand], temp3) ; /* Q28 */
if ((alphar[0][loBand] >= 0x40000000) || (alphar[0][loBand] <= (Int32)0xC0000000))
{
alphar[0][loBand] = 0;
alphar[1][loBand] = 0;
}
}
}
else
{
alphar[0][loBand] = 0;
alphar[1][loBand] = 0;
k1[loBand] = 0;
}
}
k1[0] = 0;
degreeAlias[1] = 0;
for (loBand = 2; loBand < v_k_master[0]; loBand++)
{
degreeAlias[loBand] = 0;
if ((!(loBand & 1)) && (k1[loBand] < 0))
{
if (k1[loBand-1] < 0)
{ // 2-CH Aliasing Detection
degreeAlias[loBand] = 0x40000000;
if (k1[loBand-2] > 0)
{ // 3-CH Aliasing Detection
degreeAlias[loBand-1] = 0x40000000 - fxp_mul32_Q30(k1[loBand-1], k1[loBand-1]);
}
}
else if (k1[loBand-2] > 0)
{ // 3-CH Aliasing Detection
degreeAlias[loBand] = 0x40000000 - fxp_mul32_Q30(k1[loBand-1], k1[loBand-1]);
}
}
if ((loBand & 1) && (k1[loBand] > 0))
{
if (k1[loBand-1] > 0)
{ // 2-CH Aliasing Detection
degreeAlias[loBand] = 0x40000000;
if (k1[loBand-2] < 0)
{ // 3-CH Aliasing Detection
degreeAlias[loBand-1] = 0x40000000 - fxp_mul32_Q30(k1[loBand-1], k1[loBand-1]);
}
}
else if (k1[loBand-2] < 0)
{ // 3-CH Aliasing Detection
degreeAlias[loBand] = 0x40000000 - fxp_mul32_Q30(k1[loBand-1], k1[loBand-1]);
}
}
}
}
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void high_freq_generation_LC(Int32 sourceBufferReal[][32],
Int32 *targetBufferReal,
Int32 *alphar[2],
Int32 *degreeAlias,
Int32 *invFiltBandTable,
Int32 targetStopBand,
Int32 patchDistance,
Int32 numBandsInPatch,
Int32 startSample,
Int32 slopeLength,
Int32 stopSample,
Int32 *BwVector,
Int32 sbrStartFreqOffset)
{
Int32 temp1;
Int32 temp2;
Int32 temp3;
Int32 a0r;
Int32 a1r;
Int32 i;
Int32 bw;
Int32 hiBand;
Int32 bwIndex;
Int32 loBand;
Int32 j;
bwIndex = 0;
for (hiBand = targetStopBand; hiBand < targetStopBand + numBandsInPatch; hiBand++)
{
loBand = hiBand - patchDistance;
if (hiBand != targetStopBand)
{
degreeAlias[hiBand] = degreeAlias[loBand];
}
else
{
degreeAlias[hiBand] = 0;
}
while (hiBand >= invFiltBandTable[bwIndex])
{
bwIndex++;
}
bw = BwVector[bwIndex];
/*
* Inverse Filtering
*/
j = hiBand - sbrStartFreqOffset;
if (bw > 0 && (alphar[0][loBand] | alphar[1][loBand]))
{
/* Apply current bandwidth expansion factor */
a0r = fxp_mul32_Q29(bw, alphar[0][loBand]);
bw = fxp_mul32_Q31(bw, bw) << 2;
a1r = fxp_mul32_Q28(bw, alphar[1][loBand]);
i = startSample + slopeLength;
temp1 = sourceBufferReal[i ][loBand];
temp2 = sourceBufferReal[i - 1][loBand];
temp3 = sourceBufferReal[i - 2][loBand];
for (; i < stopSample + slopeLength - 1; i++)
{
targetBufferReal[i*SBR_NUM_BANDS + j] = temp1 + fxp_mul32_Q28(a0r, temp2) +
fxp_mul32_Q28(a1r, temp3);
temp3 = temp2;
temp2 = temp1;
temp1 = sourceBufferReal[i + 1][loBand];
}
targetBufferReal[i*SBR_NUM_BANDS + j] = temp1 + fxp_mul32_Q28(a0r, temp2) +
fxp_mul32_Q28(a1r, temp3);
}
else
{
for (i = startSample + slopeLength; i < stopSample + slopeLength; i++)
{
targetBufferReal[i*SBR_NUM_BANDS + j] = sourceBufferReal[i][loBand];
}
}
} /* hiBand */
}
#ifdef HQ_SBR
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void high_freq_coeff(Int32 sourceBufferReal[][32],
Int32 sourceBufferImag[][32],
Int32 *alphar[2],
Int32 *alphai[2],
Int32 *v_k_master)
{
Int32 overflow_flag;
Int32 temp1r;
Int32 temp1i;
Int32 temp0r;
Int32 temp0i;
Int32 loBand;
struct ACORR_COEFS ac;
struct intg_div quotient;
Int32 autoCorrLength;
autoCorrLength = 38;
for (loBand = 1; loBand < v_k_master[0]; loBand++)
{
calc_auto_corr(&ac,
sourceBufferReal,
sourceBufferImag,
loBand,
autoCorrLength);
overflow_flag = 0;
if (ac.det < 1)
{
/* --- */
temp1r = 0;
temp1i = 0;
alphar[1][loBand] = 0;
alphai[1][loBand] = 0;
}
else
{
temp1r = fxp_mul32_Q29(ac.r01r, ac.r12r);
temp1r = fxp_msu32_Q29(ac.r01i, ac.r12i, temp1r);
temp1r = fxp_msu32_Q29(ac.r02r, ac.r11r, temp1r);
temp1i = fxp_mul32_Q29(ac.r01r, ac.r12i);
temp1i = fxp_msu32_Q29(ac.r02i, ac.r11r, temp1i);
temp1i = fxp_mac32_Q29(ac.r01i, ac.r12r, temp1i);
pv_div(temp1r, ac.det, &quotient);
overflow_flag = (quotient.shift_factor < -2) ? 1 : 0;
temp1r = quotient.quotient >> (2 + quotient.shift_factor); /* Q28 */
pv_div(temp1i, ac.det, &quotient);
overflow_flag = (quotient.shift_factor < -2) ? 1 : 0;
temp1i = quotient.quotient >> (2 + quotient.shift_factor); /* Q28 */
alphar[1][loBand] = temp1r;
alphai[1][loBand] = temp1i;
}
if (ac.r11r == 0)
{
temp0r = 0;
temp0i = 0;
alphar[0][loBand] = 0;
alphai[0][loBand] = 0;
}
else
{
temp0r = - (ac.r01r + fxp_mul32_Q28(temp1r, ac.r12r) + fxp_mul32_Q28(temp1i, ac.r12i));
temp0i = - (ac.r01i + fxp_mul32_Q28(temp1i, ac.r12r) - fxp_mul32_Q28(temp1r, ac.r12i));
pv_div(temp0r, ac.r11r, &quotient);
overflow_flag = (quotient.shift_factor < -2) ? 1 : 0;
temp0r = quotient.quotient >> (2 + quotient.shift_factor); /* Q28 */
pv_div(temp0i, ac.r11r, &quotient);
overflow_flag = (quotient.shift_factor < -2) ? 1 : 0;
temp0i = quotient.quotient >> (2 + quotient.shift_factor); /* Q28 */
alphar[0][loBand] = temp0r;
alphai[0][loBand] = temp0i;
}
/* prevent for shootovers */
if (fxp_mul32_Q28((temp0r >> 2), (temp0r >> 2)) + fxp_mul32_Q28((temp0i >> 2), (temp0i >> 2)) >= 0x10000000 ||
fxp_mul32_Q28((temp1r >> 2), (temp1r >> 2)) + fxp_mul32_Q28((temp1i >> 2), (temp1i >> 2)) >= 0x10000000 ||
overflow_flag) /* 0x10000000 == 1 in Q28 */
{
alphar[0][loBand] = 0;
alphar[1][loBand] = 0;
alphai[0][loBand] = 0;
alphai[1][loBand] = 0;
}
}
}
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void high_freq_generation(Int32 sourceBufferReal[][32],
Int32 sourceBufferImag[][32],
Int32 *targetBufferReal,
Int32 *targetBufferImag,
Int32 *alphar[2],
Int32 *alphai[2],
Int32 *invFiltBandTable,
Int32 targetStopBand,
Int32 patchDistance,
Int32 numBandsInPatch,
Int32 startSample,
Int32 slopeLength,
Int32 stopSample,
Int32 *BwVector,
Int32 sbrStartFreqOffset)
{
Int32 temp1_r;
Int32 temp2_r;
Int32 temp3_r;
Int32 temp1_i;
Int32 temp2_i;
Int32 temp3_i;
Int32 a0i;
Int32 a1i;
Int32 a0r;
Int32 a1r;
Int32 i;
Int32 bw;
Int32 hiBand;
Int32 bwIndex;
Int32 loBand;
Int32 j;
int64_t tmp;
bwIndex = 0;
for (hiBand = targetStopBand; hiBand < targetStopBand + numBandsInPatch; hiBand++)
{
loBand = hiBand - patchDistance;
while (hiBand >= invFiltBandTable[bwIndex])
{
bwIndex++;
}
bw = BwVector[bwIndex];
/*
* Inverse Filtering
*/
j = hiBand - sbrStartFreqOffset;
if (bw >= 0 && (alphar[0][loBand] | alphar[1][loBand] |
alphai[0][loBand] | alphai[1][loBand]))
{
/* Apply current bandwidth expansion factor */
a0r = fxp_mul32_Q29(bw, alphar[0][loBand]);
a0i = fxp_mul32_Q29(bw, alphai[0][loBand]);
bw = fxp_mul32_Q30(bw, bw);
a1r = fxp_mul32_Q28(bw, alphar[1][loBand]);
a1i = fxp_mul32_Q28(bw, alphai[1][loBand]);
i = startSample + slopeLength;
j += i * SBR_NUM_BANDS;
temp1_r = sourceBufferReal[i ][loBand];
temp2_r = sourceBufferReal[i - 1][loBand];
temp3_r = sourceBufferReal[i - 2][loBand];
temp1_i = sourceBufferImag[i ][loBand];
temp2_i = sourceBufferImag[i - 1][loBand];
temp3_i = sourceBufferImag[i - 2][loBand];
while (i < stopSample + slopeLength)
{
tmp = fxp_mac64_Q31(((int64_t)temp1_r << 28), a0r, temp2_r);
tmp = fxp_mac64_Q31(tmp, -a0i, temp2_i);
tmp = fxp_mac64_Q31(tmp, a1r, temp3_r);
targetBufferReal[j] = (Int32)(fxp_mac64_Q31(tmp, -a1i, temp3_i) >> 28);
tmp = fxp_mac64_Q31(((int64_t)temp1_i << 28), a0i, temp2_r);
tmp = fxp_mac64_Q31(tmp, a0r, temp2_i);
tmp = fxp_mac64_Q31(tmp, a1i, temp3_r);
targetBufferImag[j] = (Int32)(fxp_mac64_Q31(tmp, a1r, temp3_i) >> 28);
i++;
j += SBR_NUM_BANDS;
temp3_r = temp2_r;
temp2_r = temp1_r;
temp1_r = sourceBufferReal[i ][loBand];
temp3_i = temp2_i;
temp2_i = temp1_i;
temp1_i = sourceBufferImag[i ][loBand];
}
}
else
{
i = startSample + slopeLength;
j += i * SBR_NUM_BANDS;
for (; i < stopSample + slopeLength; i++)
{
targetBufferReal[j] = sourceBufferReal[i][loBand];
targetBufferImag[j] = sourceBufferImag[i][loBand];
j += SBR_NUM_BANDS;
}
}
}
}
#endif
#endif