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 961808 : 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 961808 : coh_fx = 0;
76 961808 : move16();
77 961808 : Word16 gB = find_guarded_bits_fx( nSamples );
78 961808 : q_ener1 = shl( q_sig, 1 );
79 961808 : q_ener2 = q_ener1;
80 961808 : move16();
81 961808 : q_cc = q_ener1;
82 961808 : move16();
83 961808 : ener1_fx = dotp_fixed_o( sig1_fx, sig1_fx, nSamples, gB, &q_ener1 ); /* q_ener1 */
84 961808 : ener2_fx = dotp_fixed_o( sig2_fx, sig2_fx, nSamples, gB, &q_ener2 ); /* q_ener2 */
85 961808 : cEner_fx = Mpy_32_32( ener1_fx, ener2_fx ); /* q_ener1+q_ener2-31 */
86 961808 : q_cEner = sub( 62, add( q_ener1, q_ener2 ) );
87 961808 : cEner_fx = Sqrt32( cEner_fx, &q_cEner ); /* Q31-q_cEner */
88 961808 : q_cEner = sub( Q31, q_cEner );
89 961808 : cc_fx = dotp_fixed_o( sig1_fx, sig2_fx, nSamples, gB, &q_cc ); /* q_cc */
90 :
91 961808 : IF( corr != NULL )
92 : {
93 961808 : *corr = cc_fx;
94 961808 : *corr_e = sub( Q31, q_cc );
95 961808 : move16();
96 961808 : move32();
97 : }
98 :
99 961808 : IF( cEner_fx > 0 )
100 : {
101 961808 : coh_fx = BASOP_Util_Divide3232_Scale( cc_fx, cEner_fx, &coh_e ); /* Q15-coh_e */
102 961808 : coh_e = add( coh_e, sub( q_cEner, q_cc ) );
103 961808 : coh_fx = shl_sat( coh_fx, coh_e ); // Q15
104 : }
105 :
106 961808 : IF( predCoeff != NULL )
107 : {
108 961808 : *predCoeff = 0;
109 961808 : move32();
110 961808 : IF( ener1_fx > 0 )
111 : {
112 961808 : *predCoeff = BASOP_Util_Divide3232_Scale( cc_fx, ener1_fx, predCoeff_e ); /* Q31-predCoeff_e */
113 961808 : move32();
114 961808 : *predCoeff_e = add( *predCoeff_e, sub( q_ener1, q_cc ) );
115 961808 : move16();
116 : }
117 : }
118 :
119 961808 : return coh_fx;
120 : }
121 :
122 :
123 : /*-------------------------------------------------------------------*
124 : * IGF_MsStereoDecision()
125 : *
126 : *
127 : *-------------------------------------------------------------------*/
128 :
129 90473 : 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 90473 : thresh = TARGET_COH_THRESHOLD_FX;
147 90473 : move16();
148 :
149 90473 : if ( EQ_16( mdct_stereo_mode, SMDCT_MS_FULL ) )
150 : {
151 58079 : thresh = 13762; /* lower threshold if core is already MS TARGET_COH_THRESHOLD_FX*(0.7 in Q15)*/
152 58079 : move16();
153 : }
154 :
155 380728 : FOR( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
156 : {
157 290255 : strt_cpy = hGrid->sbWrap[tile_idx]; /* Q0 */
158 290255 : move16();
159 :
160 771159 : FOR( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
161 : {
162 480904 : 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 480904 : pc_target_e = 0;
170 480904 : pc_src_e = 0;
171 480904 : move16();
172 480904 : move16();
173 :
174 480904 : 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 480904 : 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 480904 : tmp1_e = BASOP_Util_Add_MantExp( pc_target_fx, pc_target_e, negate( pc_src_fx ), pc_src_e, &tmp1 ); /* Q15-tmp1_e */
177 480904 : tmp2_e = BASOP_Util_Add_MantExp( pc_target_fx, pc_target_e, -16384, 1, &tmp2 ); /* Q15-tmp2_e */
178 :
179 480904 : strt_cpy = add( strt_cpy, width ); /* Q0 */
180 480904 : IF( GT_16( abs_s( coh_target ), thresh ) )
181 : {
182 : /* target is very coherent */
183 297372 : IF( GT_16( abs_s( coh_src ), SOURCE_COH_THRESHOLD_FX ) )
184 : {
185 237271 : test();
186 237271 : 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 34385 : msMask[sfb] = IGF_PATCH_LR;
190 34385 : move16();
191 : }
192 : ELSE
193 : {
194 202886 : msMask[sfb] = IGF_PATCH_MS;
195 202886 : move16();
196 : }
197 : }
198 : ELSE
199 : {
200 : /* we need to get the coherent patch, do MS */
201 60101 : msMask[sfb] = IGF_PATCH_MS;
202 60101 : move16();
203 : }
204 : }
205 : ELSE
206 : {
207 : /* target is not coherent, stick to LR patching */
208 183532 : msMask[sfb] = IGF_PATCH_LR;
209 183532 : move16();
210 : }
211 : }
212 : }
213 :
214 90473 : msMaskTrueSomewhere = 0;
215 90473 : move16();
216 90473 : msMaskFalseSomewhere = 0;
217 90473 : move16();
218 90473 : numMsMaskTrue = 0;
219 90473 : move16();
220 90473 : numMsMaskFalse = 0;
221 90473 : move16();
222 90473 : numMsMaskThresh = shr( sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ), 2 );
223 90473 : numMsMaskMSForLR = 0;
224 90473 : move16();
225 :
226 380728 : FOR( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
227 : {
228 771159 : FOR( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
229 : {
230 480904 : SWITCH( msMask[sfb] )
231 : {
232 217917 : case IGF_PATCH_LR:
233 217917 : msMask[sfb] = 0;
234 217917 : move16();
235 217917 : numMsMaskFalse = add( numMsMaskFalse, 1 ); /* Q0 */
236 217917 : msMaskFalseSomewhere = 1;
237 217917 : move16();
238 217917 : break;
239 262987 : case IGF_PATCH_MS:
240 262987 : msMask[sfb] = 1;
241 262987 : move16();
242 262987 : numMsMaskTrue = add( numMsMaskTrue, 1 ); /* Q0 */
243 262987 : msMaskTrueSomewhere = 1;
244 262987 : move16();
245 262987 : break;
246 0 : default:
247 0 : assert( 0 );
248 : break;
249 : }
250 : }
251 : }
252 :
253 90473 : IF( msMaskTrueSomewhere )
254 : {
255 58400 : IF( msMaskFalseSomewhere )
256 : {
257 31342 : *igfStereoMode = SMDCT_BW_MS;
258 31342 : move16();
259 :
260 31342 : test();
261 31342 : IF( LE_16( numMsMaskFalse, numMsMaskThresh ) )
262 : {
263 12622 : *igfStereoMode = SMDCT_MS_FULL;
264 12622 : move16();
265 12622 : set_s( &msMask[0], 1, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
266 : }
267 18720 : ELSE IF( LE_16( numMsMaskTrue, numMsMaskThresh ) && !numMsMaskMSForLR )
268 : {
269 4537 : *igfStereoMode = SMDCT_DUAL_MONO;
270 4537 : move16();
271 4537 : set_s( &msMask[0], 0, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
272 : }
273 : }
274 : ELSE
275 : {
276 27058 : *igfStereoMode = SMDCT_MS_FULL;
277 27058 : move16();
278 27058 : set_s( &msMask[0], 1, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
279 : }
280 : }
281 : ELSE
282 : {
283 32073 : *igfStereoMode = SMDCT_DUAL_MONO;
284 32073 : move16();
285 32073 : set_s( &msMask[0], 0, sub( sfbParam->sfbCnt, sfbParam->nBandsStereoCore ) );
286 : }
287 :
288 90473 : return;
289 : }
290 :
291 :
292 : /*-------------------------------------------------------------------*
293 : * IGFEncStereoEncoder()
294 : *
295 : *
296 : *-------------------------------------------------------------------*/
297 :
298 90473 : 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 90473 : IF( isTransition && isTCX20 )
315 : {
316 0 : igfGridIdx = IGF_GRID_LB_TRAN;
317 0 : move16();
318 : }
319 90473 : ELSE IF( isTCX20 )
320 : {
321 85969 : igfGridIdx = IGF_GRID_LB_NORM;
322 85969 : move16();
323 : }
324 : ELSE
325 : {
326 : /* It is short block */
327 4504 : igfGridIdx = IGF_GRID_LB_SHORT;
328 4504 : move16();
329 : }
330 :
331 90473 : hGrid = &hIGFEnc->igfData.igfInfo.grid[igfGridIdx];
332 90473 : IGF_MsStereoDecision_fx( sfbParam, hGrid, mdctSpectrumL_fx, mdctSpectrumR_fx, q_mdctSpectrum, igfStereoMode, msMask + sfbParam->nBandsStereoCore, mdct_stereo_mode );
333 :
334 90473 : return;
335 : }
|