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 <math.h>
34 : #include "options.h"
35 : #include "lib_rend.h"
36 : #include "ivas_prot_rend.h"
37 : #include "ivas_prot.h"
38 : #include "ivas_cnst.h"
39 : #include "prot.h"
40 : #include "ivas_rom_com.h"
41 : #include "wmc_auto.h"
42 :
43 :
44 : /*---------------------------------------------------------------------*
45 : * Local function prototypes
46 : *---------------------------------------------------------------------*/
47 :
48 : static void copy_masa_meta_tile( MASA_DECODER_EXT_OUT_META_HANDLE outMeta, MASA_DECODER_EXT_OUT_META_HANDLE inMeta, const uint8_t sf, const uint8_t band );
49 :
50 : static void full_stream_merge( MASA_DECODER_EXT_OUT_META_HANDLE outMeta, MASA_DECODER_EXT_OUT_META_HANDLE inMeta1, float inEne1[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], MASA_DECODER_EXT_OUT_META_HANDLE inMeta2, float inEne2[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] );
51 :
52 : static void diffuse_meta_merge_1x1( MASA_DECODER_EXT_OUT_META_HANDLE outMeta, MASA_DECODER_EXT_OUT_META_HANDLE inMeta, float inEne[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], MASA_DECODER_EXT_OUT_META_HANDLE inMetaISM, float inEneISM[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] );
53 :
54 :
55 : /*---------------------------------------------------------------------*
56 : * copy_masa_meta_tile()
57 : *
58 : *
59 : *---------------------------------------------------------------------*/
60 :
61 15380928 : void copy_masa_meta_tile(
62 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta, /* o : metadata to be written */
63 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta, /* i : input metadata */
64 : const uint8_t sf, /* i : sub-frame index */
65 : const uint8_t band /* i : band index */
66 : )
67 : {
68 15380928 : outMeta->directionIndex[0][sf][band] = inMeta->directionIndex[0][sf][band];
69 15380928 : outMeta->directToTotalRatio[0][sf][band] = inMeta->directToTotalRatio[0][sf][band];
70 15380928 : outMeta->spreadCoherence[0][sf][band] = inMeta->spreadCoherence[0][sf][band];
71 :
72 15380928 : outMeta->surroundCoherence[sf][band] = inMeta->surroundCoherence[sf][band];
73 15380928 : outMeta->diffuseToTotalRatio[sf][band] = inMeta->diffuseToTotalRatio[sf][band];
74 :
75 15380928 : if ( inMeta->descriptiveMeta.numberOfDirections == 1 )
76 : {
77 6232126 : outMeta->directionIndex[1][sf][band] = inMeta->directionIndex[1][sf][band];
78 6232126 : outMeta->directToTotalRatio[1][sf][band] = inMeta->directToTotalRatio[1][sf][band];
79 6232126 : outMeta->spreadCoherence[1][sf][band] = inMeta->spreadCoherence[1][sf][band];
80 : }
81 : else
82 : {
83 : /* make sure the output has zeroed data in the second direction */
84 9148802 : outMeta->directionIndex[1][sf][band] = SPH_IDX_FRONT;
85 9148802 : outMeta->directToTotalRatio[1][sf][band] = 0u;
86 9148802 : outMeta->spreadCoherence[1][sf][band] = 0u;
87 : }
88 :
89 15380928 : return;
90 : }
91 :
92 :
93 : /*---------------------------------------------------------------------*
94 : * copy_masa_descriptive_meta()
95 : *
96 : *
97 : *---------------------------------------------------------------------*/
98 :
99 304693 : void copy_masa_descriptive_meta(
100 : MASA_DECRIPTIVE_META *outMeta, /* o : metadata to be written */
101 : MASA_DECRIPTIVE_META *inMeta /* i : input metadata */
102 : )
103 : {
104 : uint8_t char_idx;
105 2742237 : for ( char_idx = 0; char_idx < 8; char_idx++ )
106 : {
107 2437544 : outMeta->formatDescriptor[char_idx] = inMeta->formatDescriptor[char_idx];
108 : }
109 304693 : outMeta->numberOfDirections = inMeta->numberOfDirections;
110 304693 : outMeta->numberOfChannels = inMeta->numberOfChannels;
111 304693 : outMeta->sourceFormat = inMeta->sourceFormat;
112 304693 : outMeta->transportDefinition = inMeta->transportDefinition;
113 304693 : outMeta->channelAngle = inMeta->channelAngle;
114 304693 : outMeta->channelDistance = inMeta->channelDistance;
115 304693 : outMeta->channelLayout = inMeta->channelLayout;
116 :
117 304693 : return;
118 : }
119 :
120 :
121 : /*---------------------------------------------------------------------*
122 : * diffuse_meta_merge_1x1()
123 : *
124 : *
125 : *---------------------------------------------------------------------*/
126 :
127 157032 : void diffuse_meta_merge_1x1(
128 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta, /* o : Merged metadata output */
129 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta, /* i : Input metadata 1 */
130 : float inEne[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i/o: TF-energy of input 1. energy after merge */
131 : MASA_DECODER_EXT_OUT_META_HANDLE inMetaISM, /* i : Input metadata 2 */
132 : float inEneISM[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] /* i : TF-energy of input 2 */
133 : )
134 : {
135 : int8_t sf, band;
136 :
137 785160 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
138 : {
139 15703200 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
140 : {
141 : float energyTimesRatio, energyTimesRatioISM, total_diff_nrg, dir_nrg_ratio, total_nrg;
142 : float dir_ratio_ism;
143 :
144 15075072 : energyTimesRatio = (float) ( inMeta->directToTotalRatio[0][sf][band] ) / UINT8_MAX * inEne[sf][band];
145 :
146 15075072 : total_nrg = inEne[sf][band] + inEneISM[sf][band];
147 :
148 : /* target is original MASA diffuseness */
149 15075072 : total_diff_nrg = (float) ( inMeta->diffuseToTotalRatio[sf][band] ) / UINT8_MAX * inEne[sf][band];
150 : /* criterion is mean of ISM ratio and new ratio */
151 15075072 : dir_ratio_ism = (float) ( inMetaISM->directToTotalRatio[0][sf][band] ) / UINT8_MAX;
152 :
153 15075072 : energyTimesRatioISM = ( dir_ratio_ism + ( 1.0f - total_diff_nrg / ( EPSILON + total_nrg ) ) ) / 2.0f * inEneISM[sf][band];
154 :
155 15075072 : if ( energyTimesRatioISM > energyTimesRatio )
156 : {
157 : float new_dir_ratio, new_diff_ratio;
158 8501044 : outMeta->directionIndex[0][sf][band] = inMetaISM->directionIndex[0][sf][band];
159 8501044 : outMeta->directToTotalRatio[0][sf][band] = inMetaISM->directToTotalRatio[0][sf][band];
160 8501044 : outMeta->spreadCoherence[0][sf][band] = inMetaISM->spreadCoherence[0][sf][band];
161 :
162 8501044 : outMeta->surroundCoherence[sf][band] = inMetaISM->surroundCoherence[sf][band];
163 :
164 8501044 : dir_nrg_ratio = 1.0f - total_diff_nrg / ( EPSILON + total_nrg ); /* new dir ratio */
165 8501044 : new_dir_ratio = min( dir_nrg_ratio, dir_ratio_ism ); /* clip with original ISM dir */
166 8501044 : outMeta->directToTotalRatio[0][sf][band] = (uint8_t) floorf( new_dir_ratio * UINT8_MAX );
167 8501044 : new_diff_ratio = 1.0f - new_dir_ratio;
168 8501044 : outMeta->diffuseToTotalRatio[sf][band] = (uint8_t) floorf( new_diff_ratio * UINT8_MAX );
169 : }
170 : else
171 : {
172 : /* use the plain original meta for this tile */
173 6574028 : outMeta->directionIndex[0][sf][band] = inMeta->directionIndex[0][sf][band];
174 6574028 : outMeta->directToTotalRatio[0][sf][band] = inMeta->directToTotalRatio[0][sf][band];
175 6574028 : outMeta->spreadCoherence[0][sf][band] = inMeta->spreadCoherence[0][sf][band];
176 :
177 6574028 : outMeta->surroundCoherence[sf][band] = inMeta->surroundCoherence[sf][band];
178 6574028 : outMeta->diffuseToTotalRatio[sf][band] = inMeta->diffuseToTotalRatio[sf][band];
179 : }
180 15075072 : outMeta->directionIndex[1][sf][band] = SPH_IDX_FRONT;
181 15075072 : outMeta->directToTotalRatio[1][sf][band] = 0u;
182 15075072 : outMeta->spreadCoherence[1][sf][band] = 0u;
183 :
184 15075072 : inEne[sf][band] += inEneISM[sf][band]; /* Update energy for subsequent mergings */
185 : }
186 : }
187 :
188 : /* Set descriptive meta for mixed format */
189 157032 : outMeta->descriptiveMeta.sourceFormat = 0u;
190 157032 : outMeta->descriptiveMeta.transportDefinition = 0u;
191 157032 : outMeta->descriptiveMeta.channelAngle = 0u;
192 157032 : outMeta->descriptiveMeta.channelDistance = 0u;
193 157032 : outMeta->descriptiveMeta.channelLayout = 0u;
194 157032 : outMeta->descriptiveMeta.numberOfDirections = 0u;
195 : /* Number of transports should be set outside. */
196 :
197 157032 : return;
198 : }
199 :
200 :
201 : /*---------------------------------------------------------------------*
202 : * full_stream_merge()
203 : *
204 : *
205 : *---------------------------------------------------------------------*/
206 :
207 160218 : void full_stream_merge(
208 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta, /* o : Merged metadata output */
209 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta1, /* i : Input metadata 1 */
210 : float inEne1[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i/o: TF-energy of input 1. after merge, contains the energy of the merged signal */
211 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2, /* i : Input metadata 2 */
212 : float inEne2[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] /* i : TF-energy of input 2 */
213 : )
214 : {
215 : float dir_nrg_1, dir_nrg_2;
216 : uint8_t n_dirs_1, n_dirs_2;
217 : uint8_t sf, band;
218 :
219 : /* full stream select based on total direct energy */
220 160218 : n_dirs_1 = inMeta1->descriptiveMeta.numberOfDirections + 1u; /* to 1-based */
221 160218 : n_dirs_2 = inMeta2->descriptiveMeta.numberOfDirections + 1u;
222 :
223 801090 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
224 : {
225 16021800 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
226 : {
227 15380928 : dir_nrg_1 = (float) ( inMeta1->directToTotalRatio[0][sf][band] ) / UINT8_MAX * inEne1[sf][band];
228 15380928 : dir_nrg_2 = (float) ( inMeta2->directToTotalRatio[0][sf][band] ) / UINT8_MAX * inEne2[sf][band];
229 :
230 15380928 : if ( n_dirs_1 == 2 )
231 : {
232 14833728 : dir_nrg_1 += (float) ( inMeta1->directToTotalRatio[1][sf][band] ) / UINT8_MAX * inEne1[sf][band];
233 : }
234 :
235 15380928 : if ( n_dirs_2 == 2 )
236 : {
237 273600 : dir_nrg_2 += (float) ( inMeta2->directToTotalRatio[1][sf][band] ) / UINT8_MAX * inEne2[sf][band];
238 : }
239 :
240 15380928 : if ( dir_nrg_1 > dir_nrg_2 )
241 : {
242 6394454 : copy_masa_meta_tile( outMeta, inMeta1, sf, band );
243 : }
244 : else
245 : {
246 8986474 : copy_masa_meta_tile( outMeta, inMeta2, sf, band );
247 : }
248 :
249 15380928 : inEne1[sf][band] += inEne2[sf][band]; /* Update energy for subsequent mergings */
250 : }
251 : }
252 :
253 : /* Set descriptive meta for mixed format */
254 160218 : outMeta->descriptiveMeta.sourceFormat = 0u;
255 160218 : outMeta->descriptiveMeta.transportDefinition = 0u;
256 160218 : outMeta->descriptiveMeta.channelAngle = 0u;
257 160218 : outMeta->descriptiveMeta.channelDistance = 0u;
258 160218 : outMeta->descriptiveMeta.channelLayout = 0u;
259 160218 : if ( n_dirs_1 == 2 || n_dirs_2 == 2 )
260 : {
261 157368 : outMeta->descriptiveMeta.numberOfDirections = 1u;
262 : }
263 : else
264 : {
265 2850 : outMeta->descriptiveMeta.numberOfDirections = 0u;
266 : }
267 : /* Number of transports should be set outside. */
268 :
269 160218 : return;
270 : }
271 :
272 :
273 : /*---------------------------------------------------------------------*
274 : * ivas_prerend_merge_masa_metadata()
275 : *
276 : *
277 : *---------------------------------------------------------------------*/
278 :
279 317250 : void ivas_prerend_merge_masa_metadata(
280 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta, /* o : Merged metadata output */
281 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta1, /* i : Input metadata 1 */
282 : IVAS_REND_AudioConfigType inType1, /* i : Type of input 1 */
283 : float inEne1[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i/o: TF-energy of input 1. after merge, contains the energy of the merged signal */
284 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2, /* i : Input metadata 2 */
285 : IVAS_REND_AudioConfigType inType2, /* i : Type of input 2 */
286 : float inEne2[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] /* i : TF-energy of input 2. may be altered */
287 : )
288 : {
289 : /* mixing ISMs with non-ISM use different merge */
290 317250 : if ( inType1 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED && inType2 != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED && ( inMeta1->descriptiveMeta.numberOfDirections == 0u && inMeta2->descriptiveMeta.numberOfDirections == 0u ) )
291 0 : {
292 : /* meta_1 is ISM and both are 1dir */
293 : int8_t sf;
294 :
295 0 : diffuse_meta_merge_1x1( outMeta, inMeta2, inEne2, inMeta1, inEne1 ); /* post-merge energy is now in inEne2 and needs to be copied to inEne1 */
296 :
297 0 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
298 : {
299 0 : mvr2r( inEne2[sf], inEne1[sf], MASA_FREQUENCY_BANDS );
300 : }
301 : }
302 317250 : else if ( inType2 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED && inType1 != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED && ( inMeta1->descriptiveMeta.numberOfDirections == 0u && inMeta2->descriptiveMeta.numberOfDirections == 0u ) )
303 : {
304 : /* meta_2 is ISM and both are 1dir */
305 157032 : diffuse_meta_merge_1x1( outMeta, inMeta1, inEne1, inMeta2, inEne2 );
306 : }
307 : else
308 : {
309 160218 : full_stream_merge( outMeta, inMeta1, inEne1, inMeta2, inEne2 );
310 : }
311 :
312 317250 : return;
313 : }
314 :
315 :
316 : /*---------------------------------------------------------------------*
317 : * masaPrerendOpen()
318 : *
319 : *
320 : *---------------------------------------------------------------------*/
321 :
322 163 : ivas_error masaPrerendOpen(
323 : MASA_PREREND_HANDLE *hMasaPrerendPtr, /* o : handle to the opened prerenderer */
324 : int16_t numTransports, /* i : number of transport channels */
325 : int32_t input_Fs /* i : signal sampling rate */
326 : )
327 : {
328 : MASA_PREREND_HANDLE hMasaPrerend;
329 : int16_t i;
330 : int16_t maxBin;
331 : ivas_error error;
332 :
333 163 : error = IVAS_ERR_OK;
334 :
335 163 : hMasaPrerend = (MASA_PREREND_HANDLE) malloc( sizeof( MASA_PREREND_DATA ) );
336 163 : if ( hMasaPrerend == NULL )
337 : {
338 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA prerenderer\n" ) );
339 : }
340 :
341 : /* Determine the number of bands and band grouping */
342 163 : hMasaPrerend->nbands = MASA_FREQUENCY_BANDS;
343 163 : mvs2s( MASA_band_grouping_24, hMasaPrerend->band_grouping, MASA_FREQUENCY_BANDS + 1 );
344 :
345 163 : maxBin = (int16_t) ( input_Fs * INV_CLDFB_BANDWIDTH + 0.5f );
346 3642 : for ( i = 1; i < hMasaPrerend->nbands + 1; i++ )
347 : {
348 3642 : if ( hMasaPrerend->band_grouping[i] >= maxBin )
349 : {
350 163 : hMasaPrerend->band_grouping[i] = maxBin;
351 163 : hMasaPrerend->nbands = i;
352 163 : break;
353 : }
354 : }
355 :
356 163 : hMasaPrerend->num_Cldfb_instances = numTransports;
357 417 : for ( i = 0; i < hMasaPrerend->num_Cldfb_instances; i++ )
358 : {
359 254 : if ( ( error = openCldfb( &( hMasaPrerend->cldfbAnaEnc[i] ), CLDFB_ANALYSIS, input_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
360 : {
361 0 : return error;
362 : }
363 : }
364 235 : for ( ; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
365 : {
366 72 : hMasaPrerend->cldfbAnaEnc[i] = NULL;
367 : }
368 :
369 163 : if ( ( hMasaPrerend->hMasaOut = (MASA_DECODER_EXT_OUT_META_HANDLE) malloc( sizeof( MASA_DECODER_EXT_OUT_META ) ) ) == NULL )
370 : {
371 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA prerenderer\n" ) );
372 : }
373 :
374 163 : if ( ( hMasaPrerend->sph_grid16 = (SPHERICAL_GRID_DATA *) malloc( sizeof( SPHERICAL_GRID_DATA ) ) ) == NULL )
375 : {
376 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA prerenderer\n" ) );
377 : }
378 163 : generate_gridEq( hMasaPrerend->sph_grid16 );
379 :
380 163 : if ( error == IVAS_ERR_OK )
381 : {
382 163 : *hMasaPrerendPtr = hMasaPrerend;
383 : }
384 :
385 163 : return error;
386 : }
387 :
388 :
389 : /*---------------------------------------------------------------------*
390 : * masaPrerendClose()
391 : *
392 : *
393 : *---------------------------------------------------------------------*/
394 :
395 14179 : void masaPrerendClose(
396 : MASA_PREREND_HANDLE *hMasaPrerendPtr /* i/o: prerenderer handle to be closed */
397 : )
398 : {
399 : int16_t i;
400 :
401 14179 : if ( hMasaPrerendPtr == NULL || *hMasaPrerendPtr == NULL )
402 : {
403 14016 : return;
404 : }
405 :
406 417 : for ( i = 0; i < ( *hMasaPrerendPtr )->num_Cldfb_instances; i++ )
407 : {
408 254 : deleteCldfb( &( ( *hMasaPrerendPtr )->cldfbAnaEnc[i] ) );
409 : }
410 :
411 163 : free( ( *hMasaPrerendPtr )->hMasaOut );
412 163 : ( *hMasaPrerendPtr )->hMasaOut = NULL;
413 163 : free( ( *hMasaPrerendPtr )->sph_grid16 );
414 163 : ( *hMasaPrerendPtr )->sph_grid16 = NULL;
415 :
416 163 : free( ( *hMasaPrerendPtr ) );
417 163 : ( *hMasaPrerendPtr ) = NULL;
418 :
419 163 : return;
420 : }
|