rtphone/src/libs/libevs/lib_com/ari_hm.cpp

271 lines
7.3 KiB
C++

/*====================================================================================
EVS Codec 3GPP TS26.443 Nov 13, 2018. Version 12.11.0 / 13.7.0 / 14.3.0 / 15.1.0
====================================================================================*/
#include <assert.h>
#include <math.h>
#include "cnst.h"
#include "stl.h"
#include "basop_util.h"
#include "prot.h"
#include "rom_com.h"
/*-------------------------------------------------------------------*
* UnmapIndex()
*
*
*-------------------------------------------------------------------*/
void UnmapIndex(
int PeriodicityIndex,
int Bandwidth,
short LtpPitchLag,
int SmallerLags,
int *FractionalResolution,
int *Lag)
{
if ((LtpPitchLag > 0) && (PeriodicityIndex & kLtpHmFlag))
{
int LtpPitchIndex, Multiplier;
LtpPitchIndex = PeriodicityIndex >> 9;
Multiplier = PeriodicityIndex & 0xff;
assert(0 <= LtpPitchIndex && LtpPitchIndex <= 16);
assert(1 <= Multiplier && Multiplier <= (1 << NumRatioBits[Bandwidth][LtpPitchIndex]));
*FractionalResolution = kLtpHmFractionalResolution;
*Lag = (LtpPitchLag * (int)(4 * Ratios[Bandwidth][LtpPitchIndex][Multiplier-1])) >> 2;
}
else
{
if (PeriodicityIndex < 16)
{
*FractionalResolution = 3;
*Lag = PeriodicityIndex + GET_ADJ(0, 6);
}
else if (PeriodicityIndex < 80)
{
*FractionalResolution = 4;
*Lag = PeriodicityIndex + GET_ADJ(16, 8);
}
else if (PeriodicityIndex < 208)
{
*FractionalResolution = 3;
*Lag = PeriodicityIndex + GET_ADJ(80, 12);
}
else if (PeriodicityIndex < 224 || SmallerLags)
{
*FractionalResolution = 1;
*Lag = PeriodicityIndex + GET_ADJ(208, 28);
}
else
{
*FractionalResolution = 0;
*Lag = PeriodicityIndex + GET_ADJ(224, 188);
}
}
return;
}
/*-------------------------------------------------------------------*
* ConfigureContextHm()
*
*
*-------------------------------------------------------------------*/
void ConfigureContextHm(
int NumCoeffs, /* (I) Number of coefficients */
int TargetBits, /* (I) Target bit budget (excl. Done flag) */
int PeriodicityIndex, /* (I) Pitch related index */
short LtpPitchLag, /* (I) TCX-LTP pitch in F.D. */
CONTEXT_HM_CONFIG *hm_cfg /* (O) Context-based harmonic model configuration */
)
{
int Bandwidth, SmallerLags;
int i, Limit, Lag;
int j, Index, FractionalResolution;
int *tmp;
Bandwidth = 0;
if (NumCoeffs >= 256)
{
Bandwidth = 1;
}
SmallerLags = 0;
if (TargetBits <= kSmallerLagsTargetBitsThreshold || Bandwidth == 0)
{
SmallerLags = 1;
}
UnmapIndex(PeriodicityIndex, Bandwidth, LtpPitchLag, SmallerLags, &FractionalResolution, &Lag );
/* Set up and fill peakIndices */
hm_cfg->peakIndices = hm_cfg->indexBuffer;
tmp = hm_cfg->peakIndices;
Limit = (NumCoeffs - 1) << FractionalResolution;
for (i=Lag; i<Limit; i+=Lag)
{
Index = i >> FractionalResolution;
*tmp++ = Index - 1;
*tmp++ = Index;
*tmp++ = Index + 1;
}
hm_cfg->numPeakIndices = tmp - hm_cfg->indexBuffer;
/* Set up and fill holeIndices */
hm_cfg->holeIndices = hm_cfg->indexBuffer + hm_cfg->numPeakIndices;
tmp = hm_cfg->holeIndices;
Index = 0;
for (j=0; j<hm_cfg->numPeakIndices; j+=3)
{
for (; Index<hm_cfg->peakIndices[j]; ++Index)
{
*tmp++ = Index;
}
Index += 3; /* Skip the peak */
}
for (; Index<NumCoeffs; ++Index)
{
*tmp++ = Index;
}
hm_cfg->numHoleIndices = tmp - hm_cfg->holeIndices;
/* Add extremal element signaling the end of the buffer */
*tmp++ = NumCoeffs;
return;
}
/*-------------------------------------------------------------------*
* CountIndexBits()
*
*
*-------------------------------------------------------------------*/
int CountIndexBits(
int Bandwidth,
int PeriodicityIndex)
{
if (PeriodicityIndex & kLtpHmFlag)
{
int LtpPitchIndex = PeriodicityIndex >> 9;
return NumRatioBits[Bandwidth][LtpPitchIndex];
}
return 8;
}
/*-------------------------------------------------------------------*
* tcx_hm_render()
*
*
*-------------------------------------------------------------------*/
int tcx_hm_render(
int lag, /* i: pitch lag */
int fract_res, /* i: fractional resolution of the lag */
float LtpGain, /* i: LTP gain */
Word16 p[] /* o: harmonic model (Q13) */
)
{
int k;
Word32 f0, tmp32;
Word16 height, PeakDeviation, tmp;
/* Set up overall shape */
(void)LtpGain;
f0 = L_shl(lag, sub(15, fract_res)); /* Q15 */
tmp32 = Mpy_32_16(f0, -26474);
tmp32 = L_shr_r(BASOP_Util_InvLog2(L_shl(tmp32, 7)), 2);
tmp32 = L_sub(603979776L, tmp32);
tmp32 = L_add(L_add(tmp32, tmp32), Mpy_32_16(tmp32, 26214));
height = round_fx(tmp32); /* Q13 */
tmp32 = Mpy_32_16(f0, -18910);
tmp32 = L_shr_r(BASOP_Util_InvLog2(L_shl(tmp32, 7)), 2);
tmp32 = L_sub(1395864371L, tmp32);
PeakDeviation = round_fx(tmp32); /* Q14 */
IF( sub(13915,PeakDeviation) > 0 )
{
/* A bit error was encountered */
return 1;
}
ELSE
{
tmp = div_s(13915, PeakDeviation);
tmp = mult_r(tmp, tmp); /* Q15 */
}
/* Render the prototype peak */
p[kTcxHmParabolaHalfWidth] = height;
for (k=1; k<=kTcxHmParabolaHalfWidth; ++k)
{
p[kTcxHmParabolaHalfWidth+k] = round_fx(Mpy_32_16(BASOP_Util_InvLog2(L_shl(L_mult0(mult0(negate(k),k), tmp),10)), height));
}
/* Mirror */
for (k=-kTcxHmParabolaHalfWidth; k<0; ++k)
{
p[kTcxHmParabolaHalfWidth+k] = p[kTcxHmParabolaHalfWidth-k];
}
return 0;
}
/*-------------------------------------------------------------------*
* tcx_hm_modify_envelope()
*
*
*-------------------------------------------------------------------*/
void tcx_hm_modify_envelope(
Word16 gain, /* i: HM gain (Q11) */
int lag,
int fract_res,
Word16 p[], /* i: harmonic model (Q13) */
Word32 env[], /* i/o: envelope (Q16) */
int L_frame /* i: number of spectral lines */
)
{
int k;
int h, x;
Word16 inv_shape[2*kTcxHmParabolaHalfWidth+1]; /* Q15 */
if (gain == 0)
{
return;
}
for (k=0; k<2*kTcxHmParabolaHalfWidth+1; ++k)
{
inv_shape[k] = div_s(512, add(512, round_fx(L_mult(gain, p[k]))));
}
h = 1;
k = lag >> fract_res;
while (k <= L_frame + kTcxHmParabolaHalfWidth - 1)
{
for (x=max(0, k-kTcxHmParabolaHalfWidth); x<=min(k+kTcxHmParabolaHalfWidth, L_frame-1); ++x)
{
env[x] = Mpy_32_16(env[x], inv_shape[x-k+kTcxHmParabolaHalfWidth]);
}
++h;
k = (h * lag) >> fract_res;
}
return;
}