Line data Source code
1 : /***********************************************************************
2 : Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3 : Redistribution and use in source and binary forms, with or without
4 : modification, are permitted provided that the following conditions
5 : are met:
6 : - Redistributions of source code must retain the above copyright notice,
7 : this list of conditions and the following disclaimer.
8 : - Redistributions in binary form must reproduce the above copyright
9 : notice, this list of conditions and the following disclaimer in the
10 : documentation and/or other materials provided with the distribution.
11 : - Neither the name of Internet Society, IETF or IETF Trust, nor the
12 : names of specific contributors, may be used to endorse or promote
13 : products derived from this software without specific prior written
14 : permission.
15 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 : AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 : IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 : ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 : LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 : CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 : SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 : INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 : CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 : ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 : POSSIBILITY OF SUCH DAMAGE.
26 : ***********************************************************************/
27 :
28 : #ifdef HAVE_CONFIG_H
29 : #include "config.h"
30 : #endif
31 :
32 : #include "main_FLP.h"
33 : #include "tuning_parameters.h"
34 :
35 : /* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
36 : /* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
37 : /* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
38 : /* coefficient in an array of coefficients, for monic filters. */
39 0 : static OPUS_INLINE silk_float warped_gain(
40 : const silk_float *coefs,
41 : silk_float lambda,
42 : opus_int order
43 : ) {
44 : opus_int i;
45 : silk_float gain;
46 :
47 0 : lambda = -lambda;
48 0 : gain = coefs[ order - 1 ];
49 0 : for( i = order - 2; i >= 0; i-- ) {
50 0 : gain = lambda * gain + coefs[ i ];
51 : }
52 0 : return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) );
53 : }
54 :
55 : /* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
56 : /* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
57 0 : static OPUS_INLINE void warped_true2monic_coefs(
58 : silk_float *coefs,
59 : silk_float lambda,
60 : silk_float limit,
61 : opus_int order
62 : ) {
63 0 : opus_int i, iter, ind = 0;
64 : silk_float tmp, maxabs, chirp, gain;
65 :
66 : /* Convert to monic coefficients */
67 0 : for( i = order - 1; i > 0; i-- ) {
68 0 : coefs[ i - 1 ] -= lambda * coefs[ i ];
69 : }
70 0 : gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] );
71 0 : for( i = 0; i < order; i++ ) {
72 0 : coefs[ i ] *= gain;
73 : }
74 :
75 : /* Limit */
76 0 : for( iter = 0; iter < 10; iter++ ) {
77 : /* Find maximum absolute value */
78 0 : maxabs = -1.0f;
79 0 : for( i = 0; i < order; i++ ) {
80 0 : tmp = silk_abs_float( coefs[ i ] );
81 0 : if( tmp > maxabs ) {
82 0 : maxabs = tmp;
83 0 : ind = i;
84 : }
85 : }
86 0 : if( maxabs <= limit ) {
87 : /* Coefficients are within range - done */
88 0 : return;
89 : }
90 :
91 : /* Convert back to true warped coefficients */
92 0 : for( i = 1; i < order; i++ ) {
93 0 : coefs[ i - 1 ] += lambda * coefs[ i ];
94 : }
95 0 : gain = 1.0f / gain;
96 0 : for( i = 0; i < order; i++ ) {
97 0 : coefs[ i ] *= gain;
98 : }
99 :
100 : /* Apply bandwidth expansion */
101 0 : chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) );
102 0 : silk_bwexpander_FLP( coefs, order, chirp );
103 :
104 : /* Convert to monic warped coefficients */
105 0 : for( i = order - 1; i > 0; i-- ) {
106 0 : coefs[ i - 1 ] -= lambda * coefs[ i ];
107 : }
108 0 : gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] );
109 0 : for( i = 0; i < order; i++ ) {
110 0 : coefs[ i ] *= gain;
111 : }
112 : }
113 0 : silk_assert( 0 );
114 : }
115 :
116 0 : static OPUS_INLINE void limit_coefs(
117 : silk_float *coefs,
118 : silk_float limit,
119 : opus_int order
120 : ) {
121 0 : opus_int i, iter, ind = 0;
122 : silk_float tmp, maxabs, chirp;
123 :
124 0 : for( iter = 0; iter < 10; iter++ ) {
125 : /* Find maximum absolute value */
126 0 : maxabs = -1.0f;
127 0 : for( i = 0; i < order; i++ ) {
128 0 : tmp = silk_abs_float( coefs[ i ] );
129 0 : if( tmp > maxabs ) {
130 0 : maxabs = tmp;
131 0 : ind = i;
132 : }
133 : }
134 0 : if( maxabs <= limit ) {
135 : /* Coefficients are within range - done */
136 0 : return;
137 : }
138 :
139 : /* Apply bandwidth expansion */
140 0 : chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) );
141 0 : silk_bwexpander_FLP( coefs, order, chirp );
142 : }
143 0 : silk_assert( 0 );
144 : }
145 :
146 : /* Compute noise shaping coefficients and initial gain values */
147 0 : void silk_noise_shape_analysis_FLP(
148 : silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
149 : silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
150 : const silk_float *pitch_res, /* I LPC residual from pitch analysis */
151 : const silk_float *x /* I Input signal [frame_length + la_shape] */
152 : )
153 : {
154 0 : silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
155 : opus_int k, nSamples, nSegs;
156 : silk_float SNR_adj_dB, HarmShapeGain, Tilt;
157 : silk_float nrg, log_energy, log_energy_prev, energy_variation;
158 : silk_float BWExp, gain_mult, gain_add, strength, b, warping;
159 : silk_float x_windowed[ SHAPE_LPC_WIN_MAX ];
160 : silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
161 : silk_float rc[ MAX_SHAPE_LPC_ORDER + 1 ];
162 : const silk_float *x_ptr, *pitch_res_ptr;
163 :
164 : /* Point to start of first LPC analysis block */
165 0 : x_ptr = x - psEnc->sCmn.la_shape;
166 :
167 : /****************/
168 : /* GAIN CONTROL */
169 : /****************/
170 0 : SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f );
171 :
172 : /* Input quality is the average of the quality in the lowest two VAD bands */
173 0 : psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f );
174 :
175 : /* Coding quality level, between 0.0 and 1.0 */
176 0 : psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) );
177 :
178 0 : if( psEnc->sCmn.useCBR == 0 ) {
179 : /* Reduce coding SNR during low speech activity */
180 0 : b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
181 0 : SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b;
182 : }
183 :
184 0 : if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
185 : /* Reduce gains for periodic signals */
186 0 : SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr;
187 : } else {
188 : /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
189 0 : SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality );
190 : }
191 :
192 : /*************************/
193 : /* SPARSENESS PROCESSING */
194 : /*************************/
195 : /* Set quantizer offset */
196 0 : if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
197 : /* Initially set to 0; may be overruled in process_gains(..) */
198 0 : psEnc->sCmn.indices.quantOffsetType = 0;
199 : } else {
200 : /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
201 0 : nSamples = 2 * psEnc->sCmn.fs_kHz;
202 0 : energy_variation = 0.0f;
203 0 : log_energy_prev = 0.0f;
204 0 : pitch_res_ptr = pitch_res;
205 0 : nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2;
206 0 : for( k = 0; k < nSegs; k++ ) {
207 0 : nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples );
208 0 : log_energy = silk_log2( nrg );
209 0 : if( k > 0 ) {
210 0 : energy_variation += silk_abs_float( log_energy - log_energy_prev );
211 : }
212 0 : log_energy_prev = log_energy;
213 0 : pitch_res_ptr += nSamples;
214 : }
215 :
216 : /* Set quantization offset depending on sparseness measure */
217 0 : if( energy_variation > ENERGY_VARIATION_THRESHOLD_QNT_OFFSET * (nSegs-1) ) {
218 0 : psEnc->sCmn.indices.quantOffsetType = 0;
219 : } else {
220 0 : psEnc->sCmn.indices.quantOffsetType = 1;
221 : }
222 : }
223 :
224 : /*******************************/
225 : /* Control bandwidth expansion */
226 : /*******************************/
227 : /* More BWE for signals with high prediction gain */
228 0 : strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */
229 0 : BWExp = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength );
230 :
231 : /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
232 0 : warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality;
233 :
234 : /********************************************/
235 : /* Compute noise shaping AR coefs and gains */
236 : /********************************************/
237 0 : for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
238 : /* Apply window: sine slope followed by flat part followed by cosine slope */
239 : opus_int shift, slope_part, flat_part;
240 0 : flat_part = psEnc->sCmn.fs_kHz * 3;
241 0 : slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2;
242 :
243 0 : silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part );
244 0 : shift = slope_part;
245 0 : silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) );
246 0 : shift += flat_part;
247 0 : silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part );
248 :
249 : /* Update pointer: next LPC analysis block */
250 0 : x_ptr += psEnc->sCmn.subfr_length;
251 :
252 0 : if( psEnc->sCmn.warping_Q16 > 0 ) {
253 : /* Calculate warped auto correlation */
254 0 : silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping,
255 : psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
256 : } else {
257 : /* Calculate regular auto correlation */
258 0 : silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 );
259 : }
260 :
261 : /* Add white noise, as a fraction of energy */
262 0 : auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION + 1.0f;
263 :
264 : /* Convert correlations to prediction coefficients, and compute residual energy */
265 0 : nrg = silk_schur_FLP( rc, auto_corr, psEnc->sCmn.shapingLPCOrder );
266 0 : silk_k2a_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], rc, psEnc->sCmn.shapingLPCOrder );
267 0 : psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg );
268 :
269 0 : if( psEnc->sCmn.warping_Q16 > 0 ) {
270 : /* Adjust gain for warping */
271 0 : psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder );
272 : }
273 :
274 : /* Bandwidth expansion for synthesis filter shaping */
275 0 : silk_bwexpander_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp );
276 :
277 0 : if( psEnc->sCmn.warping_Q16 > 0 ) {
278 : /* Convert to monic warped prediction coefficients and limit absolute values */
279 0 : warped_true2monic_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, 3.999f, psEnc->sCmn.shapingLPCOrder );
280 : } else {
281 : /* Limit absolute values */
282 0 : limit_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], 3.999f, psEnc->sCmn.shapingLPCOrder );
283 : }
284 : }
285 :
286 : /*****************/
287 : /* Gain tweaking */
288 : /*****************/
289 : /* Increase gains during low speech activity */
290 0 : gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB );
291 0 : gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB );
292 0 : for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
293 0 : psEncCtrl->Gains[ k ] *= gain_mult;
294 0 : psEncCtrl->Gains[ k ] += gain_add;
295 : }
296 :
297 : /************************************************/
298 : /* Control low-frequency shaping and noise tilt */
299 : /************************************************/
300 : /* Less low frequency shaping for noisy inputs */
301 0 : strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) );
302 0 : strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
303 0 : if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
304 : /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
305 : /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
306 0 : for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
307 0 : b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ];
308 0 : psEncCtrl->LF_MA_shp[ k ] = -1.0f + b;
309 0 : psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength;
310 : }
311 0 : Tilt = - HP_NOISE_COEF -
312 0 : (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
313 : } else {
314 0 : b = 1.3f / psEnc->sCmn.fs_kHz;
315 0 : psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b;
316 0 : psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f;
317 0 : for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
318 0 : psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ];
319 0 : psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ];
320 : }
321 0 : Tilt = -HP_NOISE_COEF;
322 : }
323 :
324 : /****************************/
325 : /* HARMONIC SHAPING CONTROL */
326 : /****************************/
327 0 : if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
328 : /* Harmonic noise shaping */
329 0 : HarmShapeGain = HARMONIC_SHAPING;
330 :
331 : /* More harmonic noise shaping for high bitrates or noisy input */
332 0 : HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING *
333 0 : ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality );
334 :
335 : /* Less harmonic noise shaping for less periodic signals */
336 0 : HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr );
337 : } else {
338 0 : HarmShapeGain = 0.0f;
339 : }
340 :
341 : /*************************/
342 : /* Smooth over subframes */
343 : /*************************/
344 0 : for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
345 0 : psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth );
346 0 : psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth;
347 0 : psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth );
348 0 : psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth;
349 : }
350 0 : }
|