📄 dtx.c
字号:
RX_SPARE |(class2 garb.)| |
----------------------------------------------------------------
*/
Word16 rx_dtx_handler(
dtx_decState * st, /* i/o : State struct */
Word16 frame_type /* i : Frame type */
)
{
Word16 newState;
Word16 encState;
/* DTX if SID frame or previously in DTX{_MUTE} and (NO_RX OR BAD_SPEECH) */
test();test();test();
test();test();test();
test();test();
if ((sub(frame_type, RX_SID_FIRST) == 0) ||
(sub(frame_type, RX_SID_UPDATE) == 0) ||
(sub(frame_type, RX_SID_BAD) == 0) ||
(((sub(st->dtxGlobalState, DTX) == 0) ||
(sub(st->dtxGlobalState, DTX_MUTE) == 0)) &&
((sub(frame_type, RX_NO_DATA) == 0) ||
(sub(frame_type, RX_SPEECH_BAD) == 0) ||
(sub(frame_type, RX_SPEECH_LOST) == 0))))
{
newState = DTX; move16();
/* stay in mute for these input types */
test();test();test();test();test();
if ((sub(st->dtxGlobalState, DTX_MUTE) == 0) &&
((sub(frame_type, RX_SID_BAD) == 0) ||
(sub(frame_type, RX_SID_FIRST) == 0) ||
(sub(frame_type, RX_SPEECH_LOST) == 0) ||
(sub(frame_type, RX_NO_DATA) == 0)))
{
newState = DTX_MUTE; move16();
}
/* evaluate if noise parameters are too old */
/* since_last_sid is reset when CN parameters have been updated */
st->since_last_sid = add(st->since_last_sid, 1); move16();
/* no update of sid parameters in DTX for a long while */
test();
if (sub(st->since_last_sid, DTX_MAX_EMPTY_THRESH) > 0)
{
newState = DTX_MUTE; move16();
}
} else
{
newState = SPEECH; move16();
st->since_last_sid = 0; move16();
}
/* 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. */
test();test();
if ((st->data_updated == 0) &&
(sub(frame_type, RX_SID_UPDATE) == 0))
{
st->decAnaElapsedCount = 0; move16();
}
/* update the SPE-SPD DTX hangover synchronization */
/* to know when SPE has added dtx hangover */
st->decAnaElapsedCount = add(st->decAnaElapsedCount, 1); move16();
st->dtxHangoverAdded = 0; move16();
test();test();test();test();
if ((sub(frame_type, RX_SID_FIRST) == 0) ||
(sub(frame_type, RX_SID_UPDATE) == 0) ||
(sub(frame_type, RX_SID_BAD) == 0) ||
(sub(frame_type, RX_NO_DATA) == 0))
{
encState = DTX; move16();
} else
{
encState = SPEECH; move16();
}
test();
if (sub(encState, SPEECH) == 0)
{
st->dtxHangoverCount = DTX_HANG_CONST; move16();
} else
{
test();test();
if (sub(st->decAnaElapsedCount, DTX_ELAPSED_FRAMES_THRESH) > 0)
{
st->dtxHangoverAdded = 1; move16();
st->decAnaElapsedCount = 0; move16();
st->dtxHangoverCount = 0; move16();
} else if (test(), st->dtxHangoverCount == 0)
{
st->decAnaElapsedCount = 0; move16();
} else
{
st->dtxHangoverCount = sub(st->dtxHangoverCount, 1); move16();
}
}
test();
if (sub(newState, SPEECH) != 0)
{
/* 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; move16();
st->valid_data = 0; move16();
test();test();test();
if (sub(frame_type, RX_SID_FIRST) == 0)
{
st->sid_frame = 1; move16();
} else if (test(), sub(frame_type, RX_SID_UPDATE) == 0)
{
st->sid_frame = 1; move16();
st->valid_data = 1; move16();
} else if (test(), sub(frame_type, RX_SID_BAD) == 0)
{
st->sid_frame = 1; move16();
st->dtxHangoverAdded = 0; /* use old data */move16();
}
}
return newState;
/* newState is used by both SPEECH AND DTX synthesis routines */
}
static void aver_isf_history(
Word16 isf_old[],
Word16 indices[],
Word32 isf_aver[]
)
{
Word16 i, j, k;
Word16 isf_tmp[2 * M];
Word32 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++)
{
test();
if (add(indices[k], 1) != 0)
{
for (i = 0; i < M; i++)
{
isf_tmp[k * M + i] = isf_old[indices[k] * M + i]; move16();
isf_old[indices[k] * M + i] = isf_old[indices[2] * M + i]; move16();
}
}
}
/* Perform the ISF averaging */
for (j = 0; j < M; j++)
{
L_tmp = 0; move32();
for (i = 0; i < DTX_HIST_SIZE; i++)
{
L_tmp = L_add(L_tmp, L_deposit_l(isf_old[i * M + j]));
}
isf_aver[j] = L_tmp; move32();
}
/* Retrieve from isf_tmp[][] the ISF vectors saved prior to averaging */
for (k = 0; k < 2; k++)
{
test();
if (add(indices[k], 1) != 0)
{
for (i = 0; i < M; i++)
{
isf_old[indices[k] * M + i] = isf_tmp[k * M + i]; move16();
}
}
}
return;
}
static void find_frame_indices(
Word16 isf_old_tx[],
Word16 indices[],
dtx_encState * st
)
{
Word32 L_tmp, summin, summax, summax2nd;
Word16 i, j, tmp;
Word16 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; move16();
j = -1; move16();
for (i = 0; i < DTX_HIST_SIZE_MIN_ONE; i++)
{
j = add(j, tmp);
st->sumD[i] = L_sub(st->sumD[i], st->D[j]); move16();
tmp = sub(tmp, 1);
}
/* 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]; move32();
}
st->sumD[0] = 0; move32();
/* 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; move16();
for (i = 27; i >= 12; i = (Word16) (i - tmp))
{
tmp = add(tmp, 1);
for (j = tmp; j > 0; j--)
{
st->D[i - j + 1] = st->D[i - j - tmp]; move32();
}
}
/* Compute the first column of the distance matrix D */
/* (squared Euclidean distances from isf1[] to isf_old_tx[][]). */
ptr = st->hist_ptr; move16();
for (i = 1; i < DTX_HIST_SIZE; i++)
{
/* Compute the distance between the latest isf and the other isfs. */
ptr = sub(ptr, 1);
test();
if (ptr < 0)
{
ptr = DTX_HIST_SIZE_MIN_ONE; move16();
}
L_tmp = 0; move32();
for (j = 0; j < M; j++)
{
tmp = sub(isf_old_tx[st->hist_ptr * M + j], isf_old_tx[ptr * M + j]);
L_tmp = L_mac(L_tmp, tmp, tmp);
}
st->D[i - 1] = L_tmp; move32();
/* Update also the column sums. */
st->sumD[0] = L_add(st->sumD[0], st->D[i - 1]); move32();
st->sumD[i] = L_add(st->sumD[i], st->D[i - 1]); move32();
}
/* Find the minimum and maximum distances */
summax = st->sumD[0]; move32();
summin = st->sumD[0]; move32();
indices[0] = 0; move16();
indices[2] = 0; move16();
for (i = 1; i < DTX_HIST_SIZE; i++)
{
test();
if (L_sub(st->sumD[i], summax) > 0)
{
indices[0] = i; move16();
summax = st->sumD[i]; move32();
}
test();
if (L_sub(st->sumD[i], summin) < 0)
{
indices[2] = i; move16();
summin = st->sumD[i]; move32();
}
}
/* Find the second largest distance */
summax2nd = -2147483647L; move32();
indices[1] = -1; move16();
for (i = 0; i < DTX_HIST_SIZE; i++)
{
test();
if ((L_sub(st->sumD[i], summax2nd) > 0) && (sub(i, indices[0]) != 0))
{
indices[1] = i; move16();
summax2nd = st->sumD[i]; move32();
}
}
for (i = 0; i < 3; i++)
{
indices[i] = sub(st->hist_ptr, indices[i]); move16();
test();
if (indices[i] < 0)
{
indices[i] = add(indices[i], DTX_HIST_SIZE); move16();
}
}
/* If maximum distance/MED_THRESH is smaller than minimum distance */
/* then the median ISF vector replacement is not performed */
tmp = norm_l(summax);
summax = L_shl(summax, tmp);
summin = L_shl(summin, tmp);
L_tmp = L_mult(round(summax), INV_MED_THRESH);
test();
if (L_sub(L_tmp, summin) <= 0)
{
indices[0] = -1; move16();
}
/* If second largest distance/MED_THRESH is smaller than */
/* minimum distance then the median ISF vector replacement is */
/* not performed */
summax2nd = L_shl(summax2nd, tmp);
L_tmp = L_mult(round(summax2nd), INV_MED_THRESH);
test();
if (L_sub(L_tmp, summin) <= 0)
{
indices[1] = -1; move16();
}
return;
}
static Word16 dithering_control(
dtx_encState * st
)
{
Word16 i, tmp, mean, CN_dith, gain_diff;
Word32 ISF_diff;
/* determine how stationary the spectrum of background noise is */
ISF_diff = 0;
for (i = 0; i < 8; i++)
{
ISF_diff = L_add(ISF_diff, st->sumD[i]);
}
if (L_shr(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(mean, st->log_en_hist[i]);
}
mean = shr(mean, 3);
gain_diff = 0;
for (i = 0; i < DTX_HIST_SIZE; i++)
{
tmp = abs_s(sub(st->log_en_hist[i], mean));
gain_diff = add(gain_diff, tmp);
}
if (sub(gain_diff, GAIN_THR) > 0)
{
CN_dith = 1;
}
return CN_dith;
}
static void CN_dithering(
Word16 isf[M],
Word32 * L_log_en_int,
Word16 * dither_seed
)
{
Word16 temp, temp1, i, dither_fac, rand_dith;
Word16 rand_dith2;
/* Insert comfort noise dithering for energy parameter */
rand_dith = shr(Random(dither_seed), 1);
rand_dith2 = shr(Random(dither_seed), 1);
rand_dith = add(rand_dith, rand_dith2);
*L_log_en_int = L_add(*L_log_en_int, L_mult(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 = shr(Random(dither_seed), 1);
rand_dith2 = shr(Random(dither_seed), 1);
rand_dith = add(rand_dith, rand_dith2);
temp = add(isf[0], mult_r(rand_dith, dither_fac));
/* Make sure that isf[0] will not get negative values */
if (sub(temp, ISF_GAP) < 0)
{
isf[0] = ISF_GAP;
} else
{
isf[0] = temp;
}
for (i = 1; i < M - 1; i++)
{
dither_fac = add(dither_fac, ISF_FACTOR_STEP);
rand_dith = shr(Random(dither_seed), 1);
rand_dith2 = shr(Random(dither_seed), 1);
rand_dith = add(rand_dith, rand_dith2);
temp = add(isf[i], mult_r(rand_dith, dither_fac));
temp1 = sub(temp, isf[i - 1]);
/* Make sure that isf spacing remains at least ISF_DITH_GAP Hz */
if (sub(temp1, ISF_DITH_GAP) < 0)
{
isf[i] = add(isf[i - 1], ISF_DITH_GAP);
} else
{
isf[i] = temp;
}
}
/* Make sure that isf[M-2] will not get values above 16384 */
if (sub(isf[M - 2], 16384) > 0)
{
isf[M - 2] = 16384;
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -