📄 gsm_encode.c
字号:
/*
GSM voice codec, part of the HawkVoice Direct Interface (HVDI)
cross platform network voice library
Copyright (C) 2001-2003 Phil Frisbie, Jr. (phil@hawksoft.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Or go to http://www.gnu.org/copyleft/lgpl.html
*/
/*
* Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
* Universitaet Berlin. See the accompanying file "COPYRIGHT" for
* details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include "private.h"
static unsigned char const bitoff[ 256 ] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static gsmword gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 };
static gsmword gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 };
static gsmword gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 };
static gsmword gsm_DLB[4] = {6554, 16384, 26214, 32767};
static gsmword gsm_norm(longword a)
{
if(a < 0)
{
if(a <= -1073741824)
return 0;
a = ~a;
}
return (gsmword)(a & 0xffff0000
? ( a & 0xff000000
? -1 + bitoff[ 0xFF & (a >> 24) ]
: 7 + bitoff[ 0xFF & (a >> 16) ] )
: ( a & 0xff00
? 15 + bitoff[ 0xFF & (a >> 8) ]
: 23 + bitoff[ 0xFF & a ] ));
}
static void Gsm_Preprocess(struct gsm_state * S, short *s, gsmword *so)
{
gsmword z1 = S->z1;
longword L_z2 = S->L_z2;
gsmword mp = (gsmword)S->mp;
gsmword s1;
longword L_s2;
longword L_temp;
gsmword msp;
gsmword SO;
int k = 160;
while(k--)
{
SO = (gsmword)(SASL( SASR( *s, 3 ), 2 ));
s++;
s1 = (gsmword)(SO - z1);
z1 = SO;
L_s2 = s1;
L_s2 = SASL( L_s2, 15 );
L_z2 += L_s2;
L_temp = L_z2 + 16384;
msp = (gsmword)GSM_MULT_R( mp, -28672 );
mp = (gsmword)SASR( L_temp, 15 );
*so++ = (gsmword)(mp + msp);
}
S->z1 = z1;
S->L_z2 = L_z2;
S->mp = mp;
}
static void Autocorrelation(gsmword *s, longword *L_ACF)
{
int k, i;
gsmword * sp = s;
gsmword sl;
gsmword temp, smax, scalauto;
gsmword ss[160];
gsmword * ssp = ss;
smax = 0;
for(k = 160; k--; sp++)
{
temp = (gsmword)GSM_ABS( *sp );
if(temp > smax)
smax = temp;
}
if(smax == 0)
{
scalauto = 0;
}
else {
scalauto = (gsmword)(4 - gsm_norm( SASL( (longword)smax, 16 ) ));/* sub(4,..) */
}
sp = s;
if(scalauto > 0)
{
for(k = 160; k--; sp++, ssp++)
*ssp = (gsmword)SASR( *sp, scalauto );
}
else
{
memcpy(ssp, sp, sizeof(ss));
}
# define STEP(k) L_ACF[k] += ((longword)sl * ssp[ -(k) ]);
# define NEXTI sl = *++ssp
ssp = ss;
sl = *ssp;
for(k = 9; k--; L_ACF[k] = 0) ;
STEP (0);
NEXTI;
STEP(0); STEP(1);
NEXTI;
STEP(0); STEP(1); STEP(2);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6);
NEXTI;
STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7);
for(i = 8; i < 160; i++)
{
NEXTI;
STEP(0);
STEP(1); STEP(2); STEP(3); STEP(4);
STEP(5); STEP(6); STEP(7); STEP(8);
}
for(k = 9; k--; L_ACF[k] *= 2) ;
}
static void Reflection_coefficients(longword *L_ACF, gsmword *r)
{
int i, m, n;
gsmword temp;
gsmword ACF[9]; /* 0..8 */
gsmword P[ 9]; /* 0..8 */
gsmword K[ 9]; /* 2..8 */
if(L_ACF[0] == 0)
{
for(i = 8; i--; *r++ = 0) ;
return;
}
temp = gsm_norm( L_ACF[0] );
for(i = 0; i <= 8; i++)
ACF[i] = (gsmword)SASR( SASL (L_ACF[i], temp ), 16 );
for(i = 1; i <= 7; i++)
K[ i ] = ACF[ i ];
for(i = 0; i <= 8; i++)
P[ i ] = ACF[ i ];
for(n = 1; n <= 8; n++, r++)
{
temp = P[1];
temp = (gsmword)GSM_ABS(temp);
if(P[0] < temp)
{
for(i = n; i <= 8; i++)
*r++ = 0;
return;
}
*r = gsm_div( temp, P[0] );
if(P[1] > 0)
*r = (gsmword)-*r;
if(n == 8)
return;
temp = (gsmword)GSM_MULT_R( P[1], *r );
P[0] += temp;
for(m = 1; m <= 8 - n; m++)
{
P[m] = (gsmword)P[ m+1 ] + (gsmword)GSM_MULT_R( K[m], *r );
K[m] = (gsmword)K[ m ] + (gsmword)GSM_MULT_R( P[ m+1 ], *r );
}
}
}
static void Transformation_to_Log_Area_Ratios(gsmword *r)
{
gsmword temp;
int i;
for(i = 1; i <= 8; i++, r++)
{
temp = *r;
temp = (gsmword)GSM_ABS(temp);
if(temp < 22118)
{
temp = (gsmword)SASR( temp, 1 );
}
else if(temp < 31130)
{
temp -= 11059;
}
else
{
temp -= 26112;
temp = (gsmword)SASL( temp, 2 );
}
*r = (gsmword)(*r < 0 ? -temp : temp);
}
}
static void Quantization_and_coding(gsmword *LAR)
{
gsmword temp;
# undef STEP
# define STEP( A, B, MAC, MIC ) \
temp = (gsmword)GSM_MULT( A, *LAR ); \
temp += B; \
temp += 256; \
temp = (gsmword)SASR( temp, 9 ); \
*LAR = (gsmword)(temp>MAC ? MAC - MIC : (temp<MIC ? 0 : temp - MIC)); \
LAR++;
STEP( 20480, 0, 31, -32 );
STEP( 20480, 0, 31, -32 );
STEP( 20480, 2048, 15, -16 );
STEP( 20480, -2560, 15, -16 );
STEP( 13964, 94, 7, -8 );
STEP( 15360, -1792, 7, -8 );
STEP( 8534, -341, 3, -4 );
STEP( 9036, -1144, 3, -4 );
# undef STEP
}
static void Gsm_LPC_Analysis(gsmword *s, gsmword *LARc)
{
longword L_ACF[9];
Autocorrelation (s, L_ACF);
Reflection_coefficients(L_ACF, LARc);
Transformation_to_Log_Area_Ratios(LARc);
Quantization_and_coding(LARc);
}
static void Weighting_filter(gsmword *e, gsmword *x)
{
longword L_result, ltmp;
gsmword * pe = e;
int k;
pe -= 5;
for (k = 40; k--; pe++)
{
#undef STEP
#define STEP( i, H ) (SASL( pe[i], (H) ) )
L_result = 4096 - STEP( 0, 7 ) - (STEP( 1, 8 ))
+ STEP( 3, 11 ) + STEP( 4, 12 ) + STEP( 4, 10 )
+ STEP( 5, 13 ) + STEP( 6, 12 ) + STEP( 6, 10 )
+ STEP( 7, 11 ) - STEP( 9, 8 ) - STEP( 10, 7 );
*x++ = (gsmword)GSM_ADD( SASR( L_result, 13 ), 0 );
}
}
static void RPE_grid_selection(gsmword *x, gsmword *xM, gsmword *Mc_out)
{
int i;
longword L_result, L_temp;
longword EM;
gsmword Mc;
longword L_common_0_3;
EM = 0;
Mc = 0;
#undef STEP
#define STEP( m, i ) L_temp = SASR( x[m + 3 * i], 2 ); \
L_result += L_temp * L_temp;
L_result = 0;
STEP( 0, 1 ); STEP( 0, 2 ); STEP( 0, 3 ); STEP( 0, 4 );
STEP( 0, 5 ); STEP( 0, 6 ); STEP( 0, 7 ); STEP( 0, 8 );
STEP( 0, 9 ); STEP( 0, 10); STEP( 0, 11); STEP( 0, 12);
L_common_0_3 = L_result;
STEP( 0, 0 );
L_result = SASL( L_result, 1 );
EM = L_result;
L_result = 0;
STEP( 1, 0 );
STEP( 1, 1 ); STEP( 1, 2 ); STEP( 1, 3 ); STEP( 1, 4 );
STEP( 1, 5 ); STEP( 1, 6 ); STEP( 1, 7 ); STEP( 1, 8 );
STEP( 1, 9 ); STEP( 1, 10); STEP( 1, 11); STEP( 1, 12);
L_result = SASL( L_result, 1 );
if(L_result > EM)
{
Mc = 1;
EM = L_result;
}
L_result = 0;
STEP( 2, 0 );
STEP( 2, 1 ); STEP( 2, 2 ); STEP( 2, 3 ); STEP( 2, 4 );
STEP( 2, 5 ); STEP( 2, 6 ); STEP( 2, 7 ); STEP( 2, 8 );
STEP( 2, 9 ); STEP( 2, 10); STEP( 2, 11); STEP( 2, 12);
L_result = SASL( L_result, 1 );
if(L_result > EM)
{
Mc = 2;
EM = L_result;
}
L_result = L_common_0_3;
STEP( 3, 12 );
L_result = SASL( L_result, 1 );
if(L_result > EM)
{
Mc = 3;
EM = L_result;
}
for(i = 0; i <= 12; i ++)
xM[i] = x[Mc + 3*i];
*Mc_out = Mc;
}
static void APCM_quantization_xmaxc_to_exp_mant(gsmword xmaxc, gsmword *exp_out,
gsmword *mant_out)
{
gsmword exp, mant;
exp = 0;
if(xmaxc > 15)
exp = (gsmword)(SASR(xmaxc, 3) - 1);
mant = (gsmword)(xmaxc - SASL( exp, 3 ));
if(mant == 0)
{
exp = -4;
mant = 7;
}
else
{
while(mant <= 7)
{
mant = (gsmword)(SASL(mant, 1) | 1);
exp--;
}
mant -= 8;
}
*exp_out = exp;
*mant_out = mant;
}
static void APCM_quantization(gsmword *xM, gsmword *xMc, gsmword *mant_out,
gsmword *exp_out, gsmword *xmaxc_out)
{
int i, itest;
gsmword xmax, xmaxc, temp, temp1, temp2;
gsmword exp, mant;
longword ltmp;
xmax = 0;
for(i = 0; i <= 12; i++)
{
temp = xM[i];
temp = (gsmword)GSM_ABS(temp);
if (temp > xmax) xmax = temp;
}
exp = 0;
temp = (gsmword)SASR( xmax, 9 );
itest = 0;
for(i = 0; i <= 5; i++)
{
itest |= (temp <= 0);
temp = (gsmword)SASR( temp, 1 );
if(itest == 0)
exp++; /* exp = add (exp, 1) */
}
temp = (gsmword)(exp + 5);
xmaxc = (gsmword)GSM_ADD( (gsmword)SASR(xmax, temp), (gsmword)SASL(exp, 3) );
APCM_quantization_xmaxc_to_exp_mant( xmaxc, &exp, &mant );
temp1 = (gsmword)(6 - exp); /* normalization by the exponent */
temp2 = gsm_NRFAC[ mant ]; /* inverse mantissa */
for(i = 0; i <= 12; i++)
{
temp = (gsmword)SASL(xM[i], temp1);
temp = (gsmword)GSM_MULT( temp, temp2 );
temp = (gsmword)SASR(temp, 12);
xMc[i] = (gsmword)(temp + 4);
}
*mant_out = mant;
*exp_out = exp;
*xmaxc_out = xmaxc;
}
static void APCM_inverse_quantization(gsmword *xMc, gsmword mant, gsmword exp, gsmword *xMp)
{
int i;
gsmword temp, temp1, temp2, temp3;
longword ltmp;
temp1 = gsm_FAC[ mant ]; /* see 4.2-15 for mant */
temp2 = (gsmword)GSM_SUB( 6, exp ); /* see 4.2-15 for exp */
temp3 = (gsmword)SASL( 1, GSM_SUB( temp2, 1 ));
for(i = 13; i--;)
{
temp = (gsmword)(SASL(*xMc++, 1) - 7); /* restore sign */
temp = (gsmword)SASL(temp, 12); /* 16 bit signed */
temp = (gsmword)GSM_MULT_R( temp1, temp );
temp = (gsmword)GSM_ADD( temp, temp3 );
*xMp++ = (gsmword)SASR( temp, temp2 );
}
}
static void RPE_grid_positioning(gsmword Mc, gsmword *xMp, gsmword *ep)
{
int i = 13;
switch (Mc) {
case 3: *ep++ = 0;
case 2: do
{
*ep++ = 0;
case 1: *ep++ = 0;
case 0: *ep++ = *xMp++;
} while (--i != 0);
}
while(++Mc < 4)
*ep++ = 0;
}
static void Gsm_RPE_Encoding(gsmword *e, gsmword *xmaxc, gsmword *Mc, gsmword *xMc)
{
gsmword x[40];
gsmword xM[13], xMp[13];
gsmword mant, exp;
Weighting_filter(e, x);
RPE_grid_selection(x, xM, Mc);
APCM_quantization( xM, xMc, &mant, &exp, xmaxc);
APCM_inverse_quantization( xMc, mant, exp, xMp);
RPE_grid_positioning( *Mc, xMp, e );
}
static void Decoding_of_the_coded_Log_Area_Ratios(gsmword *LARc, gsmword *LARpp)
{
gsmword temp1;
longword ltmp;
#undef STEP
#define STEP( B, MIC, INVA ) \
temp1 = (gsmword)(SASL( *LARc++ + MIC , 10)); \
temp1 -= SASL( B, 1 ); \
temp1 = (gsmword)GSM_MULT_R( INVA, temp1 ); \
*LARpp++ = (gsmword)GSM_ADD( temp1, temp1 );
STEP( 0, -32, 13107 );
STEP( 0, -32, 13107 );
STEP( 2048, -16, 13107 );
STEP( -2560, -16, 13107 );
STEP( 94, -8, 19223 );
STEP( -1792, -8, 17476 );
STEP( -341, -4, 31454 );
STEP( -1144, -4, 29708 );
}
INLINE void Coefficients_0_12(gsmword * LARpp_j_1, gsmword * LARpp_j, gsmword * LARp)
{
int i;
for(i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++)
{
*LARp = (gsmword)(SASR( *LARpp_j_1, 2 ) + SASR( *LARpp_j, 2 ));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -