Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : #include <stdint.h>
34 : #include <math.h>
35 : #include "options.h"
36 : #ifdef DEBUGGING
37 : #include "debug.h"
38 : #endif
39 : #include "cnst.h"
40 : #include "rom_com.h"
41 : #include "prot_fx.h"
42 : #include "ivas_rom_com.h"
43 : #include "ivas_rom_enc.h"
44 : #include "ivas_cnst.h"
45 : #include "wmc_auto.h"
46 : #include "ivas_prot_fx.h"
47 :
48 : /*-------------------------------------------------------------------*
49 : * Local constants
50 : *-------------------------------------------------------------------*/
51 :
52 : #define RC_FACT_UP 0.3f
53 : #define RC_FACT_UP_Q31 644245094
54 : #define RC_FACT_DOWN 0.7f
55 : #define RC_FACT_DOWN_Q31 1503238554
56 : #define UNCLR_SCORE_THR 4.0f
57 : #define UNCLR_SCORE_THR_Q28 ( 1073741824 )
58 : #define XTALK_SCORE_THR_DFT 4.0f
59 : #define XTALK_SCORE_THR_DFT_Q27 ( 1 << 29 )
60 : #define XTALK_SCORE_THR_TD_UP 3.0f
61 : #define XTALK_SCORE_THR_TD_UP_Q28 ( 805306368 )
62 : #define ONE_BY_XTALK_SCORE_THR_TD_UP_Q31 ( 715827882 )
63 : #define XTALK_SCORE_THR_TD_DN 4.0f
64 : #define XTALK_SCORE_THR_TD_DN_Q28 ( 1073741824 )
65 : #define ONE_BY_XTALK_SCORE_THR_TD_DN_Q31 ( 536870912 )
66 :
67 : #define UNCLR_INTERCEPT_TD 0.780313f
68 : #define UNCLR_INTERCEPT_TD_Q28 ( 209463676 )
69 : #define UNCLR_INTERCEPT_DFT 1.226513f
70 : #define UNCLR_INTERCEPT_DFT_Q30 1316958306
71 : #define XTALK_INTERCEPT_TD -1.770983f
72 : #define XTALK_INTERCEPT_TD_Q28 ( -475394629 )
73 : #define XTALK_INTERCEPT_DFT -0.758556f
74 : #define XTALK_INTERCEPT_DFT_Q31 -1628986606
75 : #define XTALK_INTERCEPT_DFT_Q27 -101811663
76 :
77 : #define EDGE_MAX_LEN 30 /* maximum length of buffer for edge detection */
78 : #define REDGE_MAX_LEN 30 /* maximum length of buffer for rising edge detection */
79 :
80 : #define CLASSIFIER_ITD_THRES 8 /* ITD threshold in samples that enables classifier to switch */
81 :
82 :
83 : /*-------------------------------------------------------------------*
84 : * Local function prototypes
85 : *-------------------------------------------------------------------*/
86 : static void rc_filter_fx( const Word32 x, Word32 *y, const Word16 order, const Word32 tau );
87 : static void edge_detect_fx( const Word32 *inp, const Word16 len, const Word32 inp_min, const Word32 inp_max, Word16 *edge_str, Word16 *edge_type );
88 :
89 : static Word32 redge_detect_fx( const Word32 *inp, const Word16 len, const Word32 inp_min, const Word32 inp_max, Word16 *edge_min_e );
90 :
91 : /*-------------------------------------------------------------------*
92 : * Function select_stereo_mode_fx()
93 : *
94 : * Select stereo technology based on output of stereo classifiers
95 : *-------------------------------------------------------------------*/
96 :
97 : /*! r: element mode */
98 148636 : Word16 select_stereo_mode_fx(
99 : CPE_ENC_HANDLE hCPE, /* i/o: CPE encoder structure */
100 : const IVAS_FORMAT ivas_format /* i : IVAS format */
101 : )
102 : {
103 : Word16 element_mode;
104 : STEREO_CLASSIF_HANDLE hStereoClassif;
105 : Word16 is_speech;
106 : Word16 stereo_switching_flag;
107 :
108 : /* initialization */
109 148636 : element_mode = hCPE->element_mode;
110 148636 : hStereoClassif = hCPE->hStereoClassif;
111 :
112 : /* set binary flag to prevent LRTD mode on music */
113 148636 : hStereoClassif->is_speech_fx = L_add( Mpy_32_32( hStereoClassif->is_speech_fx, 2083059139 ), Mpy_32_16_1( 64424509, hCPE->hCoreCoder[0]->hSpMusClas->past_dlp_fx[0] ) ); /* (((Q25*Q31) << 1) >> 32) -> Q25 + (((Q31*Q9) << 1) >> 16) -> Q25*/
114 148636 : move32();
115 148636 : is_speech = ( LT_32( hStereoClassif->is_speech_fx, ONE_IN_Q25 ) && hCPE->hCoreCoder[0]->hSpMusClas->wdlp_xtalk_fx < 0 );
116 148636 : move16();
117 :
118 : /* set binary flag indicating LRTD mode based on unclr/xtalk classifiers' decisions */
119 148636 : hStereoClassif->prev_lrtd_mode = hStereoClassif->lrtd_mode;
120 148636 : move16();
121 148636 : hStereoClassif->unclr_decision = ( hStereoClassif->unclr_decision && hCPE->hCoreCoder[0]->flag_noisy_speech_snr == 0 && GT_32( hCPE->element_brate, IVAS_16k4 ) );
122 148636 : move16();
123 148636 : hStereoClassif->lrtd_mode = ( ( hStereoClassif->unclr_decision | hStereoClassif->xtalk_decision ) && is_speech );
124 148636 : move16();
125 :
126 148636 : stereo_switching_flag = 1;
127 148636 : move16();
128 :
129 148636 : test();
130 148636 : test();
131 148636 : test();
132 : #ifdef DEBUGGING
133 : IF( GE_32( hCPE->element_brate, MIN_BRATE_MDCT_STEREO ) || ( ( ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) && LT_32( hCPE->element_brate, MASA_STEREO_MIN_BITRATE ) ) ) || ( hCPE->stereo_mode_cmdl == IVAS_CPE_DFT || hCPE->stereo_mode_cmdl == IVAS_CPE_TD ) )
134 : #else
135 160571 : if ( GE_32( hCPE->element_brate, MIN_BRATE_MDCT_STEREO ) || ( ( ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) &&
136 11935 : LT_32( hCPE->element_brate, MASA_STEREO_MIN_BITRATE ) ) ) )
137 : #endif
138 : {
139 91141 : stereo_switching_flag = 0;
140 91141 : move16();
141 : }
142 148636 : test();
143 148636 : IF( GE_32( hCPE->element_brate, MIN_BRATE_MDCT_STEREO ) )
144 : {
145 85265 : hStereoClassif->prev_lrtd_mode = 0;
146 85265 : move16();
147 85265 : hStereoClassif->lrtd_mode = 0;
148 85265 : move16();
149 85265 : element_mode = IVAS_CPE_MDCT;
150 85265 : move16();
151 : }
152 63371 : ELSE IF( LT_32( hCPE->element_brate, MIN_BRATE_MDCT_STEREO ) && EQ_16( hCPE->last_element_mode, IVAS_CPE_MDCT ) )
153 : {
154 732 : hStereoClassif->lrtd_mode = 0;
155 732 : move16();
156 732 : element_mode = IVAS_CPE_DFT;
157 732 : move16();
158 732 : test();
159 732 : test();
160 732 : test();
161 732 : test();
162 732 : test();
163 732 : test();
164 732 : IF( EQ_16( stereo_switching_flag, 1 ) && GT_32( hCPE->element_brate, IVAS_13k2 ) && LT_16( hCPE->hCoreCoder[0]->hSpMusClas->past_dlp_fx[0], ONE_IN_Q9 ) && LT_32( hCPE->hCoreCoder[0]->hSpMusClas->wdlp_xtalk_fx, -335544 /* -0.01 in Q25 */ ) && EQ_16( hCPE->hCoreCoder[0]->vad_flag, 1 ) && ( hCPE->hStereoMdct->sw_uncorr || hStereoClassif->xtalk_decision ) )
165 : {
166 8 : hStereoClassif->lrtd_mode = 1;
167 8 : move16();
168 8 : element_mode = IVAS_CPE_TD;
169 8 : move16();
170 : }
171 : }
172 :
173 : /* set the element mode */
174 148636 : test();
175 148636 : IF( EQ_16( hStereoClassif->lrtd_mode, 1 ) && EQ_16( stereo_switching_flag, 1 ) )
176 : {
177 4038 : element_mode = IVAS_CPE_TD;
178 4038 : move16();
179 : }
180 144598 : ELSE IF( LT_16( element_mode, IVAS_CPE_MDCT ) )
181 : {
182 59333 : IF( EQ_16( stereo_switching_flag, 0 ) )
183 : {
184 5876 : test();
185 5876 : test();
186 5876 : if ( ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) && LT_32( hCPE->element_brate, MASA_STEREO_MIN_BITRATE ) )
187 : {
188 5876 : element_mode = IVAS_CPE_DFT;
189 5876 : move16();
190 : }
191 : #ifdef DEBUGGING
192 : if ( hCPE->stereo_mode_cmdl > 1 )
193 : {
194 : element_mode = hCPE->stereo_mode_cmdl;
195 : }
196 : #endif
197 : }
198 53457 : ELSE IF( EQ_16( element_mode, IVAS_CPE_TD ) )
199 : {
200 21 : test();
201 21 : IF( hCPE->hStereoTD->prev_fr_LRTD_TD_dec > 0 && is_speech )
202 : {
203 : /* if unclr_decision goes from 1->0 on active content, continue in LRTD mode */
204 19 : hStereoClassif->lrtd_mode = 1;
205 19 : move16();
206 : }
207 2 : ELSE IF( EQ_16( stereo_switching_flag, 1 ) )
208 : {
209 2 : element_mode = IVAS_CPE_DFT;
210 2 : move16();
211 : }
212 : }
213 53436 : ELSE IF( EQ_16( stereo_switching_flag, 1 ) )
214 : {
215 53436 : element_mode = IVAS_CPE_DFT;
216 53436 : move16();
217 : }
218 : }
219 :
220 : /* switch from LRTD to DFT when xtalk_decision goes from 0->1 (note: this special case is not handled in the xtalk classifier) */
221 148636 : test();
222 148636 : test();
223 148636 : IF( EQ_16( hCPE->last_element_mode, IVAS_CPE_TD ) && EQ_16( element_mode, IVAS_CPE_TD ) && EQ_16( hStereoClassif->xtalk_decision, 1 ) )
224 : {
225 2094 : test();
226 2094 : test();
227 2094 : test();
228 2094 : test();
229 2094 : test();
230 2094 : IF( hCPE->hStereoTD->prev_fr_LRTD_TD_dec == 0 && GT_16( hCPE->hStereoTD->tdm_FD2LRTD_SW_cnt, 15 ) && GT_16( hCPE->hStereoTD->tdm_last_LRTD_frame_cnt, 3 ) && LT_16( hCPE->hCoreCoder[0]->clas, VOICED_CLAS ) && ( GE_32( hCPE->element_brate, IVAS_16k4 ) || LT_32( hStereoClassif->xtalk_wscore_fx, 21474836 /*0.01f in Q31*/ ) ) )
231 : {
232 19 : if ( EQ_16( stereo_switching_flag, 1 ) )
233 : {
234 19 : element_mode = IVAS_CPE_DFT;
235 19 : move16();
236 : }
237 19 : hStereoClassif->xtalk_decision = 0;
238 19 : move16();
239 19 : hStereoClassif->lrtd_mode = 0;
240 19 : move16();
241 : }
242 : }
243 :
244 : #ifdef DEBUG_FORCE_DIR
245 : if ( hCPE->hCoreCoder[0]->force_dir[0] != '\0' )
246 : {
247 : dbgread( &element_mode, sizeof( int16_t ), 1, fname( hCPE->hCoreCoder[0]->force_dir, "force_element_mode.enf", -1, -1, -1 ) );
248 : }
249 : else
250 : {
251 : dbgwrite( &element_mode, sizeof( int16_t ), 1, 1, "res/force_element_mode.enf" );
252 : }
253 : #endif
254 :
255 148636 : IF( NE_16( hCPE->last_element_mode, element_mode ) )
256 : {
257 1742 : test();
258 1742 : IF( NE_16( hCPE->last_element_mode, IVAS_CPE_DFT ) && NE_16( hCPE->last_element_mode, IVAS_CPE_TD ) )
259 732 : {
260 732 : Word16 lrtd_mode = hStereoClassif->lrtd_mode;
261 732 : move16();
262 :
263 : /* reset stereo classifier when switching from MDCT stereo to Unified stereo */
264 732 : stereo_classifier_init_fx( hCPE->hStereoClassif );
265 732 : hStereoClassif->lrtd_mode = lrtd_mode;
266 732 : move16();
267 : }
268 : ELSE
269 : {
270 : /* reset UNCLR classifier parameters */
271 1010 : set32_fx( hStereoClassif->unclr_fv_fx, -MAX_16, SSC_MAX_NFEA );
272 1010 : hStereoClassif->unclr_corrLagMax_prev = 0;
273 1010 : move16();
274 :
275 : /* reset xtalk classifier parameters */
276 1010 : set32_fx( hStereoClassif->xtalk_fv_fx, -MAX_16, SSC_MAX_NFEA );
277 : }
278 : }
279 148636 : test();
280 148636 : IF( EQ_16( element_mode, IVAS_CPE_TD ) && hCPE->hCoreCoder[0]->Opt_DTX_ON )
281 : {
282 1880 : hCPE->hStereoCng->td_active = 1;
283 1880 : move16();
284 1880 : hCPE->hStereoCng->first_SID_after_TD = 1;
285 1880 : move16();
286 : }
287 :
288 148636 : return ( element_mode );
289 : }
290 :
291 : /*-------------------------------------------------------------------*
292 : * Function stereo_classifier_init_fx()
293 : *
294 : * Initialize stereo classifier handle
295 : *-------------------------------------------------------------------*/
296 :
297 3344 : void stereo_classifier_init_fx(
298 : STEREO_CLASSIF_HANDLE hStereoClassif /* i/o: stereo classifier structure */
299 : )
300 : {
301 : /* initialization of features for xtalk classifier and UNCLR classifier */
302 3344 : hStereoClassif->clas_ch1 = 0;
303 3344 : move16();
304 3344 : set16_fx( hStereoClassif->pitch_ch1, 0, 3 );
305 3344 : set16_fx( hStereoClassif->voicing_ch1_fx, 0, 3 );
306 3344 : hStereoClassif->cor_map_sum_ch1_fx = 0;
307 3344 : move32();
308 3344 : set16_fx( hStereoClassif->lsf_ch1_fx, 0, M );
309 3344 : hStereoClassif->lepsP_ch1_fx = 0;
310 3344 : move32();
311 3344 : hStereoClassif->dE1_ch1_fx = 0;
312 3344 : move32();
313 3344 : hStereoClassif->dE1_ch1_e = 0;
314 3344 : move16();
315 3344 : hStereoClassif->dE1_ch2_fx = 0;
316 3344 : move32();
317 3344 : hStereoClassif->dE1_ch2_e = 0;
318 3344 : move16();
319 3344 : hStereoClassif->nchar_ch1_fx = 0;
320 3344 : move32();
321 3344 : hStereoClassif->nchar_ch1_e = 0;
322 3344 : move16();
323 3344 : hStereoClassif->nchar_ch2_fx = 0;
324 3344 : move32();
325 3344 : hStereoClassif->nchar_ch2_e = 0;
326 3344 : move16();
327 3344 : hStereoClassif->non_sta_ch1_fx = 0;
328 3344 : move32();
329 3344 : hStereoClassif->non_sta_ch1_e = 0;
330 3344 : move16();
331 3344 : hStereoClassif->sp_div_ch1_fx = 0;
332 3344 : move32();
333 3344 : hStereoClassif->ps_diff_ch1_fx = 0;
334 3344 : move32();
335 3344 : hStereoClassif->ps_diff_ch1_e = 0;
336 3344 : move16();
337 3344 : hStereoClassif->ps_diff_ch2_fx = 0;
338 3344 : move32();
339 3344 : hStereoClassif->ps_diff_ch2_e = 0;
340 3344 : move16();
341 3344 : hStereoClassif->ps_sta_ch1_fx = 0;
342 3344 : move32();
343 3344 : hStereoClassif->ps_sta_ch1_e = 0;
344 3344 : move16();
345 3344 : hStereoClassif->ps_sta_ch2_fx = 0;
346 3344 : move32();
347 3344 : hStereoClassif->ps_sta_ch2_e = 0;
348 3344 : move16();
349 3344 : hStereoClassif->prev_g_IPD_fx = ONE_IN_Q28; // 0.5f in Q29
350 3344 : move32();
351 3344 : hStereoClassif->prev_IPD_fx = 0; // Q29
352 3344 : move32();
353 3344 : hStereoClassif->prev_ratio_m1_m2_fx = 0; // Q31
354 3344 : move32();
355 3344 : set_zero_fx( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN );
356 3344 : hStereoClassif->ratio_L_fx = ONE_IN_Q30; // 0.5f in Q31
357 3344 : move32();
358 3344 : hStereoClassif->ratio_L_e = 0; // Q31
359 3344 : move16();
360 3344 : hStereoClassif->vad_flag_glob = 0;
361 3344 : move16();
362 3344 : hStereoClassif->vad_relE = 0;
363 3344 : move16();
364 3344 : hStereoClassif->is_speech_fx = 0; // Q25
365 3344 : move32();
366 :
367 3344 : set16_fx( hStereoClassif->aEn_raw, 0, CPE_CHANNELS );
368 :
369 3344 : hStereoClassif->Etot_dn_fx = 0;
370 3344 : move32();
371 3344 : hStereoClassif->Etot_dn_e = 0;
372 3344 : move16();
373 3344 : hStereoClassif->Etot_up_fx = 0;
374 3344 : move32();
375 3344 : hStereoClassif->Etot_up_e = 0;
376 3344 : move16();
377 :
378 3344 : set_zero_fx( hStereoClassif->relE_buf_fx, UNCLR_L_RELE );
379 3344 : set_zero_fx( hStereoClassif->Etot_buf_fx, UNCLR_L_ETOT );
380 3344 : hStereoClassif->e_Etot_buf_fx = 0;
381 3344 : move16();
382 3344 : set_zero_fx( hStereoClassif->unclr_relE_0_1_LT_fx, UNCLR_RC_ORDER );
383 :
384 3344 : hStereoClassif->unclr_sw_enable_cnt[0] = 0;
385 3344 : move16();
386 3344 : hStereoClassif->unclr_sw_enable_cnt[1] = 0;
387 3344 : move16();
388 :
389 3344 : hStereoClassif->unclr_decision = 0;
390 3344 : move16();
391 3344 : hStereoClassif->unclr_wscore_fx = 0;
392 3344 : move32();
393 :
394 3344 : set32_fx( hStereoClassif->unclr_fv_fx, -ONE_IN_Q15, SSC_MAX_NFEA ); // Q15
395 3344 : hStereoClassif->unclr_corrLagMax_prev = 0;
396 3344 : move16();
397 3344 : hStereoClassif->ave_ener_L_fx = 0;
398 3344 : move32();
399 3344 : hStereoClassif->ave_ener_L_fx_e = 0;
400 3344 : move16();
401 3344 : hStereoClassif->ave_ener_R_fx = 0;
402 3344 : move32();
403 3344 : hStereoClassif->ave_ener_R_fx_e = 0;
404 3344 : move16();
405 3344 : hStereoClassif->relE_0_1_fx = 21474836; // 0.01f in Q31
406 3344 : move32();
407 3344 : hStereoClassif->relE_0_1_LT_fx = 21474836; // 0.01f in Q31
408 3344 : move32();
409 :
410 3344 : set32_fx( hStereoClassif->xtalk_fv_fx, -ONE_IN_Q15, SSC_MAX_NFEA ); // Q15
411 3344 : hStereoClassif->xtalk_wscore_fx = 0; // Q31
412 3344 : move32();
413 3344 : hStereoClassif->xtalk_decision = 0;
414 3344 : move16();
415 3344 : hStereoClassif->xtalk_score_wrelE_fx = 0; // Q31
416 3344 : move32();
417 :
418 3344 : hStereoClassif->lrtd_mode = 0;
419 3344 : move16();
420 3344 : hStereoClassif->prev_lrtd_mode = 0;
421 3344 : move16();
422 :
423 3344 : hStereoClassif->silence_flag = 0;
424 3344 : move16();
425 :
426 3344 : return;
427 : }
428 :
429 :
430 : /*-----------------------------------------------------------------*
431 : * stereo_classifier_features()
432 : *
433 : * Collect features for stereo classifiers
434 : *-----------------------------------------------------------------*/
435 : /* Information on ouputs:
436 : hStereoClassif->Etot_buf_fx has expoenent hStereoClassif->e_Etot_buf_fx
437 : hStereoClassif->lsf_ch1_fx has Q1*1.28
438 : hStereoClassif->xtalk_fv_fx has exponent 16
439 : hStereoClassif->voicing_ch1_fx has Q-factor Q15
440 : hStereoClassif->lepsP_ch1_fx has exponent 16
441 : hStereoClassif->Etot_up_fx has exponent hStereoClassif->Etot_up_e
442 : hStereoClassif->Etot_dn_fx has exponent hStereoClassif->Etot_dn_e
443 : hStereoClassif->cor_map_sum_ch1_fx has exponent hStereoClassif->cor_map_sum_ch1_e
444 : hStereoClassif->non_sta_ch1_fx has exponent hStereoClassif->non_sta_ch1_e
445 : hStereoClassif->sp_div_ch1_fx has exponent sp_div_e
446 : hStereoClassif->nchar_ch1_fx has exponent hStereoClassif->nchar_ch1_e
447 : hStereoClassif->nchar_ch2_fx has exponent hStereoClassif->nchar_ch2_e
448 : hStereoClassif->dE1_ch1_fx has exponent hStereoClassif->dE1_ch1_e
449 : hStereoClassif->dE1_ch2_fx has exponent hStereoClassif->dE1_ch2_e
450 : hStereoClassif->ps_diff_ch1_fx has exponent hStereoClassif->ps_diff_ch1_e
451 : hStereoClassif->ps_sta_ch1_fx has exponent hStereoClassif->ps_sta_ch1_e
452 : hStereoClassif->ps_diff_ch2_fx has exponent hStereoClassif->ps_diff_ch2_e
453 : hStereoClassif->ps_sta_ch2_fx has exponent hStereoClassif->ps_sta_ch2_e
454 : */
455 760867 : void stereo_classifier_features_ivas_fx(
456 : STEREO_CLASSIF_HANDLE hStereoClassif, /* i/o: stereo classifier structure */
457 : const Word16 idchan, /* i : channel ID */
458 : const Word16 element_mode, /* i : element mode */
459 : const Word16 vad_flag, /* i : VAD flag */
460 : Word16 lsf_new_fx[], /* i : LSFs at the end of the frame Q1*1.28 */
461 : Word32 epsP_fx[], /* i : LP analysis residual energies for each iteration*/
462 : Word16 pitch[], /* i : open-loop pitch values for quantiz. Q0 */
463 : Word16 voicing_fx[], /* i : OL maximum normalized correlation Q15 */
464 : Word32 cor_map_sum_fx, /* i : speech/music clasif. parameter Q(31-cor_map_sum_e) */
465 : Word32 non_staX_fx, /* i : unbound non-stationarity for sp/mu clas. Q(31-non_staX_e) */
466 : Word16 sp_div_fx, /* i : spectral diversity feature Q(15-sp_div_e) */
467 : const Word16 clas, /* i : signal class */
468 : Word16 epsP_e, /*exponent for epsP_fx */
469 : Word16 cor_map_sum_e, /*exponent for cor_map_sum_fx */
470 : Word16 non_staX_e, /*exponent for non_staX_fx */
471 : Word16 sp_div_e /*exponent for sp_div_fx */
472 : )
473 : {
474 : Word16 i, clas_ch2;
475 : Word16 ener_e;
476 :
477 : Word32 lepsP_ch2_fx, ener_l_fx, ener_r_fx;
478 : Word32 L_tmp;
479 : Word16 exp;
480 : /* combine VAD flags from both channels */
481 760867 : IF( idchan == 0 )
482 : {
483 410255 : hStereoClassif->vad_flag_glob = vad_flag;
484 : }
485 : ELSE
486 : {
487 350612 : hStereoClassif->vad_flag_glob = s_or( hStereoClassif->vad_flag_glob, vad_flag );
488 : }
489 760867 : move16();
490 :
491 760867 : test();
492 760867 : test();
493 760867 : test();
494 760867 : IF( ( EQ_16( element_mode, IVAS_CPE_DFT ) && idchan == 0 ) || ( EQ_16( element_mode, IVAS_CPE_TD ) && EQ_16( idchan, 1 ) ) )
495 : {
496 : /* making negative exponent zero as we are using this exponent to scale 1 in next block*/
497 63470 : IF( hStereoClassif->ave_ener_L_fx_e < 0 )
498 : {
499 467 : hStereoClassif->ave_ener_L_fx = L_shl( hStereoClassif->ave_ener_L_fx, hStereoClassif->ave_ener_L_fx_e );
500 467 : hStereoClassif->ave_ener_L_fx_e = 0;
501 : }
502 63470 : IF( hStereoClassif->ave_ener_R_fx_e < 0 )
503 : {
504 468 : hStereoClassif->ave_ener_R_fx = L_shl( hStereoClassif->ave_ener_R_fx, hStereoClassif->ave_ener_R_fx_e );
505 468 : hStereoClassif->ave_ener_R_fx_e = 0;
506 : }
507 63470 : move32();
508 63470 : move16();
509 : /* update Etot_up and Etot_dn based on aEn */
510 63470 : exp = norm_l( hStereoClassif->ave_ener_L_fx );
511 63470 : if ( sub( hStereoClassif->ave_ener_L_fx_e, exp ) < 0 )
512 : {
513 774 : exp = hStereoClassif->ave_ener_L_fx_e;
514 774 : move16();
515 : }
516 63470 : hStereoClassif->ave_ener_L_fx = L_shl( hStereoClassif->ave_ener_L_fx, exp );
517 63470 : move32();
518 63470 : hStereoClassif->ave_ener_L_fx_e = sub( hStereoClassif->ave_ener_L_fx_e, exp );
519 63470 : move16();
520 63470 : exp = norm_l( hStereoClassif->ave_ener_R_fx );
521 63470 : if ( sub( hStereoClassif->ave_ener_R_fx_e, exp ) < 0 )
522 : {
523 656 : exp = hStereoClassif->ave_ener_R_fx_e;
524 656 : move16();
525 : }
526 63470 : hStereoClassif->ave_ener_R_fx = L_shl( hStereoClassif->ave_ener_R_fx, exp );
527 63470 : move32();
528 63470 : hStereoClassif->ave_ener_R_fx_e = sub( hStereoClassif->ave_ener_R_fx_e, exp );
529 63470 : move16();
530 63470 : ener_l_fx = Mpy_32_16_1( BASOP_Util_Log10( L_add( L_shr( hStereoClassif->ave_ener_L_fx, 1 ), L_shr( ONE_IN_Q30, hStereoClassif->ave_ener_L_fx_e ) ), hStereoClassif->ave_ener_L_fx_e + 1 ), 10 << 11 ); /*q21*/
531 63470 : ener_r_fx = Mpy_32_16_1( BASOP_Util_Log10( L_add( L_shr( hStereoClassif->ave_ener_R_fx, 1 ), L_shr( ONE_IN_Q30, hStereoClassif->ave_ener_R_fx_e ) ), hStereoClassif->ave_ener_R_fx_e + 1 ), 10 << 11 ); /*q21*/
532 63470 : ener_e = 10;
533 63470 : move16();
534 :
535 : /*scaling Etot_buf_fx,Etot_up_fx and Etot_dn_fx to exponent ener_e*/
536 63470 : exp = L_norm_arr( hStereoClassif->Etot_buf_fx, 3 );
537 63470 : exp = s_min( exp, L_norm_arr( &hStereoClassif->Etot_up_fx, 1 ) );
538 63470 : exp = s_min( exp, L_norm_arr( &hStereoClassif->Etot_dn_fx, 1 ) );
539 :
540 63470 : Copy32( &hStereoClassif->Etot_buf_fx[0], &hStereoClassif->Etot_buf_fx[1], UNCLR_L_ETOT - 1 );
541 63470 : IF( GE_16( sub( hStereoClassif->e_Etot_buf_fx, exp ), ener_e ) )
542 : {
543 0 : hStereoClassif->Etot_buf_fx[0] = L_shl( L_max( 0, L_max( ener_l_fx, ener_r_fx ) ), sub( ener_e, hStereoClassif->e_Etot_buf_fx ) ); /*scaling from q25 to 31-e_Etot_buf_fx*/
544 0 : move32();
545 : }
546 : ELSE
547 : {
548 : /*scaling Etot_buf_fx,Etot_up_fx and Etot_dn_fx to exponent ener_e*/
549 63470 : hStereoClassif->Etot_buf_fx[0] = L_max( 0, L_max( ener_l_fx, ener_r_fx ) );
550 63470 : hStereoClassif->Etot_buf_fx[1] = L_shr( hStereoClassif->Etot_buf_fx[1], sub( ener_e, hStereoClassif->e_Etot_buf_fx ) );
551 63470 : hStereoClassif->Etot_buf_fx[2] = L_shr( hStereoClassif->Etot_buf_fx[2], sub( ener_e, hStereoClassif->e_Etot_buf_fx ) );
552 63470 : hStereoClassif->Etot_up_fx = L_shr( hStereoClassif->Etot_up_fx, sub( ener_e, hStereoClassif->e_Etot_buf_fx ) );
553 63470 : hStereoClassif->Etot_dn_fx = L_shr( hStereoClassif->Etot_dn_fx, sub( ener_e, hStereoClassif->e_Etot_buf_fx ) );
554 63470 : hStereoClassif->e_Etot_buf_fx = ener_e;
555 63470 : move32();
556 63470 : move32();
557 63470 : move32();
558 63470 : move32();
559 63470 : move32();
560 63470 : move16();
561 : }
562 :
563 63470 : test();
564 63470 : test();
565 63470 : test();
566 63470 : test();
567 63470 : test();
568 63470 : test();
569 63470 : IF( EQ_16( hStereoClassif->aEn_raw[0], 6 ) || ( EQ_16( element_mode, IVAS_CPE_TD ) && EQ_16( hStereoClassif->aEn_raw[1], 6 ) ) )
570 : {
571 : /* active signal, update upper bound */
572 40053 : IF( LT_32( hStereoClassif->Etot_buf_fx[0], hStereoClassif->Etot_up_fx ) )
573 : {
574 : /* energy decreases -> slower update */
575 27567 : hStereoClassif->Etot_up_fx = L_add( Mpy_32_16_1( hStereoClassif->Etot_up_fx, /*0.99f Q15*/ 32440 ), Mpy_32_16_1( hStereoClassif->Etot_buf_fx[0], 328 /*0.01f*/ ) ); /*hStereoClassif->e_Etot_buf_fx*/
576 : }
577 : ELSE
578 : {
579 : /* energy increases -> faster update */
580 12486 : hStereoClassif->Etot_up_fx = L_add( Mpy_32_16_1( hStereoClassif->Etot_up_fx, 31130 /*0.95f q15*/ ), Mpy_32_16_1( hStereoClassif->Etot_buf_fx[0], 1638 /*0.05f*/ ) ); /*hStereoClassif->e_Etot_buf_fx*/
581 : }
582 40053 : move32();
583 : }
584 23417 : ELSE IF( ( EQ_16( element_mode, IVAS_CPE_DFT ) && hStereoClassif->aEn_raw[0] == 0 ) ||
585 : ( EQ_16( element_mode, IVAS_CPE_TD ) && hStereoClassif->aEn_raw[0] == 0 && hStereoClassif->aEn_raw[1] == 0 ) )
586 : {
587 : /* inactive signal, update lower bound */
588 16176 : IF( LT_32( hStereoClassif->Etot_buf_fx[0], hStereoClassif->Etot_dn_fx ) )
589 : {
590 : /* energy decreases -> faster update */
591 6185 : hStereoClassif->Etot_dn_fx = L_add( Mpy_32_16_1( hStereoClassif->Etot_dn_fx, 29491 /*0.9f q15*/ ), Mpy_32_16_1( hStereoClassif->Etot_buf_fx[0], 3277 /*0.1f q15*/ ) ); /*hStereoClassif->e_Etot_buf_fx*/
592 : }
593 : ELSE
594 : {
595 : /* energy increases -> slower update */
596 9991 : hStereoClassif->Etot_dn_fx = L_add( Mpy_32_16_1( hStereoClassif->Etot_dn_fx, 31130 /*0.95f q15*/ ), Mpy_32_16_1( hStereoClassif->Etot_buf_fx[0], 1638 /*0.05f q15*/ ) ); /*hStereoClassif->e_Etot_buf_fx*/
597 : }
598 16176 : move32();
599 :
600 16176 : IF( LT_32( hStereoClassif->Etot_dn_fx, L_shl( 30, sub( 31, hStereoClassif->e_Etot_buf_fx ) ) ) )
601 : {
602 : /* do not decrease below lower bound threshold */
603 2606 : hStereoClassif->Etot_dn_fx = L_shl( 30, sub( 31, hStereoClassif->e_Etot_buf_fx ) );
604 2606 : move32();
605 : }
606 : }
607 :
608 : /* upper bound is too low and close to lower bound -> update it */
609 63470 : IF( LT_32( L_shr( hStereoClassif->Etot_up_fx, 1 ), L_add( L_shr( hStereoClassif->Etot_dn_fx, 1 ), L_shl( 20, sub( 30, hStereoClassif->e_Etot_buf_fx ) ) ) ) ) /*right shifted by 1 to avoid avoid overflow in addition*/
610 : {
611 14506 : hStereoClassif->Etot_dn_fx = L_shr( hStereoClassif->Etot_dn_fx, 1 );
612 14506 : scale_sig32( hStereoClassif->Etot_buf_fx, 3, -1 ); // Q(31-(e_Etot_buf_fx+1))
613 14506 : hStereoClassif->e_Etot_buf_fx = add( hStereoClassif->e_Etot_buf_fx, 1 );
614 14506 : hStereoClassif->Etot_up_fx = L_add( hStereoClassif->Etot_dn_fx, L_shl( 20, sub( 31, hStereoClassif->e_Etot_buf_fx ) ) );
615 14506 : move32();
616 14506 : move32();
617 14506 : move16();
618 : }
619 :
620 : /* normalize Etot to (0,1) */
621 63470 : hStereoClassif->relE_0_1_fx = lin_interp32_fx( hStereoClassif->Etot_buf_fx[0], hStereoClassif->Etot_dn_fx, 0, hStereoClassif->Etot_up_fx, 1932735283 /* 0.9 in Q31 */, 1 );
622 63470 : move32();
623 :
624 : /* update relE_buf */
625 63470 : Copy32( &hStereoClassif->relE_buf_fx[0], &hStereoClassif->relE_buf_fx[1], UNCLR_L_RELE - 1 );
626 63470 : hStereoClassif->relE_buf_fx[0] = hStereoClassif->relE_0_1_fx;
627 63470 : move32();
628 :
629 63470 : IF( GE_32( hStereoClassif->relE_0_1_fx, hStereoClassif->relE_buf_fx[1] ) )
630 : {
631 39513 : hStereoClassif->relE_0_1_LT_fx = L_add( Mpy_32_16_1( hStereoClassif->relE_0_1_LT_fx, 29491 /* 0.9f in Q15 */ ), Mpy_32_16_1( hStereoClassif->relE_0_1_fx, 3277 /* 0.1f in Q15 */ ) );
632 : }
633 : ELSE
634 : {
635 23957 : hStereoClassif->relE_0_1_LT_fx = L_add( Mpy_32_16_1( hStereoClassif->relE_0_1_LT_fx, 31129 /* 0.95f in Q15 */ ), Mpy_32_16_1( hStereoClassif->relE_0_1_fx, 1638 /* 0.05f in Q15 */ ) );
636 : }
637 63470 : move32();
638 :
639 : /* estimate VAD flag based on relative energy */
640 :
641 63470 : IF( LT_32( hStereoClassif->relE_0_1_LT_fx, 214748365 /* 0.1f in Q31 */ ) )
642 : {
643 14852 : hStereoClassif->vad_relE = 0;
644 : }
645 : ELSE
646 : {
647 48618 : hStereoClassif->vad_relE = 1;
648 : }
649 63470 : move16();
650 :
651 : /* combine classical VAD flag with VAD flag based on relative energy */
652 63470 : hStereoClassif->vad_flag_glob = s_and( hStereoClassif->vad_flag_glob, hStereoClassif->vad_relE );
653 63470 : move16();
654 : }
655 :
656 760867 : IF( idchan == 0 )
657 : {
658 410255 : Copy( lsf_new_fx, hStereoClassif->lsf_ch1_fx, M );
659 410255 : hStereoClassif->lepsP_ch1_fx = L_shr( L_sub( BASOP_Util_Loge( L_add( epsP_fx[13], L_shr( 21474 /*1e-5*2^31*/, epsP_e ) ), epsP_e ), BASOP_Util_Loge( L_add( epsP_fx[0], L_shr( 21474 /*1e-5*2^31*/, epsP_e ) ), epsP_e ) ), 10 ); /*q15*/
660 410255 : move32();
661 :
662 410255 : hStereoClassif->xtalk_fv_fx[E_lsf_1] = Mpy_32_16_1( 419430400 /* 1/2.56f in Q30 */, lsf_new_fx[0] ); /*q15*/
663 410255 : hStereoClassif->xtalk_fv_fx[E_lsf_4] = Mpy_32_16_1( 419430400 /* 1/2.56f in Q30 */, lsf_new_fx[3] ); /*q15*/
664 410255 : hStereoClassif->xtalk_fv_fx[E_lsf_9] = Mpy_32_16_1( 419430400 /* 1/2.56f in Q30 */, lsf_new_fx[8] ); /*q15*/
665 410255 : hStereoClassif->xtalk_fv_fx[E_lsf_14] = Mpy_32_16_1( 419430400 /* 1/2.56f in Q30 */, lsf_new_fx[13] ); /*q15*/
666 410255 : hStereoClassif->xtalk_fv_fx[E_lepsP_13] = hStereoClassif->lepsP_ch1_fx; /*q15*/
667 410255 : move32();
668 410255 : move32();
669 410255 : move32();
670 410255 : move32();
671 410255 : move32();
672 : }
673 : ELSE
674 : {
675 350612 : hStereoClassif->xtalk_fv_fx[E_sum_d_LSF] = 0;
676 350612 : move32();
677 : /* making negative exponent zero as we are using this exponent to scale 1 in next block*/
678 350612 : IF( hStereoClassif->ratio_L_e < 0 )
679 : {
680 0 : hStereoClassif->ratio_L_fx = L_shl( hStereoClassif->ratio_L_fx, hStereoClassif->ratio_L_e );
681 0 : hStereoClassif->ratio_L_e = 0;
682 0 : move32();
683 0 : move16();
684 : }
685 5960404 : FOR( i = 0; i < M; i++ )
686 : {
687 5609792 : hStereoClassif->xtalk_fv_fx[E_sum_d_LSF] = L_add( hStereoClassif->xtalk_fv_fx[E_sum_d_LSF], L_abs( Mpy_32_16_1( 419430400 /* 1/2.56f in Q30 */, sub( lsf_new_fx[i], hStereoClassif->lsf_ch1_fx[i] ) ) ) ); /*q15*/
688 5609792 : move32();
689 : }
690 :
691 350612 : test();
692 350612 : test();
693 350612 : IF( hStereoClassif->vad_flag_glob && ( hStereoClassif->ratio_L_fx > 0 && LT_32( L_shr( hStereoClassif->ratio_L_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->ratio_L_e ) ) ) ) )
694 : {
695 327759 : hStereoClassif->xtalk_fv_fx[E_sum_d_LSF] = 0;
696 327759 : move32();
697 : }
698 350612 : lepsP_ch2_fx = L_shr( L_sub( BASOP_Util_Loge( L_add( epsP_fx[13], L_shr( 21474 /*1e-5*2^31*/, epsP_e ) ), epsP_e ), BASOP_Util_Loge( L_add( epsP_fx[0], L_shr( 21474 /*1e-5*2^31*/, epsP_e ) ), epsP_e ) ), 10 ); /*q15*/
699 350612 : hStereoClassif->xtalk_fv_fx[E_d_lepsP_13] = L_abs( L_sub( hStereoClassif->lepsP_ch1_fx, lepsP_ch2_fx ) ); /*q15*/
700 350612 : move32();
701 : }
702 :
703 760867 : IF( idchan == 0 )
704 : {
705 410255 : Copy( pitch, hStereoClassif->pitch_ch1, 3 );
706 410255 : Copy( voicing_fx, hStereoClassif->voicing_ch1_fx, 3 );
707 :
708 410255 : hStereoClassif->xtalk_fv_fx[E_pitch] = Mpy_32_16_1( L_shl( add( pitch[0], add( pitch[1], pitch[2] ) ), 15 ), 10923 ); /*q15*/
709 410255 : hStereoClassif->xtalk_fv_fx[E_voicing] = Mpy_32_16_1( L_add( voicing_fx[0], L_add( voicing_fx[1], voicing_fx[2] ) ), 10923 ); /*q15*/
710 410255 : move32();
711 410255 : move32();
712 : }
713 : ELSE
714 : {
715 350612 : hStereoClassif->xtalk_fv_fx[E_d_pitch] = 0;
716 350612 : hStereoClassif->xtalk_fv_fx[E_d_voicing] = 0;
717 1402448 : FOR( i = 0; i < 3; i++ )
718 : {
719 1051836 : hStereoClassif->xtalk_fv_fx[E_d_pitch] = L_add( hStereoClassif->xtalk_fv_fx[E_d_pitch], L_shl( abs_s( sub( pitch[i], hStereoClassif->pitch_ch1[i] ) ), Q15 ) );
720 1051836 : hStereoClassif->xtalk_fv_fx[E_d_voicing] = L_add( hStereoClassif->xtalk_fv_fx[E_d_voicing], L_abs( L_sub( voicing_fx[i], hStereoClassif->voicing_ch1_fx[i] ) ) );
721 1051836 : move32();
722 1051836 : move32();
723 : }
724 350612 : hStereoClassif->xtalk_fv_fx[E_d_pitch] = Mult_32_16( hStereoClassif->xtalk_fv_fx[E_d_pitch], 10923 /*1/3 q15*/ );
725 350612 : hStereoClassif->xtalk_fv_fx[E_d_voicing] = Mult_32_16( hStereoClassif->xtalk_fv_fx[E_d_voicing], 10923 /*1/3 q15*/ );
726 350612 : move32();
727 350612 : move32();
728 350612 : move32();
729 350612 : move32();
730 : }
731 :
732 : /* making negative exponent zero as we are using this exponent to scale 1 in next block*/
733 760867 : IF( hStereoClassif->nchar_ch1_e < 0 )
734 : {
735 0 : hStereoClassif->nchar_ch1_fx = L_shl( hStereoClassif->nchar_ch1_fx, hStereoClassif->nchar_ch1_e );
736 0 : hStereoClassif->nchar_ch1_e = 0;
737 : }
738 760867 : IF( hStereoClassif->nchar_ch2_e < 0 )
739 : {
740 0 : hStereoClassif->nchar_ch2_fx = L_shl( hStereoClassif->nchar_ch2_fx, hStereoClassif->nchar_ch2_e );
741 0 : hStereoClassif->nchar_ch2_e = 0;
742 : }
743 760867 : move32();
744 760867 : move16();
745 760867 : IF( idchan == 0 )
746 : {
747 410255 : hStereoClassif->cor_map_sum_ch1_fx = cor_map_sum_fx;
748 410255 : hStereoClassif->cor_map_sum_ch1_e = cor_map_sum_e;
749 410255 : hStereoClassif->non_sta_ch1_fx = non_staX_fx;
750 410255 : hStereoClassif->non_sta_ch1_e = non_staX_e;
751 410255 : hStereoClassif->sp_div_ch1_fx = sp_div_fx;
752 410255 : hStereoClassif->sp_div_ch1_e = sp_div_e;
753 410255 : hStereoClassif->xtalk_fv_fx[E_cor_map_sum] = L_shr( cor_map_sum_fx, sub( 16, cor_map_sum_e ) ); /*q15*/
754 410255 : hStereoClassif->xtalk_fv_fx[E_nchar] = L_shr( BASOP_Util_Loge( L_add( L_shr( hStereoClassif->nchar_ch1_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->nchar_ch1_e ) ) ), add( hStereoClassif->nchar_ch1_e, 1 ) ) /*q25*/, 10 ); /*q15*/
755 410255 : hStereoClassif->xtalk_fv_fx[E_non_sta] = L_shr( non_staX_fx, sub( 16, non_staX_e ) ); /*q15*/
756 410255 : L_tmp = BASOP_Util_Add_Mant32Exp( L_deposit_h( sp_div_fx ), sp_div_e, ONE_IN_Q31, 0, &exp );
757 410255 : hStereoClassif->xtalk_fv_fx[E_sp_div] = L_shr( BASOP_Util_Loge( L_tmp, exp ), 10 ); /*q15*/
758 410255 : move32();
759 410255 : move32();
760 410255 : move32();
761 410255 : move32();
762 410255 : move32();
763 410255 : move32();
764 410255 : move16();
765 410255 : move16();
766 410255 : move16();
767 410255 : move16();
768 : }
769 : ELSE
770 : {
771 350612 : hStereoClassif->xtalk_fv_fx[E_d_cor_map_sum] = L_abs( L_sub( L_shr( hStereoClassif->cor_map_sum_ch1_fx, sub( 16, hStereoClassif->cor_map_sum_ch1_e ) ) /*q15*/, L_shr( cor_map_sum_fx, sub( 16, cor_map_sum_e ) ) /*q15*/ ) ); /*q15*/
772 350612 : hStereoClassif->xtalk_fv_fx[E_d_nchar] = L_abs( L_shr( L_sub( BASOP_Util_Loge( L_add( L_shr( hStereoClassif->nchar_ch1_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->nchar_ch1_e ) ) ), add( hStereoClassif->nchar_ch1_e, 1 ) ), BASOP_Util_Loge( L_add( L_shr( hStereoClassif->nchar_ch2_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->nchar_ch2_e ) ) ), add( hStereoClassif->nchar_ch2_e, 1 ) ) ) /*q25*/, 10 ) ); /*q15*/
773 350612 : hStereoClassif->xtalk_fv_fx[E_d_non_sta] = L_abs( L_sub( L_shr( hStereoClassif->non_sta_ch1_fx, sub( 16, hStereoClassif->non_sta_ch1_e ) ) /*q15*/, L_shr( non_staX_fx, sub( 16, non_staX_e ) ) /*q15*/ ) ); /*q15*/
774 350612 : L_tmp = BASOP_Util_Add_Mant32Exp( L_deposit_h( sp_div_fx ), sp_div_e, ONE_IN_Q31, 0, &exp );
775 350612 : hStereoClassif->xtalk_fv_fx[E_d_sp_div] = L_shr( BASOP_Util_Loge( L_tmp, exp ), 10 ); /*q15*/
776 350612 : L_tmp = BASOP_Util_Add_Mant32Exp( L_deposit_h( hStereoClassif->sp_div_ch1_fx ), hStereoClassif->sp_div_ch1_e, ONE_IN_Q31, 0, &exp );
777 350612 : hStereoClassif->xtalk_fv_fx[E_d_sp_div] = L_abs( L_sub( L_shr( BASOP_Util_Loge( L_tmp, exp ), 10 ), hStereoClassif->xtalk_fv_fx[E_d_sp_div] ) ); /*q15*/
778 : // hStereoClassif->xtalk_fv_fx[E_d_sp_div] = L_abs( L_shr( L_sub( BASOP_Util_Loge( L_deposit_h( add( shr( hStereoClassif->sp_div_ch1_fx, 1 ), shl( 1, sub( 15 - 1, hStereoClassif->sp_div_ch1_e ) ) ) ), add( hStereoClassif->sp_div_ch1_e, 1 ) ), BASOP_Util_Loge( L_deposit_h( add( shr( sp_div_fx, 1 ), shl( 1, sub( 15 - 1, sp_div_e ) ) ) ), add( sp_div_e, 1 ) ) ) /*q25*/, 10 ) ); /*q15*/
779 350612 : move32();
780 350612 : move32();
781 350612 : move32();
782 350612 : move32();
783 350612 : move32();
784 : }
785 :
786 : /* making negative exponent zero as we are using this exponent to scale 1 in next block*/
787 760867 : IF( hStereoClassif->dE1_ch1_e < 0 )
788 : {
789 0 : hStereoClassif->dE1_ch1_fx = L_shl( hStereoClassif->dE1_ch1_fx, hStereoClassif->dE1_ch1_e );
790 0 : hStereoClassif->dE1_ch1_e = 0;
791 : }
792 760867 : IF( hStereoClassif->dE1_ch2_e < 0 )
793 : {
794 0 : hStereoClassif->dE1_ch2_fx = L_shl( hStereoClassif->dE1_ch2_fx, hStereoClassif->dE1_ch2_e );
795 0 : hStereoClassif->dE1_ch2_e = 0;
796 : }
797 760867 : move32();
798 760867 : move16();
799 :
800 760867 : IF( idchan == 0 )
801 : {
802 410255 : hStereoClassif->xtalk_fv_fx[E_dE1] = L_shr( BASOP_Util_Loge( L_add( L_shr( hStereoClassif->dE1_ch1_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->dE1_ch1_e ) ) ), hStereoClassif->dE1_ch1_e + 1 ) /*q25*/, 10 ); /*q15*/
803 : }
804 : ELSE
805 : {
806 350612 : hStereoClassif->xtalk_fv_fx[E_d_dE1] = L_shr( L_abs( L_sub( BASOP_Util_Loge( L_add( L_shr( hStereoClassif->dE1_ch1_fx, 1 ) /*right shifting to avoid overflow*/, L_shl( 1, sub( 30, hStereoClassif->dE1_ch1_e ) ) ), add( hStereoClassif->dE1_ch1_e, 1 ) ) /*q25*/, BASOP_Util_Loge( L_add( L_shr( hStereoClassif->dE1_ch2_fx, 1 ), L_shl( 1, sub( 30, hStereoClassif->dE1_ch2_e ) ) ), add( hStereoClassif->dE1_ch2_e, 1 ) ) /*q25*/ ) ), 10 ); /*right shifting the ouput of log by 10 to bring value to q15*/
807 : }
808 760867 : move32();
809 :
810 760867 : IF( idchan == 0 )
811 : {
812 410255 : IF( GT_16( clas, VOICED_CLAS ) )
813 : {
814 21700 : hStereoClassif->clas_ch1 = VOICED_CLAS; /*q0*/
815 : }
816 388555 : ELSE IF( LT_16( clas, VOICED_CLAS ) )
817 : {
818 241640 : hStereoClassif->clas_ch1 = UNVOICED_CLAS;
819 : }
820 : ELSE
821 : {
822 146915 : hStereoClassif->clas_ch1 = clas;
823 : }
824 410255 : move16();
825 :
826 410255 : hStereoClassif->xtalk_fv_fx[E_clas] = L_shl( hStereoClassif->clas_ch1, 15 ); /*q15*/
827 : }
828 : ELSE
829 : {
830 350612 : IF( GT_16( clas, VOICED_CLAS ) )
831 : {
832 14815 : clas_ch2 = VOICED_CLAS;
833 : }
834 335797 : ELSE IF( LT_16( clas, VOICED_CLAS ) )
835 : {
836 236556 : clas_ch2 = UNVOICED_CLAS;
837 : }
838 : ELSE
839 : {
840 99241 : clas_ch2 = clas;
841 : }
842 350612 : move16();
843 :
844 350612 : hStereoClassif->xtalk_fv_fx[E_d_clas] = L_shl( L_abs( sub( hStereoClassif->clas_ch1 /*q0*/, clas_ch2 /*q0*/ ) ), 15 ); /*q15*/
845 : }
846 760867 : move32();
847 :
848 760867 : IF( idchan == 0 )
849 : {
850 410255 : hStereoClassif->xtalk_fv_fx[E_ps_diff] = L_shr( hStereoClassif->ps_diff_ch1_fx, sub( 16, hStereoClassif->ps_diff_ch1_e ) ); /*scaling to q15*/
851 410255 : hStereoClassif->xtalk_fv_fx[E_ps_sta] = L_shr( hStereoClassif->ps_sta_ch1_fx, sub( 16, hStereoClassif->ps_sta_ch1_e ) ); /*q15*/
852 : }
853 : ELSE
854 : {
855 350612 : hStereoClassif->xtalk_fv_fx[E_d_ps_diff] = L_abs( L_sub( L_shr( hStereoClassif->ps_diff_ch1_fx, sub( 16, hStereoClassif->ps_diff_ch1_e ) ) /*q15*/, L_shr( hStereoClassif->ps_diff_ch2_fx, sub( 16, hStereoClassif->ps_diff_ch2_e ) ) /*q15*/ ) ); /*q15*/
856 350612 : hStereoClassif->xtalk_fv_fx[E_d_ps_sta] = L_abs( L_sub( L_shr( hStereoClassif->ps_sta_ch1_fx, sub( 16, hStereoClassif->ps_sta_ch1_e ) ) /*q15*/, L_shr( hStereoClassif->ps_sta_ch2_fx, sub( 16, hStereoClassif->ps_sta_ch1_e ) ) /*q15*/ ) ); /*q15*/
857 : }
858 760867 : move32();
859 760867 : move32();
860 760867 : hStereoClassif->Etot_dn_e = hStereoClassif->Etot_up_e = hStereoClassif->e_Etot_buf_fx; /*updating the exponents*/
861 760867 : move16();
862 760867 : move16();
863 760867 : return;
864 : }
865 :
866 : /*-------------------------------------------------------------------*
867 : * Function unclr_classifier_td()
868 : *
869 : * Classify current TD frame as uncorrelated L/R (1) or normal (0)
870 : *-------------------------------------------------------------------*/
871 3827 : void unclr_classifier_td_fx(
872 : CPE_ENC_HANDLE hCPE /* i/o: CPE encoder structure */
873 : )
874 : {
875 : Word16 i, ind, exp;
876 : Word32 relE_ST, score, fvn;
877 : Word16 edge, edge_0_1, score_exp;
878 3827 : STEREO_CLASSIF_HANDLE hStereoClassif = hCPE->hStereoClassif;
879 :
880 : /* calcualte raw score based on LR */
881 3827 : exp = 0;
882 3827 : move16();
883 3827 : score = UNCLR_INTERCEPT_TD_Q28;
884 3827 : move32();
885 3827 : score_exp = 3;
886 3827 : move16();
887 42097 : FOR( i = 0; i < SIZE_UNCLR_ISEL_TD; i++ )
888 : {
889 38270 : ind = unclr_isel_td[i];
890 38270 : move16();
891 :
892 : /* mean & std removal */
893 38270 : fvn = BASOP_Util_Divide3232_Scale_newton( L_sub( hStereoClassif->unclr_fv_fx[ind], unclr_mean_td[i] ), unclr_scale_td[i], &exp );
894 38270 : fvn = Mpy_32_32( fvn, unclr_coef_td[i] ); // Q = 31-exp+15-31 = 15-exp
895 38270 : exp = add( exp, 16 ); // exp = 31-(15-exp) = 16+exp
896 :
897 : /* LR */
898 38270 : score = BASOP_Util_Add_Mant32Exp( score, score_exp, fvn, exp, &score_exp );
899 : }
900 :
901 3827 : score = L_shl_sat( score, sub( score_exp, 3 ) ); // Q28
902 :
903 :
904 : /* normalize score to -1:+1 */
905 3827 : IF( GT_32( score, UNCLR_SCORE_THR_Q28 ) )
906 : {
907 379 : score = UNCLR_SCORE_THR_Q28;
908 379 : move32();
909 : }
910 3448 : ELSE IF( LT_32( score, -UNCLR_SCORE_THR_Q28 ) )
911 : {
912 645 : score = -UNCLR_SCORE_THR_Q28;
913 645 : move32();
914 : }
915 : /*score /= 2 * UNCLR_SCORE_THR; = score = score / 8
916 : score Q will be 31 to account the above operation*/
917 :
918 : /* weight raw score with relative energy */
919 3827 : score = Mpy_32_32( score, hStereoClassif->relE_0_1_fx ); // Q31
920 :
921 : /* rising edge detection on relE */
922 3827 : Word32 L_tmp = 0, tmp32;
923 3827 : move32();
924 3827 : Word16 L_tmp_e = 0, flag = 0;
925 3827 : move16();
926 3827 : move16();
927 3827 : tmp32 = hStereoClassif->relE_buf_fx[0];
928 42097 : FOR( i = 0; i < UNCLR_L_RELE; i++ )
929 : {
930 38270 : L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, hStereoClassif->relE_buf_fx[i], 0, &L_tmp_e );
931 38270 : IF( NE_32( tmp32, hStereoClassif->relE_buf_fx[i] ) )
932 : {
933 31050 : flag = 1;
934 31050 : move16();
935 : }
936 : }
937 3827 : IF( EQ_16( flag, 1 ) )
938 : {
939 3660 : relE_ST = L_shl( Mpy_32_32( L_tmp, ONE_BY_UNCLR_L_RELE_Q31 ), L_tmp_e ); // Q31
940 : }
941 : ELSE
942 : {
943 167 : relE_ST = hStereoClassif->relE_buf_fx[0];
944 167 : move16();
945 : }
946 :
947 3827 : IF( hStereoClassif->relE_0_1_fx > relE_ST )
948 : {
949 1759 : rc_filter_fx( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx, UNCLR_RC_ORDER, RC_FACT_UP_Q31 );
950 : }
951 : ELSE
952 : {
953 2068 : rc_filter_fx( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx, UNCLR_RC_ORDER, RC_FACT_DOWN_Q31 );
954 : }
955 :
956 3827 : edge = extract_h( L_sub( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx[UNCLR_RC_ORDER - 1] ) ); // Q15
957 3827 : edge_0_1 = lin_interp_ivas_fx( edge, 0, 31129 /*0.95 in Q15*/, MAX_16, 29491 /*0.9 in Q15f*/, 1 ); // Q15
958 :
959 : /* LT average */
960 3827 : hStereoClassif->unclr_wscore_fx = Madd_32_16( Mpy_32_16_1( hStereoClassif->unclr_wscore_fx, edge_0_1 ), score, sub( MAX_16, edge_0_1 ) ); // Q31
961 3827 : move32();
962 :
963 : /* binary decision w. hysteresis (switch the decision only when coder_type is GC, UC or IC) */
964 3827 : test();
965 3827 : test();
966 3827 : test();
967 3827 : test();
968 3827 : test();
969 3827 : if ( ( ( hStereoClassif->unclr_decision == 0 && GT_32( hStereoClassif->unclr_wscore_fx, 214748365 /*0.1f in Q31*/ ) ) || ( EQ_16( hStereoClassif->unclr_decision, 1 ) && LT_32( hStereoClassif->unclr_wscore_fx, -150323855 /*-0.07f in Q31*/ ) ) ) && ( hStereoClassif->unclr_sw_enable_cnt[0] > 0 || hStereoClassif->unclr_sw_enable_cnt[1] > 0 ) )
970 : {
971 : /* let's switch the binary decision */
972 0 : hStereoClassif->unclr_decision = !hStereoClassif->unclr_decision;
973 0 : move16();
974 : }
975 :
976 : #ifdef DEBUG_FORCE_DIR
977 : if ( hCPE->hCoreCoder[0]->force_dir[0] != '\0' )
978 : {
979 : dbgread( &hStereoClassif->unclr_decision, sizeof( int16_t ), 1, fname( hCPE->hCoreCoder[0]->force_dir, "force_unclr_decision.enf", -1, -1, -1 ) );
980 : }
981 : else
982 : {
983 : dbgwrite( &hStereoClassif->unclr_decision, sizeof( int16_t ), 1, 1, "res/force_unclr_decision.enf" );
984 : }
985 : #endif
986 :
987 3827 : return;
988 : }
989 :
990 : /*-------------------------------------------------------------------*
991 : * Function unclr_classifier_dft()
992 : *
993 : * Classifies current DFT frame as uncorrelated L/R (1) or normal stereo (0)
994 : *-------------------------------------------------------------------*/
995 59643 : void unclr_classifier_dft_fx(
996 : CPE_ENC_HANDLE hCPE /* i/o: CPE encoder structure */
997 : )
998 : {
999 : Word16 i, ind;
1000 : Word16 edge, edge_0_1;
1001 : Word32 relE_ST;
1002 : Word32 score, fvn[SSC_MAX_NFEA];
1003 : Word16 score_e, fvn_e[SSC_MAX_NFEA];
1004 :
1005 59643 : STEREO_CLASSIF_HANDLE hStereoClassif = hCPE->hStereoClassif;
1006 :
1007 : /* calculate raw score based on LR */
1008 59643 : score = UNCLR_INTERCEPT_DFT_Q30;
1009 59643 : move32();
1010 59643 : score_e = 1;
1011 59643 : move16();
1012 536787 : FOR( i = 0; i < SIZE_UNCLR_ISEL_DFT; i++ )
1013 : {
1014 477144 : ind = unclr_isel_dft[i];
1015 477144 : move16();
1016 :
1017 : /* mean & std removal */
1018 : // fvn[i] = (hStereoClassif->unclr_fv[ind] - unclr_mean_dft[i]) / unclr_scale_dft[i];
1019 477144 : fvn[i] = BASOP_Util_Divide3232_Scale_newton( L_sub( hStereoClassif->unclr_fv_fx[ind], unclr_mean_dft_Q15[i] ), unclr_scale_dft_Q15[i], &fvn_e[i] );
1020 477144 : move32();
1021 :
1022 : /* LR */
1023 : // score += fvn[i] * unclr_coef_dft[i];
1024 477144 : score = BASOP_Util_Add_Mant32Exp( score, score_e, Mpy_32_32( fvn[i], unclr_coef_dft_Q28[i] ), add( fvn_e[i], 3 ), &score_e );
1025 : }
1026 :
1027 :
1028 : /* normalize score to -1:+1 */
1029 59643 : IF( BASOP_Util_Add_Mant32Exp( score, score_e, -UNCLR_SCORE_THR_Q28, 3, &i ) > 0 )
1030 : {
1031 872 : score = UNCLR_SCORE_THR_Q28;
1032 872 : move32();
1033 872 : score_e = 3;
1034 872 : move16();
1035 : }
1036 58771 : ELSE IF( BASOP_Util_Add_Mant32Exp( score, score_e, UNCLR_SCORE_THR_Q28, 3, &i ) < 0 )
1037 : {
1038 35994 : score = -UNCLR_SCORE_THR_Q28;
1039 35994 : move32();
1040 35994 : score_e = 3;
1041 35994 : move16();
1042 : }
1043 :
1044 59643 : score = L_shr_r_sat( score, sub( 3, score_e ) ); // Q31
1045 :
1046 : /* weight raw score with relative energy */
1047 : // score *= hStereoClassif->relE_0_1;
1048 59643 : score = Mpy_32_32( score, hStereoClassif->relE_0_1_fx ); // Q31
1049 :
1050 59643 : if ( !hStereoClassif->vad_flag_glob )
1051 : {
1052 21034 : score = 0;
1053 21034 : move32();
1054 : }
1055 :
1056 : /* rising edge detector on relE */
1057 : // relE_ST = mean(hStereoClassif->relE_buf, UNCLR_L_RELE);
1058 59643 : Word32 L_tmp = 0, tmp32;
1059 59643 : move32();
1060 59643 : Word16 L_tmp_e = 0, flag = 0;
1061 59643 : move16();
1062 59643 : move16();
1063 59643 : tmp32 = hStereoClassif->relE_buf_fx[0];
1064 59643 : move32();
1065 656073 : FOR( i = 0; i < UNCLR_L_RELE; i++ )
1066 : {
1067 596430 : L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, hStereoClassif->relE_buf_fx[i], 0, &L_tmp_e );
1068 596430 : IF( NE_32( tmp32, hStereoClassif->relE_buf_fx[i] ) )
1069 : {
1070 410239 : flag = 1;
1071 410239 : move16();
1072 : }
1073 : }
1074 59643 : IF( EQ_16( flag, 1 ) )
1075 : {
1076 52151 : relE_ST = L_shl( Mpy_32_32( L_tmp, ONE_BY_UNCLR_L_RELE_Q31 ), L_tmp_e ); // Q31
1077 : }
1078 : ELSE
1079 : {
1080 7492 : relE_ST = hStereoClassif->relE_buf_fx[0];
1081 7492 : move16();
1082 : }
1083 :
1084 59643 : IF( GT_32( hStereoClassif->relE_0_1_fx, relE_ST ) )
1085 : {
1086 : // rc_filter(hStereoClassif->relE_0_1, hStereoClassif->unclr_relE_0_1_LT, UNCLR_RC_ORDER, RC_FACT_UP);
1087 27288 : rc_filter_fx( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx, UNCLR_RC_ORDER, RC_FACT_UP_Q31 );
1088 : }
1089 : ELSE
1090 : {
1091 : // rc_filter(hStereoClassif->relE_0_1, hStereoClassif->unclr_relE_0_1_LT, UNCLR_RC_ORDER, RC_FACT_DOWN);
1092 32355 : rc_filter_fx( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx, UNCLR_RC_ORDER, RC_FACT_DOWN_Q31 );
1093 : }
1094 :
1095 : // edge = hStereoClassif->relE_0_1 - hStereoClassif->unclr_relE_0_1_LT[UNCLR_RC_ORDER - 1];
1096 59643 : edge = extract_h( L_sub( hStereoClassif->relE_0_1_fx, hStereoClassif->unclr_relE_0_1_LT_fx[UNCLR_RC_ORDER - 1] ) ); // Q15
1097 : // edge_0_1 = lin_interp(edge, 0.0f, 0.95f, 1.0f, 0.9f, 1);
1098 59643 : edge_0_1 = lin_interp_ivas_fx( edge, 0, 31129 /*0.95f*/, MAX_16, 29491 /*0.9f*/, 1 );
1099 :
1100 : /* LT average */
1101 : // hStereoClassif->unclr_wscore = edge_0_1 * hStereoClassif->unclr_wscore + (1 - edge_0_1) * score;
1102 59643 : hStereoClassif->unclr_wscore_fx = L_add( Mpy_32_16_1( hStereoClassif->unclr_wscore_fx, edge_0_1 ), Mpy_32_16_1( score, sub( MAX_16, edge_0_1 ) ) ); // Q31
1103 59643 : move32();
1104 :
1105 : /* binary decision w. hysteresis (switch the decision only when coder_type is GC, UC or IC) */
1106 : // if (((hStereoClassif->unclr_decision == 0 && hStereoClassif->unclr_wscore > 0.1f) || (hStereoClassif->unclr_decision == 1 && hStereoClassif->unclr_wscore < -0.07f)) && (hStereoClassif->unclr_sw_enable_cnt[0] > 0))
1107 59643 : test();
1108 59643 : test();
1109 59643 : test();
1110 59643 : test();
1111 59643 : if ( ( ( hStereoClassif->unclr_decision == 0 && GT_32( hStereoClassif->unclr_wscore_fx, 214748365 /*0.1f*/ ) ) || ( EQ_16( hStereoClassif->unclr_decision, 1 ) && LT_32( hStereoClassif->unclr_wscore_fx, -150323855 /*-0.07f*/ ) ) ) && ( hStereoClassif->unclr_sw_enable_cnt[0] > 0 ) )
1112 : {
1113 : /* let's switch the binary decision */
1114 522 : hStereoClassif->unclr_decision = !hStereoClassif->unclr_decision;
1115 522 : move16();
1116 : }
1117 :
1118 : #ifdef DEBUG_FORCE_DIR
1119 : if ( hCPE->hCoreCoder[0]->force_dir[0] != '\0' )
1120 : {
1121 : dbgread( &hStereoClassif->unclr_decision, sizeof( int16_t ), 1, fname( hCPE->hCoreCoder[0]->force_dir, "force_unclr_decision.enf", -1, -1, -1 ) );
1122 : }
1123 : else
1124 : {
1125 : dbgwrite( &hStereoClassif->unclr_decision, sizeof( int16_t ), 1, 1, "res/force_unclr_decision.enf" );
1126 : }
1127 : #endif
1128 :
1129 59643 : return;
1130 : }
1131 :
1132 : /*-------------------------------------------------------------------*
1133 : * Function xtalk_classifier_td()
1134 : *
1135 : * Classify current TD frame as cross-talk frame (1) or normal stereo frame (0)
1136 : *-------------------------------------------------------------------*/
1137 3827 : void xtalk_classifier_td_fx(
1138 : CPE_ENC_HANDLE hCPE /* i/o: CPE encoder structure */
1139 : )
1140 : {
1141 : Word16 i, ind, edge_type, exp, score_exp;
1142 : Word32 score, fvn, scr_min, scr_max;
1143 : Word16 edge, edge_0_1, wedge, wrelE;
1144 :
1145 3827 : STEREO_CLASSIF_HANDLE hStereoClassif = hCPE->hStereoClassif;
1146 :
1147 : /* calcualte raw score based on LR */
1148 3827 : exp = 0;
1149 3827 : move16();
1150 3827 : score = XTALK_INTERCEPT_TD_Q28;
1151 3827 : move32();
1152 3827 : score_exp = 3;
1153 3827 : move16();
1154 68886 : FOR( i = 0; i < SIZE_XTALK_ISEL_TD; i++ )
1155 : {
1156 65059 : ind = xtalk_isel_td[i];
1157 65059 : move16();
1158 :
1159 : /* mean & std removal */
1160 65059 : fvn = BASOP_Util_Divide3232_Scale_newton( L_sub( hStereoClassif->xtalk_fv_fx[ind], xtalk_mean_td[i] ), xtalk_scale_td[i], &exp );
1161 65059 : fvn = Mpy_32_32( fvn, xtalk_coef_td[i] ); // Q = 31-exp+15-31 = 15-exp
1162 65059 : exp = add( exp, 16 ); // exp = 31-(15-exp) = 16+exp
1163 :
1164 : /* LR */
1165 65059 : score = BASOP_Util_Add_Mant32Exp( score, score_exp, fvn, exp, &score_exp );
1166 : }
1167 :
1168 3827 : score = L_shl_sat( score, sub( score_exp, 3 ) ); // Q28
1169 :
1170 : /* normalize raw score to -1:+1 */
1171 3827 : IF( GT_32( score, XTALK_SCORE_THR_TD_UP_Q28 ) )
1172 : {
1173 1131 : score = MAX_32; // Q31
1174 1131 : move32();
1175 : }
1176 2696 : ELSE IF( LT_32( score, -XTALK_SCORE_THR_TD_DN_Q28 ) )
1177 : {
1178 110 : score = MIN_32; // Q31
1179 110 : move32();
1180 : }
1181 2586 : ELSE IF( score > 0 )
1182 : {
1183 1775 : score = Mpy_32_32( score, ONE_BY_XTALK_SCORE_THR_TD_UP_Q31 ); // Q = 31-score_exp
1184 1775 : score = L_shl( score, 3 ); // Q31
1185 : }
1186 : ELSE
1187 : {
1188 811 : score = Mpy_32_32( score, ONE_BY_XTALK_SCORE_THR_TD_DN_Q31 ); // Q = 31-score_exp
1189 811 : score = L_shl( score, 3 ); // Q31
1190 : }
1191 :
1192 3827 : IF( EQ_16( hCPE->last_element_mode, IVAS_CPE_DFT ) )
1193 : {
1194 : /* overwrite score if we have just switched from DFT stereo */
1195 54 : score = hStereoClassif->xtalk_score_fx; // Q31
1196 54 : move32();
1197 : }
1198 : ELSE
1199 : {
1200 3773 : hStereoClassif->xtalk_score_fx = score; // Q31
1201 3773 : move32();
1202 : }
1203 :
1204 3827 : if ( !hStereoClassif->vad_flag_glob )
1205 : {
1206 : /* reset score to 0 in inactive segments */
1207 173 : score = 0;
1208 173 : move32();
1209 : }
1210 :
1211 :
1212 : /* weight raw score with relative energy */
1213 3827 : wrelE = lin_interp_ivas_fx( extract_h( hStereoClassif->relE_0_1_fx ), 16384 /*0.5f Q15*/, 31129 /*0.95f Q15*/, 29491 /*0.9f Q15*/, 0, 1 );
1214 3827 : hStereoClassif->xtalk_score_wrelE_fx = Madd_32_16( Mpy_32_16_1( hStereoClassif->xtalk_score_wrelE_fx, wrelE ), score, sub( MAX_16, wrelE ) ); // Q31
1215 3827 : move32();
1216 3827 : score = hStereoClassif->xtalk_score_wrelE_fx; // Q31
1217 3827 : move32();
1218 :
1219 : /* rising edge detector on raw score -> yields 1 if strong rising edge is detected in the raw score buffer */
1220 3827 : Copy32( &hStereoClassif->xtalk_score_buf_fx[0], &hStereoClassif->xtalk_score_buf_fx[1], XTALK_SCORE_BUF_LEN - 1 );
1221 3827 : hStereoClassif->xtalk_score_buf_fx[0] = score; // Q31
1222 3827 : move32();
1223 :
1224 3827 : minimum_l( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, &scr_min );
1225 3827 : maximum_l( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, &scr_max );
1226 :
1227 3827 : test();
1228 3827 : test();
1229 3827 : IF( ( scr_min < 0 && GT_32( scr_max, 429496730 /*0.2f in Q31*/ ) ) || GT_32( L_sub_sat( scr_max, scr_min ), 1073741824 /*0.5f Q31*/ ) )
1230 : {
1231 : /* test rising edge (use 0 as edge_type because of newer->older buffer samples ordering) */
1232 894 : edge_type = 0;
1233 894 : move16();
1234 894 : edge_detect_fx( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, -53687091 /*-0.2f Q28*/, ONE_IN_Q28, &edge, &edge_type );
1235 :
1236 894 : test();
1237 894 : IF( edge_type == 0 && LT_16( edge, 9830 /*0.3f Q15*/ ) )
1238 : {
1239 : /* normalize edge to 0-1 interval */
1240 570 : edge_0_1 = lin_interp_ivas_fx( sub( MAX_16, edge ), MAX_16, MAX_16, 19661 /*0.6f Q15*/, 0, 1 );
1241 : }
1242 : ELSE
1243 : {
1244 324 : edge_0_1 = 0;
1245 324 : move16();
1246 : }
1247 : }
1248 : ELSE
1249 : {
1250 2933 : edge_0_1 = 0;
1251 2933 : move16();
1252 : }
1253 :
1254 : /* weight raw score based on rising edge detector */
1255 3827 : wedge = lin_interp_ivas_fx( edge_0_1, 0, 29491 /*0.9f Q15*/, MAX_16, 16384 /*0.5f Q15 */, 1 );
1256 :
1257 3827 : hStereoClassif->xtalk_wscore_fx = Madd_32_16( Mpy_32_16_1( hStereoClassif->xtalk_wscore_fx, wedge ), score, sub( MAX_16, wedge ) ); // Q31
1258 3827 : move32();
1259 :
1260 3827 : if ( !hStereoClassif->vad_flag_glob )
1261 : {
1262 173 : hStereoClassif->xtalk_wscore_fx = 0;
1263 173 : move16();
1264 : }
1265 :
1266 : /* binary decision w. hysteresis (switch the decision only when coder_type is GC, UC or IC) */
1267 3827 : test();
1268 3827 : test();
1269 3827 : test();
1270 3827 : test();
1271 3827 : if ( ( hStereoClassif->unclr_decision == 0 && hStereoClassif->xtalk_decision == 0 && GT_32( hStereoClassif->xtalk_wscore_fx, 64424509 /*0.03f Q31*/ ) ) /*|| (hStereoClassif->xtalk_decision == 1 && hStereoClassif->xtalk_wscore < 0.00f)*/ && ( hStereoClassif->unclr_sw_enable_cnt[0] > 0 || hStereoClassif->unclr_sw_enable_cnt[1] > 0 ) )
1272 : {
1273 : /* let's switch the binary decision */
1274 8 : hStereoClassif->xtalk_decision = !hStereoClassif->xtalk_decision;
1275 8 : move16();
1276 : }
1277 :
1278 : #ifdef DEBUG_FORCE_DIR
1279 : if ( hCPE->hCoreCoder[0]->force_dir[0] != '\0' )
1280 : {
1281 : dbgread( &hStereoClassif->xtalk_decision, sizeof( int16_t ), 1, fname( hCPE->hCoreCoder[0]->force_dir, "force_xtalk_decision.enf", -1, -1, -1 ) );
1282 : }
1283 : else
1284 : {
1285 : dbgwrite( &hStereoClassif->xtalk_decision, sizeof( int16_t ), 1, 1, "res/force_xtalk_decision.enf" );
1286 : }
1287 : #endif
1288 :
1289 3827 : return;
1290 : }
1291 :
1292 : /*-------------------------------------------------------------------*
1293 : * Function xtalk_classifier_dft()
1294 : *
1295 : * Classify current DFT frame as cross-talk frame (1) or normal stereo frame (0)
1296 : *-------------------------------------------------------------------*/
1297 :
1298 74333 : void xtalk_classifier_dft_fx(
1299 : CPE_ENC_HANDLE hCPE, /* i/o: CPE encoder structure */
1300 : const Word16 itd, /* i : ITD from DFT stereo - used as a feature */
1301 : const Word32 gcc_phat[] /* i : GPHAT cross-channel correlation function Q31*/
1302 : )
1303 : {
1304 : Word16 i, ind, itd2, thr;
1305 : Word32 score, m1, m2;
1306 : STEREO_CLASSIF_HANDLE hStereoClassif;
1307 : ITD_DATA_HANDLE hItd;
1308 : Word32 fvn[SSC_MAX_NFEA] /*Q28*/, edge;
1309 : Word16 edge_e;
1310 : Word16 edge_0_1, wedge;
1311 : Word32 ratio_m1_m2, m2_m2, d_itd2, itd1_flip;
1312 : Word32 scr_min, scr_max;
1313 : Word64 W_tmp;
1314 :
1315 74333 : hStereoClassif = hCPE->hStereoClassif;
1316 74333 : IF( hCPE->hStereoDft != NULL )
1317 : {
1318 59643 : hItd = hCPE->hStereoDft->hItd;
1319 : }
1320 : ELSE
1321 : {
1322 14690 : hItd = hCPE->hStereoMdct->hItd;
1323 : }
1324 :
1325 74333 : m1 = 0;
1326 74333 : move32();
1327 74333 : m2 = 0;
1328 74333 : move32();
1329 :
1330 74333 : itd2 = 0;
1331 74333 : move16();
1332 : // thr = ( hCPE->element_brate >= IVAS_32k ? 2 : 1 ) * CLASSIFIER_ITD_THRES;
1333 74333 : IF( GE_32( hCPE->element_brate, IVAS_32k ) )
1334 : {
1335 35913 : thr = 2 * CLASSIFIER_ITD_THRES;
1336 35913 : move16();
1337 : }
1338 : ELSE
1339 : {
1340 38420 : thr = CLASSIFIER_ITD_THRES;
1341 38420 : move16();
1342 : }
1343 74333 : IF( GT_16( itd, thr ) )
1344 : {
1345 16002 : m1 = L_abs( gcc_phat[itd + XTALK_PHAT_LEN] );
1346 16002 : m2 = L_abs( gcc_phat[0] );
1347 16002 : itd2 = -XTALK_PHAT_LEN;
1348 16002 : move16();
1349 3018840 : FOR( i = 1; i < ( XTALK_PHAT_LEN - thr ); i++ )
1350 : {
1351 3002838 : IF( GT_32( L_abs( gcc_phat[i] ), m2 ) )
1352 : {
1353 130652 : itd2 = add( -XTALK_PHAT_LEN, i );
1354 130652 : m2 = L_abs( gcc_phat[i] );
1355 : }
1356 : }
1357 : }
1358 58331 : ELSE IF( LT_16( itd, negate( thr ) ) )
1359 : {
1360 11032 : m1 = L_abs( gcc_phat[itd + XTALK_PHAT_LEN] );
1361 11032 : m2 = L_abs( gcc_phat[XTALK_PHAT_LEN + thr + 1] );
1362 11032 : itd2 = add( thr, 1 );
1363 2074008 : FOR( i = ( XTALK_PHAT_LEN + 2 + thr ); i < 2 * XTALK_PHAT_LEN + 1; i++ )
1364 : {
1365 2062976 : IF( GT_32( L_abs( gcc_phat[i] ), m2 ) )
1366 : {
1367 56322 : itd2 = add( -XTALK_PHAT_LEN, i );
1368 56322 : m2 = L_abs( gcc_phat[i] );
1369 : }
1370 : }
1371 : }
1372 :
1373 : // ratio_m1_m2 = fabsf( m1 * m2 ) / fabsf( m1 + m2 + 1.0f );
1374 : Word16 exp;
1375 74333 : ratio_m1_m2 = BASOP_Util_Divide3232_Scale_newton( L_abs( Mpy_32_32( m1, m2 ) ), L_abs( L_add( L_add( L_shr( m1, 2 ), L_shr( m2, 2 ) ), ONE_IN_Q29 ) ), &exp );
1376 74333 : exp = sub( exp, 2 );
1377 : // m2_m2 = hItd->prev_m2 * m2;
1378 74333 : m2_m2 = Mpy_32_32( hItd->prev_m2_fx, m2 );
1379 : // d_itd2 = (float) abs( itd2 - hItd->prev_itd2 );
1380 74333 : d_itd2 = abs_s( sub( itd2, hItd->prev_itd2 ) ); // Q0
1381 : // itd1_flip = (float) ( max( itd, hItd->prev_itd1 ) * ( -min( itd, hItd->prev_itd1 ) ) );
1382 74333 : itd1_flip = L_mult0( s_max( itd, hItd->prev_itd1 ), negate( s_min( itd, hItd->prev_itd1 ) ) ); // Q0
1383 :
1384 :
1385 74333 : hStereoClassif->xtalk_fv_fx[E_gphat_d_itd2] = L_shl( d_itd2, 15 ); // Q15
1386 74333 : move32();
1387 74333 : hStereoClassif->xtalk_fv_fx[E_gphat_itd1_flip] = L_shl( itd1_flip, 15 ); // Q15
1388 74333 : move32();
1389 74333 : hStereoClassif->xtalk_fv_fx[E_gphat_ratio_m1_m2] = L_shr_r( Mpy_32_32( ratio_m1_m2, hStereoClassif->prev_ratio_m1_m2_fx ), sub( Q16, exp ) ); // Q15
1390 74333 : move32();
1391 74333 : hStereoClassif->xtalk_fv_fx[E_gphat_m2_m2] = L_shr_r( m2_m2, Q16 ); // Q15
1392 74333 : move32();
1393 :
1394 74333 : hStereoClassif->prev_ratio_m1_m2_fx = L_shl( ratio_m1_m2, exp );
1395 74333 : move32();
1396 :
1397 74333 : set32_fx( fvn, -ONE_IN_Q29, SSC_MAX_NFEA );
1398 :
1399 : /* calcualte raw score based on LR */
1400 74333 : W_tmp = XTALK_INTERCEPT_DFT_Q27;
1401 74333 : move64();
1402 891996 : FOR( i = 0; i < SIZE_XTALK_ISEL_DFT; i++ )
1403 : {
1404 817663 : ind = xtalk_isel_dft[i];
1405 817663 : move16();
1406 :
1407 : /* mean & std removal */
1408 : // fvn[i] = ( hStereoClassif->xtalk_fv[ind] - xtalk_mean_dft[i] ) / xtalk_scale_dft[i];
1409 817663 : fvn[i] = BASOP_Util_Divide3232_Scale_newton( L_sub( hStereoClassif->xtalk_fv_fx[ind], xtalk_mean_dft_q15[i] ), xtalk_scale_dft_q15[i], &exp ); // Q15
1410 817663 : move32();
1411 817663 : fvn[i] = L_shl_sat( fvn[i], sub( exp, 2 ) ); // Q29
1412 817663 : move32();
1413 :
1414 : /* LR */
1415 : // score += fvn[i] * xtalk_coef_dft[i];
1416 817663 : W_tmp = W_add( W_tmp, L_shr( Mpy_32_32( fvn[i], xtalk_coef_dft_q30[i] ), 1 ) ); // Q27
1417 : }
1418 :
1419 : /* normalize score to -1:+1 */
1420 74333 : IF( GT_64( W_tmp, XTALK_SCORE_THR_DFT_Q27 ) )
1421 : {
1422 2463 : score = MAX_32; // Q31
1423 2463 : move32();
1424 : }
1425 71870 : ELSE IF( LT_64( W_tmp, -XTALK_SCORE_THR_DFT_Q27 ) )
1426 : {
1427 4536 : score = MIN_32; // Q31
1428 4536 : move32();
1429 : }
1430 : ELSE
1431 : {
1432 : // score /= XTALK_SCORE_THR_DFT;
1433 67334 : score = L_shl_sat( W_extract_l( W_tmp ), 2 ); // Q27->Q31/XTALK_SCORE_THR_DFT
1434 : }
1435 :
1436 : /* raw score */
1437 74333 : hStereoClassif->xtalk_score_fx = score;
1438 74333 : move32();
1439 : // printf( "%f ", (float) hStereoClassif->xtalk_score_fx / 0x7fffffff );
1440 :
1441 74333 : if ( !hStereoClassif->vad_flag_glob )
1442 : {
1443 24931 : score = 0;
1444 24931 : move32();
1445 : }
1446 :
1447 :
1448 : /* rising edge detector on raw score -> yields 1 if strong rising edge is detected in the given buffer */
1449 74333 : Copy32( &hStereoClassif->xtalk_score_buf_fx[0], &hStereoClassif->xtalk_score_buf_fx[1], XTALK_SCORE_BUF_LEN - 1 );
1450 74333 : hStereoClassif->xtalk_score_buf_fx[0] = score;
1451 74333 : move32();
1452 74333 : minimum_l( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, &scr_min );
1453 74333 : maximum_l( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, &scr_max );
1454 :
1455 74333 : test();
1456 74333 : IF( LT_32( scr_min, 429496730 /*0.2f*/ ) && scr_max > 0 )
1457 15815 : {
1458 15815 : edge = redge_detect_fx( hStereoClassif->xtalk_score_buf_fx, XTALK_SCORE_BUF_LEN, -429496730 /*-0.2f*/, MAX_32 /*1.0f*/, &edge_e );
1459 : // edge_0_1 = lin_interp( 1 - edge, 1.0f, 1.0f, 0.83f, 0.0f, 1 );
1460 : Word16 temp;
1461 15815 : Word16 temp_e = BASOP_Util_Add_MantExp( MAX_16, 0, negate( extract_h( edge ) ), edge_e, &temp );
1462 15815 : temp = shl( temp, temp_e ); // Q15
1463 15815 : edge_0_1 = lin_interp_ivas_fx( temp, MAX_16, MAX_16, 27197, 0, 1 );
1464 : }
1465 : ELSE
1466 : {
1467 58518 : edge_0_1 = 0;
1468 58518 : move16();
1469 : }
1470 :
1471 : /* weight raw score based on rising edge detector */
1472 : // wedge = lin_interp( edge_0_1, 0.0f, 0.95f, 1.0f, 0.3f, 1 );
1473 74333 : wedge = lin_interp_ivas_fx( edge_0_1, 0, 31129, MAX_16, 9830, 1 );
1474 : // hStereoClassif->xtalk_wscore = wedge * hStereoClassif->xtalk_wscore + ( 1 - wedge ) * score;
1475 74333 : hStereoClassif->xtalk_wscore_fx = L_add( Mpy_32_16_1( hStereoClassif->xtalk_wscore_fx, wedge ), Mpy_32_16_1( score, sub( MAX_16, wedge ) ) );
1476 74333 : move32();
1477 :
1478 74333 : test();
1479 74333 : test();
1480 74333 : test();
1481 74333 : test();
1482 74333 : test();
1483 74333 : test();
1484 74333 : test();
1485 74333 : test();
1486 74333 : test();
1487 74333 : test();
1488 74333 : test();
1489 74333 : test();
1490 74333 : test();
1491 74333 : test();
1492 74333 : test();
1493 74333 : test();
1494 74333 : test();
1495 74333 : test();
1496 74333 : test();
1497 74333 : test();
1498 74333 : IF( ( itd == 0 ) || ( hCPE->hCoreCoder[0]->vad_flag == 0 ) )
1499 : {
1500 39403 : hStereoClassif->xtalk_decision = 0;
1501 39403 : move16();
1502 : }
1503 34930 : ELSE IF( GE_32( hCPE->element_brate, IVAS_24k4 ) &&
1504 : hStereoClassif->xtalk_decision == 0 && ( ( LT_32( Mpy_32_32( m1, 1717986918 /*0.8f*/ ), m2 ) && LT_32( Mpy_32_32( hItd->prev_m1_fx, 1717986918 /*0.8*/ ), hItd->prev_m2_fx ) && LT_16( abs_s( sub( itd2, hItd->prev_itd2 ) ), 4 ) && GT_32( m1, 322122547 /*0.15*/ ) && GT_32( hItd->prev_m1_fx, 322122547 /*0.15*/ ) ) || GT_32( hStereoClassif->xtalk_wscore_fx, 1717986918 /*0.8*/ ) || ( GT_16( itd, thr ) && LT_16( hItd->prev_itd1, negate( thr ) ) && hStereoClassif->silence_flag == 0 ) || ( GT_16( hItd->prev_itd1, thr ) && LT_16( itd, negate( thr ) ) && hStereoClassif->silence_flag == 0 ) ) &&
1505 : EQ_16( hCPE->hCoreCoder[0]->vad_flag, 1 ) && hCPE->hCoreCoder[0]->flag_noisy_speech_snr == 0 && GT_16( hCPE->hCoreCoder[0]->hNoiseEst->aEn_inac_cnt, 15 ) )
1506 : {
1507 0 : hStereoClassif->xtalk_decision = 1;
1508 0 : move16();
1509 : }
1510 34930 : ELSE IF( GE_32( hCPE->element_brate, IVAS_16k4 ) && hStereoClassif->xtalk_decision == 0 && GT_16( abs_s( itd ), STEREO_DFT_ITD_MAX ) && GT_16( sub( hCPE->hCoreCoder[0]->lp_speech_fx, hCPE->hCoreCoder[0]->lp_noise_fx ), 25 << 8 ) )
1511 : {
1512 69 : hStereoClassif->xtalk_decision = 1;
1513 69 : move16();
1514 : }
1515 :
1516 : /* updates */
1517 74333 : hItd->prev_m1_fx = m1;
1518 74333 : move32();
1519 74333 : hItd->prev_m2_fx = m2;
1520 74333 : move32();
1521 74333 : hItd->prev_itd1 = itd;
1522 74333 : move16();
1523 74333 : hItd->prev_itd2 = itd2;
1524 74333 : move16();
1525 :
1526 : #ifdef DEBUG_FORCE_DIR
1527 : if ( hCPE->hCoreCoder[0]->force_dir[0] != '\0' )
1528 : {
1529 : dbgread( &hStereoClassif->xtalk_decision, sizeof( int16_t ), 1, fname( hCPE->hCoreCoder[0]->force_dir, "force_xtalk_decision.enf", -1, -1, -1 ) );
1530 : }
1531 : else
1532 : {
1533 : dbgwrite( &hStereoClassif->xtalk_decision, sizeof( int16_t ), 1, 1, "res/force_xtalk_decision.enf" );
1534 : }
1535 : #endif
1536 :
1537 74333 : return;
1538 : }
1539 :
1540 : /*-------------------------------------------------------------------*
1541 : * Function rc_filter()
1542 : *
1543 : *
1544 : *-------------------------------------------------------------------*/
1545 63470 : static void rc_filter_fx(
1546 : const Word32 x, // Q31
1547 : Word32 *y, // Q31
1548 : const Word16 order,
1549 : const Word32 tau ) // Q31
1550 : {
1551 : Word16 i;
1552 :
1553 63470 : y[0] = L_add( Mpy_32_32( tau, y[0] ), Mpy_32_32( L_sub( MAX_32, tau ), x ) );
1554 63470 : move32();
1555 1269400 : FOR( i = 1; i < order; i++ )
1556 : {
1557 1205930 : y[i] = L_add( Mpy_32_32( tau, y[i] ), Mpy_32_32( L_sub( MAX_32, tau ), y[i - 1] ) );
1558 1205930 : move32();
1559 : }
1560 :
1561 63470 : return;
1562 : }
1563 :
1564 : /*-------------------------------------------------------------------*
1565 : * Function edge_detect_fx()
1566 : *
1567 : * Rising/falling edge detection algorithm
1568 : * Analyzes the input buffer and outputs strength and type of the detected edge (rising or falling)
1569 : * Set edge_type to 0/1/2 when calling this function to specify the edge type you want to detect. The returned value will be modified
1570 : * according to the edge type detected (-1 indicates that no edge has been detected)
1571 : *-------------------------------------------------------------------*/
1572 894 : static void edge_detect_fx(
1573 : const Word32 *inp, /* i : input buffer Q31*/
1574 : const Word16 len, /* i : length of the input buffer Q0*/
1575 : const Word32 inp_min, /* i : minimum value for edge detection Q28*/
1576 : const Word32 inp_max, /* i : maximum value for edge detection Q28*/
1577 : Word16 *edge_str, /* o : edge strength (from 0 to Inf) Q15*/
1578 : Word16 *edge_type /* i/o: edge type (to be) detected: 0 = falling, 1 = rising, 2 = both */
1579 : )
1580 : {
1581 : Word16 i, j, et;
1582 : Word32 y, err, edge_slope, edge[EDGE_MAX_LEN];
1583 : Word32 edge_min, err0, L_tmp;
1584 :
1585 894 : et = -1;
1586 894 : move16();
1587 894 : edge_min = ONE_IN_Q25;
1588 894 : move32();
1589 :
1590 894 : test();
1591 894 : IF( *edge_type == 0 || EQ_16( *edge_type, 2 ) )
1592 : {
1593 : /* falling edge detection */
1594 894 : set_zero_fx( edge, EDGE_MAX_LEN );
1595 :
1596 : /* set error at 0th index */
1597 894 : IF( GT_32( L_shr( inp[0], 6 ), inp_max ) )
1598 : {
1599 0 : err0 = 0;
1600 0 : move32();
1601 : }
1602 : ELSE
1603 : {
1604 : /* inhibits edge smearing effect */
1605 : /* err0 = powf( inp[0] - inp_max, 2 ); */
1606 894 : L_tmp = L_sub( L_shr( inp[0], 3 ), inp_max ); // Q28
1607 894 : err0 = Mpy_32_32( L_tmp, L_tmp ); // Q25
1608 : }
1609 :
1610 : /* test edges on intervals from 2 to len */
1611 4470 : FOR( i = 1; i < len; i++ )
1612 : {
1613 3576 : IF( EQ_16( i, 1 ) )
1614 : {
1615 894 : edge_slope = L_sub( inp_max, inp_min ); // Q28
1616 : }
1617 : ELSE
1618 : {
1619 2682 : edge_slope = Mpy_32_16_1( L_sub( inp_max, inp_min ), divide1616( 1, i ) ); // Q28
1620 : }
1621 3576 : edge[i] = err0; // Q25
1622 3576 : move32();
1623 12516 : FOR( j = 1; j <= i; j++ )
1624 : {
1625 8940 : y = L_sub( inp_max, imult3216( edge_slope, j ) ); // Q28
1626 8940 : err = L_sub( y, check_bounds_l( L_shr( inp[j], 3 ), inp_min, inp_max ) ); // Q28
1627 8940 : edge[i] = Madd_32_32( edge[i], err, err ); // Q25
1628 8940 : move32();
1629 : }
1630 :
1631 3576 : edge[i] = Mpy_32_16_1( edge[i], divide1616( 1, add( i, 1 ) ) ); // Q25
1632 3576 : move32();
1633 :
1634 3576 : IF( LT_32( edge[i], edge_min ) )
1635 : {
1636 2590 : edge_min = edge[i]; // Q25
1637 2590 : move32();
1638 2590 : et = 0;
1639 2590 : move16();
1640 : }
1641 : }
1642 : }
1643 :
1644 894 : test();
1645 894 : IF( EQ_16( *edge_type, 1 ) || EQ_16( *edge_type, 2 ) )
1646 : {
1647 : /* rising edge detection */
1648 0 : set_zero_fx( edge, EDGE_MAX_LEN );
1649 :
1650 : /* set error at 0th index */
1651 0 : IF( LT_32( L_shr( inp[0], 3 ), inp_min ) )
1652 : {
1653 0 : err0 = 0;
1654 0 : move32();
1655 : }
1656 : ELSE
1657 : {
1658 : /* inhibits edge smearing effect */
1659 : /*err0 = powf( inp[0] - inp_min, 2 );*/
1660 0 : L_tmp = L_sub( L_shr( inp[0], 3 ), inp_min ); // Q28
1661 0 : err0 = Mpy_32_32( L_tmp, L_tmp ); // Q25
1662 : }
1663 :
1664 : /* test edges on intervals from 2 to len */
1665 0 : FOR( i = 1; i <= len; i++ )
1666 : {
1667 0 : IF( EQ_16( i, 1 ) )
1668 : {
1669 0 : edge_slope = L_sub( inp_max, inp_min ); // Q28
1670 : }
1671 : ELSE
1672 : {
1673 0 : edge_slope = Mpy_32_16_1( L_sub( inp_max, inp_min ), divide1616( 1, i ) ); // Q28
1674 : }
1675 :
1676 0 : edge[i] = err0; // Q25
1677 0 : move32();
1678 :
1679 0 : FOR( j = 1; j < i; j++ )
1680 : {
1681 0 : y = L_add( inp_min, imult3216( edge_slope, j ) ); // Q28
1682 0 : err = L_sub( y, check_bounds_l( L_shr( inp[j], 1 ), inp_min, inp_max ) ); // Q28
1683 0 : edge[i] = Madd_32_32( edge[i], err, err ); // Q25
1684 0 : move32();
1685 : }
1686 :
1687 0 : edge[i] = Mpy_32_16_1( edge[i], divide1616( 1, add( i, 1 ) ) ); // Q25
1688 0 : move32();
1689 :
1690 0 : IF( LT_32( edge[i], edge_min ) )
1691 : {
1692 0 : edge_min = edge[i]; // Q25
1693 0 : move32();
1694 0 : et = 1;
1695 0 : move16();
1696 : }
1697 : }
1698 : }
1699 :
1700 894 : *edge_str = extract_h( L_shl_sat( edge_min, 16 - 10 ) ); // Q15
1701 894 : move16();
1702 894 : *edge_type = et; // Q0
1703 894 : move16();
1704 :
1705 894 : return;
1706 : }
1707 :
1708 : /*-------------------------------------------------------------------*
1709 : * Function redge_detect()
1710 : *
1711 : * Rising edge detection algorithm
1712 : * Analyzes the input buffer and outputs value close to 1 when it detects strong rising edge
1713 : *-------------------------------------------------------------------*/
1714 :
1715 : /*! r: rising edge strength normalized to 0-1 */
1716 15815 : static Word32 redge_detect_fx(
1717 : const Word32 *inp, /* i : input buffer (ordered from newest to oldest values) Q31*/
1718 : const Word16 len, /* i : length of the input buffer */
1719 : const Word32 inp_min, /* i : minimum value for edge detection Q31 */
1720 : const Word32 inp_max, /* i : maximum value for edge detection Q31 */
1721 : Word16 *edge_min_e )
1722 : {
1723 : Word16 i, j;
1724 : Word32 y, err, edge_slope, edge[REDGE_MAX_LEN];
1725 : Word16 y_e, edge_slope_e, edge_e[REDGE_MAX_LEN];
1726 : Word32 edge_min, err0;
1727 : Word16 err0_e;
1728 : Word16 L_temp_e;
1729 : Word32 L_temp;
1730 :
1731 15815 : set32_fx( edge, 0, REDGE_MAX_LEN );
1732 15815 : set16_fx( edge_e, 0, REDGE_MAX_LEN );
1733 15815 : edge_min = 10000000 /*1e7f*/; // Q0
1734 15815 : move32();
1735 15815 : *edge_min_e = 31;
1736 15815 : move16();
1737 :
1738 : /* test rising edges on intervals from 2 to len */
1739 15815 : IF( GT_32( inp[0], inp_max ) )
1740 : {
1741 0 : err0 = 0;
1742 0 : move32();
1743 0 : err0_e = 0;
1744 0 : move16();
1745 : }
1746 : ELSE
1747 : {
1748 : // err0 = powf( inp[0] - inp_max, 2 );
1749 : // Word32 temp = L_sub( inp[0], inp_max );
1750 15815 : err0 = BASOP_Util_Add_Mant32Exp( inp[0], 0, L_negate( inp_max ), 0, &err0_e );
1751 15815 : err0 = Mpy_32_32( err0, err0 );
1752 15815 : err0_e = shl( err0_e, 1 );
1753 : }
1754 79075 : FOR( i = 1; i < len; i++ )
1755 : {
1756 : // edge_slope = ( inp_max - inp_min ) / i;
1757 63260 : L_temp = BASOP_Util_Add_Mant32Exp( inp_max, 0, L_negate( inp_min ), 0, &L_temp_e );
1758 63260 : edge_slope = BASOP_Util_Divide3232_Scale_newton( L_temp, i, &edge_slope_e );
1759 63260 : edge_slope_e = add( edge_slope_e, sub( L_temp_e, 31 ) );
1760 63260 : edge[i] = err0;
1761 63260 : move32();
1762 63260 : edge_e[i] = err0_e;
1763 63260 : move16();
1764 158150 : FOR( j = 1; j < i; j++ )
1765 : {
1766 : // y = inp_max - edge_slope * j;
1767 94890 : y = BASOP_Util_Add_Mant32Exp( inp_max, 0, L_negate( Mpy_32_32( edge_slope, L_shl( j, 28 ) ) ), add( edge_slope_e, 3 ), &y_e );
1768 94890 : y = L_shl( y, y_e );
1769 94890 : IF( EQ_32( inp[j], inp[j - 1] ) && EQ_32( inp[j], inp_max ) )
1770 : {
1771 : /* we are saturated at inp_max */
1772 775 : err = 0;
1773 775 : move32();
1774 : }
1775 94115 : ELSE IF( LT_32( inp[j], inp_min ) )
1776 : {
1777 : /* we are below inp_min */
1778 6885 : err = L_sub( y, inp_min );
1779 : }
1780 : ELSE
1781 : {
1782 87230 : err = L_sub( y, inp[j] );
1783 : }
1784 94890 : err = Mpy_32_32( err, err );
1785 : // edge[i] = L_add( edge[i], err );
1786 94890 : edge[i] = BASOP_Util_Add_Mant32Exp( edge[i], edge_e[i], err, 0, &edge_e[i] );
1787 94890 : move32();
1788 : }
1789 :
1790 : // edge[i] /= i + 1;
1791 63260 : edge[i] = BASOP_Util_Divide3232_Scale_newton( edge[i], add( i, 1 ), &L_temp_e );
1792 63260 : move32();
1793 63260 : edge_e[i] = add( L_temp_e, sub( edge_e[i], 31 ) );
1794 63260 : move16();
1795 :
1796 : // if ( edge[i] < edge_min )
1797 63260 : IF( BASOP_Util_Cmp_Mant32Exp( edge[i], edge_e[i], edge_min, *edge_min_e ) < 0 )
1798 : {
1799 56744 : edge_min = edge[i];
1800 56744 : move32();
1801 56744 : *edge_min_e = edge_e[i];
1802 56744 : move16();
1803 : }
1804 : }
1805 :
1806 15815 : return edge_min; // Q31
1807 : }
|