FreeCalypso > hg > gsm-codec-lib
view libtwamr/vad1.c @ 581:e2d5cad04cbf
libgsmhr1 RxFE: store CN R0+LPC separately from speech
In the original GSM 06.06 code the ECU for speech mode is entirely
separate from the CN generator, maintaining separate state. (The
main intertie between them is the speech vs CN state variable,
distinguishing between speech and CN BFIs, in addition to the
CN-specific function of distinguishing between initial and update
SIDs.)
In the present RxFE implementation I initially thought that we could
use the same saved_frame buffer for both ECU and CN, overwriting
just the first 4 params (R0 and LPC) when a valid SID comes in.
However, I now realize it was a bad idea: the original code has a
corner case (long sequence of speech-mode BFIs to put the ECU in
state 6, then SID and CN-mode BFIs, then a good speech frame) that
would be broken by that buffer reuse approach. We could eliminate
this corner case by resetting the ECU state when passing through
a CN insertion period, but doing so would needlessly increase
the behavioral diffs between GSM 06.06 and our version.
Solution: use a separate CN-specific buffer for CN R0+LPC parameters,
and match the behavior of GSM 06.06 code in this regard.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 13 Feb 2025 10:02:45 +0000 |
parents | 8847c1740e78 |
children |
line wrap: on
line source
/* ***************************************************************************** **-------------------------------------------------------------------------** ** ** ** GSM AMR-NB speech codec R98 Version 7.6.0 December 12, 2001 ** ** R99 Version 3.3.0 ** ** REL-4 Version 4.1.0 ** ** ** **-------------------------------------------------------------------------** ***************************************************************************** * * File : vad1.c * Purpose : Voice Activity Detection (VAD) for AMR (option 1) * ***************************************************************************** */ /* ***************************************************************************** * MODULE INCLUDE FILE AND VERSION ID ***************************************************************************** */ #include "namespace.h" #include "vad1.h" /* ***************************************************************************** * INCLUDE FILES ***************************************************************************** */ #include "typedef.h" #include "basic_op.h" #include "no_count.h" #include "oper_32b.h" #include "cnst_vad.h" /* ***************************************************************************** * LOCAL VARIABLES AND TABLES ***************************************************************************** */ /* ******************************************************************************** * PRIVATE PROGRAM CODE ******************************************************************************** */ /**************************************************************************** * * Function : first_filter_stage * Purpose : Scale input down by one bit. Calculate 5th order * half-band lowpass/highpass filter pair with * decimation. * ***************************************************************************/ static void first_filter_stage(Word16 in[], /* i : input signal */ Word16 out[], /* o : output values, every other */ /* output is low-pass part and */ /* other is high-pass part every */ Word16 data[] /* i/o : filter memory */ ) { Word16 temp0, temp1, temp2, temp3, i; Word16 data0, data1; data0 = data[0]; move16 (); data1 = data[1]; move16 (); for (i = 0; i < FRAME_LEN/4; i++) { temp0 = sub(shr(in[4*i+0], 2), mult(COEFF5_1, data0)); temp1 = add(data0, mult(COEFF5_1, temp0)); temp3 = sub(shr(in[4*i+1], 2), mult(COEFF5_2, data1)); temp2 = add(data1, mult(COEFF5_2, temp3)); out[4*i+0] = add(temp1, temp2); move16 (); out[4*i+1] = sub(temp1, temp2); move16 (); data0 = sub(shr(in[4*i+2], 2), mult(COEFF5_1, temp0)); temp1 = add(temp0, mult(COEFF5_1, data0)); data1 = sub(shr(in[4*i+3], 2), mult(COEFF5_2, temp3)); temp2 = add(temp3, mult(COEFF5_2, data1)); out[4*i+2] = add(temp1, temp2); move16 (); out[4*i+3] = sub(temp1, temp2); move16 (); } data[0] = data0; move16 (); data[1] = data1; move16 (); } /**************************************************************************** * * Function : filter5 * Purpose : Fifth-order half-band lowpass/highpass filter pair with * decimation. * ***************************************************************************/ static void filter5(Word16 *in0, /* i/o : input values; output low-pass part */ Word16 *in1, /* i/o : input values; output high-pass part */ Word16 data[] /* i/o : updated filter memory */ ) { Word16 temp0, temp1, temp2; temp0 = sub(*in0, mult(COEFF5_1, data[0])); temp1 = add(data[0], mult(COEFF5_1, temp0)); data[0] = temp0; move16 (); temp0 = sub(*in1, mult(COEFF5_2, data[1])); temp2 = add(data[1], mult(COEFF5_2, temp0)); data[1] = temp0; move16 (); *in0 = shr(add(temp1, temp2), 1); move16 (); *in1 = shr(sub(temp1, temp2), 1); move16 (); } /**************************************************************************** * * Function : filter3 * Purpose : Third-order half-band lowpass/highpass filter pair with * decimation. * Return value : * ***************************************************************************/ static void filter3(Word16 *in0, /* i/o : input values; output low-pass part */ Word16 *in1, /* i/o : input values; output high-pass part */ Word16 *data /* i/o : updated filter memory */ ) { Word16 temp1, temp2; temp1 = sub(*in1, mult(COEFF3, *data)); temp2 = add(*data, mult(COEFF3, temp1)); *data = temp1; move16 (); *in1 = shr(sub(*in0, temp2), 1); move16 (); *in0 = shr(add(*in0, temp2), 1); move16 (); } /**************************************************************************** * * Function : level_calculation * Purpose : Calculate signal level in a sub-band. Level is calculated * by summing absolute values of the input data. * Return value : signal level * ***************************************************************************/ static Word16 level_calculation( Word16 data[], /* i : signal buffer */ Word16 *sub_level, /* i : level calculate at the end of the previous frame */ /* o : level of signal calculated from the last */ /* (count2 - count1) samples */ Word16 count1, /* i : number of samples to be counted */ Word16 count2, /* i : number of samples to be counted */ Word16 ind_m, /* i : step size for the index of the data buffer */ Word16 ind_a, /* i : starting index of the data buffer */ Word16 scale /* i : scaling for the level calculation */ ) { Word32 l_temp1, l_temp2; Word16 level, i; l_temp1 = 0L; move32 (); for (i = count1; i < count2; i++) { l_temp1 = L_mac(l_temp1, 1, abs_s(data[ind_m*i+ind_a])); } l_temp2 = L_add(l_temp1, L_shl(*sub_level, sub(16, scale))); *sub_level = extract_h(L_shl(l_temp1, scale)); for (i = 0; i < count1; i++) { l_temp2 = L_mac(l_temp2, 1, abs_s(data[ind_m*i+ind_a])); } level = extract_h(L_shl(l_temp2, scale)); return level; } /**************************************************************************** * * Function : filter_bank * Purpose : Divides input signal into 9-bands and calculas level of * the signal in each band * ***************************************************************************/ static void filter_bank(vadState1 *st, /* i/o : State struct */ Word16 in[], /* i : input frame */ Word16 level[] /* 0 : signal levels at each band */ ) { Word16 i; Word16 tmp_buf[FRAME_LEN]; /* calculate the filter bank */ first_filter_stage(in, tmp_buf, st->a_data5[0]); for (i = 0; i < FRAME_LEN/4; i++) { filter5(&tmp_buf[4*i], &tmp_buf[4*i+2], st->a_data5[1]); filter5(&tmp_buf[4*i+1], &tmp_buf[4*i+3], st->a_data5[2]); } for (i = 0; i < FRAME_LEN/8; i++) { filter3(&tmp_buf[8*i+0], &tmp_buf[8*i+4], &st->a_data3[0]); filter3(&tmp_buf[8*i+2], &tmp_buf[8*i+6], &st->a_data3[1]); filter3(&tmp_buf[8*i+3], &tmp_buf[8*i+7], &st->a_data3[4]); } for (i = 0; i < FRAME_LEN/16; i++) { filter3(&tmp_buf[16*i+0], &tmp_buf[16*i+8], &st->a_data3[2]); filter3(&tmp_buf[16*i+4], &tmp_buf[16*i+12], &st->a_data3[3]); } /* calculate levels in each frequency band */ /* 3000 - 4000 Hz*/ level[8] = level_calculation(tmp_buf, &st->sub_level[8], FRAME_LEN/4-8, FRAME_LEN/4, 4, 1, 15); move16 (); /* 2500 - 3000 Hz*/ level[7] = level_calculation(tmp_buf, &st->sub_level[7], FRAME_LEN/8-4, FRAME_LEN/8, 8, 7, 16); move16 (); /* 2000 - 2500 Hz*/ level[6] = level_calculation(tmp_buf, &st->sub_level[6], FRAME_LEN/8-4, FRAME_LEN/8, 8, 3, 16); move16 (); /* 1500 - 2000 Hz*/ level[5] = level_calculation(tmp_buf, &st->sub_level[5], FRAME_LEN/8-4, FRAME_LEN/8, 8, 2, 16); move16 (); /* 1000 - 1500 Hz*/ level[4] = level_calculation(tmp_buf, &st->sub_level[4], FRAME_LEN/8-4, FRAME_LEN/8, 8, 6, 16); move16 (); /* 750 - 1000 Hz*/ level[3] = level_calculation(tmp_buf, &st->sub_level[3], FRAME_LEN/16-2, FRAME_LEN/16, 16, 4, 16); move16 (); /* 500 - 750 Hz*/ level[2] = level_calculation(tmp_buf, &st->sub_level[2], FRAME_LEN/16-2, FRAME_LEN/16, 16, 12, 16); move16 (); /* 250 - 500 Hz*/ level[1] = level_calculation(tmp_buf, &st->sub_level[1], FRAME_LEN/16-2, FRAME_LEN/16, 16, 8, 16); move16 (); /* 0 - 250 Hz*/ level[0] = level_calculation(tmp_buf, &st->sub_level[0], FRAME_LEN/16-2, FRAME_LEN/16, 16, 0, 16); move16 (); } /**************************************************************************** * * Function : update_cntrl * Purpose : Control update of the background noise estimate. * Inputs : pitch: flags for pitch detection * stat_count: stationary counter * tone: flags indicating presence of a tone * complex: flags for complex detection * vadreg: intermediate VAD flags * Output : stat_count: stationary counter * ***************************************************************************/ static void update_cntrl(vadState1 *st, /* i/o : State struct */ Word16 level[] /* i : sub-band levels of the input frame */ ) { Word16 i, temp, stat_rat, exp; Word16 num, denom; Word16 alpha; /* handle highband complex signal input separately */ /* if ther has been highband correlation for some time */ /* make sure that the VAD update speed is low for a while */ test (); if (st->complex_warning != 0) { test (); if (sub(st->stat_count, CAD_MIN_STAT_COUNT) < 0) { st->stat_count = CAD_MIN_STAT_COUNT; move16 (); } } /* NB stat_count is allowed to be decreased by one below again */ /* deadlock in speech is not possible unless the signal is very */ /* complex and need a high rate */ /* if fullband pitch or tone have been detected for a while, initialize stat_count */ logic16 (); test (); logic16 (); test (); if ((sub((st->pitch & 0x6000), 0x6000) == 0) || (sub((st->tone & 0x7c00), 0x7c00) == 0)) { st->stat_count = STAT_COUNT; move16 (); } else { /* if 8 last vad-decisions have been "0", reinitialize stat_count */ logic16 (); test (); if ((st->vadreg & 0x7f80) == 0) { st->stat_count = STAT_COUNT; move16 (); } else { stat_rat = 0; move16 (); for (i = 0; i < COMPLEN; i++) { test (); if (sub(level[i], st->ave_level[i]) > 0) { num = level[i]; move16 (); denom = st->ave_level[i]; move16 (); } else { num = st->ave_level[i]; move16 (); denom = level[i]; move16 (); } /* Limit nimimum value of num and denom to STAT_THR_LEVEL */ test (); if (sub(num, STAT_THR_LEVEL) < 0) { num = STAT_THR_LEVEL; move16 (); } test (); if (sub(denom, STAT_THR_LEVEL) < 0) { denom = STAT_THR_LEVEL; move16 (); } exp = norm_s(denom); denom = shl(denom, exp); /* stat_rat = num/denom * 64 */ temp = div_s(shr(num, 1), denom); stat_rat = add(stat_rat, shr(temp, sub(8, exp))); } /* compare stat_rat with a threshold and update stat_count */ test (); if (sub(stat_rat, STAT_THR) > 0) { st->stat_count = STAT_COUNT; move16 (); } else { logic16 ();test (); if ((st->vadreg & 0x4000) != 0) { test (); if (st->stat_count != 0) { st->stat_count = sub(st->stat_count, 1); move16 (); } } } } } /* Update average amplitude estimate for stationarity estimation */ alpha = ALPHA4; move16 (); test (); if (sub(st->stat_count, STAT_COUNT) == 0) { alpha = 32767; move16 (); } else if ((st->vadreg & 0x4000) == 0) { logic16 (); test (); alpha = ALPHA5; move16 (); } for (i = 0; i < COMPLEN; i++) { st->ave_level[i] = add(st->ave_level[i], mult_r(alpha, sub(level[i], st->ave_level[i]))); move16 (); } } /**************************************************************************** * * Function : hangover_addition * Purpose : Add hangover for complex signal or after speech bursts * Inputs : burst_count: counter for the length of speech bursts * hang_count: hangover counter * vadreg: intermediate VAD decision * Outputs : burst_count: counter for the length of speech bursts * hang_count: hangover counter * Return value : VAD_flag indicating final VAD decision * ***************************************************************************/ static Word16 hangover_addition( vadState1 *st, /* i/o : State struct */ Word16 noise_level, /* i : average level of the noise */ /* estimates */ Word16 low_power /* i : flag power of the input frame */ ) { Word16 hang_len, burst_len; /* Calculate burst_len and hang_len burst_len: number of consecutive intermediate vad flags with "1"-decision required for hangover addition hang_len: length of the hangover */ test (); if (sub(noise_level, HANG_NOISE_THR) > 0) { burst_len = BURST_LEN_HIGH_NOISE; move16 (); hang_len = HANG_LEN_HIGH_NOISE; move16 (); } else { burst_len = BURST_LEN_LOW_NOISE; move16 (); hang_len = HANG_LEN_LOW_NOISE; move16 (); } /* if the input power (pow_sum) is lower than a threshold, clear counters and set VAD_flag to "0" "fast exit" */ test (); if (low_power != 0) { st->burst_count = 0; move16 (); st->hang_count = 0; move16 (); st->complex_hang_count = 0; move16 (); st->complex_hang_timer = 0; move16 (); return 0; } test (); if (sub(st->complex_hang_timer, CVAD_HANG_LIMIT) > 0) { test (); if (sub(st->complex_hang_count, CVAD_HANG_LENGTH) < 0) { st->complex_hang_count = CVAD_HANG_LENGTH; move16 (); } } /* long time very complex signal override VAD output function */ test (); if (st->complex_hang_count != 0) { st->burst_count = BURST_LEN_HIGH_NOISE; move16 (); st->complex_hang_count = sub(st->complex_hang_count, 1); move16 (); return 1; } else { /* let hp_corr work in from a noise_period indicated by the VAD */ test (); test (); logic16 (); if (((st->vadreg & 0x3ff0) == 0) && (sub(st->corr_hp_fast, CVAD_THRESH_IN_NOISE) > 0)) { return 1; } } /* update the counters (hang_count, burst_count) */ logic16 (); test (); if ((st->vadreg & 0x4000) != 0) { st->burst_count = add(st->burst_count, 1); move16 (); test (); if (sub(st->burst_count, burst_len) >= 0) { st->hang_count = hang_len; move16 (); } return 1; } else { st->burst_count = 0; move16 (); test (); if (st->hang_count > 0) { st->hang_count = sub(st->hang_count, 1); move16 (); return 1; } } return 0; } /**************************************************************************** * * Function : noise_estimate_update * Purpose : Update of background noise estimate * Inputs : bckr_est: background noise estimate * pitch: flags for pitch detection * stat_count: stationary counter * Outputs : bckr_est: background noise estimate * ***************************************************************************/ static void noise_estimate_update( vadState1 *st, /* i/o : State struct */ Word16 level[] /* i : sub-band levels of the input frame */ ) { Word16 i, alpha_up, alpha_down, bckr_add; /* Control update of bckr_est[] */ update_cntrl(st, level); /* Choose update speed */ bckr_add = 2; move16 (); logic16 (); test (); logic16 (); test (); test (); if (((0x7800 & st->vadreg) == 0) && ((st->pitch & 0x7800) == 0) && (st->complex_hang_count == 0)) { alpha_up = ALPHA_UP1; move16 (); alpha_down = ALPHA_DOWN1; move16 (); } else { test (); test (); if ((st->stat_count == 0) && (st->complex_hang_count == 0)) { alpha_up = ALPHA_UP2; move16 (); alpha_down = ALPHA_DOWN2; move16 (); } else { alpha_up = 0; move16 (); alpha_down = ALPHA3; move16 (); bckr_add = 0; move16 (); } } /* Update noise estimate (bckr_est) */ for (i = 0; i < COMPLEN; i++) { Word16 temp; temp = sub(st->old_level[i], st->bckr_est[i]); test (); if (temp < 0) { /* update downwards*/ st->bckr_est[i] = add(-2, add(st->bckr_est[i], mult_r(alpha_down, temp))); move16 (); /* limit minimum value of the noise estimate to NOISE_MIN */ test (); if (sub(st->bckr_est[i], NOISE_MIN) < 0) { st->bckr_est[i] = NOISE_MIN; move16 (); } } else { /* update upwards */ st->bckr_est[i] = add(bckr_add, add(st->bckr_est[i], mult_r(alpha_up, temp))); move16 (); /* limit maximum value of the noise estimate to NOISE_MAX */ test (); if (sub(st->bckr_est[i], NOISE_MAX) > 0) { st->bckr_est[i] = NOISE_MAX; move16 (); } } } /* Update signal levels of the previous frame (old_level) */ for(i = 0; i < COMPLEN; i++) { st->old_level[i] = level[i]; move16 (); } } /**************************************************************************** * * Function : complex_estimate_adapt * Purpose : Update/adapt of complex signal estimate * Inputs : low_power: low signal power flag * Outputs : st->corr_hp_fast: long term complex signal estimate * ***************************************************************************/ static void complex_estimate_adapt( vadState1 *st, /* i/o : VAD state struct */ Word16 low_power /* i : very low level flag of the input frame */ ) { Word16 alpha; /* Q15 */ Word32 L_tmp; /* Q31 */ /* adapt speed on own state */ test (); if (sub(st->best_corr_hp, st->corr_hp_fast) < 0) /* decrease */ { test (); if (sub(st->corr_hp_fast, CVAD_THRESH_ADAPT_HIGH) < 0) { /* low state */ alpha = CVAD_ADAPT_FAST; move16(); } else { /* high state */ alpha = CVAD_ADAPT_REALLY_FAST; move16(); } } else /* increase */ { test (); if (sub(st->corr_hp_fast, CVAD_THRESH_ADAPT_HIGH) < 0) { alpha = CVAD_ADAPT_FAST; move16(); } else { alpha = CVAD_ADAPT_SLOW; move16(); } } L_tmp = L_deposit_h(st->corr_hp_fast); L_tmp = L_msu(L_tmp, alpha, st->corr_hp_fast); L_tmp = L_mac(L_tmp, alpha, st->best_corr_hp); st->corr_hp_fast = round(L_tmp); /* Q15 */ move16(); test (); if (sub(st->corr_hp_fast, CVAD_MIN_CORR) < 0) { st->corr_hp_fast = CVAD_MIN_CORR; move16(); } test (); if (low_power != 0) { st->corr_hp_fast = CVAD_MIN_CORR; move16(); } } /**************************************************************************** * * Function : complex_vad * Purpose : complex background decision * Return value : the complex background decision * ***************************************************************************/ static Word16 complex_vad(vadState1 *st, /* i/o : VAD state struct */ Word16 low_power /* i : flag power of the input frame */ ) { st->complex_high = shr(st->complex_high, 1); move16 (); st->complex_low = shr(st->complex_low, 1); move16 (); test (); if (low_power == 0) { test (); if (sub(st->corr_hp_fast, CVAD_THRESH_ADAPT_HIGH) > 0) { st->complex_high = st->complex_high | 0x4000; logic16 (); move16 (); } test (); if (sub(st->corr_hp_fast, CVAD_THRESH_ADAPT_LOW) > 0 ) { st->complex_low = st->complex_low | 0x4000; logic16 (); move16 (); } } test (); if (sub(st->corr_hp_fast, CVAD_THRESH_HANG) > 0) { st->complex_hang_timer = add(st->complex_hang_timer, 1); move16 (); } else { st->complex_hang_timer = 0; move16 (); } test (); logic16 (); test (); logic16 (); return ((sub((st->complex_high & 0x7f80), 0x7f80) == 0) || (sub((st->complex_low & 0x7fff), 0x7fff) == 0)); } /**************************************************************************** * * Function : vad_decision * Purpose : Calculates VAD_flag * Inputs : bckr_est: background noise estimate * vadreg: intermediate VAD flags * Outputs : noise_level: average level of the noise estimates * vadreg: intermediate VAD flags * Return value : VAD_flag * ***************************************************************************/ static Word16 vad_decision( vadState1 *st, /* i/o : State struct */ Word16 level[COMPLEN], /* i : sub-band levels of the input frame */ Word32 pow_sum /* i : power of the input frame */ ) { Word16 i; Word16 snr_sum; Word32 L_temp; Word16 vad_thr, temp, noise_level; Word16 low_power_flag; /* Calculate squared sum of the input levels (level) divided by the background noise components (bckr_est). */ L_temp = 0; move32(); for (i = 0; i < COMPLEN; i++) { Word16 exp; exp = norm_s(st->bckr_est[i]); temp = shl(st->bckr_est[i], exp); temp = div_s(shr(level[i], 1), temp); temp = shl(temp, sub(exp, UNIRSHFT-1)); L_temp = L_mac(L_temp, temp, temp); } snr_sum = extract_h(L_shl(L_temp, 6)); snr_sum = mult(snr_sum, INV_COMPLEN); /* Calculate average level of estimated background noise */ L_temp = 0; move32(); for (i = 0; i < COMPLEN; i++) { L_temp = L_add(L_temp, st->bckr_est[i]); } noise_level = extract_h(L_shl(L_temp, 13)); /* Calculate VAD threshold */ vad_thr = add(mult(VAD_SLOPE, sub(noise_level, VAD_P1)), VAD_THR_HIGH); test (); if (sub(vad_thr, VAD_THR_LOW) < 0) { vad_thr = VAD_THR_LOW; move16 (); } /* Shift VAD decision register */ st->vadreg = shr(st->vadreg, 1); move16 (); /* Make intermediate VAD decision */ test (); if (sub(snr_sum, vad_thr) > 0) { st->vadreg = st->vadreg | 0x4000; logic16 (); move16 (); } /* primary vad decsion made */ /* check if the input power (pow_sum) is lower than a threshold" */ test (); if (L_sub(pow_sum, VAD_POW_LOW) < 0) { low_power_flag = 1; move16 (); } else { low_power_flag = 0; move16 (); } /* update complex signal estimate st->corr_hp_fast and hangover reset timer using */ /* low_power_flag and corr_hp_fast and various adaptation speeds */ complex_estimate_adapt(st, low_power_flag); /* check multiple thresholds of the st->corr_hp_fast value */ st->complex_warning = complex_vad(st, low_power_flag); move16(); /* Update speech subband vad background noise estimates */ noise_estimate_update(st, level); /* Add speech and complex hangover and return speech VAD_flag */ /* long term complex hangover may be added */ st->speech_vad_decision = hangover_addition(st, noise_level, low_power_flag); move16 (); return (st->speech_vad_decision); } /* ***************************************************************************** * PUBLIC PROGRAM CODE ***************************************************************************** */ /************************************************************************* * * Function: vad1_reset * Purpose: Initializes state memory to zero * ************************************************************************** */ void vad1_reset (vadState1 *state) { Word16 i, j; /* Initialize pitch detection variables */ state->oldlag_count = 0; state->oldlag = 0; state->pitch = 0; state->tone = 0; state->complex_high = 0; state->complex_low = 0; state->complex_hang_timer = 0; state->vadreg = 0; state->stat_count = 0; state->burst_count = 0; state->hang_count = 0; state->complex_hang_count = 0; /* initialize memory used by the filter bank */ for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) { state->a_data5[i][j] = 0; } } for (i = 0; i < 5; i++) { state->a_data3[i] = 0; } /* initialize the rest of the memory */ for (i = 0; i < COMPLEN; i++) { state->bckr_est[i] = NOISE_INIT; state->old_level[i] = NOISE_INIT; state->ave_level[i] = NOISE_INIT; state->sub_level[i] = 0; } state->best_corr_hp = CVAD_LOWPOW_RESET; state->speech_vad_decision = 0; state->complex_warning = 0; state->sp_burst_count = 0; state->corr_hp_fast = CVAD_LOWPOW_RESET; } /**************************************************************************** * * Function : vad_complex_detection_update * Purpose : update vad->bestCorr_hp complex signal feature state * ***************************************************************************/ void vad_complex_detection_update (vadState1 *st, /* i/o : State struct */ Word16 best_corr_hp /* i : best Corr */ ) { st->best_corr_hp = best_corr_hp; move16(); } /**************************************************************************** * * Function : vad_tone_detection * Purpose : Set tone flag if pitch gain is high. This is used to detect * signaling tones and other signals with high pitch gain. * Inputs : tone: flags indicating presence of a tone * Outputs : tone: flags indicating presence of a tone * ***************************************************************************/ void vad_tone_detection (vadState1 *st, /* i/o : State struct */ Word32 t0, /* i : autocorrelation maxima */ Word32 t1 /* i : energy */ ) { Word16 temp; /* if (t0 > TONE_THR * t1) set tone flag */ temp = round(t1); test (); test (); if ((temp > 0) && (L_msu(t0, temp, TONE_THR) > 0)) { st->tone = st->tone | 0x4000; logic16 (); move16 (); } } /**************************************************************************** * * Function : vad_tone_detection_update * Purpose : Update the tone flag register. Tone flags are shifted right * by one bit. This function should be called from the speech * encoder before call to Vad_tone_detection() function. * ***************************************************************************/ void vad_tone_detection_update ( vadState1 *st, /* i/o : State struct */ Word16 one_lag_per_frame /* i : 1 if one open-loop lag is calculated per each frame, otherwise 0 */ ) { /* Shift tone flags right by one bit */ st->tone = shr(st->tone, 1); move16 (); /* If open-loop lag is calculated only once in each frame, do extra update and assume that the other tone flag of the frame is one. */ if (one_lag_per_frame != 0) { st->tone = shr(st->tone, 1); st->tone = st->tone | 0x2000; logic16 (); move16 (); } } /**************************************************************************** * * Function : vad_pitch_detection * Purpose : Test whether signal contains pitch or other periodic * component. * Return value : Boolean voiced / unvoiced decision in state variable * ***************************************************************************/ void vad_pitch_detection (vadState1 *st, /* i/o : State struct */ Word16 T_op[] /* i : speech encoder open loop lags */ ) { Word16 lagcount, i; lagcount = 0; move16 (); for (i = 0; i < 2; i++) { test (); if (sub (abs_s (sub (st->oldlag, T_op[i])), LTHRESH) < 0) { lagcount = add (lagcount, 1); } /* Save the current LTP lag */ st->oldlag = T_op[i]; move16 (); } /* Make pitch decision. Save flag of the pitch detection to the variable pitch. */ st->pitch = shr(st->pitch, 1); move16(); test (); if (sub ( add (st->oldlag_count, lagcount), NTHRESH) >= 0) { st->pitch = st->pitch | 0x4000; logic16(); move16(); } /* Update oldlagcount */ st->oldlag_count = lagcount; move16 (); } /**************************************************************************** * * Function : vad * Purpose : Main program for Voice Activity Detection (VAD) for AMR * Return value : VAD Decision, 1 = speech, 0 = noise * ***************************************************************************/ Word16 vad1(vadState1 *st, /* i/o : State struct */ Word16 in_buf[] /* i : samples of the input frame */ ) { Word16 level[COMPLEN]; Word32 pow_sum; Word16 i; /* Calculate power of the input frame. */ pow_sum = 0L; move32 (); for (i = 0; i < FRAME_LEN; i++) { pow_sum = L_mac(pow_sum, in_buf[i-LOOKAHEAD], in_buf[i-LOOKAHEAD]); } /* If input power is very low, clear pitch flag of the current frame */ test (); if (L_sub(pow_sum, POW_PITCH_THR) < 0) { st->pitch = st->pitch & 0x3fff; logic16 (); move16 (); } /* If input power is very low, clear complex flag of the "current" frame */ test (); if (L_sub(pow_sum, POW_COMPLEX_THR) < 0) { st->complex_low = st->complex_low & 0x3fff; logic16 (); move16 (); } /* Run the filter bank which calculates signal levels at each band */ filter_bank(st, in_buf, level); return (vad_decision(st, level, pow_sum)); }