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 1388227 : 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 1388227 : push_wmops( "TDREND_Apply_ITD" );
82 :
83 : /* Prepare resampling buffer */
84 1388227 : Copy32( mem_itd_fx, buffer_fx, ITD_MEM_LEN ); /* Retrieve memory */ // Qx
85 1388227 : p_input_fx = buffer_fx + ITD_MEM_LEN; /* pointer to the current subframe */ // Qx
86 1388227 : Copy32( input_fx, p_input_fx, length ); /* input current subframe */ // Qx
87 1388227 : Copy32( buffer_fx + length, mem_itd_fx, ITD_MEM_LEN ); /* update memory for next frame */ // Qx
88 :
89 1388227 : currShift = abs_s( itd ); // Q0
90 1388227 : prevShift = abs_s( *previtd ); // Q0
91 1388227 : tlen3 = s_max( 0, sub( SFX_SPAT_BIN_SINC_M, currShift ) ); /* Make sure there is enough look-ahead for the sinc resampling */ // Q0
92 1388227 : transition_len = sub( length, tlen3 ); // Q0
93 :
94 1388227 : 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 1347464 : tlen1 = transition_len; // Q0
118 1347464 : move16();
119 1347464 : tlen2 = 0; // Q0
120 1347464 : move16();
121 1347464 : pstart1_fx = p_input_fx - prevShift; // Qx
122 1347464 : length_in1 = sub( add( transition_len, prevShift ), currShift ); // Q0
123 1347464 : pstart2_fx = pstart1_fx + length_in1; // Qx
124 1347464 : length_in2 = 0; // Q0
125 1347464 : move16();
126 1347464 : pstart3_fx = pstart2_fx + add( length_in2, currShift ); // Qx
127 : }
128 :
129 1388227 : IF( *previtd == 0 )
130 : {
131 118845 : 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 114651 : out_buf_A_fx = out_left_fx; // Qx
139 114651 : out_buf_B_fx = out_right_fx; // Qx
140 : }
141 : }
142 : ELSE
143 : {
144 1269382 : IF( *previtd > 0 )
145 : {
146 639859 : out_buf_A_fx = out_right_fx; // Qx
147 639859 : out_buf_B_fx = out_left_fx; // Qx
148 : }
149 : ELSE
150 : {
151 629523 : out_buf_A_fx = out_left_fx; // Qx
152 629523 : out_buf_B_fx = out_right_fx; // Qx
153 : }
154 : }
155 :
156 : /* Output buffer A */
157 1388227 : sincResample_fx( pstart1_fx, out_buf_A_fx, length_in1, tlen1 );
158 1388227 : Copy32( pstart2_fx, out_buf_A_fx + tlen1, sub( length, tlen1 ) ); // Qx
159 :
160 : /* Output buffer B */
161 1388227 : Copy32( p_input_fx, out_buf_B_fx, tlen1 ); // Qx
162 1388227 : sincResample_fx( pstart2_fx, out_buf_B_fx + tlen1, length_in2, tlen2 );
163 1388227 : Copy32( pstart3_fx, out_buf_B_fx + transition_len, tlen3 ); // Qx
164 :
165 1388227 : *previtd = itd; // Q0
166 1388227 : move16();
167 :
168 1388227 : pop_wmops();
169 1388227 : 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 2776454 : 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 2776454 : const Word32 eps = 1208925824; // exp(eps_e)
204 2776454 : move32();
205 2776454 : const Word16 eps_e = -49;
206 2776454 : move16();
207 :
208 : /* avoid division by 0 */
209 2776454 : IF( 0 == length_out )
210 : {
211 1347464 : return;
212 : }
213 :
214 : /* Compute fractional time step */
215 1428990 : t_step_fx = L_deposit_h( BASOP_Util_Divide1616_Scale( length_in, length_out, &t_step_e ) ); // exp(t_step_e)
216 1428990 : t_frac_fx_acc = 0;
217 1428990 : move64();
218 1428990 : t_frac_fx = 0;
219 1428990 : move32();
220 1428990 : t_frac_e = 0;
221 1428990 : move16();
222 :
223 326821420 : FOR( i = 0; i < length_out; i++ )
224 : {
225 : Word16 t_frac_plus_eps_e;
226 325392430 : 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 325392430 : 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 325392430 : 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 )
233 325392430 : center_val_e = add( t_frac_plus_eps_e, 6 );
234 325392430 : Word16 com_e = s_max( 0, center_val_e );
235 325392430 : 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)
236 325392430 : snc0 = extract_l( W_shl_sat_l( center_val, sub( com_e, 31 ) ) );
237 : /* Run convolution forward and backward from mid point */
238 325392430 : p_mid_fx = input_fx + t; // Qx
239 325392430 : p_forward_fx = p_mid_fx + 1; // Qx
240 325392430 : p_backward_fx = p_mid_fx - 1; // Qx
241 325392430 : p_sinc_forward_fx = SincTable_fx + sub( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
242 325392430 : p_sinc_backward_fx = SincTable_fx + add( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
243 :
244 325392430 : tmp64_fx = W_mult_32_32( *p_mid_fx, SincTable_fx[snc0] ); /* Middle point */ // Qx + 32
245 :
246 1626962150 : FOR( j = 0; j < SFX_SPAT_BIN_SINC_M - 1; j++ )
247 : {
248 1301569720 : 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
249 1301569720 : p_sinc_forward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
250 1301569720 : p_sinc_backward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
251 1301569720 : p_forward_fx++; // Qx
252 1301569720 : p_backward_fx--; // Qx
253 : }
254 :
255 325392430 : 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
256 :
257 325392430 : output_fx[i] = W_extract_h( tmp64_fx ); // Qx
258 325392430 : move32();
259 :
260 : /* Advance fractional time */
261 325392430 : t_frac_fx_acc = W_add( t_frac_fx_acc, t_step_fx ); // t_step_e
262 325392430 : Word16 hdrm = W_norm( t_frac_fx_acc );
263 325392430 : hdrm = sub( hdrm, 32 );
264 325392430 : t_frac_fx = W_shl_sat_l( t_frac_fx_acc, hdrm );
265 325392430 : t_frac_e = sub( t_step_e, hdrm );
266 325392430 : move16();
267 : }
268 :
269 1428990 : return;
270 : }
271 :
272 :
273 : /*-------------------------------------------------------------------*
274 : * TDREND_firfilt()
275 : *
276 : * FIR filtering function
277 : *
278 : --------------------------------------------------------------------*/
279 :
280 2776454 : void TDREND_firfilt_fx(
281 : Word32 *signal_fx, /* i/o: Input signal / Filtered signal Qx */
282 : Word32 *filter_fx, /* i/o: FIR filter filter_e */
283 : const Word16 filter_e, /* i : FIR filter exp Q0 */
284 : const Word32 *filter_delta_fx, /* i : FIR filter delta filter_e */
285 : const Word16 intp_count, /* i : interpolation count Q0 */
286 : Word32 *mem_fx, /* i/o: filter memory Qx */
287 : const Word16 subframe_length, /* i : Length of signal Q0 */
288 : const Word16 filterlength, /* i : Filter length Q0 */
289 : const Word32 Gain_fx, /* i : Gain Q30 */
290 : const Word32 prevGain_fx /* i : Previous gain Q30 */
291 : )
292 : {
293 : /* NOTE: this function is implemented with the assumption that the exponent/Q-factor of input signal will not change. */
294 : Word32 buffer_fx[SFX_SPAT_BIN_MAX_FILTER_LENGTH - 1 + L_SUBFRAME5MS_48k]; // Qx
295 : Word32 *p_signal_fx; // Qx
296 : Word32 *p_tmp_fx; // Qx
297 : Word32 *p_filter_fx; // exp(filter_e)
298 : Word16 i, j;
299 : Word32 tmp_fx;
300 : Word32 step_fx /* Q31 */, gain_tmp_fx /* Q31 */, gain_delta_fx /* Q30 */;
301 : Word16 tmp_e;
302 : Word64 tmp64_fx;
303 2776454 : Word16 shift = sub( filter_e, 32 );
304 2776454 : gain_delta_fx = L_sub( Gain_fx, prevGain_fx ); // Q30
305 2776454 : step_fx = L_deposit_h( BASOP_Util_Divide3232_Scale( gain_delta_fx, subframe_length, &tmp_e ) ); // exp(tmp_e)
306 2776454 : tmp_e = sub( tmp_e, Q30 );
307 2776454 : step_fx = L_shl_sat( step_fx, tmp_e ); // Q31
308 2776454 : gain_tmp_fx = L_shl_sat( prevGain_fx, 1 ); // Q31
309 :
310 : /* Handle memory */
311 2776454 : p_signal_fx = buffer_fx + sub( filterlength, 1 ); // Qx
312 2776454 : Copy32( mem_fx, buffer_fx, sub( filterlength, 1 ) ); /* Insert memory */ // Qx
313 2776454 : Copy32( signal_fx, p_signal_fx, subframe_length ); /* Insert current frame */ // Qx
314 2776454 : Copy32( p_signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
315 :
316 : /* Convolution */
317 20436818 : FOR( i = 0; i < intp_count; i++ )
318 : {
319 17660364 : tmp64_fx = 0;
320 17660364 : move64();
321 17660364 : p_tmp_fx = p_signal_fx + i; // Qx
322 17660364 : p_filter_fx = filter_fx; // exp(filter_e)
323 :
324 :
325 2231383208 : FOR( j = 0; j < filterlength; j++ )
326 : {
327 2213722844 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
328 2213722844 : p_filter_fx++; // exp(filter_e)
329 2213722844 : p_tmp_fx--; // Qx
330 : }
331 :
332 : // This is done to keep the output Q same as input Q for signal
333 17660364 : tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
334 :
335 : /* Apply linear gain interpolation in case of abrupt gain changes */
336 17660364 : gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
337 17660364 : signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
338 17660364 : move32();
339 17660364 : v_add_fx( filter_fx, filter_delta_fx, filter_fx, filterlength ); // exp(filter_e)
340 : }
341 638205690 : FOR( ; i < subframe_length; i++ )
342 : {
343 635429236 : tmp64_fx = 0;
344 635429236 : move64();
345 635429236 : p_tmp_fx = p_signal_fx + i; // Qx
346 635429236 : p_filter_fx = filter_fx; // exp(filter_e)
347 :
348 :
349 81186076952 : FOR( j = 0; j < filterlength; j++ )
350 : {
351 80550647716 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
352 80550647716 : p_filter_fx++; // exp(filter_e)
353 80550647716 : p_tmp_fx--; // Qx
354 : }
355 :
356 : // This is done to keep the output Q same as input Q for signal
357 635429236 : tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
358 :
359 : /* Apply linear gain interpolation in case of abrupt gain changes */
360 635429236 : gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
361 635429236 : signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
362 635429236 : move32();
363 : }
364 :
365 2776454 : return;
366 : }
|