void bw_lpc(spx_word16_t gamma, const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order) { int i; spx_word16_t tmp=gamma; lpc_out[0] = lpc_in[0]; for (i=1;i<order+1;i++) { lpc_out[i] = MULT16_16_P15(tmp,lpc_in[i]); tmp = MULT16_16_P15(tmp, gamma); } }
static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) { /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation but I know it's MMSE-optimal on a sinc */ spx_word16_t x2, x3; x2 = MULT16_16_P15(x, x); x3 = MULT16_16_P15(x, x2); interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); /* Just to make sure we don't have rounding problems */ interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; if (interp[2]<32767) interp[2]+=1; }
static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) { void *silk_dec; CELTDecoder *celt_dec; int i, silk_ret=0, celt_ret=0; ec_dec dec; opus_int32 silk_frame_size; int pcm_silk_size; VARDECL(opus_int16, pcm_silk); int pcm_transition_silk_size; VARDECL(opus_val16, pcm_transition_silk); int pcm_transition_celt_size; VARDECL(opus_val16, pcm_transition_celt); opus_val16 *pcm_transition=NULL; int redundant_audio_size; VARDECL(opus_val16, redundant_audio); int audiosize; int mode; int transition=0; int start_band; int redundancy=0; int redundancy_bytes = 0; int celt_to_silk=0; int c; int F2_5, F5, F10, F20; const opus_val16 *window; opus_uint32 redundant_rng = 0; int celt_accum; ALLOC_STACK; silk_dec = (char*)st+st->silk_dec_offset; celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); F20 = st->Fs/50; F10 = F20>>1; F5 = F10>>1; F2_5 = F5>>1; if (frame_size < F2_5) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } /* Limit frame_size to avoid excessive stack allocations. */ frame_size = IMIN(frame_size, st->Fs/25*3); /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ if (len<=1) { data = NULL; /* In that case, don't conceal more than what the ToC says */ frame_size = IMIN(frame_size, st->frame_size); } if (data != NULL) { audiosize = st->frame_size; mode = st->mode; ec_dec_init(&dec,(unsigned char*)data,len); } else { audiosize = frame_size; mode = st->prev_mode; if (mode == 0) { /* If we haven't got any packet yet, all we can do is return zeros */ for (i=0; i<audiosize*st->channels; i++) pcm[i] = 0; RESTORE_STACK; return audiosize; } /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), 10, or 20 (e.g. 12.5 or 30 ms). */ if (audiosize > F20) { do { int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); if (ret<0) { RESTORE_STACK; return ret; } pcm += ret*st->channels; audiosize -= ret; } while (audiosize > 0); RESTORE_STACK; return frame_size; } else if (audiosize < F20) { if (audiosize > F10) audiosize = F10; else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) audiosize = F5; } } /* In fixed-point, we can tell CELT to do the accumulation on top of the SILK PCM buffer. This saves some stack space. */ #ifdef FIXED_POINT celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); #else celt_accum = 0; #endif pcm_transition_silk_size = ALLOC_NONE; pcm_transition_celt_size = ALLOC_NONE; if (data!=NULL && st->prev_mode > 0 && ( (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) ) { transition = 1; /* Decide where to allocate the stack memory for pcm_transition */ if (mode == MODE_CELT_ONLY) pcm_transition_celt_size = F5*st->channels; else pcm_transition_silk_size = F5*st->channels; } ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); if (transition && mode == MODE_CELT_ONLY) { pcm_transition = pcm_transition_celt; opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); } if (audiosize > frame_size) { /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ RESTORE_STACK; return OPUS_BAD_ARG; } else { frame_size = audiosize; } /* Don't allocate any memory when in CELT-only mode */ pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; ALLOC(pcm_silk, pcm_silk_size, opus_int16); /* SILK processing */ if (mode != MODE_CELT_ONLY) { int lost_flag, decoded_samples; opus_int16 *pcm_ptr; #ifdef FIXED_POINT if (celt_accum) pcm_ptr = pcm; else #endif pcm_ptr = pcm_silk; if (st->prev_mode==MODE_CELT_ONLY) silk_InitDecoder( silk_dec ); /* The SILK PLC cannot produce frames of less than 10 ms */ st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); if (data != NULL) { st->DecControl.nChannelsInternal = st->stream_channels; if( mode == MODE_SILK_ONLY ) { if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { st->DecControl.internalSampleRate = 8000; } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { st->DecControl.internalSampleRate = 12000; } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { st->DecControl.internalSampleRate = 16000; } else { st->DecControl.internalSampleRate = 16000; silk_assert( 0 ); } } else { /* Hybrid mode */ st->DecControl.internalSampleRate = 16000; } } lost_flag = data == NULL ? 1 : 2 * decode_fec; decoded_samples = 0; do { /* Call SILK decoder */ int first_frame = decoded_samples == 0; silk_ret = silk_Decode( silk_dec, &st->DecControl, lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size ); if( silk_ret ) { if (lost_flag) { /* PLC failure should not be fatal */ silk_frame_size = frame_size; for (i=0; i<frame_size*st->channels; i++) pcm_ptr[i] = 0; } else { RESTORE_STACK; return OPUS_INTERNAL_ERROR; } } pcm_ptr += silk_frame_size * st->channels; decoded_samples += silk_frame_size; } while( decoded_samples < frame_size ); } start_band = 0; if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) { /* Check if we have a redundant 0-8 kHz band */ if (mode == MODE_HYBRID) redundancy = ec_dec_bit_logp(&dec, 12); else redundancy = 1; if (redundancy) { celt_to_silk = ec_dec_bit_logp(&dec, 1); /* redundancy_bytes will be at least two, in the non-hybrid case due to the ec_tell() check above */ redundancy_bytes = mode==MODE_HYBRID ? (opus_int32)ec_dec_uint(&dec, 256)+2 : len-((ec_tell(&dec)+7)>>3); len -= redundancy_bytes; /* This is a sanity check. It should never happen for a valid packet, so the exact behaviour is not normative. */ if (len*8 < ec_tell(&dec)) { len = 0; redundancy_bytes = 0; redundancy = 0; } /* Shrink decoder because of raw bits */ dec.storage -= redundancy_bytes; } } if (mode != MODE_CELT_ONLY) start_band = 17; { int endband=21; switch(st->bandwidth) { case OPUS_BANDWIDTH_NARROWBAND: endband = 13; break; case OPUS_BANDWIDTH_MEDIUMBAND: case OPUS_BANDWIDTH_WIDEBAND: endband = 17; break; case OPUS_BANDWIDTH_SUPERWIDEBAND: endband = 19; break; case OPUS_BANDWIDTH_FULLBAND: endband = 21; break; } celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); } if (redundancy) { transition = 0; pcm_transition_silk_size=ALLOC_NONE; } ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); if (transition && mode != MODE_CELT_ONLY) { pcm_transition = pcm_transition_silk; opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); } /* Only allocation memory for redundancy if/when needed */ redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; ALLOC(redundant_audio, redundant_audio_size, opus_val16); /* 5 ms redundant frame for CELT->SILK*/ if (redundancy && celt_to_silk) { celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); } /* MUST be after PLC */ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)); if (mode != MODE_SILK_ONLY) { int celt_frame_size = IMIN(F20, frame_size); /* Make sure to discard any previous CELT state */ if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); /* Decode CELT */ celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, len, pcm, celt_frame_size, &dec, celt_accum); } else { unsigned char silence[2] = {0xFF, 0xFF}; if (!celt_accum) { for (i=0; i<frame_size*st->channels; i++) pcm[i] = 0; } /* For hybrid -> SILK transitions, we let the CELT MDCT do a fade-out by decoding a silence frame */ if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) { celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); } } if (mode != MODE_CELT_ONLY && !celt_accum) { #ifdef FIXED_POINT for (i=0; i<frame_size*st->channels; i++) pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); #else for (i=0; i<frame_size*st->channels; i++) pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); #endif } { const CELTMode *celt_mode; celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)); window = celt_mode->window; } /* 5 ms redundant frame for SILK->CELT */ if (redundancy && !celt_to_silk) { celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); } if (redundancy && celt_to_silk) { for (c=0; c<st->channels; c++) { for (i=0; i<F2_5; i++) pcm[st->channels*i+c] = redundant_audio[st->channels*i+c]; } smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); } if (transition) { if (audiosize >= F5) { for (i=0; i<st->channels*F2_5; i++) pcm[i] = pcm_transition[i]; smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); } else { /* Not enough time to do a clean transition, but we do it anyway This will not preserve amplitude perfectly and may introduce a bit of temporal aliasing, but it shouldn't be too bad and that's pretty much the best we can do. In any case, generating this transition it pretty silly in the first place */ smooth_fade(pcm_transition, pcm, pcm, F2_5, st->channels, window, st->Fs); } } if(st->decode_gain) { opus_val32 gain; gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); for (i=0; i<frame_size*st->channels; i++) { opus_val32 x; x = MULT16_32_P16(pcm[i],gain); pcm[i] = SATURATE(x, 32767); } } if (len <= 1) st->rangeFinal = 0; else st->rangeFinal = dec.rng ^ redundant_rng; st->prev_mode = mode; st->prev_redundancy = redundancy && !celt_to_silk; if (celt_ret>=0) { if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) OPUS_PRINT_INT(audiosize); } RESTORE_STACK; return celt_ret < 0 ? celt_ret : audiosize; }
void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[]) { int i; uint16_t parameters[NB_PARAMETERS]; /* the output parameters in an array */ /* internal buffers which we do not need to keep between calls */ word16_t LPCoefficients[NB_LSP_COEFF]; /* the LP coefficients in Q3.12 */ word16_t qLPCoefficients[2*NB_LSP_COEFF]; /* the quantized LP coefficients in Q3.12 computed from the qLSP one after interpolation: two sets, one for each subframe */ word16_t weightedqLPCoefficients[2*NB_LSP_COEFF]; /* the qLP coefficients in Q3.12 weighted according to spec A3.3.3 */ word16_t LSPCoefficients[NB_LSP_COEFF]; /* the LSP coefficients in Q15 */ word16_t qLSPCoefficients[NB_LSP_COEFF]; /* the quantized LSP coefficients in Q15 */ word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used for first subframe in Q15 */ /*****************************************************************************************/ /*** on frame basis : preProcessing, LP Analysis, Open-loop pitch search ***/ preProcessing(encoderChannelContext, inputFrame, encoderChannelContext->signalLastInputFrame); /* output of the function in the signal buffer */ computeLP(encoderChannelContext->signalBuffer, LPCoefficients); /* use the whole signal Buffer for windowing and autocorrelation */ /*** compute LSP: it might fail, get the previous one in this case ***/ if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) { /* unable to find the 10 roots repeat previous LSP */ memcpy(LSPCoefficients, encoderChannelContext->previousLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); } /*** LSPQuantization and compute L0, L1, L2, L3: the first four parameters ***/ LSPQuantization(encoderChannelContext, LSPCoefficients, qLSPCoefficients, parameters); /*** interpolate qLSP and convert to LP ***/ interpolateqLSP(encoderChannelContext->previousqLSPCoefficients, qLSPCoefficients, interpolatedqLSP); /* copy the currentqLSP to previousqLSP buffer */ for (i=0; i<NB_LSP_COEFF; i++) { encoderChannelContext->previousqLSPCoefficients[i] = qLSPCoefficients[i]; } /* first subframe */ qLSP2LP(interpolatedqLSP, qLPCoefficients); /* second subframe */ qLSP2LP(qLSPCoefficients, &(qLPCoefficients[NB_LSP_COEFF])); /*** Compute the weighted Quantized LP Coefficients according to spec A3.3.3 ***/ /* weightedqLPCoefficients[0] = qLPCoefficients[0]*Gamma^(i+1) (i=0..9) with Gamma = 0.75 in Q15 */ weightedqLPCoefficients[0] = MULT16_16_P15(qLPCoefficients[0], GAMMA_E1); weightedqLPCoefficients[1] = MULT16_16_P15(qLPCoefficients[1], GAMMA_E2); weightedqLPCoefficients[2] = MULT16_16_P15(qLPCoefficients[2], GAMMA_E3); weightedqLPCoefficients[3] = MULT16_16_P15(qLPCoefficients[3], GAMMA_E4); weightedqLPCoefficients[4] = MULT16_16_P15(qLPCoefficients[4], GAMMA_E5); weightedqLPCoefficients[5] = MULT16_16_P15(qLPCoefficients[5], GAMMA_E6); weightedqLPCoefficients[6] = MULT16_16_P15(qLPCoefficients[6], GAMMA_E7); weightedqLPCoefficients[7] = MULT16_16_P15(qLPCoefficients[7], GAMMA_E8); weightedqLPCoefficients[8] = MULT16_16_P15(qLPCoefficients[8], GAMMA_E9); weightedqLPCoefficients[9] = MULT16_16_P15(qLPCoefficients[9], GAMMA_E10); weightedqLPCoefficients[10] = MULT16_16_P15(qLPCoefficients[10], GAMMA_E1); weightedqLPCoefficients[11] = MULT16_16_P15(qLPCoefficients[11], GAMMA_E2); weightedqLPCoefficients[12] = MULT16_16_P15(qLPCoefficients[12], GAMMA_E3); weightedqLPCoefficients[13] = MULT16_16_P15(qLPCoefficients[13], GAMMA_E4); weightedqLPCoefficients[14] = MULT16_16_P15(qLPCoefficients[14], GAMMA_E5); weightedqLPCoefficients[15] = MULT16_16_P15(qLPCoefficients[15], GAMMA_E6); weightedqLPCoefficients[16] = MULT16_16_P15(qLPCoefficients[16], GAMMA_E7); weightedqLPCoefficients[17] = MULT16_16_P15(qLPCoefficients[17], GAMMA_E8); weightedqLPCoefficients[18] = MULT16_16_P15(qLPCoefficients[18], GAMMA_E9); weightedqLPCoefficients[19] = MULT16_16_P15(qLPCoefficients[19], GAMMA_E10); /*** Compute weighted signal according to spec A3.3.3, this function also set LPResidualSignal(entire frame values) as specified in eq A.3 in excitationVector[L_PAST_EXCITATION] ***/ computeWeightedSpeech(encoderChannelContext->signalCurrentFrame, qLPCoefficients, weightedqLPCoefficients, &(encoderChannelContext->weightedInputSignal[MAXIMUM_INT_PITCH_DELAY]), &(encoderChannelContext->excitationVector[L_PAST_EXCITATION])); /* weightedInputSignal contains MAXIMUM_INT_PITCH_DELAY values from previous frame, points to current frame */ /*** find the open loop pitch delay ***/ uint16_t openLoopPitchDelay = findOpenLoopPitchDelay(&(encoderChannelContext->weightedInputSignal[MAXIMUM_INT_PITCH_DELAY])); /* define boundaries for closed loop pitch delay search as specified in 3.7 */ int16_t intPitchDelayMin = openLoopPitchDelay-3; if (intPitchDelayMin < 20) { intPitchDelayMin = 20; } int16_t intPitchDelayMax = intPitchDelayMin + 6; if (intPitchDelayMax > MAXIMUM_INT_PITCH_DELAY) { intPitchDelayMax = MAXIMUM_INT_PITCH_DELAY; intPitchDelayMin = MAXIMUM_INT_PITCH_DELAY - 6; } /*****************************************************************************************/ /* loop over the two subframes: Closed-loop pitch search(adaptative codebook), fixed codebook, memory update */ /* set index and buffers */ int subframeIndex; int LPCoefficientsIndex = 0; int parametersIndex = 4; /* index to insert parameters in the parameters output array */ word16_t impulseResponseInput[L_SUBFRAME]; /* input buffer for the impulse response computation: in Q12, 1 followed by all zeros see spec A3.5*/ impulseResponseInput[0] = ONE_IN_Q12; memset(&(impulseResponseInput[1]), 0, (L_SUBFRAME-1)*sizeof(word16_t)); for (subframeIndex=0; subframeIndex<L_FRAME; subframeIndex+=L_SUBFRAME) { /*** Compute the impulse response : filter a subframe long buffer filled with unit and only zero through the 1/weightedqLPCoefficients as in spec A.3.5 ***/ word16_t impulseResponseBuffer[NB_LSP_COEFF+L_SUBFRAME]; /* impulseResponseBuffer in Q12, need NB_LSP_COEFF as past value to go through filtering function */ memset(impulseResponseBuffer, 0, (NB_LSP_COEFF)*sizeof(word16_t)); /* set the past values to zero */ synthesisFilter(impulseResponseInput, &(weightedqLPCoefficients[LPCoefficientsIndex]), &(impulseResponseBuffer[NB_LSP_COEFF])); /*** Compute the target signal (x[n]) as in spec A.3.6 in Q0 ***/ /* excitationVector[L_PAST_EXCITATION+subframeIndex] currently store in Q0 the LPResidualSignal as in spec A.3.3 eq A.3*/ synthesisFilter( &(encoderChannelContext->excitationVector[L_PAST_EXCITATION+subframeIndex]), &(weightedqLPCoefficients[LPCoefficientsIndex]), &(encoderChannelContext->targetSignal[NB_LSP_COEFF])); /*** Adaptative Codebook search : compute the intPitchDelay, fracPitchDelay and associated parameter, compute also the adaptative codebook vector used to generate the excitation ***/ /* after this call, the excitationVector[L_PAST_EXCITATION + subFrameIndex] contains the adaptative codebook vector as in spec 3.7.1 */ int16_t intPitchDelay, fracPitchDelay; adaptativeCodebookSearch(&(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &intPitchDelayMin, &intPitchDelayMax, &(impulseResponseBuffer[NB_LSP_COEFF]), &(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &intPitchDelay, &fracPitchDelay, &(parameters[parametersIndex]), subframeIndex); /*** Compute adaptative codebook gain spec 3.7.3, result in Q14 ***/ /* compute the filtered adaptative codebook vector spec 3.7.3 */ /* this computation makes use of two partial results used for gainQuantization too (yy and xy in eq63), they are part of the function output */ /* note spec 3.7.3 eq44 make use of convolution of impulseResponse and adaptative codebook vector to compute the filtered version */ /* in the Annex A, the filter being simpler, it's faster to directly filter the the vector using the weightedqLPCoefficients */ word16_t filteredAdaptativeCodebookVector[NB_LSP_COEFF+L_SUBFRAME]; /* in Q0, the first NB_LSP_COEFF words are set to zero and used by filter only */ memset(filteredAdaptativeCodebookVector, 0, NB_LSP_COEFF*sizeof(word16_t)); synthesisFilter(&(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(weightedqLPCoefficients[LPCoefficientsIndex]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF])); word64_t gainQuantizationXy, gainQuantizationYy; /* used to store in Q0 values reused in gain quantization */ word16_t adaptativeCodebookGain = computeAdaptativeCodebookGain(&(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), &gainQuantizationXy, &gainQuantizationYy); /* gain in Q14 */ /* increase parameters index and compute P0 if needed */ parametersIndex++; if (subframeIndex==0) { /* first subframe compute P0, the parity bit of P1 */ parameters[parametersIndex] = computeParity(parameters[parametersIndex-1]); parametersIndex++; } /*** Fixed Codebook Search : compute the parameters for fixed codebook and the regular and convolved version of the fixed codebook vector ***/ word16_t fixedCodebookVector[L_SUBFRAME]; /* in Q13 */ word16_t convolvedFixedCodebookVector[L_SUBFRAME]; /* in Q12 */ fixedCodebookSearch(&(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(impulseResponseBuffer[NB_LSP_COEFF]), intPitchDelay, encoderChannelContext->lastQuantizedAdaptativeCodebookGain, &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), adaptativeCodebookGain, &(parameters[parametersIndex]), &(parameters[parametersIndex+1]), fixedCodebookVector, convolvedFixedCodebookVector); parametersIndex+=2; /*** gains Quantization ***/ word16_t quantizedAdaptativeCodebookGain; /* in Q14 */ word16_t quantizedFixedCodebookGain; /* in Q1 */ gainQuantization(encoderChannelContext, &(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(filteredAdaptativeCodebookVector[NB_LSP_COEFF]), convolvedFixedCodebookVector, fixedCodebookVector, gainQuantizationXy, gainQuantizationYy, &quantizedAdaptativeCodebookGain, &quantizedFixedCodebookGain, &(parameters[parametersIndex]), &(parameters[parametersIndex+1])); parametersIndex+=2; /*** subframe basis indexes and memory updates ***/ LPCoefficientsIndex+= NB_LSP_COEFF; encoderChannelContext->lastQuantizedAdaptativeCodebookGain = quantizedAdaptativeCodebookGain; if (encoderChannelContext->lastQuantizedAdaptativeCodebookGain>ONE_POINT_2_IN_Q14) encoderChannelContext->lastQuantizedAdaptativeCodebookGain = ONE_POINT_2_IN_Q14; if (encoderChannelContext->lastQuantizedAdaptativeCodebookGain<O2_IN_Q14) encoderChannelContext->lastQuantizedAdaptativeCodebookGain = O2_IN_Q14; /* compute excitation for current subframe as in spec A.3.10 */ /* excitationVector[L_PAST_EXCITATION + subframeIndex] currently contains in Q0 the adaptative codebook vector, quantizedAdaptativeCodebookGain in Q14 */ /* fixedCodebookVector in Q13, quantizedFixedCodebookGain in Q1 */ for (i=0; i<L_SUBFRAME; i++) { encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex + i] = (word16_t)(SATURATE(PSHR(ADD32(MULT16_16(encoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex + i], quantizedAdaptativeCodebookGain), MULT16_16(fixedCodebookVector[i], quantizedFixedCodebookGain)), 14), MAXINT16)); /* result in Q0 */ } /* update targetSignal memory as in spec A.3.10 */ quantizedAdaptativeCodebookGain = PSHR(quantizedAdaptativeCodebookGain, 1); /* quantizedAdaptativeCodebookGain in Q13 */ for (i=0; i<NB_LSP_COEFF; i++) { /* targetSignal[i] = targetSignal[L_SUBFRAME+i] - quantizedAdaptativeCodebookGain*filteredAdaptativeCodebookVector[L_SUBFRAME+i] - quantizedFixedCodebookGain*convolvedFixedCodebookVector[L_SUBFRAME-NB_LSP_COEFF+i]*/ word32_t acc = MAC16_16(MULT16_16(quantizedAdaptativeCodebookGain, filteredAdaptativeCodebookVector[L_SUBFRAME+i]), quantizedFixedCodebookGain, convolvedFixedCodebookVector[L_SUBFRAME-NB_LSP_COEFF+i]); /* acc in Q13 */ encoderChannelContext->targetSignal[i] = (word16_t)(SATURATE(SUB32(encoderChannelContext->targetSignal[L_SUBFRAME+i], PSHR(acc, 13)), MAXINT16)); } } /*****************************************************************************************/ /*** frame basis memory updates ***/ /* shift left by L_FRAME the signal buffer */ memmove(encoderChannelContext->signalBuffer, &(encoderChannelContext->signalBuffer[L_FRAME]), (L_LP_ANALYSIS_WINDOW-L_FRAME)*sizeof(word16_t)); /* update previousLSP coefficient buffer */ memcpy(encoderChannelContext->previousLSPCoefficients, LSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); memcpy(encoderChannelContext->previousqLSPCoefficients, qLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); /* shift left by L_FRAME the weightedInputSignal buffer */ memmove(encoderChannelContext->weightedInputSignal, &(encoderChannelContext->weightedInputSignal[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); /* shift left by L_FRAME the excitationVector */ memmove(encoderChannelContext->excitationVector, &(encoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t)); /*** Convert array of parameters into bitStream ***/ parametersArray2BitStream(parameters, bitStream); return; }
void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[], word32_t reflectionCoefficients[], word32_t autoCorrelationCoefficients[], word32_t noLagAutocorrelationCoefficients[], int8_t *autoCorrelationCoefficientsScale, uint8_t autoCorrelationCoefficientsNumber) { int i,j; word16_t windowedSignal[L_LP_ANALYSIS_WINDOW]; word64_t acc64=0; /* acc on 64 bits */ int rightShiftToNormalise=0; word32_t residualEnergy; /* interally compute by autoCorrelation2LP and extracted for DTX only, useless here */ /*********************************************************************/ /* Compute the windowed signal according to spec 3.2.1 eq4 */ /*********************************************************************/ for (i=0; i<L_LP_ANALYSIS_WINDOW; i++) { windowedSignal[i] = MULT16_16_P15(signal[i], wlp[i]); /* signal in Q0, wlp in Q0.15, windowedSignal in Q0 */ } /*********************************************************************************/ /* Compute the autoCorrelation coefficients r[0..10] according to spec 3.2.1 eq5 */ /*********************************************************************************/ /* Compute autoCorrelationCoefficients[0] first as it is the highest number and normalise it on 32 bits then apply the same normalisation to the other coefficients */ /* autoCorrelationCoefficients are normalised on 32 bits and then considered as Q31 in range [-1,1[ */ /* autoCorrelationCoefficients[0] is computed on 64 bits as it is likely to overflow 32 bits */ for (i=0; i<L_LP_ANALYSIS_WINDOW; i++) { acc64 = MAC64(acc64, windowedSignal[i], windowedSignal[i]); } if (acc64==0) { acc64 = 1; /* spec 3.2.1: To avoid arithmetic problems for low-level input signals the value of r(0) has a lower boundary of r(0) = 1.0 */ } /* normalise the acc64 on 32 bits */ if (acc64>MAXINT32) { do { acc64 = SHR(acc64,1); rightShiftToNormalise++; } while (acc64>MAXINT32); autoCorrelationCoefficients[0] = acc64; } else { rightShiftToNormalise = -countLeadingZeros((word32_t)acc64); autoCorrelationCoefficients[0] = SHL((word32_t)acc64, -rightShiftToNormalise); } /* give current autoCorrelation coefficients scale to the output */ *autoCorrelationCoefficientsScale = -rightShiftToNormalise; /* compute autoCorrelationCoefficients 1 to requested number (10 - no VAD - or 12 if VAD is enabled */ if (rightShiftToNormalise>0) { /* acc64 was not fitting on 32 bits so compute the other sum on 64 bits too */ for (i=1; i<autoCorrelationCoefficientsNumber; i++) { /* compute the sum in the 64 bits acc*/ acc64=0; for (j=i; j<L_LP_ANALYSIS_WINDOW; j++) { acc64 = ADD64_32(acc64, MULT16_16(windowedSignal[j], windowedSignal[j-i])); } /* normalise it */ autoCorrelationCoefficients[i] = SHR(acc64 ,rightShiftToNormalise); } } else { /* acc64 was fitting on 32 bits, compute the other sum on 32 bits only as it is faster */ for (i=1; i<autoCorrelationCoefficientsNumber; i++) { /* compute the sum in the 64 bits acc*/ word32_t acc32=0; for (j=i; j<L_LP_ANALYSIS_WINDOW; j++) { acc32 = MAC16_16(acc32, windowedSignal[j], windowedSignal[j-i]); } /* normalise it */ autoCorrelationCoefficients[i] = SHL(acc32, -rightShiftToNormalise); } } /* save autocorrelation before applying lag window as they are requested like this for DTX */ for (i=0; i<autoCorrelationCoefficientsNumber; i++) { noLagAutocorrelationCoefficients[i] = autoCorrelationCoefficients[i]; } /* apply lag window on the autocorrelation coefficients spec 3.2.1 eq7 */ /* this check shall be useless but it makes some compiler happy */ if (autoCorrelationCoefficientsNumber>NB_LSP_COEFF+3) { autoCorrelationCoefficientsNumber = NB_LSP_COEFF+3; } for (i=1; i<autoCorrelationCoefficientsNumber; i++) { autoCorrelationCoefficients[i] = MULT16_32_P15(wlag[i], autoCorrelationCoefficients[i]); /* wlag in Q15 */ //autoCorrelationCoefficients[i] = MULT32_32_Q31(wlag[i], autoCorrelationCoefficients[i]); /* wlag in Q31 */ } /* convert to LP using Levinson-Durbin algo described in sepc 3.2.2 */ autoCorrelation2LP(autoCorrelationCoefficients, LPCoefficientsQ12, reflectionCoefficients, &residualEnergy); return; }
/** Performs echo cancellation on a frame */ EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) { int i,j, chan, speak; int N,M, C, K; spx_word32_t Syy,See,Sxx,Sdd, Sff; #ifdef TWO_PATH spx_word32_t Dbf; int update_foreground; #endif spx_word32_t Sey; spx_word16_t ss, ss_1; spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE; spx_float_t alpha, alpha_1; spx_word16_t RER; spx_word32_t tmp32; N = st->window_size; M = st->M; C = st->C; K = st->K; st->cancel_count++; #ifdef FIXED_POINT ss=DIV32_16(11469,M); ss_1 = SUB16(32767,ss); #else ss=.35/M; ss_1 = 1-ss; #endif for (chan = 0; chan < C; chan++) { /* Apply a notch filter to make sure DC doesn't end up causing problems */ filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); /* Copy input data to buffer and apply pre-emphasis */ /* Copy input data to buffer */ for (i=0;i<st->frame_size;i++) { spx_word32_t tmp32; /* FIXME: This core has changed a bit, need to merge properly */ tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); #ifdef FIXED_POINT if (tmp32 > 32767) { tmp32 = 32767; if (st->saturated == 0) st->saturated = 1; } if (tmp32 < -32767) { tmp32 = -32767; if (st->saturated == 0) st->saturated = 1; } #endif st->memD[chan] = st->input[chan*st->frame_size+i]; st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); } } for (speak = 0; speak < K; speak++) { for (i=0;i<st->frame_size;i++) { spx_word32_t tmp32; st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); #ifdef FIXED_POINT /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ if (tmp32 > 32767) { tmp32 = 32767; st->saturated = M+1; } if (tmp32 < -32767) { tmp32 = -32767; st->saturated = M+1; } #endif st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); st->memX[speak] = far_end[i*K+speak]; } } for (speak = 0; speak < K; speak++) { /* Shift memory: this could be optimized eventually*/ for (j=M-1;j>=0;j--) { for (i=0;i<N;i++) st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i]; } /* Convert x (echo input) to frequency domain */ spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); } Sxx = 0; for (speak = 0; speak < K; speak++) { Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N); } Sff = 0; for (chan = 0; chan < C; chan++) { #ifdef TWO_PATH /* Compute foreground filter */ spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); for (i=0;i<st->frame_size;i++) st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); #endif } /* Adjust proportional adaption rate */ /* FIXME: Adjust that for C, K*/ if (st->adapted) mdf_adjust_prop (st->W, N, M, C*K, st->prop); /* Compute weight gradient */ if (st->saturated == 0) { for (chan = 0; chan < C; chan++) { for (speak = 0; speak < K; speak++) { for (j=M-1;j>=0;j--) { weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); for (i=0;i<N;i++) st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; } } } } else { st->saturated--; } /* FIXME: MC conversion required */ /* Update weight to prevent circular convolution (MDF / AUMDF) */ for (chan = 0; chan < C; chan++) { for (speak = 0; speak < K; speak++) { for (j=0;j<M;j++) { /* This is a variant of the Alternatively Updated MDF (AUMDF) */ /* Remove the "if" to make this an MDF filter */ if (j==0 || st->cancel_count%(M-1) == j-1) { #ifdef FIXED_POINT for (i=0;i<N;i++) st->wtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16)); spx_ifft(st->fft_table, st->wtmp2, st->wtmp); for (i=0;i<st->frame_size;i++) { st->wtmp[i]=0; } for (i=st->frame_size;i<N;i++) { st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); } spx_fft(st->fft_table, st->wtmp, st->wtmp2); /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ for (i=0;i<N;i++) st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); #else spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp); for (i=st->frame_size;i<N;i++) { st->wtmp[i]=0; } spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]); #endif } } } } /* So we can use power_spectrum_accum */ for (i=0;i<=st->frame_size;i++) st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; Dbf = 0; See = 0; #ifdef TWO_PATH /* Difference in response, this is used to estimate the variance of our residual power estimate */ for (chan = 0; chan < C; chan++) { spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); for (i=0;i<st->frame_size;i++) st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); for (i=0;i<st->frame_size;i++) st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); } #endif #ifndef TWO_PATH Sff = See; #endif #ifdef TWO_PATH /* Logic for updating the foreground filter */ /* For two time windows, compute the mean of the energy difference, as well as the variance */ st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); /* Equivalent float code: st->Davg1 = .6*st->Davg1 + .4*(Sff-See); st->Davg2 = .85*st->Davg2 + .15*(Sff-See); st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; */ update_foreground = 0; /* Check if we have a statistically significant reduction in the residual echo */ /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf))) update_foreground = 1; else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1)))) update_foreground = 1; else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) update_foreground = 1; /* Do we update? */ if (update_foreground) { st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; /* Copy background filter to foreground filter */ for (i=0;i<N*M*C*K;i++) st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16)); /* Apply a smooth transition so as to not introduce blocking artifacts */ for (chan = 0; chan < C; chan++) for (i=0;i<st->frame_size;i++) st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); } else { int reset_background=0; /* Otherwise, check if the background filter is significantly worse */ if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf)))) reset_background = 1; if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1))) reset_background = 1; if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2))) reset_background = 1; if (reset_background) { /* Copy foreground filter to background filter */ for (i=0;i<N*M*C*K;i++) st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); /* We also need to copy the output so as to get correct adaptation */ for (chan = 0; chan < C; chan++) { for (i=0;i<st->frame_size;i++) st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; for (i=0;i<st->frame_size;i++) st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); } See = Sff; st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; } } #endif Sey = Syy = Sdd = 0; for (chan = 0; chan < C; chan++) { /* Compute error signal (for the output with de-emphasis) */ for (i=0;i<st->frame_size;i++) { spx_word32_t tmp_out; #ifdef TWO_PATH tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); #else tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); #endif tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); /* This is an arbitrary test for saturation in the microphone signal */ if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) { if (st->saturated == 0) st->saturated = 1; } out[i*C+chan] = WORD2INT(tmp_out); st->memE[chan] = tmp_out; } #ifdef DUMP_ECHO_CANCEL_DATA dump_audio(in, far_end, out, st->frame_size); #endif /* Compute error signal (filter update version) */ for (i=0;i<st->frame_size;i++) { st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; st->e[chan*N+i] = 0; } /* Compute a bunch of correlations */ /* FIXME: bad merge */ Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); /* Convert error to frequency domain */ spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); for (i=0;i<st->frame_size;i++) st->y[i+chan*N] = 0; spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ power_spectrum_accum(st->E+chan*N, st->Rf, N); power_spectrum_accum(st->Y+chan*N, st->Yf, N); } /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ /* Do some sanity check */ if (!(Syy>=0 && Sxx>=0 && See >= 0) #ifndef FIXED_POINT || !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9) #endif ) { /* Things have gone really bad */ st->screwed_up += 50; for (i=0;i<st->frame_size*C;i++) out[i] = 0; } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) { /* AEC seems to add lots of echo instead of removing it, let's see if it will improve */ st->screwed_up++; } else { /* Everything's fine */ st->screwed_up=0; } if (st->screwed_up>=50) { speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now."); speex_echo_state_reset(st); return; } /* Add a small noise floor to make sure not to have problems when dividing */ See = MAX32(See, SHR32(MULT16_16(N, 100),6)); for (speak = 0; speak < K; speak++) { Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N); } /* Smooth far end energy estimate over time */ for (j=0;j<=st->frame_size;j++) st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); /* Compute filtered spectra and (cross-)correlations */ for (j=st->frame_size;j>=0;j--) { spx_float_t Eh, Yh; Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]); Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]); Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh)); Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh)); #ifdef FIXED_POINT st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]); st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]); #else st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j]; st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; #endif } Pyy = FLOAT_SQRT(Pyy); Pey = FLOAT_DIVU(Pey,Pyy); /* Compute correlation updatete rate */ tmp32 = MULT16_32_Q15(st->beta0,Syy); if (tmp32 > MULT16_32_Q15(st->beta_max,See)) tmp32 = MULT16_32_Q15(st->beta_max,See); alpha = FLOAT_DIV32(tmp32, See); alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha); /* Update correlations (recursive average) */ st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey)); st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy)); if (FLOAT_LT(st->Pyy, FLOAT_ONE)) st->Pyy = FLOAT_ONE; /* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */ if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy))) st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy); if (FLOAT_GT(st->Pey, st->Pyy)) st->Pey = st->Pyy; /* leak_estimate is the linear regression result */ st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14)); /* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */ if (st->leak_estimate > 16383) st->leak_estimate = 32767; else st->leak_estimate = SHL16(st->leak_estimate,1); /*printf ("%f\n", st->leak_estimate);*/ /* Compute Residual to Error Ratio */ #ifdef FIXED_POINT tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1))); /* Check for y in e (lower bound on RER) */ { spx_float_t bound = PSEUDOFLOAT(Sey); bound = FLOAT_DIVU(FLOAT_MULT(bound, bound), PSEUDOFLOAT(ADD32(1,Syy))); if (FLOAT_GT(bound, PSEUDOFLOAT(See))) tmp32 = See; else if (tmp32 < FLOAT_EXTRACT32(bound)) tmp32 = FLOAT_EXTRACT32(bound); } if (tmp32 > SHR32(See,1)) tmp32 = SHR32(See,1); RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15)); #else RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See; /* Check for y in e (lower bound on RER) */ if (RER < Sey*Sey/(1+See*Syy)) RER = Sey*Sey/(1+See*Syy); if (RER > .5) RER = .5; #endif /* We consider that the filter has had minimal adaptation if the following is true*/ if (!st->adapted && st->sum_adapt > SHL32(EXTEND32(M),15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy)) { st->adapted = 1; } if (st->adapted) { /* Normal learning rate calculation once we're past the minimal adaptation phase */ for (i=0;i<=st->frame_size;i++) { spx_word32_t r, e; /* Compute frequency-domain adaptation mask */ r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3)); e = SHL32(st->Rf[i],3)+1; #ifdef FIXED_POINT if (r>SHR32(e,1)) r = SHR32(e,1); #else if (r>.5*e) r = .5*e; #endif r = MULT16_32_Q15(QCONST16(.7,15),r) + MULT16_32_Q15(QCONST16(.3,15),(spx_word32_t)(MULT16_32_Q15(RER,e))); /*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/ st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16); } } else { /* Temporary adaption rate if filter is not yet adapted enough */ spx_word16_t adapt_rate=0; if (Sxx > SHR32(MULT16_16(N, 1000),6)) { tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); #ifdef FIXED_POINT if (tmp32 > SHR32(See,2)) tmp32 = SHR32(See,2); #else if (tmp32 > .25*See) tmp32 = .25*See; #endif adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15)); } for (i=0;i<=st->frame_size;i++) st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1); /* How much have we adapted so far? */ st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); } /* FIXME: MC conversion required */ for (i=0;i<st->frame_size;i++) st->last_y[i] = st->last_y[st->frame_size+i]; if (st->adapted) { /* If the filter is adapted, take the filtered echo */ for (i=0;i<st->frame_size;i++) st->last_y[st->frame_size+i] = in[i]-out[i]; } else { /* If filter isn't adapted yet, all we can do is take the far end signal directly */ /* moved earlier: for (i=0;i<N;i++) st->last_y[i] = st->x[i];*/ } }
void postFilter(bcg729DecoderChannelContextStruct *decoderChannelContext, word16_t *LPCoefficients, word16_t *reconstructedSpeech, int16_t intPitchDelay, int subframeIndex, word16_t *postFilteredSignal) { int i,j; /********************************************************************/ /* Long Term Post Filter */ /********************************************************************/ /*** Compute LPGammaN and LPGammaD coefficients : LPGamma[0] = LP[0]*Gamma^(i+1) (i=0..9) ***/ word16_t LPGammaNCoefficients[NB_LSP_COEFF]; /* in Q12 */ /* GAMMA_XX constants are in Q15 */ LPGammaNCoefficients[0] = MULT16_16_P15(LPCoefficients[0], GAMMA_N1); LPGammaNCoefficients[1] = MULT16_16_P15(LPCoefficients[1], GAMMA_N2); LPGammaNCoefficients[2] = MULT16_16_P15(LPCoefficients[2], GAMMA_N3); LPGammaNCoefficients[3] = MULT16_16_P15(LPCoefficients[3], GAMMA_N4); LPGammaNCoefficients[4] = MULT16_16_P15(LPCoefficients[4], GAMMA_N5); LPGammaNCoefficients[5] = MULT16_16_P15(LPCoefficients[5], GAMMA_N6); LPGammaNCoefficients[6] = MULT16_16_P15(LPCoefficients[6], GAMMA_N7); LPGammaNCoefficients[7] = MULT16_16_P15(LPCoefficients[7], GAMMA_N8); LPGammaNCoefficients[8] = MULT16_16_P15(LPCoefficients[8], GAMMA_N9); LPGammaNCoefficients[9] = MULT16_16_P15(LPCoefficients[9], GAMMA_N10); /*** Compute the residual signal as described in spec 4.2.1 eq79 ***/ /* Compute also a scaled residual signal: shift right by 2 to avoid overflows on 32 bits when computing correlation and energy */ /* pointers to current subframe beginning */ word16_t *residualSignal = &(decoderChannelContext->residualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+subframeIndex]); word16_t *scaledResidualSignal = &(decoderChannelContext->scaledResidualSignalBuffer[MAXIMUM_INT_PITCH_DELAY+subframeIndex]); for (i=0; i<L_SUBFRAME; i++) { word32_t acc = SHL((word32_t)reconstructedSpeech[i], 12); /* reconstructedSpeech in Q0 shifted to set acc in Q12 */ for (j=0; j<NB_LSP_COEFF; j++) { acc = MAC16_16(acc, LPGammaNCoefficients[j],reconstructedSpeech[i-j-1]); /* LPGammaNCoefficients in Q12, reconstructedSpeech in Q0 -> acc in Q12 */ } residualSignal[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* shift back acc to Q0 and saturate it to avoid overflow when going back to 16 bits */ scaledResidualSignal[i] = PSHR(residualSignal[i], 2); /* shift acc to Q-2 and saturate it to get the scaled version of the signal */ } /*** Compute the maximum correlation on scaledResidualSignal delayed by intPitchDelay +/- 3 to get the best delay. Spec 4.2.1 eq80 ***/ /* using a scaled(Q-2) signals gives correlation in Q-4. */ word32_t correlationMax = (word32_t)MININT32; int16_t intPitchDelayMax = intPitchDelay+3; /* intPitchDelayMax shall be < MAXIMUM_INT_PITCH_DELAY(143) */ int16_t bestIntPitchDelay = 0; word16_t *delayedResidualSignal; if (intPitchDelayMax>MAXIMUM_INT_PITCH_DELAY) { intPitchDelayMax = MAXIMUM_INT_PITCH_DELAY; } for (i=intPitchDelay-3; i<=intPitchDelayMax; i++) { word32_t correlation = 0; delayedResidualSignal = &(scaledResidualSignal[-i]); /* delayedResidualSignal points to scaledResidualSignal[-i] */ /* compute correlation: ∑r(n)*rk(n) */ for (j=0; j<L_SUBFRAME; j++) { correlation = MAC16_16(correlation, delayedResidualSignal[j], scaledResidualSignal[j]); } /* if we have a maximum correlation */ if (correlation>correlationMax) { correlationMax = correlation; bestIntPitchDelay = i; /* get the intPitchDelay */ } } /* saturate correlation to a positive integer */ if (correlationMax<0) { correlationMax = 0; } /*** Compute the signal energy ∑r(n)*r(n) and delayed signal energy ∑rk(n)*rk(n) which shall be used to compute gl spec 4.2.1 eq81, eq 82 and eq83 ***/ word32_t residualSignalEnergy = 0; /* in Q-4 */ word32_t delayedResidualSignalEnergy = 0; /* in Q-4 */ delayedResidualSignal = &(scaledResidualSignal[-bestIntPitchDelay]); /* in Q-2, points to the residual signal delayed to give the higher correlation: rk(n) */ for (i=0; i<L_SUBFRAME; i++) { residualSignalEnergy = MAC16_16(residualSignalEnergy, scaledResidualSignal[i], scaledResidualSignal[i]); delayedResidualSignalEnergy = MAC16_16(delayedResidualSignalEnergy, delayedResidualSignal[i], delayedResidualSignal[i]); } /*** Scale correlationMax, residualSignalEnergy and delayedResidualSignalEnergy to the best fit on 16 bits ***/ /* these variables must fit on 16bits for the following computation, to avoid loosing information, scale them */ /* at best fit: scale the higher of three to get the value over 2^14 and shift the other two from the same amount */ /* Note: all three value are >= 0 */ word32_t maximumThree = correlationMax; if (maximumThree<residualSignalEnergy) { maximumThree = residualSignalEnergy; } if (maximumThree<delayedResidualSignalEnergy) { maximumThree = delayedResidualSignalEnergy; } int16_t leadingZeros = 0; word16_t correlationMaxWord16 = 0; word16_t residualSignalEnergyWord16 = 0; word16_t delayedResidualSignalEnergyWord16 = 0; if (maximumThree>0) { /* if all of them a null, just do nothing otherwise shift right to get the max number in range [0x4000,0x8000[ */ leadingZeros = countLeadingZeros(maximumThree); if (leadingZeros<16) { correlationMaxWord16 = (word16_t)SHR32(correlationMax, 16-leadingZeros); residualSignalEnergyWord16 = (word16_t)SHR32(residualSignalEnergy, 16-leadingZeros); delayedResidualSignalEnergyWord16 = (word16_t)SHR32(delayedResidualSignalEnergy, 16-leadingZeros); } else { /* if the values already fit on 16 bits, no need to shift */ correlationMaxWord16 = (word16_t)correlationMax; residualSignalEnergyWord16 = (word16_t)residualSignalEnergy; delayedResidualSignalEnergyWord16 = (word16_t)delayedResidualSignalEnergy; } } /* eq78: Hp(z)=(1 + γp*gl*z(−T))/(1 + γp*gl) -> (with g=γp*gl) Hp(z)=1/(1+g) + (g/(1+g))*z(-T) = g0 + g1*z(-T) */ /* g = gl/2 (as γp=0.5)= (eq83) correlationMax/(2*delayedResidualSignalEnergy) */ /* compute g0 = 1/(1+g)= delayedResidualSignalEnergy/(delayedResidualSignalEnergy+correlationMax/2) = 1-g1*/ /* compute g1 = g/(1+g) = correlationMax/(2*delayedResidualSignalEnergy+correlationMax) = 1-g0 */ /*** eq82 -> (correlationMax^2)/(residualSignalEnergy*delayedResidualSignalEnergy)<0.5 ***/ /* (correlationMax^2) < (residualSignalEnergy*delayedResidualSignalEnergy)*0.5 */ if ((MULT16_16(correlationMaxWord16, correlationMaxWord16) < SHR(MULT16_16(residualSignalEnergyWord16, delayedResidualSignalEnergyWord16), 1)) /* eq82 */ || ((correlationMaxWord16==0) && (delayedResidualSignalEnergyWord16==0))) { /* correlationMax and delayedResidualSignalEnergy values are 0 -> unable to compute g0 and g1 -> disable filter */ /* long term post filter disabled */ for (i=0; i<L_SUBFRAME; i++) { decoderChannelContext->longTermFilteredResidualSignal[i] = residualSignal[i]; } } else { /* eq82 gives long term filter enabled, */ word16_t g0, g1; /* eq83: gl = correlationMax/delayedResidualSignalEnergy bounded in ]0,1] */ /* check if gl > 1 -> gl=1 -> g=1/2 -> g0=2/3 and g1=1/3 */ if (correlationMax > delayedResidualSignalEnergy) { g0 = 21845; /* 2/3 in Q15 */ g1 = 10923; /* 1/3 in Q15 */ } else { /* g1 = correlationMax/(2*delayedResidualSignalEnergy+correlationMax) */ g1 = DIV32((word32_t)SHL32(correlationMaxWord16,15),(word32_t)ADD32(SHL32(delayedResidualSignalEnergyWord16,1), correlationMaxWord16)); /* g1 in Q15 */ g0 = SUB16(32767, g1); /* g0 = 1 - g1 in Q15 */ } /* longTermFilteredResidualSignal[i] = g0*residualSignal[i] + g1*delayedResidualSignal[i]*/ delayedResidualSignal = &(residualSignal[-bestIntPitchDelay]); for (i=0; i<L_SUBFRAME; i++) { decoderChannelContext->longTermFilteredResidualSignal[i] = (word16_t)SATURATE(PSHR(ADD32(MULT16_16(g0, residualSignal[i]), MULT16_16(g1, delayedResidualSignal[i])), 15), MAXINT16); } } /********************************************************************/ /* Tilt Compensation Filter */ /********************************************************************/ /* compute hf the truncated (to 22 coefficients) impulse response of the filter A(z/γn)/A(z/γd) described in spec 4.2.2 eq84 */ /* hf(i) = LPGammaNCoeff[i] - ∑[j:0..9]LPGammaDCoeff[j]*hf[i-j-1]) */ word16_t LPGammaDCoefficients[NB_LSP_COEFF]; /* in Q12 */ /* GAMMA_XX constants are in Q15 */ LPGammaDCoefficients[0] = MULT16_16_P15(LPCoefficients[0], GAMMA_D1); LPGammaDCoefficients[1] = MULT16_16_P15(LPCoefficients[1], GAMMA_D2); LPGammaDCoefficients[2] = MULT16_16_P15(LPCoefficients[2], GAMMA_D3); LPGammaDCoefficients[3] = MULT16_16_P15(LPCoefficients[3], GAMMA_D4); LPGammaDCoefficients[4] = MULT16_16_P15(LPCoefficients[4], GAMMA_D5); LPGammaDCoefficients[5] = MULT16_16_P15(LPCoefficients[5], GAMMA_D6); LPGammaDCoefficients[6] = MULT16_16_P15(LPCoefficients[6], GAMMA_D7); LPGammaDCoefficients[7] = MULT16_16_P15(LPCoefficients[7], GAMMA_D8); LPGammaDCoefficients[8] = MULT16_16_P15(LPCoefficients[8], GAMMA_D9); LPGammaDCoefficients[9] = MULT16_16_P15(LPCoefficients[9], GAMMA_D10); word16_t hf[22]; /* the truncated impulse response to short term filter Hf in Q12 */ hf[0] = 4096; /* 1 in Q12 as LPGammaNCoefficients and LPGammaDCoefficient doesn't contain the first element which is 1 and past values of hf are 0 */ for (i=1; i<11; i++) { word32_t acc = (word32_t)SHL(LPGammaNCoefficients[i-1],12); /* LPGammaNCoefficients in Q12 -> acc in Q24 */ for (j=0; j<NB_LSP_COEFF && j<i; j++) { /* j<i to avoid access to negative index of hf(past values are 0 anyway) */ acc = MSU16_16(acc, LPGammaDCoefficients[j], hf[i-j-1]); /* LPGammaDCoefficient in Q12, hf in Q12 -> Q24 TODO: Possible overflow?? */ } hf[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* get result back in Q12 and saturate on 16 bits */ } for (i=11; i<22; i++) { word32_t acc = 0; for (j=0; j<NB_LSP_COEFF; j++) { /* j<i to avoid access to negative index of hf(past values are 0 anyway) */ acc = MSU16_16(acc, LPGammaDCoefficients[j], hf[i-j-1]); /* LPGammaDCoefficient in Q12, hf in Q12 -> Q24 TODO: Possible overflow?? */ } hf[i] = (word16_t)SATURATE(PSHR(acc, 12), MAXINT16); /* get result back in Q12 and saturate on 16 bits */ } /* hf is then used to compute k'1 spec 4.2.3 eq87: k'1 = -rh1/rh0 */ /* rh0 = ∑[i:0..21]hf[i]*hf[i] */ /* rh1 = ∑[i:0..20]hf[i]*hf[i+1] */ word32_t rh1 = MULT16_16(hf[0], hf[1]); for (i=1; i<21; i++) { rh1 = MAC16_16(rh1, hf[i], hf[i+1]); /* rh1 in Q24 */ } /* tiltCompensationGain is set to 0 if k'1>0 -> rh1<0 (as rh0 is always>0) */ word16_t tiltCompensatedSignal[L_SUBFRAME]; /* in Q0 */ if (rh1<0) { /* tiltCompensationGain = 0 -> no gain filter is off, just copy the input */ memcpy(tiltCompensatedSignal, decoderChannelContext->longTermFilteredResidualSignal, L_SUBFRAME*sizeof(word16_t)); } else { /*compute tiltCompensationGain = k'1*γt */ word32_t rh0 = MULT16_16(hf[0], hf[0]); for (i=1; i<22; i++) { rh0 = MAC16_16(rh0, hf[i], hf[i]); /* rh0 in Q24 */ } rh1 = MULT16_32_Q15(GAMMA_T, rh1); /* GAMMA_T in Q15, rh1 in Q24*/ word16_t tiltCompensationGain = (word16_t)SATURATE((word32_t)(DIV32(rh1,PSHR(rh0,12))), MAXINT16); /* rh1 in Q24, PSHR(rh0,12) in Q12 -> tiltCompensationGain in Q12 */ /* compute filter Ht (spec A.4.2.3 eqA14) = 1 + gain*z(-1) */ for (i=0; i<L_SUBFRAME; i++) { tiltCompensatedSignal[i] = MSU16_16_Q12(decoderChannelContext->longTermFilteredResidualSignal[i], tiltCompensationGain, decoderChannelContext->longTermFilteredResidualSignal[i-1]); } } /* update memory word of longTermFilteredResidualSignal for next subframe */ decoderChannelContext->longTermFilteredResidualSignal[-1] = decoderChannelContext->longTermFilteredResidualSignal[L_SUBFRAME-1]; /********************************************************************/ /* synthesis filter 1/[Â(z /γd)] spec A.4.2.2 */ /* */ /* Note: Â(z/γn) was done before when computing residual signal */ /********************************************************************/ /* shortTermFilteredResidualSignal is accessed in range [-NB_LSP_COEFF,L_SUBFRAME[ */ synthesisFilter(tiltCompensatedSignal, LPGammaDCoefficients, decoderChannelContext->shortTermFilteredResidualSignal); /* get the last NB_LSP_COEFF of shortTermFilteredResidualSignal and set them as memory for next subframe(they do not overlap so use memcpy) */ memcpy(decoderChannelContext->shortTermFilteredResidualSignalBuffer, &(decoderChannelContext->shortTermFilteredResidualSignalBuffer[L_SUBFRAME]), NB_LSP_COEFF*sizeof(word16_t)); /********************************************************************/ /* Adaptive Gain Control spec A.4.2.4 */ /* */ /********************************************************************/ /*** compute G(gain scaling factor) according to eqA15 : G = Sqrt((∑s(n)^2)/∑sf(n)^2 ) ***/ word16_t gainScalingFactor; /* in Q12 */ /* compute ∑sf(n)^2 scale the signal shifting left by 2 to avoid overflow on 32 bits sum */ word32_t shortTermFilteredResidualSignalSquareSum = 0; for (i=0; i<L_SUBFRAME; i++) { shortTermFilteredResidualSignalSquareSum = MAC16_16_Q4(shortTermFilteredResidualSignalSquareSum, decoderChannelContext->shortTermFilteredResidualSignal[i], decoderChannelContext->shortTermFilteredResidualSignal[i]); } /* if the sum is null we can't compute gain -> output of postfiltering is the output of shortTermFilter and previousAdaptativeGain is set to 0 */ /* the reset of previousAdaptativeGain is not mentionned in the spec but in ITU code only */ if (shortTermFilteredResidualSignalSquareSum == 0) { decoderChannelContext->previousAdaptativeGain = 0; for (i=0; i<L_SUBFRAME; i++) { postFilteredSignal[i] = decoderChannelContext->shortTermFilteredResidualSignal[i]; } } else { /* we can compute adaptativeGain and output signal */ /* compute ∑s(n)^2 scale the signal shifting left by 2 to avoid overflow on 32 bits sum */ word32_t reconstructedSpeechSquareSum = 0; for (i=0; i<L_SUBFRAME; i++) { reconstructedSpeechSquareSum = MAC16_16_Q4(reconstructedSpeechSquareSum, reconstructedSpeech[i], reconstructedSpeech[i]); } if (reconstructedSpeechSquareSum==0) { /* numerator is null -> current gain is null */ gainScalingFactor = 0; } else { /* Compute ∑s(n)^2)/∑sf(n)^2 result shall be in Q10 */ /* normalise the numerator on 32 bits */ word16_t numeratorShift = countLeadingZeros(reconstructedSpeechSquareSum); reconstructedSpeechSquareSum = SHL(reconstructedSpeechSquareSum, numeratorShift); /* reconstructedSpeechSquareSum*2^numeratorShift */ /* normalise denominator to get the result directly in Q10 if possible */ word32_t fractionResult; /* stores ∑s(n)^2)/∑sf(n)^2 */ word32_t scaledShortTermFilteredResidualSignalSquareSum = VSHR32(shortTermFilteredResidualSignalSquareSum, 10-numeratorShift); /* shortTermFilteredResidualSignalSquareSum*2^(numeratorShift-10)*/ if (scaledShortTermFilteredResidualSignalSquareSum==0) {/* shift might have sent to zero the denominator */ fractionResult = DIV32(reconstructedSpeechSquareSum, shortTermFilteredResidualSignalSquareSum); /* result in QnumeratorShift */ fractionResult = VSHR32(fractionResult, numeratorShift-10); /* result in Q10 */ } else { /* ok denominator is still > 0 */ fractionResult = DIV32(reconstructedSpeechSquareSum, scaledShortTermFilteredResidualSignalSquareSum); /* result in Q10 */ } /* now compute current Gain = Sqrt((∑s(n)^2)/∑sf(n)^2 ) */ /* g729Sqrt_Q0Q7(Q0)->Q7, by giving a Q10 as input, output is in Q12 */ gainScalingFactor = (word16_t)SATURATE(g729Sqrt_Q0Q7(fractionResult), MAXINT16); /* multiply by 0.1 as described in spec A.4.2.4 */ gainScalingFactor = MULT16_16_P15(gainScalingFactor, 3277); /* in Q12, 3277 = 0.1 in Q15*/ } /* Compute the signal according to eq89 (spec 4.2.4 and section A4.2.4) */ /* currentGain = 0.9*previousGain + 0.1*gainScalingFactor the 0.1 factor has already been integrated in the variable gainScalingFactor */ /* outputsignal = currentGain*shortTermFilteredResidualSignal */ word16_t currentAdaptativeGain = decoderChannelContext->previousAdaptativeGain; for (i=0; i<L_SUBFRAME; i++) { currentAdaptativeGain = ADD16(gainScalingFactor, MULT16_16_P15(currentAdaptativeGain, 29491)); /* 29492 = 0.9 in Q15, result in Q12 */ postFilteredSignal[i] = MULT16_16_Q12(currentAdaptativeGain, decoderChannelContext->shortTermFilteredResidualSignal[i]); } decoderChannelContext->previousAdaptativeGain = currentAdaptativeGain; } /* shift buffers if needed */ if (subframeIndex>0) { /* only after 2nd subframe treatment */ /* shift left by L_FRAME the residualSignal and scaledResidualSignal buffers */ memmove(decoderChannelContext->residualSignalBuffer, &(decoderChannelContext->residualSignalBuffer[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); memmove(decoderChannelContext->scaledResidualSignalBuffer, &(decoderChannelContext->scaledResidualSignalBuffer[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t)); } return; }