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.h"
38 : #include "cnst.h"
39 : #include "stat_enc.h"
40 : #include "ivas_stat_enc.h"
41 : #include "ivas_prot.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 0.6f
51 : #define SOURCE_COH_THRESHOLD 0.7f
52 : #define PANNING_THRESHOLD 0.07f
53 :
54 :
55 : /*-------------------------------------------------------------------*
56 : * calcCoh()
57 : *
58 : *
59 : *-------------------------------------------------------------------*/
60 :
61 984174 : static float calcCoh(
62 : const float *sig1,
63 : const float *sig2,
64 : const int16_t nSamples,
65 : float *corr,
66 : float *predCoeff )
67 : {
68 : float coh, ener1, ener2, cEner, cc;
69 :
70 984174 : coh = 0.0f;
71 984174 : ener1 = dotp( sig1, sig1, nSamples );
72 984174 : ener2 = dotp( sig2, sig2, nSamples );
73 984174 : cEner = sqrtf( ener1 * ener2 );
74 984174 : cc = dotp( sig1, sig2, nSamples );
75 :
76 984174 : if ( corr != NULL )
77 : {
78 984174 : *corr = cc;
79 : }
80 :
81 984174 : if ( cEner > 0.0f )
82 : {
83 984174 : coh = cc / cEner;
84 : }
85 :
86 984174 : if ( predCoeff != NULL )
87 : {
88 984174 : *predCoeff = 0.f;
89 984174 : if ( ener1 > 0.0f )
90 : {
91 984174 : *predCoeff = cc / ener1;
92 : }
93 : }
94 :
95 984174 : return coh;
96 : }
97 :
98 :
99 : /*-------------------------------------------------------------------*
100 : * IGF_MsStereoDecision()
101 : *
102 : *
103 : *-------------------------------------------------------------------*/
104 :
105 92706 : static void IGF_MsStereoDecision(
106 : STEREO_MDCT_BAND_PARAMETERS *sfbParam,
107 : H_IGF_GRID hGrid,
108 : const float *specL,
109 : const float *specR,
110 : int16_t *igfStereoMode, /* output*/
111 : int16_t *msMask, /* output*/
112 : const int16_t mdct_stereo_mode )
113 : {
114 : int16_t sfb;
115 : int16_t msMaskTrueSomewhere, msMaskFalseSomewhere;
116 : int16_t numMsMaskTrue, numMsMaskFalse, numMsMaskThresh, numMsMaskMSForLR;
117 : int16_t tile_idx;
118 : int16_t strt_cpy;
119 : float thresh;
120 :
121 92706 : thresh = TARGET_COH_THRESHOLD;
122 92706 : if ( mdct_stereo_mode == SMDCT_MS_FULL )
123 : {
124 58911 : thresh *= 0.7f; /* lower threshold if core is already MS */
125 : }
126 :
127 388781 : for ( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
128 : {
129 296075 : strt_cpy = hGrid->sbWrap[tile_idx];
130 :
131 788162 : for ( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
132 : {
133 492087 : int16_t width = hGrid->swb_offset[sfb + 1] - hGrid->swb_offset[sfb];
134 : float cc_src, cc_target, pc_target, pc_src;
135 492087 : float coh_src = calcCoh( &specL[strt_cpy], &specR[strt_cpy], width, &cc_src, &pc_src );
136 492087 : float coh_target = calcCoh( &specL[hGrid->swb_offset[sfb]], &specR[hGrid->swb_offset[sfb]], width, &cc_target, &pc_target );
137 :
138 492087 : strt_cpy += width;
139 492087 : if ( fabsf( coh_target ) > thresh )
140 : {
141 : /* target is very coherent */
142 303301 : if ( fabsf( coh_src ) > SOURCE_COH_THRESHOLD )
143 : {
144 242635 : if ( fabsf( pc_target - pc_src ) < PANNING_THRESHOLD && fabsf( pc_target - 1.0f ) > 2.0f * PANNING_THRESHOLD ) /* same position but not close to the MID */
145 : {
146 : /* same for the source, stereo pos are close, stay on LR */
147 34773 : msMask[sfb] = IGF_PATCH_LR;
148 : }
149 : else
150 : {
151 207862 : msMask[sfb] = IGF_PATCH_MS;
152 : }
153 : }
154 : else
155 : {
156 : /* we need to get the coherent patch, do MS */
157 60666 : msMask[sfb] = IGF_PATCH_MS;
158 : }
159 : }
160 : else
161 : {
162 : /* target is not coherent, stick to LR patching */
163 188786 : msMask[sfb] = IGF_PATCH_LR;
164 : }
165 : }
166 : }
167 :
168 92706 : msMaskTrueSomewhere = 0;
169 92706 : msMaskFalseSomewhere = 0;
170 92706 : numMsMaskTrue = 0;
171 92706 : numMsMaskFalse = 0;
172 92706 : numMsMaskThresh = ( sfbParam->sfbCnt - sfbParam->nBandsStereoCore ) / 4;
173 92706 : numMsMaskMSForLR = 0;
174 :
175 388781 : for ( tile_idx = 0; tile_idx < hGrid->nTiles; tile_idx++ )
176 : {
177 788162 : for ( sfb = hGrid->sfbWrap[tile_idx]; sfb < hGrid->sfbWrap[tile_idx + 1]; sfb++ )
178 : {
179 492087 : switch ( msMask[sfb] )
180 : {
181 223559 : case IGF_PATCH_LR:
182 223559 : msMask[sfb] = 0;
183 223559 : numMsMaskFalse++;
184 223559 : msMaskFalseSomewhere = 1;
185 223559 : break;
186 268528 : case IGF_PATCH_MS:
187 268528 : msMask[sfb] = 1;
188 268528 : numMsMaskTrue++;
189 268528 : msMaskTrueSomewhere = 1;
190 268528 : break;
191 0 : default:
192 0 : assert( 0 );
193 : break;
194 : }
195 : }
196 : }
197 :
198 92706 : if ( msMaskTrueSomewhere )
199 : {
200 59261 : if ( msMaskFalseSomewhere )
201 : {
202 31712 : *igfStereoMode = SMDCT_BW_MS;
203 :
204 31712 : if ( numMsMaskFalse <= numMsMaskThresh )
205 : {
206 12949 : *igfStereoMode = SMDCT_MS_FULL;
207 12949 : set_s( &msMask[0], 1, sfbParam->sfbCnt - sfbParam->nBandsStereoCore );
208 : }
209 18763 : else if ( numMsMaskTrue <= numMsMaskThresh && !numMsMaskMSForLR )
210 : {
211 4462 : *igfStereoMode = SMDCT_DUAL_MONO;
212 4462 : set_s( &msMask[0], 0, sfbParam->sfbCnt - sfbParam->nBandsStereoCore );
213 : }
214 : }
215 : else
216 : {
217 27549 : *igfStereoMode = SMDCT_MS_FULL;
218 27549 : set_s( &msMask[0], 1, sfbParam->sfbCnt - sfbParam->nBandsStereoCore );
219 : }
220 : }
221 : else
222 : {
223 33445 : *igfStereoMode = SMDCT_DUAL_MONO;
224 33445 : set_s( &msMask[0], 0, sfbParam->sfbCnt - sfbParam->nBandsStereoCore );
225 : }
226 :
227 92706 : return;
228 : }
229 :
230 :
231 : /*-------------------------------------------------------------------*
232 : * IGFEncStereoEncoder()
233 : *
234 : *
235 : *-------------------------------------------------------------------*/
236 :
237 92706 : void IGFEncStereoEncoder(
238 : STEREO_MDCT_BAND_PARAMETERS *sfbParam, /* i/o: sfb parameters for the right channel */
239 : const IGF_ENC_INSTANCE_HANDLE hIGFEnc, /* i : IGF handle */
240 : const float *mdctSpectrumL, /* i : left spectrum */
241 : const float *mdctSpectrumR, /* i : right spectrum */
242 : int16_t *msMask, /* i/o: MS mask */
243 : int16_t *igfStereoMode, /* o : IGF stereo mode */
244 : const int16_t mdct_stereo_mode, /* i : MDCT stereo mode */
245 : const int16_t isTCX20, /* i : flag for indicating TCX20 */
246 : const int16_t isTransition /* i : flag for transtition */
247 : )
248 : {
249 : int16_t igfGridIdx;
250 : H_IGF_GRID hGrid;
251 :
252 92706 : if ( isTransition && isTCX20 )
253 : {
254 0 : igfGridIdx = IGF_GRID_LB_TRAN;
255 : }
256 92706 : else if ( isTCX20 )
257 : {
258 88016 : igfGridIdx = IGF_GRID_LB_NORM;
259 : }
260 : else
261 : {
262 : /* It is short block */
263 4690 : igfGridIdx = IGF_GRID_LB_SHORT;
264 : }
265 :
266 92706 : hGrid = &hIGFEnc->igfData.igfInfo.grid[igfGridIdx];
267 :
268 92706 : IGF_MsStereoDecision( sfbParam, hGrid, mdctSpectrumL, mdctSpectrumR, igfStereoMode, msMask + sfbParam->nBandsStereoCore, mdct_stereo_mode );
269 :
270 92706 : return;
271 : }
|