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 "prot_fx.h"
36 : #include "ivas_prot_fx.h"
37 : #include "ivas_rom_com_fx.h"
38 : #ifdef DEBUGGING
39 : #include "debug.h"
40 : #endif
41 : #include "ivas_stat_com.h"
42 : #include "wmc_auto.h"
43 :
44 : /*------------------------------------------------------------------------------------------*
45 : * Local constants
46 : *------------------------------------------------------------------------------------------*/
47 :
48 : #define IVAS_MDCT_SCALING_GAIN_48k_Q31 0x00001086 /* 1.9699011974118126e-06f */
49 : #define IVAS_MDCT_SCALING_GAIN_48k_Q46 0x08432A51
50 : #define IVAS_MDCT_SCALING_GAIN_32k_Q31 0x000018C9 /* 2.9548517961177197e-06f */
51 : #define IVAS_MDCT_SCALING_GAIN_32k_Q46 0x0C64BF7A
52 : #define IVAS_MDCT_SCALING_GAIN_16k_Q31 0X00003193 /* 5.909703592235439e-06f */
53 : #define IVAS_MDCT_SCALING_GAIN_16k_Q46 0x18C97EF4
54 :
55 :
56 : #define IVAS_ONE_BY_IMDCT_SCALING_GAIN_Q16 0x08432A51 /* 1 / 2115.165304808f */
57 :
58 :
59 : /*-----------------------------------------------------------------------------------------*
60 : * Function ivas_tda_fx()
61 : *
62 : * Time domain aliasing
63 : *-----------------------------------------------------------------------------------------*/
64 :
65 252 : void ivas_tda_fx(
66 : const Word32 *pIn, /* i : time domain buffer of size 2*length Q10*/
67 : Word32 *pOut, /* o : time domain buffer of size length Q10 */
68 : const Word16 length /* i : length of time alised signal buffer Q0*/
69 : )
70 : {
71 : Word16 i;
72 : Word16 len_by_2;
73 252 : len_by_2 = shr( length, 1 );
74 :
75 60572 : FOR( i = 0; i < len_by_2; i++ )
76 : {
77 60320 : pOut[i] = L_sub( pIn[len_by_2 + i], pIn[len_by_2 - i - 1] ); /* Q10*/
78 60320 : move32();
79 60320 : pOut[len_by_2 + i] = L_add( pIn[length * 2 - i - 1], pIn[length + i] ); /* Q10*/
80 60320 : move32();
81 : }
82 :
83 252 : return;
84 : }
85 :
86 :
87 : /*-----------------------------------------------------------------------------------------*
88 : * Function ivas_dct_windowing_fx()
89 : *
90 : * Windowing block, input is passed through Fielder window
91 : *-----------------------------------------------------------------------------------------*/
92 :
93 53092 : void ivas_dct_windowing_fx(
94 : const Word16 fade_len, /*Q0*/
95 : const Word16 full_len, /*Q0*/
96 : const Word16 dct_len, /*Q0*/
97 : const Word16 zero_pad_len, /*Q0*/
98 : const Word32 *pWindow_coeffs, /*Q31*/
99 : const Word16 frame_len, /*Q0*/
100 : Word32 *pOut_buf, // Q10
101 : Word32 *pBuffer_prev, // Q10
102 : Word32 *pTemp_lfe ) // Q10
103 : {
104 : Word16 i;
105 : Word16 rem_len;
106 53092 : rem_len = 0;
107 53092 : move16();
108 :
109 53092 : Copy32( pBuffer_prev, pOut_buf + zero_pad_len, fade_len ); // Q10
110 :
111 53092 : Copy32( pTemp_lfe, ( pOut_buf + add( fade_len, zero_pad_len ) ), dct_len ); // Q10
112 :
113 53092 : set32_fx( pOut_buf, 0, zero_pad_len );
114 :
115 53092 : Copy32( ( pOut_buf + sub( full_len, fade_len ) ), pBuffer_prev, fade_len ); // Q10
116 :
117 20322404 : FOR( i = 0; i < fade_len; i++ )
118 : {
119 20269312 : pOut_buf[zero_pad_len + i] = Mult_32_32( pOut_buf[zero_pad_len + i], pWindow_coeffs[i] ); // Q10
120 20269312 : move32();
121 : }
122 :
123 53092 : rem_len = sub( full_len, ( add( i_mult( zero_pad_len, 3 ), fade_len ) ) );
124 :
125 20322404 : FOR( i = 0; i < rem_len; i++ )
126 : {
127 20269312 : pOut_buf[zero_pad_len * 3 + fade_len + i] = Mult_32_32( pOut_buf[zero_pad_len * 3 + fade_len + i], pWindow_coeffs[fade_len - i - 1] ); // Q10
128 20269312 : move32();
129 : }
130 :
131 53092 : set32_fx( &pOut_buf[full_len], 0, sub( frame_len, full_len ) );
132 :
133 53092 : return;
134 : }
135 :
136 :
137 : /*-----------------------------------------------------------------------------------------*
138 : * Function ivas_mdct_fx()
139 : *
140 : * MDCT implementation
141 : *-----------------------------------------------------------------------------------------*/
142 :
143 52840 : void ivas_mdct_fx(
144 : const Word32 *pIn, // q_out
145 : Word32 *pOut, // q_out
146 : const Word16 length, // Q0
147 : Word16 *q_out )
148 : {
149 : const Word16 *pTwid_re, *pTwid_im;
150 : Word16 i, len_by_2;
151 : Word32 re[IVAS_480_PT_LEN], im[IVAS_480_PT_LEN];
152 : Word32 ivas_mdct_scaling_gain;
153 :
154 52840 : len_by_2 = shr( length, 1 );
155 52840 : ivas_mdct_scaling_gain = ivas_get_mdct_scaling_gain_fx( len_by_2 ); // Q46
156 :
157 52840 : ivas_get_twid_factors_fx1( length, &pTwid_re, &pTwid_im );
158 :
159 12660840 : FOR( i = 0; i < len_by_2; i++ )
160 : {
161 12608000 : pOut[i] = L_sub( pIn[len_by_2 + i], pIn[len_by_2 - i - 1] ); // q_out
162 12608000 : move32();
163 12608000 : pOut[len_by_2 + i] = L_add( pIn[length * 2 - i - 1], pIn[length + i] ); // q_out
164 12608000 : move32();
165 : }
166 :
167 12660840 : FOR( i = 0; i < len_by_2; i++ )
168 : {
169 12608000 : re[i] = L_negate( L_add( Mpy_32_16_1( pOut[2 * i], pTwid_re[i] ), Mpy_32_16_1( pOut[length - 1 - 2 * i], pTwid_im[i] ) ) ); // q_out
170 12608000 : move32();
171 12608000 : im[i] = L_sub( Mpy_32_16_1( pOut[length - 1 - 2 * i], pTwid_re[i] ), Mpy_32_16_1( pOut[2 * i], pTwid_im[i] ) ); // q_out
172 12608000 : move32();
173 : }
174 :
175 52840 : DoFFT_fx( &re[0], &im[0], len_by_2 );
176 :
177 12660840 : FOR( i = 0; i < len_by_2; i++ )
178 : {
179 12608000 : re[i] = Mult_32_32( re[i], ivas_mdct_scaling_gain ); // q_out+15
180 12608000 : move32();
181 12608000 : im[i] = Mult_32_32( im[i], ivas_mdct_scaling_gain ); // q_out +15
182 12608000 : move32();
183 : }
184 52840 : *q_out = add( *q_out, Q15 );
185 52840 : move16();
186 12660840 : FOR( i = 0; i < len_by_2; i++ )
187 : {
188 : Word32 tmp;
189 12608000 : tmp = L_sub( Mpy_32_16_1( re[i], pTwid_re[i] ), Mpy_32_16_1( im[i], pTwid_im[i] ) ); // q_out
190 12608000 : im[i] = L_add( Mpy_32_16_1( im[i], pTwid_re[i] ), Mpy_32_16_1( re[i], pTwid_im[i] ) ); // q_out
191 12608000 : move32();
192 12608000 : re[i] = tmp; // q_out
193 12608000 : move32();
194 : }
195 :
196 12660840 : FOR( i = 0; i < len_by_2; i++ )
197 : {
198 12608000 : pOut[length - 2 * i - 1] = re[i]; // q_out
199 12608000 : move32();
200 12608000 : pOut[2 * i] = im[i]; // q_out
201 12608000 : move32();
202 : }
203 :
204 52840 : return;
205 : }
206 :
207 :
208 : /*-----------------------------------------------------------------------------------------*
209 : * Function ivas_ifft_cplx()
210 : *
211 : * Complex IFFT implementation using DoFFT
212 : *-----------------------------------------------------------------------------------------*/
213 :
214 49922 : static void ivas_ifft_cplx(
215 : Word32 *re, /*Q24*/
216 : Word32 *im, /*Q24*/
217 : const Word16 length /*Q0*/ )
218 : {
219 : Word16 i;
220 : Word32 ivas_imdct_one_by_powergain;
221 49922 : ivas_imdct_one_by_powergain = IVAS_ONE_BY_IMDCT_SCALING_GAIN_Q16; // Q16
222 49922 : move32();
223 : /*re-arrange inputs to use fft as ifft */
224 49922 : re[0] = Mult_32_32( re[0], ivas_imdct_one_by_powergain ); // Q9
225 49922 : move32();
226 49922 : im[0] = Mult_32_32( im[0], ivas_imdct_one_by_powergain ); // Q9
227 49922 : move32();
228 :
229 5734242 : FOR( i = 1; i <= ( length / 2 ); i++ )
230 : {
231 : Word32 tmp;
232 5684320 : tmp = Mult_32_32( re[length - i], ivas_imdct_one_by_powergain ); // Q9
233 5684320 : re[length - i] = Mult_32_32( re[i], ivas_imdct_one_by_powergain ); // Q9
234 5684320 : move32();
235 5684320 : re[i] = tmp; //-Q6
236 5684320 : move32();
237 :
238 5684320 : tmp = Mult_32_32( im[length - i], ivas_imdct_one_by_powergain ); // Q9
239 5684320 : im[length - i] = Mult_32_32( im[i], ivas_imdct_one_by_powergain ); // Q9
240 5684320 : move32();
241 5684320 : im[i] = tmp; // Q9
242 5684320 : move32();
243 : }
244 :
245 49922 : DoFFT_fx( re, im, length );
246 :
247 49922 : return;
248 : }
249 :
250 :
251 : /*-----------------------------------------------------------------------------------------*
252 : * Function ivas_itda()
253 : *
254 : * Inverse time domain alias implementation
255 : *-----------------------------------------------------------------------------------------*/
256 :
257 252 : void ivas_itda_fx(
258 : const Word32 *re, /* i : time alised signal after IDCT Q24 */
259 : Word32 *pOut, /* o : time domain buffer of size 2*length */
260 : const Word16 length /* i : length of time alised signal buffer Q0 */
261 : )
262 : {
263 : Word16 i;
264 : Word16 len_by_2;
265 252 : len_by_2 = shr( length, 1 );
266 :
267 60572 : FOR( i = 0; i < len_by_2; i++ )
268 : {
269 60320 : pOut[i] = L_negate( re[len_by_2 - i - 1] ); /*Q24 */
270 60320 : move32();
271 60320 : pOut[add( len_by_2, i )] = re[i]; /*Q24 */
272 60320 : move32();
273 60320 : pOut[add( length, i )] = re[len_by_2 + i]; /*Q24 */
274 60320 : move32();
275 60320 : pOut[3 * len_by_2 + i] = re[length - i - 1]; /*Q24 */
276 60320 : move32();
277 : }
278 :
279 252 : return;
280 : }
281 :
282 :
283 : /*-----------------------------------------------------------------------------------------*
284 : * Function ivas_imdct_fx()
285 : *
286 : * IMDCT implementation
287 : *-----------------------------------------------------------------------------------------*/
288 :
289 49922 : void ivas_imdct_fx(
290 : const Word32 *pIn, // Q24
291 : Word32 *pOut, // q_out Q9
292 : const Word16 length /*Q0*/,
293 : Word16 *q_out )
294 : {
295 : const Word16 *pTwid_re, *pTwid_im;
296 : Word16 len_by_2;
297 : Word16 i;
298 : Word32 re[IVAS_480_PT_LEN];
299 : Word32 im[IVAS_480_PT_LEN];
300 49922 : len_by_2 = shr( length, 1 );
301 :
302 49922 : ivas_get_twid_factors_fx1( length, &pTwid_re, &pTwid_im );
303 :
304 11418562 : FOR( i = 0; i < len_by_2; i++ )
305 : {
306 11368640 : re[i] = L_add( Mpy_32_16_1( pIn[length - 2 * i - 1], pTwid_re[i] ), Mpy_32_16_1( pIn[2 * i], pTwid_im[i] ) ); /*stl_arr_index Q24*/
307 11368640 : move32();
308 11368640 : im[i] = L_sub( Mpy_32_16_1( pIn[2 * i], pTwid_re[i] ), Mpy_32_16_1( pIn[length - 2 * i - 1], pTwid_im[i] ) ); /*stl_arr_index Q24*/
309 11368640 : move32();
310 : }
311 :
312 49922 : ivas_ifft_cplx( &re[0], &im[0], len_by_2 );
313 49922 : IF( len_by_2 > 0 )
314 : {
315 49922 : *q_out = sub( *q_out, Q15 );
316 49922 : move16();
317 : }
318 :
319 11418562 : FOR( i = 0; i < len_by_2; i++ )
320 : {
321 : Word32 tmp;
322 11368640 : tmp = L_add( Mpy_32_16_1( re[i], pTwid_re[i] ), Mpy_32_16_1( im[i], pTwid_im[i] ) ); // Q9
323 11368640 : im[i] = L_sub( Mpy_32_16_1( im[i], pTwid_re[i] ), Mpy_32_16_1( re[i], pTwid_im[i] ) ); // Q9
324 11368640 : move32();
325 11368640 : re[i] = tmp; // Q9
326 11368640 : move32();
327 : }
328 :
329 11418562 : FOR( i = ( len_by_2 - 1 ); i >= 0; i-- )
330 : {
331 11368640 : re[2 * i + 1] = im[( len_by_2 - 1 ) - i]; // Q9
332 11368640 : move32();
333 11368640 : re[2 * i] = L_negate( re[i] ); // Q9
334 11368640 : move32();
335 : }
336 :
337 11418562 : FOR( i = 0; i < len_by_2; i++ )
338 : {
339 11368640 : pOut[i] = L_negate( re[len_by_2 - i - 1] ); // Q9
340 11368640 : move32();
341 11368640 : pOut[len_by_2 + i] = re[i]; // Q9
342 11368640 : move32();
343 11368640 : pOut[length + i] = re[len_by_2 + i]; // Q9
344 11368640 : move32();
345 11368640 : pOut[3 * len_by_2 + i] = re[length - i - 1]; // Q9
346 11368640 : move32();
347 : }
348 :
349 49922 : return;
350 : }
351 :
352 :
353 : /*-----------------------------------------------------------------------------------------*
354 : * Function ivas_get_twid_factors_fx1()
355 : *
356 : * Sets/Maps the fft twiddle tables based on fft length
357 : *-----------------------------------------------------------------------------------------*/
358 102762 : void ivas_get_twid_factors_fx1(
359 : const Word16 length, // Q0
360 : const Word16 **pTwid_re, // Q15
361 : const Word16 **pTwid_im ) // Q15
362 : {
363 102762 : IF( EQ_16( length, 480 ) )
364 : {
365 97824 : *pTwid_re = (const Word16 *) &ivas_cos_twiddle_480_fx[0]; // Q15
366 97824 : *pTwid_im = (const Word16 *) &ivas_sin_twiddle_480_fx[0]; // Q15
367 : }
368 4938 : ELSE IF( EQ_16( length, 320 ) )
369 : {
370 1298 : *pTwid_re = (const Word16 *) &ivas_cos_twiddle_320_fx[0]; // Q15
371 1298 : *pTwid_im = (const Word16 *) &ivas_sin_twiddle_320_fx[0]; // Q15
372 : }
373 3640 : ELSE IF( EQ_16( length, 160 ) )
374 : {
375 3640 : *pTwid_re = (const Word16 *) &ivas_cos_twiddle_160_fx[0]; // Q15
376 3640 : *pTwid_im = (const Word16 *) &ivas_sin_twiddle_160_fx[0]; // Q15
377 : }
378 0 : ELSE IF( EQ_16( length, 80 ) )
379 : {
380 0 : *pTwid_re = (const Word16 *) &ivas_cos_twiddle_80_fx[0]; // Q15
381 0 : *pTwid_im = (const Word16 *) &ivas_sin_twiddle_80_fx[0]; // Q15
382 : }
383 : ELSE
384 : {
385 0 : assert( !"Not supported FFT length!" );
386 : }
387 :
388 102762 : return;
389 : }
390 :
391 : /*-----------------------------------------------------------------------------------------*
392 : * Function ivas_get_mdct_scaling_gain_fx()
393 : *
394 : * Get scaling gain for MDCT functions
395 : *-----------------------------------------------------------------------------------------*/
396 :
397 52840 : Word32 ivas_get_mdct_scaling_gain_fx(
398 : const Word16 dct_len_by_2 )
399 : {
400 : Word32 gain;
401 52840 : gain = 0;
402 52840 : move32();
403 :
404 52840 : SWITCH( dct_len_by_2 )
405 : {
406 51920 : case L_FRAME48k >> 2:
407 : {
408 51920 : gain = IVAS_MDCT_SCALING_GAIN_48k_Q46; /*Q46*/
409 51920 : move32();
410 51920 : BREAK;
411 : }
412 920 : case L_FRAME32k >> 2:
413 : {
414 920 : gain = IVAS_MDCT_SCALING_GAIN_32k_Q46; /*Q46*/
415 920 : move32();
416 920 : BREAK;
417 : }
418 0 : case L_FRAME16k >> 2:
419 : {
420 0 : gain = IVAS_MDCT_SCALING_GAIN_16k_Q46; /*Q46*/
421 0 : move32();
422 0 : BREAK;
423 : }
424 0 : default:
425 : {
426 0 : assert( !"Unsupported frame length!" );
427 : BREAK;
428 : }
429 : }
430 :
431 52840 : return gain;
432 : }
|