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 1329442 : 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 1329442 : push_wmops( "TDREND_Apply_ITD" );
82 :
83 : /* Prepare resampling buffer */
84 1329442 : Copy32( mem_itd_fx, buffer_fx, ITD_MEM_LEN ); /* Retrieve memory */ // Qx
85 1329442 : p_input_fx = buffer_fx + ITD_MEM_LEN; /* pointer to the current subframe */ // Qx
86 1329442 : Copy32( input_fx, p_input_fx, length ); /* input current subframe */ // Qx
87 1329442 : Copy32( buffer_fx + length, mem_itd_fx, ITD_MEM_LEN ); /* update memory for next frame */ // Qx
88 :
89 1329442 : currShift = abs_s( itd ); // Q0
90 1329442 : prevShift = abs_s( *previtd ); // Q0
91 1329442 : tlen3 = s_max( 0, sub( SFX_SPAT_BIN_SINC_M, currShift ) ); /* Make sure there is enough look-ahead for the sinc resampling */ // Q0
92 1329442 : transition_len = sub( length, tlen3 ); // Q0
93 :
94 1329442 : IF( i_mult( ( *previtd ), itd ) < 0 )
95 : {
96 : /* ITD sign change - apply shift on both channels */
97 38168 : Word16 tmp1 = imult1616( transition_len, prevShift ); // Q0
98 38168 : Word16 tmp2 = add( prevShift, currShift ); // Q0
99 : Word16 tmp_e;
100 38168 : Word16 tmp3 = BASOP_Util_Divide1616_Scale( tmp1, tmp2, &tmp_e ); // exp(tmp_e)
101 : Word16 tmp4;
102 38168 : Word16 tmp_e2 = BASOP_Util_Add_MantExp( tmp3, tmp_e, ONE_IN_Q14, 0, &tmp4 ); // exp(tmp4)
103 38168 : tmp4 = shr( tmp4, sub( 15, tmp_e2 ) ); // Q0
104 38168 : tlen1 = tmp4; // Q0
105 38168 : move16();
106 :
107 38168 : tlen2 = sub( transition_len, tlen1 ); // Q0
108 38168 : pstart1_fx = p_input_fx - prevShift; // Qx
109 38168 : length_in1 = add( tlen1, prevShift ); // Q0
110 38168 : pstart2_fx = pstart1_fx + length_in1; // Qx
111 38168 : length_in2 = sub( tlen2, currShift ); // Q0
112 38168 : pstart3_fx = pstart2_fx + length_in2; // Qx
113 : }
114 : ELSE
115 : {
116 : /* ITD sign stays the same, or one of them is zero */
117 1291274 : tlen1 = transition_len; // Q0
118 1291274 : move16();
119 1291274 : tlen2 = 0; // Q0
120 1291274 : move16();
121 1291274 : pstart1_fx = p_input_fx - prevShift; // Qx
122 1291274 : length_in1 = sub( add( transition_len, prevShift ), currShift ); // Q0
123 1291274 : pstart2_fx = pstart1_fx + length_in1; // Qx
124 1291274 : length_in2 = 0; // Q0
125 1291274 : move16();
126 1291274 : pstart3_fx = pstart2_fx + add( length_in2, currShift ); // Qx
127 : }
128 :
129 1329442 : IF( *previtd == 0 )
130 : {
131 111757 : IF( itd > 0 )
132 : {
133 3849 : out_buf_A_fx = out_right_fx; // Qx
134 3849 : out_buf_B_fx = out_left_fx; // Qx
135 : }
136 : ELSE
137 : {
138 107908 : out_buf_A_fx = out_left_fx; // Qx
139 107908 : out_buf_B_fx = out_right_fx; // Qx
140 : }
141 : }
142 : ELSE
143 : {
144 1217685 : IF( *previtd > 0 )
145 : {
146 613973 : out_buf_A_fx = out_right_fx; // Qx
147 613973 : out_buf_B_fx = out_left_fx; // Qx
148 : }
149 : ELSE
150 : {
151 603712 : out_buf_A_fx = out_left_fx; // Qx
152 603712 : out_buf_B_fx = out_right_fx; // Qx
153 : }
154 : }
155 :
156 : /* Output buffer A */
157 1329442 : sincResample_fx( pstart1_fx, out_buf_A_fx, length_in1, tlen1 );
158 1329442 : Copy32( pstart2_fx, out_buf_A_fx + tlen1, sub( length, tlen1 ) ); // Qx
159 :
160 : /* Output buffer B */
161 1329442 : Copy32( p_input_fx, out_buf_B_fx, tlen1 ); // Qx
162 1329442 : sincResample_fx( pstart2_fx, out_buf_B_fx + tlen1, length_in2, tlen2 );
163 1329442 : Copy32( pstart3_fx, out_buf_B_fx + transition_len, tlen3 ); // Qx
164 :
165 1329442 : *previtd = itd; // Q0
166 1329442 : move16();
167 :
168 1329442 : pop_wmops();
169 1329442 : 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 2658884 : 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 tmp64_fx; // Qx + 32
195 : const Word32 *p_mid_fx;
196 : const Word32 *p_forward_fx;
197 : const Word32 *p_backward_fx;
198 : const Word32 *p_sinc_forward_fx;
199 : const Word32 *p_sinc_backward_fx;
200 :
201 : // epsilon: 1e-15f
202 2658884 : const Word32 eps = 1208925824; // exp(eps_e)
203 2658884 : move32();
204 2658884 : const Word16 eps_e = -49;
205 2658884 : move16();
206 :
207 : /* avoid division by 0 */
208 2658884 : IF( 0 == length_out )
209 : {
210 1291274 : return;
211 : }
212 :
213 : /* Compute fractional time step */
214 1367610 : t_step_fx = L_deposit_h( BASOP_Util_Divide1616_Scale( length_in, length_out, &t_step_e ) ); // exp(t_step_e)
215 1367610 : t_frac_fx = 0;
216 1367610 : move32();
217 1367610 : t_frac_e = 0;
218 1367610 : move16();
219 :
220 314247101 : FOR( i = 0; i < length_out; i++ )
221 : {
222 : Word16 t_frac_plus_eps_e;
223 312879491 : 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)
224 312879491 : t = extract_l( L_shr( t_frac_plus_eps, sub( 31, t_frac_plus_eps_e ) ) ); // Q0
225 :
226 : /* Calculate the sinc-index for the center value of the sinc */
227 : Word32 center_val;
228 : Word16 center_val_e;
229 312879491 : center_val = BASOP_Util_Add_Mant32Exp( t_frac_plus_eps, t_frac_plus_eps_e, L_negate( L_deposit_h( t ) ), 15, ¢er_val_e ); // exp(center_val_e)
230 312879491 : center_val_e = add( center_val_e, 6 ); // center_val * SFX_SPAT_BIN_NUM_SUBSAMPLES (i.e. 64)
231 312879491 : center_val = BASOP_Util_Add_Mant32Exp( center_val, center_val_e, ONE_IN_Q29, 1, ¢er_val_e ); // exp(center_val_e)
232 312879491 : snc0 = extract_l( L_shr( center_val, sub( 31, center_val_e ) ) ); // Q0
233 :
234 : /* Run convolution forward and backward from mid point */
235 312879491 : p_mid_fx = input_fx + t; // Qx
236 312879491 : p_forward_fx = p_mid_fx + 1; // Qx
237 312879491 : p_backward_fx = p_mid_fx - 1; // Qx
238 312879491 : p_sinc_forward_fx = SincTable_fx + sub( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
239 312879491 : p_sinc_backward_fx = SincTable_fx + add( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
240 :
241 312879491 : tmp64_fx = W_mult_32_32( *p_mid_fx, SincTable_fx[snc0] ); /* Middle point */ // Qx + 32
242 :
243 1564397455 : FOR( j = 0; j < SFX_SPAT_BIN_SINC_M - 1; j++ )
244 : {
245 1251517964 : 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
246 1251517964 : p_sinc_forward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
247 1251517964 : p_sinc_backward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES; // Q31
248 1251517964 : p_forward_fx++; // Qx
249 1251517964 : p_backward_fx--; // Qx
250 : }
251 :
252 312879491 : 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
253 :
254 312879491 : output_fx[i] = W_extract_h( tmp64_fx ); // Qx
255 312879491 : move32();
256 :
257 : /* Advance fractional time */
258 312879491 : t_frac_fx = BASOP_Util_Add_Mant32Exp( t_frac_fx, t_frac_e, t_step_fx, t_step_e, &t_frac_e ); // exp( t_frac_fx )
259 : }
260 :
261 1367610 : return;
262 : }
263 :
264 :
265 : /*-------------------------------------------------------------------*
266 : * TDREND_firfilt()
267 : *
268 : * FIR filtering function
269 : *
270 : --------------------------------------------------------------------*/
271 :
272 2658884 : void TDREND_firfilt_fx(
273 : Word32 *signal_fx, /* i/o: Input signal / Filtered signal Qx */
274 : Word32 *filter_fx, /* i/o: FIR filter filter_e */
275 : const Word16 filter_e, /* i : FIR filter exp Q0 */
276 : const Word32 *filter_delta_fx, /* i : FIR filter delta filter_e */
277 : const Word16 intp_count, /* i : interpolation count Q0 */
278 : Word32 *mem_fx, /* i/o: filter memory Qx */
279 : const Word16 subframe_length, /* i : Length of signal Q0 */
280 : const Word16 filterlength, /* i : Filter length Q0 */
281 : const Word16 Gain_fx, /* i : Gain Q14 */
282 : const Word16 prevGain_fx /* i : Previous gain Q14 */
283 : )
284 : {
285 : /* NOTE: this function is implemented with the assumption that the exponent/Q-factor of input signal will not change. */
286 : Word32 buffer_fx[SFX_SPAT_BIN_MAX_FILTER_LENGTH - 1 + L_SUBFRAME5MS_48k]; // Qx
287 : Word32 *p_signal_fx; // Qx
288 : Word32 *p_tmp_fx; // Qx
289 : Word32 *p_filter_fx; // exp(filter_e)
290 : Word16 i, j;
291 : Word32 tmp_fx;
292 : Word16 step_fx /* Q15 */, gain_tmp_fx /* Q15 */, gain_delta_fx /* Q14 */;
293 : Word16 tmp_e;
294 : Word64 tmp64_fx;
295 :
296 2658884 : gain_delta_fx = sub( Gain_fx, prevGain_fx ); // Q14
297 2658884 : step_fx = BASOP_Util_Divide1616_Scale( gain_delta_fx, subframe_length, &tmp_e ); // exp(tmp_e)
298 2658884 : tmp_e = sub( tmp_e, Q14 );
299 2658884 : step_fx = shl_sat( step_fx, tmp_e ); // Q15
300 2658884 : gain_tmp_fx = shl_sat( prevGain_fx, 1 ); // Q15
301 :
302 : /* Handle memory */
303 2658884 : p_signal_fx = buffer_fx + sub( filterlength, 1 ); // Qx
304 2658884 : Copy32( mem_fx, buffer_fx, sub( filterlength, 1 ) ); /* Insert memory */ // Qx
305 2658884 : Copy32( signal_fx, buffer_fx + sub( filterlength, 1 ), subframe_length ); /* Insert current frame */ // Qx
306 2658884 : Copy32( signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
307 :
308 : /* Convolution */
309 630583044 : FOR( i = 0; i < subframe_length; i++ )
310 : {
311 627924160 : tmp64_fx = 0;
312 627924160 : move64();
313 627924160 : tmp_e = 0;
314 627924160 : move16();
315 627924160 : p_tmp_fx = p_signal_fx + i; // Qx
316 627924160 : p_filter_fx = filter_fx; // exp(filter_e)
317 :
318 :
319 80312603840 : FOR( j = 0; j < filterlength; j++ )
320 : {
321 79684679680 : tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
322 79684679680 : p_filter_fx++; // exp(filter_e)
323 79684679680 : p_tmp_fx--; // Qx
324 : }
325 :
326 : // This is done to keep the output Q same as input Q for signal
327 627924160 : tmp64_fx = W_shl( tmp64_fx, filter_e ); // Qx + 32
328 627924160 : tmp_fx = W_extract_h( tmp64_fx ); // Qx
329 :
330 : /* Apply linear gain interpolation in case of abrupt gain changes */
331 627924160 : gain_tmp_fx = add( gain_tmp_fx, step_fx ); // Q15
332 627924160 : signal_fx[i] = Mpy_32_16_1( tmp_fx, gain_tmp_fx ); // Qx
333 627924160 : move32();
334 627924160 : IF( LT_16( i, intp_count ) )
335 : {
336 17326932 : v_add_fx( filter_fx, filter_delta_fx, filter_fx, filterlength ); // exp(filter_e)
337 : }
338 : }
339 :
340 2658884 : return;
341 : }
|