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 <assert.h>
34 : #include <stdint.h>
35 : #include "options.h"
36 : #include <math.h>
37 : #include "prot_fx.h"
38 : #include "cnst.h"
39 : #include "stat_enc.h"
40 : #include "ivas_stat_enc.h"
41 : #include "ivas_prot_fx.h"
42 : #include "wmc_auto.h"
43 :
44 : /*-------------------------------------------------------------------*
45 : * Local constants
46 : *-------------------------------------------------------------------*/
47 :
48 : #define IGF_PATCH_MS 1
49 : #define IGF_PATCH_LR 0
50 : #define TARGET_COH_THRESHOLD_FX 19661
51 : #define SOURCE_COH_THRESHOLD_FX 22938
52 : #define PANNING_THRESHOLD_FX 2294
53 :
54 :
55 : /*-------------------------------------------------------------------*
56 : * calcCoh()
57 : *
58 : *
59 : *-------------------------------------------------------------------*/
60 :
61 961574 : static Word16 calcCoh_fx( // Q15
62 : const Word32 *sig1_fx, // Q( q_sig )
63 : const Word32 *sig2_fx, // Q( q_sig )
64 : const Word16 q_sig,
65 : const Word16 nSamples, /* Q0 */
66 : Word32 *corr, /* Q31-corr_e */
67 : Word16 *corr_e,
68 : Word16 *predCoeff, /* Q31-predCoeff_e */
69 : Word16 *predCoeff_e )
70 : {
71 : Word32 ener1_fx, ener2_fx, cEner_fx, cc_fx;
72 : Word16 coh_fx, coh_e;
73 : Word16 q_ener1, q_ener2, q_cEner, q_cc;
74 :
75 961574 : coh_fx = 0;
76 961574 : move16();
77 961574 : Word16 gB = find_guarded_bits_fx( nSamples );
78 961574 : q_ener1 = shl( q_sig, 1 );
79 961574 : q_ener2 = q_ener1;
80 961574 : move16();
81 961574 : q_cc = q_ener1;
82 961574 : move16();
83 961574 : ener1_fx = dotp_fixed_o( sig1_fx, sig1_fx, nSamples, gB, &q_ener1 ); /* q_ener1 */
84 961574 : ener2_fx = dotp_fixed_o( sig2_fx, sig2_fx, nSamples, gB, &q_ener2 ); /* q_ener2 */
85 961574 : cEner_fx = Mpy_32_32( ener1_fx, ener2_fx ); /* q_ener1+q_ener2-31 */
86 961574 : q_cEner = sub( 62, add( q_ener1, q_ener2 ) );
87 961574 : cEner_fx = Sqrt32( cEner_fx, &q_cEner ); /* Q31-q_cEner */
88 961574 : q_cEner = sub( Q31, q_cEner );
89 961574 : cc_fx = dotp_fixed_o( sig1_fx, sig2_fx, nSamples, gB, &q_cc ); /* q_cc */
90 :
91 961574 : IF( corr != NULL )
92 : {
93 961574 : *corr = cc_fx;
94 961574 : *corr_e = sub( Q31, q_cc );
95 961574 : move16();
96 961574 : move32();
97 : }
98 :
99 961574 : IF( cEner_fx > 0 )
100 : {
101 961574 : coh_fx = BASOP_Util_Divide3232_Scale( cc_fx, cEner_fx, &coh_e ); /* Q15-coh_e */
102 961574 : coh_e = add( coh_e, sub( q_cEner, q_cc ) );
103 961574 : coh_fx = shl_sat( coh_fx, coh_e ); // Q15
104 : }
105 :
106 961574 : IF( predCoeff != NULL )
107 : {
108 961574 : *predCoeff = 0;
109 961574 : move32();
110 961574 : IF( ener1_fx > 0 )
111 : {
112 961574 : *predCoeff = BASOP_Util_Divide3232_Scale( cc_fx, ener1_fx, predCoeff_e ); /* Q31-predCoeff_e */
113 961574 : move32();
114 961574 : *predCoeff_e = add( *predCoeff_e, sub( q_ener1, q_cc ) );
115 961574 : move16();
116 : }
117 : }
118 :
119 961574 : return coh_fx;
120 : }
121 :
122 :
123 : /*-------------------------------------------------------------------*
124 : * IGF_MsStereoDecision()
125 : *
126 : *
127 : *-------------------------------------------------------------------*/
128 :
129 90438 : static void IGF_MsStereoDecision_fx(
130 : STEREO_MDCT_BAND_PARAMETERS *sfbParam,
131 : H_IGF_GRID hGrid,
132 : const Word32 *specL_fx, /* q_spec */
133 : const Word32 *specR_fx, /* q_spec */
134 : Word16 q_spec,
135 : Word16 *igfStereoMode, /* output Q0*/
136 : Word16 *msMask, /* output Q0*/
137 : const Word16 mdct_stereo_mode /* Q0 */ )
138 : {
139 : Word16 sfb;
140 : Word16 msMaskTrueSomewhere, msMaskFalseSomewhere;
141 : Word16 numMsMaskTrue, numMsMaskFalse, numMsMaskThresh, numMsMaskMSForLR;
142 : Word16 tile_idx;
143 : Word16 strt_cpy;
144 : Word16 thresh;
145 :
146 90438 : thresh = TARGET_COH_THRESHOLD_FX;
147 90438 : move16();
148 :
149 90438 : if ( EQ_16( mdct_stereo_mode, SMDCT_MS_FULL ) )
150 : {
151 58143 : thresh = 13762; /* lower threshold if core is already MS TARGET_COH_THRESHOLD_FX*(0.7 in Q15)*/
152 58143 : move16();
153 : }
154 :
155 380638 : FOR( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
156 : {
157 290200 : strt_cpy = hGrid->sbWrap[tile_idx]; /* Q0 */
158 290200 : move16();
159 :
160 770987 : FOR( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
161 : {
162 480787 : Word16 width = sub( hGrid->swb_offset[sfb + 1], hGrid->swb_offset[sfb] ); /* Q0 */
163 : Word32 cc_src_fx, cc_target_fx;
164 : Word16 cc_src_e, cc_target_e;
165 : Word16 pc_target_fx, pc_src_fx;
166 : Word16 pc_target_e, pc_src_e;
167 : Word16 tmp1, tmp1_e, tmp2, tmp2_e;
168 :
169 480787 : pc_target_e = 0;
170 480787 : pc_src_e = 0;
171 480787 : move16();
172 480787 : move16();
173 :
174 480787 : Word16 coh_src = calcCoh_fx( &specL_fx[strt_cpy], &specR_fx[strt_cpy], q_spec, width, &cc_src_fx, &cc_src_e, &pc_src_fx, &pc_src_e );
175 480787 : Word16 coh_target = calcCoh_fx( &specL_fx[hGrid->swb_offset[sfb]], &specR_fx[hGrid->swb_offset[sfb]], q_spec, width, &cc_target_fx, &cc_target_e, &pc_target_fx, &pc_target_e );
176 480787 : tmp1_e = BASOP_Util_Add_MantExp( pc_target_fx, pc_target_e, negate( pc_src_fx ), pc_src_e, &tmp1 ); /* Q15-tmp1_e */
177 480787 : tmp2_e = BASOP_Util_Add_MantExp( pc_target_fx, pc_target_e, -16384, 1, &tmp2 ); /* Q15-tmp2_e */
178 :
179 480787 : strt_cpy = add( strt_cpy, width ); /* Q0 */
180 480787 : IF( GT_16( abs_s( coh_target ), thresh ) )
181 : {
182 : /* target is very coherent */
183 298657 : IF( GT_16( abs_s( coh_src ), SOURCE_COH_THRESHOLD_FX ) )
184 : {
185 238340 : test();
186 238340 : IF( LT_16( abs_s( shl_sat( tmp1, tmp1_e ) ), PANNING_THRESHOLD_FX ) && GT_16( abs_s( shl_sat( tmp2, tmp2_e ) ), 2 * PANNING_THRESHOLD_FX ) ) /* same position but not close to the MID */
187 : {
188 : /* same for the source, stereo pos are close, stay on LR */
189 34453 : msMask[sfb] = IGF_PATCH_LR;
190 34453 : move16();
191 : }
192 : ELSE
193 : {
194 203887 : msMask[sfb] = IGF_PATCH_MS;
195 203887 : move16();
196 : }
197 : }
198 : ELSE
199 : {
200 : /* we need to get the coherent patch, do MS */
201 60317 : msMask[sfb] = IGF_PATCH_MS;
202 60317 : move16();
203 : }
204 : }
205 : ELSE
206 : {
207 : /* target is not coherent, stick to LR patching */
208 182130 : msMask[sfb] = IGF_PATCH_LR;
209 182130 : move16();
210 : }
211 : }
212 : }
213 :
214 90438 : msMaskTrueSomewhere = 0;
215 90438 : move16();
216 90438 : msMaskFalseSomewhere = 0;
217 90438 : move16();
218 90438 : numMsMaskTrue = 0;
219 90438 : move16();
220 90438 : numMsMaskFalse = 0;
221 90438 : move16();
222 90438 : numMsMaskThresh = shr( sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ), 2 );
223 90438 : numMsMaskMSForLR = 0;
224 90438 : move16();
225 :
226 380638 : FOR( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
227 : {
228 770987 : FOR( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
229 : {
230 480787 : SWITCH( msMask[sfb] )
231 : {
232 216583 : case IGF_PATCH_LR:
233 216583 : msMask[sfb] = 0;
234 216583 : move16();
235 216583 : numMsMaskFalse = add( numMsMaskFalse, 1 ); /* Q0 */
236 216583 : msMaskFalseSomewhere = 1;
237 216583 : move16();
238 216583 : break;
239 264204 : case IGF_PATCH_MS:
240 264204 : msMask[sfb] = 1;
241 264204 : move16();
242 264204 : numMsMaskTrue = add( numMsMaskTrue, 1 ); /* Q0 */
243 264204 : msMaskTrueSomewhere = 1;
244 264204 : move16();
245 264204 : break;
246 0 : default:
247 0 : assert( 0 );
248 : break;
249 : }
250 : }
251 : }
252 :
253 90438 : IF( msMaskTrueSomewhere )
254 : {
255 58565 : IF( msMaskFalseSomewhere )
256 : {
257 31359 : *igfStereoMode = SMDCT_BW_MS;
258 31359 : move16();
259 :
260 31359 : test();
261 31359 : IF( LE_16( numMsMaskFalse, numMsMaskThresh ) )
262 : {
263 12688 : *igfStereoMode = SMDCT_MS_FULL;
264 12688 : move16();
265 12688 : set_s( &msMask[0], 1, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
266 : }
267 18671 : ELSE IF( LE_16( numMsMaskTrue, numMsMaskThresh ) && !numMsMaskMSForLR )
268 : {
269 4477 : *igfStereoMode = SMDCT_DUAL_MONO;
270 4477 : move16();
271 4477 : set_s( &msMask[0], 0, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
272 : }
273 : }
274 : ELSE
275 : {
276 27206 : *igfStereoMode = SMDCT_MS_FULL;
277 27206 : move16();
278 27206 : set_s( &msMask[0], 1, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
279 : }
280 : }
281 : ELSE
282 : {
283 31873 : *igfStereoMode = SMDCT_DUAL_MONO;
284 31873 : move16();
285 31873 : set_s( &msMask[0], 0, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
286 : }
287 :
288 90438 : return;
289 : }
290 :
291 :
292 : /*-------------------------------------------------------------------*
293 : * IGFEncStereoEncoder()
294 : *
295 : *
296 : *-------------------------------------------------------------------*/
297 :
298 90438 : void IGFEncStereoEncoder_fx(
299 : STEREO_MDCT_BAND_PARAMETERS *sfbParam, /* i/o: sfb parameters for the right channel */
300 : const IGF_ENC_INSTANCE_HANDLE hIGFEnc, /* i : IGF handle */
301 : const Word32 *mdctSpectrumL_fx, /* i : left spectrum q_mdctSpectrum*/
302 : const Word32 *mdctSpectrumR_fx, /* i : right spectrum q_mdctSpectrum*/
303 : Word16 q_mdctSpectrum,
304 : Word16 *msMask, /* i/o: MS mask Q0*/
305 : Word16 *igfStereoMode, /* o : IGF stereo mode Q0*/
306 : const Word16 mdct_stereo_mode, /* i : MDCT stereo mode Q0*/
307 : const Word16 isTCX20, /* i : flag for indicating TCX20 Q0*/
308 : const Word16 isTransition /* i : flag for transtition Q0*/
309 : )
310 : {
311 : Word16 igfGridIdx;
312 : H_IGF_GRID hGrid;
313 :
314 90438 : IF( isTransition && isTCX20 )
315 : {
316 0 : igfGridIdx = IGF_GRID_LB_TRAN;
317 0 : move16();
318 : }
319 90438 : ELSE IF( isTCX20 )
320 : {
321 85934 : igfGridIdx = IGF_GRID_LB_NORM;
322 85934 : move16();
323 : }
324 : ELSE
325 : {
326 : /* It is short block */
327 4504 : igfGridIdx = IGF_GRID_LB_SHORT;
328 4504 : move16();
329 : }
330 :
331 90438 : hGrid = &hIGFEnc->igfData.igfInfo.grid[igfGridIdx];
332 90438 : IGF_MsStereoDecision_fx( sfbParam, hGrid, mdctSpectrumL_fx, mdctSpectrumR_fx, q_mdctSpectrum, igfStereoMode, msMask + sfbParam->nBandsStereoCore, mdct_stereo_mode );
333 :
334 90438 : return;
335 : }
|