blob: 4c66d54a7b010b22da588591a1f16cfaf99bf04e [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/agc.c
Funtions: energy_old
energy_new
agc_init
agc_reset
agc_exit
agc
agc2
------------------------------------------------------------------------------
MODULE DESCRIPTION
This set of modules scale the excitation level and output of the speech
signals.
------------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include "agc.h"
#include "cnst.h"
#include "inv_sqrt.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: energy_old
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
in = input signal (Word16)
l_trm = input signal length (Word16)
pOverflow = address of overflow (Flag)
Outputs:
pOverflow -> 1 if the energy computation saturates
Returns:
s = return energy of signal (Word32)
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
Returns the energy of the signal.
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
static Word32 energy_old( // o : return energy of signal
Word16 in[], // i : input signal (length l_trm)
Word16 l_trm // i : signal length
)
{
Word32 s;
Word16 i, temp;
temp = shr (in[0], 2);
s = L_mult (temp, temp);
for (i = 1; i < l_trm; i++)
{
temp = shr (in[i], 2);
s = L_mac (s, temp, temp);
}
return s;
}
------------------------------------------------------------------------------
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]
------------------------------------------------------------------------------
*/
static Word32 energy_old( /* o : return energy of signal */
Word16 in[], /* i : input signal (length l_trm) */
Word16 l_trm, /* i : signal length */
Flag *pOverflow /* overflow: flag to indicate overflow */
)
{
Word32 s = 0;
Word16 i;
Word16 temp;
for (i = 0; i < l_trm; i++)
{
temp = in[i] >> 2;
s = L_mac(s, temp, temp, pOverflow);
}
return(s);
}
/*----------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: energy_old__Wrapper
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
in = input signal (Word16)
l_trm = input signal length (Word16)
pOverflow = address of overflow (Flag)
Outputs:
pOverflow -> 1 if the energy computation saturates
Returns:
s = return energy of signal (Word32)
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
This function provides external access to the static function energy_old.
------------------------------------------------------------------------------
REQUIREMENTS
None
------------------------------------------------------------------------------
REFERENCES
None
------------------------------------------------------------------------------
PSEUDO-CODE
CALL energy_old ( in = in
l_trm = l_trm
pOverflow = pOverflow )
MODIFYING(nothing)
RETURNING(energy_old_value = s)
------------------------------------------------------------------------------
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]
------------------------------------------------------------------------------
*/
Word32 energy_old_Wrapper(Word16 in[], Word16 l_trm, Flag *pOverflow)
{
Word32 energy_old_value;
/*----------------------------------------------------------------------------
CALL energy_old ( in = in
l_trm = l_trm
pOverflow = pOverflow )
MODIFYING(nothing)
RETURNING(energy_old_value = s)
----------------------------------------------------------------------------*/
energy_old_value = energy_old(in, l_trm, pOverflow);
return(energy_old_value);
}
/*--------------------------------------------------------------------------*/
/*
-----------------------------------------------------------------------------
FUNCTION NAME: energy_new
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
in = input signal
l_trm = input signal length
pOverflow = address of overflow (Flag)
Outputs:
pOverflow -> 1 if the energy computation saturates
Returns:
s = return energy of signal
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
Returns the energy of the signal.
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
static Word32 energy_new( // o : return energy of signal
Word16 in[], // i : input signal (length l_trm)
Word16 l_trm ) // i : signal length
{
Word32 s;
Word16 i;
Flag ov_save;
ov_save = Overflow; //save overflow flag in case energy_old
// must be called
s = L_mult(in[0], in[0]);
for (i = 1; i < l_trm; i++)
{
s = L_mac(s, in[i], in[i]);
}
// check for overflow
if (L_sub (s, MAX_32) == 0L)
{
Overflow = ov_save; // restore overflow flag
s = energy_old (in, l_trm); // function result
}
else
{
s = L_shr(s, 4);
}
return(s);
}
------------------------------------------------------------------------------
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]
------------------------------------------------------------------------------
*/
static Word32 energy_new( /* o : return energy of signal */
Word16 in[], /* i : input signal (length l_trm) */
Word16 l_trm, /* i : signal length */
Flag *pOverflow /* i : overflow flag */
)
{
Word32 s = 0;
Word16 i;
Flag ov_save;
ov_save = *(pOverflow); /* save overflow flag in case energy_old */
/* must be called */
for (i = 0; i < l_trm; i++)
{
s = L_mac(s, in[i], in[i], pOverflow);
}
/* check for overflow */
if (s != MAX_32)
{
/* s is a sum of squares, so it won't be negative */
s = s >> 4;
}
else
{
*(pOverflow) = ov_save; /* restore overflow flag */
s = energy_old(in, l_trm, pOverflow); /* function result */
}
return (s);
}
/*--------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: energy_new__Wrapper
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
in = input signal (Word16)
l_trm = input signal length (Word16)
overflow = address of overflow (Flag)
Outputs:
pOverflow -> 1 if the energy computation saturates
Returns:
s = return energy of signal (Word32)
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
This function provides external access to the static function energy_new.
------------------------------------------------------------------------------
REQUIREMENTS
None
------------------------------------------------------------------------------
REFERENCES
None
------------------------------------------------------------------------------
PSEUDO-CODE
CALL energy_new ( in = in
l_trm = l_trm
pOverflow = pOverflow )
MODIFYING(nothing)
RETURNING(energy_new_value = s)
------------------------------------------------------------------------------
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]
------------------------------------------------------------------------------
*/
Word32 energy_new_Wrapper(Word16 in[], Word16 l_trm, Flag *pOverflow)
{
Word32 energy_new_value;
/*----------------------------------------------------------------------------
CALL energy_new ( in = in
l_trm = l_trm
pOverflow = pOverflow )
MODIFYING(nothing)
RETURNING(energy_new_value = s)
----------------------------------------------------------------------------*/
energy_new_value = energy_new(in, l_trm, pOverflow);
return(energy_new_value);
}
/*--------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: agc_reset
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
state = pointer to a structure of type agcState
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
Reset of agc (i.e. set state memory to 1.0).
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
int agc_reset (agcState *state)
{
if (state == (agcState *) NULL)
{
fprintf(stderr, "agc_reset: invalid parameter\n");
return -1;
}
state->past_gain = 4096; // initial value of past_gain = 1.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 agc_reset(agcState *state)
{
if (state == (agcState *) NULL)
{
/* fprintf(stderr, "agc_reset: invalid parameter\n"); */
return(-1);
}
state->past_gain = 4096; /* initial value of past_gain = 1.0 */
return(0);
}
/*--------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: agc
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
st = pointer to agc state
sig_in = pointer to a buffer containing the postfilter input signal
sig_out = pointer to a buffer containing the postfilter output signal
agc_fac = AGC factor
l_trm = subframe size
pOverflow = pointer to the overflow flag
Outputs:
st->past_gain = gain
buffer pointed to by sig_out contains the new postfilter output signal
pOverflow -> 1 if the agc computation saturates
Returns:
return = 0
Global Variables Used:
none.
Local Variables Needed:
none.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
Scales the postfilter output on a subframe basis using:
sig_out[n] = sig_out[n] * gain[n]
gain[n] = agc_fac * gain[n-1] + (1 - agc_fac) g_in/g_out
where: gain[n] = gain at the nth sample given by
g_in/g_out = square root of the ratio of energy at
the input and output of the postfilter.
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
int agc (
agcState *st, // i/o : agc state
Word16 *sig_in, // i : postfilter input signal (l_trm)
Word16 *sig_out, // i/o : postfilter output signal (l_trm)
Word16 agc_fac, // i : AGC factor
Word16 l_trm // i : subframe size
)
{
Word16 i, exp;
Word16 gain_in, gain_out, g0, gain;
Word32 s;
// calculate gain_out with exponent
s = energy_new(sig_out, l_trm); // function result
if (s == 0)
{
st->past_gain = 0;
return 0;
}
exp = sub (norm_l (s), 1);
gain_out = pv_round (L_shl (s, exp));
// calculate gain_in with exponent
s = energy_new(sig_in, l_trm); // function result
if (s == 0)
{
g0 = 0;
}
else
{
i = norm_l (s);
gain_in = pv_round (L_shl (s, i));
exp = sub (exp, i);
*---------------------------------------------------*
* g0 = (1-agc_fac) * sqrt(gain_in/gain_out); *
*---------------------------------------------------*
s = L_deposit_l (div_s (gain_out, gain_in));
s = L_shl (s, 7); // s = gain_out / gain_in
s = L_shr (s, exp); // add exponent
s = Inv_sqrt (s); // function result
i = pv_round (L_shl (s, 9));
// g0 = i * (1-agc_fac)
g0 = mult (i, sub (32767, agc_fac));
}
// compute gain[n] = agc_fac * gain[n-1]
+ (1-agc_fac) * sqrt(gain_in/gain_out)
// sig_out[n] = gain[n] * sig_out[n]
gain = st->past_gain;
for (i = 0; i < l_trm; i++)
{
gain = mult (gain, agc_fac);
gain = add (gain, g0);
sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], gain), 3));
}
st->past_gain = gain;
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]
------------------------------------------------------------------------------
*/
void agc(
agcState *st, /* i/o : agc state */
Word16 *sig_in, /* i : postfilter input signal (l_trm) */
Word16 *sig_out, /* i/o : postfilter output signal (l_trm) */
Word16 agc_fac, /* i : AGC factor */
Word16 l_trm, /* i : subframe size */
Flag *pOverflow /* i : overflow Flag */
)
{
Word16 i;
Word16 exp;
Word16 gain_in;
Word16 gain_out;
Word16 g0;
Word16 gain;
Word32 s;
Word32 L_temp;
Word16 temp;
Word16 *p_sig_out;
/* calculate gain_out with exponent */
s = energy_new(sig_out, l_trm, pOverflow); /* function result */
if (s == 0)
{
st->past_gain = 0;
return;
}
exp = norm_l(s) - 1;
L_temp = L_shl(s, exp, pOverflow);
gain_out = pv_round(L_temp, pOverflow);
/* calculate gain_in with exponent */
s = energy_new(sig_in, l_trm, pOverflow); /* function result */
if (s == 0)
{
g0 = 0;
}
else
{
i = norm_l(s);
/* L_temp = L_shl(s, i, pOverflow); */
L_temp = s << i;
gain_in = pv_round(L_temp, pOverflow);
exp -= i;
/*---------------------------------------------------*
* g0 = (1-agc_fac) * sqrt(gain_in/gain_out); *
*---------------------------------------------------*/
/* s = gain_out / gain_in */
temp = div_s(gain_out, gain_in);
/* s = L_deposit_l (temp); */
s = (Word32) temp;
s = s << 7;
s = L_shr(s, exp, pOverflow); /* add exponent */
s = Inv_sqrt(s, pOverflow); /* function result */
L_temp = s << 9;
i = (Word16)((L_temp + (Word32) 0x00008000L) >> 16);
/* g0 = i * (1-agc_fac) */
temp = 32767 - agc_fac;
g0 = (Word16)(((Word32) i * temp) >> 15);
}
/* compute gain[n] = agc_fac * gain[n-1]
+ (1-agc_fac) * sqrt(gain_in/gain_out) */
/* sig_out[n] = gain[n] * sig_out[n] */
gain = st->past_gain;
p_sig_out = sig_out;
for (i = 0; i < l_trm; i++)
{
/* gain = mult (gain, agc_fac, pOverflow); */
gain = (Word16)(((Word32) gain * agc_fac) >> 15);
/* gain = add (gain, g0, pOverflow); */
gain += g0;
/* L_temp = L_mult (sig_out[i], gain, pOverflow); */
L_temp = ((Word32)(*(p_sig_out)) * gain) << 1;
*(p_sig_out++) = (Word16)(L_temp >> 13);
}
st->past_gain = gain;
return;
}
/*--------------------------------------------------------------------------*/
/*
------------------------------------------------------------------------------
FUNCTION NAME: agc2
------------------------------------------------------------------------------
INPUT AND OUTPUT DEFINITIONS
Inputs:
sig_in = pointer to a buffer containing the postfilter input signal
sig_out = pointer to a buffer containing the postfilter output signal
l_trm = subframe size
pOverflow = pointer to overflow flag
Outputs:
sig_out points to a buffer containing the new scaled output signal.
pOverflow -> 1 if the agc computation saturates
Returns:
None.
Global Variables Used:
None.
Local Variables Needed:
None.
------------------------------------------------------------------------------
FUNCTION DESCRIPTION
Scales the excitation on a subframe basis.
------------------------------------------------------------------------------
REQUIREMENTS
None.
------------------------------------------------------------------------------
REFERENCES
agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001
------------------------------------------------------------------------------
PSEUDO-CODE
void agc2 (
Word16 *sig_in, // i : postfilter input signal
Word16 *sig_out, // i/o : postfilter output signal
Word16 l_trm // i : subframe size
)
{
Word16 i, exp;
Word16 gain_in, gain_out, g0;
Word32 s;
// calculate gain_out with exponent
s = energy_new(sig_out, l_trm); // function result
if (s == 0)
{
return;
}
exp = sub (norm_l (s), 1);
gain_out = pv_round (L_shl (s, exp));
// calculate gain_in with exponent
s = energy_new(sig_in, l_trm); // function result
if (s == 0)
{
g0 = 0;
}
else
{
i = norm_l (s);
gain_in = pv_round (L_shl (s, i));
exp = sub (exp, i);
*---------------------------------------------------*
* g0 = sqrt(gain_in/gain_out); *
*---------------------------------------------------*
s = L_deposit_l (div_s (gain_out, gain_in));
s = L_shl (s, 7); // s = gain_out / gain_in
s = L_shr (s, exp); // add exponent
s = Inv_sqrt (s); // function result
g0 = pv_round (L_shl (s, 9));
}
// sig_out(n) = gain(n) sig_out(n)
for (i = 0; i < l_trm; i++)
{
sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], g0), 3));
}
return;
}
------------------------------------------------------------------------------
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]
------------------------------------------------------------------------------
*/
void agc2(
Word16 *sig_in, /* i : postfilter input signal */
Word16 *sig_out, /* i/o : postfilter output signal */
Word16 l_trm, /* i : subframe size */
Flag *pOverflow /* i : overflow flag */
)
{
Word16 i;
Word16 exp;
Word16 gain_in;
Word16 gain_out;
Word16 g0;
Word32 s;
Word32 L_temp;
Word16 temp;
/* calculate gain_out with exponent */
s = energy_new(sig_out, l_trm, pOverflow); /* function result */
if (s == 0)
{
return;
}
exp = norm_l(s) - 1;
L_temp = L_shl(s, exp, pOverflow);
gain_out = pv_round(L_temp, pOverflow);
/* calculate gain_in with exponent */
s = energy_new(sig_in, l_trm, pOverflow); /* function result */
if (s == 0)
{
g0 = 0;
}
else
{
i = norm_l(s);
L_temp = L_shl(s, i, pOverflow);
gain_in = pv_round(L_temp, pOverflow);
exp -= i;
/*---------------------------------------------------*
* g0 = sqrt(gain_in/gain_out); *
*---------------------------------------------------*/
/* s = gain_out / gain_in */
temp = div_s(gain_out, gain_in);
/* s = L_deposit_l (temp); */
s = (Word32)temp;
if (s > (Word32) 0x00FFFFFFL)
{
s = MAX_32;
}
else if (s < (Word32) 0xFF000000L)
{
s = MIN_32;
}
else
{
s = s << 7;
}
s = L_shr(s, exp, pOverflow); /* add exponent */
s = Inv_sqrt(s, pOverflow); /* function result */
if (s > (Word32) 0x003FFFFFL)
{
L_temp = MAX_32;
}
else if (s < (Word32) 0xFFC00000L)
{
L_temp = MIN_32;
}
else
{
L_temp = s << 9;
}
g0 = pv_round(L_temp, pOverflow);
}
/* sig_out(n) = gain(n) sig_out(n) */
for (i = l_trm - 1; i >= 0; i--)
{
L_temp = L_mult(sig_out[i], g0, pOverflow);
if (L_temp > (Word32) 0x0FFFFFFFL)
{
sig_out[i] = MAX_16;
}
else if (L_temp < (Word32) 0xF0000000L)
{
sig_out[i] = MIN_16;
}
else
{
sig_out[i] = (Word16)(L_temp >> 13);
}
}
return;
}