blob: 91d3982c3ff239ab2851f2337aee6ff7da227aa0 [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.
* -------------------------------------------------------------------
*/
/****************************************************************************************
Portions of this file are derived from the following 3GPP standard:
3GPP TS 26.073
ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
Available from http://www.3gpp.org
(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
Permission to distribute, modify and use this file under the standard license
terms listed above has been obtained from the copyright holder.
****************************************************************************************/
/*
------------------------------------------------------------------------------
Pathname: ./audio/gsm-amr/c/src/c_g_aver.c
Functions:
Cb_gain_average_reset
Cb_gain_average
Date: 03/28/2000
------------------------------------------------------------------------------
REVISION HISTORY
Description: Made some changes to the comments to match the comments from
other modules.
Description: Made changes based on comments from the review meeting.
Description: Synchronized file with UMTS version 3.2.0. Updated coding
template.
Description: Made the following changes per comments from Phase 2/3 review:
1. Defined one local variable per line.
Description: Removed the functions Cb_gain_average_init and
Cb_gain_average_exit. The Cb_gain_average related structure is no longer
dynamically allocated.
Description: Passing in pOverflow to comply with changes needed for EPOC
Updated the include files for the module.
Description: Changed round function name to pv_round to avoid conflict with
round function in C standard library.
Description: Replaced OSCL mem type functions and eliminated include
files that now are chosen by OSCL definitions
Description:
------------------------------------------------------------------------------
MODULE DESCRIPTION
This file contains functions that reset and perform
codebook gain calculations.
------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include <string.h>
#include "c_g_aver.h"
#include "typedef.h"
#include "mode.h"
#include "cnst.h"
#include "basic_op.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
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
; LOCAL VARIABLE DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: Cb_gain_average_reset
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
state = pointer to a structure of type Cb_gain_averageState
Outputs:
Structure pointed to by state is initialized to zeros
Returns:
Returns 0 if memory was successfully initialized,
otherwise returns -1.
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
Resets state memory
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
c_g_aver.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
Word16 Cb_gain_average_reset (Cb_gain_averageState *state)
{
if (state == (Cb_gain_averageState *) NULL){
fprintf(stderr, "Cb_gain_average_reset: invalid parameter\n");
return -1;
}
// Static vectors to zero
Set_zero (state->cbGainHistory, L_CBGAINHIST);
// Initialize hangover handling
state->hangVar = 0;
state->hangCount= 0;
return 0;
}
------------------------------------------------------------------------------
RESOURCES USED [optional]
When the code is written for a specific target processor the
the resources used should be documented below.
HEAP MEMORY USED: x bytes
STACK MEMORY USED: x bytes
CLOCK CYCLES: (cycle count equation for this function) + (variable
used to represent cycle count for each subroutine
called)
where: (cycle count variable) = cycle count for [subroutine
name]
------------------------------------------------------------------------------
CAUTION [optional]
[State any special notes, constraints or cautions for users of this function]
------------------------------------------------------------------------------
*/
Word16 Cb_gain_average_reset(Cb_gain_averageState *state)
{
if (state == (Cb_gain_averageState *) NULL)
{
/* fprint(stderr, "Cb_gain_average_reset: invalid parameter\n"); */
return(-1);
}
/* Static vectors to zero */
memset(state->cbGainHistory, 0, L_CBGAINHIST*sizeof(Word16));
/* Initialize hangover handling */
state->hangVar = 0;
state->hangCount = 0;
return(0);
}
/****************************************************************************/
/*
------------------------------------------------------------------------------
FUNCTION NAME: Cb_gain_average
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
st = pointer to structure of type Cb_gain_averageState
mode = AMR mode (enum Mode)
gain_code = CB gain (Word16)
lsp = the LSP for the current frame (Word16)
lspAver = the average of LSP for 8 frames (Word16)
bfi = bad frame indication flag (Word16)
prev_bf = previous bad frame indication flag (Word16)
pdfi = potential degraded bad frame ind flag (Word16)
prev_pdf = prev pot. degraded bad frame ind flag (Word16)
inBackgroundNoise = background noise decision (Word16)
voicedHangover = # of frames after last voiced frame (Word16)
pOverflow = address of overflow (Flag)
Returns:
cbGainMix = codebook gain (Word16)
Outputs:
None.
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
The mix cb gains for MR475, MR515, MR59, MR67, MR102; gain_code other modes
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
c_g_aver.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
Word16 Cb_gain_average (
Cb_gain_averageState *st, // i/o : State variables for CB gain avergeing
enum Mode mode, // i : AMR mode
Word16 gain_code, // i : CB gain Q1
Word16 lsp[], // i : The LSP for the current frame Q15
Word16 lspAver[], // i : The average of LSP for 8 frames Q15
Word16 bfi, // i : bad frame indication flag
Word16 prev_bf, // i : previous bad frame indication flag
Word16 pdfi, // i : potential degraded bad frame ind flag
Word16 prev_pdf, // i : prev pot. degraded bad frame ind flag
Word16 inBackgroundNoise, // i : background noise decision
Word16 voicedHangover // i : # of frames after last voiced frame
)
{
//---------------------------------------------------------*
* Compute mixed cb gain, used to make cb gain more *
* smooth in background noise for modes 5.15, 5.9 and 6.7 *
* states that needs to be updated by all *
*---------------------------------------------------------
Word16 i;
Word16 cbGainMix, diff, tmp_diff, bgMix, cbGainMean;
Word32 L_sum;
Word16 tmp[M], tmp1, tmp2, shift1, shift2, shift;
// set correct cbGainMix for MR74, MR795, MR122
cbGainMix = gain_code;
*-------------------------------------------------------*
* Store list of CB gain needed in the CB gain *
* averaging *
*-------------------------------------------------------*
for (i = 0; i < (L_CBGAINHIST-1); i++)
{
st->cbGainHistory[i] = st->cbGainHistory[i+1];
}
st->cbGainHistory[L_CBGAINHIST-1] = gain_code;
// compute lsp difference
for (i = 0; i < M; i++) {
tmp1 = abs_s(sub(lspAver[i], lsp[i])); // Q15
shift1 = sub(norm_s(tmp1), 1); // Qn
tmp1 = shl(tmp1, shift1); // Q15+Qn
shift2 = norm_s(lspAver[i]); // Qm
tmp2 = shl(lspAver[i], shift2); // Q15+Qm
tmp[i] = div_s(tmp1, tmp2); // Q15+(Q15+Qn)-(Q15+Qm)
shift = sub(add(2, shift1), shift2);
if (shift >= 0)
{
tmp[i] = shr(tmp[i], shift); // Q15+Qn-Qm-Qx=Q13
}
else
{
tmp[i] = shl(tmp[i], negate(shift)); // Q15+Qn-Qm-Qx=Q13
}
}
diff = tmp[0];
for (i = 1; i < M; i++) {
diff = add(diff, tmp[i]); // Q13
}
// Compute hangover
if (sub(diff, 5325) > 0) // 0.65 in Q11
{
st->hangVar = add(st->hangVar, 1);
}
else
{
st->hangVar = 0;
}
if (sub(st->hangVar, 10) > 0)
{
st->hangCount = 0; // Speech period, reset hangover variable
}
// Compute mix constant (bgMix)
bgMix = 8192; // 1 in Q13
if ((sub(mode, MR67) <= 0) || (sub(mode, MR102) == 0))
// MR475, MR515, MR59, MR67, MR102
{
// if errors and presumed noise make smoothing probability stronger
if (((((pdfi != 0) && (prev_pdf != 0)) || (bfi != 0) || (prev_bf != 0)) &&
(sub(voicedHangover, 1) > 0) && (inBackgroundNoise != 0) &&
((sub(mode, MR475) == 0) ||
(sub(mode, MR515) == 0) ||
(sub(mode, MR59) == 0)) ))
{
// bgMix = min(0.25, max(0.0, diff-0.55)) / 0.25;
tmp_diff = sub(diff, 4506); // 0.55 in Q13
// max(0.0, diff-0.55)
if (tmp_diff > 0)
{
tmp1 = tmp_diff;
}
else
{
tmp1 = 0;
}
// min(0.25, tmp1)
if (sub(2048, tmp1) < 0)
{
bgMix = 8192;
}
else
{
bgMix = shl(tmp1, 2);
}
}
else
{
// bgMix = min(0.25, max(0.0, diff-0.40)) / 0.25;
tmp_diff = sub(diff, 3277); // 0.4 in Q13
// max(0.0, diff-0.40)
if (tmp_diff > 0)
{
tmp1 = tmp_diff;
}
else
{
tmp1 = 0;
}
// min(0.25, tmp1)
if (sub(2048, tmp1) < 0)
{
bgMix = 8192;
}
else
{
bgMix = shl(tmp1, 2);
}
}
if ((sub(st->hangCount, 40) < 0) || (sub(diff, 5325) > 0)) // 0.65 in Q13
{
bgMix = 8192; // disable mix if too short time since
}
// Smoothen the cb gain trajectory
// smoothing depends on mix constant bgMix
L_sum = L_mult(6554, st->cbGainHistory[2]); // 0.2 in Q15; L_sum in Q17
for (i = 3; i < L_CBGAINHIST; i++)
{
L_sum = L_mac(L_sum, 6554, st->cbGainHistory[i]);
}
cbGainMean = pv_round(L_sum); // Q1
// more smoothing in error and bg noise (NB no DFI used here)
if (((bfi != 0) || (prev_bf != 0)) && (inBackgroundNoise != 0) &&
((sub(mode, MR475) == 0) ||
(sub(mode, MR515) == 0) ||
(sub(mode, MR59) == 0)) )
{
L_sum = L_mult(4681, st->cbGainHistory[0]); // 0.143 in Q15; L_sum in Q17
for (i = 1; i < L_CBGAINHIST; i++)
{
L_sum = L_mac(L_sum, 4681, st->cbGainHistory[i]);
}
cbGainMean = pv_round(L_sum); // Q1
}
// cbGainMix = bgMix*cbGainMix + (1-bgMix)*cbGainMean;
L_sum = L_mult(bgMix, cbGainMix); // L_sum in Q15
L_sum = L_mac(L_sum, 8192, cbGainMean);
L_sum = L_msu(L_sum, bgMix, cbGainMean);
cbGainMix = pv_round(L_shl(L_sum, 2)); // Q1
}
st->hangCount = add(st->hangCount, 1);
return cbGainMix;
}
------------------------------------------------------------------------------
RESOURCES USED [optional]
When the code is written for a specific target processor the
the resources used should be documented below.
HEAP MEMORY USED: x bytes
STACK MEMORY USED: x bytes
CLOCK CYCLES: (cycle count equation for this function) + (variable
used to represent cycle count for each subroutine
called)
where: (cycle count variable) = cycle count for [subroutine
name]
------------------------------------------------------------------------------
CAUTION [optional]
[State any special notes, constraints or cautions for users of this function]
------------------------------------------------------------------------------
*/
Word16 Cb_gain_average(
Cb_gain_averageState *st, /* i/o : State variables for CB gain averaging */
enum Mode mode, /* i : AMR mode */
Word16 gain_code, /* i : CB gain Q1 */
Word16 lsp[], /* i : The LSP for the current frame Q15 */
Word16 lspAver[], /* i : The average of LSP for 8 frames Q15 */
Word16 bfi, /* i : bad frame indication flag */
Word16 prev_bf, /* i : previous bad frame indication flag */
Word16 pdfi, /* i : potential degraded bad frame ind flag */
Word16 prev_pdf, /* i : prev pot. degraded bad frame ind flag */
Word16 inBackgroundNoise, /* i : background noise decision */
Word16 voicedHangover, /* i : # of frames after last voiced frame */
Flag *pOverflow
)
{
Word16 i;
Word16 cbGainMix;
Word16 diff;
Word16 tmp_diff;
Word16 bgMix;
Word16 cbGainMean;
Word32 L_sum;
Word16 tmp[M];
Word16 tmp1;
Word16 tmp2;
Word16 shift1;
Word16 shift2;
Word16 shift;
/*---------------------------------------------------------*
* Compute mixed cb gain, used to make cb gain more *
* smooth in background noise for modes 5.15, 5.9 and 6.7 *
* states that needs to be updated by all *
*---------------------------------------------------------*/
/* set correct cbGainMix for MR74, MR795, MR122 */
cbGainMix = gain_code;
/*-------------------------------------------------------*
* Store list of CB gain needed in the CB gain *
* averaging *
*-------------------------------------------------------*/
for (i = 0; i < (L_CBGAINHIST - 1); i++)
{
st->cbGainHistory[i] = st->cbGainHistory[i+1];
}
st->cbGainHistory[L_CBGAINHIST-1] = gain_code;
diff = 0;
/* compute lsp difference */
for (i = 0; i < M; i++)
{
tmp1 = abs_s(sub(*(lspAver + i), *(lsp + i), pOverflow));
/* Q15 */
shift1 = sub(norm_s(tmp1), 1, pOverflow); /* Qn */
tmp1 = shl(tmp1, shift1, pOverflow); /* Q15+Qn */
shift2 = norm_s(*(lspAver + i)); /* Qm */
tmp2 = shl(*(lspAver + i), shift2, pOverflow); /* Q15+Qm */
tmp[i] = div_s(tmp1, tmp2); /* Q15+(Q15+Qn)-(Q15+Qm) */
shift = 2 + shift1 - shift2;
if (shift >= 0)
{
*(tmp + i) = shr(*(tmp + i), shift, pOverflow);
/* Q15+Qn-Qm-Qx=Q13 */
}
else
{
*(tmp + i) = shl(*(tmp + i), negate(shift), pOverflow);
/* Q15+Qn-Qm-Qx=Q13 */
}
diff = add(diff, *(tmp + i), pOverflow); /* Q13 */
}
/* Compute hangover */
if (diff > 5325) /* 0.65 in Q11 */
{
st->hangVar += 1;
}
else
{
st->hangVar = 0;
}
if (st->hangVar > 10)
{
/* Speech period, reset hangover variable */
st->hangCount = 0;
}
/* Compute mix constant (bgMix) */
bgMix = 8192; /* 1 in Q13 */
if ((mode <= MR67) || (mode == MR102))
/* MR475, MR515, MR59, MR67, MR102 */
{
/* if errors and presumed noise make smoothing probability stronger */
if (((((pdfi != 0) && (prev_pdf != 0)) || (bfi != 0) ||
(prev_bf != 0))
&& (voicedHangover > 1)
&& (inBackgroundNoise != 0)
&& ((mode == MR475) || (mode == MR515) ||
(mode == MR59))))
{
/* bgMix = min(0.25, max(0.0, diff-0.55)) / 0.25; */
tmp_diff = sub(diff, 4506, pOverflow); /* 0.55 in Q13 */
}
else
{
/* bgMix = min(0.25, max(0.0, diff-0.40)) / 0.25; */
tmp_diff = sub(diff, 3277, pOverflow); /* 0.4 in Q13 */
}
/* max(0.0, diff-0.55) or */
/* max(0.0, diff-0.40) */
if (tmp_diff > 0)
{
tmp1 = tmp_diff;
}
else
{
tmp1 = 0;
}
/* min(0.25, tmp1) */
if (2048 < tmp1)
{
bgMix = 8192;
}
else
{
bgMix = shl(tmp1, 2, pOverflow);
}
if ((st->hangCount < 40) || (diff > 5325)) /* 0.65 in Q13 */
{
/* disable mix if too short time since */
bgMix = 8192;
}
/* Smoothen the cb gain trajectory */
/* smoothing depends on mix constant bgMix */
L_sum = L_mult(6554, st->cbGainHistory[2], pOverflow);
/* 0.2 in Q15; L_sum in Q17 */
for (i = 3; i < L_CBGAINHIST; i++)
{
L_sum = L_mac(L_sum, 6554, st->cbGainHistory[i], pOverflow);
}
cbGainMean = pv_round(L_sum, pOverflow); /* Q1 */
/* more smoothing in error and bg noise (NB no DFI used here) */
if (((bfi != 0) || (prev_bf != 0)) && (inBackgroundNoise != 0)
&& ((mode == MR475) || (mode == MR515)
|| (mode == MR59)))
{
/* 0.143 in Q15; L_sum in Q17 */
L_sum = L_mult(4681, st->cbGainHistory[0], pOverflow);
for (i = 1; i < L_CBGAINHIST; i++)
{
L_sum =
L_mac(L_sum, 4681, st->cbGainHistory[i], pOverflow);
}
cbGainMean = pv_round(L_sum, pOverflow); /* Q1 */
}
/* cbGainMix = bgMix*cbGainMix + (1-bgMix)*cbGainMean; */
/* L_sum in Q15 */
L_sum = L_mult(bgMix, cbGainMix, pOverflow);
L_sum = L_mac(L_sum, 8192, cbGainMean, pOverflow);
L_sum = L_msu(L_sum, bgMix, cbGainMean, pOverflow);
cbGainMix = pv_round(L_shl(L_sum, 2, pOverflow), pOverflow); /* Q1 */
}
st->hangCount += 1;
return (cbGainMix);
}