diff options
Diffstat (limited to 'media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp')
-rw-r--r-- | media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp new file mode 100644 index 0000000..7c798cc --- /dev/null +++ b/media/libstagefright/codecs/amrwb/src/dtx_decoder_amr_wb.cpp @@ -0,0 +1,984 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 1998-2009 PacketVideo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ +/**************************************************************************************** +Portions of this file are derived from the following 3GPP standard: + + 3GPP TS 26.173 + ANSI-C code for the Adaptive Multi-Rate - Wideband (AMR-WB) speech codec + Available from http://www.3gpp.org + +(C) 2007, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC) +Permission to distribute, modify and use this file under the standard license +terms listed above has been obtained from the copyright holder. +****************************************************************************************/ +/* +------------------------------------------------------------------------------ + + + + Filename: dtx_decoder_amr_wb.cpp + + Date: 05/08/2007 + +------------------------------------------------------------------------------ + REVISION HISTORY + + + Description: + +------------------------------------------------------------------------------ + INPUT AND OUTPUT DEFINITIONS + + +------------------------------------------------------------------------------ + FUNCTION DESCRIPTION + + DTX functions + +------------------------------------------------------------------------------ + REQUIREMENTS + + +------------------------------------------------------------------------------ + REFERENCES + +------------------------------------------------------------------------------ + PSEUDO-CODE + +------------------------------------------------------------------------------ +*/ + + +/*---------------------------------------------------------------------------- +; INCLUDES +----------------------------------------------------------------------------*/ + +#include "pv_amr_wb_type_defs.h" +#include "pvamrwbdecoder_basic_op.h" +#include "pvamrwb_math_op.h" +#include "pvamrwbdecoder_cnst.h" +#include "pvamrwbdecoder_acelp.h" /* prototype of functions */ +#include "get_amr_wb_bits.h" +#include "dtx.h" + +/*---------------------------------------------------------------------------- +; MACROS +; Define module specific macros here +----------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------- +; DEFINES +; Include all pre-processor statements here. Include conditional +; compile variables also. +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; LOCAL FUNCTION DEFINITIONS +; Function Prototype declaration +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; LOCAL STORE/BUFFER/POINTER DEFINITIONS +; Variable declaration - defined here and used outside this module +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; EXTERNAL FUNCTION REFERENCES +; Declare functions defined elsewhere and referenced in this module +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES +; Declare variables used in this module but defined elsewhere +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ +/* + * Function : dtx_dec_amr_wb_reset + */ +int16 dtx_dec_amr_wb_reset(dtx_decState * st, const int16 isf_init[]) +{ + int16 i; + + + if (st == (dtx_decState *) NULL) + { + /* dtx_dec_amr_wb_reset invalid parameter */ + return (-1); + } + st->since_last_sid = 0; + st->true_sid_period_inv = (1 << 13); /* 0.25 in Q15 */ + + st->log_en = 3500; + st->old_log_en = 3500; + /* low level noise for better performance in DTX handover cases */ + + st->cng_seed = RANDOM_INITSEED; + + st->hist_ptr = 0; + + /* Init isf_hist[] and decoder log frame energy */ + pv_memcpy((void *)st->isf, (void *)isf_init, M*sizeof(*isf_init)); + + pv_memcpy((void *)st->isf_old, (void *)isf_init, M*sizeof(*isf_init)); + + for (i = 0; i < DTX_HIST_SIZE; i++) + { + pv_memcpy((void *)&st->isf_hist[i * M], (void *)isf_init, M*sizeof(*isf_init)); + st->log_en_hist[i] = st->log_en; + } + + st->dtxHangoverCount = DTX_HANG_CONST; + st->decAnaElapsedCount = 32767; + + st->sid_frame = 0; + st->valid_data = 0; + st->dtxHangoverAdded = 0; + + st->dtxGlobalState = SPEECH; + st->data_updated = 0; + + st->dither_seed = RANDOM_INITSEED; + st->CN_dith = 0; + + return 0; +} + + +/* + Table of new SPD synthesis states + + | previous SPD_synthesis_state + Incoming | + frame_type | SPEECH | DTX | DTX_MUTE + --------------------------------------------------------------- + RX_SPEECH_GOOD , | | | + RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH + ---------------------------------------------------------------- + RX_SPEECH_BAD, | SPEECH | DTX | DTX_MUTE + ---------------------------------------------------------------- + RX_SID_FIRST, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_SID_UPDATE, | DTX | DTX | DTX + ---------------------------------------------------------------- + RX_SID_BAD, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_NO_DATA, | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE + RX_SPARE |(class2 garb.)| | + ---------------------------------------------------------------- +*/ + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +/* + * Function : dtx_dec_amr_wb + */ +int16 dtx_dec_amr_wb( + dtx_decState * st, /* i/o : State struct */ + int16 * exc2, /* o : CN excitation */ + int16 new_state, /* i : New DTX state */ + int16 isf[], /* o : CN ISF vector */ + int16 ** prms +) +{ + int16 log_en_index; + int16 ind[7]; + int16 i, j; + int16 int_fac; + int16 gain; + + int32 L_isf[M], L_log_en_int, level32, ener32; + int16 ptr; + int16 tmp_int_length; + int16 tmp, exp, exp0, log_en_int_e, log_en_int_m, level; + + /* This function is called if synthesis state is not SPEECH the globally passed inputs to this function + * are st->sid_frame st->valid_data st->dtxHangoverAdded new_state (SPEECH, DTX, DTX_MUTE) */ + + if ((st->dtxHangoverAdded != 0) && + (st->sid_frame != 0)) + { + /* sid_first after dtx hangover period */ + /* or sid_upd after dtxhangover */ + + /* consider twice the last frame */ + ptr = st->hist_ptr + 1; + + if (ptr == DTX_HIST_SIZE) + ptr = 0; + + pv_memcpy((void *)&st->isf_hist[ptr * M], (void *)&st->isf_hist[st->hist_ptr * M], M*sizeof(*st->isf_hist)); + + st->log_en_hist[ptr] = st->log_en_hist[st->hist_ptr]; + + /* compute mean log energy and isf from decoded signal (SID_FIRST) */ + st->log_en = 0; + for (i = 0; i < M; i++) + { + L_isf[i] = 0; + } + + /* average energy and isf */ + for (i = 0; i < DTX_HIST_SIZE; i++) + { + /* Division by DTX_HIST_SIZE = 8 has been done in dtx_buffer log_en is in Q10 */ + st->log_en = add_int16(st->log_en, st->log_en_hist[i]); + + for (j = 0; j < M; j++) + { + L_isf[j] = add_int32(L_isf[j], (int32)(st->isf_hist[i * M + j])); + } + } + + /* st->log_en in Q9 */ + st->log_en >>= 1; + + /* Add 2 in Q9, in order to have only positive values for Pow2 */ + /* this value is subtracted back after Pow2 function */ + st->log_en += 1024; + + if (st->log_en < 0) + st->log_en = 0; + + for (j = 0; j < M; j++) + { + st->isf[j] = (int16)(L_isf[j] >> 3); /* divide by 8 */ + } + + } + + if (st->sid_frame != 0) + { + /* Set old SID parameters, always shift */ + /* even if there is no new valid_data */ + + pv_memcpy((void *)st->isf_old, (void *)st->isf, M*sizeof(*st->isf)); + + st->old_log_en = st->log_en; + + if (st->valid_data != 0) /* new data available (no CRC) */ + { + /* st->true_sid_period_inv = 1.0f/st->since_last_sid; */ + /* Compute interpolation factor, since the division only works * for values of since_last_sid < + * 32 we have to limit the * interpolation to 32 frames */ + tmp_int_length = st->since_last_sid; + + + if (tmp_int_length > 32) + { + tmp_int_length = 32; + } + + if (tmp_int_length >= 2) + { + st->true_sid_period_inv = div_16by16(1 << 10, shl_int16(tmp_int_length, 10)); + } + else + { + st->true_sid_period_inv = 1 << 14; /* 0.5 it Q15 */ + } + + ind[0] = Serial_parm(6, prms); + ind[1] = Serial_parm(6, prms); + ind[2] = Serial_parm(6, prms); + ind[3] = Serial_parm(5, prms); + ind[4] = Serial_parm(5, prms); + + Disf_ns(ind, st->isf); + + log_en_index = Serial_parm(6, prms); + + /* read background noise stationarity information */ + st->CN_dith = Serial_parm_1bit(prms); + + /* st->log_en = (float)log_en_index / 2.625 - 2.0; */ + /* log2(E) in Q9 (log2(E) lies in between -2:22) */ + st->log_en = shl_int16(log_en_index, 15 - 6); + + /* Divide by 2.625 */ + st->log_en = mult_int16(st->log_en, 12483); + /* Subtract 2 in Q9 is done later, after Pow2 function */ + + /* no interpolation at startup after coder reset */ + /* or when SID_UPD has been received right after SPEECH */ + + if ((st->data_updated == 0) || (st->dtxGlobalState == SPEECH)) + { + pv_memcpy((void *)st->isf_old, (void *)st->isf, M*sizeof(*st->isf)); + + st->old_log_en = st->log_en; + } + } /* endif valid_data */ + } /* endif sid_frame */ + + + if ((st->sid_frame != 0) && (st->valid_data != 0)) + { + st->since_last_sid = 0; + } + /* Interpolate SID info */ + int_fac = shl_int16(st->since_last_sid, 10); /* Q10 */ + int_fac = mult_int16(int_fac, st->true_sid_period_inv); /* Q10 * Q15 -> Q10 */ + + /* Maximize to 1.0 in Q10 */ + + if (int_fac > 1024) + { + int_fac = 1024; + } + int_fac = shl_int16(int_fac, 4); /* Q10 -> Q14 */ + + L_log_en_int = mul_16by16_to_int32(int_fac, st->log_en); /* Q14 * Q9 -> Q24 */ + + for (i = 0; i < M; i++) + { + isf[i] = mult_int16(int_fac, st->isf[i]);/* Q14 * Q15 -> Q14 */ + } + + int_fac = 16384 - int_fac; /* 1-k in Q14 */ + + /* ( Q14 * Q9 -> Q24 ) + Q24 -> Q24 */ + L_log_en_int = mac_16by16_to_int32(L_log_en_int, int_fac, st->old_log_en); + + for (i = 0; i < M; i++) + { + /* Q14 + (Q14 * Q15 -> Q14) -> Q14 */ + isf[i] = add_int16(isf[i], mult_int16(int_fac, st->isf_old[i])); + isf[i] = shl_int16(isf[i], 1); /* Q14 -> Q15 */ + } + + /* If background noise is non-stationary, insert comfort noise dithering */ + if (st->CN_dith != 0) + { + CN_dithering(isf, &L_log_en_int, &st->dither_seed); + } + /* L_log_en_int corresponds to log2(E)+2 in Q24, i.e log2(gain)+1 in Q25 */ + /* Q25 -> Q16 */ + L_log_en_int >>= 9; + + /* Find integer part */ + log_en_int_e = extract_h(L_log_en_int); + + /* Find fractional part */ + log_en_int_m = (int16)(sub_int32(L_log_en_int, L_deposit_h(log_en_int_e)) >> 1); + + /* Subtract 2 from L_log_en_int in Q9, i.e divide the gain by 2 (energy by 4) */ + /* Add 16 in order to have the result of pow2 in Q16 */ + log_en_int_e += 15; + + /* level = (float)( pow( 2.0f, log_en ) ); */ + level32 = power_of_2(log_en_int_e, log_en_int_m); /* Q16 */ + + exp0 = normalize_amr_wb(level32); + level32 <<= exp0; /* level in Q31 */ + exp0 = 15 - exp0; + level = (int16)(level32 >> 16); /* level in Q15 */ + + /* generate white noise vector */ + for (i = 0; i < L_FRAME; i++) + { + exc2[i] = noise_gen_amrwb(&(st->cng_seed)) >> 4; + } + + /* gain = level / sqrt(ener) * sqrt(L_FRAME) */ + + /* energy of generated excitation */ + ener32 = Dot_product12(exc2, exc2, L_FRAME, &exp); + + one_ov_sqrt_norm(&ener32, &exp); + + gain = extract_h(ener32); + + gain = mult_int16(level, gain); /* gain in Q15 */ + + exp += exp0; + + /* Multiply by sqrt(L_FRAME)=16, i.e. shift left by 4 */ + exp += 4; + + for (i = 0; i < L_FRAME; i++) + { + tmp = mult_int16(exc2[i], gain); /* Q0 * Q15 */ + exc2[i] = shl_int16(tmp, exp); + } + + + if (new_state == DTX_MUTE) + { + /* mute comfort noise as it has been quite a long time since last SID update was performed */ + + tmp_int_length = st->since_last_sid; + + if (tmp_int_length > 32) + { + tmp_int_length = 32; + } + + st->true_sid_period_inv = div_16by16(1 << 10, shl_int16(tmp_int_length, 10)); + + st->since_last_sid = 0; + st->old_log_en = st->log_en; + /* subtract 1/8 in Q9 (energy), i.e -3/8 dB */ + st->log_en -= 64; + } + /* reset interpolation length timer if data has been updated. */ + + if ((st->sid_frame != 0) && + ((st->valid_data != 0) || + ((st->valid_data == 0) && (st->dtxHangoverAdded) != 0))) + { + st->since_last_sid = 0; + st->data_updated = 1; + } + return 0; +} + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +void dtx_dec_amr_wb_activity_update( + dtx_decState * st, + int16 isf[], + int16 exc[]) +{ + int16 i; + + int32 L_frame_en; + int16 log_en_e, log_en_m, log_en; + + + st->hist_ptr++; + + if (st->hist_ptr == DTX_HIST_SIZE) + { + st->hist_ptr = 0; + } + pv_memcpy((void *)&st->isf_hist[st->hist_ptr * M], (void *)isf, M*sizeof(*isf)); + + + /* compute log energy based on excitation frame energy in Q0 */ + L_frame_en = 0; + for (i = 0; i < L_FRAME; i++) + { + L_frame_en = mac_16by16_to_int32(L_frame_en, exc[i], exc[i]); + } + L_frame_en >>= 1; + + /* log_en = (float)log10(L_frame_en/(float)L_FRAME)/(float)log10(2.0f); */ + amrwb_log_2(L_frame_en, &log_en_e, &log_en_m); + + /* convert exponent and mantissa to int16 Q7. Q7 is used to simplify averaging in dtx_enc */ + log_en = shl_int16(log_en_e, 7); /* Q7 */ + log_en += log_en_m >> 8; + + /* Divide by L_FRAME = 256, i.e subtract 8 in Q7 = 1024 */ + log_en -= 1024; + + /* insert into log energy buffer */ + st->log_en_hist[st->hist_ptr] = log_en; + + return; +} + + +/* + Table of new SPD synthesis states + + | previous SPD_synthesis_state + Incoming | + frame_type | SPEECH | DTX | DTX_MUTE + --------------------------------------------------------------- + RX_SPEECH_GOOD , | | | + RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH + ---------------------------------------------------------------- + RX_SPEECH_BAD, | SPEECH | DTX | DTX_MUTE + ---------------------------------------------------------------- + RX_SID_FIRST, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_SID_UPDATE, | DTX | DTX | DTX + ---------------------------------------------------------------- + RX_SID_BAD, | DTX | DTX/(DTX_MUTE)| DTX_MUTE + ---------------------------------------------------------------- + RX_NO_DATA, | SPEECH | DTX/(DTX_MUTE)| DTX_MUTE + RX_SPARE |(class2 garb.)| | + ---------------------------------------------------------------- +*/ + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +int16 rx_amr_wb_dtx_handler( + dtx_decState * st, /* i/o : State struct */ + int16 frame_type /* i : Frame type */ +) +{ + int16 newState; + int16 encState; + + /* DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH) */ + + + + if ((frame_type == RX_SID_FIRST) || + (frame_type == RX_SID_UPDATE) || + (frame_type == RX_SID_BAD) || + (((st->dtxGlobalState == DTX) || + (st->dtxGlobalState == DTX_MUTE)) && + ((frame_type == RX_NO_DATA) || + (frame_type == RX_SPEECH_BAD) || + (frame_type == RX_SPEECH_LOST)))) + { + newState = DTX; + + /* stay in mute for these input types */ + + if ((st->dtxGlobalState == DTX_MUTE) && + ((frame_type == RX_SID_BAD) || + (frame_type == RX_SID_FIRST) || + (frame_type == RX_SPEECH_LOST) || + (frame_type == RX_NO_DATA))) + { + newState = DTX_MUTE; + } + /* evaluate if noise parameters are too old */ + /* since_last_sid is reset when CN parameters have been updated */ + st->since_last_sid = add_int16(st->since_last_sid, 1); + + /* no update of sid parameters in DTX for a long while */ + + if (st->since_last_sid > DTX_MAX_EMPTY_THRESH) + { + newState = DTX_MUTE; + } + } + else + { + newState = SPEECH; + st->since_last_sid = 0; + } + + /* reset the decAnaElapsed Counter when receiving CNI data the first time, to robustify counter missmatch + * after handover this might delay the bwd CNI analysis in the new decoder slightly. */ + + if ((st->data_updated == 0) && + (frame_type == RX_SID_UPDATE)) + { + st->decAnaElapsedCount = 0; + } + /* update the SPE-SPD DTX hangover synchronization */ + /* to know when SPE has added dtx hangover */ + st->decAnaElapsedCount = add_int16(st->decAnaElapsedCount, 1); + st->dtxHangoverAdded = 0; + + + if ((frame_type == RX_SID_FIRST) || + (frame_type == RX_SID_UPDATE) || + (frame_type == RX_SID_BAD) || + (frame_type == RX_NO_DATA)) + { + encState = DTX; + } + else + { + encState = SPEECH; + } + + + if (encState == SPEECH) + { + st->dtxHangoverCount = DTX_HANG_CONST; + } + else + { + + if (st->decAnaElapsedCount > DTX_ELAPSED_FRAMES_THRESH) + { + st->dtxHangoverAdded = 1; + st->decAnaElapsedCount = 0; + st->dtxHangoverCount = 0; + } + else if (st->dtxHangoverCount == 0) + { + st->decAnaElapsedCount = 0; + } + else + { + st->dtxHangoverCount--; + } + } + + if (newState != SPEECH) + { + /* DTX or DTX_MUTE CN data is not in a first SID, first SIDs are marked as SID_BAD but will do + * backwards analysis if a hangover period has been added according to the state machine above */ + + st->sid_frame = 0; + st->valid_data = 0; + + + if (frame_type == RX_SID_FIRST) + { + st->sid_frame = 1; + } + else if (frame_type == RX_SID_UPDATE) + { + st->sid_frame = 1; + st->valid_data = 1; + } + else if (frame_type == RX_SID_BAD) + { + st->sid_frame = 1; + st->dtxHangoverAdded = 0; /* use old data */ + } + } + return newState; + /* newState is used by both SPEECH AND DTX synthesis routines */ +} + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +void aver_isf_history( + int16 isf_old[], + int16 indices[], + int32 isf_aver[] +) +{ + int16 i, j, k; + int16 isf_tmp[2 * M]; + int32 L_tmp; + + /* Memorize in isf_tmp[][] the ISF vectors to be replaced by */ + /* the median ISF vector prior to the averaging */ + for (k = 0; k < 2; k++) + { + + if (indices[k] + 1 != 0) + { + for (i = 0; i < M; i++) + { + isf_tmp[k * M + i] = isf_old[indices[k] * M + i]; + isf_old[indices[k] * M + i] = isf_old[indices[2] * M + i]; + } + } + } + + /* Perform the ISF averaging */ + for (j = 0; j < M; j++) + { + L_tmp = 0; + + for (i = 0; i < DTX_HIST_SIZE; i++) + { + L_tmp = add_int32(L_tmp, (int32)(isf_old[i * M + j])); + } + isf_aver[j] = L_tmp; + } + + /* Retrieve from isf_tmp[][] the ISF vectors saved prior to averaging */ + for (k = 0; k < 2; k++) + { + + if (indices[k] + 1 != 0) + { + for (i = 0; i < M; i++) + { + isf_old[indices[k] * M + i] = isf_tmp[k * M + i]; + } + } + } + + return; +} + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +void find_frame_indices( + int16 isf_old_tx[], + int16 indices[], + dtx_encState * st +) +{ + int32 L_tmp, summin, summax, summax2nd; + int16 i, j, tmp; + int16 ptr; + + /* Remove the effect of the oldest frame from the column */ + /* sum sumD[0..DTX_HIST_SIZE-1]. sumD[DTX_HIST_SIZE] is */ + /* not updated since it will be removed later. */ + + tmp = DTX_HIST_SIZE_MIN_ONE; + j = -1; + for (i = 0; i < DTX_HIST_SIZE_MIN_ONE; i++) + { + j += tmp; + st->sumD[i] = sub_int32(st->sumD[i], st->D[j]); + tmp--; + } + + /* Shift the column sum sumD. The element sumD[DTX_HIST_SIZE-1] */ + /* corresponding to the oldest frame is removed. The sum of */ + /* the distances between the latest isf and other isfs, */ + /* i.e. the element sumD[0], will be computed during this call. */ + /* Hence this element is initialized to zero. */ + + for (i = DTX_HIST_SIZE_MIN_ONE; i > 0; i--) + { + st->sumD[i] = st->sumD[i - 1]; + } + st->sumD[0] = 0; + + /* Remove the oldest frame from the distance matrix. */ + /* Note that the distance matrix is replaced by a one- */ + /* dimensional array to save static memory. */ + + tmp = 0; + for (i = 27; i >= 12; i -= tmp) + { + tmp++; + for (j = tmp; j > 0; j--) + { + st->D[i - j + 1] = st->D[i - j - tmp]; + } + } + + /* Compute the first column of the distance matrix D */ + /* (squared Euclidean distances from isf1[] to isf_old_tx[][]). */ + + ptr = st->hist_ptr; + for (i = 1; i < DTX_HIST_SIZE; i++) + { + /* Compute the distance between the latest isf and the other isfs. */ + ptr--; + + if (ptr < 0) + { + ptr = DTX_HIST_SIZE_MIN_ONE; + } + L_tmp = 0; + for (j = 0; j < M; j++) + { + tmp = sub_int16(isf_old_tx[st->hist_ptr * M + j], isf_old_tx[ptr * M + j]); + L_tmp = mac_16by16_to_int32(L_tmp, tmp, tmp); + } + st->D[i - 1] = L_tmp; + + /* Update also the column sums. */ + st->sumD[0] = add_int32(st->sumD[0], st->D[i - 1]); + st->sumD[i] = add_int32(st->sumD[i], st->D[i - 1]); + } + + /* Find the minimum and maximum distances */ + summax = st->sumD[0]; + summin = st->sumD[0]; + indices[0] = 0; + indices[2] = 0; + for (i = 1; i < DTX_HIST_SIZE; i++) + { + + if (st->sumD[i] > summax) + { + indices[0] = i; + summax = st->sumD[i]; + } + + if (st->sumD[i] < summin) + { + indices[2] = i; + summin = st->sumD[i]; + } + } + + /* Find the second largest distance */ + summax2nd = -2147483647L; + indices[1] = -1; + for (i = 0; i < DTX_HIST_SIZE; i++) + { + + if ((st->sumD[i] > summax2nd) && (i != indices[0])) + { + indices[1] = i; + summax2nd = st->sumD[i]; + } + } + + for (i = 0; i < 3; i++) + { + indices[i] = sub_int16(st->hist_ptr, indices[i]); + + if (indices[i] < 0) + { + indices[i] = add_int16(indices[i], DTX_HIST_SIZE); + } + } + + /* If maximum distance/MED_THRESH is smaller than minimum distance */ + /* then the median ISF vector replacement is not performed */ + tmp = normalize_amr_wb(summax); + summax <<= tmp; + summin <<= tmp; + L_tmp = mul_16by16_to_int32(amr_wb_round(summax), INV_MED_THRESH); + + if (L_tmp <= summin) + { + indices[0] = -1; + } + /* If second largest distance/MED_THRESH is smaller than */ + /* minimum distance then the median ISF vector replacement is */ + /* not performed */ + summax2nd = shl_int32(summax2nd, tmp); + L_tmp = mul_16by16_to_int32(amr_wb_round(summax2nd), INV_MED_THRESH); + + if (L_tmp <= summin) + { + indices[1] = -1; + } + return; +} + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +int16 dithering_control(dtx_encState * st) +{ + int16 i, tmp, mean, CN_dith, gain_diff; + int32 ISF_diff; + + /* determine how stationary the spectrum of background noise is */ + ISF_diff = 0; + for (i = 0; i < 8; i++) + { + ISF_diff = add_int32(ISF_diff, st->sumD[i]); + } + if ((ISF_diff >> 26) > 0) + { + CN_dith = 1; + } + else + { + CN_dith = 0; + } + + /* determine how stationary the energy of background noise is */ + mean = 0; + for (i = 0; i < DTX_HIST_SIZE; i++) + { + mean = add_int16(mean, st->log_en_hist[i]); + } + mean >>= 3; + gain_diff = 0; + for (i = 0; i < DTX_HIST_SIZE; i++) + { + tmp = sub_int16(st->log_en_hist[i], mean); + tmp = tmp - (tmp < 0); + + gain_diff += tmp ^(tmp >> 15); /* tmp ^sign(tmp) */; + } + if (gain_diff > GAIN_THR) + { + CN_dith = 1; + } + return CN_dith; +} + + +/*---------------------------------------------------------------------------- +; FUNCTION CODE +----------------------------------------------------------------------------*/ + +void CN_dithering( + int16 isf[M], + int32 * L_log_en_int, + int16 * dither_seed +) +{ + int16 temp, temp1, i, dither_fac, rand_dith; + int16 rand_dith2; + + /* Insert comfort noise dithering for energy parameter */ + rand_dith = noise_gen_amrwb(dither_seed) >> 1; + rand_dith2 = noise_gen_amrwb(dither_seed) >> 1; + rand_dith += rand_dith2; + *L_log_en_int = add_int32(*L_log_en_int, mul_16by16_to_int32(rand_dith, GAIN_FACTOR)); + + if (*L_log_en_int < 0) + { + *L_log_en_int = 0; + } + /* Insert comfort noise dithering for spectral parameters (ISF-vector) */ + dither_fac = ISF_FACTOR_LOW; + + rand_dith = noise_gen_amrwb(dither_seed) >> 1; + rand_dith2 = noise_gen_amrwb(dither_seed) >> 1; + rand_dith += rand_dith2; + temp = add_int16(isf[0], mult_int16_r(rand_dith, dither_fac)); + + /* Make sure that isf[0] will not get negative values */ + if (temp < ISF_GAP) + { + isf[0] = ISF_GAP; + } + else + { + isf[0] = temp; + } + + for (i = 1; i < M - 1; i++) + { + dither_fac = add_int16(dither_fac, ISF_FACTOR_STEP); + + rand_dith = noise_gen_amrwb(dither_seed) >> 1; + rand_dith2 = noise_gen_amrwb(dither_seed) >> 1; + rand_dith += rand_dith2; + temp = add_int16(isf[i], mult_int16_r(rand_dith, dither_fac)); + temp1 = sub_int16(temp, isf[i - 1]); + + /* Make sure that isf spacing remains at least ISF_DITH_GAP Hz */ + if (temp1 < ISF_DITH_GAP) + { + isf[i] = isf[i - 1] + ISF_DITH_GAP; + } + else + { + isf[i] = temp; + } + } + + /* Make sure that isf[M-2] will not get values above 16384 */ + if (isf[M - 2] > 16384) + { + isf[M - 2] = 16384; + } + return; +} |