From 8d59e70434118a39f355487a9f288cf962907160 Mon Sep 17 00:00:00 2001 From: "turaj@webrtc.org" Date: Fri, 29 Jun 2012 18:17:53 +0000 Subject: [PATCH] In this CL four pitch-filters are integrated into a single function. I have kept the interfaces unchanged so there was no need to modify any other file. A test is uploaded to show how this CL is tested. The test engages all the functions affected by this CL and compares their output with the version of iSAC before this change. This CL is bit-exact. Furthermore, I ran iSAC release test and diff results with previous version. The test file will not be commited, as running it requires a hack in old iSAC to. Hence you don't need to code-review it. test = bit-exact with previous version of iSAC verified by iSAC Release test and the test written specifically to test functions affected by this CL. Review URL: https://webrtc-codereview.appspot.com/611004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2470 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../codecs/iSAC/main/source/pitch_filter.c | 756 ++++++++---------- 1 file changed, 335 insertions(+), 421 deletions(-) diff --git a/src/modules/audio_coding/codecs/iSAC/main/source/pitch_filter.c b/src/modules/audio_coding/codecs/iSAC/main/source/pitch_filter.c index ccc8d214da..f03d230e65 100644 --- a/src/modules/audio_coding/codecs/iSAC/main/source/pitch_filter.c +++ b/src/modules/audio_coding/codecs/iSAC/main/source/pitch_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -9,461 +9,375 @@ */ #include "pitch_estimator.h" + +#include +#include +#include + #include "os_specific_inline.h" -#include -#include -#include +/* + * We are implementing the following filters; + * + * Pre-filtering: + * y(z) = x(z) + damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); + * + * Post-filtering: + * y(z) = x(z) - damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); + * + * Note that |lag| is a floating number so we perform an interpolation to + * obtain the correct |lag|. + * + */ -static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, -0.07}; +static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, + -0.07}; /* interpolation coefficients; generated by design_pitch_filter.m */ static const double kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = { - {-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, 0.01754159521746}, - {-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, 0.01654127246314}, - {-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, 0.01295781500709}, - {-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, 0.00719783432422}, - {-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, -0.00000000000000}, - { 0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, -0.00764851320885}, - { 0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, -0.01463300534216}, - { 0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, -0.01985640750433} + {-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, + 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, + 0.01754159521746}, + {-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, + 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, + 0.01654127246314}, + {-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, + 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, + 0.01295781500709}, + {-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, + 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, + 0.00719783432422}, + {-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, + 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, + -0.00000000000000}, + {0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, + 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, + -0.00764851320885}, + {0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, + 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, + -0.01463300534216}, + {0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, + 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, + -0.01985640750433} }; +/* + * Enumerating the operation of the filter. + * iSAC has 4 different pitch-filter which are very similar in their structure. + * + * kPitchFilterPre : In this mode the filter is operating as pitch + * pre-filter. This is used at the encoder. + * kPitchFilterPost : In this mode the filter is operating as pitch + * post-filter. This is the inverse of pre-filter and used + * in the decoder. + * kPitchFilterPreLa : This is, in structure, similar to pre-filtering but + * utilizing 3 millisecond lookahead. It is used to + * obtain the signal for LPC analysis. + * kPitchFilterPreGain : This is, in structure, similar to pre-filtering but + * differential changes in gain is considered. This is + * used to find the optimal gain. + */ +typedef enum { + kPitchFilterPre, kPitchFilterPost, kPitchFilterPreLa, kPitchFilterPreGain +} PitchFilterOperation; -void WebRtcIsac_PitchfilterPre(double *indat, - double *outdat, - PitchFiltstr *pfp, - double *lags, - double *gains) -{ +/* + * Structure with parameters used for pitch-filtering. + * buffer : a buffer where the sum of previous inputs and outputs + * are stored. + * damper_state : the state of the damping filter. The filter is defined by + * |kDampFilter|. + * interpol_coeff : pointer to a set of coefficient which are used to utilize + * fractional pitch by interpolation. + * gain : pitch-gain to be applied to the current segment of input. + * lag : pitch-lag for the current segment of input. + * lag_offset : the offset of lag w.r.t. current sample. + * sub_frame : sub-frame index, there are 4 pitch sub-frames in an iSAC + * frame. + * This specifies the usage of the filter. See + * 'PitchFilterOperation' for operational modes. + * num_samples : number of samples to be processed in each segment. + * index : index of the input and output sample. + * damper_state_dg : state of damping filter for different trial gains. + * gain_mult : differential changes to gain. + */ +typedef struct { + double buffer[PITCH_INTBUFFSIZE + QLOOKAHEAD]; + double damper_state[PITCH_DAMPORDER]; + const double *interpol_coeff; + double gain; + double lag; + int lag_offset; - double ubuf[PITCH_INTBUFFSIZE]; - const double *fracoeff = NULL; - double curgain, curlag, gaindelta, lagdelta; - double sum, inystate[PITCH_DAMPORDER]; - double ftmp, oldlag, oldgain; - int k, n, m, pos, ind, pos2, Li, frc; + int sub_frame; + PitchFilterOperation mode; + int num_samples; + int index; - Li = 0; - /* Set up buffer and states */ - memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); - memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); - - oldlag = *pfp->oldlagp; - oldgain = *pfp->oldgainp; - - /* No interpolation if pitch lag step is big */ - if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { - oldlag = lags[0]; - oldgain = gains[0]; - } - - ind=0; - for (k=0;k0;m--) - inystate[m] = inystate[m-1]; - - /* Filter to get fractional pitch */ - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - sum=0; - for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); - memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); - - *pfp->oldlagp = oldlag; - *pfp->oldgainp = oldgain; - -} - - -void WebRtcIsac_PitchfilterPre_la(double *indat, - double *outdat, - PitchFiltstr *pfp, - double *lags, - double *gains) -{ - double ubuf[PITCH_INTBUFFSIZE+QLOOKAHEAD]; - const double *fracoeff = NULL; - double curgain, curlag, gaindelta, lagdelta; - double sum, inystate[PITCH_DAMPORDER]; - double ftmp; - double oldlag, oldgain; - int k, n, m, pos, ind, pos2, Li, frc; - - Li = 0; - /* Set up buffer and states */ - memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); - memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); - - oldlag = *pfp->oldlagp; - oldgain = *pfp->oldgainp; - - /* No interpolation if pitch lag step is big */ - if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { - oldlag = lags[0]; - oldgain = gains[0]; - } - - - ind=0; - for (k=0;k0;m--) - inystate[m] = inystate[m-1]; - - /* Filter to get fractional pitch */ - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - sum=0.0; - for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); - memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); - - *pfp->oldlagp = oldlag; - *pfp->oldgainp = oldgain; - - - /* Filter look-ahead segment */ - for (n=0;n0;m--) - inystate[m] = inystate[m-1]; - - /* Filter to get fractional pitch */ - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - sum=0.0; - for (m=0;mbuffer| where the output is written to. */ + int pos = parameters->index + PITCH_BUFFSIZE; + /* Index of |parameters->buffer| where samples are read for fractional-lag + * computation. */ + int pos_lag = pos - parameters->lag_offset; - /* Set up buffer and states */ - memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); - memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); + for (n = 0; n < parameters->num_samples; ++n) { + /* Shift low pass filter states. */ + for (m = PITCH_DAMPORDER - 1; m > 0; --m) { + parameters->damper_state[m] = parameters->damper_state[m - 1]; + } + /* Filter to get fractional pitch. */ + sum = 0.0; + for (m = 0; m < PITCH_FRACORDER; ++m) { + sum += parameters->buffer[pos_lag + m] * parameters->interpol_coeff[m]; + } + /* Multiply with gain. */ + parameters->damper_state[0] = parameters->gain * sum; - /* clear some buffers */ - for (k = 0; k < 4; k++) { - gain_mult[k] = 0.0; - for (n = 0; n < PITCH_DAMPORDER; n++) - inystate_dG[k][n] = 0.0; - } - - oldlag = *pfp->oldlagp; - oldgain = *pfp->oldgainp; - - /* No interpolation if pitch lag step is big */ - if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { - oldlag = lags[0]; - oldgain = gains[0]; - gain_mult[0] = 1.0; - } - - - ind=0; - for (k=0;k 1.0) gain_mult[k] = 1.0; - if (k > 0) gain_mult[k-1] -= 0.2; + if (parameters->mode == kPitchFilterPreGain) { + int lag_index = parameters->index - parameters->lag_offset; + int m_tmp = (lag_index < 0) ? -lag_index : 0; + /* Update the damper state for the new sample. */ + for (m = PITCH_DAMPORDER - 1; m > 0; --m) { + for (j = 0; j < 4; ++j) { + parameters->damper_state_dg[j][m] = + parameters->damper_state_dg[j][m - 1]; + } } - /* shift low pass filter states */ - for (m=PITCH_DAMPORDER-1;m>0;m--) { - inystate[m] = inystate[m-1]; - for (j = 0; j < 4; j++) - inystate_dG[j][m] = inystate_dG[j][m-1]; - } - - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - - /* Filter to get fractional pitch */ - sum=0.0; - for (m=0;m 0) ? Li-ind : 0; - for (j = 0; j < k+1; j++) { - /* filter */ + for (j = 0; j < parameters->sub_frame + 1; ++j) { + /* Filter for fractional pitch. */ sum2 = 0.0; - for (m = PITCH_FRACORDER-1; m >= m_tmp; m--) - sum2 += out_dG[j][ind-Li + m] * fracoeff[m]; - inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2; + for (m = PITCH_FRACORDER-1; m >= m_tmp; --m) { + /* |lag_index + m| is always larger than or equal to zero, see how + * m_tmp is computed. This is equivalent to assume samples outside + * |out_dg[j]| are zero. */ + sum2 += out_dg[j][lag_index + m] * parameters->interpol_coeff[m]; + } + /* Add the contribution of differential gain change. */ + parameters->damper_state_dg[j][0] = parameters->gain_mult[j] * sum + + parameters->gain * sum2; } - /* Low pass filter */ - sum=0.0; - for (m=0;msub_frame + 1; ++j) { sum = 0.0; - for (m=0;mdamper_state_dg[j][m] * kDampFilter[m]; + } + out_dg[j][parameters->index] = sum; } - for (j = k+1; j < 4; j++) - out_dG[j][ind] = 0.0; - - - ind++; } + /* Filter with damping filter. */ + sum = 0.0; + for (m = 0; m < PITCH_DAMPORDER; ++m) { + sum += parameters->damper_state[m] * kDampFilter[m]; + } + + /* Subtract from input and update buffer. */ + out_data[parameters->index] = in_data[parameters->index] - sum; + parameters->buffer[pos] = in_data[parameters->index] + + out_data[parameters->index]; + + ++parameters->index; + ++pos; + ++pos_lag; } + return; +} - /* Filter look-ahead segment */ - for (n=0;n0;m--) { - inystate[m] = inystate[m-1]; - for (j = 0; j < 4; j++) - inystate_dG[j][m] = inystate_dG[j][m-1]; +/* Update filter parameters based on the pitch-gains and pitch-lags. */ +static void Update(PitchFilterParam* parameters) { + double fraction; + int fraction_index; + /* Compute integer lag-offset. */ + parameters->lag_offset = WebRtcIsac_lrint(parameters->lag + PITCH_FILTDELAY + + 0.5); + /* Find correct set of coefficients for computing fractional pitch. */ + fraction = parameters->lag_offset - (parameters->lag + PITCH_FILTDELAY); + fraction_index = WebRtcIsac_lrint(PITCH_FRACS * fraction - 0.5); + parameters->interpol_coeff = kIntrpCoef[fraction_index]; + + if (parameters->mode == kPitchFilterPreGain) { + /* If in this mode make a differential change to pitch gain. */ + parameters->gain_mult[parameters->sub_frame] += 0.2; + if (parameters->gain_mult[parameters->sub_frame] > 1.0) { + parameters->gain_mult[parameters->sub_frame] = 1.0; } - - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - - /* Filter to get fractional pitch */ - sum=0.0; - for (m=0;m 0) ? Li-ind : 0; - for (j = 0; (j= m_tmp; m--) - sum2 += out_dG[j][ind-Li + m] * fracoeff[m]; - inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2; + if (parameters->sub_frame > 0) { + parameters->gain_mult[parameters->sub_frame - 1] -= 0.2; } - - /* Low pass filter */ - sum=0.0; - for (m=0;mubuf, + sizeof(filter_state->ubuf)); + memcpy(filter_parameters.damper_state, filter_state->ystate, + sizeof(filter_state->ystate)); - double ubuf[PITCH_INTBUFFSIZE]; - const double *fracoeff = NULL; - double curgain, curlag, gaindelta, lagdelta; - double sum, inystate[PITCH_DAMPORDER]; - double ftmp, oldlag, oldgain; - int k, n, m, pos, ind, pos2, Li, frc; - - Li = 0; - - /* Set up buffer and states */ - memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); - memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); - - oldlag = *pfp->oldlagp; - oldgain = *pfp->oldgainp; - - /* make output more periodic */ - for (k=0;k (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { - oldlag = lags[0]; - oldgain = gains[0]; - } - - - ind=0; - for (k=0;k0;m--) - inystate[m] = inystate[m-1]; - - /* Filter to get fractional pitch */ - pos = ind + PITCH_BUFFSIZE; - pos2 = pos - Li; - sum=0.0; - for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); - memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); + old_lag = *filter_state->oldlagp; + old_gain = *filter_state->oldgainp; - *pfp->oldlagp = oldlag; - *pfp->oldgainp = oldgain; + /* No interpolation if pitch lag step is big. */ + if ((lags[0] > (PITCH_UPSTEP * old_lag)) || + (lags[0] < (PITCH_DOWNSTEP * old_lag))) { + old_lag = lags[0]; + old_gain = gains[0]; + if (mode == kPitchFilterPreGain) { + filter_parameters.gain_mult[0] = 1.0; + } + } + + filter_parameters.num_samples = PITCH_UPDATE; + for (m = 0; m < PITCH_SUBFRAMES; ++m) { + /* Set the sub-frame value. */ + filter_parameters.sub_frame = m; + /* Calculate interpolation steps for pitch-lag and pitch-gain. */ + lag_delta = (lags[m] - old_lag) / PITCH_GRAN_PER_SUBFRAME; + filter_parameters.lag = old_lag; + gain_delta = (gains[m] - old_gain) / PITCH_GRAN_PER_SUBFRAME; + filter_parameters.gain = old_gain; + /* Store for the next sub-frame. */ + old_lag = lags[m]; + old_gain = gains[m]; + + for (n = 0; n < PITCH_GRAN_PER_SUBFRAME; ++n) { + /* Step-wise interpolation of pitch gains and lags. As pitch-lag changes, + * some parameters of filter need to be update. */ + filter_parameters.gain += gain_delta; + filter_parameters.lag += lag_delta; + /* Update parameters according to new lag value. */ + Update(&filter_parameters); + /* Filter a segment of input. */ + FilterSegment(in_data, &filter_parameters, out_data, out_dg); + } + } + + if (mode != kPitchFilterPreGain) { + /* Export buffer and states. */ + memcpy(filter_state->ubuf, &filter_parameters.buffer[PITCH_FRAME_LEN], + sizeof(filter_state->ubuf)); + memcpy(filter_state->ystate, filter_parameters.damper_state, + sizeof(filter_state->ystate)); + + /* Store for the next frame. */ + *filter_state->oldlagp = old_lag; + *filter_state->oldgainp = old_gain; + } + + if ((mode == kPitchFilterPreGain) || (mode == kPitchFilterPreLa)) { + /* Filter the lookahead segment, this is treated as the last sub-frame. So + * set |pf_param| to last sub-frame. */ + filter_parameters.sub_frame = PITCH_SUBFRAMES - 1; + filter_parameters.num_samples = QLOOKAHEAD; + FilterSegment(in_data, &filter_parameters, out_data, out_dg); + } +} + +void WebRtcIsac_PitchfilterPre(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPre, out_data, NULL); +} + +void WebRtcIsac_PitchfilterPre_la(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreLa, out_data, + NULL); +} + +void WebRtcIsac_PitchfilterPre_gains( + double* in_data, double* out_data, + double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD], PitchFiltstr *pf_state, + double* lags, double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreGain, out_data, + out_dg); +} + +void WebRtcIsac_PitchfilterPost(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPost, out_data, NULL); }