📄 gsm610.c
字号:
temp = xM[i] << temp1;
temp = (word) (GSM_MULT( temp, temp2 ));
temp = SASR(temp, 12);
xMc[i] = temp + 4;
}
*mant_out = mant;
*exp_out = exp;
*xmaxc_out = xmaxc;
}
/*
* 输入: 量化值xMc[0..12],exp指数,mant尾数
* 输出:还原量化xMc[0..12]的值
* 根据量化值xMc[0..12]的值,逆量化估计计算xMp[0..12]
* This part is for decoding the RPE sequence of coded xMc[0..12]
* samples to obtain the xMp[0..12] array. Table 4.6 is used to get
* the mantissa of xmaxc (FAC[0..7]).
*/
static void APCM_inverse_quantization (register word * xMc, word mant, word exp, register word * xMp)
{
int i;
word temp, temp1, temp2, temp3;
longword ltmp;
assert( mant >= 0 && mant <= 7 );
temp1 = gsm_FAC[ mant ];
temp2 = gsm_sub( 6, exp );
temp3 = gsm_asl( 1, (int) (gsm_sub(temp2, 1))); /* 0.5*2^(temp2)目的四舍五入 */
for ( i = 0; i < 13; i++)
{
assert( *xMc <=7 && *xMc >= 0);
temp = (*xMc++ << 1) - 7; /* 取经过逆量化后的平均值 */
assert(temp <= 7 && temp >= -7);
temp <<= 12; /* 转换成平均值 */
temp = (word) (GSM_MULT_R( temp1, temp));
temp = (word) (GSM_ADD( temp, temp3 )); /* 四舍五入+0.5 */
*xMp++ = gsm_asr( temp, temp2 ); /* 右移temp2位,若temp2为负则左移temp2位 */
}
}
/*
* 输入:Mc子序列栅格位置,xMp[0..12]经过自适应量化后的估计值
* 输出:ep[0..39],拷贝差分估计值估计值
* This procedure computes the reconstructed long term residual signal
* ep[0..39] for the LTP analysis filter. The inputs are the Mc
* which is the grid position selection and the xMp[0..12] decoded
* RPE samples which are upsampled by a factor of 3 by inserting zero
* values.
*/
static void RPE_grid_positioning (word Mc, register word * xMp, register word * ep)
{
int i;
assert(0 <= Mc && Mc <= 3);
for (i = 0; i < 40; i++)
ep[i] = 0;
for (i = 0; i <= 36; i+=3)
ep[Mc + i] = *xMp++;
}
/* 输入: e[-5..45]差分值,其中e[0..40]为有效值
* 输出: Mc子序列栅格号(序号),xmaxc为子序列量化值最大值,xMc[0..12]子序列各数值与xm/xmaxc的量化值
*/
void Gsm_RPE_Encoding (struct gsm610_state * g_gsm, word * e, word * xmaxc, word * Mc, word * xMc)
{
word x[40];
word xM[13], xMp[13];
word mant, exp;
Weighting_filter(e, x);
RPE_grid_selection(x, xM, Mc);//xM子序列值
APCM_quantization( xM, xMc, &mant, &exp, xmaxc);
APCM_inverse_quantization( xMc, mant, exp, xMp);
RPE_grid_positioning( *Mc, xMp, e );
}
/*
* 输入:xmaxcr最大能量值,Mcr子序列栅格位置,xMcr[0..12]子序列量化值
* 输出:erp[0..39]差分估计值
*/
void Gsm_RPE_Decoding (struct gsm610_state * g_gsm, word xmaxcr, word Mcr, word * xMcr, word * erp)
{
word exp, mant;
word xMp[ 13 ];
APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &exp, &mant );
APCM_inverse_quantization( xMcr, mant, exp, xMp );
RPE_grid_positioning( Mcr, xMp, erp );
}
/***************************RPE Code(结束)*******************************************************/
/************************************************************************************************/
/***************************主要函数模块*********************************************************/
/*
* 输入:s 原始一帧160个采样数据
* 输出:LARc[0..7]LPC分析自相关系数,分别点6,6,5,5,4,4,3,3个bit;Nc[0..3]4个子帧的LTP滞后系数各占7bit;
* bc[0..3]4个子帧LTP增益系数各占2bit;Mc[0..3]4个子帧所选子序列栅格位置(序号)各占2bit;
* xmaxc[0..3]4个子帧所选子序列最大能量量化值占6bit;xMc[13*4]4个子帧13个抽样标量量化值各占3bit;
* 一帧160个采样点压缩后共260bit需33byte,
*/
void gsm610_coder (
gsm610 g_gsm, /* 储存各运算过程所需联系的数据 IN/OUT */
word * s_in, /* [0..159] samples原始数据 IN */
word * LARc, /* [0..7] LAR coefficients LPC自相关系数 OUT */
word * Nc, /* [0..3] LTP lag LTP滞后系数 OUT */
word * bc, /* [0..3] coded LTP gain LTP增益系数 OUT */
word * Mc, /* [0..3] RPE grid selection 所选子序列栅格位置 OUT */
word * xmaxc,/* [0..3] Coded maximum amplitude 所选子序列最大能量量化值 OUT */
word * xMc /* [13*4] normalized RPE samples 13个抽样标量量化 OUT */
)
{
int k,i;
word * dp = g_gsm->dp0 + 120; /* [ -120...-1 ] 存放前3个子帧估计值*/
word * dpp = dp; /* [ 0...39 ]存放该子帧估计值 */
static word e [50] = {0}; /*存放一个子帧估计数据的差分值[5..44] dp-dpp*/
word so[160]; /*so存放原始数据s[0..159]经过运算后的值*/
longword ltmp;
Gsm_Preprocess (g_gsm, s_in, so);
Gsm_LPC_Analysis (g_gsm, so, LARc);
Gsm_Short_Term_Analysis_Filter (g_gsm, LARc, so);
for (k = 0; k < 4; k++)
{
Gsm_Long_Term_Predictor ( g_gsm,
so+k*40, /* d [0..39] IN */
dp, /* dp [-120..-1] IN */
e + 5, /* e [0..39] OUT */
dpp, /* dpp [0..39] OUT */
Nc++,
bc++);
Gsm_RPE_Encoding ( g_gsm,e + 5,xmaxc++, Mc++, xMc );
for (i = 0; i < 40; i++)
dp[ i ] = (word) (GSM_ADD( e[5 + i], dpp[i] ));
xMc += 13;
dp += 40;
dpp += 40;
}
(void)memcpy( (char *)g_gsm->dp0, (char *)(g_gsm->dp0 + 160),
120 * sizeof(*g_gsm->dp0) );
}
/*
* 输入:LARcr=[0..7]8个LPC自相关系数,Ncr[0..3]4个LTP滞后值,bcr[0..3]4个LTP增益值
* xmaxcr[0..3]最大能量量化值,xMcr[0..13*4]4个子序列13个量化值
* 输出:s_out经过解码后的一帧语音160个采样数据
* Gsm610_Coder()的逆过程
*/
void Gsm610_Decoder (
gsm610 g_gsm,
word * LARcr, /* [0..7] IN */
word * Ncr, /* [0..3] IN */
word * bcr, /* [0..3] IN */
word * Mcr, /* [0..3] IN */
word * xmaxcr, /* [0..3] IN */
word * xMcr, /* [0..13*4] IN */
word * s_out
) /* [0..159] OUT */
{
int i, k;
word erp[40];
word wt[160];
word * drp = g_gsm->dp0 + 120;
for ( k = 0; k < 4; k++)
{
Gsm_RPE_Decoding( g_gsm, *xmaxcr, *Mcr, xMcr, erp);
Gsm_Long_Term_Synthesis_Filtering( g_gsm, *Ncr, *bcr, erp, drp );
for ( i = 0; i < 40; i++)
wt[ k * 40 + i] = drp [i];
xmaxcr ++;
Mcr ++;
bcr ++;
Ncr ++;
xMcr +=13;
}
Gsm_Short_Term_Synthesis_Filter( g_gsm, LARcr, wt, s_out );
Postprocessing(g_gsm, s_out);
}
/*
* 分配初始化gsm610缓存
*/
gsm610 gsm610_create ()
{
gsm610 r;
r = (gsm610)malloc(sizeof(struct gsm610_state));
if (!r) return r;
memset((char *)r, 0, sizeof(*r));
r->nrp = 40;
return r;
}
/*
* 释放缓存
*/
void gsm610_destroy (gsm610 g_gsm)
{
if (g_gsm)
free((char *)g_gsm);
}
/*
* 输入:source 未经过压缩的标准语音数据,共160个采样数据,点320byte。
* 输出:c 经过编码后语音压缩数据,共占33个字节
* 压缩原理:首先对一帧160个抽样数据s[0..159](20ms)进行缩减数据取13位有效值,
* 再进行加权分析,再通过LPC自相关分析得到各个LPC自相关系数量化值LARc[0..8];
* 接下来对一帧20ms160个抽样数据分成4个子帧处理,每个子帧40个抽样。对每个子帧
* 查找对应的LTP增益bc与延迟Nc。最后通过RPE差分处理过程编码处理,即将子帧40个抽样
* 的差分信号分成4个子序列(第一个:0,3..36;第二个:1,4..37;第三个:2,5..38;
* 第四个:3,6..39),选择最接近原始40个抽样的子序列,子序列栅格位置Mc,并记录子序列
* 的最大能量量化值xmaxc;压缩前160*2*8bit,压缩后260bit
*/
void gsm610_encode(gsm610 g_gsm, gsm_signal * source, gsm_byte * c)
{
word LARc[8]; //存储一帧数据(160)8个LPC自相关分析系数
word Nc[4]; //各子序列LTP分析滞后值
word Mc[4]; //存储和子序列栅格位置
word bc[4]; //各子序列LTP分析增益值
word xmaxc[4]; //经量化后各子序列13个抽样误差最大值
word xmc[13*4]; //13个抽样数据量化值为0-7
gsm610_coder(g_gsm, source, LARc, Nc, bc, Mc, xmaxc, xmc);
*c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */
| ((LARc[0] >> 2) & 0xF);
*c++ = ((LARc[0] & 0x3) << 6)
| (LARc[1] & 0x3F);
*c++ = ((LARc[2] & 0x1F) << 3)
| ((LARc[3] >> 2) & 0x7);
*c++ = ((LARc[3] & 0x3) << 6)
| ((LARc[4] & 0xF) << 2)
| ((LARc[5] >> 2) & 0x3);
*c++ = ((LARc[5] & 0x3) << 6)
| ((LARc[6] & 0x7) << 3)
| (LARc[7] & 0x7);
*c++ = ((Nc[0] & 0x7F) << 1)
| ((bc[0] >> 1) & 0x1);
*c++ = ((bc[0] & 0x1) << 7)
| ((Mc[0] & 0x3) << 5)
| ((xmaxc[0] >> 1) & 0x1F);
*c++ = ((xmaxc[0] & 0x1) << 7)
| ((xmc[0] & 0x7) << 4)
| ((xmc[1] & 0x7) << 1)
| ((xmc[2] >> 2) & 0x1);
*c++ = ((xmc[2] & 0x3) << 6)
| ((xmc[3] & 0x7) << 3)
| (xmc[4] & 0x7);
*c++ = ((xmc[5] & 0x7) << 5) /* 10 */
| ((xmc[6] & 0x7) << 2)
| ((xmc[7] >> 1) & 0x3);
*c++ = ((xmc[7] & 0x1) << 7)
| ((xmc[8] & 0x7) << 4)
| ((xmc[9] & 0x7) << 1)
| ((xmc[10] >> 2) & 0x1);
*c++ = ((xmc[10] & 0x3) << 6)
| ((xmc[11] & 0x7) << 3)
| (xmc[12] & 0x7);
*c++ = ((Nc[1] & 0x7F) << 1)
| ((bc[1] >> 1) & 0x1);
*c++ = ((bc[1] & 0x1) << 7)
| ((Mc[1] & 0x3) << 5)
| ((xmaxc[1] >> 1) & 0x1F);
*c++ = ((xmaxc[1] & 0x1) << 7)
| ((xmc[13] & 0x7) << 4)
| ((xmc[14] & 0x7) << 1)
| ((xmc[15] >> 2) & 0x1);
*c++ = ((xmc[15] & 0x3) << 6)
| ((xmc[16] & 0x7) << 3)
| (xmc[17] & 0x7);
*c++ = ((xmc[18] & 0x7) << 5)
| ((xmc[19] & 0x7) << 2)
| ((xmc[20] >> 1) & 0x3);
*c++ = ((xmc[20] & 0x1) << 7)
| ((xmc[21] & 0x7) << 4)
| ((xmc[22] & 0x7) << 1)
| ((xmc[23] >> 2) & 0x1);
*c++ = ((xmc[23] & 0x3) << 6)
| ((xmc[24] & 0x7) << 3)
| (xmc[25] & 0x7);
*c++ = ((Nc[2] & 0x7F) << 1) /* 20 */
| ((bc[2] >> 1) & 0x1);
*c++ = ((bc[2] & 0x1) << 7)
| ((Mc[2] & 0x3) << 5)
| ((xmaxc[2] >> 1) & 0x1F);
*c++ = ((xmaxc[2] & 0x1) << 7)
| ((xmc[26] & 0x7) << 4)
| ((xmc[27] & 0x7) << 1)
| ((xmc[28] >> 2) & 0x1);
*c++ = ((xmc[28] & 0x3) << 6)
| ((xmc[29] & 0x7) << 3)
| (xmc[30] & 0x7);
*c++ = ((xmc[31] & 0x7) << 5)
| ((xmc[32] & 0x7) << 2)
| ((xmc[33] >> 1) & 0x3);
*c++ = ((xmc[33] & 0x1) << 7)
| ((xmc[34] & 0x7) << 4)
| ((xmc[35] & 0x7) << 1)
| ((xmc[36] >> 2) & 0x1);
*c++ = ((xmc[36] & 0x3) << 6)
| ((xmc[37] & 0x7) << 3)
| (xmc[38] & 0x7);
*c++ = ((Nc[3] & 0x7F) << 1)
| ((bc[3] >> 1) & 0x1);
*c++ = ((bc[3] & 0x1) << 7)
| ((Mc[3] & 0x3) << 5)
| ((xmaxc[3] >> 1) & 0x1F);
*c++ = ((xmaxc[3] & 0x1) << 7)
| ((xmc[39] & 0x7) << 4)
| ((xmc[40] & 0x7) << 1)
| ((xmc[41] >> 2) & 0x1);
*c++ = ((xmc[41] & 0x3) << 6) /* 30 */
| ((xmc[42] & 0x7) << 3)
| (xmc[43] & 0x7);
*c++ = ((xmc[44] & 0x7) << 5)
| ((xmc[45] & 0x7) << 2)
| ((xmc[46] >> 1) & 0x3);
*c++ = ((xmc[46] & 0x1) << 7)
| ((xmc[47] & 0x7) << 4)
| ((xmc[48] & 0x7) << 1)
| ((xmc[49] >> 2) & 0x1);
*c++ = ((xmc[49] & 0x3) << 6)
| ((xmc[50] & 0x7) << 3)
| (xmc[51] & 0x7);
}
/*
* 输入:c 未解码前的一帧20ms语音压缩数据,占33byte。
* 输出: target 解码后的一帧20ms语音数据,共160个采样数据,共320byte。
* 解压原理:输入33byte经GSM6.10编码后的压缩语音,首先取前4bit判断是否为GSM_MAGIC(类似验证码),
* 验证通过,进行按位操作具体步骤:1.首先提取LARc[0..7],为接下来6,6,5,5,4,4,3,3位。2.将剩下224bit
* 分成4部分,即4个子帧来分析,每个子帧占56bit,并对各帧进行位操作。3.将56bit各分配为:LTP滞后Nc[0..3]
* 为7bit*4(每个子帧56bit前7bit);LTP增益bc[0..3]为2bit*4(接下来2bit);子序列栅格位置Mc[0..3]为2bit*4(接
* 下来2bit);再接下来为最大能量量化值xmaxc[0..3]占6bit;最后剩39bit分别为子序列13个抽样差分量化值xmc[0..12*4]。
* 位操作完毕根据各系数逆编码原理解码。
*/
void gsm610_decode (gsm610 g_gsm, gsm_byte * c, gsm_signal * target)
{
word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
/* GSM_MAGIC = (*c >> 4) & 0xF; */
if (((*c >> 4) & 0x0F) != GSM_MAGIC)
return ;//-1;
LARc[0] = (*c++ & 0xF) << 2; /* 1 */
LARc[0] |= (*c >> 6) & 0x3;
LARc[1] = *c++ & 0x3F;
LARc[2] = (*c >> 3) & 0x1F;
LARc[3] = (*c++ & 0x7) << 2;
LARc[3] |= (*c >> 6) & 0x3;
LARc[4] = (*c >> 2) & 0xF;
LARc[5] = (*c++ & 0x3) << 2;
LARc[5] |= (*c >> 6) & 0x3;
LARc[6] = (*c >> 3) & 0x7;
LARc[7] = *c++ & 0x7;
Nc[0] = (*c >> 1) & 0x7F;
bc[0] = (*c++ & 0x1) << 1;
bc[0] |= (*c >> 7) & 0x1;
Mc[0] = (*c >> 5) & 0x3;
xmaxc[0] = (*c++ & 0x1F) << 1;
xmaxc[0] |= (*c >> 7) & 0x1;
xmc[0] = (*c >> 4) & 0x7;
xmc[1] = (*c >> 1) & 0x7;
xmc[2] = (*c++ & 0x1) << 2;
xmc[2] |= (*c >> 6) & 0x3;
xmc[3] = (*c >> 3) & 0x7;
xmc[4] = *c++ & 0x7;
xmc[5] = (*c >> 5) & 0x7;
xmc[6] = (*c >> 2) & 0x7;
xmc[7] = (*c++ & 0x3) << 1; /* 10 */
xmc[7] |= (*c >> 7) & 0x1;
xmc[8] = (*c >> 4) & 0x7;
xmc[9] = (*c >> 1) & 0x7;
xmc[10] = (*c++ & 0x1) << 2;
xmc[10] |= (*c >> 6) & 0x3;
xmc[11] = (*c >> 3) & 0x7;
xmc[12] = *c++ & 0x7;
Nc[1] = (*c >> 1) & 0x7F;
bc[1] = (*c++ & 0x1) << 1;
bc[1] |= (*c >> 7) & 0x1;
Mc[1] = (*c >> 5) & 0x3;
xmaxc[1] = (*c++ & 0x1F) << 1;
xmaxc[1] |= (*c >> 7) & 0x1;
xmc[13] = (*c >> 4) & 0x7;
xmc[14] = (*c >> 1) & 0x7;
xmc[15] = (*c++ & 0x1) << 2;
xmc[15] |= (*c >> 6) & 0x3;
xmc[16] = (*c >> 3) & 0x7;
xmc[17] = *c++ & 0x7;
xmc[18] = (*c >> 5) & 0x7;
xmc[19] = (*c >> 2) & 0x7;
xmc[20] = (*c++ & 0x3) << 1;
xmc[20] |= (*c >> 7) & 0x1;
xmc[21] = (*c >> 4) & 0x7;
xmc[22] = (*c >> 1) & 0x7;
xmc[23] = (*c++ & 0x1) << 2;
xmc[23] |= (*c >> 6) & 0x3;
xmc[24] = (*c >> 3) & 0x7;
xmc[25] = *c++ & 0x7;
Nc[2] = (*c >> 1) & 0x7F;
bc[2] = (*c++ & 0x1) << 1; /* 20 */
bc[2] |= (*c >> 7) & 0x1;
Mc[2] = (*c >> 5) & 0x3;
xmaxc[2] = (*c++ & 0x1F) << 1;
xmaxc[2] |= (*c >> 7) & 0x1;
xmc[26] = (*c >> 4) & 0x7;
xmc[27] = (*c >> 1) & 0x7;
xmc[28] = (*c++ & 0x1) << 2;
xmc[28] |= (*c >> 6) & 0x3;
xmc[29] = (*c >> 3) & 0x7;
xmc[30] = *c++ & 0x7;
xmc[31] = (*c >> 5) & 0x7;
xmc[32] = (*c >> 2) & 0x7;
xmc[33] = (*c++ & 0x3) << 1;
xmc[33] |= (*c >> 7) & 0x1;
xmc[34] = (*c >> 4) & 0x7;
xmc[35] = (*c >> 1) & 0x7;
xmc[36] = (*c++ & 0x1) << 2;
xmc[36] |= (*c >> 6) & 0x3;
xmc[37] = (*c >> 3) & 0x7;
xmc[38] = *c++ & 0x7;
Nc[3] = (*c >> 1) & 0x7F;
bc[3] = (*c++ & 0x1) << 1;
bc[3] |= (*c >> 7) & 0x1;
Mc[3] = (*c >> 5) & 0x3;
xmaxc[3] = (*c++ & 0x1F) << 1;
xmaxc[3] |= (*c >> 7) & 0x1;
xmc[39] = (*c >> 4) & 0x7;
xmc[40] = (*c >> 1) & 0x7;
xmc[41] = (*c++ & 0x1) << 2;
xmc[41] |= (*c >> 6) & 0x3;
xmc[42] = (*c >> 3) & 0x7;
xmc[43] = *c++ & 0x7; /* 30 */
xmc[44] = (*c >> 5) & 0x7;
xmc[45] = (*c >> 2) & 0x7;
xmc[46] = (*c++ & 0x3) << 1;
xmc[46] |= (*c >> 7) & 0x1;
xmc[47] = (*c >> 4) & 0x7;
xmc[48] = (*c >> 1) & 0x7;
xmc[49] = (*c++ & 0x1) << 2;
xmc[49] |= (*c >> 6) & 0x3;
xmc[50] = (*c >> 3) & 0x7;
xmc[51] = *c & 0x7; /* 33 */
Gsm610_Decoder(g_gsm, LARc, Nc, bc, Mc, xmaxc, xmc, target);
//return; 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -