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