/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** The "appropriate copyright message" mentioned in section 2c of the GPLv2
** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com"
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Nero AG through Mpeg4AAClicense@nero.com.
**
** $Id: sbr_hfadj.c,v 1.23 2008/09/19 22:50:20 menno Exp $
**/
/* High Frequency adjustment */
#include "common.h"
#include "structs.h"
#ifdef SBR_DEC
#include "sbr_syntax.h"
#include "sbr_hfadj.h"
#include "sbr_noise.h"
/* static function declarations */
static uint8_t estimate_current_envelope(sbr_info *sbr, sbr_hfadj_info *adj,
qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch);
static void calculate_gain(sbr_info *sbr, sbr_hfadj_info *adj, uint8_t ch);
#ifdef SBR_LOW_POWER
static void calc_gain_groups(sbr_info *sbr, sbr_hfadj_info *adj, real_t *deg, uint8_t ch);
static void aliasing_reduction(sbr_info *sbr, sbr_hfadj_info *adj, real_t *deg, uint8_t ch);
#endif
static void hf_assembly(sbr_info *sbr, sbr_hfadj_info *adj, qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch);
uint8_t hf_adjustment(sbr_info *sbr, qmf_t Xsbr[MAX_NTSRHFG][64]
#ifdef SBR_LOW_POWER
,real_t *deg /* aliasing degree */
#endif
,uint8_t ch)
{
ALIGN sbr_hfadj_info adj = {{{0}}};
uint8_t ret = 0;
if (sbr->bs_frame_class[ch] == FIXFIX)
{
sbr->l_A[ch] = -1;
} else if (sbr->bs_frame_class[ch] == VARFIX) {
if (sbr->bs_pointer[ch] > 1)
sbr->l_A[ch] = sbr->bs_pointer[ch] - 1;
else
sbr->l_A[ch] = -1;
} else {
if (sbr->bs_pointer[ch] == 0)
sbr->l_A[ch] = -1;
else
sbr->l_A[ch] = sbr->L_E[ch] + 1 - sbr->bs_pointer[ch];
}
ret = estimate_current_envelope(sbr, &adj, Xsbr, ch);
if (ret > 0)
return 1;
calculate_gain(sbr, &adj, ch);
#ifdef SBR_LOW_POWER
calc_gain_groups(sbr, &adj, deg, ch);
aliasing_reduction(sbr, &adj, deg, ch);
#endif
hf_assembly(sbr, &adj, Xsbr, ch);
return 0;
}
static uint8_t get_S_mapped(sbr_info *sbr, uint8_t ch, uint8_t l, uint8_t current_band)
{
if (sbr->f[ch][l] == HI_RES)
{
/* in case of using f_table_high we just have 1 to 1 mapping
* from bs_add_harmonic[l][k]
*/
if ((l >= sbr->l_A[ch]) ||
(sbr->bs_add_harmonic_prev[ch][current_band] && sbr->bs_add_harmonic_flag_prev[ch]))
{
return sbr->bs_add_harmonic[ch][current_band];
}
} else {
uint8_t b, lb, ub;
/* in case of f_table_low we check if any of the HI_RES bands
* within this LO_RES band has bs_add_harmonic[l][k] turned on
* (note that borders in the LO_RES table are also present in
* the HI_RES table)
*/
/* find first HI_RES band in current LO_RES band */
lb = 2*current_band - ((sbr->N_high & 1) ? 1 : 0);
/* find first HI_RES band in next LO_RES band */
ub = 2*(current_band+1) - ((sbr->N_high & 1) ? 1 : 0);
/* check all HI_RES bands in current LO_RES band for sinusoid */
for (b = lb; b < ub; b++)
{
if ((l >= sbr->l_A[ch]) ||
(sbr->bs_add_harmonic_prev[ch][b] && sbr->bs_add_harmonic_flag_prev[ch]))
{
if (sbr->bs_add_harmonic[ch][b] == 1)
return 1;
}
}
}
return 0;
}
static uint8_t estimate_current_envelope(sbr_info *sbr, sbr_hfadj_info *adj,
qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch)
{
uint8_t m, l, j, k, k_l, k_h, p;
real_t nrg, div;
if (sbr->bs_interpol_freq == 1)
{
for (l = 0; l < sbr->L_E[ch]; l++)
{
uint8_t i, l_i, u_i;
l_i = sbr->t_E[ch][l];
u_i = sbr->t_E[ch][l+1];
div = (real_t)(u_i - l_i);
if (div == 0)
div = 1;
for (m = 0; m < sbr->M; m++)
{
nrg = 0;
for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++)
{
#ifdef FIXED_POINT
#ifdef SBR_LOW_POWER
nrg += ((QMF_RE(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_RE(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS);
#else
nrg += ((QMF_RE(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_RE(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS) +
((QMF_IM(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_IM(Xsbr[i][m + sbr->kx])+(1<<(REAL_BITS-1)))>>REAL_BITS);
#endif
#else
nrg += MUL_R(QMF_RE(Xsbr[i][m + sbr->kx]), QMF_RE(Xsbr[i][m + sbr->kx]))
#ifndef SBR_LOW_POWER
+ MUL_R(QMF_IM(Xsbr[i][m + sbr->kx]), QMF_IM(Xsbr[i][m + sbr->kx]))
#endif
;
#endif
}
sbr->E_curr[ch][m][l] = nrg / div;
#ifdef SBR_LOW_POWER
#ifdef FIXED_POINT
sbr->E_curr[ch][m][l] <<= 1;
#else
sbr->E_curr[ch][m][l] *= 2;
#endif
#endif
}
}
} else {
for (l = 0; l < sbr->L_E[ch]; l++)
{
for (p = 0; p < sbr->n[sbr->f[ch][l]]; p++)
{
k_l = sbr->f_table_res[sbr->f[ch][l]][p];
k_h = sbr->f_table_res[sbr->f[ch][l]][p+1];
for (k = k_l; k < k_h; k++)
{
uint8_t i, l_i, u_i;
nrg = 0;
l_i = sbr->t_E[ch][l];
u_i = sbr->t_E[ch][l+1];
div = (real_t)((u_i - l_i)*(k_h - k_l));
if (div == 0)
div = 1;
for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++)
{
for (j = k_l; j < k_h; j++)
{
#ifdef FIXED_POINT
#ifdef SBR_LOW_POWER
nrg += ((QMF_RE(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_RE(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS);
#else
nrg += ((QMF_RE(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_RE(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS) +
((QMF_IM(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS)*((QMF_IM(Xsbr[i][j])+(1<<(REAL_BITS-1)))>>REAL_BITS);
#endif
#else
nrg += MUL_R(QMF_RE(Xsbr[i][j]), QMF_RE(Xsbr[i][j]))
#ifndef SBR_LOW_POWER
+ MUL_R(QMF_IM(Xsbr[i][j]), QMF_IM(Xsbr[i][j]))
#endif
;
#endif
}
}
sbr->E_curr[ch][k - sbr->kx][l] = nrg / div;
#ifdef SBR_LOW_POWER
#ifdef FIXED_POINT