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 <math.h>
35 : #include "options.h"
36 : #include "ivas_cnst.h"
37 : #include "ivas_rom_com.h"
38 : #include "ivas_stat_enc.h"
39 : #include "wmc_auto.h"
40 : #include "prot_fx.h"
41 : #include "prot_fx_enc.h"
42 : #include "ivas_prot_fx.h"
43 : #include "ivas_rom_com_fx.h"
44 :
45 :
46 : /*-----------------------------------------------------------------------*
47 : * Local function prototypes
48 : *-----------------------------------------------------------------------*/
49 :
50 : static void combine_freqbands_and_subframes_fx( MASA_ENCODER_HANDLE hMasa );
51 :
52 : static void find_n_largest_fx( const Word32 *input_fx, Word16 exp_input, Word16 *largestIndices, const Word16 numElements, const Word16 numLargest );
53 :
54 : static void move_metadata_to_qmetadata_fx( const MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMeta );
55 :
56 : static void detect_metadata_composition_fx(
57 : const MASA_ENCODER_HANDLE hMasa, /* i : MASA encoder data */
58 : UWord8 *joinedSubframes, /* o : Result of subframe composition */
59 : UWord8 *coherencePresent, /* o : Result of coherence presence */
60 : UWord8 *isTwoDir /* o : Result of two direction check */
61 : );
62 :
63 : static void compensate_energy_ratios_fx( MASA_ENCODER_HANDLE hMasa );
64 :
65 : static Word16 encode_lfe_to_total_energy_ratio_fx( MASA_ENCODER_HANDLE hMasa, BSTR_ENC_HANDLE hMetaData, const Word32 ivas_total_brate );
66 :
67 : static void ivas_encode_masaism_metadata_fx( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hQMetaData, BSTR_ENC_HANDLE hMetaData, ISM_METADATA_HANDLE hIsmMeta[], const Word16 nchan_ism, const Word16 low_bitrate_mode, const Word16 omasa_nbands, const Word16 omasa_nblocks, const Word16 idx_separated_object, const Word16 ism_imp );
68 :
69 : static void reduce_metadata_further_fx( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hqmetadata, const IVAS_FORMAT ivas_format );
70 :
71 : static void average_masa_metadata_fx(
72 : MASA_METADATA_FRAME *hMeta,
73 : Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
74 : Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS],
75 : const SPHERICAL_GRID_DATA *Sph_Grid16,
76 : const UWord8 useSphGrid );
77 :
78 : static void copy_masa_metadata_subframe_fx(
79 : const MASA_METADATA_HANDLE hMetaFrom, /* i : MASA frame metdata to be copied */
80 : const UWord8 sfFrom, /* i : subframe index of the copy source */
81 : MASA_METADATA_HANDLE hMetaTo, /* o : MASA frame metadata copy destination */
82 : const UWord8 sfTo /* i : subframe index of the copy target */
83 : );
84 :
85 : static void copy_masa_metadata_fx( const MASA_METADATA_HANDLE hMetaFrom, MASA_METADATA_HANDLE hMetaTo );
86 :
87 : static UWord8 are_masa_subframes_similar_fx(
88 : const MASA_METADATA_HANDLE frame1, /* i : MASA metadata frame 1 */
89 : const UWord8 sf1_idx, /* i : index of the subframe of frame1 to inspect */
90 : const MASA_METADATA_HANDLE frame2, /* i : MASA metadata frame 2 */
91 : const UWord8 sf2_idx /* i : index of the subframe of frame2 to inspect */
92 : );
93 :
94 : static void detect_framing_async_fx(
95 : MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
96 : );
97 :
98 : static void masa_metadata_direction_alignment_fx( MASA_ENCODER_HANDLE hMasa );
99 :
100 :
101 : /*-----------------------------------------------------------------------*
102 : * Local constants
103 : *-----------------------------------------------------------------------*/
104 :
105 : #define LOWBITRATE_ONSET_ALPHA 0.2f /* Onset values are for processing in frames */
106 : #define LOWBITRATE_ONSET_BETA 0.92f
107 : #define LOWBITRATE_ONSET_GAIN 1.4f
108 : #define LOWBITRATE_ONSET_ALPHA_Q31 429496730 /* Onset values are for processing in frames */
109 : #define LOWBITRATE_ONSET_BETA_Q31 1975684956
110 : #define LOWBITRATE_ONSET_GAIN_Q30 1503238554
111 : #define LOWBITRATE_NUM_BANDS 5
112 :
113 :
114 : /*-----------------------------------------------------------------------*
115 : * ivas_masa_enc_open()
116 : *
117 : * open and initialize MASA encoder
118 : *-----------------------------------------------------------------------*/
119 :
120 416 : ivas_error ivas_masa_enc_open_fx(
121 : Encoder_Struct *st_ivas /* i/o: IVAS encoder handle */
122 : )
123 : {
124 : Word16 i;
125 : MASA_ENCODER_HANDLE hMasa;
126 : ENCODER_CONFIG_HANDLE hEncoderConfig;
127 : ivas_error error;
128 : Word32 ism_total_brate;
129 :
130 416 : error = IVAS_ERR_OK;
131 416 : move32();
132 :
133 416 : IF( ( hMasa = (MASA_ENCODER_HANDLE) malloc( sizeof( MASA_ENCODER ) ) ) == NULL )
134 : {
135 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
136 : }
137 :
138 416 : hEncoderConfig = st_ivas->hEncoderConfig;
139 :
140 416 : generate_gridEq_fx( &( hMasa->data.Sph_Grid16 ) );
141 :
142 416 : test();
143 416 : IF( EQ_32( hEncoderConfig->ivas_format, MASA_FORMAT ) || EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) )
144 : {
145 119 : hMasa->data.num_Cldfb_instances = st_ivas->nchan_transport;
146 119 : move16();
147 : }
148 : ELSE
149 : {
150 297 : hMasa->data.num_Cldfb_instances = 0;
151 297 : move16();
152 : }
153 :
154 623 : FOR( i = 0; i < hMasa->data.num_Cldfb_instances; i++ )
155 : {
156 207 : IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasa->data.cldfbAnaEnc[i] ), CLDFB_ANALYSIS, hEncoderConfig->input_Fs, CLDFB_PROTOTYPE_5_00MS, ENC ) ), IVAS_ERR_OK ) )
157 : {
158 0 : return error;
159 : }
160 : }
161 :
162 416 : ism_total_brate = 0;
163 416 : move32();
164 416 : test();
165 416 : test();
166 416 : test();
167 416 : test();
168 416 : IF( EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
169 : {
170 104 : FOR( i = 0; i < st_ivas->nSCE; i++ )
171 : {
172 67 : ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[i]->element_brate );
173 : }
174 : }
175 :
176 416 : ivas_masa_set_elements_fx( st_ivas->hEncoderConfig->ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &hEncoderConfig->element_mode_init, &st_ivas->nSCE, &st_ivas->nCPE, hEncoderConfig->ivas_format, st_ivas->ism_mode, ism_total_brate );
177 :
178 416 : Copy( DirAC_block_grouping, hMasa->config.block_grouping, MAX_PARAM_SPATIAL_SUBFRAMES + 1 );
179 416 : Copy( MASA_band_grouping_24, hMasa->config.band_grouping, MASA_FREQUENCY_BANDS + 1 );
180 :
181 416 : hMasa->data.onset_detector_1_fx = 0; // hMasa->data.q_onset_detector
182 416 : hMasa->data.onset_detector_2_fx = 0; // hMasa->data.q_onset_detector
183 416 : hMasa->data.q_onset_detector = 0;
184 416 : move32();
185 416 : move32();
186 416 : move16();
187 :
188 416 : set32_fx( hMasa->data.lfeToTotalEnergyRatio_fx, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); // hMasa->data.lfeToTotalEnergyRatio_e
189 416 : set16_fx( hMasa->data.lfeToTotalEnergyRatio_e, 0, MAX_PARAM_SPATIAL_SUBFRAMES );
190 416 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = 0; // Q31
191 416 : move32();
192 :
193 416 : hMasa->data.prevq_lfeIndex = 0;
194 416 : move16();
195 :
196 416 : hMasa->data.sync_state.prev_sim_stop = 0;
197 416 : hMasa->data.sync_state.prev_offset = 0;
198 416 : hMasa->data.sync_state.frame_mode = MASA_FRAME_4SF;
199 416 : move16();
200 416 : move16();
201 416 : move32();
202 :
203 416 : set_zero_fx( hMasa->data.dir_align_state.previous_azi_dir1_fx, MASA_FREQUENCY_BANDS ); // Q22
204 416 : set_zero_fx( hMasa->data.dir_align_state.previous_ele_dir1_fx, MASA_FREQUENCY_BANDS ); // Q22
205 416 : set_zero_fx( hMasa->data.dir_align_state.previous_azi_dir2_fx, MASA_FREQUENCY_BANDS ); // Q22
206 416 : set_zero_fx( hMasa->data.dir_align_state.previous_ele_dir2_fx, MASA_FREQUENCY_BANDS ); // Q22
207 :
208 416 : IF( EQ_32( hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) )
209 : {
210 : OMASA_ENCODER_DATA_HANDLE hOmasaData;
211 :
212 44 : IF( ( hOmasaData = (OMASA_ENCODER_DATA_HANDLE) malloc( sizeof( OMASA_ENCODER_DATA_STATE ) ) ) == NULL )
213 : {
214 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA data encoder\n" ) );
215 : }
216 :
217 220 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
218 : {
219 176 : set32_fx( hOmasaData->masa_to_total_energy_ratio_fx[i], 0, MASA_FREQUENCY_BANDS ); // Q30
220 : }
221 :
222 44 : hOmasaData->lp_noise_CPE_fx = -256; /* -1 in Q8 */
223 44 : move16();
224 44 : hOmasaData->omasa_stereo_sw_cnt = OMASA_STEREO_SW_CNT_MAX;
225 44 : move16();
226 :
227 44 : IF( NE_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) )
228 : {
229 27 : IF( ( hOmasaData->hOmasaEnergy = (OMASA_ENCODER_ENERGY_HANDLE) malloc( sizeof( OMASA_ENCODER_ENERGY_STATE ) ) ) == NULL )
230 : {
231 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for OMASA energy handle\n" ) );
232 : }
233 :
234 135 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
235 : {
236 108 : set_zero_fx( hOmasaData->hOmasaEnergy->energy_ism_fx[i], MASA_FREQUENCY_BANDS ); // hOmasaData->energy_ism_fx_e
237 108 : set16_fx( hOmasaData->hOmasaEnergy->energy_ism_fx_e[i], 0, MASA_FREQUENCY_BANDS );
238 : }
239 : }
240 : else
241 : {
242 17 : hOmasaData->hOmasaEnergy = NULL;
243 : }
244 :
245 44 : hMasa->data.hOmasaData = hOmasaData;
246 : }
247 : ELSE
248 : {
249 372 : hMasa->data.hOmasaData = NULL;
250 : }
251 :
252 416 : st_ivas->hMasa = hMasa;
253 :
254 416 : return error;
255 : }
256 :
257 :
258 : /*-----------------------------------------------------------------------*
259 : * ivas_masa_enc_close()
260 : *
261 : * close MASA encoder
262 : *-----------------------------------------------------------------------*/
263 :
264 1086 : void ivas_masa_enc_close_fx(
265 : MASA_ENCODER_HANDLE *hMasa /* i/o: MASA metadata structure */
266 : )
267 : {
268 : Word16 i;
269 :
270 1086 : test();
271 1086 : IF( hMasa == NULL || *hMasa == NULL )
272 : {
273 670 : return;
274 : }
275 :
276 623 : FOR( i = 0; i < ( *hMasa )->data.num_Cldfb_instances; i++ )
277 : {
278 207 : deleteCldfb_ivas_fx( &( ( *hMasa )->data.cldfbAnaEnc[i] ) );
279 : }
280 :
281 416 : IF( ( *hMasa )->data.hOmasaData != NULL )
282 : {
283 44 : IF( ( *hMasa )->data.hOmasaData->hOmasaEnergy != NULL )
284 : {
285 25 : free( ( *hMasa )->data.hOmasaData->hOmasaEnergy );
286 25 : ( *hMasa )->data.hOmasaData->hOmasaEnergy = NULL;
287 : }
288 :
289 44 : free( ( *hMasa )->data.hOmasaData );
290 44 : ( *hMasa )->data.hOmasaData = NULL;
291 : }
292 :
293 416 : free( ( *hMasa ) );
294 416 : ( *hMasa ) = NULL;
295 :
296 416 : return;
297 : }
298 :
299 :
300 : /*-----------------------------------------------------------------------*
301 : * ivas_masa_encode()
302 : *
303 : * main MASA encoder function
304 : *-----------------------------------------------------------------------*/
305 :
306 51306 : ivas_error ivas_masa_encode_fx(
307 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */
308 : IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */
309 : BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */
310 : Word16 *nb_bits_metadata, /* o : number of metadata bits written */
311 : const Word16 nchan_transport, /* i : number of MASA input/transport channels */
312 : const IVAS_FORMAT ivas_format, /* i : IVAS format */
313 : const Word32 ivas_total_brate, /* i : IVAS total bitrate */
314 : const Word16 Opt_DTX_ON, /* i : DTX on flag */
315 : const Word16 element_mode, /* i : element mode */
316 : const ISM_MODE ism_mode, /* i : ISM format mode */
317 : const Word16 nchan_ism, /* i : number of ISM channels */
318 : ISM_METADATA_HANDLE hIsmMetaData[MAX_NUM_OBJECTS], /* i : ISM metadata handle */
319 : const Word16 idx_separated_object, /* i : index of the separated object */
320 : OMASA_ENC_HANDLE hOMasa, /* i : OMASA encoder handle */
321 : const Word16 ism_imp, /* i : importance of separated object */
322 : const Word16 flag_omasa_ener_brate /* i : less bitrate for objects in OMASA flag */
323 : )
324 : {
325 : MASA_DIRECTIONAL_SPATIAL_META *h_orig_metadata;
326 : Word16 i, j, s;
327 : Word16 masa_sid_descriptor;
328 : Word16 low_bitrate_mode;
329 : Word32 masa_total_brate;
330 : ivas_error error;
331 : Word16 guard_bits, tmp;
332 :
333 51306 : guard_bits = find_guarded_bits_fx( 9 );
334 :
335 51306 : masa_sid_descriptor = -1;
336 51306 : h_orig_metadata = NULL;
337 51306 : low_bitrate_mode = 0;
338 51306 : move16();
339 51306 : move16();
340 :
341 51306 : test();
342 51306 : IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
343 : {
344 : /* Create the MASA SID descriptor for the metadata and CPE mode, in order to have the SID frame self-contained. */
345 39626 : IF( Opt_DTX_ON && hQMetaData != NULL )
346 : {
347 7028 : IF( EQ_16( nchan_transport, 2 ) ) /* this is MASA format in CPE only */
348 : {
349 4016 : masa_sid_descriptor = 0; /* for IVAS_CPE_DFT */
350 4016 : move16();
351 4016 : if ( EQ_16( element_mode, IVAS_CPE_MDCT ) )
352 : {
353 1648 : masa_sid_descriptor = 1;
354 1648 : move16();
355 : }
356 : }
357 : }
358 :
359 : /* Validate and compensate ratios as necessary */
360 39626 : compensate_energy_ratios_fx( hMasa );
361 :
362 39626 : IF( Opt_DTX_ON )
363 : {
364 7028 : IF( ( h_orig_metadata = (MASA_DIRECTIONAL_SPATIAL_META *) malloc( MASA_MAXIMUM_DIRECTIONS * sizeof( MASA_DIRECTIONAL_SPATIAL_META ) ) ) == NULL )
365 : {
366 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA encoder\n" ) );
367 : }
368 :
369 21084 : FOR( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
370 : {
371 70280 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
372 : {
373 56224 : Copy32( hMasa->masaMetadata.directional_meta[i].azimuth_fx[j], h_orig_metadata[i].azimuth_fx[j], MASA_FREQUENCY_BANDS ); // Q22
374 56224 : Copy32( hMasa->masaMetadata.directional_meta[i].elevation_fx[j], h_orig_metadata[i].elevation_fx[j], MASA_FREQUENCY_BANDS ); // Q22
375 56224 : Copy32( hMasa->masaMetadata.directional_meta[i].energy_ratio_fx[j], h_orig_metadata[i].energy_ratio_fx[j], MASA_FREQUENCY_BANDS ); // Q30
376 56224 : Copy( (Word16 *) ( hMasa->masaMetadata.directional_meta[i].spherical_index[j] ), (Word16 *) ( h_orig_metadata[i].spherical_index[j] ), MASA_FREQUENCY_BANDS );
377 : }
378 : }
379 : }
380 :
381 39626 : test();
382 39626 : test();
383 39626 : if ( ( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) && GE_32( ivas_total_brate, IVAS_384k ) )
384 : {
385 2636 : hMasa->config.mergeRatiosOverSubframes = 0;
386 2636 : move16();
387 : }
388 :
389 : /* Combine frequency bands and sub-frames */
390 39626 : combine_freqbands_and_subframes_fx( hMasa );
391 : }
392 :
393 : /* aligning the exponents of energy_fx */
394 51306 : s = 0;
395 51306 : move16();
396 256530 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
397 : {
398 205224 : maximum_s( hMasa->data.energy_e[i], MASA_FREQUENCY_BANDS, &tmp );
399 205224 : s = s_max( s, tmp );
400 : }
401 51306 : s = add( s, guard_bits );
402 256530 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
403 : {
404 5130600 : FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
405 : {
406 4925376 : hMasa->data.energy_fx[i][j] = L_shr( hMasa->data.energy_fx[i][j], sub( s, hMasa->data.energy_e[i][j] ) ); // hMasa->data.energy_e[i][j] -> s
407 4925376 : hMasa->data.energy_e[i][j] = s;
408 4925376 : move32();
409 4925376 : move16();
410 : }
411 : }
412 51306 : hMasa->data.q_energy = sub( 31, s );
413 51306 : move16();
414 :
415 51306 : test();
416 51306 : test();
417 51306 : test();
418 51306 : IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && LT_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) && ( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) )
419 : {
420 9520 : test();
421 9520 : test();
422 9520 : test();
423 9520 : IF( ( EQ_32( ivas_format, MASA_ISM_FORMAT ) && NE_32( ism_mode, ISM_MODE_NONE ) && NE_32( ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) || NE_32( ivas_format, MASA_ISM_FORMAT ) )
424 : {
425 : /* Combine directions */
426 7322 : ivas_masa_combine_directions_fx( hMasa );
427 : }
428 :
429 : /* If we joined all bands, then metadata is now one directional. */
430 9520 : IF( hMasa->config.numTwoDirBands == 0 )
431 : {
432 4064 : hMasa->config.numberOfDirections = 1;
433 4064 : hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
434 4064 : hQMetaData->no_directions = 1;
435 4064 : move16();
436 4064 : move16();
437 4064 : move16();
438 : }
439 : }
440 :
441 : /* Reset qmetadata bit budget */
442 51306 : hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits;
443 51306 : move16();
444 51306 : test();
445 51306 : IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
446 : {
447 39626 : test();
448 39626 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && NE_32( ism_mode, ISM_MODE_NONE ) )
449 : {
450 : /* write the number of objects in ISM_MASA format*/
451 7058 : push_next_indice( hMetaData, sub( nchan_ism, 1 ), NO_BITS_MASA_ISM_NO_OBJ );
452 7058 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, NO_BITS_MASA_ISM_NO_OBJ );
453 7058 : move16();
454 :
455 : /* write index of separated object if needed */
456 7058 : test();
457 7058 : IF( EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) && GT_16( nchan_ism, 1 ) )
458 : {
459 1862 : push_next_indice( hMetaData, idx_separated_object, NO_BITS_MASA_ISM_NO_OBJ );
460 1862 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, NO_BITS_MASA_ISM_NO_OBJ );
461 1862 : move16();
462 : }
463 :
464 : /* write ISM importance flag (one per object) */
465 7058 : IF( EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
466 : {
467 1862 : push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
468 1862 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
469 1862 : move16();
470 : }
471 5196 : ELSE IF( EQ_32( ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) )
472 : {
473 2054 : IF( hIsmMetaData[0]->ism_md_null_flag )
474 : {
475 : /* signal NULL metadata frame */
476 0 : push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
477 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
478 0 : move16();
479 :
480 : /* write the ISM class to ISM_NO_META and again the true ISM class */
481 0 : push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
482 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
483 0 : move16();
484 0 : push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
485 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
486 0 : move16();
487 : }
488 : ELSE
489 : {
490 2054 : push_next_indice( hMetaData, hIsmMetaData[0]->ism_imp, ISM_METADATA_FLAG_BITS );
491 2054 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
492 2054 : move16();
493 :
494 2054 : IF( EQ_16( hIsmMetaData[0]->ism_imp, ISM_NO_META ) )
495 : {
496 : /* signal low-rate ISM_NO_META frame */
497 0 : push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
498 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
499 0 : move16();
500 :
501 : /* signal presence of MD in low-rate ISM_NO_META frame */
502 0 : push_next_indice( hMetaData, hIsmMetaData[0]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
503 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_INACTIVE_FLAG_BITS );
504 0 : move16();
505 : }
506 : }
507 : }
508 3142 : ELSE IF( EQ_32( ism_mode, ISM_MASA_MODE_DISC ) )
509 : {
510 11602 : FOR( i = 0; i < nchan_ism; i++ )
511 : {
512 8460 : IF( hIsmMetaData[i]->ism_md_null_flag )
513 : {
514 : /* signal NULL metadata frame */
515 0 : push_next_indice( hMetaData, 1, ISM_METADATA_MD_FLAG_BITS );
516 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
517 0 : move16();
518 :
519 : /* write the ISM class to ISM_NO_META and again the true ISM class */
520 0 : push_next_indice( hMetaData, ISM_NO_META, ISM_METADATA_FLAG_BITS );
521 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
522 0 : move16();
523 0 : push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
524 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
525 0 : move16();
526 : }
527 : ELSE
528 : {
529 8460 : push_next_indice( hMetaData, hIsmMetaData[i]->ism_imp, ISM_METADATA_FLAG_BITS );
530 8460 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_FLAG_BITS );
531 8460 : move16();
532 :
533 8460 : IF( EQ_16( hIsmMetaData[i]->ism_imp, ISM_NO_META ) )
534 : {
535 : /* signal low-rate ISM_NO_META frame */
536 0 : push_next_indice( hMetaData, 0, ISM_METADATA_MD_FLAG_BITS );
537 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_MD_FLAG_BITS );
538 0 : move16();
539 :
540 : /* signal presence of MD in low-rate ISM_NO_META frame */
541 0 : push_next_indice( hMetaData, hIsmMetaData[i]->ism_md_lowrate_flag, ISM_METADATA_INACTIVE_FLAG_BITS );
542 0 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, ISM_METADATA_INACTIVE_FLAG_BITS );
543 0 : move16();
544 : }
545 : }
546 : }
547 3142 : test();
548 3142 : IF( EQ_32( ivas_total_brate, IVAS_128k ) && GE_16( nchan_ism, 3 ) )
549 : {
550 126 : push_next_indice( hMetaData, flag_omasa_ener_brate, 1 );
551 126 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, 1 );
552 126 : move16();
553 : }
554 : }
555 : }
556 : ELSE
557 : {
558 32568 : test();
559 32568 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) )
560 : {
561 : /* use the MASA number of transport channels bit to signal if there are 1 or 2 objects */
562 1942 : test();
563 1942 : IF( EQ_16( nchan_ism, 1 ) || EQ_16( nchan_ism, 2 ) )
564 : {
565 474 : push_next_indice( hMetaData, sub( nchan_ism, 1 ), MASA_TRANSP_BITS );
566 : }
567 : ELSE
568 : {
569 : /* for 3 or 4 objects write already the number of MASA directions */
570 1468 : push_next_indice( hMetaData, sub( hQMetaData->no_directions, 1 ), MASA_TRANSP_BITS );
571 : }
572 : }
573 : ELSE
574 : {
575 : /* write the number of MASA transport channels */
576 30626 : push_next_indice( hMetaData, sub( nchan_transport, 1 ), MASA_TRANSP_BITS );
577 : }
578 32568 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_TRANSP_BITS );
579 32568 : move16();
580 : }
581 :
582 39626 : test();
583 39626 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) )
584 : {
585 1942 : IF( GE_16( nchan_ism, 3 ) ) /* if 3 or 4 objects */
586 : {
587 1468 : push_next_indice( hMetaData, sub( 5, nchan_ism ), MASA_HEADER_BITS );
588 : }
589 : ELSE
590 : {
591 474 : push_next_indice( hMetaData, 3, MASA_HEADER_BITS );
592 : }
593 1942 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS );
594 1942 : move16();
595 : }
596 : ELSE
597 : {
598 : /* the MASA_ISM_FORMAT is not signalled here */
599 : /* write reserved bits */
600 37684 : push_next_indice( hMetaData, 0, MASA_HEADER_BITS );
601 37684 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS );
602 37684 : move16();
603 : }
604 39626 : test();
605 39626 : test();
606 39626 : test();
607 39626 : IF( !( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) && GT_16( nchan_ism, 2 ) ) )
608 : {
609 : /* write number of directions */
610 38158 : push_next_indice( hMetaData, sub( hQMetaData->no_directions, 1 ), 1 );
611 38158 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, 1 );
612 38158 : move16();
613 : }
614 :
615 : /* write subframe mode */
616 39626 : IF( EQ_16( hQMetaData->q_direction[0].cfg.nblocks, 1 ) )
617 : {
618 5550 : push_next_indice( hMetaData, 1, MASA_SUBFRAME_BITS );
619 : }
620 : ELSE
621 : {
622 34076 : push_next_indice( hMetaData, 0, MASA_SUBFRAME_BITS );
623 : }
624 39626 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_SUBFRAME_BITS );
625 39626 : move16();
626 : }
627 :
628 :
629 51306 : IF( EQ_32( ivas_format, MC_FORMAT ) )
630 : {
631 : Word16 lfeBitsWritten;
632 :
633 11680 : lfeBitsWritten = encode_lfe_to_total_energy_ratio_fx( hMasa, hMetaData, ivas_total_brate );
634 :
635 11680 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, lfeBitsWritten );
636 11680 : move16();
637 : }
638 :
639 : /* Move data from encoder to qmetadata */
640 51306 : test();
641 51306 : IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) )
642 : {
643 39626 : move_metadata_to_qmetadata_fx( hMasa, hQMetaData );
644 : }
645 :
646 51306 : test();
647 51306 : IF( LT_16( hMasa->config.max_metadata_bits, MINIMUM_BIT_BUDGET_NORMAL_META ) && !hMasa->config.joinedSubframes )
648 : {
649 25011 : reduce_metadata_further_fx( hMasa, hQMetaData, ivas_format );
650 :
651 25011 : low_bitrate_mode = (Word16) LE_32( ivas_total_brate, 32000 );
652 :
653 : /* Write low bitrate mode. 1 signals that we have merged through time, 0 signals merge through frequency. */
654 25011 : IF( EQ_16( hQMetaData->q_direction[0].cfg.nblocks, 1 ) )
655 : {
656 21010 : push_next_indice( hMetaData, 1, MASA_LOWBITRATE_MODE_BITS );
657 : }
658 : ELSE
659 : {
660 4001 : push_next_indice( hMetaData, 0, MASA_LOWBITRATE_MODE_BITS );
661 : }
662 25011 : hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_LOWBITRATE_MODE_BITS );
663 25011 : move16();
664 : }
665 :
666 : /* Encode MASA+ISM metadata */
667 51306 : test();
668 51306 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
669 : {
670 : /* encode MASA/ISM energy ratios */
671 1862 : ivas_encode_masaism_metadata_fx( hMasa, hQMetaData, hMetaData, hIsmMetaData, nchan_ism, low_bitrate_mode, hOMasa->nCodingBands, hOMasa->nSubframes, idx_separated_object, ism_imp );
672 : }
673 : ELSE
674 : {
675 49444 : if ( EQ_32( ivas_format, MASA_ISM_FORMAT ) )
676 : {
677 7138 : hMasa->data.hOmasaData->masa_to_total_energy_ratio_fx[0][0] = -ONE_IN_Q30; /* signals NOT to adjust the energy ratios */
678 7138 : move32();
679 : }
680 : }
681 :
682 : /* Encode metadata */
683 51306 : masa_total_brate = ivas_total_brate;
684 51306 : move32();
685 51306 : test();
686 51306 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_DISC ) )
687 : {
688 3142 : masa_total_brate = calculate_cpe_brate_MASA_ISM_fx( ism_mode, ivas_total_brate, nchan_ism );
689 : }
690 :
691 51306 : IF( GE_32( masa_total_brate, IVAS_384k ) )
692 : {
693 2276 : IF( GE_32( masa_total_brate, IVAS_512k ) )
694 : {
695 800 : IF( NE_32( ( error = ivas_qmetadata_enc_encode_hr_384_512_fx( hMetaData, hQMetaData, 16, 4 ) ), IVAS_ERR_OK ) )
696 : {
697 0 : return error;
698 : }
699 : }
700 : ELSE
701 : {
702 1476 : IF( NE_32( ( error = ivas_qmetadata_enc_encode_hr_384_512_fx( hMetaData, hQMetaData, 11, 3 ) ), IVAS_ERR_OK ) )
703 : {
704 0 : return error;
705 : }
706 : }
707 : }
708 : ELSE
709 : {
710 49030 : IF( NE_32( ( error = ivas_qmetadata_enc_encode_fx( hMetaData, hQMetaData, 0 ) ), IVAS_ERR_OK ) )
711 : {
712 0 : return error;
713 : }
714 : }
715 :
716 51306 : test();
717 51306 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
718 : {
719 : /* Modify spatial metadata based on the MASA-to-total energy ratios */
720 1862 : ivas_omasa_modify_masa_energy_ratios_fx( hQMetaData, hMasa->data.hOmasaData->masa_to_total_energy_ratio_fx );
721 : }
722 :
723 51306 : *nb_bits_metadata = hMetaData->nb_bits_tot;
724 51306 : move16();
725 :
726 51306 : test();
727 51306 : IF( EQ_32( ivas_format, MASA_FORMAT ) && Opt_DTX_ON )
728 : {
729 : /* save old values */
730 7028 : UWord8 numCodingBands = hMasa->config.numCodingBands;
731 7028 : UWord8 numTwoDirBands = hMasa->config.numTwoDirBands;
732 7028 : Word16 nbands = hQMetaData->q_direction[0].cfg.nbands;
733 7028 : UWord8 numberOfDirections = hMasa->config.numberOfDirections;
734 7028 : UWord8 numberOfDirectionsMeta = hMasa->masaMetadata.descriptive_meta.numberOfDirections;
735 7028 : UWord16 numberOfDirectionsQMetaData = hQMetaData->no_directions;
736 7028 : move16();
737 7028 : move16();
738 7028 : move16();
739 7028 : move16();
740 7028 : move16();
741 7028 : move16();
742 :
743 7028 : test();
744 7028 : IF( !( EQ_16( hMasa->config.numberOfDirections, 1 ) && EQ_16( hQMetaData->q_direction->cfg.nbands, 5 ) ) )
745 : {
746 5937 : FOR( i = 0; i < MASA_MAXIMUM_DIRECTIONS; i++ )
747 : {
748 19790 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
749 : {
750 15832 : Copy32( h_orig_metadata[i].azimuth_fx[j], hMasa->masaMetadata.directional_meta[i].azimuth_fx[j], MASA_FREQUENCY_BANDS ); // Q22
751 15832 : Copy32( h_orig_metadata[i].elevation_fx[j], hMasa->masaMetadata.directional_meta[i].elevation_fx[j], MASA_FREQUENCY_BANDS ); // Q22
752 15832 : Copy32( h_orig_metadata[i].energy_ratio_fx[j], hMasa->masaMetadata.directional_meta[i].energy_ratio_fx[j], MASA_FREQUENCY_BANDS ); // Q30
753 : }
754 : }
755 :
756 : /* Force to have 5 bands and 1 direction */
757 1979 : hMasa->config.numCodingBands = 5;
758 1979 : hMasa->config.numTwoDirBands = 0;
759 1979 : move16();
760 1979 : move16();
761 :
762 1979 : combine_freqbands_and_subframes_fx( hMasa );
763 :
764 1979 : hQMetaData->q_direction[0].cfg.nbands = 5;
765 1979 : move16();
766 :
767 1979 : test();
768 1979 : IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && LT_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
769 : {
770 : /* Combine directions */
771 0 : ivas_masa_combine_directions_fx( hMasa );
772 :
773 : /* If we joined all bands, then metadata is now one directional. */
774 0 : IF( hMasa->config.numTwoDirBands == 0 )
775 : {
776 0 : hMasa->config.numberOfDirections = 1;
777 0 : hMasa->masaMetadata.descriptive_meta.numberOfDirections = 0;
778 0 : hQMetaData->no_directions = 1;
779 0 : move16();
780 0 : move16();
781 0 : move16();
782 : }
783 : }
784 :
785 1979 : move_metadata_to_qmetadata_fx( hMasa, hQMetaData );
786 :
787 11874 : FOR( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j )
788 : {
789 9895 : hQMetaData->q_direction[0].band_data[j].energy_ratio_index[0] = masa_sq_fx( L_sub( ONE_IN_Q30, hQMetaData->q_direction[0].band_data[j].energy_ratio_fx[0] ), diffuseness_thresholds_fx, DIRAC_DIFFUSE_LEVELS );
790 9895 : move32();
791 : }
792 : }
793 :
794 7028 : free( h_orig_metadata );
795 :
796 7028 : ivas_qmetadata_enc_sid_encode_fx( hMetaData, hQMetaData, masa_sid_descriptor, 0, ivas_format );
797 :
798 : /* restore old values */
799 7028 : hMasa->config.numCodingBands = numCodingBands;
800 7028 : hMasa->config.numTwoDirBands = numTwoDirBands;
801 7028 : hQMetaData->q_direction[0].cfg.nbands = nbands;
802 7028 : hMasa->config.numberOfDirections = numberOfDirections;
803 7028 : hMasa->masaMetadata.descriptive_meta.numberOfDirections = numberOfDirectionsMeta;
804 7028 : hQMetaData->no_directions = numberOfDirectionsQMetaData;
805 7028 : move16();
806 7028 : move16();
807 7028 : move16();
808 7028 : move16();
809 7028 : move16();
810 7028 : move16();
811 : }
812 :
813 51306 : return IVAS_ERR_OK;
814 : }
815 :
816 :
817 : /*-----------------------------------------------------------------------*
818 : * ivas_masa_estimate_energy_fx()
819 : *
820 : *
821 : *-----------------------------------------------------------------------*/
822 :
823 39626 : void ivas_masa_estimate_energy_fx(
824 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */
825 : Word32 *data_fx[], /* i : Input audio channels Q(q_data) */
826 : const Word16 input_frame, /* i : frame length */
827 : const Word16 nchan_transport, /* i : number of MASA input/transport channels */
828 : Word16 q_data /* i : q for data_fx */
829 : )
830 : {
831 : Word32 Input_RealBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
832 : Word32 Input_ImagBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
833 : Word16 block_m_idx, band_m_idx;
834 : Word16 mrange[2], brange[2];
835 : Word16 i, j, ts, l_ts, maxBin;
836 : Word64 energy_fx_temp[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
837 39626 : Word16 scale = 63;
838 39626 : move16();
839 : Word16 q_buf;
840 39626 : maxBin = extract_l( Mpy_32_32( 134217728 /*CLDFB_NO_CHANNELS_MAX / L_FRAME48k in Q31*/, input_frame ) );
841 39626 : l_ts = shr( input_frame, CLDFB_NO_COL_MAX_LOG2 );
842 :
843 198130 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
844 : {
845 3962600 : FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
846 : {
847 3804096 : energy_fx_temp[i][j] = 0;
848 3804096 : move64();
849 : }
850 : }
851 :
852 198130 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
853 : {
854 158504 : mrange[0] = hMasa->config.block_grouping[block_m_idx];
855 158504 : move16();
856 158504 : mrange[1] = hMasa->config.block_grouping[block_m_idx + 1];
857 158504 : move16();
858 158504 : set_zero_fx( hMasa->data.energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
859 158504 : set16_fx( hMasa->data.energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
860 :
861 792520 : FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
862 : {
863 1676608 : FOR( i = 0; i < nchan_transport; i++ )
864 : {
865 1042592 : q_buf = q_data;
866 1042592 : move16();
867 1042592 : scale_sig32( hMasa->data.cldfbAnaEnc[i]->cldfb_state_fx, hMasa->data.cldfbAnaEnc[i]->cldfb_state_length, sub( q_buf, hMasa->data.cldfbAnaEnc[i]->Q_cldfb_state ) );
868 1042592 : hMasa->data.cldfbAnaEnc[i]->Q_cldfb_state = q_buf;
869 1042592 : move16();
870 1042592 : cldfbAnalysis_ts_fx_fixed_q( &( data_fx[i][l_ts * ts] ), Input_RealBuffer[i], Input_ImagBuffer[i], l_ts, hMasa->data.cldfbAnaEnc[i], &q_buf ); // (q_data - 5) for Input_RealBuffer[i], Input_ImagBuffer[i]
871 : }
872 :
873 15850400 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
874 : {
875 15216384 : brange[0] = hMasa->config.band_grouping[band_m_idx];
876 15216384 : move16();
877 15216384 : brange[1] = hMasa->config.band_grouping[band_m_idx + 1];
878 15216384 : move16();
879 :
880 40238592 : FOR( i = 0; i < nchan_transport; i++ )
881 : {
882 25022208 : IF( GT_16( brange[0], maxBin ) )
883 : {
884 72000 : hMasa->data.energy_fx[block_m_idx][band_m_idx] = 0;
885 72000 : move32();
886 72000 : CONTINUE;
887 : }
888 24950208 : ELSE IF( GE_16( brange[1], maxBin ) )
889 : {
890 1116992 : brange[1] = maxBin;
891 1116992 : move16();
892 : }
893 :
894 85537728 : FOR( j = brange[0]; j < brange[1]; j++ )
895 : {
896 60587520 : energy_fx_temp[block_m_idx][band_m_idx] = W_add( energy_fx_temp[block_m_idx][band_m_idx], W_mac_32_32( W_mult_32_32( Input_RealBuffer[i][j], Input_RealBuffer[i][j] ), Input_ImagBuffer[i][j], Input_ImagBuffer[i][j] ) ); // Q: 2 * (q_data - 5) + 1 for energy_fx_temp
897 60587520 : move64();
898 : }
899 24950208 : IF( energy_fx_temp[block_m_idx][band_m_idx] != 0 )
900 : {
901 24875808 : scale = s_min( scale, W_norm( energy_fx_temp[block_m_idx][band_m_idx] ) ); // scale calculates minimum shift can be done across a buffer
902 : }
903 : }
904 : }
905 : }
906 : }
907 :
908 198130 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
909 : {
910 3962600 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
911 : {
912 3804096 : energy_fx_temp[block_m_idx][band_m_idx] = W_shl( energy_fx_temp[block_m_idx][band_m_idx], scale ); // Q: 2 * (q_data - 5) + 1 + scale
913 3804096 : move64();
914 3804096 : hMasa->data.energy_fx[block_m_idx][band_m_idx] = W_extract_h( energy_fx_temp[block_m_idx][band_m_idx] ); // Q: 2 * (q_data - 5) + 1 + scale - 32
915 3804096 : move32();
916 3804096 : hMasa->data.energy_e[block_m_idx][band_m_idx] = sub( 31, add( add( imult1616( 2, q_data ), scale ), 1 - 10 - 32 ) );
917 3804096 : move16();
918 : }
919 : }
920 39626 : hMasa->data.q_energy = add( add( imult1616( 2, q_data ), scale ), 1 - 10 - 32 );
921 39626 : move16();
922 :
923 39626 : return;
924 : }
925 :
926 :
927 : /*-----------------------------------------------------------------------*
928 : * ivas_masa_enc_config()
929 : *
930 : * Frame-by-frame configuration of MASA encoder
931 : *-----------------------------------------------------------------------*/
932 :
933 39923 : ivas_error ivas_masa_enc_config_fx(
934 : Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
935 : )
936 : {
937 : Word16 i;
938 : MASA_ENCODER_HANDLE hMasa;
939 : IVAS_QMETADATA_HANDLE hQMetaData;
940 : IVAS_FORMAT ivas_format;
941 : UWord8 joinedSubframes;
942 : UWord8 coherencePresent;
943 : UWord8 isActualTwoDir; /* Flag to tell that when there are two directions present in metadata, they both contain meaningful information. */
944 : Word32 ivas_total_brate;
945 : UWord8 maxBand;
946 : Word16 maxBin, sf;
947 : ivas_error error;
948 : Word32 ism_total_brate;
949 : Word32 masa_total_brate;
950 :
951 39923 : error = IVAS_ERR_OK;
952 39923 : move16();
953 :
954 39923 : hMasa = st_ivas->hMasa;
955 39923 : hQMetaData = st_ivas->hQMetaData;
956 39923 : ivas_format = st_ivas->hEncoderConfig->ivas_format;
957 39923 : ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
958 39923 : move16();
959 39923 : move32();
960 :
961 39923 : ism_total_brate = 0;
962 39923 : move32();
963 39923 : test();
964 39923 : test();
965 39923 : test();
966 39923 : test();
967 39923 : IF( EQ_16( ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
968 : {
969 19434 : FOR( i = 0; i < st_ivas->nSCE; i++ )
970 : {
971 12376 : ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[i]->element_brate );
972 : }
973 : }
974 :
975 39923 : ivas_masa_set_elements_fx( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, hQMetaData, &st_ivas->hEncoderConfig->element_mode_init, &st_ivas->nSCE, &st_ivas->nCPE, ivas_format, st_ivas->ism_mode, ism_total_brate );
976 :
977 39923 : hQMetaData->is_masa_ivas_format = 1;
978 39923 : move16();
979 :
980 39923 : test();
981 39923 : test();
982 39923 : IF( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) )
983 : {
984 39626 : masa_metadata_direction_alignment_fx( hMasa );
985 :
986 39626 : detect_framing_async_fx( hMasa ); /* detect the offset, set 1sf/4sf mode based on this. potentially also shift the metadata using a history buffer */
987 39626 : test();
988 39626 : IF( EQ_16( hMasa->data.sync_state.frame_mode, MASA_FRAME_1SF ) && hMasa->data.sync_state.prev_offset != 0 )
989 : {
990 : /* average over sub-frames */
991 0 : IF( EQ_32( ivas_total_brate, IVAS_512k ) )
992 : {
993 0 : average_masa_metadata_fx( &( hMasa->masaMetadata ), hMasa->data.energy_fx, hMasa->data.energy_e, &( hMasa->data.Sph_Grid16 ), TRUE );
994 : }
995 : ELSE
996 : {
997 0 : average_masa_metadata_fx( &( hMasa->masaMetadata ), hMasa->data.energy_fx, hMasa->data.energy_e, &( hMasa->data.Sph_Grid16 ), FALSE );
998 : }
999 : }
1000 :
1001 : /* Inspect metadata for parameter changes that affect coding. */
1002 39626 : detect_metadata_composition_fx( hMasa, &joinedSubframes, &coherencePresent, &isActualTwoDir );
1003 :
1004 39626 : hMasa->config.joinedSubframes = joinedSubframes;
1005 39626 : hMasa->config.coherencePresent = coherencePresent;
1006 39626 : move16();
1007 39626 : move16();
1008 39626 : test();
1009 39626 : IF( EQ_16( add( hMasa->masaMetadata.descriptive_meta.numberOfDirections, 1 ), 2 ) && isActualTwoDir )
1010 : {
1011 9900 : hMasa->config.numberOfDirections = 2;
1012 : }
1013 : ELSE
1014 : {
1015 29726 : hMasa->config.numberOfDirections = 1;
1016 : }
1017 39626 : move16();
1018 : }
1019 297 : ELSE IF( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( st_ivas->mc_mode, MC_MODE_MCMASA ) )
1020 : {
1021 : /* For McMASA, these are set only once as this function is called only once. */
1022 297 : hMasa->config.joinedSubframes = 0;
1023 297 : hMasa->config.numberOfDirections = 1;
1024 297 : move16();
1025 297 : move16();
1026 : }
1027 :
1028 39923 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) )
1029 : {
1030 9000 : ivas_masa_set_coding_config_fx( &( hMasa->config ), hMasa->data.band_mapping, st_ivas->hCPE[0]->element_brate, st_ivas->nchan_transport, MC_MODE_NONE );
1031 : }
1032 : ELSE
1033 : {
1034 30923 : test();
1035 30923 : ivas_masa_set_coding_config_fx( &( hMasa->config ), hMasa->data.band_mapping, ivas_total_brate, st_ivas->nchan_transport, ( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( st_ivas->mc_mode, MC_MODE_MCMASA ) ) );
1036 : }
1037 :
1038 : /* Setup importance weights for two-direction band selection. */
1039 39923 : IF( EQ_16( hMasa->config.numberOfDirections, 2 ) )
1040 : {
1041 9900 : set32_fx( hMasa->data.importanceWeight_fx, ONE_IN_Q30 /*1.0f Q30*/, MASA_FREQUENCY_BANDS );
1042 :
1043 9900 : IF( EQ_16( hMasa->config.numCodingBands, 5 ) )
1044 : {
1045 6670 : hMasa->data.importanceWeight_fx[4] = 751619277 /*0.7f q30*/;
1046 6670 : move32();
1047 : }
1048 3230 : ELSE IF( EQ_16( hMasa->config.numCodingBands, 8 ) )
1049 : {
1050 354 : hMasa->data.importanceWeight_fx[7] = 751619277 /*0.7f q30*/;
1051 354 : move32();
1052 : }
1053 2876 : ELSE IF( EQ_16( hMasa->config.numCodingBands, 10 ) )
1054 : {
1055 0 : hMasa->data.importanceWeight_fx[8] = 751619277 /*0.7f q30*/;
1056 0 : hMasa->data.importanceWeight_fx[9] = 107374182 /*0.1f q30*/;
1057 0 : move32();
1058 0 : move32();
1059 : }
1060 2876 : ELSE IF( EQ_16( hMasa->config.numCodingBands, 12 ) )
1061 : {
1062 794 : hMasa->data.importanceWeight_fx[10] = 751619277 /*0.7f q30*/;
1063 794 : hMasa->data.importanceWeight_fx[11] = 107374182 /*0.1f q30*/;
1064 794 : move32();
1065 794 : move32();
1066 : }
1067 2082 : ELSE IF( EQ_16( hMasa->config.numCodingBands, 18 ) )
1068 : {
1069 798 : hMasa->data.importanceWeight_fx[14] = 858993459 /*0.8f q30*/;
1070 798 : hMasa->data.importanceWeight_fx[15] = 536870912 /*0.5f q30*/;
1071 798 : hMasa->data.importanceWeight_fx[16] = 214748365 /*0.2f q30*/;
1072 798 : hMasa->data.importanceWeight_fx[17] = 0 /*0 q30*/;
1073 798 : move32();
1074 798 : move32();
1075 798 : move32();
1076 798 : move32();
1077 : }
1078 1284 : ELSE IF( EQ_16( hMasa->config.numCodingBands, 24 ) )
1079 : {
1080 1284 : hMasa->data.importanceWeight_fx[20] = 858993459 /*0.8f q30*/;
1081 1284 : hMasa->data.importanceWeight_fx[21] = 536870912 /*0.5f q30*/;
1082 1284 : hMasa->data.importanceWeight_fx[22] = 214748365 /*0.2f q30*/;
1083 1284 : hMasa->data.importanceWeight_fx[23] = 0 /*0 q30*/;
1084 1284 : move32();
1085 1284 : move32();
1086 1284 : move32();
1087 1284 : move32();
1088 : }
1089 :
1090 9900 : IF( EQ_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
1091 : {
1092 380 : set8_fx( (Word8 *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
1093 : }
1094 : }
1095 : ELSE
1096 : {
1097 30023 : set8_fx( (Word8 *) hMasa->data.twoDirBands, 0, hMasa->config.numCodingBands );
1098 : }
1099 :
1100 : /* Set qmeta to correct values */
1101 39923 : test();
1102 39923 : IF( EQ_16( hMasa->config.numberOfDirections, 2 ) && hMasa->config.numTwoDirBands != 0 )
1103 : {
1104 5836 : IF( NE_32( ( error = ivas_qmetadata_allocate_memory_fx( hQMetaData, hMasa->config.numCodingBands, 2, hMasa->config.useCoherence ) ), IVAS_ERR_OK ) )
1105 : {
1106 0 : return error;
1107 : }
1108 : }
1109 : ELSE
1110 : {
1111 34087 : IF( NE_32( ( error = ivas_qmetadata_allocate_memory_fx( hQMetaData, hMasa->config.numCodingBands, 1, hMasa->config.useCoherence ) ), IVAS_ERR_OK ) )
1112 : {
1113 0 : return error;
1114 : }
1115 : }
1116 :
1117 85682 : FOR( i = 0; i < hQMetaData->no_directions; i++ )
1118 : {
1119 45759 : hQMetaData->q_direction[i].cfg.nbands = hMasa->config.numCodingBands;
1120 45759 : move16();
1121 45759 : IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
1122 : {
1123 6546 : hQMetaData->q_direction[i].cfg.nblocks = 1;
1124 : }
1125 : ELSE
1126 : {
1127 39213 : hQMetaData->q_direction[i].cfg.nblocks = MAX_PARAM_SPATIAL_SUBFRAMES;
1128 : }
1129 45759 : move16();
1130 :
1131 45759 : IF( EQ_16( ivas_format, MC_FORMAT ) )
1132 : {
1133 297 : hQMetaData->q_direction[i].cfg.mc_ls_setup = st_ivas->hEncoderConfig->mc_input_setup;
1134 297 : move16();
1135 : }
1136 : ELSE
1137 : {
1138 : /* Just to be sure that this default value is maintained */
1139 45462 : hQMetaData->q_direction[i].cfg.mc_ls_setup = MC_LS_SETUP_INVALID;
1140 45462 : move16();
1141 : }
1142 : }
1143 :
1144 39923 : hQMetaData->all_coherence_zero = !hMasa->config.coherencePresent;
1145 39923 : move16();
1146 :
1147 39923 : ivas_set_qmetadata_maxbit_req_fx( hQMetaData, ivas_format );
1148 :
1149 : /* Find maximum band usable */
1150 39923 : maxBin = extract_l( Mpy_32_32( st_ivas->hEncoderConfig->input_Fs /*q0*/, INV_CLDFB_BANDWIDTH_Q31 /*Q31*/ ) ); /*q0+q31-q31->q0*/
1151 39923 : maxBand = 0;
1152 39923 : move16();
1153 39923 : test();
1154 1033308 : WHILE( ( maxBand <= MASA_FREQUENCY_BANDS ) && ( MASA_band_grouping_24[maxBand] <= maxBin ) )
1155 : {
1156 993385 : test();
1157 993385 : maxBand = (UWord8) add( maxBand, 1 );
1158 993385 : move16(); /*because typecasting word16 to uword8*/
1159 : }
1160 39923 : maxBand = (UWord8) sub( maxBand, 1 );
1161 39923 : move16(); /*because typecasting word16 to uword8*/
1162 :
1163 39923 : st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
1164 39923 : masa_total_brate = ivas_total_brate;
1165 39923 : move16();
1166 39923 : move32();
1167 39923 : test();
1168 39923 : IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) )
1169 : {
1170 3142 : masa_total_brate = calculate_cpe_brate_MASA_ISM_fx( st_ivas->ism_mode, ivas_total_brate, st_ivas->hEncoderConfig->nchan_ism ); /*q0*/
1171 : }
1172 39923 : test();
1173 39923 : test();
1174 39923 : IF( GE_32( masa_total_brate, IVAS_384k ) && ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) )
1175 : {
1176 : Word16 continueLoop;
1177 2276 : continueLoop = 1;
1178 2276 : move16();
1179 2276 : test();
1180 4552 : WHILE( ( maxBand > 5 ) && continueLoop )
1181 : {
1182 2276 : test();
1183 2276 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
1184 : {
1185 2276 : IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( hMasa->data.energy_fx[sf][maxBand - 1], hMasa->data.energy_e[sf][maxBand - 1], 100000 /*q0*/, 31 ), 1 ) )
1186 : {
1187 2276 : continueLoop = 0;
1188 2276 : move16();
1189 2276 : BREAK;
1190 : }
1191 : }
1192 2276 : IF( continueLoop )
1193 : {
1194 0 : maxBand = (UWord8) sub( maxBand, 1 );
1195 0 : move16(); /*because typecasting word16 to uword8*/
1196 : }
1197 : }
1198 :
1199 2276 : IF( LT_16( maxBand, MASA_MAXIMUM_CODING_SUBBANDS ) )
1200 : {
1201 300 : st_ivas->hQMetaData->q_direction->cfg.inactiveBands = (UWord8) sub( MASA_MAXIMUM_CODING_SUBBANDS, maxBand );
1202 300 : move16(); /*because typecasting word16 to uword8*/
1203 : }
1204 : ELSE
1205 : {
1206 1976 : st_ivas->hQMetaData->q_direction->cfg.inactiveBands = 0;
1207 1976 : move16();
1208 : }
1209 : }
1210 :
1211 39923 : masa_sample_rate_band_correction_fx( &( hMasa->config ), hMasa->data.band_mapping, hQMetaData, maxBand, (UWord8) GE_32( masa_total_brate, IVAS_384k ), NULL );
1212 :
1213 39923 : IF( GE_16( hMasa->config.numTwoDirBands, hMasa->config.numCodingBands ) )
1214 : {
1215 380 : hMasa->config.numTwoDirBands = hMasa->config.numCodingBands;
1216 380 : move16();
1217 380 : set8_fx( (Word8 *) hMasa->data.twoDirBands, 1, hMasa->config.numCodingBands );
1218 : }
1219 :
1220 39923 : test();
1221 39923 : test();
1222 39923 : test();
1223 39923 : test();
1224 : /* Transmit stereo signals using a mono downmix at lowest bitrates */
1225 39923 : IF( ( EQ_16( ivas_format, MASA_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) ) && EQ_16( st_ivas->nCPE, 1 ) && st_ivas->hCPE[0]->hStereoDft != NULL && st_ivas->hCPE[0]->hStereoDft->hConfig != NULL )
1226 : {
1227 11938 : IF( LT_32( L_sub( ivas_total_brate, ism_total_brate ), MASA_STEREO_MIN_BITRATE ) )
1228 : {
1229 5484 : st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = 1;
1230 : }
1231 : ELSE
1232 : {
1233 6454 : st_ivas->hCPE[0]->hStereoDft->hConfig->force_mono_transmission = 0;
1234 : }
1235 11938 : move16();
1236 : }
1237 :
1238 39923 : test();
1239 39923 : test();
1240 39923 : test();
1241 39923 : IF( EQ_16( ivas_format, MASA_ISM_FORMAT ) && ( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) )
1242 : {
1243 7058 : test();
1244 7058 : IF( EQ_16( st_ivas->hCPE[0]->element_mode, IVAS_CPE_DFT ) || LT_16( st_ivas->hMasa->data.hOmasaData->omasa_stereo_sw_cnt, OMASA_STEREO_SW_CNT_MAX ) )
1245 : {
1246 3051 : st_ivas->hMasa->data.hOmasaData->lp_noise_CPE_fx = extract_h( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_32fx ); /*Q8*/
1247 : }
1248 : ELSE
1249 : {
1250 : /* ( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise + st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise ) / CPE_CHANNELS; */
1251 4007 : st_ivas->hMasa->data.hOmasaData->lp_noise_CPE_fx = extract_h( L_mac( L_mult( extract_h( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_32fx ), ONE_IN_Q14 ), extract_h( st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise_32fx ), ONE_IN_Q14 ) ); /*Q8*/
1252 : }
1253 7058 : move16();
1254 : }
1255 :
1256 39923 : return error;
1257 : }
1258 :
1259 :
1260 : /*-----------------------------------------------------------------------*
1261 : * ivas_masa_surrcoh_signicant()
1262 : *
1263 : * Determine if surrounding coherence is significant in this frame and should be encoded
1264 : *-----------------------------------------------------------------------*/
1265 :
1266 2589 : UWord8 ivas_masa_surrcoh_signicant_fx(
1267 : Word32 surroundingCoherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i : Surround coherence Q31 */
1268 : Word32 diffuse_to_total_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /* i : Diffuse to total ratio Q31 */
1269 : const Word16 nSubFrames, /* i : Number of sub frames */
1270 : const Word16 nBands /* i : Number of frequency bands */
1271 : )
1272 : {
1273 : Word32 significanceMeasure1, significanceMeasure2, significanceMeasure;
1274 : Word32 surrCohToTotal, surrCohToTotalSum, surrCohToTotalTimesDiffSum, diffSum;
1275 : Word32 sf, band;
1276 : Word16 surrCohToTotalSum_e, surrCohToTotalTimesDiffSum_e, diffSum_e;
1277 :
1278 : // input buffers Q=31
1279 2589 : Word32 surrCohSignificanceCoef = 858993459; //( 0.4 * ( 1 << q ) ) 0.4 scaled to Q=31
1280 2589 : move32();
1281 2589 : Word32 threshold = 214748365; //( 0.1 * ( 1 << q ) ) 0.1 scaled to Q=31
1282 2589 : move32();
1283 5802 : FOR( sf = 0; sf < nSubFrames; sf++ )
1284 : {
1285 3630 : surrCohToTotalSum = 0;
1286 3630 : move32();
1287 3630 : surrCohToTotalSum_e = 0;
1288 3630 : move16();
1289 3630 : surrCohToTotalTimesDiffSum = 0;
1290 3630 : move32();
1291 3630 : surrCohToTotalTimesDiffSum_e = 0;
1292 3630 : move16();
1293 3630 : diffSum = 0;
1294 3630 : move32();
1295 3630 : diffSum_e = 0;
1296 3630 : move16();
1297 :
1298 75702 : FOR( band = 0; band < nBands; band++ )
1299 : {
1300 72072 : surrCohToTotal = Mpy_32_32( diffuse_to_total_ratio[sf][band], surroundingCoherence[sf][band] ); // Q31
1301 72072 : surrCohToTotalSum = BASOP_Util_Add_Mant32Exp( surrCohToTotalSum, surrCohToTotalSum_e, surrCohToTotal, 0, &surrCohToTotalSum_e );
1302 72072 : surrCohToTotalTimesDiffSum = BASOP_Util_Add_Mant32Exp( surrCohToTotalTimesDiffSum, surrCohToTotalTimesDiffSum_e, Mpy_32_32( (Word32) diffuse_to_total_ratio[sf][band], surrCohToTotal ), 0, &surrCohToTotalTimesDiffSum_e );
1303 72072 : diffSum = BASOP_Util_Add_Mant32Exp( diffSum, diffSum_e, diffuse_to_total_ratio[sf][band], 0, &diffSum_e );
1304 : }
1305 :
1306 : Word16 significanceMeasure1_e, significanceMeasure2_e;
1307 : Word16 significanceMeasure_e;
1308 3630 : significanceMeasure1 = L_deposit_h( BASOP_Util_Divide3216_Scale( surrCohToTotalSum, nBands, &significanceMeasure1_e ) );
1309 3630 : significanceMeasure1_e = add( significanceMeasure1_e, sub( surrCohToTotalSum_e, 15 ) );
1310 3630 : significanceMeasure2 = L_deposit_h( BASOP_Util_Divide3232_Scale( Mpy_32_32( surrCohSignificanceCoef, surrCohToTotalTimesDiffSum ), L_add( diffSum, EPSILON_FX ), &significanceMeasure2_e ) );
1311 3630 : significanceMeasure2_e = add( significanceMeasure2_e, sub( surrCohToTotalTimesDiffSum_e, diffSum_e ) );
1312 :
1313 3630 : IF( BASOP_Util_Cmp_Mant32Exp( significanceMeasure1, significanceMeasure1_e, significanceMeasure2, significanceMeasure2_e ) > 0 )
1314 : {
1315 3605 : significanceMeasure = significanceMeasure1;
1316 3605 : move32();
1317 3605 : significanceMeasure_e = significanceMeasure1_e;
1318 3605 : move16();
1319 : }
1320 : ELSE
1321 : {
1322 25 : significanceMeasure = significanceMeasure2;
1323 25 : move32();
1324 25 : significanceMeasure_e = significanceMeasure2_e;
1325 25 : move16();
1326 : }
1327 3630 : IF( BASOP_Util_Cmp_Mant32Exp( significanceMeasure, significanceMeasure_e, threshold, 0 ) > 0 )
1328 : {
1329 417 : return 1;
1330 : }
1331 : }
1332 :
1333 2172 : return 0;
1334 : }
1335 :
1336 :
1337 : /*-----------------------------------------------------------------------*
1338 : * Local functions
1339 : *-----------------------------------------------------------------------*/
1340 :
1341 41605 : static void combine_freqbands_and_subframes_fx(
1342 : MASA_ENCODER_HANDLE hMasa )
1343 : {
1344 : Word16 i, j, k, m;
1345 : Word16 aziRad, eleRad;
1346 : Word32 x[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1347 : Word32 y[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1348 : Word32 z[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1349 : Word16 x_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1350 : Word16 y_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1351 : Word16 z_e[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1352 : Word32 vecLen;
1353 : Word16 vecLen_e;
1354 : Word32 xSum, ySum, zSum;
1355 : Word16 xSum_e, ySum_e, zSum_e, common_e;
1356 : Word64 xSum_sq, ySum_sq, zSum_sq;
1357 : Word32 energySum;
1358 : Word16 energySum_e;
1359 : Word32 spreadCohSum;
1360 : Word16 spreadCohSum_e;
1361 : Word32 surrCohSum;
1362 : Word16 surrCohSum_e;
1363 : Word32 energyRatioSum;
1364 : Word16 energyRatioSum_e;
1365 : Word16 surrCohTemp;
1366 : Word32 energyRatioTemp;
1367 : Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1368 : Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1369 : Word16 brange[2];
1370 : UWord8 numCodingBands;
1371 : UWord8 numSf;
1372 : UWord8 numDirections;
1373 : MASA_METADATA_HANDLE hMeta;
1374 : UWord8 mergeRatiosOverSubframes;
1375 : UWord8 computeCoherence;
1376 : Word16 exp_diff;
1377 : Word32 L_tmp;
1378 : Word64 W_tmp;
1379 : Word16 q_shift;
1380 :
1381 41605 : numCodingBands = hMasa->config.numCodingBands;
1382 41605 : move16();
1383 41605 : numDirections = hMasa->config.numberOfDirections;
1384 41605 : move16();
1385 41605 : IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
1386 : {
1387 5550 : numSf = 1;
1388 5550 : move16();
1389 : }
1390 : ELSE
1391 : {
1392 36055 : numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
1393 36055 : move16();
1394 : }
1395 41605 : hMeta = &( hMasa->masaMetadata );
1396 :
1397 41605 : mergeRatiosOverSubframes = hMasa->config.mergeRatiosOverSubframes;
1398 41605 : move16();
1399 41605 : test();
1400 41605 : IF( hMasa->config.useCoherence && hMasa->config.coherencePresent )
1401 : {
1402 20604 : computeCoherence = 1;
1403 20604 : move16();
1404 : }
1405 : ELSE
1406 : {
1407 21001 : computeCoherence = 0;
1408 21001 : move16();
1409 : }
1410 :
1411 : /* If metadata subframes are joined then we need all energy to be in the first subframe for combining.
1412 : * This optimizes following computations a bit.
1413 : * Note: If energy is used elsewhere, then this can cause problems and local energy should be used. */
1414 41605 : IF( EQ_16( numSf, 1 ) )
1415 : {
1416 22200 : FOR( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
1417 : {
1418 416250 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
1419 : {
1420 399600 : hMasa->data.energy_fx[0][k] = BASOP_Util_Add_Mant32Exp( hMasa->data.energy_fx[0][k], hMasa->data.energy_e[0][k], hMasa->data.energy_fx[j][k], hMasa->data.energy_e[j][k], &hMasa->data.energy_e[0][k] ); // 31-hMasa->data.energy_e[0][k]
1421 399600 : move32();
1422 : }
1423 : }
1424 : }
1425 :
1426 41605 : IF( LE_16( numCodingBands, MAX_REDUCED_NBANDS ) )
1427 : {
1428 : /* reduce metadata *frequency* resolution. time resolution is not touched */
1429 84542 : FOR( i = 0; i < numDirections; i++ )
1430 : {
1431 212303 : FOR( j = 0; j < numSf; j++ ) /* NB: for numSf==1, operates only on first sub-frame */
1432 : {
1433 4143100 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
1434 : {
1435 3977376 : aziRad = extract_l( L_shl( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], PI_OVER_180_FX ), Q13 - Q22 ) ); // ((Q22, Q31) -> Q22) >> Q9 -> Q13
1436 3977376 : eleRad = extract_l( L_shl( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], PI_OVER_180_FX ), Q13 - Q22 ) ); // ((Q22, Q31) -> Q22) >> Q9 -> Q13
1437 3977376 : vecLen = Mpy_32_32( hMeta->directional_meta[i].energy_ratio_fx[j][k], hMasa->data.energy_fx[j][k] ); // (Q30, 31-hMasa->data.energy_e[j][k]) -> (31-hMasa->data.energy_e[j][k]) - Q1
1438 :
1439 : /* Need more precision for some DTX cases with low energy frames */
1440 3977376 : W_tmp = W_mult0_32_32( L_mult( getCosWord16( aziRad ), getCosWord16( eleRad ) ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
1441 3977376 : q_shift = W_norm( W_tmp );
1442 3977376 : x[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
1443 3977376 : move32();
1444 3977376 : x_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
1445 3977376 : move16();
1446 :
1447 3977376 : W_tmp = W_mult0_32_32( L_mult0( getSinWord16( aziRad ), getCosWord16( eleRad ) ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
1448 3977376 : q_shift = W_norm( W_tmp );
1449 3977376 : y[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
1450 3977376 : move32();
1451 3977376 : y_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
1452 3977376 : move16();
1453 :
1454 3977376 : W_tmp = W_mult0_32_32( L_mult0( getSinWord16( eleRad ), ONE_IN_Q14 ), vecLen ); // (Q29, (31-hMasa->data.energy_e[j][k]) - Q1) -> (Q59 - hMasa->data.energy_e[j][k])
1455 3977376 : q_shift = W_norm( W_tmp );
1456 3977376 : z[i][j][k] = W_extract_h( W_shl( W_tmp, q_shift ) );
1457 3977376 : move32();
1458 3977376 : z_e[i][j][k] = sub( Q31, add( sub( 59, hMasa->data.energy_e[j][k] ), sub( q_shift, 32 ) ) );
1459 3977376 : move16();
1460 : }
1461 : }
1462 : }
1463 :
1464 84542 : FOR( i = 0; i < numDirections; i++ )
1465 : {
1466 212303 : FOR( j = 0; j < numSf; j++ )
1467 : {
1468 1155432 : FOR( k = 0; k < numCodingBands; k++ )
1469 : {
1470 989708 : brange[0] = hMasa->data.band_mapping[k];
1471 989708 : move16();
1472 989708 : brange[1] = hMasa->data.band_mapping[k + 1];
1473 989708 : move16();
1474 :
1475 989708 : xSum = 0;
1476 989708 : ySum = 0;
1477 989708 : zSum = 0;
1478 989708 : energySum = 0;
1479 989708 : spreadCohSum = 0;
1480 989708 : xSum_e = 0;
1481 989708 : ySum_e = 0;
1482 989708 : zSum_e = 0;
1483 989708 : energySum_e = 0;
1484 989708 : spreadCohSum_e = 0;
1485 989708 : move32();
1486 989708 : move32();
1487 989708 : move32();
1488 989708 : move32();
1489 989708 : move32();
1490 989708 : move16();
1491 989708 : move16();
1492 989708 : move16();
1493 989708 : move16();
1494 989708 : move16();
1495 :
1496 4860002 : FOR( m = brange[0]; m < brange[1]; m++ )
1497 : {
1498 3870294 : xSum = BASOP_Util_Add_Mant32Exp( xSum, xSum_e, x[i][j][m], x_e[i][j][m], &xSum_e ); // xSum_e
1499 3870294 : ySum = BASOP_Util_Add_Mant32Exp( ySum, ySum_e, y[i][j][m], y_e[i][j][m], &ySum_e ); // ySum_e
1500 3870294 : zSum = BASOP_Util_Add_Mant32Exp( zSum, zSum_e, z[i][j][m], z_e[i][j][m], &zSum_e ); // zSum_e
1501 3870294 : energySum = BASOP_Util_Add_Mant32Exp( energySum, energySum_e, hMasa->data.energy_fx[j][m], hMasa->data.energy_e[j][m], &energySum_e ); // energySum_e
1502 : }
1503 989708 : common_e = add( s_max( xSum_e, s_max( ySum_e, zSum_e ) ), 2 ); /*2 is guard bit for addition operations*/
1504 989708 : xSum = L_shr( xSum, sub( common_e, xSum_e ) ); /*common_e*/
1505 989708 : ySum = L_shr( ySum, sub( common_e, ySum_e ) ); /*common_e*/
1506 989708 : zSum = L_shr( zSum, sub( common_e, zSum_e ) ); /*common_e*/
1507 989708 : aziRad = BASOP_util_atan2( ySum, xSum, 0 ); // Q13
1508 989708 : xSum_sq = W_mult0_32_32( xSum, xSum ); // 2 * (31-common_e)
1509 989708 : ySum_sq = W_mult0_32_32( ySum, ySum ); // 2 * (31-common_e)
1510 989708 : zSum_sq = W_mult0_32_32( zSum, zSum ); // 2 * (31-common_e)
1511 989708 : W_tmp = W_add( xSum_sq, ySum_sq ); // 2 * (31-common_e)
1512 989708 : q_shift = W_norm( W_tmp );
1513 989708 : L_tmp = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 * (31-common_e) + (q_shift -32)
1514 989708 : exp_diff = sub( Q31, add( imult1616( 2, sub( 31, common_e ) ), sub( q_shift, 32 ) ) );
1515 989708 : L_tmp = Sqrt32( L_tmp, &exp_diff );
1516 989708 : eleRad = BASOP_util_atan2( zSum, L_tmp, sub( common_e, exp_diff ) ); // Q13
1517 :
1518 989708 : hMeta->directional_meta[i].azimuth_fx[j][k] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, aziRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
1519 989708 : move32();
1520 989708 : hMeta->directional_meta[i].elevation_fx[j][k] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, eleRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
1521 989708 : move32();
1522 :
1523 989708 : W_tmp = W_add( xSum_sq, ySum_sq ); // 2 * (31-common_e)
1524 989708 : W_tmp = W_add( W_tmp, zSum_sq ); // 2 * (31-common_e)
1525 989708 : q_shift = W_norm( W_tmp );
1526 989708 : vecLen = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 * (31-common_e) + (q_shift -32)
1527 989708 : exp_diff = sub( Q31, add( imult1616( 2, sub( 31, common_e ) ), sub( q_shift, 32 ) ) );
1528 989708 : vecLen = Sqrt32( vecLen, &exp_diff );
1529 989708 : vecLen_e = exp_diff;
1530 989708 : move16();
1531 :
1532 1979416 : hMeta->directional_meta[i].energy_ratio_fx[j][k] =
1533 989708 : BASOP_Util_Divide3232_Scale_newton( vecLen, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+vecLen_e-energySum_e*/
1534 989708 : move32();
1535 989708 : exp_diff = add( exp_diff, sub( vecLen_e, energySum_e ) );
1536 1979416 : hMeta->directional_meta[i].energy_ratio_fx[j][k] =
1537 989708 : L_shl( hMeta->directional_meta[i].energy_ratio_fx[j][k], sub( exp_diff, Q1 ) ); // (Q31 - exp_diff ) -> Q30
1538 989708 : move32();
1539 :
1540 989708 : IF( computeCoherence )
1541 : {
1542 2379466 : FOR( m = brange[0]; m < brange[1]; m++ )
1543 : {
1544 1827408 : spreadCohSum = BASOP_Util_Add_Mant32Exp( spreadCohSum, spreadCohSum_e, Mpy_32_16_1( hMasa->data.energy_fx[j][m], hMeta->directional_meta[i].spread_coherence_fx[j][m] ), hMasa->data.energy_e[j][m], &spreadCohSum_e ); // 31-spreadCohSum_e
1545 : }
1546 552058 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( spreadCohSum, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+spreadCohSum_e-energySum_e*/
1547 552058 : exp_diff = add( exp_diff, sub( spreadCohSum_e, energySum_e ) );
1548 552058 : move16();
1549 : /* Saturation - LTV fix for values close to 1.0f+ */
1550 552058 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = shl_sat( hMeta->directional_meta[i].spread_coherence_fx[j][k], exp_diff ); // Q15
1551 552058 : move16();
1552 :
1553 552058 : IF( i == 0 )
1554 : {
1555 427914 : surrCohSum = 0;
1556 427914 : surrCohSum_e = 0;
1557 427914 : move32();
1558 427914 : move16();
1559 1833186 : FOR( m = brange[0]; m < brange[1]; m++ )
1560 : {
1561 1405272 : surrCohSum = BASOP_Util_Add_Mant32Exp( surrCohSum, surrCohSum_e, Mpy_32_16_1( hMasa->data.energy_fx[j][m], hMeta->common_meta.surround_coherence_fx[j][m] ), hMasa->data.energy_e[j][m], &surrCohSum_e ); // 31-surrCohSum_e
1562 : }
1563 427914 : hMeta->common_meta.surround_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( surrCohSum, L_add( energySum, EPSILON_FX ), &exp_diff ); /*exp_diff+surrCohSum_e-energySum_e*/
1564 427914 : move16();
1565 427914 : exp_diff = add( exp_diff, sub( surrCohSum_e, energySum_e ) );
1566 : /* Saturation - LTV fix for values close to 1.0f+ */
1567 427914 : hMeta->common_meta.surround_coherence_fx[j][k] = shl_sat( hMeta->common_meta.surround_coherence_fx[j][k], exp_diff ); // Q15
1568 427914 : move16();
1569 : }
1570 : }
1571 :
1572 989708 : IF( i == 0 )
1573 : {
1574 805350 : energy[j][k] = energySum; // 31-energySum_e
1575 805350 : energy_e[j][k] = energySum_e;
1576 805350 : move32();
1577 805350 : move16();
1578 : }
1579 : }
1580 : }
1581 : }
1582 : }
1583 3642 : ELSE IF( mergeRatiosOverSubframes ) /* keep frequency resolution */
1584 : {
1585 5700 : FOR( j = 0; j < numSf; j++ )
1586 : {
1587 114000 : FOR( k = 0; k < numCodingBands; k++ )
1588 : {
1589 109440 : energy[j][k] = hMasa->data.energy_fx[j][k]; // 31-hMasa->data.energy_e[j][k]
1590 109440 : energy_e[j][k] = hMasa->data.energy_e[j][k];
1591 109440 : move32();
1592 109440 : move16();
1593 : }
1594 : }
1595 : }
1596 :
1597 41605 : IF( mergeRatiosOverSubframes )
1598 : {
1599 244114 : FOR( k = 0; k < numCodingBands; k++ )
1600 : {
1601 210663 : energySum = 0;
1602 210663 : move32();
1603 210663 : energySum_e = 0;
1604 210663 : move16();
1605 1053315 : FOR( j = 0; j < numSf; j++ )
1606 : {
1607 842652 : energySum = BASOP_Util_Add_Mant32Exp( energySum, energySum_e, energy[j][k], energy_e[j][k], &energySum_e ); // 31-energySum_e
1608 : }
1609 :
1610 210663 : IF( computeCoherence )
1611 : {
1612 122333 : surrCohSum = 0;
1613 122333 : surrCohSum_e = 0;
1614 122333 : move32();
1615 122333 : move16();
1616 611665 : FOR( j = 0; j < numSf; j++ )
1617 : {
1618 489332 : surrCohSum = BASOP_Util_Add_Mant32Exp( surrCohSum, surrCohSum_e, Mpy_32_16_1( energy[j][k], hMeta->common_meta.surround_coherence_fx[j][k] ), energy_e[j][k], &surrCohSum_e ); // 31-surrCohSum_e
1619 : }
1620 122333 : surrCohTemp = BASOP_Util_Divide3232_Scale( surrCohSum, L_add( energySum, EPSILON_FX ), &exp_diff );
1621 122333 : exp_diff = add( exp_diff, sub( surrCohSum_e, energySum_e ) );
1622 122333 : surrCohTemp = shl_sat( surrCohTemp, exp_diff ); // Q15
1623 :
1624 611665 : FOR( j = 0; j < numSf; j++ )
1625 : {
1626 489332 : hMeta->common_meta.surround_coherence_fx[j][k] = surrCohTemp; // Q15
1627 489332 : move16();
1628 : }
1629 : }
1630 :
1631 459874 : FOR( i = 0; i < numDirections; i++ )
1632 : {
1633 249211 : energyRatioSum = 0;
1634 249211 : energyRatioSum_e = 0;
1635 249211 : move32();
1636 249211 : move16();
1637 1246055 : FOR( j = 0; j < numSf; j++ )
1638 : {
1639 996844 : energyRatioSum = BASOP_Util_Add_Mant32Exp( energyRatioSum, energyRatioSum_e, Mpy_32_32( energy[j][k], hMeta->directional_meta[i].energy_ratio_fx[j][k] ), add( energy_e[j][k], 1 ), &energyRatioSum_e ); // 31-energyRatioSum_e
1640 : }
1641 249211 : energyRatioTemp = BASOP_Util_Divide3232_Scale_newton( energyRatioSum, L_add( energySum, EPSILON_FX ), &exp_diff );
1642 249211 : exp_diff = add( exp_diff, sub( energyRatioSum_e, energySum_e ) );
1643 249211 : energyRatioTemp = L_shl( energyRatioTemp, sub( exp_diff, 1 ) ); // Q30
1644 :
1645 1246055 : FOR( j = 0; j < numSf; j++ )
1646 : {
1647 996844 : hMeta->directional_meta[i].energy_ratio_fx[j][k] = energyRatioTemp; // Q30
1648 996844 : move32();
1649 : }
1650 : }
1651 : }
1652 : }
1653 :
1654 41605 : return;
1655 : }
1656 :
1657 :
1658 : /*-------------------------------------------------------------------*
1659 : * ivas_masa_combine_directions()
1660 : *
1661 : *
1662 : *-------------------------------------------------------------------*/
1663 :
1664 9520 : void ivas_masa_combine_directions_fx(
1665 : MASA_ENCODER_HANDLE hMasa )
1666 : {
1667 : Word16 i, j, k;
1668 : UWord8 numCodingBands;
1669 : UWord8 numSf;
1670 : UWord8 numDirections;
1671 : UWord8 computeCoherence;
1672 : MASA_METADATA_HANDLE hMeta;
1673 :
1674 : Word16 aziRad_fx;
1675 : Word16 eleRad_fx;
1676 : Word32 x_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1677 : Word32 y_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1678 : Word32 z_fx[MASA_MAXIMUM_DIRECTIONS][MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1679 : Word32 vecLen_fx;
1680 : Word32 xSum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1681 : Word32 ySum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1682 : Word32 zSum_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1683 : Word32 sumVecLen_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
1684 9520 : Word16 exp_sumVecLen_buff[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], exp_sumVecLen = MIN16B_FLT_FX;
1685 9520 : move16();
1686 : Word32 tempImportance_fx;
1687 : Word32 importance_fx[MASA_FREQUENCY_BANDS];
1688 : Word16 exp_importance;
1689 : Word16 indicesOfLargest[MASA_FREQUENCY_BANDS];
1690 :
1691 : Word32 ratioSum_fx;
1692 : Word32 ambience1dir_fx;
1693 : Word32 ambience2dir_fx;
1694 : Word32 ambienceIncrease_fx;
1695 : Word32 origSurrCohEne_fx;
1696 : Word32 newSurrCohEne_fx;
1697 :
1698 9520 : numCodingBands = hMasa->config.numCodingBands;
1699 9520 : numDirections = hMasa->config.numberOfDirections;
1700 9520 : move16();
1701 9520 : move16();
1702 :
1703 9520 : IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
1704 : {
1705 1800 : numSf = 1;
1706 : }
1707 : ELSE
1708 : {
1709 7720 : numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
1710 : }
1711 9520 : move16();
1712 9520 : hMeta = &( hMasa->masaMetadata );
1713 :
1714 9520 : computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
1715 9520 : move16();
1716 9520 : Word16 azi_cos = 0, azi_sine = 0, ele_cos = 0, ele_sine = 0;
1717 9520 : move16();
1718 9520 : move16();
1719 9520 : move16();
1720 9520 : move16();
1721 28560 : FOR( i = 0; i < numDirections; i++ )
1722 : {
1723 84400 : FOR( j = 0; j < numSf; j++ )
1724 : {
1725 865744 : FOR( k = 0; k < numCodingBands; k++ )
1726 : {
1727 800384 : aziRad_fx = extract_l( L_shr( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], PI_OVER_180_Q25 ), 3 ) ); // (Q22 + Q25 - 31) - 3 = Q13
1728 800384 : azi_cos = getCosWord16( aziRad_fx ); // Q14
1729 800384 : azi_sine = getSinWord16( aziRad_fx ); // Q15
1730 :
1731 800384 : eleRad_fx = extract_l( L_shr( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], PI_OVER_180_Q25 ), 3 ) ); // (Q22 + Q25 - 31) - 3 = Q13
1732 800384 : ele_sine = getSinWord16( eleRad_fx ); // Q15
1733 800384 : ele_cos = getCosWord16( eleRad_fx ); // Q14
1734 :
1735 800384 : vecLen_fx = hMeta->directional_meta[i].energy_ratio_fx[j][k];
1736 800384 : move32();
1737 :
1738 800384 : x_fx[i][j][k] = L_mult0( azi_cos, ele_cos ); // Q14+Q14
1739 800384 : x_fx[i][j][k] = Mpy_32_32( x_fx[i][j][k], vecLen_fx ); // Q28+Q30-31
1740 800384 : y_fx[i][j][k] = L_mult0( azi_sine, ele_cos ); // Q15+Q14
1741 800384 : y_fx[i][j][k] = Mpy_32_32( y_fx[i][j][k], vecLen_fx ); // Q29+Q30-31
1742 800384 : z_fx[i][j][k] = Mpy_32_32( L_deposit_h( ele_sine ), vecLen_fx ); // Q16+Q15+Q30 - 31
1743 800384 : move32();
1744 800384 : move32();
1745 800384 : move32();
1746 800384 : move32();
1747 800384 : move32();
1748 : }
1749 : }
1750 : }
1751 :
1752 : /* Compute sum vector */
1753 42200 : FOR( j = 0; j < numSf; j++ )
1754 : {
1755 432872 : FOR( k = 0; k < numCodingBands; k++ )
1756 : {
1757 400192 : xSum_fx[j][k] = L_add( x_fx[0][j][k], x_fx[1][j][k] ); // Q27
1758 400192 : ySum_fx[j][k] = L_add( y_fx[0][j][k], y_fx[1][j][k] ); // Q28
1759 400192 : zSum_fx[j][k] = L_add( z_fx[0][j][k], z_fx[1][j][k] ); // Q30
1760 400192 : move32();
1761 400192 : move32();
1762 400192 : move32();
1763 :
1764 400192 : Word32 var1 = Mpy_32_32( xSum_fx[j][k], xSum_fx[j][k] ); // Q27 + Q27 - 31 //Q23
1765 400192 : Word32 var2 = Mpy_32_32( ySum_fx[j][k], ySum_fx[j][k] ); // Q28 + Q28 - 31 //Q25
1766 400192 : Word32 var3 = Mpy_32_32( zSum_fx[j][k], zSum_fx[j][k] ); // Q30 + Q30 - 31 //Q29
1767 400192 : Word32 var4 = L_add( L_add( var1, L_shr( var2, 2 ) ), L_shr( var3, 6 ) ); // Q23
1768 400192 : Word16 exp_var4 = 31 - Q23;
1769 400192 : move16();
1770 :
1771 400192 : Word16 exp_var5 = exp_var4;
1772 400192 : move16();
1773 400192 : Word32 var5 = 0;
1774 400192 : move32();
1775 :
1776 400192 : IF( var4 != 0 )
1777 : {
1778 400192 : var5 = Sqrt32( var4, &exp_var5 );
1779 : }
1780 400192 : sumVecLen_fx[j][k] = var5;
1781 400192 : move32();
1782 400192 : exp_sumVecLen_buff[j][k] = exp_var5;
1783 400192 : move16();
1784 : }
1785 : }
1786 :
1787 : /*make commen exp for sumVecLen_fx buffer*/
1788 42200 : FOR( j = 0; j < numSf; j++ )
1789 : {
1790 432872 : FOR( k = 0; k < numCodingBands; k++ )
1791 : {
1792 400192 : exp_sumVecLen = s_max( exp_sumVecLen_buff[j][k], exp_sumVecLen );
1793 : }
1794 : }
1795 :
1796 42200 : FOR( j = 0; j < numSf; j++ )
1797 : {
1798 432872 : FOR( k = 0; k < numCodingBands; k++ )
1799 : {
1800 400192 : sumVecLen_fx[j][k] = L_shr( sumVecLen_fx[j][k], sub( exp_sumVecLen, exp_sumVecLen_buff[j][k] ) );
1801 400192 : move32();
1802 : }
1803 : }
1804 :
1805 : /* Estimate the importance of having two directions instead of one */
1806 : /* Reduced precision of importance_fx intentionally to Q13 to maintatin 0.0001f resolution */
1807 132644 : FOR( i = 0; i < numCodingBands; i++ )
1808 : {
1809 123124 : importance_fx[i] = 0;
1810 123124 : move32();
1811 523316 : FOR( j = 0; j < numSf; j++ )
1812 : {
1813 400192 : tempImportance_fx = L_shr( L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ), Q30 - Q13 ); // Q13
1814 400192 : tempImportance_fx = L_sub( tempImportance_fx, L_shr( sumVecLen_fx[j][i], sub( sub( Q31, exp_sumVecLen ), Q13 ) ) ); // Q13
1815 400192 : importance_fx[i] = L_add( importance_fx[i], tempImportance_fx ); // Q13
1816 400192 : move32();
1817 : }
1818 :
1819 123124 : IF( NE_16( numSf, 1 ) )
1820 : {
1821 92356 : importance_fx[i] = L_shr( importance_fx[i], 2 ); // Q13
1822 92356 : move32();
1823 : }
1824 123124 : importance_fx[i] = Mpy_32_32( importance_fx[i], hMasa->data.importanceWeight_fx[i] ); //(Q13, Q30) -> Q12
1825 123124 : move32();
1826 : }
1827 9520 : exp_importance = Q31 - Q12;
1828 9520 : move16();
1829 :
1830 : /* Determine bands where to use two directions */
1831 9520 : find_n_largest_fx( importance_fx, exp_importance, indicesOfLargest, numCodingBands, hMasa->config.numTwoDirBands );
1832 :
1833 132644 : FOR( i = 0; i < numCodingBands; i++ )
1834 : {
1835 123124 : hMasa->data.twoDirBands[i] = 0;
1836 123124 : move16();
1837 : }
1838 :
1839 31054 : FOR( i = 0; i < hMasa->config.numTwoDirBands; i++ )
1840 : {
1841 21534 : hMasa->data.twoDirBands[indicesOfLargest[i]] = 1;
1842 21534 : move16();
1843 : }
1844 :
1845 : /* Combine directions on the remaining bands */
1846 132644 : FOR( i = 0; i < numCodingBands; i++ )
1847 : {
1848 123124 : IF( hMasa->data.twoDirBands[i] == 0 )
1849 : {
1850 430178 : FOR( j = 0; j < numSf; j++ )
1851 : {
1852 328588 : aziRad_fx = BASOP_util_atan2( ySum_fx[j][i], xSum_fx[j][i], Q27 - Q28 ); // Q13
1853 328588 : Word32 tmp1 = Mpy_32_32( xSum_fx[j][i], xSum_fx[j][i] ); // Q27+Q27-31 //Q23
1854 328588 : Word32 tmp2 = Mpy_32_32( ySum_fx[j][i], ySum_fx[j][i] ); // Q28+Q28-31 //Q25
1855 328588 : Word32 tmp3 = L_add( tmp1, L_shr( tmp2, 2 ) ); // Q23
1856 328588 : Word16 exp_tmp3 = 31 - Q23;
1857 328588 : move16();
1858 328588 : Word32 tmp4 = Sqrt32( tmp3, &exp_tmp3 );
1859 328588 : eleRad_fx = BASOP_util_atan2( zSum_fx[j][i], tmp4, sub( sub( 31, Q30 ), exp_tmp3 ) );
1860 :
1861 328588 : Word16 exp_tmp5 = 0;
1862 328588 : move16();
1863 328588 : Word16 tmp5 = BASOP_Util_Divide1616_Scale( aziRad_fx, EVS_PI_FX, &exp_tmp5 );
1864 328588 : Word16 Q_tmp6 = 0;
1865 328588 : move16();
1866 328588 : Word32 tmp6 = L_mult( tmp5, 23040 /*180.0f in Q7*/ );
1867 328588 : Q_tmp6 = sub( 31, add( exp_tmp5, 8 ) );
1868 :
1869 328588 : Word16 exp_tmp7 = 0;
1870 328588 : move16();
1871 328588 : Word16 tmp7 = BASOP_Util_Divide1616_Scale( eleRad_fx, EVS_PI_FX, &exp_tmp7 );
1872 328588 : Word16 Q_tmp8 = 0;
1873 328588 : move16();
1874 328588 : Word32 tmp8 = L_mult( tmp7, 23040 /*180.0f in Q7*/ );
1875 328588 : Q_tmp8 = sub( 31, add( exp_tmp7, 8 ) );
1876 :
1877 328588 : Scale_sig32( &tmp6, 1, Q22 - Q_tmp6 );
1878 328588 : Scale_sig32( &tmp8, 1, Q22 - Q_tmp8 );
1879 :
1880 328588 : hMeta->directional_meta[0].azimuth_fx[j][i] = tmp6; // Q22
1881 328588 : hMeta->directional_meta[0].elevation_fx[j][i] = tmp8; // Q22
1882 328588 : move32();
1883 328588 : move32();
1884 328588 : ratioSum_fx = L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ); // Q30
1885 328588 : IF( computeCoherence )
1886 : {
1887 127198 : Word32 var1 = Mpy_32_16_1( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[0].spread_coherence_fx[j][i] );
1888 127198 : Word32 var2 = Mpy_32_16_1( hMeta->directional_meta[1].energy_ratio_fx[j][i], hMeta->directional_meta[1].spread_coherence_fx[j][i] );
1889 127198 : Word32 var3 = L_add( var1, var2 ); // Q30
1890 127198 : Word16 exp_var4 = 0;
1891 127198 : move16();
1892 127198 : Word32 var4 = BASOP_Util_Add_Mant32Exp( ratioSum_fx, 31 - Q30, EPSILON_FX_M, EPSILON_FX_E, &exp_var4 );
1893 127198 : Word16 exp_var5 = 0;
1894 127198 : move16();
1895 127198 : Word16 var5 = BASOP_Util_Divide3232_Scale( var3, var4, &exp_var5 );
1896 127198 : exp_var5 = add( exp_var5, ( sub( sub( 31, Q30 ), exp_var4 ) ) );
1897 127198 : Scale_sig( &var5, 1, sub( Q15, sub( 15, exp_var5 ) ) );
1898 127198 : hMeta->directional_meta[0].spread_coherence_fx[j][i] = var5; // Q15
1899 127198 : move16();
1900 : }
1901 :
1902 328588 : ambience2dir_fx = L_sub( ONE_IN_Q30, ratioSum_fx ); // Q30
1903 328588 : Word32 ambience2dir_fx_by_2 = L_shr( ambience2dir_fx, 1 );
1904 328588 : Word32 var_a = L_add( L_add( hMeta->directional_meta[0].energy_ratio_fx[j][i], hMeta->directional_meta[1].energy_ratio_fx[j][i] ), ambience2dir_fx_by_2 ); // Q30
1905 328588 : Word16 exp_var_b = 0;
1906 328588 : move16();
1907 328588 : Word16 var_b = BASOP_Util_Divide3232_Scale( sumVecLen_fx[j][i], var_a, &exp_var_b );
1908 328588 : exp_var_b = add( exp_var_b, sub( exp_sumVecLen, 1 ) );
1909 328588 : Word32 var_b_32 = L_deposit_h( var_b );
1910 328588 : hMeta->directional_meta[0].energy_ratio_fx[j][i] = L_shr( var_b_32, 1 - exp_var_b ); // Q30
1911 328588 : hMeta->directional_meta[1].energy_ratio_fx[j][i] = 0; // Q30
1912 328588 : move16();
1913 328588 : move16();
1914 328588 : hMeta->common_meta.diffuse_to_total_ratio_fx[j][i] = L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][i] ); // Q30
1915 :
1916 328588 : IF( computeCoherence )
1917 : {
1918 127198 : ambience1dir_fx = L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][i] ); // Q30
1919 127198 : ambienceIncrease_fx = L_max( L_sub( ambience1dir_fx, ambience2dir_fx ), 0 ); // Q30
1920 127198 : origSurrCohEne_fx = Mpy_32_16_1( ambience2dir_fx /*Q30*/, hMeta->common_meta.surround_coherence_fx[j][i] /*Q15*/ ); // Q30
1921 127198 : newSurrCohEne_fx = Mpy_32_16_1( ambienceIncrease_fx /*Q30*/, hMeta->directional_meta[0].spread_coherence_fx[j][i] /*Q15*/ ); // Q30
1922 :
1923 127198 : Word16 exp_y = 0, exp_z = 0;
1924 127198 : move16();
1925 127198 : move16();
1926 127198 : Word32 x = L_add( origSurrCohEne_fx, newSurrCohEne_fx ); // Q30
1927 127198 : Word32 y = BASOP_Util_Add_Mant32Exp( ambience1dir_fx, 1, EPSILON_FX_M, EPSILON_FX_E, &exp_y );
1928 127198 : Word16 z = BASOP_Util_Divide3232_Scale( x, y, &exp_z );
1929 127198 : exp_z = add( exp_z, ( sub( 31 - Q30, exp_y ) ) );
1930 127198 : z = shl_sat( z, exp_z ); // Q15
1931 127198 : hMeta->common_meta.surround_coherence_fx[j][i] = s_min( MAX16B, z );
1932 127198 : move16();
1933 : }
1934 : }
1935 : }
1936 : }
1937 :
1938 9520 : return;
1939 : }
1940 :
1941 9520 : static void find_n_largest_fx(
1942 : const Word32 *input_fx, // Q(31 - exp_input)
1943 : Word16 exp_input,
1944 : Word16 *largestIndices,
1945 : const Word16 numElements,
1946 : const Word16 numLargest )
1947 : {
1948 : Word16 i, j;
1949 : Word32 largestValue;
1950 : Word16 largestIndex;
1951 : Word32 values[MASA_FREQUENCY_BANDS];
1952 :
1953 132644 : FOR( j = 0; j < numElements; j++ )
1954 : {
1955 123124 : values[j] = input_fx[j]; // Q(31 - exp_input)
1956 123124 : move32();
1957 : }
1958 :
1959 31054 : FOR( i = 0; i < numLargest; i++ )
1960 : {
1961 21534 : largestValue = values[0]; // Q(31 - exp_input)
1962 21534 : move32();
1963 21534 : largestIndex = 0;
1964 21534 : move16();
1965 342038 : FOR( j = 1; j < numElements; j++ )
1966 : {
1967 320504 : IF( GT_32( values[j], largestValue ) )
1968 : {
1969 41074 : largestValue = values[j]; // Q(31 - exp_input)
1970 41074 : largestIndex = j;
1971 41074 : move32();
1972 41074 : move16();
1973 : }
1974 : }
1975 21534 : largestIndices[i] = largestIndex;
1976 21534 : move16();
1977 21534 : IF( exp_input != 0 )
1978 : {
1979 21534 : values[largestIndex] = L_negate( 1 << ( sub( 31, exp_input ) ) ); // Q(31 - exp_input)
1980 21534 : move32();
1981 : }
1982 : ELSE
1983 : {
1984 0 : values[largestIndex] = 1 << ( sub( 31, exp_input ) ); // Q(31 - exp_input)
1985 0 : move32();
1986 : }
1987 : }
1988 :
1989 9520 : return;
1990 : }
1991 :
1992 41605 : static void move_metadata_to_qmetadata_fx(
1993 : const MASA_ENCODER_HANDLE hMasa,
1994 : IVAS_QMETADATA_HANDLE hQMeta )
1995 : {
1996 : Word16 dir, sf, band;
1997 : UWord8 numCodingBands;
1998 : UWord8 numDirections;
1999 : UWord8 numSf;
2000 : MASA_METADATA_HANDLE hMeta;
2001 :
2002 41605 : numCodingBands = hMasa->config.numCodingBands;
2003 41605 : numDirections = hMasa->config.numberOfDirections;
2004 41605 : move16();
2005 41605 : move16();
2006 41605 : move16();
2007 41605 : numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
2008 41605 : if ( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
2009 : {
2010 5550 : numSf = 1;
2011 5550 : move16();
2012 : }
2013 41605 : hMeta = &( hMasa->masaMetadata );
2014 :
2015 89046 : FOR( dir = 0; dir < numDirections; dir++ )
2016 : {
2017 217567 : FOR( sf = 0; sf < numSf; sf++ )
2018 : {
2019 1526120 : FOR( band = 0; band < numCodingBands; band++ )
2020 : {
2021 1355994 : hQMeta->q_direction[dir].band_data[band].azimuth_fx[sf] = hMeta->directional_meta[dir].azimuth_fx[sf][band]; // Q22
2022 1355994 : hQMeta->q_direction[dir].band_data[band].elevation_fx[sf] = hMeta->directional_meta[dir].elevation_fx[sf][band]; // Q22
2023 1355994 : hQMeta->q_direction[dir].band_data[band].energy_ratio_fx[sf] = hMeta->directional_meta[dir].energy_ratio_fx[sf][band]; // Q30
2024 1355994 : hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band];
2025 1355994 : move32();
2026 1355994 : move32();
2027 1355994 : move32();
2028 1355994 : move16();
2029 :
2030 1355994 : IF( hQMeta->q_direction[dir].coherence_band_data != NULL )
2031 : {
2032 990540 : hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = (UWord8) mult_r( hMeta->directional_meta[dir].spread_coherence_fx[sf][band], UINT8_MAX ); // Q15
2033 990540 : move16();
2034 : }
2035 : }
2036 : }
2037 : }
2038 :
2039 191375 : FOR( sf = 0; sf < numSf; sf++ )
2040 : {
2041 1280362 : FOR( band = 0; band < numCodingBands; band++ )
2042 : {
2043 1130592 : IF( hQMeta->surcoh_band_data != NULL )
2044 : {
2045 765138 : hQMeta->surcoh_band_data[band].surround_coherence[sf] = (UWord8) mult_r( hMeta->common_meta.surround_coherence_fx[sf][band], UINT8_MAX ); // Q15
2046 765138 : move16();
2047 : }
2048 : }
2049 : }
2050 :
2051 41605 : IF( GT_16( numDirections, 1 ) )
2052 : {
2053 75232 : FOR( band = 0; band < numCodingBands; band++ )
2054 : {
2055 69396 : hQMeta->twoDirBands[band] = hMasa->data.twoDirBands[band];
2056 69396 : move16();
2057 : }
2058 5836 : hQMeta->numTwoDirBands = hMasa->config.numTwoDirBands;
2059 5836 : move16();
2060 : }
2061 :
2062 : /* Copy spread coherence for DCT-based coding */
2063 41605 : test();
2064 41605 : IF( EQ_16( numSf, 1 ) && hMasa->config.useCoherence )
2065 : {
2066 6620 : FOR( dir = 0; dir < numDirections; dir++ )
2067 : {
2068 15232 : FOR( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2069 : {
2070 200268 : FOR( band = 0; band < numCodingBands; band++ )
2071 : {
2072 188844 : hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[0];
2073 188844 : move16();
2074 : }
2075 : }
2076 : }
2077 : }
2078 :
2079 41605 : return;
2080 : }
2081 :
2082 :
2083 : /* This function studies parametric MASA metadata to provide information for codec configuration */
2084 39626 : static void detect_metadata_composition_fx(
2085 : const MASA_ENCODER_HANDLE hMasa, /* i : MASA encoder data */
2086 : UWord8 *joinedSubframes, /* o : Result of subframe composition */
2087 : UWord8 *coherencePresent, /* o : Result of coherence presence */
2088 : UWord8 *isTwoDir /* o : Result of two direction check */
2089 : )
2090 : {
2091 : MASA_METADATA_FRAME *hMeta;
2092 : Word8 sf, band, dir, numDir;
2093 : Word16 nSubFrames;
2094 39626 : UWord8 dirValid[2] = { FALSE, FALSE };
2095 39626 : UWord8 cohPresent = FALSE;
2096 39626 : UWord8 sfDiffer = FALSE;
2097 : UWord8 sfSimilar;
2098 39626 : move16(); /*dirValid[0]*/
2099 39626 : move16(); /*dirValid[1]*/
2100 39626 : move16(); /*cohPresent*/
2101 39626 : move16(); /*sfDiffer*/
2102 :
2103 39626 : hMeta = &( hMasa->masaMetadata );
2104 39626 : numDir = (Word8) add( hMeta->descriptive_meta.numberOfDirections, 1 );
2105 39626 : move16();
2106 :
2107 39626 : *isTwoDir = FALSE;
2108 39626 : move16();
2109 :
2110 : /* First check for valid two directions */
2111 39626 : IF( EQ_16( numDir, 1 ) )
2112 : {
2113 29726 : dirValid[0] = TRUE;
2114 29726 : move16();
2115 : }
2116 : ELSE
2117 : {
2118 : /* Default assumption */
2119 9900 : *isTwoDir = TRUE;
2120 9900 : move16();
2121 :
2122 : /* Check for direct-to-total ratio values */
2123 29700 : FOR( dir = 0; dir < numDir; dir++ )
2124 : {
2125 19800 : sf = 0;
2126 19800 : move16();
2127 39600 : WHILE( !dirValid[dir] && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
2128 : {
2129 19800 : test();
2130 19800 : band = 0;
2131 19800 : move16();
2132 39600 : WHILE( !dirValid[dir] && ( band < MASA_FREQUENCY_BANDS ) )
2133 : {
2134 19800 : test();
2135 19800 : IF( GE_32( hMeta->directional_meta[dir].energy_ratio_fx[sf][band] /*q30*/, MASA_RATIO_THRESHOLD_FX >> 1 /*q30*/ ) )
2136 : {
2137 19800 : dirValid[dir] = TRUE;
2138 19800 : move16();
2139 : }
2140 19800 : band = (Word8) add( band, 1 );
2141 : }
2142 19800 : sf = (Word8) add( sf, 1 );
2143 : }
2144 : }
2145 :
2146 9900 : test();
2147 9900 : IF( dirValid[1] == FALSE )
2148 : {
2149 : /* This handles also case where both are false. Then we just use first dir metadata. */
2150 0 : *isTwoDir = FALSE;
2151 0 : move16();
2152 : }
2153 9900 : ELSE IF( dirValid[0] == FALSE && EQ_16( dirValid[1], TRUE ) )
2154 : {
2155 0 : *isTwoDir = FALSE;
2156 0 : move16();
2157 : /* Copy data to first direction */
2158 0 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2159 : {
2160 0 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
2161 : {
2162 0 : hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band];
2163 0 : move16();
2164 0 : hMeta->directional_meta[0].azimuth_fx[sf][band] = hMeta->directional_meta[1].azimuth_fx[sf][band]; /*q22*/
2165 0 : hMeta->directional_meta[0].elevation_fx[sf][band] = hMeta->directional_meta[1].elevation_fx[sf][band]; /*q22*/
2166 0 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = hMeta->directional_meta[1].energy_ratio_fx[sf][band]; /*q30*/
2167 0 : hMeta->directional_meta[0].spread_coherence_fx[sf][band] = hMeta->directional_meta[1].spread_coherence_fx[sf][band]; /*q15*/
2168 0 : move32();
2169 0 : move16();
2170 0 : move16();
2171 0 : move16();
2172 : }
2173 : }
2174 : }
2175 :
2176 9900 : if ( *isTwoDir == FALSE )
2177 : {
2178 : /* Further checks will be done with just one direction */
2179 0 : numDir = 1;
2180 0 : move16();
2181 : }
2182 : }
2183 :
2184 : /* Check if data over subframes is identical. Check is done by comparing to first subframe. */
2185 39626 : sfSimilar = TRUE;
2186 39626 : sf = 1;
2187 39626 : move16();
2188 39626 : move16();
2189 :
2190 39626 : test();
2191 90352 : WHILE( ( sfSimilar == TRUE ) && ( sf < MAX_PARAM_SPATIAL_SUBFRAMES ) )
2192 : {
2193 50726 : sfSimilar = are_masa_subframes_similar_fx( hMeta, 0, hMeta, sf );
2194 50726 : sf = (Word8) add( sf, 1 );
2195 50726 : move16();
2196 : }
2197 39626 : IF( sfSimilar == TRUE )
2198 5550 : sfDiffer = FALSE;
2199 : ELSE
2200 34076 : sfDiffer = TRUE;
2201 39626 : move16();
2202 :
2203 : /* Further checks can be done with just one subframe if they are identical */
2204 39626 : IF( EQ_16( sfDiffer, TRUE ) )
2205 34076 : nSubFrames = MAX_PARAM_SPATIAL_SUBFRAMES;
2206 : ELSE
2207 5550 : nSubFrames = 1;
2208 39626 : move16();
2209 :
2210 : /* Check spread coherence */
2211 39626 : dir = 0;
2212 39626 : move16();
2213 39626 : test();
2214 79252 : WHILE( cohPresent == FALSE && ( dir < numDir ) )
2215 : {
2216 39626 : sf = 0;
2217 39626 : move16();
2218 39626 : test();
2219 82138 : WHILE( cohPresent == FALSE && ( sf < nSubFrames ) )
2220 : {
2221 42512 : band = 0;
2222 42512 : move16();
2223 42512 : test();
2224 277843 : WHILE( cohPresent == FALSE /*has value zero*/ && ( band < MASA_FREQUENCY_BANDS ) )
2225 : {
2226 : /* Check coherences for presence of coherence */
2227 235331 : IF( GT_16( hMeta->directional_meta[dir].spread_coherence_fx[sf][band] /*Q15*/, MASA_COHERENCE_THRESHOLD_FX >> 16 ) ) /*Q15*/
2228 : {
2229 37829 : cohPresent = TRUE;
2230 37829 : move16();
2231 : }
2232 235331 : band = (Word8) add( band, 1 );
2233 235331 : move16();
2234 : }
2235 42512 : sf = (Word8) add( sf, 1 );
2236 42512 : move16();
2237 : }
2238 39626 : dir = (Word8) add( dir, 1 );
2239 39626 : move16();
2240 : }
2241 :
2242 : /* Check surround coherence separately if we do not have already knowledge of coherence */
2243 39626 : IF( cohPresent == FALSE )
2244 : {
2245 : Word32 surround_coherence_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
2246 : Word32 diffuse_to_total_ratio_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
2247 : Word16 i, j;
2248 8985 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2249 : {
2250 179700 : FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
2251 : {
2252 172512 : surround_coherence_fx[i][j] = L_deposit_h( hMeta->common_meta.surround_coherence_fx[i][j] ); /*q31*/
2253 172512 : diffuse_to_total_ratio_fx[i][j] = L_shl_sat( hMeta->common_meta.diffuse_to_total_ratio_fx[i][j], 1 ); /*q31*/
2254 : }
2255 : }
2256 1797 : cohPresent = ivas_masa_surrcoh_signicant_fx( surround_coherence_fx, diffuse_to_total_ratio_fx, nSubFrames, MASA_FREQUENCY_BANDS );
2257 : }
2258 :
2259 : /* Set output flags */
2260 39626 : IF( EQ_16( sfDiffer, TRUE ) )
2261 : {
2262 34076 : *joinedSubframes = FALSE;
2263 : }
2264 : ELSE
2265 : {
2266 5550 : *joinedSubframes = TRUE;
2267 : }
2268 39626 : move16();
2269 39626 : *coherencePresent = cohPresent;
2270 39626 : move16();
2271 :
2272 39626 : return;
2273 : }
2274 :
2275 :
2276 : /* Check and compensate energy ratios. This function verifies that energy ratios follow the principle of summing to one.
2277 : * In addition, it implements simple remainder-to-total handling where remainder energy is proportionally added to other
2278 : * ratios. */
2279 39626 : static void compensate_energy_ratios_fx(
2280 : MASA_ENCODER_HANDLE hMasa )
2281 : {
2282 : Word16 sf, band, dir;
2283 : Word32 ratioSum;
2284 : MASA_METADATA_HANDLE hMeta;
2285 : UWord8 numDirs;
2286 :
2287 39626 : hMeta = &( hMasa->masaMetadata );
2288 39626 : numDirs = hMasa->config.numberOfDirections;
2289 39626 : move16();
2290 :
2291 198130 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2292 : {
2293 3962600 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
2294 : {
2295 : /* Remainder is always set to zero and energy removal is compensated in following steps
2296 : * to other ratios. */
2297 3804096 : hMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0; // Q30
2298 3804096 : move32();
2299 :
2300 3804096 : ratioSum = 0;
2301 3804096 : move32();
2302 8558592 : FOR( dir = 0; dir < numDirs; dir++ )
2303 : {
2304 4754496 : ratioSum = L_add( ratioSum, hMeta->directional_meta[dir].energy_ratio_fx[sf][band] ); // Q30
2305 : }
2306 3804096 : ratioSum = L_add( ratioSum, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] ); // Q30
2307 :
2308 3804096 : IF( ratioSum == 0 )
2309 : {
2310 0 : FOR( dir = 0; dir < numDirs; dir++ )
2311 : {
2312 0 : hMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0; // Q30
2313 0 : move32();
2314 : }
2315 0 : hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30; // Q30
2316 0 : move32();
2317 : }
2318 : // ELSE IF( NE_32( ratioSum, ONE_IN_Q30 ) )
2319 : ELSE /* Removing the check against 1 works well!!! */
2320 : {
2321 : Word16 exp_diff;
2322 8558592 : FOR( dir = 0; dir < numDirs; dir++ )
2323 : {
2324 9508992 : hMeta->directional_meta[dir].energy_ratio_fx[sf][band] =
2325 4754496 : BASOP_Util_Divide3232_Scale_newton( hMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum, &exp_diff );
2326 4754496 : move32();
2327 4754496 : hMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( hMeta->directional_meta[dir].energy_ratio_fx[sf][band], sub( exp_diff, Q1 ) ); // Q30
2328 4754496 : move32();
2329 : }
2330 7608192 : hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] =
2331 3804096 : BASOP_Util_Divide3232_Scale_newton( hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum, &exp_diff );
2332 3804096 : move32();
2333 3804096 : hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], sub( exp_diff, Q1 ) ); // Q30
2334 3804096 : move32();
2335 : }
2336 : }
2337 : }
2338 :
2339 39626 : return;
2340 : }
2341 :
2342 :
2343 : /* If the bit budget is very low, reduce metadata further to either 1 subframe and 5 bands, or 1 band and 4 subframes, based on which works better */
2344 25011 : static void reduce_metadata_further_fx(
2345 : MASA_ENCODER_HANDLE hMasa,
2346 : IVAS_QMETADATA_HANDLE hqmetadata,
2347 : const IVAS_FORMAT ivas_format )
2348 : {
2349 : Word16 sf;
2350 : Word16 band;
2351 : Word16 selectedBand;
2352 : Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][LOWBITRATE_NUM_BANDS];
2353 : Word64 W_tmp;
2354 : Word32 totalEnergySum;
2355 : UWord8 numCodingBands;
2356 : UWord8 computeCoherence;
2357 : Word32 onset_filter;
2358 : Word16 onset_filter_e, exp;
2359 : Word64 bandEnergy;
2360 : Word32 bandEnergy32;
2361 : Word16 bandEnergy_exp, shift;
2362 : UWord8 mergeOverFreqBands;
2363 : Word32 meanRatio;
2364 : Word16 tmp, tmp2, q_totalEnergySum;
2365 :
2366 25011 : numCodingBands = hMasa->config.numCodingBands;
2367 25011 : test();
2368 25011 : computeCoherence = hMasa->config.useCoherence && hMasa->config.coherencePresent;
2369 25011 : move16();
2370 25011 : move16();
2371 :
2372 : /* Set default values */
2373 25011 : selectedBand = 0;
2374 25011 : mergeOverFreqBands = 0;
2375 25011 : move16();
2376 25011 : move16();
2377 :
2378 : /* Get energy for the input data in 4-subframe, 5-band format */
2379 25011 : W_tmp = 0;
2380 25011 : move64();
2381 25011 : test();
2382 25011 : IF( EQ_32( ivas_format, MASA_FORMAT ) || EQ_32( ivas_format, MASA_ISM_FORMAT ) ) /* Energy data is in 4-subframe, 24-band format */
2383 : {
2384 84280 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2385 : {
2386 : Word16 brange[2];
2387 : Word32 eneSum;
2388 : Word16 m;
2389 :
2390 404544 : FOR( band = 0; band < numCodingBands; band++ )
2391 : {
2392 337120 : brange[0] = hMasa->data.band_mapping[band];
2393 337120 : brange[1] = hMasa->data.band_mapping[band + 1];
2394 337120 : move16();
2395 337120 : move16();
2396 :
2397 337120 : eneSum = 0;
2398 337120 : move32();
2399 1949840 : FOR( m = brange[0]; m < brange[1]; m++ )
2400 : {
2401 1612720 : eneSum = L_add( eneSum, hMasa->data.energy_fx[sf][m] ); // hMasa->data.q_energy
2402 : }
2403 337120 : energy[sf][band] = eneSum; // hMasa->data.q_energy
2404 337120 : move32();
2405 337120 : W_tmp = W_add( W_tmp, eneSum ); // hMasa->data.q_energy
2406 : }
2407 : }
2408 : }
2409 : ELSE /* Energy data is already in 4-subframe, 5-band format */
2410 : {
2411 40775 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2412 : {
2413 195720 : FOR( band = 0; band < numCodingBands; band++ )
2414 : {
2415 163100 : energy[sf][band] = hMasa->data.energy_fx[sf][band]; // hMasa->data.q_energy
2416 163100 : move32();
2417 163100 : W_tmp = W_add( W_tmp, energy[sf][band] ); // hMasa->data.q_energy
2418 : }
2419 : }
2420 : }
2421 :
2422 25011 : IF( W_tmp != 0 )
2423 : {
2424 25011 : tmp2 = sub( W_norm( W_tmp ), 1 ); // Usage of guard bits to avoid the large values of onset_detector in multiplication
2425 : }
2426 : ELSE
2427 : {
2428 0 : tmp2 = 0;
2429 0 : move16();
2430 : }
2431 :
2432 25011 : tmp2 = s_min( 32, tmp2 );
2433 25011 : totalEnergySum = W_extract_h( W_shl( W_tmp, tmp2 ) );
2434 25011 : tmp2 = sub( tmp2, 32 );
2435 25011 : q_totalEnergySum = add( hMasa->data.q_energy, tmp2 );
2436 :
2437 : /* Determine onsets */
2438 25011 : hMasa->data.onset_detector_1_fx = Mpy_32_32( hMasa->data.onset_detector_1_fx, LOWBITRATE_ONSET_ALPHA_Q31 );
2439 25011 : move32();
2440 :
2441 25011 : tmp = hMasa->data.q_onset_detector;
2442 25011 : move16();
2443 25011 : IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.onset_detector_1_fx, sub( 31, hMasa->data.q_onset_detector ), totalEnergySum, sub( 31, q_totalEnergySum ) ) < 0 )
2444 : {
2445 24488 : hMasa->data.onset_detector_1_fx = totalEnergySum; // hMasa->data.q_energy
2446 24488 : hMasa->data.q_onset_detector = add( hMasa->data.q_energy, tmp2 );
2447 24488 : move32();
2448 24488 : move16();
2449 :
2450 24488 : shift = norm_l( hMasa->data.onset_detector_2_fx );
2451 24488 : hMasa->data.onset_detector_2_fx = L_shl( hMasa->data.onset_detector_2_fx, shift );
2452 24488 : move32();
2453 24488 : tmp = add( tmp, shift );
2454 : }
2455 25011 : IF( LT_16( tmp, hMasa->data.q_onset_detector ) )
2456 : {
2457 234 : hMasa->data.onset_detector_1_fx = L_shr( hMasa->data.onset_detector_1_fx, sub( hMasa->data.q_onset_detector, tmp ) ); // tmp
2458 234 : hMasa->data.onset_detector_2_fx = L_add( Mpy_32_32( LOWBITRATE_ONSET_BETA_Q31, hMasa->data.onset_detector_2_fx ), Mpy_32_32( ( ONE_IN_Q31 - LOWBITRATE_ONSET_BETA_Q31 ), hMasa->data.onset_detector_1_fx ) ); // tmp
2459 234 : hMasa->data.q_onset_detector = tmp;
2460 234 : move32();
2461 234 : move32();
2462 234 : move16();
2463 : }
2464 : ELSE
2465 : {
2466 24777 : hMasa->data.onset_detector_2_fx = L_add( L_shr( Mpy_32_32( LOWBITRATE_ONSET_BETA_Q31, hMasa->data.onset_detector_2_fx ), sub( tmp, hMasa->data.q_onset_detector ) ), Mpy_32_32( ( ONE_IN_Q31 - LOWBITRATE_ONSET_BETA_Q31 ), hMasa->data.onset_detector_1_fx ) ); // hMasa->data.q_onset_detector
2467 24777 : move32();
2468 : }
2469 25011 : hMasa->data.onset_detector_2_fx = L_shl( Mpy_32_32( LOWBITRATE_ONSET_GAIN_Q30, L_min( hMasa->data.onset_detector_1_fx, hMasa->data.onset_detector_2_fx ) ), 1 ); // hMasa->data.q_onset_detector
2470 25011 : move32();
2471 :
2472 25011 : IF( hMasa->data.onset_detector_1_fx != 0 )
2473 : {
2474 25011 : onset_filter = L_max( BASOP_Util_Divide3232_Scale_newton( hMasa->data.onset_detector_2_fx, hMasa->data.onset_detector_1_fx, &onset_filter_e ), 0 );
2475 :
2476 25011 : IF( BASOP_Util_Cmp_Mant32Exp( onset_filter, onset_filter_e, ONE_IN_Q31, 0 ) > 0 )
2477 : {
2478 19273 : onset_filter = ONE_IN_Q31;
2479 19273 : onset_filter_e = 0;
2480 19273 : move32();
2481 19273 : move16();
2482 : }
2483 : }
2484 : ELSE
2485 : {
2486 0 : onset_filter = ONE_IN_Q31;
2487 0 : onset_filter_e = 0;
2488 0 : move32();
2489 0 : move16();
2490 : }
2491 : /* If we have onset, continue checking if we should reduce in frequency instead of time. */
2492 25011 : IF( BASOP_Util_Cmp_Mant32Exp( onset_filter, onset_filter_e, 2126008812 /* 0.99f in Q31 */, 0 ) < 0 )
2493 : {
2494 : /* Determine one frequency band to use to represent all frequency bands */
2495 23519 : FOR( band = numCodingBands - 1; band >= 0; band-- )
2496 : {
2497 : Word32 threshold;
2498 : Word32 bandRatio;
2499 :
2500 : // threshold = totalEnergySum / ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 0.5f; /* Average energy multiplied with energy ratio of 0.5f */
2501 23440 : threshold = BASOP_Util_Divide3232_Scale_newton( totalEnergySum, ( MAX_PARAM_SPATIAL_SUBFRAMES * LOWBITRATE_NUM_BANDS ) * 2, &exp ); /* Average energy multiplied with energy ratio of 0.5f */
2502 23440 : exp = add( exp, sub( sub( 31, add( hMasa->data.q_energy, tmp2 ) ), 31 ) );
2503 23440 : bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[0]; // Q30
2504 23440 : move32();
2505 :
2506 23440 : bandEnergy = 0;
2507 23440 : move64();
2508 117200 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2509 : {
2510 93760 : bandEnergy = W_mac_32_32( bandEnergy, energy[sf][band], 1 );
2511 : }
2512 23440 : shift = W_norm( bandEnergy );
2513 23440 : bandEnergy32 = W_extract_h( W_shl( bandEnergy, shift ) );
2514 23440 : bandEnergy_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
2515 :
2516 23440 : IF( BASOP_Util_Cmp_Mant32Exp( Mpy_32_32( L_shr( bandEnergy32, 2 ), bandRatio ), add( 1, bandEnergy_exp ), threshold, exp ) > 0 )
2517 : {
2518 5600 : selectedBand = band;
2519 5600 : move16();
2520 5600 : BREAK;
2521 : }
2522 : }
2523 :
2524 : /* Determine if to merge over frequency instead of time */
2525 5679 : W_tmp = 0;
2526 5679 : move64();
2527 28395 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2528 : {
2529 136296 : FOR( band = 0; band < numCodingBands; band++ )
2530 : {
2531 113580 : W_tmp = W_mac_32_16( W_tmp, Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ), 1 ); // hMasa->data.q_energy
2532 : }
2533 : }
2534 5679 : shift = W_norm( W_tmp );
2535 5679 : meanRatio = W_extract_h( W_shl( W_tmp, shift ) ); // Q:sub( add( hMasa->data.q_energy, shift ), 32 )
2536 5679 : shift = sub( 31, sub( add( hMasa->data.q_energy, shift ), 32 ) );
2537 :
2538 5679 : IF( totalEnergySum != 0 )
2539 : {
2540 5679 : meanRatio = BASOP_Util_Divide3232_Scale_newton( meanRatio, totalEnergySum, &exp );
2541 5679 : exp = add( exp, sub( shift, sub( 31, add( hMasa->data.q_energy, tmp2 ) ) ) ); // exp + (shift - (31 - hMasa->data.q_energy - tmp2)) => 1 + tmp2
2542 : }
2543 : ELSE
2544 : {
2545 0 : meanRatio = MAX_32;
2546 0 : exp = 31;
2547 0 : move32();
2548 0 : move16();
2549 : }
2550 :
2551 : /* If the ratio of the selected band is larger than the average ratio of all bands and if there is an onset, merge over frequency bands.
2552 : * Otherwise, merge over subframes. */
2553 5679 : IF( BASOP_Util_Cmp_Mant32Exp( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[0], 1, meanRatio, exp ) > 0 )
2554 : {
2555 4001 : mergeOverFreqBands = 1;
2556 4001 : move16();
2557 : }
2558 : ELSE
2559 : {
2560 1678 : mergeOverFreqBands = 0;
2561 1678 : move16();
2562 : }
2563 : }
2564 : ELSE
2565 : {
2566 19332 : mergeOverFreqBands = 0;
2567 19332 : move16();
2568 : }
2569 :
2570 : /* Merge values over subframes or frequency bands, depending on which one is less important */
2571 25011 : IF( !mergeOverFreqBands ) /* Merge values over subframes */
2572 : {
2573 : Word32 xSum, ySum, zSum;
2574 : Word64 W_xSum_sq, W_ySum_sq;
2575 : Word32 bandSumEnergy;
2576 : Word16 aziRad, eleRad, q_shift, exp_diff;
2577 : Word32 x, y, z;
2578 : Word32 veclen, L_tmp;
2579 :
2580 21010 : W_tmp = 0;
2581 21010 : move64();
2582 126060 : FOR( band = 0; band < numCodingBands; band++ )
2583 : {
2584 105050 : xSum = 0;
2585 105050 : ySum = 0;
2586 105050 : zSum = 0;
2587 105050 : bandSumEnergy = 0;
2588 105050 : move32();
2589 105050 : move32();
2590 105050 : move32();
2591 105050 : move32();
2592 :
2593 525250 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2594 : {
2595 420200 : aziRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].azimuth_fx[sf], PI_OVER_180_Q22 ) );
2596 420200 : eleRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].elevation_fx[sf], PI_OVER_180_Q22 ) );
2597 420200 : veclen = Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ); // hMasa->data.q_energy - 1
2598 :
2599 420200 : x = Mpy_32_32( L_mult( getCosWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2600 420200 : move32();
2601 420200 : y = Mpy_32_32( L_mult0( getSinWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2602 420200 : move32();
2603 420200 : z = Mpy_32_32( L_mult0( getSinWord16( eleRad ), ONE_IN_Q14 ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2604 420200 : move32();
2605 :
2606 420200 : xSum = L_add( xSum, x );
2607 420200 : ySum = L_add( ySum, y );
2608 420200 : zSum = L_add( zSum, z );
2609 :
2610 420200 : W_tmp = W_add( W_tmp, energy[sf][band] );
2611 : }
2612 :
2613 105050 : tmp2 = W_norm( W_tmp );
2614 105050 : tmp2 = s_min( 32, tmp2 );
2615 105050 : bandSumEnergy = W_extract_h( W_shl( W_tmp, tmp2 ) );
2616 105050 : tmp2 = sub( add( hMasa->data.q_energy, tmp2 ), 32 );
2617 :
2618 105050 : aziRad = BASOP_util_atan2( ySum, xSum, 0 ); // Q13
2619 105050 : W_xSum_sq = W_mult0_32_32( xSum, xSum ); // 2 * hMasa->data.q_energy - Q6
2620 105050 : W_ySum_sq = W_mult0_32_32( ySum, ySum ); // 2 * hMasa->data.q_energy - Q6
2621 105050 : W_tmp = W_add( W_xSum_sq, W_ySum_sq ); // 2 * hMasa->data.q_energy - Q6
2622 105050 : q_shift = W_norm( W_tmp );
2623 105050 : L_tmp = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 * hMasa->data.q_energy - Q6 + (q_shift -32)
2624 105050 : exp_diff = sub( Q31, add( sub( imult1616( 2, hMasa->data.q_energy ), Q6 ), sub( q_shift, 32 ) ) );
2625 105050 : L_tmp = Sqrt32( L_tmp, &exp_diff );
2626 105050 : eleRad = BASOP_util_atan2( zSum, L_tmp, sub( sub( 34, hMasa->data.q_energy ), exp_diff ) ); // Q13
2627 :
2628 105050 : hqmetadata->q_direction[0].band_data[band].azimuth_fx[0] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, aziRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
2629 105050 : hqmetadata->q_direction[0].band_data[band].elevation_fx[0] = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, eleRad ), Q1 ); // ((Q25, Q13) -> Q23) >> Q1 -> Q22
2630 :
2631 : /* Energy ratio is already merged through time */
2632 105050 : test();
2633 105050 : IF( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
2634 : {
2635 : Word16 spreadCoh;
2636 27180 : Word32 spreadCohSum = 0;
2637 27180 : move32();
2638 135900 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2639 : {
2640 108720 : spreadCoh = div_s( (Word16) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf], 255 ); // Q15
2641 108720 : spreadCohSum = L_add( spreadCohSum, Mpy_32_16_1( energy[sf][band], spreadCoh ) );
2642 : }
2643 : // hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (uint8_t) roundf( spreadCohSum / ( bandSumEnergy + EPSILON ) * 255.0f );
2644 27180 : tmp = BASOP_Util_Divide3232_Scale( spreadCohSum, bandSumEnergy, &exp );
2645 27180 : exp = add( exp, sub( tmp2, hMasa->data.q_energy ) );
2646 27180 : tmp = mult_r( tmp, 32640 /* 255 in Q7 */ ); // 15 - exp + 7 - 15 => 7 - exp
2647 27180 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (UWord8) shr( tmp, sub( 7, exp ) ); // Q0
2648 27180 : move16();
2649 :
2650 : /* Copy spread coherence to the rest of subframes for the coherence coding algorithm. */
2651 108720 : FOR( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2652 : {
2653 81540 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0]; // Q0
2654 81540 : move16();
2655 : }
2656 :
2657 : /* Surround coherence is already merged through time */
2658 : }
2659 : }
2660 :
2661 21010 : hqmetadata->q_direction->cfg.nblocks = 1;
2662 21010 : hMasa->config.joinedSubframes = 1;
2663 21010 : move16();
2664 21010 : move16();
2665 : }
2666 : ELSE /* Merge values over frequency bands */
2667 : {
2668 : /* Use the selected frequency band to represent all data */
2669 20005 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2670 : {
2671 16004 : hqmetadata->q_direction[0].band_data[0].azimuth_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth_fx[sf]; // Q22
2672 16004 : hqmetadata->q_direction[0].band_data[0].elevation_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation_fx[sf]; // Q22
2673 16004 : hqmetadata->q_direction[0].band_data[0].energy_ratio_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[sf]; // Q30
2674 16004 : move32();
2675 16004 : move32();
2676 16004 : move32();
2677 16004 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2678 : {
2679 5408 : hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf]; // Q0
2680 5408 : move16();
2681 : }
2682 16004 : IF( hqmetadata->surcoh_band_data != NULL )
2683 : {
2684 5408 : hqmetadata->surcoh_band_data[0].surround_coherence[sf] = hqmetadata->surcoh_band_data[selectedBand].surround_coherence[sf];
2685 5408 : move16();
2686 : }
2687 : }
2688 :
2689 : /* Copy coherence to rest of bands for the coherence coding algorithm. */
2690 20005 : FOR( band = 1; band < numCodingBands; band++ )
2691 : {
2692 16004 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2693 : {
2694 27040 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2695 : {
2696 21632 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf]; // Q0
2697 21632 : move16();
2698 : }
2699 : }
2700 16004 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2701 : {
2702 27040 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2703 : {
2704 21632 : hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
2705 21632 : move16();
2706 : }
2707 : }
2708 : }
2709 :
2710 4001 : hqmetadata->q_direction[0].cfg.nbands = 1;
2711 4001 : move16();
2712 : }
2713 :
2714 25011 : return;
2715 : }
2716 :
2717 :
2718 11680 : static Word16 encode_lfe_to_total_energy_ratio_fx(
2719 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */
2720 : BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */
2721 : const Word32 ivas_total_brate /* i : IVAS total bitrate */
2722 : )
2723 : {
2724 : Word16 i;
2725 : Word16 xq;
2726 : Word16 VQLevels;
2727 : Word32 maxLFESubFrameEner;
2728 : Word16 maxLFESubFrameEner_e;
2729 : Word32 log2LFEaverage;
2730 : Word32 log2LFEratio[4];
2731 : Word32 xqv[4];
2732 : Word32 linearLFEaverage;
2733 : Word16 linearLFEaverage_e;
2734 : Word16 lfeToTotalEnergyRatioIndices[3];
2735 : Word16 lfeAdaptiveVQBits;
2736 : Word16 lfeBitsWritten;
2737 : Word32 maxVal;
2738 : Word16 maxVal_e;
2739 :
2740 11680 : VQLevels = 0;
2741 11680 : move16();
2742 11680 : lfeAdaptiveVQBits = 0;
2743 11680 : move16();
2744 :
2745 : /* Determine maximum amount of LFE energy in any subframe */
2746 11680 : maxLFESubFrameEner = 0; // maxLFESubFrameEner_e
2747 11680 : move32();
2748 11680 : maxLFESubFrameEner_e = 0;
2749 11680 : move16();
2750 58400 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2751 : {
2752 46720 : IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxLFESubFrameEner, maxLFESubFrameEner_e ) > 0 )
2753 : {
2754 4607 : maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio_fx[i]; // hMasa->data.lfeToTotalEnergyRatio_e[i]
2755 4607 : move32();
2756 4607 : maxLFESubFrameEner_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
2757 4607 : move16();
2758 : }
2759 : }
2760 :
2761 : /* Set default values for the indices */
2762 46720 : FOR( i = 0; i < 3; i++ )
2763 : {
2764 35040 : lfeToTotalEnergyRatioIndices[i] = 0;
2765 35040 : move16();
2766 : }
2767 :
2768 : /* Check if there is enough energy in any subframe. If not, send only 1 bit (0) and abort. */
2769 : /* If there is enough LFE energy at least in one subframe, quantize it. */
2770 11680 : IF( BASOP_Util_Cmp_Mant32Exp( maxLFESubFrameEner, maxLFESubFrameEner_e, 10737418 /* 0.005f in Q31 */, 0 ) > 0 )
2771 : {
2772 : /* Convert energy to log2 domain, and clamp it to reasonable values */
2773 1904 : log2LFEaverage = 0; // Q25
2774 1904 : move32();
2775 9520 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2776 : {
2777 : // log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
2778 7616 : maxVal = 2147484 /* 0.001f in Q31 */;
2779 7616 : move32();
2780 7616 : maxVal_e = 0;
2781 7616 : move16();
2782 7616 : IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxVal, maxVal_e ) > 0 )
2783 : {
2784 7374 : maxVal = hMasa->data.lfeToTotalEnergyRatio_fx[i];
2785 7374 : move32();
2786 7374 : maxVal_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
2787 7374 : move16();
2788 : }
2789 7616 : log2LFEratio[i] = L_add( BASOP_Util_Log2( maxVal ), L_shl( maxVal_e, Q25 ) ); // Q25
2790 7616 : move32();
2791 7616 : IF( GT_32( log2LFEratio[i], ONE_IN_Q25 ) ) /* Corresponds to linear value 2.0f */
2792 : {
2793 0 : log2LFEratio[i] = ONE_IN_Q25; // Q25
2794 0 : move32();
2795 : }
2796 7616 : ELSE IF( LT_32( log2LFEratio[i], -301989888 /* -9.0f in Q25 */ ) )
2797 : {
2798 289 : log2LFEratio[i] = -301989888 /* -9.0f in Q25 */; // Q25
2799 289 : move32();
2800 : }
2801 7616 : log2LFEaverage = L_add( log2LFEaverage, Mpy_32_32( 536870912 /* 0.25f in Q31 */, log2LFEratio[i] ) ); // Q25
2802 : }
2803 :
2804 1904 : IF( EQ_32( ivas_total_brate, IVAS_13k2 ) )
2805 : {
2806 : /* Calculate adaptive 1-bit LFE quantizer index */
2807 : // linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
2808 175 : linearLFEaverage = BASOP_util_Pow2( log2LFEaverage, Q31 - Q25, &linearLFEaverage_e ); /* Convert back to linear domain */
2809 175 : linearLFEaverage = L_shl_sat( linearLFEaverage, sub( linearLFEaverage_e, Q1 ) ); // Q30
2810 175 : test();
2811 175 : IF( GT_32( linearLFEaverage, MCMASA_LFE_1BIT_THRES_Q30 ) &&
2812 : GT_32( linearLFEaverage, L_add( L_add( MCMASA_LFE_BETA_Q30 >> Q1, L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q2 ) ),
2813 : L_shr( Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ), Q1 ) ) ) )
2814 : {
2815 128 : lfeToTotalEnergyRatioIndices[0] = 1;
2816 128 : move16();
2817 128 : IF( EQ_16( hMasa->data.prevq_lfeIndex, 1 ) )
2818 : {
2819 86 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_add( L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ), 125627793 /* MCMASA_LFE_THETA * MCMASA_LFE_BETA in Q30 */ ); /* larger "bump-up" to LFE-to-total energy ratio */ // Q30
2820 86 : move32();
2821 : }
2822 : ELSE
2823 : {
2824 42 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_add( L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ), MCMASA_LFE_BETA_Q30 ); /* default "bump-up" to LFE-to-total energy ratio */ // Q30
2825 42 : move32();
2826 : }
2827 : }
2828 : ELSE
2829 : {
2830 47 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ); /* exponential decay */ // Q30
2831 47 : move32();
2832 : }
2833 :
2834 175 : IF( GE_32( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, ONE_IN_Q30 ) )
2835 : {
2836 0 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = ONE_IN_Q31; // Q31
2837 0 : move32();
2838 : }
2839 : ELSE
2840 : {
2841 175 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_shl( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ); // Q31
2842 175 : move32();
2843 : }
2844 175 : hMasa->data.prevq_lfeIndex = lfeToTotalEnergyRatioIndices[0]; /* Update to previous frame's index memories */
2845 175 : move16();
2846 : }
2847 : ELSE /* Bitrate >= 16.4 kbps */
2848 : {
2849 : /* Do 1st stage scalar quantization */
2850 1729 : lfeToTotalEnergyRatioIndices[0] = 1;
2851 1729 : move16();
2852 1729 : lfeToTotalEnergyRatioIndices[1] = usquant_fx( extract_l( L_shr( log2LFEaverage, Q14 ) ), &xq, MCMASA_LFE_QLOW_Q11, MCMASA_LFE_DELTA_Q10, 8 );
2853 1729 : move16();
2854 :
2855 1729 : IF( GE_32( ivas_total_brate, IVAS_24k4 ) ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
2856 : {
2857 : /* Remove scalar value from the vector*/
2858 8120 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2859 : {
2860 6496 : log2LFEratio[i] = L_sub( log2LFEratio[i], L_shl( xq, Q14 ) ); // Q25
2861 6496 : move32();
2862 : }
2863 :
2864 : /* Vector quantize residual with energy adaptive bit allocation */
2865 1624 : SWITCH( lfeToTotalEnergyRatioIndices[1] )
2866 : {
2867 222 : case 0:
2868 : case 1:
2869 222 : VQLevels = 0;
2870 222 : move16();
2871 222 : lfeAdaptiveVQBits = 0;
2872 222 : move16();
2873 222 : BREAK;
2874 98 : case 2:
2875 98 : VQLevels = 2;
2876 98 : move16();
2877 98 : lfeAdaptiveVQBits = 1;
2878 98 : move16();
2879 98 : BREAK;
2880 97 : case 3:
2881 97 : VQLevels = 4;
2882 97 : move16();
2883 97 : lfeAdaptiveVQBits = 2;
2884 97 : move16();
2885 97 : BREAK;
2886 246 : case 4:
2887 246 : VQLevels = 8;
2888 246 : move16();
2889 246 : lfeAdaptiveVQBits = 3;
2890 246 : move16();
2891 246 : BREAK;
2892 961 : default:
2893 961 : VQLevels = 16;
2894 961 : move16();
2895 961 : lfeAdaptiveVQBits = 4;
2896 961 : move16();
2897 : }
2898 :
2899 1624 : IF( VQLevels > 0 )
2900 : {
2901 1402 : lfeToTotalEnergyRatioIndices[2] = vquant_ivas_fx( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors_fx, 4, VQLevels );
2902 1402 : move16();
2903 : }
2904 : }
2905 : }
2906 : }
2907 :
2908 : /* Write first LFE bit */
2909 11680 : lfeBitsWritten = 0;
2910 11680 : move16();
2911 11680 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
2912 11680 : lfeBitsWritten = add( lfeBitsWritten, 1 );
2913 :
2914 11680 : test();
2915 11680 : IF( EQ_16( lfeToTotalEnergyRatioIndices[0], 1 ) && GE_32( ivas_total_brate, IVAS_16k4 ) )
2916 : {
2917 : /* If bitrate >= 16.4kbit/s, send 1-bit on/off + 3-bit scalar */
2918 1729 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
2919 1729 : lfeBitsWritten = add( lfeBitsWritten, 3 );
2920 :
2921 : /* If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
2922 1729 : IF( GE_32( ivas_total_brate, IVAS_24k4 ) )
2923 : {
2924 : /* Vector quantize residual with energy adaptive bit allocation */
2925 1624 : IF( lfeAdaptiveVQBits > 0 )
2926 : {
2927 1402 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
2928 1402 : lfeBitsWritten = add( lfeBitsWritten, lfeAdaptiveVQBits );
2929 : }
2930 : }
2931 : }
2932 :
2933 11680 : return lfeBitsWritten;
2934 : }
2935 :
2936 :
2937 : /*-------------------------------------------------------------------*
2938 : * ivas_masa_enc_reconfigure()
2939 : *
2940 : * Reconfigure IVAS MASA encoder
2941 : *-------------------------------------------------------------------*/
2942 :
2943 30626 : void ivas_masa_enc_reconfigure_fx(
2944 : Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
2945 : )
2946 : {
2947 : Word16 n, tmp;
2948 : Word16 sce_id, cpe_id;
2949 : Word32 ivas_total_brate;
2950 : Word32 ism_total_brate;
2951 : Word32 tmp_br, tmp_mod;
2952 :
2953 30626 : ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
2954 30626 : move32();
2955 :
2956 30626 : ism_total_brate = 0;
2957 30626 : move32();
2958 30626 : test();
2959 30626 : test();
2960 30626 : test();
2961 30626 : test();
2962 30626 : IF( EQ_32( st_ivas->hEncoderConfig->ivas_format, MASA_ISM_FORMAT ) && st_ivas->nSCE > 0 && ( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) )
2963 : {
2964 0 : FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
2965 : {
2966 0 : ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[sce_id]->element_brate );
2967 : }
2968 : }
2969 :
2970 30626 : IF( NE_32( ivas_total_brate, st_ivas->hEncoderConfig->last_ivas_total_brate ) )
2971 : {
2972 1269 : iDiv_and_mod_32( ivas_total_brate, st_ivas->nchan_transport, &tmp_br, &tmp_mod, 0 );
2973 1934 : FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
2974 : {
2975 665 : copy_encoder_config_fx( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
2976 665 : st_ivas->hSCE[sce_id]->element_brate = tmp_br;
2977 665 : st_ivas->hSCE[sce_id]->hCoreCoder[0]->total_brate = st_ivas->hSCE[sce_id]->element_brate; /* dummy initialization for getting right pointers initialization of input buffers in init_coder_ace_plus() */
2978 665 : move32();
2979 665 : move32();
2980 : }
2981 :
2982 1873 : FOR( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
2983 : {
2984 604 : st_ivas->hCPE[cpe_id]->element_brate = imult3216( tmp_br, 2 ); //( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
2985 604 : move32();
2986 :
2987 604 : IF( GT_16( st_ivas->nCPE, 1 ) )
2988 : {
2989 0 : tmp = 1;
2990 : }
2991 : ELSE
2992 : {
2993 604 : tmp = CPE_CHANNELS;
2994 : }
2995 604 : move16();
2996 : /* prepare bitstream buffers */
2997 1812 : FOR( n = 0; n < CPE_CHANNELS; n++ )
2998 : {
2999 1208 : copy_encoder_config_fx( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
3000 : /* st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = st_ivas->hCPE[cpe_id]->element_brate / ( st_ivas->nCPE > 1 ? 1 : CPE_CHANNELS ); */
3001 1208 : st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = L_shr( st_ivas->hCPE[cpe_id]->element_brate, sub( tmp, 1 ) ); /* dummy initialization for getting right pointers initialization of input buffers in init_coder_ace_plus() */
3002 1208 : move32();
3003 : }
3004 :
3005 604 : IF( LT_32( L_sub( ivas_total_brate, ism_total_brate ), MIN_BRATE_MDCT_STEREO ) )
3006 : {
3007 218 : st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
3008 : }
3009 : ELSE
3010 : {
3011 386 : st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
3012 : }
3013 604 : move16();
3014 : }
3015 :
3016 1269 : ivas_masa_set_elements_fx( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &tmp, &tmp, &tmp, st_ivas->hEncoderConfig->ivas_format, st_ivas->ism_mode, ism_total_brate );
3017 : }
3018 :
3019 30626 : return;
3020 : }
3021 :
3022 :
3023 : /*-------------------------------------------------------------------*
3024 : * average_masa_metadata()
3025 : *
3026 : * Average MASA metadata frame subframe contents: applies aggregation over time
3027 : *-------------------------------------------------------------------*/
3028 :
3029 0 : static void average_masa_metadata_fx(
3030 : MASA_METADATA_FRAME *hMeta,
3031 : Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /*i Q(31 - energy_e) */
3032 : Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /*i:stores exponent values for energy_e*/
3033 : const SPHERICAL_GRID_DATA *Sph_Grid16,
3034 : const UWord8 useSphGrid )
3035 : {
3036 : Word16 i, j, k;
3037 : Word16 azi_rad_fx, ele_rad_fx;
3038 : UWord8 numDirections;
3039 :
3040 : /* use the nominal values without data-adaptivity */
3041 0 : numDirections = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 );
3042 0 : move16();
3043 :
3044 : /* azi/ele/nrg into vectors for each sub-frame and band */
3045 0 : FOR( i = 0; i < numDirections; i++ )
3046 : {
3047 0 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
3048 : {
3049 : Word32 x_sum_fx, y_sum_fx, z_sum_fx, energy_sum_fx, vec_len_fx, spread_coh_sum_fx, surr_coh_sum_fx, temp1, temp2;
3050 : Word16 vec_len_e, x_sum_e, y_sum_e, z_sum_e, energy_sum_e, spread_coh_sum_e, surr_coh_sum_e, temp1_e, temp2_e;
3051 0 : x_sum_fx = 0;
3052 0 : y_sum_fx = 0;
3053 0 : z_sum_fx = 0;
3054 0 : energy_sum_fx = 0;
3055 0 : spread_coh_sum_fx = 0;
3056 0 : surr_coh_sum_fx = 0;
3057 0 : x_sum_e = 0; /*exponent for x_sum_fx*/
3058 0 : y_sum_e = 0; /*exponent for y_sum_fx*/
3059 0 : z_sum_e = 0; /*exponent for z_sum_fx*/
3060 0 : energy_sum_e = 0; /*exponent for energy_sum_fx*/
3061 0 : spread_coh_sum_e = 0; /*exponent for spread_coh_sum_fx*/
3062 0 : surr_coh_sum_e = 0; /*exponent for surr_coh_sum_fx*/
3063 0 : temp1 = 0; /* to store temporary computations*/
3064 0 : temp2 = 0; /* to store temporary computations*/
3065 0 : temp1_e = 0; /*to store temporary exponents*/
3066 0 : temp2_e = 0; /*to store temporary exponents*/
3067 0 : move32();
3068 0 : move32();
3069 0 : move32();
3070 0 : move32();
3071 0 : move32();
3072 0 : move32();
3073 0 : move32();
3074 0 : move32();
3075 0 : move16();
3076 0 : move16();
3077 0 : move16();
3078 0 : move16();
3079 0 : move16();
3080 0 : move16();
3081 0 : move16();
3082 0 : move16();
3083 :
3084 0 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3085 : {
3086 0 : azi_rad_fx = extract_l( Mpy_32_32( hMeta->directional_meta[i].azimuth_fx[j][k], 46603 /*1/(360) in Q24*/ ) ); /*=angle *(1/2pi) brings the azi_rad_fx in -32767 to 32767 in q15 (this argument is further passed in cos and sin functions)*/ /*22+24-31=15*/
3087 0 : ele_rad_fx = extract_l( Mpy_32_32( hMeta->directional_meta[i].elevation_fx[j][k], 46603 /*1/(360) in Q24*/ ) ); /*=angle *(1/2pi) brings the azi_rad_fx in -32767 to 32767 in q15 (this argument is further passed in cos and sin functions)*/ /*22+24-31=15*/
3088 0 : vec_len_fx = Mpy_32_32( hMeta->directional_meta[i].energy_ratio_fx[j][k] /*q30*/, energy[j][k] ); /*exponent=energy_e+1*/
3089 0 : vec_len_e = add( energy_e[j][k], 1 );
3090 :
3091 : /* energy-weighted sum over subframes */
3092 0 : x_sum_fx = BASOP_Util_Add_Mant32Exp( x_sum_fx, x_sum_e, Mpy_32_32( L_mult( getCosWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ) /*q31*/, vec_len_fx ), vec_len_e, &x_sum_e ); /*x_sum_e*/
3093 0 : y_sum_fx = BASOP_Util_Add_Mant32Exp( y_sum_fx, y_sum_e, Mpy_32_32( L_mult( getSineWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ) /*q31*/, vec_len_fx ), vec_len_e, &y_sum_e ); /*y_sum_e*/
3094 0 : z_sum_fx = BASOP_Util_Add_Mant32Exp( z_sum_fx, z_sum_e, Mpy_32_16_1( vec_len_fx, getSineWord16R2( ele_rad_fx ) /*q15*/ ), vec_len_e, &z_sum_e ); /*z_sum_e*/
3095 :
3096 0 : energy_sum_fx = BASOP_Util_Add_Mant32Exp( energy_sum_fx, energy_sum_e, energy[j][k], energy_e[j][k], &energy_sum_e ); /*energy_sum_e*/
3097 :
3098 0 : spread_coh_sum_fx = BASOP_Util_Add_Mant32Exp( spread_coh_sum_fx, spread_coh_sum_e, Mpy_32_16_1( energy[j][k], hMeta->directional_meta[i].spread_coherence_fx[j][k] ), energy_e[j][k], &spread_coh_sum_e ); /*spread_coh_sum_e*/
3099 0 : IF( i == 0 )
3100 : {
3101 : /* this is in common metadata and not in each direction */
3102 0 : surr_coh_sum_fx = BASOP_Util_Add_Mant32Exp( surr_coh_sum_fx, surr_coh_sum_e, Mpy_32_16_1( energy[j][k], hMeta->common_meta.surround_coherence_fx[j][k] ), energy_e[j][k], &surr_coh_sum_e ); /*surr_coh_sum_e*/
3103 : }
3104 : }
3105 :
3106 : /* the data from the combined sub-frames is written into the first sub-frame band */
3107 0 : j = 0;
3108 0 : move16();
3109 0 : hMeta->directional_meta[i].azimuth_fx[j][k] = Mpy_32_16_1( 961263669 /*(1/ EVS_PI * 180.0f) in Q24*/, BASOP_util_atan2( y_sum_fx, x_sum_fx, sub( y_sum_e, x_sum_e ) ) /*q13*/ ); /*24+13-15=22*/
3110 0 : move32();
3111 0 : temp1 = BASOP_Util_Add_Mant32Exp( Mpy_32_32( x_sum_fx, x_sum_fx ), shl( x_sum_e, 1 ), Mpy_32_32( y_sum_fx, y_sum_fx ), shl( y_sum_e, 1 ), &temp1_e ); /*temp1_e*/
3112 0 : temp2_e = temp1_e;
3113 0 : temp2 = Sqrt32( temp1, &temp2_e ); /*temp2_e*/
3114 0 : hMeta->directional_meta[i].elevation_fx[j][k] = Mpy_32_16_1( 961263669 /*(1/ EVS_PI * 180.0f) in Q24*/, BASOP_util_atan2( z_sum_fx, temp2, sub( z_sum_e, temp2_e ) ) /*q13*/ ); /*24+13-15=22*/
3115 0 : move32();
3116 0 : IF( EQ_16( useSphGrid, TRUE ) )
3117 : {
3118 :
3119 0 : hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16_fx( &( hMeta->directional_meta[i].elevation_fx[j][k] ),
3120 0 : &( hMeta->directional_meta[i].azimuth_fx[j][k] ), Sph_Grid16 );
3121 0 : move16();
3122 : }
3123 0 : vec_len_fx = BASOP_Util_Add_Mant32Exp( temp1, temp1_e, Mpy_32_32( z_sum_fx, z_sum_fx ), shl( z_sum_e, 1 ), &vec_len_e ); /*vec_len_e*/ /*x_sum * x_sum + y_sum * y_sum + z_sum * z_sum*/
3124 0 : vec_len_fx = Sqrt32( vec_len_fx, &vec_len_e ); /*vec_len_e*/
3125 0 : hMeta->directional_meta[i].energy_ratio_fx[j][k] = BASOP_Util_Divide3232_Scale( vec_len_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e ); /*temp2_e*/
3126 0 : move32();
3127 0 : temp2_e = add( temp2_e, sub( vec_len_e, energy_sum_e ) );
3128 0 : hMeta->directional_meta[i].energy_ratio_fx[j][k] = L_shl( hMeta->directional_meta[i].energy_ratio_fx[j][k], add( temp2_e, 15 ) ); /*changing q from 15-temp2_e to q30*/
3129 0 : move32();
3130 0 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( spread_coh_sum_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e );
3131 0 : move16();
3132 0 : temp2_e = add( temp2_e, sub( spread_coh_sum_e, energy_sum_e ) );
3133 0 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = shl( hMeta->directional_meta[i].spread_coherence_fx[j][k], temp2_e ); /*changing q from 15-temp2_e to q15*/
3134 0 : move16();
3135 0 : IF( i == 0 )
3136 : {
3137 0 : hMeta->common_meta.surround_coherence_fx[j][k] = BASOP_Util_Divide3232_Scale( surr_coh_sum_fx, L_add( energy_sum_fx, EPSILON_FX ), &temp2_e );
3138 0 : move16();
3139 0 : temp2_e = add( temp2_e, sub( surr_coh_sum_e, energy_sum_e ) );
3140 0 : hMeta->common_meta.surround_coherence_fx[j][k] = shl_sat( hMeta->common_meta.surround_coherence_fx[j][k], temp2_e ); /*changing q from 15-temp2_e to q15*/
3141 0 : move16();
3142 : }
3143 :
3144 : /* copy the same value to all subframes */
3145 0 : FOR( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3146 : {
3147 0 : hMeta->directional_meta[i].azimuth_fx[j][k] = hMeta->directional_meta[i].azimuth_fx[0][k]; /*q22*/
3148 0 : hMeta->directional_meta[i].elevation_fx[j][k] = hMeta->directional_meta[i].elevation_fx[0][k]; /*q22*/
3149 0 : hMeta->directional_meta[i].energy_ratio_fx[j][k] = hMeta->directional_meta[i].energy_ratio_fx[0][k]; /*q30*/
3150 0 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = hMeta->directional_meta[i].spread_coherence_fx[0][k]; /*q15*/
3151 0 : move32();
3152 0 : move32();
3153 0 : move32();
3154 0 : move16();
3155 0 : IF( i == 0 )
3156 : {
3157 0 : hMeta->common_meta.surround_coherence_fx[j][k] = hMeta->common_meta.surround_coherence_fx[0][k]; /*q15*/
3158 0 : move16();
3159 : }
3160 : }
3161 : }
3162 : }
3163 :
3164 0 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
3165 : {
3166 0 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3167 : {
3168 0 : IF( EQ_16( numDirections, 2 ) )
3169 : {
3170 0 : hMeta->common_meta.diffuse_to_total_ratio_fx[j][k] = L_max( 0, L_sub( L_sub( ONE_IN_Q30, hMeta->directional_meta[1].energy_ratio_fx[j][k] ), hMeta->directional_meta[0].energy_ratio_fx[j][k] ) ); /*q30*/
3171 : }
3172 : ELSE
3173 : {
3174 0 : hMeta->common_meta.diffuse_to_total_ratio_fx[j][k] = L_max( 0, L_sub( ONE_IN_Q30, hMeta->directional_meta[0].energy_ratio_fx[j][k] ) ); /*q30*/
3175 : }
3176 0 : move32();
3177 0 : hMeta->common_meta.remainder_to_total_ratio_fx[j][k] = 0; /*q30*/
3178 0 : move32();
3179 : }
3180 : }
3181 :
3182 0 : return;
3183 : }
3184 :
3185 :
3186 : /*-------------------------------------------------------------------*
3187 : * copy_masa_metadata_subframe()
3188 : *
3189 : * Copy MASA metadata frame subframe contents
3190 : *-------------------------------------------------------------------*/
3191 :
3192 158504 : static void copy_masa_metadata_subframe_fx(
3193 : const MASA_METADATA_HANDLE hMetaFrom, /* i : MASA frame metdata to be copied */
3194 : const UWord8 sfFrom, /* i : subframe index of the copy source */
3195 : MASA_METADATA_HANDLE hMetaTo, /* o : MASA frame metadata copy destination */
3196 : const UWord8 sfTo /* i : subframe index of the copy target */
3197 : )
3198 : {
3199 : UWord8 dir;
3200 : UWord8 band;
3201 :
3202 : /* directional metadata */
3203 475512 : FOR( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
3204 : {
3205 7925200 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
3206 : {
3207 7608192 : hMetaTo->directional_meta[dir].spherical_index[sfTo][band] = hMetaFrom->directional_meta[dir].spherical_index[sfFrom][band];
3208 7608192 : move16();
3209 : }
3210 317008 : Copy32( hMetaFrom->directional_meta[dir].azimuth_fx[sfFrom], hMetaTo->directional_meta[dir].azimuth_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q22
3211 317008 : Copy32( hMetaFrom->directional_meta[dir].elevation_fx[sfFrom], hMetaTo->directional_meta[dir].elevation_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q22
3212 317008 : Copy32( hMetaFrom->directional_meta[dir].energy_ratio_fx[sfFrom], hMetaTo->directional_meta[dir].energy_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3213 317008 : Copy( hMetaFrom->directional_meta[dir].spread_coherence_fx[sfFrom], hMetaTo->directional_meta[dir].spread_coherence_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q15
3214 : }
3215 :
3216 : /* common metadata */
3217 158504 : Copy32( hMetaFrom->common_meta.diffuse_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3218 158504 : Copy( hMetaFrom->common_meta.surround_coherence_fx[sfFrom], hMetaTo->common_meta.surround_coherence_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q15
3219 158504 : Copy32( hMetaFrom->common_meta.remainder_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3220 :
3221 158504 : return;
3222 : }
3223 :
3224 :
3225 : /*-------------------------------------------------------------------*
3226 : * copy_masa_metadata()
3227 : *
3228 : * Copy MASA metada frame contents
3229 : *-------------------------------------------------------------------*/
3230 :
3231 39626 : static void copy_masa_metadata_fx(
3232 : const MASA_METADATA_HANDLE hMetaFrom, /* i : MASA frame metadata to be copied */
3233 : MASA_METADATA_HANDLE hMetaTo /* o : MASA frame metadata copy destination */
3234 : )
3235 : {
3236 : UWord8 sf, byte_idx;
3237 :
3238 : /* descriptive metadata */
3239 356634 : FOR( byte_idx = 0; byte_idx < 8; byte_idx++ )
3240 : {
3241 317008 : hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
3242 317008 : move16();
3243 : }
3244 :
3245 39626 : hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
3246 39626 : hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
3247 39626 : hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
3248 39626 : hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
3249 39626 : hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
3250 39626 : hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
3251 39626 : hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
3252 39626 : move16();
3253 39626 : move16();
3254 39626 : move16();
3255 39626 : move16();
3256 39626 : move16();
3257 39626 : move16();
3258 39626 : move16();
3259 :
3260 : /* directional and common metadata */
3261 198130 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
3262 : {
3263 158504 : copy_masa_metadata_subframe_fx( hMetaFrom, sf, hMetaTo, sf );
3264 : }
3265 :
3266 39626 : return;
3267 : }
3268 :
3269 :
3270 : /*-------------------------------------------------------------------*
3271 : * are_masa_subframes_similar()
3272 : *
3273 : * Compare the similarity of MASA metadata in two sub-frames
3274 : *-------------------------------------------------------------------*/
3275 :
3276 : /* r: similarity decision */
3277 175035 : static UWord8 are_masa_subframes_similar_fx(
3278 : const MASA_METADATA_HANDLE frame1, /* i : MASA metadata frame 1 */
3279 : const UWord8 sf1_idx, /* i : index of the subframe of frame1 to inspect */
3280 : const MASA_METADATA_HANDLE frame2, /* i : MASA metadata frame 2 */
3281 : const UWord8 sf2_idx /* i : index of the subframe of frame2 to inspect */
3282 : )
3283 : {
3284 : UWord8 num_dir;
3285 : UWord8 dir;
3286 : UWord8 band_idx;
3287 : UWord8 sf_differ;
3288 :
3289 175035 : num_dir = frame1->descriptive_meta.numberOfDirections;
3290 175035 : dir = 0;
3291 175035 : band_idx = 0;
3292 175035 : sf_differ = FALSE;
3293 175035 : move16();
3294 175035 : move16();
3295 175035 : move16();
3296 175035 : move16();
3297 :
3298 175035 : IF( NE_16( num_dir, frame2->descriptive_meta.numberOfDirections ) )
3299 : {
3300 0 : sf_differ = TRUE;
3301 0 : move16();
3302 : }
3303 : ELSE
3304 : {
3305 : /* check per-direction metadata */
3306 175035 : dir = 0;
3307 175035 : band_idx = 0;
3308 175035 : move16();
3309 175035 : move16();
3310 :
3311 360870 : WHILE( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
3312 : {
3313 185835 : test();
3314 185835 : band_idx = 0;
3315 185835 : move16();
3316 1244235 : WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
3317 : {
3318 1200135 : test();
3319 : Word32 azi_dif_fx;
3320 1200135 : azi_dif_fx = L_abs( L_sub( frame1->directional_meta[dir].azimuth_fx[sf1_idx][band_idx], frame2->directional_meta[dir].azimuth_fx[sf2_idx][band_idx] ) ); // Q22
3321 1200135 : IF( GT_32( azi_dif_fx, 180 << Q22 ) )
3322 16892 : azi_dif_fx = L_sub( 360 << Q22, azi_dif_fx ); // Q22
3323 :
3324 1200135 : IF( GT_32( azi_dif_fx, ONE_IN_Q21 /*0.5 in Q22*/ ) )
3325 : {
3326 139100 : sf_differ = TRUE;
3327 139100 : move16();
3328 139100 : BREAK;
3329 : }
3330 :
3331 1061035 : IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].elevation_fx[sf1_idx][band_idx], frame2->directional_meta[dir].elevation_fx[sf2_idx][band_idx] ) ), MASA_ANGLE_TOLERANCE_FX ) )
3332 : {
3333 2616 : sf_differ = TRUE;
3334 2616 : move16();
3335 2616 : BREAK;
3336 : }
3337 :
3338 1058419 : IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].energy_ratio_fx[sf1_idx][band_idx], frame2->directional_meta[dir].energy_ratio_fx[sf2_idx][band_idx] ) ), MASA_RATIO_TOLERANCE_FX ) )
3339 : {
3340 19 : sf_differ = TRUE;
3341 19 : move16();
3342 19 : BREAK;
3343 : }
3344 :
3345 1058400 : IF( GT_32( L_abs( L_sub( frame1->directional_meta[dir].spread_coherence_fx[sf1_idx][band_idx], frame2->directional_meta[dir].spread_coherence_fx[sf2_idx][band_idx] ) ), MASA_COHERENCE_TOLERANCE_FX ) )
3346 : {
3347 0 : sf_differ = TRUE;
3348 0 : move16();
3349 0 : BREAK;
3350 : }
3351 :
3352 1058400 : band_idx = (UWord8) add( band_idx, 1 );
3353 1058400 : move16();
3354 : }
3355 185835 : dir = (UWord8) add( dir, 1 );
3356 185835 : move16();
3357 : }
3358 :
3359 : /* check the common metadata */
3360 175035 : WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
3361 : {
3362 0 : test();
3363 0 : IF( GT_32( L_abs( L_sub( frame1->common_meta.surround_coherence_fx[sf1_idx][band_idx], frame2->common_meta.surround_coherence_fx[sf2_idx][band_idx] ) ), MASA_COHERENCE_TOLERANCE_FX ) )
3364 : {
3365 0 : sf_differ = TRUE;
3366 0 : move16();
3367 0 : BREAK;
3368 : }
3369 :
3370 0 : band_idx = (UWord8) add( band_idx, 1 );
3371 0 : move16();
3372 : }
3373 : }
3374 :
3375 175035 : IF( sf_differ )
3376 : {
3377 141735 : return FALSE;
3378 : }
3379 : ELSE
3380 : {
3381 33300 : return TRUE;
3382 : }
3383 : }
3384 :
3385 :
3386 : /*-------------------------------------------------------------------*
3387 : * detect_framing_async()
3388 : *
3389 : * Compare the similarity of MASA metadata in two sub-frames
3390 : * Analysis result is stored in hMasa->data.sync_state, and
3391 : * potentially hMasa->masaMetadata is modified
3392 : *-------------------------------------------------------------------*/
3393 :
3394 39626 : static void detect_framing_async_fx(
3395 : MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
3396 : )
3397 : {
3398 : MASA_METADATA_HANDLE current_meta;
3399 : MASA_METADATA_HANDLE previous_meta;
3400 : MASA_SYNC_HANDLE sync_state;
3401 : MASA_FRAME_MODE frame_mode;
3402 : UWord8 n_sim_start, n_sim_stop, sf_idx;
3403 : UWord8 found_offset;
3404 :
3405 39626 : current_meta = &( hMasa->masaMetadata ); /* metadata from current frame */
3406 39626 : sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
3407 39626 : previous_meta = &( sync_state->previous_metadata );
3408 :
3409 : /* check current frame, how many are similar from the start and from the end */
3410 39626 : n_sim_start = 1;
3411 39626 : move16();
3412 56276 : FOR( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
3413 : {
3414 50726 : IF( EQ_16( are_masa_subframes_similar_fx( current_meta, 0, current_meta, sf_idx ), TRUE ) )
3415 : {
3416 16650 : n_sim_start = (UWord8) add( sf_idx, 1 );
3417 16650 : move16();
3418 : }
3419 : ELSE
3420 : {
3421 34076 : BREAK;
3422 : }
3423 : }
3424 :
3425 : /* number of similar sub-frames starting from the end of the frame */
3426 39626 : IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) ) /* shortcut */
3427 : {
3428 5550 : n_sim_stop = n_sim_start;
3429 5550 : move16();
3430 : }
3431 : ELSE
3432 : {
3433 34076 : n_sim_stop = 1;
3434 34076 : move16();
3435 34076 : FOR( sf_idx = 2; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
3436 : {
3437 : /* we need to check only the two middle sub-frames, as all being the same would have taken the shortcut above */
3438 34076 : IF( EQ_16( are_masa_subframes_similar_fx( current_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1, current_meta, (UWord8) sub( MAX_PARAM_SPATIAL_SUBFRAMES, sf_idx ) ), TRUE ) )
3439 : {
3440 0 : n_sim_stop = sf_idx;
3441 0 : move16();
3442 : }
3443 : ELSE
3444 : {
3445 34076 : BREAK;
3446 : }
3447 : }
3448 : }
3449 :
3450 39626 : frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
3451 39626 : move16();
3452 39626 : IF( GT_16( sync_state->prev_offset, MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) )
3453 : {
3454 : /* earlier offset was large => reset the offset */
3455 0 : found_offset = 0;
3456 : }
3457 : ELSE
3458 : {
3459 : /* keep previous offset unless something else is found. alternatively, we could reset always */
3460 39626 : found_offset = sync_state->prev_offset;
3461 : }
3462 39626 : move16();
3463 :
3464 39626 : test();
3465 39626 : test();
3466 39626 : IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) && EQ_16( n_sim_stop, MAX_PARAM_SPATIAL_SUBFRAMES ) )
3467 : {
3468 : /* full frame consists of similar sub-frames */
3469 5550 : frame_mode = MASA_FRAME_1SF;
3470 5550 : move16();
3471 5550 : test();
3472 5550 : IF( ( sync_state->prev_sim_stop != 0 ) && EQ_16( are_masa_subframes_similar_fx( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ), TRUE ) )
3473 : {
3474 : /* > 4 sub-frames of similar data */
3475 0 : IF( LT_16( sync_state->prev_sim_stop, 3 ) )
3476 : {
3477 : /* can nicely align the framing with the earlier data and a small offset */
3478 0 : found_offset = sync_state->prev_sim_stop;
3479 : }
3480 : ELSE
3481 : {
3482 : /* too many similar sub-frames to determine the offset accurately => keep earlier value */
3483 0 : found_offset = sync_state->prev_offset;
3484 : }
3485 0 : move16();
3486 : }
3487 : ELSE
3488 : {
3489 : /* earlier window was different => reset the offset */
3490 5550 : found_offset = 0;
3491 5550 : move16();
3492 : }
3493 : }
3494 34076 : ELSE IF( EQ_16( n_sim_stop, 3 ) )
3495 : {
3496 : /* first sub-frame different that the rest 3
3497 : => make a risky guess that the future sf would be the same too and we're in an offset case */
3498 0 : frame_mode = MASA_FRAME_1SF;
3499 0 : found_offset = 3;
3500 0 : move16();
3501 0 : move16();
3502 : }
3503 34076 : ELSE IF( ( sync_state->prev_sim_stop > 0 ) && EQ_16( are_masa_subframes_similar_fx( current_meta, 0, previous_meta, MAX_PARAM_SPATIAL_SUBFRAMES - 1 ), TRUE ) )
3504 : {
3505 : /* seeing data similar to past */
3506 0 : test();
3507 0 : IF( GT_16( n_sim_start, 1 ) && ( GE_16( add( n_sim_start, sync_state->prev_sim_stop ), MAX_PARAM_SPATIAL_SUBFRAMES ) ) )
3508 : {
3509 : /* with the past, would have at least one long frame similar subframes */
3510 0 : frame_mode = MASA_FRAME_1SF;
3511 0 : move16();
3512 :
3513 0 : IF( sync_state->prev_offset == 0 )
3514 : {
3515 0 : found_offset = (UWord8) s_min( 2, sync_state->prev_sim_stop );
3516 : }
3517 : ELSE
3518 : {
3519 0 : found_offset = sync_state->prev_offset;
3520 0 : move16();
3521 : }
3522 : }
3523 : }
3524 :
3525 : /* keep the original contents of the frame, but then perform interpolation later */
3526 : /* just copy current frame to storage */
3527 39626 : copy_masa_metadata_fx( current_meta, previous_meta );
3528 :
3529 39626 : sync_state->prev_sim_stop = n_sim_stop;
3530 39626 : sync_state->prev_offset = found_offset;
3531 39626 : sync_state->frame_mode = frame_mode;
3532 39626 : move16();
3533 39626 : move16();
3534 39626 : move16();
3535 :
3536 39626 : return;
3537 : }
3538 :
3539 :
3540 : /*-------------------------------------------------------------------*
3541 : * masa_metadata_direction_alignment()
3542 : *
3543 : * In 2dir MASA metadata, determine the ordering of the directional
3544 : * fields such that the azi/ele change across time is minimized.
3545 : *-------------------------------------------------------------------*/
3546 :
3547 39626 : static void masa_metadata_direction_alignment_fx(
3548 : MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder handle */
3549 : )
3550 : {
3551 : UWord8 band, n_dirs;
3552 : MASA_DIR_ALIGN_HANDLE hAlignState;
3553 : MASA_METADATA_HANDLE hMeta;
3554 39626 : hAlignState = &( hMasa->data.dir_align_state );
3555 39626 : hMeta = &( hMasa->masaMetadata );
3556 :
3557 39626 : n_dirs = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 ); /* 1-based */
3558 39626 : move16();
3559 990650 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
3560 : {
3561 : UWord8 sf;
3562 : Word32 diff_swap_fx;
3563 : Word32 diff_no_swap_fx;
3564 :
3565 : /* trade 2*(cos+sin) against storing the values between frames */
3566 : Word16 prev_ele_dir1_sin_fx, prev_ele_dir2_sin_fx;
3567 : Word16 prev_ele_dir1_cos_fx, prev_ele_dir2_cos_fx;
3568 :
3569 951024 : prev_ele_dir1_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3570 951024 : prev_ele_dir2_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3571 :
3572 951024 : prev_ele_dir1_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3573 951024 : prev_ele_dir2_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3574 :
3575 4755120 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
3576 : {
3577 : Word32 azi_rad1_fx, ele_rad1_fx;
3578 : Word32 azi_rad2_fx, ele_rad2_fx;
3579 : Word16 cos_ele1_fx, cos_ele2_fx;
3580 : Word16 sin_ele1_fx, sin_ele2_fx;
3581 : Word16 temp1;
3582 : Word32 temp2;
3583 : Word16 temp1_e;
3584 :
3585 :
3586 3804096 : azi_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3587 3804096 : ele_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3588 :
3589 3804096 : IF( GT_16( n_dirs, 1 ) )
3590 : {
3591 950400 : azi_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3592 950400 : ele_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3593 :
3594 950400 : test();
3595 950400 : test();
3596 950400 : test();
3597 950400 : test();
3598 950400 : test();
3599 950400 : test();
3600 : /* quick checks to detect constant data and earlier flip */
3601 950400 : IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
3602 : LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
3603 : LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) &&
3604 : LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) )
3605 : {
3606 91800 : diff_swap_fx = ONE_IN_Q13; /*1 q13*/
3607 91800 : move32();
3608 91800 : diff_no_swap_fx = 0;
3609 91800 : move32();
3610 : /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
3611 91800 : sin_ele1_fx = prev_ele_dir1_sin_fx; /*q15*/
3612 91800 : sin_ele2_fx = prev_ele_dir2_sin_fx; /*q15*/
3613 91800 : cos_ele1_fx = prev_ele_dir1_cos_fx; /*q15*/
3614 91800 : cos_ele2_fx = prev_ele_dir2_cos_fx; /*q15*/
3615 91800 : move16();
3616 91800 : move16();
3617 91800 : move16();
3618 91800 : move16();
3619 : }
3620 858600 : ELSE IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
3621 : LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
3622 : LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) &&
3623 : LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) )
3624 : {
3625 37800 : diff_swap_fx = 0;
3626 37800 : move32();
3627 37800 : diff_no_swap_fx = ONE_IN_Q13; /*1.0 q13*/
3628 37800 : move32();
3629 : /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
3630 37800 : sin_ele1_fx = prev_ele_dir2_sin_fx; /*q15*/
3631 37800 : sin_ele2_fx = prev_ele_dir1_sin_fx; /*q15*/
3632 37800 : cos_ele1_fx = prev_ele_dir2_cos_fx; /*q15*/
3633 37800 : cos_ele2_fx = prev_ele_dir1_cos_fx; /*q15*/
3634 37800 : move16();
3635 37800 : move16();
3636 37800 : move16();
3637 37800 : move16();
3638 : }
3639 : ELSE
3640 : {
3641 : /* angular distance of the two vectors */
3642 : /* pre-compute values for re-use */
3643 820800 : sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3644 820800 : sin_ele2_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3645 :
3646 820800 : cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3647 820800 : cos_ele2_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3648 :
3649 820800 : temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir1_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3650 820800 : temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ ); /*q15*/
3651 820800 : temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir1_sin_fx ), temp1 ); /*q15*/
3652 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3653 820800 : move16();
3654 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3655 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3656 820800 : diff_no_swap_fx = L_deposit_l( temp1 ); /*q13*/
3657 :
3658 820800 : temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir2_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3659 820800 : temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ ); /*q15*/
3660 820800 : temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir2_sin_fx ), temp1 ); /*q15*/
3661 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3662 820800 : move16();
3663 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3664 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3665 820800 : diff_no_swap_fx = L_add( diff_no_swap_fx, temp1 ); /*q13*/
3666 :
3667 820800 : temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir2_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3668 820800 : temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ ); /*q15*/
3669 820800 : temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir2_sin_fx ), temp1 ); /*q15*/
3670 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3671 820800 : move16();
3672 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3673 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3674 820800 : diff_swap_fx = L_deposit_l( temp1 ); /*q13*/
3675 :
3676 820800 : temp1 = getCosWord16R2( extract_l( Mpy_32_32( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir1_fx[band] ), 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3677 820800 : temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ ); /*q15*/
3678 820800 : temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir1_sin_fx ), temp1 ); /*q15*/
3679 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3680 820800 : move16();
3681 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3682 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3683 820800 : diff_swap_fx = L_add( diff_swap_fx, temp1 ); /*q13*/
3684 : }
3685 : }
3686 : ELSE
3687 : {
3688 : /* 1dir */
3689 2853696 : sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3690 2853696 : cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3691 :
3692 2853696 : azi_rad2_fx = 0;
3693 2853696 : ele_rad2_fx = 0;
3694 2853696 : move32();
3695 2853696 : move32();
3696 :
3697 2853696 : sin_ele2_fx = 0; /* sin(0) */
3698 2853696 : cos_ele2_fx = MAX_16; /* cos(0) in Q15*/
3699 2853696 : move16();
3700 2853696 : move16();
3701 :
3702 2853696 : diff_swap_fx = ONE_IN_Q13; /*1.0 in Q13*/
3703 2853696 : diff_no_swap_fx = 0;
3704 2853696 : move32();
3705 2853696 : move32();
3706 : }
3707 :
3708 3804096 : test();
3709 3804096 : IF( GT_16( n_dirs, 1 ) && GT_32( diff_no_swap_fx, diff_swap_fx ) )
3710 121788 : {
3711 : /* swap the metadata of the two directions in this TF-tile */
3712 : Word32 tmp_val;
3713 : Word16 tmp_val_16;
3714 : UWord16 tmp_int_val;
3715 121788 : tmp_val = hMeta->directional_meta[0].azimuth_fx[sf][band]; /*q22*/
3716 121788 : hMeta->directional_meta[0].azimuth_fx[sf][band] = hMeta->directional_meta[1].azimuth_fx[sf][band]; /*q22*/
3717 121788 : hMeta->directional_meta[1].azimuth_fx[sf][band] = tmp_val; /*q22*/
3718 121788 : move32();
3719 121788 : move32();
3720 121788 : move32();
3721 :
3722 121788 : tmp_val = hMeta->directional_meta[0].elevation_fx[sf][band]; /*q22*/
3723 121788 : hMeta->directional_meta[0].elevation_fx[sf][band] = hMeta->directional_meta[1].elevation_fx[sf][band]; /*q22*/
3724 121788 : hMeta->directional_meta[1].elevation_fx[sf][band] = tmp_val; /*q22*/
3725 121788 : move32();
3726 121788 : move32();
3727 121788 : move32();
3728 :
3729 121788 : tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band]; /*q0*/
3730 121788 : hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band]; /*q0*/
3731 121788 : hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val; /*q0*/
3732 121788 : move32();
3733 121788 : move32();
3734 121788 : move32();
3735 :
3736 121788 : tmp_val = hMeta->directional_meta[0].energy_ratio_fx[sf][band]; /*q30*/
3737 121788 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = hMeta->directional_meta[1].energy_ratio_fx[sf][band]; /*q30*/
3738 121788 : hMeta->directional_meta[1].energy_ratio_fx[sf][band] = tmp_val; /*q30*/
3739 121788 : move32();
3740 121788 : move32();
3741 121788 : move32();
3742 :
3743 121788 : tmp_val_16 = hMeta->directional_meta[0].spread_coherence_fx[sf][band]; /*q15*/
3744 121788 : hMeta->directional_meta[0].spread_coherence_fx[sf][band] = hMeta->directional_meta[1].spread_coherence_fx[sf][band]; /*q15*/
3745 121788 : hMeta->directional_meta[1].spread_coherence_fx[sf][band] = tmp_val_16; /*q15*/
3746 121788 : move16();
3747 121788 : move16();
3748 121788 : move16();
3749 :
3750 121788 : hAlignState->previous_azi_dir1_fx[band] = azi_rad2_fx; /*q22*/
3751 121788 : hAlignState->previous_ele_dir1_fx[band] = ele_rad2_fx; /*q22*/
3752 121788 : move32();
3753 121788 : move32();
3754 :
3755 121788 : hAlignState->previous_azi_dir2_fx[band] = azi_rad1_fx; /*q22*/
3756 121788 : hAlignState->previous_ele_dir2_fx[band] = ele_rad1_fx; /*q22*/
3757 121788 : move32();
3758 121788 : move32();
3759 :
3760 121788 : prev_ele_dir1_cos_fx = cos_ele2_fx; /*q15*/
3761 121788 : prev_ele_dir1_sin_fx = sin_ele2_fx; /*q15*/
3762 121788 : move16();
3763 121788 : move16();
3764 :
3765 121788 : prev_ele_dir2_cos_fx = cos_ele1_fx; /*q15*/
3766 121788 : prev_ele_dir2_sin_fx = sin_ele1_fx; /*q15*/
3767 121788 : move16();
3768 121788 : move16();
3769 : }
3770 : ELSE
3771 : {
3772 3682308 : hAlignState->previous_azi_dir1_fx[band] = azi_rad1_fx; /*q22*/
3773 3682308 : hAlignState->previous_ele_dir1_fx[band] = ele_rad1_fx; /*q22*/
3774 3682308 : move32();
3775 3682308 : move32();
3776 :
3777 3682308 : hAlignState->previous_azi_dir2_fx[band] = azi_rad2_fx; /*q22*/
3778 3682308 : hAlignState->previous_ele_dir2_fx[band] = ele_rad2_fx; /*q22*/
3779 3682308 : move32();
3780 3682308 : move32();
3781 :
3782 3682308 : prev_ele_dir1_cos_fx = cos_ele1_fx; /*q15*/
3783 3682308 : prev_ele_dir1_sin_fx = sin_ele1_fx; /*q15*/
3784 3682308 : move16();
3785 3682308 : move16();
3786 :
3787 3682308 : prev_ele_dir2_cos_fx = cos_ele2_fx; /*q15*/
3788 3682308 : prev_ele_dir2_sin_fx = sin_ele2_fx; /*q15*/
3789 3682308 : move16();
3790 3682308 : move16();
3791 : }
3792 : } /* sf */
3793 : } /* band */
3794 :
3795 39626 : return;
3796 : }
3797 :
3798 :
3799 : /*-------------------------------------------------------------------*
3800 : * ivas_merge_masa_metadata()
3801 : *
3802 : *
3803 : *-------------------------------------------------------------------*/
3804 :
3805 3996 : void ivas_merge_masa_metadata_fx(
3806 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA enc handle. source for MASA metadata and combined metadata will be here */
3807 : OMASA_SPATIAL_META_HANDLE hOMasaMeta /* i : ISM-object metadata to be merged with the MASA metadata */
3808 : )
3809 : {
3810 : Word16 sf, band;
3811 : UWord8 numCodingBands;
3812 : UWord8 numDirections;
3813 : UWord8 numSf;
3814 : MASA_METADATA_HANDLE hMeta;
3815 : Word16 energyTimesRatioMASA_e[2];
3816 : Word16 total_diff_nrg_e;
3817 : Word16 energyMerged_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
3818 : Word32 energyTimesRatioISM_fx; /*energyTimesRatioISM_e*/
3819 : Word16 energyTimesRatioISM_e;
3820 : Word32 energyTimesRatioMASA_fx[2]; /*energyTimesRatioMASA_e*/
3821 : Word32 total_diff_nrg_fx;
3822 : Word32 eneBand_fx; /*eneBand_e*/
3823 : Word16 eneBand_e;
3824 : Word32 energyMerged_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; /*energyMerged_e*/
3825 3996 : OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hMasa->data.hOmasaData->hOmasaEnergy;
3826 : Word32 temp1 /*temp1_e*/, temp2 /*temp2_e*/;
3827 : Word16 temp1_e, temp2_e;
3828 :
3829 3996 : numCodingBands = hMasa->config.numCodingBands;
3830 3996 : numDirections = hMasa->config.numberOfDirections;
3831 3996 : IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
3832 : {
3833 0 : numSf = 1;
3834 : }
3835 : ELSE
3836 : {
3837 3996 : numSf = MAX_PARAM_SPATIAL_SUBFRAMES;
3838 : }
3839 3996 : move16();
3840 3996 : move16();
3841 3996 : move16();
3842 3996 : hMeta = &( hMasa->masaMetadata );
3843 :
3844 19980 : FOR( sf = 0; sf < numSf; sf++ )
3845 : {
3846 396000 : FOR( band = 0; band < numCodingBands; band++ )
3847 : {
3848 : Word16 merge_dest;
3849 : Word32 dir_sum_fx; /*dir_sum_e*/
3850 : Word16 dir_sum_e;
3851 : UWord8 band_n_dirs;
3852 380016 : test();
3853 380016 : test();
3854 380016 : IF( EQ_16( numDirections, 1 ) || ( EQ_16( numDirections, 2 ) && hMasa->data.twoDirBands[band] == 0 ) )
3855 : {
3856 380016 : band_n_dirs = 1;
3857 : }
3858 : ELSE
3859 : {
3860 0 : band_n_dirs = 2;
3861 : }
3862 380016 : move16();
3863 :
3864 : /* Compute energies */
3865 380016 : eneBand_fx = hMasa->data.energy_fx[sf][band];
3866 380016 : eneBand_e = hMasa->data.energy_e[sf][band];
3867 380016 : move32();
3868 380016 : move16();
3869 380016 : energyMerged_fx[sf][band] = BASOP_Util_Add_Mant32Exp( eneBand_fx, eneBand_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energyMerged_e[sf][band] );
3870 380016 : move32();
3871 :
3872 : /* Compute weights */
3873 380016 : energyTimesRatioMASA_fx[0] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] );
3874 380016 : energyTimesRatioMASA_e[0] = add( eneBand_e, 1 );
3875 380016 : move32();
3876 380016 : move16();
3877 380016 : IF( EQ_16( band_n_dirs, 2 ) )
3878 : {
3879 0 : energyTimesRatioMASA_fx[1] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[1].energy_ratio_fx[sf][band] ); // energyTimesRatioMASA_e
3880 0 : energyTimesRatioMASA_e[1] = add( eneBand_e, 1 );
3881 : }
3882 : ELSE
3883 : {
3884 380016 : energyTimesRatioMASA_fx[1] = 0; // energyTimesRatioMASA_e
3885 380016 : energyTimesRatioMASA_e[1] = 0;
3886 : }
3887 380016 : move32();
3888 380016 : move16();
3889 :
3890 : /* target is original MASA diffuseness */
3891 380016 : total_diff_nrg_fx = Mpy_32_32( eneBand_fx, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] ); // total_diff_nrg_e
3892 380016 : total_diff_nrg_e = add( eneBand_e, 1 );
3893 :
3894 : /* criterion is mean of ISM ratio and new ratio */
3895 380016 : temp1 = BASOP_Util_Add_Mant32Exp( L_add( EPSILON_FX, eneBand_fx ), eneBand_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &temp1_e ); /* EPSILON + eneBand + hMasa->data.hOmasaData->energy_ism[sf][band]*/
3896 380016 : temp2 = L_deposit_h( BASOP_Util_Divide3232_Scale( total_diff_nrg_fx, temp1, &temp2_e ) ); /*temp2_e*/ /*total_diff_nrg / ( EPSILON + eneBand + hMasa->data.hOmasaData->energy_ism[sf][band] )*/
3897 380016 : temp2_e = add( temp2_e, sub( total_diff_nrg_e, temp1_e ) );
3898 380016 : IF( temp2_e < 0 )
3899 : {
3900 283974 : temp2 = L_shl( temp2, temp2_e );
3901 283974 : temp2_e = 0;
3902 283974 : move16();
3903 : }
3904 380016 : temp2 = L_sub( L_shl_sat( 1, sub( 31, temp2_e ) ), temp2 ); /*( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) )*/
3905 380016 : temp2 = BASOP_Util_Add_Mant32Exp( hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band], 1, temp2, temp2_e, &temp2_e ); /*( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) )*/
3906 380016 : energyTimesRatioISM_fx = Mpy_32_32( L_shr( temp2, 1 ), hOmasaEnergy->energy_ism_fx[sf][band] ); /*energyTimesRatioISM_e*/
3907 380016 : energyTimesRatioISM_e = add( temp2_e, hOmasaEnergy->energy_ism_fx_e[sf][band] );
3908 : /*energyTimesRatioISM = ( hOMasaMeta->directional_meta[0].energy_ratio[sf][band] + ( 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] ) ) ) / 2.0f * hOmasaEnergy->energy_ism[sf][band];*/
3909 :
3910 : /* Determine combined metadata based on the weights */
3911 380016 : merge_dest = -1;
3912 380016 : move16();
3913 380016 : test();
3914 380016 : test();
3915 380016 : test();
3916 380016 : test();
3917 380016 : test();
3918 380016 : test();
3919 380016 : IF( ( EQ_16( band_n_dirs, 1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) ) ||
3920 : ( EQ_16( band_n_dirs, 2 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1] ), -1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) ) )
3921 : {
3922 : /* 1dir and ISM the most energetic, or 2dir and ISM the more energetic than MASA1 */
3923 143404 : merge_dest = 0;
3924 : }
3925 236612 : ELSE IF( EQ_16( band_n_dirs, 2 ) && NE_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1], energyTimesRatioMASA_fx[0], energyTimesRatioMASA_e[0] ), 1 ) && EQ_16( BASOP_Util_Cmp_Mant32Exp( energyTimesRatioMASA_fx[1], energyTimesRatioMASA_e[1], energyTimesRatioISM_fx, energyTimesRatioISM_e ), -1 ) )
3926 : {
3927 : /* 2dir and ISM the most energetic and MASA2 the least energetic */
3928 0 : merge_dest = 1;
3929 : }
3930 380016 : move16();
3931 :
3932 380016 : IF( merge_dest >= 0 ) /* replace one MASA with ISM */
3933 : {
3934 143404 : hMeta->directional_meta[merge_dest].azimuth_fx[sf][band] = hOMasaMeta->directional_meta[0].azimuth_fx[sf][band]; /*q22*/
3935 143404 : hMeta->directional_meta[merge_dest].elevation_fx[sf][band] = hOMasaMeta->directional_meta[0].elevation_fx[sf][band]; /*q22*/
3936 143404 : move32();
3937 143404 : move32();
3938 : /* limit with the earlier direct-energy ratio */
3939 143404 : dir_sum_fx = temp2; /* new dir ratio */
3940 143404 : dir_sum_e = temp2_e;
3941 143404 : move32();
3942 143404 : move16();
3943 : /*dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hOmasaEnergy->energy_ism[sf][band] )*/
3944 143404 : IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( dir_sum_fx, dir_sum_e, hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band], 1 ), -1 ) )
3945 : {
3946 0 : hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = L_shl( dir_sum_fx, sub( dir_sum_e, 1 ) ); /*scaling to Q30*/
3947 : }
3948 : ELSE
3949 : {
3950 143404 : hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band]; /*q30*/
3951 143404 : move32();
3952 : }
3953 : /* clip with original ISM dir */
3954 143404 : hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_sub( ONE_IN_Q30, hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] ); /*q30*/
3955 143404 : move32();
3956 143404 : move32(); /*hMeta->directional_meta[merge_dest].energy_ratio_fx*/
3957 :
3958 143404 : IF( hMasa->config.useCoherence )
3959 : {
3960 0 : hMeta->directional_meta[merge_dest].spread_coherence_fx[sf][band] = hOMasaMeta->directional_meta[0].spread_coherence_fx[sf][band]; /*q15*/
3961 0 : hMeta->common_meta.surround_coherence_fx[sf][band] = hOMasaMeta->common_meta.surround_coherence_fx[sf][band]; /*q15*/
3962 0 : move16();
3963 0 : move16();
3964 : }
3965 :
3966 : /* recompute direct energy ratios to match the diffuse ratio */
3967 : Word32 direct_quota_fx, direct_scaler_fx;
3968 : Word16 direct_scaler_e;
3969 143404 : direct_quota_fx = L_sub( ONE_IN_Q30, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
3970 143404 : IF( EQ_16( band_n_dirs, 1 ) )
3971 : {
3972 143404 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = direct_quota_fx; /*q30*/
3973 143404 : move32();
3974 : }
3975 : ELSE
3976 : {
3977 0 : dir_sum_fx = L_add( hMeta->directional_meta[0].energy_ratio_fx[sf][band], hMeta->directional_meta[1].energy_ratio_fx[sf][band] ); /*q30*/
3978 0 : direct_scaler_fx = BASOP_Util_Divide3232_Scale( direct_quota_fx, L_add( EPSILON_FX, dir_sum_fx ), &direct_scaler_e );
3979 0 : direct_scaler_fx = L_shl( direct_scaler_fx, direct_scaler_e ); /*q31*/
3980 0 : direct_scaler_e = 0;
3981 0 : move16();
3982 0 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = Mpy_32_32( direct_scaler_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] ); /*q30*/
3983 0 : hMeta->directional_meta[1].energy_ratio_fx[sf][band] = Mpy_32_32( direct_scaler_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] ); /*q30*/
3984 0 : move32();
3985 0 : move32();
3986 : }
3987 : }
3988 : }
3989 : }
3990 :
3991 19980 : FOR( sf = 0; sf < numSf; sf++ )
3992 : {
3993 396000 : FOR( band = 0; band < numCodingBands; band++ )
3994 : {
3995 380016 : hMasa->data.energy_fx[sf][band] = energyMerged_fx[sf][band];
3996 380016 : hMasa->data.energy_e[sf][band] = energyMerged_e[sf][band];
3997 380016 : move32();
3998 380016 : move16();
3999 : }
4000 : }
4001 :
4002 3996 : return;
4003 : }
4004 :
4005 :
4006 30442 : static void quantize_ratio_ism_vector_ivas_fx(
4007 : const Word16 *ratio_ism, /* ratio_ism_e */
4008 : Word16 ratio_ism_e,
4009 : Word16 *idx, /* Q0 */
4010 : const Word16 nchan_ism,
4011 : const Word32 masa_to_total_energy_ratio,
4012 : const Word16 idx_sep_object )
4013 : {
4014 : Word16 i, j, best_i, best_i2;
4015 : Word16 dist, div, tmp, dist2, best_dist, temp, temp_e, tmp_e, idx_e, best_dist_e, dist_e, dist2_e;
4016 : Word16 part_idx_sum, max_sum_idx;
4017 : Word16 ratio_ism_loc[MAX_NUM_OBJECTS];
4018 : Word16 no_ism_loc;
4019 :
4020 30442 : max_sum_idx = sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 );
4021 :
4022 30442 : test();
4023 30442 : IF( GT_16( idx_sep_object, -1 ) )
4024 : {
4025 30442 : temp = BASOP_Util_Divide1616_Scale( 1, max_sum_idx, &temp_e );
4026 30442 : BASOP_Util_Add_MantExp( ratio_ism[idx_sep_object], ratio_ism_e, negate( temp ), temp_e, &tmp );
4027 :
4028 30442 : test();
4029 30442 : IF( tmp < 0 )
4030 : {
4031 : /* take it out from quantize function */
4032 28839 : Copy( ratio_ism, ratio_ism_loc, idx_sep_object ); // Q(15 - ratio_ism_e)
4033 28839 : Copy( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
4034 28839 : no_ism_loc = sub( nchan_ism, 1 );
4035 : }
4036 : ELSE
4037 : {
4038 1603 : no_ism_loc = nchan_ism;
4039 1603 : move16();
4040 1603 : Copy( ratio_ism, ratio_ism_loc, nchan_ism );
4041 : }
4042 : }
4043 : ELSE
4044 : {
4045 0 : no_ism_loc = nchan_ism;
4046 0 : move16();
4047 0 : Copy( ratio_ism, ratio_ism_loc, nchan_ism );
4048 : }
4049 :
4050 30442 : test();
4051 30442 : IF( GT_16( nchan_ism, 1 ) )
4052 : {
4053 30442 : test();
4054 30442 : IF( GE_32( masa_to_total_energy_ratio, MASA2TOTAL_THR_Q30 ) )
4055 : {
4056 3593 : distribute_evenly_ism_fx( idx, max_sum_idx, nchan_ism );
4057 : }
4058 : ELSE
4059 : {
4060 26849 : test();
4061 26849 : IF( GT_16( no_ism_loc, 1 ) )
4062 : {
4063 :
4064 26135 : dist = 0;
4065 26135 : dist_e = 0;
4066 26135 : div = div_s( 1, max_sum_idx ); // Q15
4067 26135 : move16();
4068 26135 : move16();
4069 :
4070 26135 : part_idx_sum = 0;
4071 26135 : move16();
4072 :
4073 95154 : FOR( i = 0; i < no_ism_loc; i++ )
4074 : {
4075 69019 : idx[i] = extract_l( L_shr( L_mult0( ratio_ism_loc[i], max_sum_idx ), sub( 15, ratio_ism_e ) ) ); // Q0
4076 69019 : move16();
4077 69019 : part_idx_sum = add( part_idx_sum, idx[i] );
4078 :
4079 69019 : tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( imult1616( idx[i], div ) ), 0, &tmp ); // tmp_e
4080 69019 : dist_e = BASOP_Util_Add_MantExp( dist, dist_e, mult( tmp, tmp ), add( tmp_e, tmp_e ), &dist ); // dist_e
4081 : }
4082 :
4083 26135 : best_dist = dist;
4084 26135 : best_dist_e = dist_e;
4085 26135 : best_i2 = -1;
4086 26135 : move16();
4087 26135 : move16();
4088 26135 : move16();
4089 :
4090 54125 : WHILE( ( part_idx_sum < max_sum_idx ) )
4091 : {
4092 27990 : best_i = -1;
4093 27990 : move16();
4094 : /* check which index to increase by 1 for a possible improvement */
4095 :
4096 102694 : FOR( i = 0; i < no_ism_loc; i++ )
4097 : {
4098 74704 : idx[i] = add( idx[i], 1 );
4099 74704 : move16();
4100 74704 : dist2 = 0;
4101 74704 : dist2_e = 0;
4102 74704 : move16();
4103 74704 : move16();
4104 :
4105 282160 : FOR( j = 0; j < no_ism_loc; j++ )
4106 : {
4107 207456 : Word32 temp1 = L_mult( idx[i], div ); // Q : 15 + 0 + 1
4108 207456 : Word16 temp1_n = norm_l( temp1 );
4109 207456 : Word16 temp1_16 = extract_h( L_shl( temp1, temp1_n ) ); // Q : Q + temp1_n - 16
4110 207456 : tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( temp1_16 ), sub( 15, temp1_n ), &tmp ); // tmp_e
4111 207456 : dist2_e = BASOP_Util_Add_MantExp( dist2, dist2_e, mult_sat( tmp, tmp ), add( tmp_e, tmp_e ), &dist2 ); // dist_e
4112 : }
4113 :
4114 74704 : BASOP_Util_Add_MantExp( dist2, dist2_e, negate( best_dist ), best_dist_e, &tmp );
4115 74704 : test();
4116 74704 : IF( tmp < 0 )
4117 : {
4118 22940 : best_i2 = best_i;
4119 22940 : best_i = i;
4120 22940 : best_dist = dist2;
4121 22940 : best_dist_e = dist2_e;
4122 22940 : move16();
4123 22940 : move16();
4124 22940 : move16();
4125 22940 : move16();
4126 : }
4127 74704 : idx[i] = sub( idx[i], 1 );
4128 74704 : move16();
4129 : }
4130 :
4131 27990 : test();
4132 27990 : IF( GT_16( best_i, -1 ) )
4133 : {
4134 21734 : idx[best_i] = add( idx[best_i], 1 );
4135 21734 : move16();
4136 21734 : part_idx_sum = add( part_idx_sum, 1 );
4137 : }
4138 : ELSE
4139 : {
4140 6256 : test();
4141 6256 : IF( GT_16( best_i2, -1 ) )
4142 : {
4143 1043 : idx[best_i2] = add( idx[best_i2], 1 );
4144 1043 : move16();
4145 1043 : part_idx_sum = add( part_idx_sum, 1 );
4146 : }
4147 : ELSE
4148 : {
4149 5213 : idx[no_ism_loc - 1] = add( idx[no_ism_loc - 1], sub( max_sum_idx, part_idx_sum ) );
4150 5213 : move16();
4151 5213 : part_idx_sum = max_sum_idx;
4152 5213 : move16();
4153 : }
4154 : }
4155 : }
4156 26135 : assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
4157 : }
4158 : ELSE
4159 : {
4160 714 : idx[0] = max_sum_idx;
4161 714 : move16();
4162 : }
4163 :
4164 26849 : test();
4165 26849 : IF( LT_16( no_ism_loc, nchan_ism ) )
4166 : {
4167 : /* insert back the ratio of the separated object */
4168 70971 : FOR( i = nchan_ism - 1; i > idx_sep_object; i-- )
4169 : {
4170 45655 : idx[i] = idx[i - 1];
4171 45655 : move16();
4172 : }
4173 25316 : idx[idx_sep_object] = 0;
4174 25316 : move16();
4175 : }
4176 : }
4177 : }
4178 : ELSE
4179 : {
4180 : // idx[0] = (int16_t) ( ( ratio_ism[0] ) * ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) + 0.5f );
4181 0 : tmp = imult1616( ratio_ism[0], sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 ) ); // tmp_e
4182 0 : tmp_e = ratio_ism_e;
4183 0 : move16();
4184 0 : idx_e = BASOP_Util_Add_MantExp( tmp, tmp_e, 16384 /* 0.5 in Q15 */, 0, &idx[0] ); // idx_e
4185 0 : idx[0] = shl( idx[0], sub( idx_e, 15 ) ); // Q0
4186 0 : move16();
4187 : }
4188 :
4189 30442 : return;
4190 : }
4191 :
4192 :
4193 6665 : static Word16 index_slice_enum_fx(
4194 : const Word16 *ratio_ism_idx,
4195 : const Word16 nchan_ism )
4196 : {
4197 : Word16 i;
4198 : Word16 x, index;
4199 : Word16 base;
4200 :
4201 6665 : IF( EQ_16( nchan_ism, 2 ) )
4202 : {
4203 308 : index = ratio_ism_idx[0];
4204 308 : move16();
4205 : }
4206 : ELSE
4207 : {
4208 6357 : x = ratio_ism_idx[nchan_ism - 2];
4209 6357 : base = 10;
4210 6357 : move16();
4211 6357 : move16();
4212 17248 : FOR( i = nchan_ism - 3; i >= 0; i-- )
4213 : {
4214 10891 : x = add( x, imult1616( ratio_ism_idx[i], base ) );
4215 10891 : base = imult1616( base, 10 );
4216 : }
4217 :
4218 6357 : index = 0;
4219 6357 : i = 0;
4220 6357 : move16();
4221 6357 : move16();
4222 928866 : WHILE( LE_16( i, x ) )
4223 : {
4224 922509 : IF( valid_ratio_index_fx( i, 7, nchan_ism - 1 ) )
4225 : {
4226 252718 : index = add( index, 1 );
4227 : }
4228 922509 : i = add( i, 1 );
4229 : }
4230 6357 : index = sub( index, 1 );
4231 : }
4232 :
4233 6665 : return index;
4234 : }
4235 :
4236 61502 : static void transform_difference_index_ivas_fx(
4237 : const Word16 *diff_idx,
4238 : Word16 *idx,
4239 : const Word16 len )
4240 : {
4241 : Word16 i;
4242 189070 : FOR( i = 0; i < len; i++ )
4243 : {
4244 127568 : IF( diff_idx[i] <= 0 )
4245 : {
4246 99618 : idx[i] = negate( shl( diff_idx[i], 1 ) );
4247 99618 : move16();
4248 : }
4249 : ELSE
4250 : {
4251 27950 : idx[i] = sub( shl( diff_idx[i], 1 ), 1 );
4252 27950 : move16();
4253 : }
4254 : }
4255 :
4256 61502 : return;
4257 : }
4258 :
4259 :
4260 20139 : static void transform_index_and_GR_encode_ivas_fx(
4261 : Word16 *diff_idx, /* i : differenc eindex to encode */
4262 : const Word16 len, /* i : input length */
4263 : const Word16 GR_order, /* i : GR order */
4264 : BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */
4265 : )
4266 : {
4267 : Word16 i;
4268 : Word16 idx[IVAS_MAX_NUM_OBJECTS];
4269 :
4270 : /* transform difference index into positive */
4271 20139 : transform_difference_index_ivas_fx( diff_idx, idx, len );
4272 :
4273 : /* GR encoding */
4274 61030 : FOR( i = 0; i < len; i++ )
4275 : {
4276 40891 : ivas_qmetadata_encode_extended_gr_fx( hMetaData, idx[i], 100, GR_order );
4277 : }
4278 :
4279 20139 : return;
4280 : }
4281 :
4282 :
4283 1862 : static Word16 try_differential_fx(
4284 : const Word16 numCodingBands,
4285 : const Word32 *masa_to_total_energy_ratio, /* Q30 */
4286 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4287 : const Word16 nchan_ism,
4288 : const Word16 bits_index,
4289 : Word16 *p_b_signif )
4290 : {
4291 : Word16 b, i;
4292 : Word16 nbits0;
4293 : Word16 b_signif;
4294 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4295 : Word16 diff_idx[MAX_NUM_OBJECTS];
4296 :
4297 1862 : b_signif = 0;
4298 1862 : move16();
4299 2162 : WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
4300 : {
4301 300 : test();
4302 300 : b_signif = add( b_signif, 1 );
4303 : }
4304 :
4305 1862 : nbits0 = 0;
4306 1862 : move16();
4307 :
4308 1862 : IF( LT_16( b_signif, numCodingBands ) )
4309 : {
4310 1806 : nbits0 = bits_index;
4311 1806 : move16();
4312 1806 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4313 :
4314 11560 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4315 : {
4316 9754 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4317 : {
4318 8627 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4319 8627 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4320 :
4321 : /* transform difference index into positive */
4322 8627 : transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( nchan_ism, 1 ) );
4323 :
4324 : /* GR encoding */
4325 30122 : FOR( i = 0; i < nchan_ism - 1; i++ )
4326 : {
4327 21495 : nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
4328 : }
4329 : }
4330 : }
4331 : }
4332 1862 : *p_b_signif = b_signif;
4333 1862 : move16();
4334 :
4335 1862 : return nbits0;
4336 : }
4337 :
4338 :
4339 666 : static void differential_coding_first_subframe_ivas_fx(
4340 : BSTR_ENC_HANDLE hMetaData,
4341 : const Word32 *masa_to_total_energy_ratio, // Q30
4342 : const Word16 b_signif,
4343 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4344 : const Word16 nchan_ism,
4345 : const Word16 numCodingBands,
4346 : const Word16 bits_index )
4347 : {
4348 : Word16 index, b;
4349 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4350 : Word16 diff_idx[MAX_NUM_OBJECTS];
4351 :
4352 : /* differential encoding*/
4353 666 : push_next_indice( hMetaData, 0, 1 );
4354 :
4355 666 : IF( LT_16( b_signif, numCodingBands ) )
4356 : {
4357 666 : index = index_slice_enum_fx( ratio_ism_idx[b_signif], nchan_ism );
4358 666 : push_next_indice( hMetaData, index, bits_index );
4359 :
4360 666 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4361 :
4362 4892 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4363 : {
4364 4226 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4365 : {
4366 3768 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4367 3768 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4368 :
4369 : /* transform difference index into positive */
4370 3768 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( nchan_ism, 1 ), 0, hMetaData );
4371 : }
4372 : }
4373 : }
4374 :
4375 666 : return;
4376 : }
4377 :
4378 :
4379 1140 : static void independent_coding_ratio_ism_idx_fx(
4380 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], /* i : ISM ratios */
4381 : const Word32 *masa_to_total_energy_ratio, /* i : MASA to total ratios, Q30 */
4382 : const Word16 nchan_ism, /* i : number of objects */
4383 : const Word16 numCodingBands, /* i : number of subbands */
4384 : const Word16 bits_index, /* i : number of bits per index */
4385 : BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */
4386 : )
4387 : {
4388 : Word16 b, index;
4389 :
4390 7844 : FOR( b = 0; b < numCodingBands; b++ )
4391 : {
4392 6704 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4393 : {
4394 5999 : index = index_slice_enum_fx( ratio_ism_idx[b], nchan_ism );
4395 5999 : push_next_indice( hMetaData, index, bits_index );
4396 : }
4397 : }
4398 :
4399 1140 : return;
4400 : }
4401 :
4402 :
4403 29124 : static void remove_sep_obj_fx(
4404 : Word16 *diff_idx, /* i/o: array of difference of indexes */
4405 : const Word16 nchan_ism, /* i : number of objects */
4406 : const Word16 idx_sep_obj /* i : index of separated object, to be taken out of array */
4407 : )
4408 : {
4409 : Word16 i;
4410 :
4411 88197 : FOR( i = idx_sep_obj; i < nchan_ism - 1; i++ )
4412 : {
4413 59073 : diff_idx[i] = diff_idx[i + 1];
4414 59073 : move16();
4415 : }
4416 :
4417 29124 : return;
4418 : }
4419 :
4420 :
4421 32736 : static void estimate_bits_subband_ism_ratio_fx(
4422 : const Word16 *ratio_ism_idx,
4423 : const Word16 *ratio_ism_idx_ref, /* ( i/o ) */
4424 : const Word16 nchan_ism,
4425 : const Word16 shift_one,
4426 : const Word16 idx_sep_obj,
4427 : Word16 *p_nbits0,
4428 : Word16 *p_nbits1 )
4429 : {
4430 : Word16 diff_idx[MAX_NUM_OBJECTS];
4431 : Word16 nbits0, nbits1;
4432 : Word16 i;
4433 :
4434 32736 : nbits0 = 0;
4435 32736 : nbits1 = 0;
4436 32736 : move16();
4437 32736 : move16();
4438 :
4439 : /* take difference with respect to previous subframe */
4440 32736 : v_sub_s16_fx( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
4441 :
4442 32736 : IF( shift_one )
4443 : {
4444 19416 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj );
4445 : }
4446 :
4447 : /* transform difference index into positive */
4448 32736 : transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( sub( nchan_ism, 1 ), shift_one ) );
4449 :
4450 : /* GR encoding */
4451 97918 : FOR( i = 0; i < nchan_ism - 1 - shift_one; i++ )
4452 : {
4453 65182 : nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
4454 65182 : nbits1 = add( nbits1, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 1 ) );
4455 : }
4456 :
4457 32736 : *p_nbits0 = nbits0;
4458 32736 : *p_nbits1 = nbits1;
4459 32736 : move16();
4460 32736 : move16();
4461 :
4462 32736 : return;
4463 : }
4464 :
4465 :
4466 5636 : static Word16 encode_ratio_ism_subframe_fx(
4467 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4468 : const Word16 nchan_ism,
4469 : const UWord8 numCodingBands,
4470 : const Word16 sf,
4471 : Word16 ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4472 : BSTR_ENC_HANDLE hMetaData,
4473 : const Word32 *masa_to_total_energy_ratio, /* Q30 */
4474 : const Word16 shift_one,
4475 : const Word16 idx_separated_obj )
4476 : {
4477 : Word16 b, b_signif;
4478 : Word16 diff_idx[MAX_NUM_OBJECTS];
4479 : Word16 nbits, nbits0, nbits1, GR_order, GR_order_sb;
4480 : Word16 differential_subframe;
4481 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4482 : Word16 bits_index;
4483 : Word16 nbits00, nbits11;
4484 : Word16 idx_sep_obj_local;
4485 :
4486 5636 : idx_sep_obj_local = idx_separated_obj;
4487 5636 : move16();
4488 5636 : IF( GT_16( idx_separated_obj, -1 ) )
4489 : {
4490 5636 : if ( EQ_16( idx_separated_obj, sub( nchan_ism, 1 ) ) )
4491 : {
4492 803 : idx_sep_obj_local = 0;
4493 803 : move16();
4494 : }
4495 : }
4496 5636 : nbits = 0;
4497 5636 : nbits0 = 0;
4498 5636 : nbits1 = 0;
4499 5636 : move16();
4500 5636 : move16();
4501 5636 : move16();
4502 :
4503 5636 : differential_subframe = 1; /* the differences are taken with respect to previous subframe */
4504 5636 : move16();
4505 :
4506 : /* first subframe */
4507 5636 : bits_index = 0;
4508 5636 : move16();
4509 5636 : IF( sf == 0 )
4510 : {
4511 1862 : bits_index = bits_index_ism_ratio_fx( nchan_ism );
4512 :
4513 1862 : nbits = 0;
4514 1862 : move16();
4515 13722 : FOR( b = 0; b < numCodingBands; b++ )
4516 : {
4517 11860 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4518 : {
4519 10433 : nbits = add( nbits, bits_index );
4520 : }
4521 : }
4522 :
4523 1862 : nbits0 = try_differential_fx( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
4524 :
4525 1862 : test();
4526 1862 : IF( LE_16( nbits, nbits0 ) && nbits > 0 )
4527 : {
4528 : /* independent encoding */
4529 1140 : push_next_indice( hMetaData, 1, 1 );
4530 1140 : independent_coding_ratio_ism_idx_fx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
4531 1140 : nbits = add( nbits, 1 );
4532 : }
4533 : ELSE
4534 : {
4535 722 : IF( nbits > 0 )
4536 : {
4537 666 : differential_coding_first_subframe_ivas_fx( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
4538 :
4539 666 : nbits = add( nbits0, 1 );
4540 : }
4541 : }
4542 : }
4543 : ELSE
4544 : {
4545 : /* not first subframe */
4546 3774 : test();
4547 3774 : IF( EQ_16( shift_one, 1 ) && EQ_16( nchan_ism, 2 ) )
4548 : {
4549 45 : nbits = 0;
4550 45 : move16();
4551 : }
4552 : ELSE
4553 : {
4554 3729 : nbits0 = 0;
4555 3729 : nbits1 = 0;
4556 3729 : move16();
4557 3729 : move16();
4558 :
4559 22266 : FOR( b = 0; b < numCodingBands; b++ )
4560 : {
4561 18537 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4562 : {
4563 16371 : estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
4564 16371 : nbits0 = add( nbits0, nbits00 );
4565 16371 : nbits1 = add( nbits1, nbits11 );
4566 : }
4567 : }
4568 3729 : IF( LT_16( nbits0, nbits1 ) )
4569 : {
4570 2691 : GR_order = 0;
4571 2691 : nbits = nbits0;
4572 2691 : move16();
4573 2691 : move16();
4574 : }
4575 : ELSE
4576 : {
4577 1038 : GR_order = 1;
4578 1038 : nbits = nbits1;
4579 1038 : move16();
4580 1038 : move16();
4581 : }
4582 :
4583 3729 : IF( GT_16( numCodingBands, 1 ) )
4584 : {
4585 : /* try the difference from subband to subband; first subband is compared to previous subframe first subband*/
4586 : /* take difference with respect to previous subframe only for first subband */
4587 3702 : nbits0 = 0;
4588 3702 : nbits1 = 0;
4589 3702 : b_signif = 0;
4590 3702 : move16();
4591 3702 : move16();
4592 3702 : move16();
4593 3963 : WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
4594 : {
4595 261 : test();
4596 261 : b_signif = add( b_signif, 1 );
4597 : }
4598 :
4599 3702 : IF( LT_16( b_signif, numCodingBands ) )
4600 : {
4601 3690 : estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], nchan_ism, shift_one, idx_sep_obj_local, &nbits0, &nbits1 );
4602 :
4603 3690 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4604 :
4605 18249 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4606 : {
4607 14559 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4608 : {
4609 12675 : estimate_bits_subband_ism_ratio_fx( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism, shift_one, idx_sep_obj_local, &nbits00, &nbits11 );
4610 12675 : nbits0 = add( nbits0, nbits00 );
4611 12675 : nbits1 = add( nbits1, nbits11 );
4612 12675 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4613 : }
4614 : }
4615 :
4616 3690 : IF( LT_16( nbits0, nbits1 ) )
4617 : {
4618 529 : GR_order_sb = 0;
4619 529 : move16();
4620 : }
4621 : ELSE
4622 : {
4623 3161 : GR_order_sb = 1;
4624 3161 : nbits0 = nbits1;
4625 3161 : move16();
4626 3161 : move16();
4627 : }
4628 :
4629 3690 : IF( LT_16( nbits0, nbits ) )
4630 : {
4631 343 : differential_subframe = 0;
4632 343 : nbits = nbits0;
4633 343 : GR_order = GR_order_sb;
4634 343 : move16();
4635 343 : move16();
4636 343 : move16();
4637 : }
4638 :
4639 3690 : IF( nbits > 0 )
4640 : {
4641 : /* write prediction type */
4642 3690 : push_next_indice( hMetaData, differential_subframe, 1 );
4643 : /* write GR order */
4644 3690 : push_next_indice( hMetaData, GR_order, 1 );
4645 3690 : nbits = add( nbits, 1 ); /* for the prediction type */
4646 3690 : nbits = add( nbits, 1 ); /* for GR_order */
4647 :
4648 : /* write data */
4649 3690 : IF( differential_subframe )
4650 : {
4651 20082 : FOR( b = 0; b < numCodingBands; b++ )
4652 : {
4653 16735 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4654 : {
4655 : /* take difference with respect to previous subframe */
4656 14850 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
4657 :
4658 14850 : IF( shift_one )
4659 : {
4660 9289 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4661 : }
4662 :
4663 14850 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4664 : }
4665 : }
4666 : }
4667 : ELSE
4668 : {
4669 343 : v_sub_s16_fx( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
4670 :
4671 343 : IF( shift_one )
4672 : {
4673 87 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4674 : }
4675 :
4676 343 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4677 :
4678 343 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
4679 :
4680 1709 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4681 : {
4682 : /* take difference with respect to previous subband */
4683 1366 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4684 : {
4685 1172 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4686 :
4687 1172 : IF( shift_one )
4688 : {
4689 332 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4690 : }
4691 :
4692 1172 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4693 :
4694 1172 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
4695 : }
4696 : }
4697 : }
4698 : }
4699 : }
4700 : }
4701 : ELSE
4702 : {
4703 : /* only differential wrt previous subframe is possible */
4704 : /* write the differential to subframe case and no bit to signal the difference type */
4705 :
4706 27 : IF( nbits > 0 )
4707 : {
4708 : /* write GR order */
4709 6 : push_next_indice( hMetaData, GR_order, 1 );
4710 6 : nbits = add( nbits, 1 ); /* for GR_order */
4711 : /* write data */
4712 : /* only one subband */
4713 6 : IF( LT_32( masa_to_total_energy_ratio[0], MASA2TOTAL_THR_Q30 ) )
4714 : {
4715 : /* take difference with respect to previous subframe */
4716 6 : v_sub_s16_fx( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
4717 :
4718 6 : IF( shift_one )
4719 : {
4720 0 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4721 : }
4722 :
4723 6 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4724 : }
4725 : }
4726 : }
4727 : }
4728 : }
4729 :
4730 5636 : return nbits;
4731 : }
4732 :
4733 :
4734 1862 : static void ivas_encode_masaism_metadata_fx(
4735 : MASA_ENCODER_HANDLE hMasa,
4736 : IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */
4737 : BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */
4738 : ISM_METADATA_HANDLE hIsmMeta[], /* i/o: ISM metadata handles */
4739 : const Word16 nchan_ism, /* i : number of ISM channels */
4740 : const Word16 low_bitrate_mode, /* i : is low bitrate more? 1/0 */
4741 : const Word16 omasa_nbands,
4742 : const Word16 omasa_nblocks,
4743 : const Word16 idx_separated_object,
4744 : const Word16 ism_imp )
4745 : {
4746 : Word16 sf, band;
4747 : UWord8 numCodingBands;
4748 : UWord8 numSf;
4749 : Word16 brange[2];
4750 : Word64 eneBand;
4751 : Word32 eneBand32;
4752 : Word16 eneBand_exp, shift;
4753 : Word16 bin;
4754 : Word16 obj;
4755 : Word16 bits_ism[MAX_NUM_OBJECTS];
4756 : UWord16 idx_sph;
4757 : Word32 theta_q, phi_q;
4758 : UWord16 index_theta, index_phi;
4759 : Word16 ratio_ism_fx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
4760 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
4761 : Word32 energy_ism, energy_ism_ind[MAX_NUM_OBJECTS];
4762 : Word16 tmp, rotate, energy_ism_e, energy_ism_ind_e[MAX_NUM_OBJECTS];
4763 : Word16 n_ism_tmp, i;
4764 1862 : OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
4765 1862 : OMASA_ENCODER_ENERGY_HANDLE hOmasaEnergy = hOmasaData->hOmasaEnergy;
4766 : Word16 nbands_work;
4767 : Word32 L_tmp;
4768 : Word16 L_tmp_e;
4769 :
4770 : /* use the values from hQMetaData */
4771 1862 : numCodingBands = (UWord8) hQMetaData->q_direction->cfg.nbands;
4772 1862 : numSf = (Word8) hQMetaData->q_direction->cfg.nblocks;
4773 1862 : nbands_work = s_min( numCodingBands, omasa_nbands );
4774 1862 : move16();
4775 1862 : move16();
4776 1862 : IF( EQ_16( numCodingBands, 1 ) )
4777 : {
4778 120 : FOR( sf = 0; sf < numSf; sf++ )
4779 : {
4780 96 : L_tmp = 0;
4781 96 : L_tmp_e = 0;
4782 96 : move32();
4783 96 : move16();
4784 576 : FOR( i = 0; i < omasa_nbands; i++ )
4785 : {
4786 480 : L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, hOmasaEnergy->energy_ism_fx[sf][i], hOmasaEnergy->energy_ism_fx_e[sf][i], &L_tmp_e );
4787 : }
4788 :
4789 : /* if ( sum_f( hOmasaEnergy->energy_ism[sf], omasa_nbands ) == 0.0f ) */
4790 96 : IF( L_tmp == 0 )
4791 : {
4792 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
4793 0 : move32();
4794 : }
4795 : ELSE
4796 : {
4797 96 : brange[0] = hMasa->data.band_mapping[0];
4798 96 : brange[1] = hMasa->data.band_mapping[omasa_nbands];
4799 96 : eneBand = 0;
4800 96 : move16();
4801 96 : move16();
4802 96 : move64();
4803 2400 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4804 : {
4805 2304 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4806 : }
4807 96 : shift = W_norm( eneBand );
4808 96 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4809 96 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4810 :
4811 96 : energy_ism = 0;
4812 96 : energy_ism_e = 0;
4813 96 : move32();
4814 96 : move16();
4815 288 : FOR( obj = 0; obj < nchan_ism; obj++ )
4816 : {
4817 192 : energy_ism_ind[obj] = 0;
4818 192 : energy_ism_ind_e[obj] = 0;
4819 192 : move32();
4820 192 : move16();
4821 : }
4822 :
4823 576 : FOR( band = 0; band < omasa_nbands; band++ )
4824 : {
4825 480 : energy_ism = BASOP_Util_Add_Mant32Exp( energy_ism, energy_ism_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energy_ism_e );
4826 :
4827 1440 : FOR( obj = 0; obj < nchan_ism; obj++ )
4828 : {
4829 :
4830 960 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
4831 960 : move32();
4832 : }
4833 : }
4834 :
4835 288 : FOR( obj = 0; obj < nchan_ism; obj++ )
4836 : {
4837 192 : hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
4838 192 : move32();
4839 192 : L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
4840 : /* Scaling to Q30 */
4841 192 : hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj] = L_shl( hOmasaEnergy->energy_ratio_ism_fx[sf][0][obj], sub( L_tmp_e, 1 ) ); // Q30
4842 192 : move32();
4843 : }
4844 96 : L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
4845 96 : IF( L_tmp != 0 )
4846 : {
4847 96 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4848 96 : move32();
4849 96 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4850 : /* Scaling to Q30 */
4851 96 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[sf][0], sub( tmp, 1 ) ); // Q30
4852 96 : move32();
4853 : }
4854 : ELSE
4855 : {
4856 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30;
4857 0 : move32();
4858 : }
4859 : }
4860 : }
4861 : }
4862 1838 : ELSE IF( EQ_16( numSf, 1 ) )
4863 : {
4864 6270 : FOR( band = 0; band < nbands_work; band++ )
4865 : {
4866 5666 : energy_ism = 0; /* ISM energy for current subband */ // energy_ism_e
4867 5666 : energy_ism_e = 0; /* ISM energy for current subband */
4868 5666 : move32();
4869 5666 : move16();
4870 24246 : FOR( obj = 0; obj < nchan_ism; obj++ )
4871 : {
4872 18580 : energy_ism_ind[obj] = 0;
4873 18580 : energy_ism_ind_e[obj] = 0;
4874 18580 : move32();
4875 18580 : move16();
4876 : }
4877 14722 : FOR( sf = 0; sf < omasa_nblocks; sf++ )
4878 : {
4879 9056 : energy_ism = BASOP_Util_Add_Mant32Exp( energy_ism, energy_ism_e, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &energy_ism_e );
4880 :
4881 34416 : FOR( obj = 0; obj < nchan_ism; obj++ )
4882 : {
4883 25360 : L_tmp = Mpy_32_32( hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] ); // Q = (31 - hOmasaEnergy->energy_ism_fx_e[sf][band]) + Q30 - 31
4884 25360 : L_tmp_e = add( 1, hOmasaEnergy->energy_ism_fx_e[sf][band] );
4885 25360 : energy_ism_ind[obj] = BASOP_Util_Add_Mant32Exp( energy_ism_ind[obj], energy_ism_ind_e[obj], L_tmp, L_tmp_e, &energy_ism_ind_e[obj] );
4886 25360 : move32();
4887 : }
4888 : }
4889 :
4890 5666 : IF( energy_ism == 0 )
4891 : {
4892 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30; // 1.0f in Q30
4893 0 : move32();
4894 : }
4895 : ELSE
4896 : {
4897 24246 : FOR( obj = 0; obj < nchan_ism; obj++ )
4898 : {
4899 18580 : hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
4900 18580 : move32();
4901 18580 : L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
4902 : /* Scaling to Q30 */
4903 18580 : hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = L_shl( hOmasaEnergy->energy_ratio_ism_fx[0][band][obj], sub( L_tmp_e, 1 ) ); // Q30
4904 18580 : move32();
4905 : }
4906 5666 : brange[0] = hMasa->data.band_mapping[band];
4907 5666 : brange[1] = hMasa->data.band_mapping[band + 1];
4908 5666 : move16();
4909 5666 : move16();
4910 :
4911 5666 : eneBand = 0;
4912 5666 : move64();
4913 14722 : FOR( sf = 0; sf < omasa_nblocks; sf++ )
4914 : {
4915 39748 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4916 : {
4917 30692 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4918 : }
4919 : }
4920 5666 : shift = W_norm( eneBand );
4921 5666 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4922 5666 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4923 :
4924 5666 : L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
4925 5666 : IF( L_tmp != 0 )
4926 : {
4927 5666 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4928 5666 : move32();
4929 5666 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4930 : /* Scaling to Q30 */
4931 5666 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[0][band], sub( tmp, 1 ) ); // Q30
4932 5666 : move32();
4933 : }
4934 : ELSE
4935 : {
4936 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
4937 0 : move32();
4938 : }
4939 : }
4940 : }
4941 604 : FOR( band = nbands_work; band < numCodingBands; band++ )
4942 : {
4943 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
4944 0 : move32();
4945 :
4946 0 : FOR( obj = 0; obj < nchan_ism; obj++ )
4947 : {
4948 0 : hOmasaEnergy->energy_ratio_ism_fx[0][band][obj] = hOmasaEnergy->energy_ratio_ism_fx[0][nbands_work - 1][obj];
4949 0 : move32();
4950 : }
4951 : }
4952 : }
4953 : ELSE
4954 : {
4955 6170 : FOR( sf = 0; sf < numSf; sf++ )
4956 : {
4957 29616 : FOR( band = 0; band < nbands_work; band++ )
4958 : {
4959 24680 : IF( hOmasaEnergy->energy_ism_fx[sf][band] == 0 )
4960 : {
4961 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
4962 0 : move32();
4963 : }
4964 : ELSE
4965 : {
4966 24680 : brange[0] = hMasa->data.band_mapping[band];
4967 24680 : brange[1] = hMasa->data.band_mapping[band + 1];
4968 24680 : move16();
4969 24680 : move16();
4970 :
4971 24680 : eneBand = 0;
4972 24680 : move64();
4973 141656 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4974 : {
4975 116976 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4976 : }
4977 24680 : shift = W_norm( eneBand );
4978 24680 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4979 24680 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4980 :
4981 24680 : L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, hOmasaEnergy->energy_ism_fx[sf][band], hOmasaEnergy->energy_ism_fx_e[sf][band], &L_tmp_e );
4982 24680 : IF( L_tmp != 0 )
4983 : {
4984 24680 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4985 24680 : move32();
4986 24680 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4987 : /* Scaling to Q30 */
4988 24680 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = L_shl( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], sub( tmp, 1 ) ); // Q30
4989 24680 : move32();
4990 : }
4991 : ELSE
4992 : {
4993 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
4994 0 : move32();
4995 : }
4996 : }
4997 : }
4998 4936 : FOR( band = nbands_work; band < numCodingBands; band++ )
4999 : {
5000 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
5001 0 : move32();
5002 :
5003 0 : FOR( obj = 0; obj < nchan_ism; obj++ )
5004 : {
5005 0 : hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] = hOmasaEnergy->energy_ratio_ism_fx[sf][nbands_work - 1][obj];
5006 0 : move32();
5007 : }
5008 : }
5009 : }
5010 : }
5011 :
5012 1862 : ivas_omasa_encode_masa_to_total_fx( hOmasaData->masa_to_total_energy_ratio_fx, hMetaData, low_bitrate_mode, numCodingBands, numSf );
5013 :
5014 : /* quantize ism_ratios */
5015 1862 : IF( GT_16( nchan_ism, 1 ) )
5016 : {
5017 1862 : rotate = 0;
5018 1862 : n_ism_tmp = 0;
5019 1862 : move16();
5020 1862 : move16();
5021 :
5022 7498 : FOR( sf = 0; sf < numSf; sf++ )
5023 : {
5024 36078 : FOR( band = 0; band < numCodingBands; band++ )
5025 : {
5026 137614 : FOR( obj = 0; obj < nchan_ism; obj++ )
5027 : {
5028 107172 : assert( ( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] >= 0 ) && ( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] <= ONE_IN_Q30 ) );
5029 107172 : ratio_ism_fx[band][obj] = extract_h( hOmasaEnergy->energy_ratio_ism_fx[sf][band][obj] ); // Q14
5030 107172 : move16();
5031 : }
5032 :
5033 : /* Quantize ISM ratios */
5034 30442 : quantize_ratio_ism_vector_ivas_fx( ratio_ism_fx[band], 1 /* Q14 */, ratio_ism_idx[band], nchan_ism, hOmasaData->masa_to_total_energy_ratio_fx[sf][band], idx_separated_object );
5035 :
5036 30442 : test();
5037 30442 : test();
5038 30442 : IF( EQ_16( n_ism_tmp, numCodingBands ) && ratio_ism_idx[band][idx_separated_object] != 0 && LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5039 : {
5040 92 : i = 0;
5041 92 : move16();
5042 697 : WHILE( ratio_ism_idx[band][idx_separated_object] > 0 )
5043 : {
5044 605 : IF( NE_16( i, idx_separated_object ) )
5045 : {
5046 410 : ratio_ism_idx[band][i] = add( ratio_ism_idx[band][i], 1 );
5047 410 : ratio_ism_idx[band][idx_separated_object] = sub( ratio_ism_idx[band][idx_separated_object], 1 );
5048 410 : move16();
5049 410 : move16();
5050 : }
5051 605 : i = add( i, 1 );
5052 605 : if ( EQ_16( i, nchan_ism ) )
5053 : {
5054 138 : i = 0;
5055 138 : move16();
5056 : }
5057 : }
5058 : }
5059 :
5060 : /* reconstructed values */
5061 30442 : reconstruct_ism_ratios_fx( ratio_ism_idx[band], nchan_ism, STEP_PARAM_ISM_POW_RATIO_NBITS_Q31, hOmasaEnergy->q_energy_ratio_ism_fx[sf][band] );
5062 : }
5063 :
5064 5636 : test();
5065 5636 : IF( GT_16( nchan_ism, 2 ) && EQ_16( idx_separated_object, sub( nchan_ism, 1 ) ) )
5066 : {
5067 : /* rotate components */
5068 766 : rotate = 1;
5069 766 : move16();
5070 4610 : FOR( band = 0; band < numCodingBands; band++ )
5071 : {
5072 3844 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5073 : {
5074 3352 : tmp = ratio_ism_idx[band][nchan_ism - 1];
5075 3352 : ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
5076 3352 : ratio_ism_idx[band][0] = tmp;
5077 3352 : move16();
5078 3352 : move16();
5079 3352 : move16();
5080 3352 : test();
5081 3352 : IF( sf == 0 && tmp == 0 )
5082 : {
5083 799 : n_ism_tmp = add( n_ism_tmp, 1 );
5084 : }
5085 :
5086 3352 : if ( EQ_16( n_ism_tmp, numCodingBands ) )
5087 : {
5088 1753 : assert( tmp == 0 );
5089 : }
5090 : }
5091 : }
5092 : }
5093 : ELSE
5094 : {
5095 4870 : IF( GT_16( idx_separated_object, -1 ) )
5096 : {
5097 31468 : FOR( band = 0; band < numCodingBands; band++ )
5098 : {
5099 26598 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5100 : {
5101 23497 : test();
5102 23497 : IF( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
5103 : {
5104 8636 : n_ism_tmp = add( n_ism_tmp, 1 );
5105 : }
5106 : }
5107 : }
5108 : }
5109 : }
5110 :
5111 : /* encode data for current subframe */
5112 5636 : test();
5113 5636 : IF( sf > 0 && EQ_16( n_ism_tmp, numCodingBands ) )
5114 : {
5115 2082 : encode_ratio_ism_subframe_fx( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio_fx[sf], 1, idx_separated_object );
5116 : }
5117 : ELSE
5118 : {
5119 3554 : encode_ratio_ism_subframe_fx( ratio_ism_idx, nchan_ism, numCodingBands, sf, ratio_ism_idx_prev_sf, hMetaData, hOmasaData->masa_to_total_energy_ratio_fx[sf], 0, idx_separated_object );
5120 : }
5121 :
5122 : /* calculate quantized ISM ratios */
5123 : /* save previous subframe indexes */
5124 36078 : FOR( band = 0; band < numCodingBands; band++ )
5125 : {
5126 30442 : Copy( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
5127 : }
5128 :
5129 5636 : IF( rotate )
5130 : {
5131 4610 : FOR( band = 0; band < numCodingBands; band++ )
5132 : {
5133 3844 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5134 : {
5135 3352 : tmp = ratio_ism_idx[band][nchan_ism - 1];
5136 3352 : ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
5137 3352 : ratio_ism_idx[band][0] = tmp;
5138 3352 : move16();
5139 3352 : move16();
5140 3352 : move16();
5141 : }
5142 : }
5143 : }
5144 : }
5145 : }
5146 :
5147 1862 : calculate_nbits_meta_fx( nchan_ism, hOmasaEnergy->q_energy_ratio_ism_fx, hOmasaData->masa_to_total_energy_ratio_fx, numSf, numCodingBands, bits_ism, idx_separated_object, ism_imp );
5148 :
5149 : /* quantize directions */
5150 8142 : FOR( obj = 0; obj < nchan_ism; obj++ )
5151 : {
5152 6280 : IF( LT_16( bits_ism[obj], 8 ) )
5153 : {
5154 : /* check is same as previous */
5155 2009 : test();
5156 2009 : IF( LT_32( L_abs( L_sub( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->q_elevation_old_fx ) ), 41943 /* 0.01f in Q22 */ ) && LT_32( L_abs( L_sub( hIsmMeta[obj]->azimuth_fx, hIsmMeta[obj]->q_azimuth_old_fx ) ), 41943 /* 0.01f in Q22 */ ) )
5157 : {
5158 201 : push_next_indice( hMetaData, 1, 1 );
5159 : /* the old stays the same */
5160 : }
5161 : ELSE
5162 : {
5163 1808 : push_next_indice( hMetaData, 0, 1 );
5164 1808 : idx_sph = quantize_direction_fx( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->azimuth_fx, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
5165 1808 : push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
5166 1808 : hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
5167 1808 : hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
5168 1808 : move32();
5169 1808 : move32();
5170 : }
5171 : }
5172 : ELSE
5173 : {
5174 4271 : idx_sph = quantize_direction_fx( hIsmMeta[obj]->elevation_fx, hIsmMeta[obj]->azimuth_fx, bits_ism[obj], &theta_q, &phi_q, &index_theta, &index_phi, MC_LS_SETUP_INVALID );
5175 4271 : push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
5176 4271 : hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
5177 4271 : hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
5178 4271 : move32();
5179 4271 : move32();
5180 : }
5181 : }
5182 :
5183 1862 : return;
5184 : }
5185 :
5186 :
5187 : /*-------------------------------------------------------------------*
5188 : * ivas_merge_masa_transports()
5189 : *
5190 : * Merge MASA transport channels
5191 : *-------------------------------------------------------------------*/
5192 :
5193 5858 : void ivas_merge_masa_transports_fx(
5194 : Word32 data_in_f1_fx[][L_FRAME48k], // Qx
5195 : Word32 *data_in_f2_fx[], // Qx
5196 : Word32 *data_out_f_fx[], // Qx
5197 : const Word16 input_frame,
5198 : const Word16 num_transport_channels )
5199 : {
5200 : Word16 i, j;
5201 :
5202 17574 : FOR( i = 0; i < num_transport_channels; i++ )
5203 : {
5204 10588356 : FOR( j = 0; j < input_frame; j++ )
5205 : {
5206 10576640 : data_out_f_fx[i][j] = L_add( data_in_f1_fx[i][j], data_in_f2_fx[i][j] );
5207 10576640 : move32();
5208 : }
5209 : }
5210 :
5211 5858 : return;
5212 : }
|