/* ------------------------------------------------------------------------------ FUNCTION NAME: ec_gain_pitch ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: st = pointer to a pointer to a structure containing code state data of stucture type ec_gain_pitchState state = state of the state machine of type Word16 pOverflow = pointer to overflow indicator of type Flag Outputs: state = pointer to a pointer to a structure containing code state data of stucture type ec_gain_pitchState gain_pitch = pointer to pitch gain (Q14) of type Word16 pOverflow = 1 if there is an overflow else it is zero. Returns: None. Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION This function conceals the error using code gain implementation in this function. ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES ec_gain.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE static const Word16 pdown[7] = { 32767, 32112, 32112, 26214, 9830, 6553, 6553 }; Word16 tmp; // calculate median of last five gains tmp = gmed_n (st->pbuf, 5); // new gain = minimum(median, past_gain) * pdown[state] if (sub (tmp, st->past_gain_pit) > 0) { tmp = st->past_gain_pit; } *gain_pitch = mult (tmp, pdown[state]); ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ void ec_gain_pitch( ec_gain_pitchState *st, /* i/o : state variables */ Word16 state, /* i : state of the state machine */ Word16 *gain_pitch, /* o : pitch gain (Q14) */ Flag *pOverflow ) { static const Word16 pdown[7] = { 32767, 32112, 32112, 26214, 9830, 6553, 6553 }; Word16 tmp; /* calculate median of last five gains */ tmp = gmed_n(st->pbuf, 5); /* new gain = minimum(median, past_gain) * pdown[state] */ if (sub(tmp, st->past_gain_pit, pOverflow) > 0) { tmp = st->past_gain_pit; } *gain_pitch = mult(tmp, pdown[state], pOverflow); }
/* ------------------------------------------------------------------------------ FUNCTION NAME: ec_gain_code ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: st = pointer to a pointer to a structure containing code state data of stucture type ec_gain_codeState pred_state = pointer to MA predictor state of type gc_predState state = state of the state machine of type Word16 gain_code = pointer to decoded innovation gain of type Word16 pOverflow = pointer to overflow indicator of type Flag Outputs: st = pointer to a pointer to a structure containing code state data of stucture type ec_gain_codeState pred_state = pointer to MA predictor state of type gc_predState pOverflow = 1 if there is an overflow else it is zero. Returns: None. Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION This function does error concealment using the codebook. Call this function only in BFI (instead of normal gain decoding function). ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES ec_gain.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE static const Word16 cdown[7] = { 32767, 32112, 32112, 32112, 32112, 32112, 22937 }; Word16 tmp; Word16 qua_ener_MR122; Word16 qua_ener; // calculate median of last five gain values tmp = gmed_n (st->gbuf,5); // new gain = minimum(median, past_gain) * cdown[state] if (sub (tmp, st->past_gain_code) > 0) { tmp = st->past_gain_code; } tmp = mult (tmp, cdown[state]); *gain_code = tmp; // update table of past quantized energies with average of // current values gc_pred_average_limited(pred_state, &qua_ener_MR122, &qua_ener); gc_pred_update(pred_state, qua_ener_MR122, qua_ener); } ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ void ec_gain_code( ec_gain_codeState *st, /* i/o : State struct */ gc_predState *pred_state, /* i/o : MA predictor state */ Word16 state, /* i : state of the state machine */ Word16 *gain_code, /* o : decoded innovation gain */ Flag *pOverflow ) { static const Word16 cdown[7] = { 32767, 32112, 32112, 32112, 32112, 32112, 22937 }; Word16 tmp; Word16 qua_ener_MR122; Word16 qua_ener; /* calculate median of last five gain values */ tmp = gmed_n(st->gbuf, 5); /* new gain = minimum(median, past_gain) * cdown[state] */ if (sub(tmp, st->past_gain_code, pOverflow) > 0) { tmp = st->past_gain_code; } tmp = mult(tmp, cdown[state], pOverflow); *gain_code = tmp; /* update table of past quantized energies with average of * current values */ gc_pred_average_limited(pred_state, &qua_ener_MR122, &qua_ener, pOverflow); gc_pred_update(pred_state, qua_ener_MR122, qua_ener); }
/************************************************************************* * * Function: gain_adapt() * Purpose: calculate pitch/codebook gain adaptation factor alpha * (and update the adaptor state) * ************************************************************************** */ void gain_adapt( GainAdaptState *st, /* i : state struct */ Word16 ltpg, /* i : ltp coding gain (log2()), Q13 */ Word16 gain_cod, /* i : code gain, Q1 */ Word16 *alpha /* o : gain adaptation factor, Q15 */ ) { Word16 adapt; /* adaptdation status; 0, 1, or 2 */ Word16 result; /* alpha factor, Q13 */ Word16 filt; /* median-filtered LTP coding gain, Q13 */ Word16 tmp, i; /* basic adaptation */ if (sub (ltpg, LTP_GAIN_THR1) <= 0) { adapt = 0; } else { if (sub (ltpg, LTP_GAIN_THR2) <= 0) { adapt = 1; } else { adapt = 2; } } /* * // onset indicator * if ((cbGain > onFact * cbGainMem[0]) && (cbGain > 100.0)) * onset = 8; * else * if (onset) * onset--; */ /* tmp = cbGain / onFact; onFact = 2.0; 200 Q1 = 100.0 */ tmp = shr_r (gain_cod, 1); if ((sub (tmp, st->prev_gc) > 0) && sub(gain_cod, 200) > 0) { st->onset = 8; } else { if (st->onset != 0) { st->onset = sub (st->onset, 1); } } /* * // if onset, increase adaptor state * if (onset && (gainAdapt < 2)) gainAdapt++; */ if ((st->onset != 0) && (sub (adapt, 2) < 0)) { adapt = add (adapt, 1); } st->ltpg_mem[0] = ltpg; filt = gmed_n (st->ltpg_mem, 5); /* function result */ if (adapt == 0) { if (sub (filt, 5443) > 0) /* 5443 Q13 = 0.66443... */ { result = 0; } else { if (filt < 0) { result = 16384; /* 16384 Q15 = 0.5 */ } else { /* result = 0.5 - 0.75257499*filt */ /* result (Q15) = 16384 - 24660 * (filt << 2) */ filt = shl (filt, 2); /* Q15 */ result = sub (16384, mult (24660, filt)); } } } else { result = 0; } /* * if (prevAlpha == 0.0) result = 0.5 * (result + prevAlpha); */ if (st->prev_alpha == 0) { result = shr (result, 1); } /* store the result */ *alpha = result; /* update adapter state memory */ st->prev_alpha = result; st->prev_gc = gain_cod; for (i = LTPG_MEM_SIZE-1; i > 0; i--) { st->ltpg_mem[i] = st->ltpg_mem[i-1]; } /* mem[0] is just present for convenience in calling the gmed_n[5] * function above. The memory depth is really LTPG_MEM_SIZE-1. */ }
/* ************************************************************************** * * Function : Bgn_scd * Purpose : Charaterice synthesis speech and detect background noise * Returns : background noise decision; 0 = no bgn, 1 = bgn * ************************************************************************** */ Word16 Bgn_scd (Bgn_scdState *st, /* i : State variables for bgn SCD */ Word16 ltpGainHist[], /* i : LTP gain history */ Word16 speech[], /* o : synthesis speech frame */ Word16 *voicedHangover /* o : # of frames after last voiced frame */ ) { Word16 i; Word16 prevVoiced, inbgNoise; Word16 temp; Word16 ltpLimit, frameEnergyMin; Word16 currEnergy, noiseFloor, maxEnergy, maxEnergyLastPart; Word32 s; /* Update the inBackgroundNoise flag (valid for use in next frame if BFI) */ /* it now works as a energy detector floating on top */ /* not as good as a VAD. */ currEnergy = 0; move16 (); s = (Word32) 0; move32 (); for (i = 0; i < L_FRAME; i++) { s = L_mac (s, speech[i], speech[i]); } s = L_shl(s, 2); currEnergy = extract_h (s); frameEnergyMin = 32767; move16 (); for (i = 0; i < L_ENERGYHIST; i++) { test (); if (sub(st->frameEnergyHist[i], frameEnergyMin) < 0) frameEnergyMin = st->frameEnergyHist[i]; move16 (); } noiseFloor = shl (frameEnergyMin, 4); /* Frame Energy Margin of 16 */ maxEnergy = st->frameEnergyHist[0]; move16 (); for (i = 1; i < L_ENERGYHIST-4; i++) { test (); if ( sub (maxEnergy, st->frameEnergyHist[i]) < 0) { maxEnergy = st->frameEnergyHist[i]; move16 (); } } maxEnergyLastPart = st->frameEnergyHist[2*L_ENERGYHIST/3]; move16 (); for (i = 2*L_ENERGYHIST/3+1; i < L_ENERGYHIST; i++) { test (); if ( sub (maxEnergyLastPart, st->frameEnergyHist[i] ) < 0) { maxEnergyLastPart = st->frameEnergyHist[i]; move16 (); } } inbgNoise = 0; /* false */ move16 (); /* Do not consider silence as noise */ /* Do not consider continuous high volume as noise */ /* Or if the current noise level is very low */ /* Mark as noise if under current noise limit */ /* OR if the maximum energy is below the upper limit */ test (); test (); test (); test (); test (); if ( (sub(maxEnergy, LOWERNOISELIMIT) > 0) && (sub(currEnergy, FRAMEENERGYLIMIT) < 0) && (sub(currEnergy, LOWERNOISELIMIT) > 0) && ( (sub(currEnergy, noiseFloor) < 0) || (sub(maxEnergyLastPart, UPPERNOISELIMIT) < 0))) { test (); if (sub(add(st->bgHangover, 1), 30) > 0) { st->bgHangover = 30; move16 (); } else { st->bgHangover = add(st->bgHangover, 1); } } else { st->bgHangover = 0; move16 (); } /* make final decision about frame state , act somewhat cautiosly */ test (); if (sub(st->bgHangover,1) > 0) inbgNoise = 1; /* true */ move16 (); for (i = 0; i < L_ENERGYHIST-1; i++) { st->frameEnergyHist[i] = st->frameEnergyHist[i+1]; move16 (); } st->frameEnergyHist[L_ENERGYHIST-1] = currEnergy; move16 (); /* prepare for voicing decision; tighten the threshold after some time in noise */ ltpLimit = 13926; /* 0.85 Q14 */ move16 (); test (); if (sub(st->bgHangover, 8) > 0) { ltpLimit = 15565; /* 0.95 Q14 */ move16 (); } test (); if (sub(st->bgHangover, 15) > 0) { ltpLimit = 16383; /* 1.00 Q14 */ move16 (); } /* weak sort of voicing indication. */ prevVoiced = 0; /* false */ move16 (); test (); if (sub(gmed_n(<pGainHist[4], 5), ltpLimit) > 0) { prevVoiced = 1; /* true */ move16 (); } test (); if (sub(st->bgHangover, 20) > 0) { if (sub(gmed_n(ltpGainHist, 9), ltpLimit) > 0) { prevVoiced = 1; /* true */ move16 (); } else { prevVoiced = 0; /* false */ move16 (); } } test (); if (prevVoiced) { *voicedHangover = 0; move16 (); } else { temp = add(*voicedHangover, 1); test (); if (sub(temp, 10) > 0) { *voicedHangover = 10; move16 (); } else { *voicedHangover = temp; move16 (); } } return inbgNoise; }
Word16 Pitch_ol_wgh( /* o : open loop pitch lag */ pitchOLWghtState *st, /* i/o : State struct */ vadState *vadSt, /* i/o : VAD state struct */ Word16 signal[], /* i : signal used to compute the open loop pitch */ /* signal[-pit_max] to signal[-1] should be known */ Word16 pit_min, /* i : minimum pitch lag */ Word16 pit_max, /* i : maximum pitch lag */ Word16 L_frame, /* i : length of frame to compute pitch */ Word16 old_lags[], /* i : history with old stored Cl lags */ Word16 ol_gain_flg[], /* i : OL gain flag */ Word16 idx, /* i : index */ Flag dtx, /* i : dtx flag; use dtx=1, do not use dtx=0 */ Flag *pOverflow /* o : overflow flag */ ) { Word16 i; Word16 max1; Word16 p_max1; Word32 t0; #ifndef VAD2 Word16 corr_hp_max; #endif Word32 corr[PIT_MAX+1], *corr_ptr; /* Scaled signal */ Word16 scaled_signal[PIT_MAX + L_FRAME]; Word16 *scal_sig; scal_sig = &scaled_signal[pit_max]; t0 = 0L; for (i = -pit_max; i < L_frame; i++) { t0 = L_mac(t0, signal[i], signal[i], pOverflow); } /*--------------------------------------------------------* * Scaling of input signal. * * * * if Overflow -> scal_sig[i] = signal[i]>>2 * * else if t0 < 1^22 -> scal_sig[i] = signal[i]<<2 * * else -> scal_sig[i] = signal[i] * *--------------------------------------------------------*/ /*--------------------------------------------------------* * Verification for risk of overflow. * *--------------------------------------------------------*/ /* Test for overflow */ if (L_sub(t0, MAX_32, pOverflow) == 0L) { for (i = -pit_max; i < L_frame; i++) { scal_sig[i] = shr(signal[i], 3, pOverflow); } } else if (L_sub(t0, (Word32) 1048576L, pOverflow) < (Word32) 0) { for (i = -pit_max; i < L_frame; i++) { scal_sig[i] = shl(signal[i], 3, pOverflow); } } else { for (i = -pit_max; i < L_frame; i++) { scal_sig[i] = signal[i]; } } /* calculate all coreelations of scal_sig, from pit_min to pit_max */ corr_ptr = &corr[pit_max]; comp_corr(scal_sig, L_frame, pit_max, pit_min, corr_ptr); p_max1 = Lag_max(vadSt, corr_ptr, scal_sig, L_frame, pit_max, pit_min, st->old_T0_med, &max1, st->wght_flg, &ol_gain_flg[idx], dtx, pOverflow); if (ol_gain_flg[idx] > 0) { /* Calculate 5-point median of previous lags */ for (i = 4; i > 0; i--) /* Shift buffer */ { old_lags[i] = old_lags[i-1]; } old_lags[0] = p_max1; st->old_T0_med = gmed_n(old_lags, 5); st->ada_w = 32767; /* Q15 = 1.0 */ } else { st->old_T0_med = p_max1; /* = ada_w = ada_w * 0.9 */ st->ada_w = mult(st->ada_w, 29491, pOverflow); } if (sub(st->ada_w, 9830, pOverflow) < 0) /* ada_w - 0.3 */ { st->wght_flg = 0; } else { st->wght_flg = 1; } #ifndef VAD2 if (dtx) { /* no test() call since this if is only in simulation env */ if (sub(idx, 1, pOverflow) == 0) { /* calculate max high-passed filtered correlation of all lags */ hp_max(corr_ptr, scal_sig, L_frame, pit_max, pit_min, &corr_hp_max, pOverflow); /* update complex background detector */ vad_complex_detection_update(vadSt, corr_hp_max); } } #endif return (p_max1); }
//============================================================================= //函数名称:Bgn_scd //函数功能: 合成语音和检测背景噪音 //函数返回:背景噪声的决定;"0"表示BGN,"1"表示无BGN //============================================================================= Word16 Bgn_scd(Bgn_scdState *st, /* i : State variables for bgn SCD */ Word16 ltpGainHist[], /* i : LTP gain history */ Word16 speech[], /* o : synthesis speech frame */ Word16 *voicedHangover,/* o : # of frames after last voiced frame */ Flag *pOverflow ) { Word16 i; Word16 prevVoiced, inbgNoise; Word16 temp; Word16 ltpLimit, frameEnergyMin; Word16 currEnergy, noiseFloor, maxEnergy, maxEnergyLastPart; Word32 s, L_temp; /* Update the inBackgroundNoise flag (valid for use in next frame if BFI) */ /* it now works as a energy detector floating on top */ /* not as good as a VAD. */ s = (Word32) 0; for (i = L_FRAME - 1; i >= 0; i--) { L_temp = ((Word32) speech[i]) * speech[i]; if (L_temp != (Word32) 0x40000000L) { L_temp = L_temp << 1; } else { L_temp = MAX_32; } s = L_add(s, L_temp, pOverflow); } /* s is a sum of squares, so don't need to check for neg overflow */ //s是平方和,所以不需要检查负溢出 if (s > (Word32)0x1fffffffL) { currEnergy = MAX_16; } else { currEnergy = (Word16)(s >> 14); } frameEnergyMin = 32767; for (i = L_ENERGYHIST - 1; i >= 0; i--) { if (st->frameEnergyHist[i] < frameEnergyMin) { frameEnergyMin = st->frameEnergyHist[i]; } } /* Frame Energy Margin of 16 */ //16帧的能量裕度 L_temp = (Word32)frameEnergyMin << 4; if (L_temp != (Word32)((Word16) L_temp)) { if (L_temp > 0) { noiseFloor = MAX_16; } else { noiseFloor = MIN_16; } } else { noiseFloor = (Word16)(L_temp); } maxEnergy = st->frameEnergyHist[0]; for (i = L_ENERGYHIST - 5; i >= 1; i--) { if (maxEnergy < st->frameEnergyHist[i]) { maxEnergy = st->frameEnergyHist[i]; } } maxEnergyLastPart = st->frameEnergyHist[2*L_ENERGYHIST/3]; for (i = 2 * L_ENERGYHIST / 3 + 1; i < L_ENERGYHIST; i++) { if (maxEnergyLastPart < st->frameEnergyHist[i]) { maxEnergyLastPart = st->frameEnergyHist[i]; } } /* Do not consider silence as noise */ /* Do not consider continuous high volume as noise */ /* Or if the current noise level is very low */ /* Mark as noise if under current noise limit */ /* OR if the maximum energy is below the upper limit */ if ((maxEnergy > LOWERNOISELIMIT) && (currEnergy < FRAMEENERGYLIMIT) && (currEnergy > LOWERNOISELIMIT) && ((currEnergy < noiseFloor) || (maxEnergyLastPart < UPPERNOISELIMIT))) { if ((st->bgHangover + 1) > 30) { st->bgHangover = 30; } else { st->bgHangover += 1; } } else { st->bgHangover = 0; } /* make final decision about frame state , act somewhat cautiosly */ //作出关于帧状态最终决定,行动有些谨慎 if (st->bgHangover > 1) { inbgNoise = TRUE; } else { inbgNoise = FALSE; } for (i = 0; i < L_ENERGYHIST - 1; i++) { st->frameEnergyHist[i] = st->frameEnergyHist[i+1]; } st->frameEnergyHist[L_ENERGYHIST-1] = currEnergy; /* prepare for voicing decision; tighten the threshold after some time in noise */ //对于清浊决定做准备;后噪声一段时间收紧门槛 if (st->bgHangover > 15) { ltpLimit = 16383; /* 1.00 Q14 */ } else if (st->bgHangover > 8) { ltpLimit = 15565; /* 0.95 Q14 */ } else { ltpLimit = 13926; /* 0.85 Q14 */ } /* weak sort of voicing indication. */ //弱排序清浊指示 prevVoiced = FALSE; if (gmed_n(<pGainHist[4], 5) > ltpLimit) { prevVoiced = TRUE; } if (st->bgHangover > 20) { if (gmed_n(ltpGainHist, 9) > ltpLimit) { prevVoiced = TRUE; } else { prevVoiced = FALSE; } } if (prevVoiced) { *voicedHangover = 0; } else { temp = *voicedHangover + 1; if (temp > 10) { *voicedHangover = 10; } else { *voicedHangover = temp; } } return(inbgNoise); }