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 "options.h"
35 : #include <math.h>
36 : #include "ivas_prot_rend_fx.h"
37 : #include "ivas_rom_rend.h"
38 : #include "prot_fx.h"
39 : #include "wmc_auto.h"
40 :
41 :
42 : /*---------------------------------------------------------------------*
43 : * Local constants
44 : *---------------------------------------------------------------------*/
45 :
46 :
47 : /*---------------------------------------------------------------------*
48 : * Local function prototypes
49 : *---------------------------------------------------------------------*/
50 :
51 : static void sincResample_fx( const Word32 *input_fx, Word32 *output_fx, const Word16 length_in, const Word16 length_out );
52 :
53 : /*---------------------------------------------------------------------*
54 : * TDREND_Apply_ITD()
55 : *
56 : * Apply ITD by delaying late channel
57 : *---------------------------------------------------------------------*/
58 1388199 : void TDREND_Apply_ITD_fx(
59 : Word32 *input_fx, /* i : Input subframe to be time adjusted Qx */
60 : Word32 *out_left_fx, /* o : Output left channel with ITD applied Qx */
61 : Word32 *out_right_fx, /* o : Output right channel with ITD applied Qx */
62 : Word16 *previtd, /* i/o: Previous ITD value Q0 */
63 : const Word16 itd, /* i : Current subframe ITD value Q0 */
64 : Word32 *mem_itd_fx, /* i/o: ITD buffer memory Qx */
65 : const Word16 length /* i : Subframe length Q0 */
66 : )
67 : {
68 : Word16 transition_len;
69 : Word16 tlen1, tlen2, tlen3;
70 : Word16 length_in1;
71 : Word16 length_in2;
72 : Word16 currShift;
73 : Word16 prevShift;
74 : Word32 *pstart1_fx;
75 : Word32 *pstart2_fx;
76 : Word32 *pstart3_fx;
77 : Word32 buffer_fx[ITD_MEM_LEN + L_SUBFRAME5MS_48k]; // Qx
78 : Word32 *p_input_fx;
79 : Word32 *out_buf_A_fx, *out_buf_B_fx;
80 :
81 1388199 : push_wmops( "TDREND_Apply_ITD" );
82 :
83 : /* Prepare resampling buffer */
84 1388199 : Copy32( mem_itd_fx, buffer_fx, ITD_MEM_LEN ); /* Retrieve memory */ // Qx
85 1388199 : p_input_fx = buffer_fx + ITD_MEM_LEN; /* pointer to the current subframe */ // Qx
86 1388199 : Copy32( input_fx, p_input_fx, length ); /* input current subframe */ // Qx
87 1388199 : Copy32( buffer_fx + length, mem_itd_fx, ITD_MEM_LEN ); /* update memory for next frame */ // Qx
88 :
89 1388199 : currShift = abs_s( itd ); // Q0
90 1388199 : prevShift = abs_s( *previtd ); // Q0
91 1388199 : tlen3 = s_max( 0, sub( SFX_SPAT_BIN_SINC_M, currShift ) ); /* Make sure there is enough look-ahead for the sinc resampling */ // Q0
92 1388199 : transition_len = sub( length, tlen3 ); // Q0
93 :
94 1388199 : IF( i_mult( ( *previtd ), itd ) < 0 )
95 : {
96 : /* ITD sign change - apply shift on both channels */
97 40763 : Word16 tmp1 = imult1616( transition_len, prevShift ); // Q0
98 40763 : Word16 tmp2 = add( prevShift, currShift ); // Q0
99 : Word16 tmp_e;
100 40763 : Word16 tmp3 = BASOP_Util_Divide1616_Scale( tmp1, tmp2, &tmp_e ); // exp(tmp_e)
101 : Word16 tmp4;
102 40763 : Word16 tmp_e2 = BASOP_Util_Add_MantExp( tmp3, tmp_e, ONE_IN_Q14, 0, &tmp4 ); // exp(tmp4)
103 40763 : tmp4 = shr( tmp4, sub( 15, tmp_e2 ) ); // Q0
104 40763 : tlen1 = tmp4; // Q0
105 40763 : move16();
106 :
107 40763 : tlen2 = sub( transition_len, tlen1 ); // Q0
108 40763 : pstart1_fx = p_input_fx - prevShift; // Qx
109 40763 : length_in1 = add( tlen1, prevShift ); // Q0
110 40763 : pstart2_fx = pstart1_fx + length_in1; // Qx
111 40763 : length_in2 = sub( tlen2, currShift ); // Q0
112 40763 : pstart3_fx = pstart2_fx + length_in2; // Qx
113 : }
114 : ELSE
115 : {
116 : /* ITD sign stays the same, or one of them is zero */
117 1347436 : tlen1 = transition_len; // Q0
118 1347436 : move16();
119 1347436 : tlen2 = 0; // Q0
120 1347436 : move16();
121 1347436 : pstart1_fx = p_input_fx - prevShift; // Qx
122 1347436 : length_in1 = sub( add( transition_len, prevShift ), currShift ); // Q0
123 1347436 : pstart2_fx = pstart1_fx + length_in1; // Qx
124 1347436 : length_in2 = 0; // Q0
125 1347436 : move16();
126 1347436 : pstart3_fx = pstart2_fx + add( length_in2, currShift ); // Qx
127 : }
128 :
129 1388199 : IF( *previtd == 0 )
130 : {
131 118838 : IF( itd > 0 )
132 : {
133 4194 : out_buf_A_fx = out_right_fx; // Qx
134 4194 : out_buf_B_fx = out_left_fx; // Qx
135 : }
136 : ELSE
137 : {
138 114644 : out_buf_A_fx = out_left_fx; // Qx
139 114644 : out_buf_B_fx = out_right_fx; // Qx
140 : }
141 : }
142 : ELSE
143 : {
144 1269361 : IF( *previtd > 0 )
145 : {
146 639852 : out_buf_A_fx = out_right_fx; // Qx
147 639852 : out_buf_B_fx = out_left_fx; // Qx
148 : }
149 : ELSE
150 : {
151 629509 : out_buf_A_fx = out_left_fx; // Qx
152 629509 : out_buf_B_fx = out_right_fx; // Qx
153 : }
154 : }
155 :
156 : /* Output buffer A */
157 1388199 : sincResample_fx( pstart1_fx, out_buf_A_fx, length_in1, tlen1 );
158 1388199 : Copy32( pstart2_fx, out_buf_A_fx + tlen1, sub( length, tlen1 ) ); // Qx
159 :
160 : /* Output buffer B */
161 1388199 : Copy32( p_input_fx, out_buf_B_fx, tlen1 ); // Qx
162 1388199 : sincResample_fx( pstart2_fx, out_buf_B_fx + tlen1, length_in2, tlen2 );
163 1388199 : Copy32( pstart3_fx, out_buf_B_fx + transition_len, tlen3 ); // Qx
164 :
165 1388199 : *previtd = itd; // Q0
166 1388199 : move16();
167 :
168 1388199 : pop_wmops();
169 1388199 : return;
170 : }
171 :
172 : /*---------------------------------------------------------------------*
173 : * sincResample()
174 : *
175 : * Resample signal (stretch/compress) to new ITD
176 : * The sinc resampling reads SFX_SPAT_BIN_SINC_M (5) samples outside of
177 : * the target frame.
178 : *---------------------------------------------------------------------*/
179 :
180 2776398 : static void sincResample_fx(
181 : const Word32 *input_fx, /*i : Input signal Qx */
182 : Word32 *output_fx, /*o : Output signal Qx */
183 : const Word16 length_in, /*i : Input length Q0 */
184 : const Word16 length_out /*i : Output length Q0 */
185 : )
186 : {
187 : Word16 snc0;
188 : Word16 i, j;
189 : Word16 t;
190 : Word32 t_step_fx;
191 : Word16 t_step_e;
192 : Word32 t_frac_fx;
193 : Word16 t_frac_e;
194 : Word64 t_frac_fx_acc;
195 : Word64 tmp64_fx; // Qx + 32
196 : const Word32 *p_mid_fx;
197 : const Word32 *p_forward_fx;
198 : const Word32 *p_backward_fx;
199 : const Word32 *p_sinc_forward_fx;
200 : const Word32 *p_sinc_backward_fx;
201 :
202 : // epsilon: 1e-15f
203 2776398 : const Word32 eps = 1208925824; // exp(eps_e)
204 2776398 : move32();
205 2776398 : const Word16 eps_e = -49;
206 2776398 : move16();
207 :
208 : /* avoid division by 0 */
209 2776398 : IF( 0 == length_out )
210 : {
211 1347436 : return;
212 : }
213 :
214 : /* Compute fractional time step */
215 1428962 : t_step_fx = L_deposit_h( BASOP_Util_Divide1616_Scale( length_in, length_out, &t_step_e ) ); // exp(t_step_e)
216 1428962 : t_frac_fx_acc = 0;
217 1428962 : move64();
218 1428962 : t_frac_fx = 0;
219 1428962 : move32();
220 1428962 : t_frac_e = 0;
221 1428962 : move16();
222 :
223 326814739 : FOR( i = 0; i < length_out; i++ )
224 : {
225 : Word16 t_frac_plus_eps_e;
226 325385777 : Word32 t_frac_plus_eps = BASOP_Util_Add_Mant32Exp( t_frac_fx, t_frac_e, eps, eps_e, &t_frac_plus_eps_e ); // exp(t_frac_plus_eps_e)
227 325385777 : t = extract_l( L_shr( t_frac_plus_eps, sub( 31, t_frac_plus_eps_e ) ) ); // Q0
228 :
229 : /* Calculate the sinc-index for the center value of the sinc */
230 : Word16 center_val_e;
231 : Word64 center_val;
232 : #ifndef FIX_ISSUE_1811_EXCEEDING_W_SHIFTS
233 : center_val = W_sub( t_frac_plus_eps, W_shl( t, sub( 31, t_frac_plus_eps_e ) ) ); // exp(center_val_e)
234 : #else
235 325385777 : center_val = W_sub( t_frac_plus_eps, W_shl( t, s_min( sub( 31, t_frac_plus_eps_e ), 63 ) ) ); // exp( center_val_e )
236 : #endif
237 325385777 : center_val_e = add( t_frac_plus_eps_e, 6 );
238 325385777 : Word16 com_e = s_max( 0, center_val_e );
239 325385777 : center_val = W_add( W_shr( center_val, sub( com_e, center_val_e ) ), W_shl( 1, sub( 30, com_e ) ) ); // exp(center_val_e)
240 325385777 : snc0 = extract_l( W_shl_sat_l( center_val, sub( com_e, 31 ) ) );
241 : /* Run convolution forward and backward from mid point */
242 325385777 : p_mid_fx = input_fx + t; // Qx
243 325385777 : p_forward_fx = p_mid_fx + 1; // Qx
244 325385777 : p_backward_fx = p_mid_fx - 1; // Qx
245 325385777 : p_sinc_forward_fx = SincTable_fx + sub( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
246 325385777 : p_sinc_backward_fx = SincTable_fx + add( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
247 :
248 325385777 : tmp64_fx = W_mult_32_32( *p_mid_fx, SincTable_fx[snc0] ); /* Middle point */ // Qx + 32
249 :
250 1626928885 : FOR( j = 0; j < SFX_SPAT_BIN_SINC_M - 1; j++ )
251 : {
252 1301543108 : tmp64_fx = W_add( tmp64_fx, W_mac_32_32( W_mult_32_32( *p_forward_fx, *p_sinc_forward_fx ), *p_backward_fx, *p_sinc_backward_fx ) ); // Qx + 32
253 1301543108 : p_sinc_forward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
254 1301543108 : p_sinc_backward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
255 1301543108 : p_forward_fx++; // Qx
256 1301543108 : p_backward_fx--; // Qx
257 : }
258 :
259 325385777 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_forward_fx, *p_sinc_forward_fx ); /* Integer index always rounded down --> 4 steps backward, 5 steps forward */ // Qx + 32
260 :
261 325385777 : output_fx[i] = W_extract_h( tmp64_fx ); // Qx
262 325385777 : move32();
263 :
264 : /* Advance fractional time */
265 325385777 : t_frac_fx_acc = W_add( t_frac_fx_acc, t_step_fx ); // t_step_e
266 325385777 : Word16 hdrm = W_norm( t_frac_fx_acc );
267 325385777 : hdrm = sub( hdrm, 32 );
268 325385777 : t_frac_fx = W_shl_sat_l( t_frac_fx_acc, hdrm );
269 325385777 : t_frac_e = sub( t_step_e, hdrm );
270 325385777 : move16();
271 : }
272 :
273 1428962 : return;
274 : }
275 :
276 :
277 : /*-------------------------------------------------------------------*
278 : * TDREND_firfilt()
279 : *
280 : * FIR filtering function
281 : *
282 : --------------------------------------------------------------------*/
283 :
284 2776398 : void TDREND_firfilt_fx(
285 : Word32 *signal_fx, /* i/o: Input signal / Filtered signal Qx */
286 : Word32 *filter_fx, /* i/o: FIR filter filter_e */
287 : const Word16 filter_e, /* i : FIR filter exp Q0 */
288 : const Word32 *filter_delta_fx, /* i : FIR filter delta filter_e */
289 : const Word16 intp_count, /* i : interpolation count Q0 */
290 : Word32 *mem_fx, /* i/o: filter memory Qx */
291 : const Word16 subframe_length, /* i : Length of signal Q0 */
292 : const Word16 filterlength, /* i : Filter length Q0 */
293 : const Word32 Gain_fx, /* i : Gain Q30 */
294 : const Word32 prevGain_fx /* i : Previous gain Q30 */
295 : )
296 : {
297 : /* NOTE: this function is implemented with the assumption that the exponent/Q-factor of input signal will not change. */
298 : Word32 buffer_fx[SFX_SPAT_BIN_MAX_FILTER_LENGTH - 1 + L_SUBFRAME5MS_48k]; // Qx
299 : Word32 *p_signal_fx; // Qx
300 : Word32 *p_tmp_fx; // Qx
301 : Word32 *p_filter_fx; // exp(filter_e)
302 : Word16 i, j;
303 : Word32 tmp_fx;
304 : Word32 step_fx /* Q31 */, gain_tmp_fx /* Q31 */, gain_delta_fx /* Q30 */;
305 : Word16 tmp_e;
306 : Word64 tmp64_fx;
307 2776398 : Word16 shift = sub( filter_e, 32 );
308 2776398 : gain_delta_fx = L_sub( Gain_fx, prevGain_fx ); // Q30
309 2776398 : step_fx = L_deposit_h( BASOP_Util_Divide3232_Scale( gain_delta_fx, subframe_length, &tmp_e ) ); // exp(tmp_e)
310 2776398 : tmp_e = sub( tmp_e, Q30 );
311 2776398 : step_fx = L_shl_sat( step_fx, tmp_e ); // Q31
312 2776398 : gain_tmp_fx = L_shl_sat( prevGain_fx, 1 ); // Q31
313 :
314 : /* Handle memory */
315 2776398 : p_signal_fx = buffer_fx + sub( filterlength, 1 ); // Qx
316 2776398 : Copy32( mem_fx, buffer_fx, sub( filterlength, 1 ) ); /* Insert memory */ // Qx
317 : #ifdef NONBE_FIX_1176_OSBA_REVERB_JBM_ASAN_ERROR
318 2776398 : Copy32( signal_fx, p_signal_fx, subframe_length ); /* Insert current frame */ // Qx
319 2776398 : Copy32( p_signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
320 : #else
321 : Copy32( signal_fx, buffer_fx + sub( filterlength, 1 ), subframe_length ); /* Insert current frame */ // Qx
322 : Copy32( signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
323 : #endif
324 :
325 : /* Convolution */
326 20436762 : FOR( i = 0; i < intp_count; i++ )
327 : {
328 17660364 : tmp64_fx = 0;
329 17660364 : move64();
330 17660364 : p_tmp_fx = p_signal_fx + i; // Qx
331 17660364 : p_filter_fx = filter_fx; // exp(filter_e)
332 :
333 :
334 2231383208 : FOR( j = 0; j < filterlength; j++ )
335 : {
336 2213722844 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
337 2213722844 : p_filter_fx++; // exp(filter_e)
338 2213722844 : p_tmp_fx--; // Qx
339 : }
340 :
341 : // This is done to keep the output Q same as input Q for signal
342 17660364 : tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
343 :
344 : /* Apply linear gain interpolation in case of abrupt gain changes */
345 17660364 : gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
346 17660364 : signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
347 17660364 : move32();
348 17660364 : v_add_fx( filter_fx, filter_delta_fx, filter_fx, filterlength ); // exp(filter_e)
349 : }
350 638192194 : FOR( ; i < subframe_length; i++ )
351 : {
352 635415796 : tmp64_fx = 0;
353 635415796 : move64();
354 635415796 : p_tmp_fx = p_signal_fx + i; // Qx
355 635415796 : p_filter_fx = filter_fx; // exp(filter_e)
356 :
357 :
358 81184343192 : FOR( j = 0; j < filterlength; j++ )
359 : {
360 80548927396 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
361 80548927396 : p_filter_fx++; // exp(filter_e)
362 80548927396 : p_tmp_fx--; // Qx
363 : }
364 :
365 : // This is done to keep the output Q same as input Q for signal
366 635415796 : tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
367 :
368 : /* Apply linear gain interpolation in case of abrupt gain changes */
369 635415796 : gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
370 635415796 : signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
371 635415796 : move32();
372 : }
373 :
374 2776398 : return;
375 : }
|