📄 melp_syn.c
字号:
/*
2.4 kbps MELP Proposed Federal Standard speech coder
Fixed-point C code, version 1.0
Copyright (c) 1998, Texas Instruments, Inc.
Texas Instruments has intellectual property rights on the MELP
algorithm. The Texas Instruments contact for licensing issues for
commercial and non-government use is William Gordon, Director,
Government Contracts, Texas Instruments Incorporated, Semiconductor
Group (phone 972 480 7442).
The fixed-point version of the voice codec Mixed Excitation Linear
Prediction (MELP) is based on specifications on the C-language software
simulation contained in GSM 06.06 which is protected by copyright and
is the property of the European Telecommunications Standards Institute
(ETSI). This standard is available from the ETSI publication office
tel. +33 (0)4 92 94 42 58. ETSI has granted a license to United States
Department of Defense to use the C-language software simulation contained
in GSM 06.06 for the purposes of the development of a fixed-point
version of the voice codec Mixed Excitation Linear Prediction (MELP).
Requests for authorization to make other use of the GSM 06.06 or
otherwise distribute or modify them need to be addressed to the ETSI
Secretariat fax: +33 493 65 47 16.
*/
/*
Name: melp_syn.c
Description: MELP synthesis
This program takes the new parameters for a speech
frame and synthesizes the output speech. It keeps
an internal record of the previous frame parameters
to use for interpolation.
Inputs:
*par - MELP parameter structure
Outputs:
speech[] - output speech signal
Returns: void
*/
/* compiler include files */
#include <stdio.h>
#include <math.h>
#include "mathhalf.h"
#include "melp.h"
#include "spbstd.h"
#include "lpc.h"
#include "mat.h"
#include "vq.h"
#include "fs.h"
#include "math_lib.h"
#include "constant.h"
#include "wmops.h"
/* compiler constants */
#define ORIGINAL_SYNTH_GAIN 0
#if (MIX_ORD > DISP_ORD)
#define BEGIN MIX_ORD
#else
#define BEGIN DISP_ORD
#endif
#define TILT_ORD 1
#if (ORIGINAL_SYNTH_GAIN)
#define SYN_GAIN_Q4 16000 /* (1000.0*(1<<4)) */
#else
#define SYN_GAIN_Q4 32000 /* (2000.0*(1<<4)) */
#endif
#define SCALEOVER 10
#define INV_SCALEOVER_Q18 26214 /* ((1.0/SCALEOVER)*(1<<18)) */
#define PDEL SCALEOVER
/* external memory references */
extern Shortword bp_cof[NUM_BANDS][MIX_ORD+1];
extern Shortword disp_cof[DISP_ORD+1];
extern Shortword msvq_cb[];
extern Shortword msvq_cb_mean[];
extern Shortword fsvq_cb[];
extern Shortword fsvq_weighted;
extern FILE *fp_indat, *fp_outdat;
/* temporary memory */
static Shortword sigbuf[BEGIN+PITCHMAX];
static Shortword sig2[BEGIN+PITCHMAX];
static Shortword fs_real[PITCHMAX];
static Shortword sp_out[BEGIN+FRAME];
/* permanent memory */
static Shortword firstcall = 1; /* Just used for noise gain init */
static Shortword prev_gain_err;
static Shortword sigsave[PITCHMAX];
static struct melp_param prev_par;
static Shortword syn_begin;
static Shortword prev_scale;
static Shortword noise_gain = (Shortword)MIN_NOISE_Q8;
static Shortword pulse_del[MIX_ORD],noise_del[MIX_ORD];
static Shortword lpc_del[LPC_ORD],ase_del[LPC_ORD],tilt_del[TILT_ORD];
static Shortword disp_del[DISP_ORD];
static Shortword prev_lpc_gain;
static struct msvq_param vq_par; /* MSVQ parameters */
static struct msvq_param fs_vq_par; /* Fourier series VQ parameters */
static Shortword w_fs_inv[NUM_HARM];
/* these can be saved or recomputed */
static Shortword prev_pcof[MIX_ORD+1],prev_ncof[MIX_ORD+1];
static Shortword prev_tilt;
static Shortword prev_gain;
/*static Shortword frame=0;*/
void melp_syn(struct melp_param *par,Shortword speech_out[])
{
Shortword i, gaincnt;
Shortword erase;
Shortword length;
Shortword intfact, intfact1, ifact, ifact_gain;
Shortword gain,pulse_gain,pitch,jitter;
Shortword curr_tilt,tilt_cof[TILT_ORD+1];
Shortword sig_prob,syn_gain,lpc_gain;
Shortword lsf[LPC_ORD+1];
Shortword lpc[LPC_ORD+1];
Shortword ase_num[LPC_ORD+1],ase_den[LPC_ORD+1];
Shortword curr_pcof[MIX_ORD+1],curr_ncof[MIX_ORD+1];
Shortword pulse_cof[MIX_ORD+1],noise_cof[MIX_ORD+1];
Shortword temp1,temp2;
Longword L_temp1,L_temp2;
/* Copy previous period of processed speech to output array */
if (syn_begin > 0) {
if (syn_begin > FRAME) {
v_equ(&sp_out[BEGIN],&sigsave[0],FRAME);
/* past end: save remainder in sigsave[0] */
v_equ(&sigsave[0],&sigsave[FRAME],(Shortword)(syn_begin-FRAME));
}
else
v_equ(&sp_out[BEGIN],&sigsave[0],syn_begin);
}
erase = 0; /* no erasures yet */
/* Update MSVQ information */
par->msvq_stages = vq_par.num_stages;
par->msvq_bits = vq_par.num_bits;
par->msvq_levels = vq_par.num_levels;
par->msvq_index = vq_par.indices;
par->fsvq_index = fs_vq_par.indices;
/* Read and decode channel input buffer */
erase = melp_chn_read(par,&prev_par);
if (par->uv_flag != 1 && !erase) {
/* Un-weight Fourier magnitudes */
window_Q(&par->fs_mag[0],w_fs_inv,&par->fs_mag[0],NUM_HARM,14);
}
/* Update adaptive noise level estimate based on last gain */
if (firstcall) {
firstcall = 0;
noise_gain = par->gain[NUM_GAINFR-1]; /* noise_gain in Q8 */
}
else if (!erase) {
for (i = 0; i < NUM_GAINFR; i++) {
noise_est(par->gain[i],&noise_gain,(Shortword)UPCONST_Q19,
(Shortword)DOWNCONST_Q17,(Shortword)MIN_NOISE_Q8,
(Shortword)MAX_NOISE_Q8);
/* Adjust gain based on noise level (noise suppression) */
noise_sup(&par->gain[i],noise_gain,(Shortword)MAX_NS_SUP_Q8,
(Shortword)MAX_NS_ATT_Q8,(Shortword)NFACT_Q8);
}
}
/* Clamp LSP bandwidths to avoid sharp LPC filters */
lpc_clamp(par->lsf,BWMIN_Q15,LPC_ORD);
/* Calculate spectral tilt for current frame for spectral enhancement */
tilt_cof[0] = ONE_Q15; /* tilt_cof in Q15 */
lpc_lsp2pred(par->lsf,lpc,LPC_ORD);
#if (!ORIGINAL_SYNTH_GAIN)
/* Use LPC prediction gain for adaptive scaling */
/* lpc_gain = sqrt(lpc_pred2refl(lpc,sig2,LPC_ORD));*/
lpc_gain = lpc_pred2refl(lpc,sig2,LPC_ORD);
lpc_gain = sqrt_fxp(lpc_gain,15); /* lpc_gain in Q15 */
#else
/* Original synthesis scaling */
lpc_pred2refl(lpc,sig2,LPC_ORD);
lpc_gain = ONE_Q15;
#endif
if (sig2[1] < 0)
curr_tilt = shr(sig2[1],1); /* curr_tilt in Q15 */
else
curr_tilt = 0;
/* Disable pitch interpolation for high-pitched onsets */
/* if (par->pitch < 0.5*prev_par.pitch &&
par->gain[0] > 6.0 + prev_par.gain[NUM_GAINFR-1]) { */
temp1 = shr(prev_par.pitch,1);
temp2 = (Shortword)SIX_Q8 + prev_par.gain[NUM_GAINFR-1];
compare_nonzero(); compare_nonzero();
if ((par->pitch < temp1) && (par->gain[0] > temp2)) {
/* copy current pitch into previous */
prev_par.pitch = par->pitch;
}
/* Set pulse and noise coefficients based on voicing strengths */
v_zap(curr_pcof,MIX_ORD+1); /* curr_pcof in Q14 */
v_zap(curr_ncof,MIX_ORD+1); /* curr_ncof in Q14 */
for (i = 0; i < NUM_BANDS; i++) {
if (par->bpvc[i] > X05_Q14)
v_add(curr_pcof,&bp_cof[i][0],MIX_ORD+1); /* bp_cof in Q14 */
else
v_add(curr_ncof,&bp_cof[i][0],MIX_ORD+1);
}
/* Process each pitch period */
while (syn_begin < FRAME) {
/* interpolate previous and current parameters */
ifact = divide_s(syn_begin,FRAME); /* ifact in Q15 */
if (syn_begin >= GAINFR) {
gaincnt = 2;
temp1 = sub(syn_begin,GAINFR);
ifact_gain = divide_s(temp1,GAINFR);
}
else {
gaincnt = 1;
ifact_gain = divide_s(syn_begin,GAINFR);
}
/* interpolate gain */
if (gaincnt > 1) {
/* gain = ifact_gain*par->gain[gaincnt-1] +
(1.0-ifact_gain)*par->gain[gaincnt-2]; */
L_temp1 = L_mult(par->gain[gaincnt-1],ifact_gain);
temp1 = sub(ONE_Q15,ifact_gain);
L_temp2 = L_mult(par->gain[gaincnt-2],temp1);
gain = extract_h(L_add(L_temp1,L_temp2)); /* gain in Q8 */
}
else {
/* gain = ifact_gain*par->gain[gaincnt-1] +
(1.0-ifact_gain)*prev_par.gain[NUM_GAINFR-1]; */
L_temp1 = L_mult(par->gain[gaincnt-1],ifact_gain);
temp1 = sub(ONE_Q15,ifact_gain);
L_temp2 = L_mult(prev_par.gain[NUM_GAINFR-1],temp1);
gain = extract_h(L_add(L_temp1,L_temp2)); /* gain in Q8 */
}
/* Set overall interpolation path based on gain change */
temp1 = sub(par->gain[NUM_GAINFR-1],prev_par.gain[NUM_GAINFR-1]);
compare_nonzero();
if (abs_s(temp1) > SIX_Q8) {
/* Power surge: use gain adjusted interpolation */
/* intfact = (gain - prev_par.gain[NUM_GAINFR-1]) / temp; */
temp2 = sub(gain,prev_par.gain[NUM_GAINFR-1]);
if (((temp2 > 0) && (temp1 < 0)) || ((temp2 < 0) && (temp1 > 0)))
intfact = 0;
else {
temp1 = abs_s(temp1);
temp2 = abs_s(temp2);
if (temp2 >= temp1)
intfact = ONE_Q15;
else
intfact = divide_s(temp2,temp1); /* intfact in Q15 */
}
}
else
/* Otherwise, linear interpolation */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -