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 "isar_lcld_prot.h"
36 : #include "prot_fx.h"
37 : #include "isar_rom_lcld_tables.h"
38 : #include <stdio.h>
39 : #include "wmc_auto.h"
40 :
41 :
42 : /*------------------------------------------------------------------------------------------*
43 : * Local constants
44 : *------------------------------------------------------------------------------------------*/
45 : #define PERCEPTUAL_MODEL_SCALE_SHIFT ( 6 )
46 : #define PERCEPTUAL_MODEL_SCALE ( 64 )
47 : #define PERCEPTUAL_MODEL_SCALE_SHIFT ( 6 )
48 : #define PERCEPTUAL_MODEL_ALPHA_SCALE ( 614 )
49 : #define PERCEPTUAL_MODEL_ALPHA_INV_SCALE ( 6827 )
50 : #define PERCEPTUAL_MODEL_ALPHA_SHIFT ( 11 )
51 :
52 : /*------------------------------------------------------------------------------------------*
53 : * Function LogAdd()
54 : *
55 : *
56 : *------------------------------------------------------------------------------------------*/
57 :
58 0 : static inline Word16 LogAdd_fx(
59 : const Word16 iVal1,
60 : const Word16 iVal2 )
61 : {
62 : Word16 iRetVal;
63 :
64 0 : IF( iVal1 > iVal2 )
65 : {
66 0 : iRetVal = sub( iVal1, iVal2 );
67 0 : move16();
68 0 : iRetVal = ( iRetVal < sub( LOG_ADD_TABLE_LENGTH, 1 ) ) ? iRetVal : sub( LOG_ADD_TABLE_LENGTH, 1 );
69 0 : move16();
70 0 : iRetVal = add( iVal1, c_aiLogAddTable_fx[iRetVal] );
71 0 : move16();
72 : }
73 : ELSE
74 : {
75 0 : iRetVal = sub( iVal2, iVal1 );
76 0 : move16();
77 0 : iRetVal = ( iRetVal < sub( LOG_ADD_TABLE_LENGTH, 1 ) ) ? iRetVal : sub( LOG_ADD_TABLE_LENGTH, 1 );
78 0 : move16();
79 0 : iRetVal = add( iVal2, c_aiLogAddTable_fx[iRetVal] );
80 0 : move16();
81 : }
82 :
83 0 : return iRetVal;
84 : }
85 :
86 :
87 : /*------------------------------------------------------------------------------------------*
88 : * Function LogAdd()
89 : *
90 : *
91 : *------------------------------------------------------------------------------------------*/
92 :
93 0 : static inline Word32 LogAdd(
94 : const Word32 iVal1,
95 : const Word32 iVal2 )
96 : {
97 : Word32 iRetVal;
98 :
99 0 : if ( iVal1 > iVal2 )
100 : {
101 0 : iRetVal = iVal1 - iVal2;
102 0 : iRetVal = ( iRetVal < ( LOG_ADD_TABLE_LENGTH - 1 ) ) ? iRetVal : ( LOG_ADD_TABLE_LENGTH - 1 );
103 0 : iRetVal = iVal1 + c_aiLogAddTable[iRetVal];
104 : }
105 : else
106 : {
107 0 : iRetVal = iVal2 - iVal1;
108 0 : iRetVal = ( iRetVal < ( LOG_ADD_TABLE_LENGTH - 1 ) ) ? iRetVal : ( LOG_ADD_TABLE_LENGTH - 1 );
109 0 : iRetVal = iVal2 + c_aiLogAddTable[iRetVal];
110 : }
111 :
112 0 : return iRetVal;
113 : }
114 :
115 :
116 : /*------------------------------------------------------------------------------------------*
117 : * Function PerceptualModel()
118 : *
119 : *
120 : *------------------------------------------------------------------------------------------*/
121 :
122 0 : void PerceptualModel_fx(
123 : const Word32 iMaxQuantBands,
124 : const Word32 *piRMSEnvelope,
125 : Word32 *piExcitation,
126 : Word32 *piSMR )
127 : {
128 : Word16 n;
129 :
130 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
131 : {
132 : Word16 iSLOffset;
133 :
134 0 : piExcitation[n] = shl( add( extract_l( piRMSEnvelope[n] ), c_aiBandwidthAdjust48_fx[n] ), PERCEPTUAL_MODEL_SCALE_SHIFT ); // shift instead of multiplying by PERCEPTUAL_MODEL_SCALE
135 0 : move16();
136 : /* Calculate sensation level offset */
137 0 : iSLOffset = (Word16) extract_l( L_shr( L_mult0( c_aiDefaultTheta48_fx[n], sub( extract_l( piExcitation[n] ), c_aiAbsoluteThresh48_fx[n] ) ), PERCEPTUAL_MODEL_SLGAIN_SHIFT ) );
138 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
139 0 : move16();
140 : /* Offset envelope by sensation level offset */
141 0 : piExcitation[n] = sub( extract_l( piExcitation[n] ), iSLOffset );
142 0 : move16();
143 : /* Convert to loudness domain (x^0.3) */
144 0 : piExcitation[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_SCALE, extract_l( piExcitation[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
145 0 : move16();
146 : }
147 :
148 : /* Spread excitation function */
149 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
150 : {
151 : Word16 k;
152 : const Word16 *piSpread;
153 :
154 0 : piSpread = &c_aaiSpreadFunction48_fx[n * MAX_BANDS_48];
155 0 : move16();
156 0 : piSMR[n] = add( extract_l( piExcitation[n] ), piSpread[n] );
157 0 : move16();
158 0 : FOR( k = 0; k < iMaxQuantBands; k++ )
159 : {
160 0 : IF( NE_16( k, n ) )
161 : {
162 0 : piSMR[n] = L_deposit_l( LogAdd_fx( extract_l( piSMR[n] ), add( extract_l( piExcitation[k] ), piSpread[k] ) ) );
163 0 : move16();
164 : }
165 : }
166 : }
167 :
168 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
169 : {
170 0 : piSMR[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_INV_SCALE, extract_l( piSMR[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
171 0 : move16();
172 0 : piSMR[n] = shl( sub( add( extract_l( piRMSEnvelope[n] ), c_aiBandwidthAdjust48_fx[n] ), extract_l( piSMR[n] ) ), PERCEPTUAL_MODEL_SCALE_SHIFT );
173 0 : move16();
174 : }
175 :
176 0 : return;
177 : }
178 : /*------------------------------------------------------------------------------------------*
179 : * Function PerceptualModel()
180 : *
181 : *
182 : *------------------------------------------------------------------------------------------*/
183 :
184 0 : void PerceptualModel(
185 : const Word32 iMaxQuantBands,
186 : const Word32 *piRMSEnvelope,
187 : Word32 *piExcitation,
188 : Word32 *piSMR )
189 : {
190 : Word32 n;
191 :
192 0 : for ( n = 0; n < iMaxQuantBands; n++ )
193 : {
194 : Word32 iSLOffset;
195 :
196 0 : piExcitation[n] = PERCEPTUAL_MODEL_SCALE * piRMSEnvelope[n] + c_aiBandwidthAdjust48[n];
197 :
198 : /* Calculate sensation level offset */
199 0 : iSLOffset = c_aiDefaultTheta48[n] * ( piExcitation[n] - c_aiAbsoluteThresh48[n] ) >> PERCEPTUAL_MODEL_SLGAIN_SHIFT;
200 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
201 :
202 : /* Offset envelope by sensation level offset */
203 0 : piExcitation[n] -= iSLOffset;
204 :
205 : /* Convert to loudness domain (x^0.3) */
206 0 : piExcitation[n] = PERCEPTUAL_MODEL_ALPHA_SCALE * piExcitation[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
207 : }
208 :
209 : /* Spread excitation function */
210 0 : for ( n = 0; n < iMaxQuantBands; n++ )
211 : {
212 : Word32 k;
213 : const Word32 *piSpread;
214 :
215 0 : piSpread = &c_aaiSpreadFunction48[n * MAX_BANDS_48];
216 0 : piSMR[n] = piExcitation[n] + piSpread[n];
217 0 : for ( k = 0; k < iMaxQuantBands; k++ )
218 : {
219 0 : if ( k != n )
220 : {
221 0 : piSMR[n] = LogAdd( piSMR[n], piExcitation[k] + piSpread[k] );
222 : }
223 : }
224 : }
225 :
226 0 : for ( n = 0; n < iMaxQuantBands; n++ )
227 : {
228 0 : piSMR[n] = PERCEPTUAL_MODEL_ALPHA_INV_SCALE * piSMR[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
229 0 : piSMR[n] = PERCEPTUAL_MODEL_SCALE * piRMSEnvelope[n] + c_aiBandwidthAdjust48[n] - piSMR[n];
230 : }
231 :
232 0 : return;
233 : }
234 :
235 :
236 : /*------------------------------------------------------------------------------------------*
237 : * Function PerceptualModelStereo()
238 : *
239 : *
240 : *------------------------------------------------------------------------------------------*/
241 :
242 0 : void PerceptualModelStereo(
243 : const Word32 iMaxQuantBands,
244 : const Word32 *piMSFlags,
245 : const Word32 *piRMSEnvelope0,
246 : const Word32 *piRMSEnvelope1,
247 : Word32 *piExcitation0,
248 : Word32 *piExcitation1,
249 : Word32 *piSMR0,
250 : Word32 *piSMR1 )
251 : {
252 : Word32 n;
253 :
254 0 : for ( n = 0; n < iMaxQuantBands; n++ )
255 : {
256 : Word32 iMaxRMSEnv;
257 : Word32 iSLOffset;
258 :
259 0 : iMaxRMSEnv = piRMSEnvelope0[n];
260 :
261 0 : piExcitation0[n] = PERCEPTUAL_MODEL_SCALE * iMaxRMSEnv + c_aiBandwidthAdjust48[n]; /* piRMSEnvelope0[n] */
262 :
263 : /* Calculate sensation level offset */
264 0 : iSLOffset = c_aiDefaultTheta48[n] * ( piExcitation0[n] - c_aiAbsoluteThresh48[n] ) >> PERCEPTUAL_MODEL_SLGAIN_SHIFT;
265 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
266 :
267 : /* Offset envelope by sensation level offset */
268 0 : piExcitation0[n] -= iSLOffset;
269 :
270 : /* Convert to loudness domain (x^0.3) */
271 0 : piExcitation0[n] = PERCEPTUAL_MODEL_ALPHA_SCALE * piExcitation0[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
272 : }
273 :
274 : /* Spread excitation function */
275 0 : for ( n = 0; n < iMaxQuantBands; n++ )
276 : {
277 : Word32 k;
278 : const Word32 *piSpread;
279 :
280 0 : piSpread = &c_aaiSpreadFunction48[n * MAX_BANDS_48];
281 0 : piSMR0[n] = piExcitation0[n] + piSpread[n];
282 0 : for ( k = 0; k < iMaxQuantBands; k++ )
283 : {
284 0 : if ( k != n )
285 : {
286 0 : piSMR0[n] = LogAdd( piSMR0[n], piExcitation0[k] + piSpread[k] );
287 : }
288 : }
289 : }
290 :
291 0 : for ( n = 0; n < iMaxQuantBands; n++ )
292 : {
293 : Word32 iMaxRMSEnv;
294 : Word32 iSLOffset;
295 :
296 0 : iMaxRMSEnv = piRMSEnvelope1[n];
297 :
298 0 : piExcitation1[n] = PERCEPTUAL_MODEL_SCALE * iMaxRMSEnv + c_aiBandwidthAdjust48[n]; /* piRMSEnvelope1[n] */
299 :
300 : /* Calculate sensation level offset */
301 0 : iSLOffset = c_aiDefaultTheta48[n] * ( piExcitation1[n] - c_aiAbsoluteThresh48[n] ) >> PERCEPTUAL_MODEL_SLGAIN_SHIFT;
302 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
303 :
304 : /* Offset envelope by sensation level offset */
305 0 : piExcitation1[n] -= iSLOffset;
306 :
307 : /* Convert to loudness domain (x^0.3) */
308 0 : piExcitation1[n] = PERCEPTUAL_MODEL_ALPHA_SCALE * piExcitation1[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
309 : }
310 :
311 : /* Spread excitation function */
312 0 : for ( n = 0; n < iMaxQuantBands; n++ )
313 : {
314 : Word32 k;
315 : const Word32 *piSpread;
316 :
317 0 : piSpread = &c_aaiSpreadFunction48[n * MAX_BANDS_48];
318 0 : piSMR1[n] = piExcitation1[n] + piSpread[n];
319 0 : for ( k = 0; k < iMaxQuantBands; k++ )
320 : {
321 0 : if ( k != n )
322 : {
323 0 : piSMR1[n] = LogAdd( piSMR1[n], piExcitation1[k] + piSpread[k] );
324 : }
325 : }
326 : }
327 :
328 0 : for ( n = 0; n < iMaxQuantBands; n++ )
329 : {
330 0 : if ( piMSFlags[n] == 1 )
331 : {
332 0 : piSMR0[n] = ( piSMR0[n] > piSMR1[n] ) ? piSMR0[n] : piSMR1[n];
333 0 : piSMR1[n] = piSMR0[n];
334 : }
335 : }
336 :
337 0 : for ( n = 0; n < iMaxQuantBands; n++ )
338 : {
339 0 : piSMR0[n] = PERCEPTUAL_MODEL_ALPHA_INV_SCALE * piSMR0[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
340 0 : piSMR0[n] = PERCEPTUAL_MODEL_SCALE * piRMSEnvelope0[n] + c_aiBandwidthAdjust48[n] - piSMR0[n];
341 : }
342 :
343 0 : for ( n = 0; n < iMaxQuantBands; n++ )
344 : {
345 0 : piSMR1[n] = PERCEPTUAL_MODEL_ALPHA_INV_SCALE * piSMR1[n] >> PERCEPTUAL_MODEL_ALPHA_SHIFT;
346 0 : piSMR1[n] = PERCEPTUAL_MODEL_SCALE * piRMSEnvelope1[n] + c_aiBandwidthAdjust48[n] - piSMR1[n];
347 : }
348 :
349 0 : return;
350 : }
351 0 : void PerceptualModelStereo_fx(
352 : const Word32 iMaxQuantBands,
353 : const Word32 *piMSFlags,
354 : const Word32 *piRMSEnvelope0,
355 : const Word32 *piRMSEnvelope1,
356 : Word32 *piExcitation0,
357 : Word32 *piExcitation1,
358 : Word32 *piSMR0,
359 : Word32 *piSMR1 )
360 : {
361 : Word16 n;
362 :
363 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
364 : {
365 : Word16 iMaxRMSEnv;
366 : Word16 iSLOffset;
367 :
368 0 : iMaxRMSEnv = extract_l( piRMSEnvelope0[n] );
369 0 : move16();
370 0 : piExcitation0[n] = add( shl( iMaxRMSEnv, PERCEPTUAL_MODEL_SCALE_SHIFT ), c_aiBandwidthAdjust48_fx[n] ); /* piRMSEnvelope0[n] */
371 0 : move16();
372 : /* Calculate sensation level offset */
373 0 : iSLOffset = extract_l( L_shr( L_mult0( c_aiDefaultTheta48_fx[n], sub( extract_l( piExcitation0[n] ), c_aiAbsoluteThresh48_fx[n] ) ), PERCEPTUAL_MODEL_SLGAIN_SHIFT ) );
374 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
375 0 : move16();
376 : /* Offset envelope by sensation level offset */
377 0 : piExcitation0[n] = sub( extract_l( piExcitation0[n] ), iSLOffset );
378 0 : move16();
379 : /* Convert to loudness domain (x^0.3) */
380 0 : piExcitation0[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_SCALE, extract_l( piExcitation0[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
381 0 : move16();
382 : }
383 :
384 : /* Spread excitation function */
385 0 : for ( n = 0; n < iMaxQuantBands; n++ )
386 : {
387 : Word16 k;
388 : const Word16 *piSpread;
389 :
390 0 : piSpread = &c_aaiSpreadFunction48_fx[n * MAX_BANDS_48];
391 0 : move16();
392 0 : piSMR0[n] = add( extract_l( piExcitation0[n] ), piSpread[n] );
393 0 : move16();
394 0 : FOR( k = 0; k < iMaxQuantBands; k++ )
395 : {
396 0 : IF( NE_16( k, n ) )
397 : {
398 0 : piSMR0[n] = L_deposit_l( LogAdd_fx( extract_l( piSMR0[n] ), add( extract_l( piExcitation0[k] ), piSpread[k] ) ) );
399 0 : move16();
400 : }
401 : }
402 : }
403 :
404 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
405 : {
406 : Word16 iMaxRMSEnv;
407 : Word16 iSLOffset;
408 :
409 0 : iMaxRMSEnv = extract_l( piRMSEnvelope1[n] );
410 0 : move16();
411 0 : piExcitation1[n] = add( shl( iMaxRMSEnv, PERCEPTUAL_MODEL_SCALE_SHIFT ), c_aiBandwidthAdjust48_fx[n] ); /* piRMSEnvelope1[n] */
412 0 : move16();
413 : /* Calculate sensation level offset */
414 0 : iSLOffset = extract_l( L_shr( L_mult0( c_aiDefaultTheta48_fx[n], sub( extract_l( piExcitation1[n] ), c_aiAbsoluteThresh48_fx[n] ) ), PERCEPTUAL_MODEL_SLGAIN_SHIFT ) );
415 : // iSLOffset = (iSLOffset > 0) ? iSLOffset : 0;
416 0 : move16();
417 : /* Offset envelope by sensation level offset */
418 0 : piExcitation1[n] = sub( extract_l( piExcitation1[n] ), iSLOffset );
419 0 : move16();
420 : /* Convert to loudness domain (x^0.3) */
421 0 : piExcitation1[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_SCALE, extract_l( piExcitation1[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
422 0 : move16();
423 : }
424 :
425 : /* Spread excitation function */
426 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
427 : {
428 : Word16 k;
429 : const Word16 *piSpread;
430 :
431 0 : piSpread = &c_aaiSpreadFunction48_fx[n * MAX_BANDS_48];
432 0 : move16();
433 0 : piSMR1[n] = add( extract_l( piExcitation1[n] ), piSpread[n] );
434 0 : move16();
435 0 : FOR( k = 0; k < iMaxQuantBands; k++ )
436 : {
437 0 : IF( NE_16( k, n ) )
438 : {
439 0 : piSMR1[n] = LogAdd_fx( extract_l( piSMR1[n] ), add( extract_l( piExcitation1[k] ), piSpread[k] ) );
440 0 : move16();
441 : }
442 : }
443 : }
444 :
445 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
446 : {
447 0 : IF( EQ_16( extract_l( piMSFlags[n] ), 1 ) )
448 : {
449 0 : piSMR0[n] = ( piSMR0[n] > piSMR1[n] ) ? piSMR0[n] : piSMR1[n];
450 0 : move16();
451 0 : piSMR1[n] = piSMR0[n];
452 0 : move16();
453 : }
454 : }
455 :
456 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
457 : {
458 0 : piSMR0[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_INV_SCALE, extract_l( piSMR0[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
459 0 : move16();
460 0 : piSMR0[n] = sub( add( shl( extract_l( piRMSEnvelope0[n] ), PERCEPTUAL_MODEL_SCALE_SHIFT ), c_aiBandwidthAdjust48_fx[n] ), extract_l( piSMR0[n] ) );
461 0 : move16();
462 : }
463 :
464 0 : FOR( n = 0; n < iMaxQuantBands; n++ )
465 : {
466 0 : piSMR1[n] = extract_l( L_shr( L_mult0( PERCEPTUAL_MODEL_ALPHA_INV_SCALE, extract_l( piSMR1[n] ) ), PERCEPTUAL_MODEL_ALPHA_SHIFT ) );
467 0 : move16();
468 0 : piSMR1[n] = sub( add( shl( extract_l( piRMSEnvelope1[n] ), PERCEPTUAL_MODEL_SCALE_SHIFT ), c_aiBandwidthAdjust48_fx[n] ), extract_l( piSMR1[n] ) );
469 0 : move16();
470 : }
471 :
472 0 : return;
473 : }
|