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 20938 : push_next_indice( hMetaData, 1, MASA_LOWBITRATE_MODE_BITS );
607 : }
608 : ELSE
609 : {
610 3973 : 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 = st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_fx; /*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( st_ivas->hCPE[0]->hCoreCoder[0]->lp_noise_fx, ONE_IN_Q14 ), st_ivas->hCPE[0]->hCoreCoder[1]->lp_noise_fx, 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 23245 : 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 23168 : 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 23168 : exp = add( exp, sub( sub( 31, add( hMasa->data.q_energy, tmp2 ) ), 31 ) );
2444 23168 : bandRatio = hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[0]; // Q30
2445 23168 : move32();
2446 :
2447 23168 : bandEnergy = 0;
2448 23168 : move64();
2449 115840 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2450 : {
2451 92672 : bandEnergy = W_mac_32_32( bandEnergy, energy[sf][band], 1 );
2452 : }
2453 23168 : shift = W_norm( bandEnergy );
2454 23168 : bandEnergy32 = W_extract_h( W_shl( bandEnergy, shift ) );
2455 23168 : bandEnergy_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
2456 :
2457 23168 : 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 : meanRatio = 0;
2467 5619 : move32();
2468 28095 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2469 : {
2470 134856 : FOR( band = 0; band < numCodingBands; band++ )
2471 : {
2472 112380 : meanRatio = L_add( meanRatio, Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ) ); // hMasa->data.q_energy - 1
2473 : }
2474 : }
2475 5619 : IF( totalEnergySum != 0 )
2476 : {
2477 5619 : meanRatio = BASOP_Util_Divide3232_Scale_newton( meanRatio, totalEnergySum, &exp );
2478 5619 : exp = add( add( exp, 1 ), tmp2 ); // 31 - (hMasa->data.q_energy - 1) - 31 - hMasa->data.q_energy - tmp2 => 1 + tmp2
2479 : }
2480 : ELSE
2481 : {
2482 0 : meanRatio = MAX_32;
2483 0 : exp = 31;
2484 0 : move32();
2485 0 : move16();
2486 : }
2487 :
2488 : /* 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.
2489 : * Otherwise, merge over subframes. */
2490 5619 : IF( BASOP_Util_Cmp_Mant32Exp( hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[0], 1, meanRatio, exp ) > 0 )
2491 : {
2492 3973 : mergeOverFreqBands = 1;
2493 3973 : move16();
2494 : }
2495 : ELSE
2496 : {
2497 1646 : mergeOverFreqBands = 0;
2498 1646 : move16();
2499 : }
2500 : }
2501 : ELSE
2502 : {
2503 19292 : mergeOverFreqBands = 0;
2504 19292 : move16();
2505 : }
2506 :
2507 : /* Merge values over subframes or frequency bands, depending on which one is less important */
2508 24911 : IF( !mergeOverFreqBands ) /* Merge values over subframes */
2509 : {
2510 : Word32 xSum, ySum, zSum;
2511 : Word64 W_xSum_sq, W_ySum_sq;
2512 : Word32 bandSumEnergy;
2513 : Word16 aziRad, eleRad, q_shift, exp_diff;
2514 : Word32 x, y, z;
2515 : Word32 veclen, L_tmp;
2516 :
2517 20938 : W_tmp = 0;
2518 20938 : move64();
2519 104156 : FOR( band = 0; band < numCodingBands; band++ )
2520 : {
2521 83218 : xSum = 0;
2522 83218 : ySum = 0;
2523 83218 : zSum = 0;
2524 83218 : bandSumEnergy = 0;
2525 83218 : move32();
2526 83218 : move32();
2527 83218 : move32();
2528 83218 : move32();
2529 :
2530 416090 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2531 : {
2532 332872 : aziRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].azimuth_fx[sf], PI_OVER_180_Q22 ) );
2533 332872 : eleRad = extract_l( Mpy_32_32( hqmetadata->q_direction[0].band_data[band].elevation_fx[sf], PI_OVER_180_Q22 ) );
2534 332872 : veclen = Mpy_32_32( hqmetadata->q_direction[0].band_data[band].energy_ratio_fx[sf], energy[sf][band] ); // hMasa->data.q_energy - 1
2535 :
2536 332872 : x = Mpy_32_32( L_mult( getCosWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2537 332872 : move32();
2538 332872 : y = Mpy_32_32( L_mult0( getSinWord16( aziRad ), getCosWord16( eleRad ) ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2539 332872 : move32();
2540 332872 : z = Mpy_32_32( L_mult0( getSinWord16( eleRad ), ONE_IN_Q14 ), veclen ); // (Q29, hMasa->data.q_energy - Q1) -> hMasa->data.q_energy - Q3
2541 332872 : move32();
2542 :
2543 332872 : xSum = L_add( xSum, x );
2544 332872 : ySum = L_add( ySum, y );
2545 332872 : zSum = L_add( zSum, z );
2546 :
2547 332872 : W_tmp = W_add( W_tmp, energy[sf][band] );
2548 : }
2549 :
2550 83218 : tmp2 = W_norm( W_tmp );
2551 83218 : tmp2 = s_min( 32, tmp2 );
2552 83218 : bandSumEnergy = W_extract_h( W_shl( W_tmp, tmp2 ) );
2553 83218 : tmp2 = sub( add( hMasa->data.q_energy, tmp2 ), 32 );
2554 :
2555 83218 : aziRad = BASOP_util_atan2( ySum, xSum, 0 ); // Q13
2556 83218 : W_xSum_sq = W_mult0_32_32( xSum, xSum ); // 2 * hMasa->data.q_energy - Q6
2557 83218 : W_ySum_sq = W_mult0_32_32( ySum, ySum ); // 2 * hMasa->data.q_energy - Q6
2558 83218 : W_tmp = W_add( W_xSum_sq, W_ySum_sq ); // 2 * hMasa->data.q_energy - Q6
2559 83218 : q_shift = W_norm( W_tmp );
2560 83218 : L_tmp = W_extract_h( W_shl( W_tmp, q_shift ) ); // 2 * hMasa->data.q_energy - Q6 + (q_shift -32)
2561 83218 : exp_diff = sub( Q31, add( sub( imult1616( 2, hMasa->data.q_energy ), Q6 ), sub( q_shift, 32 ) ) );
2562 83218 : L_tmp = Sqrt32( L_tmp, &exp_diff );
2563 83218 : eleRad = BASOP_util_atan2( zSum, L_tmp, sub( sub( 34, hMasa->data.q_energy ), exp_diff ) ); // Q13
2564 :
2565 83218 : 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
2566 83218 : 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
2567 :
2568 : /* Energy ratio is already merged through time */
2569 83218 : test();
2570 83218 : IF( computeCoherence && hqmetadata->q_direction[0].coherence_band_data != NULL )
2571 : {
2572 : Word16 spreadCoh;
2573 5368 : Word32 spreadCohSum = 0;
2574 5368 : move32();
2575 26840 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2576 : {
2577 21472 : spreadCoh = div_s( (Word16) hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf], 255 ); // Q15
2578 21472 : spreadCohSum = L_add( spreadCohSum, Mpy_32_16_1( energy[sf][band], spreadCoh ) );
2579 : }
2580 : // hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (uint8_t) roundf( spreadCohSum / ( bandSumEnergy + EPSILON ) * 255.0f );
2581 5368 : tmp = BASOP_Util_Divide3232_Scale( spreadCohSum, bandSumEnergy, &exp );
2582 5368 : exp = add( exp, sub( tmp2, hMasa->data.q_energy ) );
2583 5368 : tmp = mult_r( tmp, 32640 /* 255 in Q7 */ ); // 15 - exp + 7 - 15 => 7 - exp
2584 5368 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0] = (UWord8) shr( tmp, sub( 7, exp ) ); // Q0
2585 5368 : move16();
2586 :
2587 : /* Copy spread coherence to the rest of subframes for the coherence coding algorithm. */
2588 21472 : FOR( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2589 : {
2590 96624 : FOR( band = 0; band < numCodingBands; band++ )
2591 : {
2592 80520 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[0]; // Q0
2593 80520 : move16();
2594 : }
2595 : }
2596 :
2597 : /* Surround coherence is already merged through time */
2598 : }
2599 : }
2600 :
2601 20938 : hqmetadata->q_direction->cfg.nblocks = 1;
2602 20938 : hMasa->config.joinedSubframes = 1;
2603 20938 : move16();
2604 20938 : move16();
2605 : }
2606 : ELSE /* Merge values over frequency bands */
2607 : {
2608 : /* Use the selected frequency band to represent all data */
2609 19865 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2610 : {
2611 15892 : hqmetadata->q_direction[0].band_data[0].azimuth_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].azimuth_fx[sf]; // Q22
2612 15892 : hqmetadata->q_direction[0].band_data[0].elevation_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].elevation_fx[sf]; // Q22
2613 15892 : hqmetadata->q_direction[0].band_data[0].energy_ratio_fx[sf] = hqmetadata->q_direction[0].band_data[selectedBand].energy_ratio_fx[sf]; // Q30
2614 15892 : move32();
2615 15892 : move32();
2616 15892 : move32();
2617 15892 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2618 : {
2619 5280 : hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[selectedBand].spread_coherence[sf]; // Q0
2620 5280 : move16();
2621 : }
2622 15892 : IF( hqmetadata->surcoh_band_data != NULL )
2623 : {
2624 5280 : hqmetadata->surcoh_band_data[0].surround_coherence[sf] = hqmetadata->surcoh_band_data[selectedBand].surround_coherence[sf];
2625 5280 : move16();
2626 : }
2627 : }
2628 :
2629 : /* Copy coherence to rest of bands for the coherence coding algorithm. */
2630 19865 : FOR( band = 1; band < numCodingBands; band++ )
2631 : {
2632 15892 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2633 : {
2634 26400 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2635 : {
2636 21120 : hqmetadata->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hqmetadata->q_direction[0].coherence_band_data[0].spread_coherence[sf]; // Q0
2637 21120 : move16();
2638 : }
2639 : }
2640 15892 : IF( hqmetadata->q_direction[0].coherence_band_data != NULL )
2641 : {
2642 26400 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
2643 : {
2644 21120 : hqmetadata->surcoh_band_data[band].surround_coherence[sf] = hqmetadata->surcoh_band_data[0].surround_coherence[sf];
2645 21120 : move16();
2646 : }
2647 : }
2648 : }
2649 :
2650 3973 : hqmetadata->q_direction[0].cfg.nbands = 1;
2651 3973 : move16();
2652 : }
2653 :
2654 24911 : return;
2655 : }
2656 :
2657 :
2658 11470 : static Word16 encode_lfe_to_total_energy_ratio_fx(
2659 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA encoder structure */
2660 : BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */
2661 : const Word32 ivas_total_brate /* i : IVAS total bitrate */
2662 : )
2663 : {
2664 : Word16 i;
2665 : Word16 xq;
2666 : Word16 VQLevels;
2667 : Word32 maxLFESubFrameEner;
2668 : Word16 maxLFESubFrameEner_e;
2669 : Word32 log2LFEaverage;
2670 : Word32 log2LFEratio[4];
2671 : Word32 xqv[4];
2672 : Word32 linearLFEaverage;
2673 : Word16 linearLFEaverage_e;
2674 : Word16 lfeToTotalEnergyRatioIndices[3];
2675 : Word16 lfeAdaptiveVQBits;
2676 : Word16 lfeBitsWritten;
2677 : Word32 maxVal;
2678 : Word16 maxVal_e;
2679 :
2680 11470 : VQLevels = 0;
2681 11470 : move16();
2682 11470 : lfeAdaptiveVQBits = 0;
2683 11470 : move16();
2684 :
2685 : /* Determine maximum amount of LFE energy in any subframe */
2686 11470 : maxLFESubFrameEner = 0; // maxLFESubFrameEner_e
2687 11470 : move32();
2688 11470 : maxLFESubFrameEner_e = 0;
2689 11470 : move16();
2690 57350 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2691 : {
2692 45880 : IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxLFESubFrameEner, maxLFESubFrameEner_e ) > 0 )
2693 : {
2694 4563 : maxLFESubFrameEner = hMasa->data.lfeToTotalEnergyRatio_fx[i]; // hMasa->data.lfeToTotalEnergyRatio_e[i]
2695 4563 : move32();
2696 4563 : maxLFESubFrameEner_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
2697 4563 : move16();
2698 : }
2699 : }
2700 :
2701 : /* Set default values for the indices */
2702 45880 : FOR( i = 0; i < 3; i++ )
2703 : {
2704 34410 : lfeToTotalEnergyRatioIndices[i] = 0;
2705 34410 : move16();
2706 : }
2707 :
2708 : /* Check if there is enough energy in any subframe. If not, send only 1 bit (0) and abort. */
2709 : /* If there is enough LFE energy at least in one subframe, quantize it. */
2710 11470 : IF( BASOP_Util_Cmp_Mant32Exp( maxLFESubFrameEner, maxLFESubFrameEner_e, 10737418 /* 0.005f in Q31 */, 0 ) > 0 )
2711 : {
2712 : /* Convert energy to log2 domain, and clamp it to reasonable values */
2713 1884 : log2LFEaverage = 0; // Q25
2714 1884 : move32();
2715 9420 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2716 : {
2717 : // log2LFEratio[i] = log2f( max( 0.001f, hMasa->data.lfeToTotalEnergyRatio[i] ) );
2718 7536 : maxVal = 2147484 /* 0.001f in Q31 */;
2719 7536 : move32();
2720 7536 : maxVal_e = 0;
2721 7536 : move16();
2722 7536 : IF( BASOP_Util_Cmp_Mant32Exp( hMasa->data.lfeToTotalEnergyRatio_fx[i], hMasa->data.lfeToTotalEnergyRatio_e[i], maxVal, maxVal_e ) > 0 )
2723 : {
2724 7297 : maxVal = hMasa->data.lfeToTotalEnergyRatio_fx[i];
2725 7297 : move32();
2726 7297 : maxVal_e = hMasa->data.lfeToTotalEnergyRatio_e[i];
2727 7297 : move16();
2728 : }
2729 7536 : log2LFEratio[i] = L_add( BASOP_Util_Log2( maxVal ), L_shl( maxVal_e, Q25 ) ); // Q25
2730 7536 : move32();
2731 7536 : IF( GT_32( log2LFEratio[i], ONE_IN_Q25 ) ) /* Corresponds to linear value 2.0f */
2732 : {
2733 0 : log2LFEratio[i] = ONE_IN_Q25; // Q25
2734 0 : move32();
2735 : }
2736 7536 : ELSE IF( LT_32( log2LFEratio[i], -301989888 /* -9.0f in Q25 */ ) )
2737 : {
2738 286 : log2LFEratio[i] = -301989888 /* -9.0f in Q25 */; // Q25
2739 286 : move32();
2740 : }
2741 7536 : log2LFEaverage = L_add( log2LFEaverage, Mpy_32_32( 536870912 /* 0.25f in Q31 */, log2LFEratio[i] ) ); // Q25
2742 : }
2743 :
2744 1884 : IF( EQ_32( ivas_total_brate, IVAS_13k2 ) )
2745 : {
2746 : /* Calculate adaptive 1-bit LFE quantizer index */
2747 : // linearLFEaverage = exp2f( log2LFEaverage ); /* Convert back to linear domain */
2748 175 : linearLFEaverage = BASOP_util_Pow2( log2LFEaverage, Q31 - Q25, &linearLFEaverage_e ); /* Convert back to linear domain */
2749 175 : linearLFEaverage = L_shl_sat( linearLFEaverage, sub( linearLFEaverage_e, Q1 ) ); // Q30
2750 175 : test();
2751 175 : IF( GT_32( linearLFEaverage, MCMASA_LFE_1BIT_THRES_Q30 ) &&
2752 : GT_32( linearLFEaverage, L_add( L_add( MCMASA_LFE_BETA_Q30 >> Q1, L_shr( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q2 ) ),
2753 : L_shr( Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ), Q1 ) ) ) )
2754 : {
2755 128 : lfeToTotalEnergyRatioIndices[0] = 1;
2756 128 : move16();
2757 128 : IF( EQ_16( hMasa->data.prevq_lfeIndex, 1 ) )
2758 : {
2759 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
2760 86 : move32();
2761 : }
2762 : ELSE
2763 : {
2764 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
2765 42 : move32();
2766 : }
2767 : }
2768 : ELSE
2769 : {
2770 47 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = Mpy_32_32( MCMASA_LFE_ALPHA_Q30, hMasa->data.prevq_lfeToTotalEnergyRatio_fx ); /* exponential decay */ // Q30
2771 47 : move32();
2772 : }
2773 :
2774 175 : IF( GE_32( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, ONE_IN_Q30 ) )
2775 : {
2776 0 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = ONE_IN_Q31; // Q31
2777 0 : move32();
2778 : }
2779 : ELSE
2780 : {
2781 175 : hMasa->data.prevq_lfeToTotalEnergyRatio_fx = L_shl( hMasa->data.prevq_lfeToTotalEnergyRatio_fx, Q1 ); // Q31
2782 175 : move32();
2783 : }
2784 175 : hMasa->data.prevq_lfeIndex = lfeToTotalEnergyRatioIndices[0]; /* Update to previous frame's index memories */
2785 175 : move16();
2786 : }
2787 : ELSE /* Bitrate >= 16.4 kbps */
2788 : {
2789 : /* Do 1st stage scalar quantization */
2790 1709 : lfeToTotalEnergyRatioIndices[0] = 1;
2791 1709 : move16();
2792 1709 : lfeToTotalEnergyRatioIndices[1] = usquant_fx( extract_l( L_shr( log2LFEaverage, Q14 ) ), &xq, MCMASA_LFE_QLOW_Q11, MCMASA_LFE_DELTA_Q10, 8 );
2793 1709 : move16();
2794 :
2795 1709 : IF( GE_32( ivas_total_brate, IVAS_24k4 ) ) /* Vector quantization is applied if bitrate >= 24.4 kbps */
2796 : {
2797 : /* Remove scalar value from the vector*/
2798 8020 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
2799 : {
2800 6416 : log2LFEratio[i] = L_sub( log2LFEratio[i], L_shl( xq, Q14 ) ); // Q25
2801 6416 : move32();
2802 : }
2803 :
2804 : /* Vector quantize residual with energy adaptive bit allocation */
2805 1604 : SWITCH( lfeToTotalEnergyRatioIndices[1] )
2806 : {
2807 222 : case 0:
2808 : case 1:
2809 222 : VQLevels = 0;
2810 222 : move16();
2811 222 : lfeAdaptiveVQBits = 0;
2812 222 : move16();
2813 222 : BREAK;
2814 97 : case 2:
2815 97 : VQLevels = 2;
2816 97 : move16();
2817 97 : lfeAdaptiveVQBits = 1;
2818 97 : move16();
2819 97 : BREAK;
2820 97 : case 3:
2821 97 : VQLevels = 4;
2822 97 : move16();
2823 97 : lfeAdaptiveVQBits = 2;
2824 97 : move16();
2825 97 : BREAK;
2826 242 : case 4:
2827 242 : VQLevels = 8;
2828 242 : move16();
2829 242 : lfeAdaptiveVQBits = 3;
2830 242 : move16();
2831 242 : BREAK;
2832 946 : default:
2833 946 : VQLevels = 16;
2834 946 : move16();
2835 946 : lfeAdaptiveVQBits = 4;
2836 946 : move16();
2837 : }
2838 :
2839 1604 : IF( VQLevels > 0 )
2840 : {
2841 1382 : lfeToTotalEnergyRatioIndices[2] = vquant_ivas_fx( log2LFEratio, 0, xqv, McMASA_LFEGain_vectors_fx_q25, 4, VQLevels );
2842 1382 : move16();
2843 : }
2844 : }
2845 : }
2846 : }
2847 :
2848 : /* Write first LFE bit */
2849 11470 : lfeBitsWritten = 0;
2850 11470 : move16();
2851 11470 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[0], 1 );
2852 11470 : lfeBitsWritten = add( lfeBitsWritten, 1 );
2853 :
2854 11470 : test();
2855 11470 : IF( EQ_16( lfeToTotalEnergyRatioIndices[0], 1 ) && GE_32( ivas_total_brate, IVAS_16k4 ) )
2856 : {
2857 : /* If bitrate >= 16.4kbit/s, send 1-bit on/off + 3-bit scalar */
2858 1709 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[1], 3 );
2859 1709 : lfeBitsWritten = add( lfeBitsWritten, 3 );
2860 :
2861 : /* If bitrate >= 24.4kbit/s, use adaptive 1 + (3.. 7) bit quantizer */
2862 1709 : IF( GE_32( ivas_total_brate, IVAS_24k4 ) )
2863 : {
2864 : /* Vector quantize residual with energy adaptive bit allocation */
2865 1604 : IF( lfeAdaptiveVQBits > 0 )
2866 : {
2867 1382 : push_next_indice( hMetaData, lfeToTotalEnergyRatioIndices[2], lfeAdaptiveVQBits );
2868 1382 : lfeBitsWritten = add( lfeBitsWritten, lfeAdaptiveVQBits );
2869 : }
2870 : }
2871 : }
2872 :
2873 11470 : return lfeBitsWritten;
2874 : }
2875 :
2876 :
2877 : /*-------------------------------------------------------------------*
2878 : * ivas_masa_enc_reconfigure()
2879 : *
2880 : * Reconfigure IVAS MASA encoder
2881 : *-------------------------------------------------------------------*/
2882 30626 : void ivas_masa_enc_reconfigure_fx(
2883 : Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */
2884 : )
2885 : {
2886 : Word16 n, tmp;
2887 : Word16 sce_id, cpe_id;
2888 : Word32 ivas_total_brate;
2889 : Word32 ism_total_brate;
2890 : Word32 tmp_br, tmp_mod;
2891 :
2892 30626 : ivas_total_brate = st_ivas->hEncoderConfig->ivas_total_brate;
2893 30626 : move32();
2894 :
2895 30626 : ism_total_brate = 0;
2896 30626 : move32();
2897 30626 : test();
2898 30626 : test();
2899 30626 : test();
2900 30626 : test();
2901 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 ) ) )
2902 : {
2903 0 : FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
2904 : {
2905 0 : ism_total_brate = L_add( ism_total_brate, st_ivas->hSCE[sce_id]->element_brate );
2906 : }
2907 : }
2908 :
2909 30626 : IF( NE_32( ivas_total_brate, st_ivas->hEncoderConfig->last_ivas_total_brate ) )
2910 : {
2911 1269 : iDiv_and_mod_32( ivas_total_brate, st_ivas->nchan_transport, &tmp_br, &tmp_mod, 0 );
2912 1934 : FOR( sce_id = 0; sce_id < st_ivas->nSCE; sce_id++ )
2913 : {
2914 665 : copy_encoder_config_fx( st_ivas, st_ivas->hSCE[sce_id]->hCoreCoder[0], 0 );
2915 665 : st_ivas->hSCE[sce_id]->element_brate = tmp_br;
2916 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() */
2917 665 : move32();
2918 665 : move32();
2919 : }
2920 :
2921 1873 : FOR( cpe_id = 0; cpe_id < st_ivas->nCPE; cpe_id++ )
2922 : {
2923 604 : st_ivas->hCPE[cpe_id]->element_brate = imult3216( tmp_br, 2 ); //( ivas_total_brate / st_ivas->nchan_transport ) * CPE_CHANNELS;
2924 604 : move32();
2925 :
2926 604 : IF( GT_16( st_ivas->nCPE, 1 ) )
2927 : {
2928 0 : tmp = 1;
2929 : }
2930 : ELSE
2931 : {
2932 604 : tmp = CPE_CHANNELS;
2933 : }
2934 604 : move16();
2935 : /* prepare bitstream buffers */
2936 1812 : FOR( n = 0; n < CPE_CHANNELS; n++ )
2937 : {
2938 1208 : copy_encoder_config_fx( st_ivas, st_ivas->hCPE[cpe_id]->hCoreCoder[n], 0 );
2939 : /* st_ivas->hCPE[cpe_id]->hCoreCoder[n]->total_brate = st_ivas->hCPE[cpe_id]->element_brate / ( st_ivas->nCPE > 1 ? 1 : CPE_CHANNELS ); */
2940 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() */
2941 1208 : move32();
2942 : }
2943 :
2944 604 : IF( LT_32( L_sub( ivas_total_brate, ism_total_brate ), MIN_BRATE_MDCT_STEREO ) )
2945 : {
2946 218 : st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_DFT;
2947 : }
2948 : ELSE
2949 : {
2950 386 : st_ivas->hCPE[cpe_id]->element_mode = IVAS_CPE_MDCT;
2951 : }
2952 604 : move16();
2953 : }
2954 :
2955 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 );
2956 : }
2957 :
2958 30626 : return;
2959 : }
2960 :
2961 : /*-------------------------------------------------------------------*
2962 : * average_masa_metadata()
2963 : *
2964 : * Average MASA metadata frame subframe contents: applies aggregation over time
2965 : *-------------------------------------------------------------------*/
2966 0 : static void average_masa_metadata_fx(
2967 : MASA_METADATA_FRAME *hMeta,
2968 : Word32 energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /*i Q(31 - energy_e) */
2969 : Word16 energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], /*i:stores exponent values for energy_e*/
2970 : const SPHERICAL_GRID_DATA *Sph_Grid16,
2971 : const UWord8 useSphGrid )
2972 : {
2973 : Word16 i, j, k;
2974 : Word16 azi_rad_fx, ele_rad_fx;
2975 : UWord8 numDirections;
2976 :
2977 : /* use the nominal values without data-adaptivity */
2978 0 : numDirections = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 );
2979 0 : move16();
2980 :
2981 : /* azi/ele/nrg into vectors for each sub-frame and band */
2982 0 : FOR( i = 0; i < numDirections; i++ )
2983 : {
2984 0 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
2985 : {
2986 : 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;
2987 : 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;
2988 0 : x_sum_fx = 0;
2989 0 : y_sum_fx = 0;
2990 0 : z_sum_fx = 0;
2991 0 : energy_sum_fx = 0;
2992 0 : spread_coh_sum_fx = 0;
2993 0 : surr_coh_sum_fx = 0;
2994 0 : x_sum_e = 0; /*exponent for x_sum_fx*/
2995 0 : y_sum_e = 0; /*exponent for y_sum_fx*/
2996 0 : z_sum_e = 0; /*exponent for z_sum_fx*/
2997 0 : energy_sum_e = 0; /*exponent for energy_sum_fx*/
2998 0 : spread_coh_sum_e = 0; /*exponent for spread_coh_sum_fx*/
2999 0 : surr_coh_sum_e = 0; /*exponent for surr_coh_sum_fx*/
3000 0 : temp1 = 0; /* to store temporary computations*/
3001 0 : temp2 = 0; /* to store temporary computations*/
3002 0 : temp1_e = 0; /*to store temporary exponents*/
3003 0 : temp2_e = 0; /*to store temporary exponents*/
3004 0 : move32();
3005 0 : move32();
3006 0 : move32();
3007 0 : move32();
3008 0 : move32();
3009 0 : move32();
3010 0 : move32();
3011 0 : move32();
3012 0 : move16();
3013 0 : move16();
3014 0 : move16();
3015 0 : move16();
3016 0 : move16();
3017 0 : move16();
3018 0 : move16();
3019 0 : move16();
3020 :
3021 0 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3022 : {
3023 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*/
3024 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*/
3025 0 : vec_len_fx = Mpy_32_32( hMeta->directional_meta[i].energy_ratio_fx[j][k] /*q30*/, energy[j][k] ); /*exponent=energy_e+1*/
3026 0 : vec_len_e = add( energy_e[j][k], 1 );
3027 :
3028 : /* energy-weighted sum over subframes */
3029 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*/
3030 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*/
3031 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*/
3032 :
3033 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*/
3034 :
3035 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*/
3036 0 : IF( i == 0 )
3037 : {
3038 : /* this is in common metadata and not in each direction */
3039 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*/
3040 : }
3041 : }
3042 :
3043 : /* the data from the combined sub-frames is written into the first sub-frame band */
3044 0 : j = 0;
3045 0 : move16();
3046 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*/
3047 0 : move32();
3048 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*/
3049 0 : temp2_e = temp1_e;
3050 0 : temp2 = Sqrt32( temp1, &temp2_e ); /*temp2_e*/
3051 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*/
3052 0 : move32();
3053 0 : IF( EQ_16( useSphGrid, TRUE ) )
3054 : {
3055 :
3056 0 : hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16_fx( &( hMeta->directional_meta[i].elevation_fx[j][k] ),
3057 0 : &( hMeta->directional_meta[i].azimuth_fx[j][k] ), Sph_Grid16 );
3058 0 : move16();
3059 : }
3060 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*/
3061 0 : vec_len_fx = Sqrt32( vec_len_fx, &vec_len_e ); /*vec_len_e*/
3062 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*/
3063 0 : move32();
3064 0 : temp2_e = add( temp2_e, sub( vec_len_e, energy_sum_e ) );
3065 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*/
3066 0 : move32();
3067 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 );
3068 0 : move16();
3069 0 : temp2_e = add( temp2_e, sub( spread_coh_sum_e, energy_sum_e ) );
3070 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*/
3071 0 : move16();
3072 0 : IF( i == 0 )
3073 : {
3074 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 );
3075 0 : move16();
3076 0 : temp2_e = add( temp2_e, sub( surr_coh_sum_e, energy_sum_e ) );
3077 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*/
3078 0 : move16();
3079 : }
3080 :
3081 : /* copy the same value to all subframes */
3082 0 : FOR( j = 1; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3083 : {
3084 0 : hMeta->directional_meta[i].azimuth_fx[j][k] = hMeta->directional_meta[i].azimuth_fx[0][k]; /*q22*/
3085 0 : hMeta->directional_meta[i].elevation_fx[j][k] = hMeta->directional_meta[i].elevation_fx[0][k]; /*q22*/
3086 0 : hMeta->directional_meta[i].energy_ratio_fx[j][k] = hMeta->directional_meta[i].energy_ratio_fx[0][k]; /*q30*/
3087 0 : hMeta->directional_meta[i].spread_coherence_fx[j][k] = hMeta->directional_meta[i].spread_coherence_fx[0][k]; /*q15*/
3088 0 : move32();
3089 0 : move32();
3090 0 : move32();
3091 0 : move16();
3092 0 : IF( i == 0 )
3093 : {
3094 0 : hMeta->common_meta.surround_coherence_fx[j][k] = hMeta->common_meta.surround_coherence_fx[0][k]; /*q15*/
3095 0 : move16();
3096 : }
3097 : }
3098 : }
3099 : }
3100 :
3101 0 : FOR( k = 0; k < MASA_FREQUENCY_BANDS; k++ )
3102 : {
3103 0 : FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
3104 : {
3105 0 : IF( EQ_16( numDirections, 2 ) )
3106 : {
3107 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*/
3108 : }
3109 : ELSE
3110 : {
3111 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*/
3112 : }
3113 0 : move32();
3114 0 : hMeta->common_meta.remainder_to_total_ratio_fx[j][k] = 0; /*q30*/
3115 0 : move32();
3116 : }
3117 : }
3118 :
3119 0 : return;
3120 : }
3121 :
3122 :
3123 : /*-------------------------------------------------------------------*
3124 : * copy_masa_metadata_subframe()
3125 : *
3126 : * Copy MASA metadata frame subframe contents
3127 : *-------------------------------------------------------------------*/
3128 158504 : static void copy_masa_metadata_subframe_fx(
3129 : const MASA_METADATA_HANDLE hMetaFrom, /* i : MASA frame metdata to be copied */
3130 : const UWord8 sfFrom, /* i : subframe index of the copy source */
3131 : MASA_METADATA_HANDLE hMetaTo, /* o : MASA frame metadata copy destination */
3132 : const UWord8 sfTo /* i : subframe index of the copy target */
3133 : )
3134 : {
3135 : UWord8 dir;
3136 :
3137 : /* directional metadata */
3138 475512 : FOR( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ )
3139 : {
3140 317008 : Copy32( hMetaFrom->directional_meta[dir].azimuth_fx[sfFrom], hMetaTo->directional_meta[dir].azimuth_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q22
3141 317008 : Copy32( hMetaFrom->directional_meta[dir].elevation_fx[sfFrom], hMetaTo->directional_meta[dir].elevation_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q22
3142 317008 : Copy32( hMetaFrom->directional_meta[dir].energy_ratio_fx[sfFrom], hMetaTo->directional_meta[dir].energy_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3143 317008 : Copy( hMetaFrom->directional_meta[dir].spread_coherence_fx[sfFrom], hMetaTo->directional_meta[dir].spread_coherence_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q15
3144 : }
3145 :
3146 : /* common metadata */
3147 158504 : Copy32( hMetaFrom->common_meta.diffuse_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.diffuse_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3148 158504 : Copy( hMetaFrom->common_meta.surround_coherence_fx[sfFrom], hMetaTo->common_meta.surround_coherence_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q15
3149 158504 : Copy32( hMetaFrom->common_meta.remainder_to_total_ratio_fx[sfFrom], hMetaTo->common_meta.remainder_to_total_ratio_fx[sfTo], MASA_FREQUENCY_BANDS ); // Q30
3150 :
3151 158504 : return;
3152 : }
3153 :
3154 : /*-------------------------------------------------------------------*
3155 : * copy_masa_metadata()
3156 : *
3157 : * Copy MASA metada frame contents
3158 : *-------------------------------------------------------------------*/
3159 39626 : static void copy_masa_metadata_fx(
3160 : const MASA_METADATA_HANDLE hMetaFrom, /* i : MASA frame metadata to be copied */
3161 : MASA_METADATA_HANDLE hMetaTo /* o : MASA frame metadata copy destination */
3162 : )
3163 : {
3164 : UWord8 sf, byte_idx;
3165 :
3166 : /* descriptive metadata */
3167 356634 : FOR( byte_idx = 0; byte_idx < 8; byte_idx++ )
3168 : {
3169 317008 : hMetaTo->descriptive_meta.formatDescriptor[byte_idx] = hMetaFrom->descriptive_meta.formatDescriptor[byte_idx];
3170 317008 : move16();
3171 : }
3172 :
3173 39626 : hMetaTo->descriptive_meta.numberOfDirections = hMetaFrom->descriptive_meta.numberOfDirections;
3174 39626 : hMetaTo->descriptive_meta.numberOfChannels = hMetaFrom->descriptive_meta.numberOfChannels;
3175 39626 : hMetaTo->descriptive_meta.sourceFormat = hMetaFrom->descriptive_meta.sourceFormat;
3176 39626 : hMetaTo->descriptive_meta.transportDefinition = hMetaFrom->descriptive_meta.transportDefinition;
3177 39626 : hMetaTo->descriptive_meta.channelAngle = hMetaFrom->descriptive_meta.channelAngle;
3178 39626 : hMetaTo->descriptive_meta.channelDistance = hMetaFrom->descriptive_meta.channelDistance;
3179 39626 : hMetaTo->descriptive_meta.channelLayout = hMetaFrom->descriptive_meta.channelLayout;
3180 39626 : move16();
3181 39626 : move16();
3182 39626 : move16();
3183 39626 : move16();
3184 39626 : move16();
3185 39626 : move16();
3186 39626 : move16();
3187 :
3188 : /* directional and common metadata */
3189 198130 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
3190 : {
3191 158504 : copy_masa_metadata_subframe_fx( hMetaFrom, sf, hMetaTo, sf );
3192 : }
3193 :
3194 39626 : return;
3195 : }
3196 :
3197 : /*-------------------------------------------------------------------*
3198 : * are_masa_subframes_similar()
3199 : *
3200 : * Compare the similarity of MASA metadata in two sub-frames
3201 : *-------------------------------------------------------------------*/
3202 :
3203 : /* r: similarity decision */
3204 175035 : static UWord8 are_masa_subframes_similar_fx(
3205 : const MASA_METADATA_HANDLE frame1, /* i : MASA metadata frame 1 */
3206 : const UWord8 sf1_idx, /* i : index of the subframe of frame1 to inspect */
3207 : const MASA_METADATA_HANDLE frame2, /* i : MASA metadata frame 2 */
3208 : const UWord8 sf2_idx /* i : index of the subframe of frame2 to inspect */
3209 : )
3210 : {
3211 : UWord8 num_dir;
3212 : UWord8 dir;
3213 : UWord8 band_idx;
3214 : UWord8 sf_differ;
3215 :
3216 175035 : num_dir = frame1->descriptive_meta.numberOfDirections;
3217 175035 : dir = 0;
3218 175035 : band_idx = 0;
3219 175035 : sf_differ = FALSE;
3220 175035 : move16();
3221 175035 : move16();
3222 175035 : move16();
3223 175035 : move16();
3224 :
3225 175035 : IF( NE_16( num_dir, frame2->descriptive_meta.numberOfDirections ) )
3226 : {
3227 0 : sf_differ = TRUE;
3228 0 : move16();
3229 : }
3230 : ELSE
3231 : {
3232 : /* check per-direction metadata */
3233 175035 : dir = 0;
3234 175035 : band_idx = 0;
3235 175035 : move16();
3236 175035 : move16();
3237 :
3238 360870 : WHILE( ( sf_differ == FALSE ) && ( dir <= num_dir ) )
3239 : {
3240 185835 : test();
3241 185835 : band_idx = 0;
3242 185835 : move16();
3243 1244235 : WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
3244 : {
3245 1200135 : test();
3246 : Word32 azi_dif_fx;
3247 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
3248 1200135 : IF( GT_32( azi_dif_fx, 180 << Q22 ) )
3249 16892 : azi_dif_fx = L_sub( 360 << Q22, azi_dif_fx ); // Q22
3250 :
3251 1200135 : IF( GT_32( azi_dif_fx, ONE_IN_Q21 /*0.5 in Q22*/ ) )
3252 : {
3253 139100 : sf_differ = TRUE;
3254 139100 : move16();
3255 139100 : BREAK;
3256 : }
3257 :
3258 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 ) )
3259 : {
3260 2616 : sf_differ = TRUE;
3261 2616 : move16();
3262 2616 : BREAK;
3263 : }
3264 :
3265 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 ) )
3266 : {
3267 19 : sf_differ = TRUE;
3268 19 : move16();
3269 19 : BREAK;
3270 : }
3271 :
3272 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 ) )
3273 : {
3274 0 : sf_differ = TRUE;
3275 0 : move16();
3276 0 : BREAK;
3277 : }
3278 :
3279 1058400 : band_idx = (UWord8) add( band_idx, 1 );
3280 1058400 : move16();
3281 : }
3282 185835 : dir = (UWord8) add( dir, 1 );
3283 185835 : move16();
3284 : }
3285 :
3286 : /* check the common metadata */
3287 175035 : WHILE( ( sf_differ == FALSE ) && ( band_idx < MASA_FREQUENCY_BANDS ) )
3288 : {
3289 0 : test();
3290 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 ) )
3291 : {
3292 0 : sf_differ = TRUE;
3293 0 : move16();
3294 0 : BREAK;
3295 : }
3296 :
3297 0 : band_idx = (UWord8) add( band_idx, 1 );
3298 0 : move16();
3299 : }
3300 : }
3301 :
3302 175035 : IF( sf_differ )
3303 : {
3304 141735 : return FALSE;
3305 : }
3306 : ELSE
3307 : {
3308 33300 : return TRUE;
3309 : }
3310 : }
3311 :
3312 : /*-------------------------------------------------------------------*
3313 : * detect_framing_async()
3314 : *
3315 : * Compare the similarity of MASA metadata in two sub-frames
3316 : * Analysis result is stored in hMasa->data.sync_state, and
3317 : * potentially hMasa->masaMetadata is modified
3318 : *-------------------------------------------------------------------*/
3319 39626 : static void detect_framing_async_fx(
3320 : MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder structure */
3321 : )
3322 : {
3323 : MASA_METADATA_HANDLE current_meta;
3324 : MASA_METADATA_HANDLE previous_meta;
3325 : MASA_SYNC_HANDLE sync_state;
3326 : MASA_FRAME_MODE frame_mode;
3327 : UWord8 n_sim_start, n_sim_stop, sf_idx;
3328 : UWord8 found_offset;
3329 :
3330 39626 : current_meta = &( hMasa->masaMetadata ); /* metadata from current frame */
3331 39626 : sync_state = &( hMasa->data.sync_state ); /* synchronization structure */
3332 39626 : previous_meta = &( sync_state->previous_metadata );
3333 :
3334 : /* check current frame, how many are similar from the start and from the end */
3335 39626 : n_sim_start = 1;
3336 39626 : move16();
3337 56276 : FOR( sf_idx = n_sim_start; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
3338 : {
3339 50726 : IF( EQ_16( are_masa_subframes_similar_fx( current_meta, 0, current_meta, sf_idx ), TRUE ) )
3340 : {
3341 16650 : n_sim_start = (UWord8) add( sf_idx, 1 );
3342 16650 : move16();
3343 : }
3344 : ELSE
3345 : {
3346 34076 : BREAK;
3347 : }
3348 : }
3349 :
3350 : /* number of similar sub-frames starting from the end of the frame */
3351 39626 : IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) ) /* shortcut */
3352 : {
3353 5550 : n_sim_stop = n_sim_start;
3354 5550 : move16();
3355 : }
3356 : ELSE
3357 : {
3358 34076 : n_sim_stop = 1;
3359 34076 : move16();
3360 34076 : FOR( sf_idx = 2; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ )
3361 : {
3362 : /* we need to check only the two middle sub-frames, as all being the same would have taken the shortcut above */
3363 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 ) )
3364 : {
3365 0 : n_sim_stop = sf_idx;
3366 0 : move16();
3367 : }
3368 : ELSE
3369 : {
3370 34076 : BREAK;
3371 : }
3372 : }
3373 : }
3374 :
3375 39626 : frame_mode = MASA_FRAME_4SF; /* default mode: 4sf */
3376 39626 : move16();
3377 39626 : IF( GT_16( sync_state->prev_offset, MAX_PARAM_SPATIAL_SUBFRAMES - 2 ) )
3378 : {
3379 : /* earlier offset was large => reset the offset */
3380 0 : found_offset = 0;
3381 : }
3382 : ELSE
3383 : {
3384 : /* keep previous offset unless something else is found. alternatively, we could reset always */
3385 39626 : found_offset = sync_state->prev_offset;
3386 : }
3387 39626 : move16();
3388 :
3389 39626 : test();
3390 39626 : test();
3391 39626 : IF( EQ_16( n_sim_start, MAX_PARAM_SPATIAL_SUBFRAMES ) && EQ_16( n_sim_stop, MAX_PARAM_SPATIAL_SUBFRAMES ) )
3392 : {
3393 : /* full frame consists of similar sub-frames */
3394 5550 : frame_mode = MASA_FRAME_1SF;
3395 5550 : move16();
3396 5550 : test();
3397 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 ) )
3398 : {
3399 : /* > 4 sub-frames of similar data */
3400 0 : IF( LT_16( sync_state->prev_sim_stop, 3 ) )
3401 : {
3402 : /* can nicely align the framing with the earlier data and a small offset */
3403 0 : found_offset = sync_state->prev_sim_stop;
3404 : }
3405 : ELSE
3406 : {
3407 : /* too many similar sub-frames to determine the offset accurately => keep earlier value */
3408 0 : found_offset = sync_state->prev_offset;
3409 : }
3410 0 : move16();
3411 : }
3412 : ELSE
3413 : {
3414 : /* earlier window was different => reset the offset */
3415 5550 : found_offset = 0;
3416 5550 : move16();
3417 : }
3418 : }
3419 34076 : ELSE IF( EQ_16( n_sim_stop, 3 ) )
3420 : {
3421 : /* first sub-frame different that the rest 3
3422 : => make a risky guess that the future sf would be the same too and we're in an offset case */
3423 0 : frame_mode = MASA_FRAME_1SF;
3424 0 : found_offset = 3;
3425 0 : move16();
3426 0 : move16();
3427 : }
3428 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 ) )
3429 : {
3430 : /* seeing data similar to past */
3431 0 : test();
3432 0 : IF( GT_16( n_sim_start, 1 ) && ( GE_16( add( n_sim_start, sync_state->prev_sim_stop ), MAX_PARAM_SPATIAL_SUBFRAMES ) ) )
3433 : {
3434 : /* with the past, would have at least one long frame similar subframes */
3435 0 : frame_mode = MASA_FRAME_1SF;
3436 0 : move16();
3437 :
3438 0 : IF( sync_state->prev_offset == 0 )
3439 : {
3440 0 : found_offset = (UWord8) s_min( 2, sync_state->prev_sim_stop );
3441 : }
3442 : ELSE
3443 : {
3444 0 : found_offset = sync_state->prev_offset;
3445 0 : move16();
3446 : }
3447 : }
3448 : }
3449 :
3450 : /* keep the original contents of the frame, but then perform interpolation later */
3451 : /* just copy current frame to storage */
3452 39626 : copy_masa_metadata_fx( current_meta, previous_meta );
3453 :
3454 39626 : sync_state->prev_sim_stop = n_sim_stop;
3455 39626 : sync_state->prev_offset = found_offset;
3456 39626 : sync_state->frame_mode = frame_mode;
3457 39626 : move16();
3458 39626 : move16();
3459 39626 : move16();
3460 :
3461 39626 : return;
3462 : }
3463 :
3464 : /*-------------------------------------------------------------------*
3465 : * masa_metadata_direction_alignment()
3466 : *
3467 : * In 2dir MASA metadata, determine the ordering of the directional
3468 : * fields such that the azi/ele change across time is minimized.
3469 : *-------------------------------------------------------------------*/
3470 39626 : static void masa_metadata_direction_alignment_fx(
3471 : MASA_ENCODER_HANDLE hMasa /* i/o: MASA encoder handle */
3472 : )
3473 : {
3474 : UWord8 band, n_dirs;
3475 : MASA_DIR_ALIGN_HANDLE hAlignState;
3476 : MASA_METADATA_HANDLE hMeta;
3477 39626 : hAlignState = &( hMasa->data.dir_align_state );
3478 39626 : hMeta = &( hMasa->masaMetadata );
3479 :
3480 39626 : n_dirs = (UWord8) add( hMeta->descriptive_meta.numberOfDirections, 1 ); /* 1-based */
3481 39626 : move16();
3482 990650 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
3483 : {
3484 : UWord8 sf;
3485 : Word32 diff_swap_fx;
3486 : Word32 diff_no_swap_fx;
3487 :
3488 : /* trade 2*(cos+sin) against storing the values between frames */
3489 : Word16 prev_ele_dir1_sin_fx, prev_ele_dir2_sin_fx;
3490 : Word16 prev_ele_dir1_cos_fx, prev_ele_dir2_cos_fx;
3491 :
3492 951024 : prev_ele_dir1_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3493 951024 : prev_ele_dir2_sin_fx = getSineWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3494 :
3495 951024 : prev_ele_dir1_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir1_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3496 951024 : prev_ele_dir2_cos_fx = getCosWord16R2( extract_l( Mpy_32_32( hAlignState->previous_ele_dir2_fx[band], 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3497 :
3498 4755120 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
3499 : {
3500 : Word32 azi_rad1_fx, ele_rad1_fx;
3501 : Word32 azi_rad2_fx, ele_rad2_fx;
3502 : Word16 cos_ele1_fx, cos_ele2_fx;
3503 : Word16 sin_ele1_fx, sin_ele2_fx;
3504 : Word16 temp1;
3505 : Word32 temp2;
3506 : Word16 temp1_e;
3507 :
3508 :
3509 3804096 : azi_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3510 3804096 : ele_rad1_fx = Mpy_32_16_1( hMeta->directional_meta[0].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3511 :
3512 3804096 : IF( GT_16( n_dirs, 1 ) )
3513 : {
3514 950400 : azi_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].azimuth_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3515 950400 : ele_rad2_fx = Mpy_32_16_1( hMeta->directional_meta[1].elevation_fx[sf][band], 572 /*PI_OVER_180 q15*/ ); /*q22*/
3516 :
3517 950400 : test();
3518 950400 : test();
3519 950400 : test();
3520 950400 : test();
3521 950400 : test();
3522 950400 : test();
3523 : /* quick checks to detect constant data and earlier flip */
3524 950400 : IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
3525 : LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
3526 : LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) &&
3527 : LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) )
3528 : {
3529 91800 : diff_swap_fx = ONE_IN_Q13; /*1 q13*/
3530 91800 : move32();
3531 91800 : diff_no_swap_fx = 0;
3532 91800 : move32();
3533 : /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
3534 91800 : sin_ele1_fx = prev_ele_dir1_sin_fx; /*q15*/
3535 91800 : sin_ele2_fx = prev_ele_dir2_sin_fx; /*q15*/
3536 91800 : cos_ele1_fx = prev_ele_dir1_cos_fx; /*q15*/
3537 91800 : cos_ele2_fx = prev_ele_dir2_cos_fx; /*q15*/
3538 91800 : move16();
3539 91800 : move16();
3540 91800 : move16();
3541 91800 : move16();
3542 : }
3543 858600 : ELSE IF( LT_32( L_abs( L_sub( azi_rad1_fx, hAlignState->previous_azi_dir2_fx[band] ) ), EPSILON_FX ) &&
3544 : LT_32( L_abs( L_sub( azi_rad2_fx, hAlignState->previous_azi_dir1_fx[band] ) ), EPSILON_FX ) &&
3545 : LT_32( L_abs( L_sub( ele_rad1_fx, hAlignState->previous_ele_dir2_fx[band] ) ), EPSILON_FX ) &&
3546 : LT_32( L_abs( L_sub( ele_rad2_fx, hAlignState->previous_ele_dir1_fx[band] ) ), EPSILON_FX ) )
3547 : {
3548 37800 : diff_swap_fx = 0;
3549 37800 : move32();
3550 37800 : diff_no_swap_fx = ONE_IN_Q13; /*1.0 q13*/
3551 37800 : move32();
3552 : /* cached values that will be used for the short-cuts and over-written by the real computations, if done */
3553 37800 : sin_ele1_fx = prev_ele_dir2_sin_fx; /*q15*/
3554 37800 : sin_ele2_fx = prev_ele_dir1_sin_fx; /*q15*/
3555 37800 : cos_ele1_fx = prev_ele_dir2_cos_fx; /*q15*/
3556 37800 : cos_ele2_fx = prev_ele_dir1_cos_fx; /*q15*/
3557 37800 : move16();
3558 37800 : move16();
3559 37800 : move16();
3560 37800 : move16();
3561 : }
3562 : ELSE
3563 : {
3564 : /* angular distance of the two vectors */
3565 : /* pre-compute values for re-use */
3566 820800 : sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3567 820800 : sin_ele2_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3568 :
3569 820800 : cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3570 820800 : cos_ele2_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad2_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3571 :
3572 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*/
3573 820800 : temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ ); /*q15*/
3574 820800 : temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir1_sin_fx ), temp1 ); /*q15*/
3575 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3576 820800 : move16();
3577 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3578 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3579 820800 : diff_no_swap_fx = L_deposit_l( temp1 ); /*q13*/
3580 :
3581 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*/
3582 820800 : temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ ); /*q15*/
3583 820800 : temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir2_sin_fx ), temp1 ); /*q15*/
3584 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3585 820800 : move16();
3586 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3587 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3588 820800 : diff_no_swap_fx = L_add( diff_no_swap_fx, temp1 ); /*q13*/
3589 :
3590 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*/
3591 820800 : temp1 = mult( mult( temp1, cos_ele1_fx ) /*q31*/, prev_ele_dir2_cos_fx /*q15*/ ); /*q15*/
3592 820800 : temp1 = add_sat( mult( sin_ele1_fx, prev_ele_dir2_sin_fx ), temp1 ); /*q15*/
3593 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3594 820800 : move16();
3595 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3596 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3597 820800 : diff_swap_fx = L_deposit_l( temp1 ); /*q13*/
3598 :
3599 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*/
3600 820800 : temp1 = mult( mult( temp1, cos_ele2_fx ) /*q31*/, prev_ele_dir1_cos_fx /*q15*/ ); /*q15*/
3601 820800 : temp1 = add_sat( mult( sin_ele2_fx, prev_ele_dir1_sin_fx ), temp1 ); /*q15*/
3602 820800 : temp1_e = 1; /*stores expoenent for square root operation*/
3603 820800 : move16();
3604 820800 : temp2 = Sqrt32( L_sub( ONE_IN_Q30, L_mult0( temp1, temp1 ) ), &temp1_e ); /*31-temp1_e*/
3605 820800 : temp1 = BASOP_util_atan2( temp2, temp1, sub( temp1_e, 16 ) ); /*q13*/
3606 820800 : diff_swap_fx = L_add( diff_swap_fx, temp1 ); /*q13*/
3607 : }
3608 : }
3609 : ELSE
3610 : {
3611 : /* 1dir */
3612 2853696 : sin_ele1_fx = getSineWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3613 2853696 : cos_ele1_fx = getCosWord16R2( extract_l( Mpy_32_32( ele_rad1_fx, 2670177 /*2^24/(2*pi)*/ ) ) ); /*q15*/
3614 :
3615 2853696 : azi_rad2_fx = 0;
3616 2853696 : ele_rad2_fx = 0;
3617 2853696 : move32();
3618 2853696 : move32();
3619 :
3620 2853696 : sin_ele2_fx = 0; /* sin(0) */
3621 2853696 : cos_ele2_fx = MAX_16; /* cos(0) in Q15*/
3622 2853696 : move16();
3623 2853696 : move16();
3624 :
3625 2853696 : diff_swap_fx = ONE_IN_Q13; /*1.0 in Q13*/
3626 2853696 : diff_no_swap_fx = 0;
3627 2853696 : move32();
3628 2853696 : move32();
3629 : }
3630 :
3631 3804096 : test();
3632 3804096 : IF( GT_16( n_dirs, 1 ) && GT_32( diff_no_swap_fx, diff_swap_fx ) )
3633 121788 : {
3634 : /* swap the metadata of the two directions in this TF-tile */
3635 : Word32 tmp_val;
3636 : Word16 tmp_val_16;
3637 : UWord16 tmp_int_val;
3638 121788 : tmp_val = hMeta->directional_meta[0].azimuth_fx[sf][band]; /*q22*/
3639 121788 : hMeta->directional_meta[0].azimuth_fx[sf][band] = hMeta->directional_meta[1].azimuth_fx[sf][band]; /*q22*/
3640 121788 : hMeta->directional_meta[1].azimuth_fx[sf][band] = tmp_val; /*q22*/
3641 121788 : move32();
3642 121788 : move32();
3643 121788 : move32();
3644 :
3645 121788 : tmp_val = hMeta->directional_meta[0].elevation_fx[sf][band]; /*q22*/
3646 121788 : hMeta->directional_meta[0].elevation_fx[sf][band] = hMeta->directional_meta[1].elevation_fx[sf][band]; /*q22*/
3647 121788 : hMeta->directional_meta[1].elevation_fx[sf][band] = tmp_val; /*q22*/
3648 121788 : move32();
3649 121788 : move32();
3650 121788 : move32();
3651 :
3652 121788 : tmp_int_val = hMeta->directional_meta[0].spherical_index[sf][band]; /*q0*/
3653 121788 : hMeta->directional_meta[0].spherical_index[sf][band] = hMeta->directional_meta[1].spherical_index[sf][band]; /*q0*/
3654 121788 : hMeta->directional_meta[1].spherical_index[sf][band] = tmp_int_val; /*q0*/
3655 121788 : move32();
3656 121788 : move32();
3657 121788 : move32();
3658 :
3659 121788 : tmp_val = hMeta->directional_meta[0].energy_ratio_fx[sf][band]; /*q30*/
3660 121788 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = hMeta->directional_meta[1].energy_ratio_fx[sf][band]; /*q30*/
3661 121788 : hMeta->directional_meta[1].energy_ratio_fx[sf][band] = tmp_val; /*q30*/
3662 121788 : move32();
3663 121788 : move32();
3664 121788 : move32();
3665 :
3666 121788 : tmp_val_16 = hMeta->directional_meta[0].spread_coherence_fx[sf][band]; /*q15*/
3667 121788 : hMeta->directional_meta[0].spread_coherence_fx[sf][band] = hMeta->directional_meta[1].spread_coherence_fx[sf][band]; /*q15*/
3668 121788 : hMeta->directional_meta[1].spread_coherence_fx[sf][band] = tmp_val_16; /*q15*/
3669 121788 : move16();
3670 121788 : move16();
3671 121788 : move16();
3672 :
3673 121788 : hAlignState->previous_azi_dir1_fx[band] = azi_rad2_fx; /*q22*/
3674 121788 : hAlignState->previous_ele_dir1_fx[band] = ele_rad2_fx; /*q22*/
3675 121788 : move32();
3676 121788 : move32();
3677 :
3678 121788 : hAlignState->previous_azi_dir2_fx[band] = azi_rad1_fx; /*q22*/
3679 121788 : hAlignState->previous_ele_dir2_fx[band] = ele_rad1_fx; /*q22*/
3680 121788 : move32();
3681 121788 : move32();
3682 :
3683 121788 : prev_ele_dir1_cos_fx = cos_ele2_fx; /*q15*/
3684 121788 : prev_ele_dir1_sin_fx = sin_ele2_fx; /*q15*/
3685 121788 : move16();
3686 121788 : move16();
3687 :
3688 121788 : prev_ele_dir2_cos_fx = cos_ele1_fx; /*q15*/
3689 121788 : prev_ele_dir2_sin_fx = sin_ele1_fx; /*q15*/
3690 121788 : move16();
3691 121788 : move16();
3692 : }
3693 : ELSE
3694 : {
3695 3682308 : hAlignState->previous_azi_dir1_fx[band] = azi_rad1_fx; /*q22*/
3696 3682308 : hAlignState->previous_ele_dir1_fx[band] = ele_rad1_fx; /*q22*/
3697 3682308 : move32();
3698 3682308 : move32();
3699 :
3700 3682308 : hAlignState->previous_azi_dir2_fx[band] = azi_rad2_fx; /*q22*/
3701 3682308 : hAlignState->previous_ele_dir2_fx[band] = ele_rad2_fx; /*q22*/
3702 3682308 : move32();
3703 3682308 : move32();
3704 :
3705 3682308 : prev_ele_dir1_cos_fx = cos_ele1_fx; /*q15*/
3706 3682308 : prev_ele_dir1_sin_fx = sin_ele1_fx; /*q15*/
3707 3682308 : move16();
3708 3682308 : move16();
3709 :
3710 3682308 : prev_ele_dir2_cos_fx = cos_ele2_fx; /*q15*/
3711 3682308 : prev_ele_dir2_sin_fx = sin_ele2_fx; /*q15*/
3712 3682308 : move16();
3713 3682308 : move16();
3714 : }
3715 : } /* sf */
3716 : } /* band */
3717 :
3718 39626 : return;
3719 : }
3720 :
3721 : /*-------------------------------------------------------------------*
3722 : * ivas_merge_masa_metadata()
3723 : *
3724 : *
3725 : *-------------------------------------------------------------------*/
3726 3996 : void ivas_merge_masa_metadata_fx(
3727 : MASA_ENCODER_HANDLE hMasa, /* i/o: MASA enc handle. source for MASA metadata and combined metadata will be here */
3728 : OMASA_SPATIAL_META_HANDLE hOMasaMeta /* i : ISM-object metadata to be merged with the MASA metadata */
3729 : )
3730 : {
3731 : Word16 sf, band;
3732 : UWord8 numCodingBands;
3733 : UWord8 numDirections;
3734 : UWord8 numSf;
3735 : MASA_METADATA_HANDLE hMeta;
3736 : Word16 energyTimesRatioMASA_e[2];
3737 : Word16 total_diff_nrg_e;
3738 : Word16 energyMerged_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
3739 : Word32 energyTimesRatioISM_fx; /*energyTimesRatioISM_e*/
3740 : Word16 energyTimesRatioISM_e;
3741 : Word32 energyTimesRatioMASA_fx[2]; /*energyTimesRatioMASA_e*/
3742 : Word32 total_diff_nrg_fx;
3743 : Word32 eneBand_fx; /*eneBand_e*/
3744 : Word16 eneBand_e;
3745 : Word32 energyMerged_fx[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; /*energyMerged_e*/
3746 : Word32 temp1 /*temp1_e*/, temp2 /*temp2_e*/;
3747 : Word16 temp1_e, temp2_e;
3748 :
3749 3996 : numCodingBands = hMasa->config.numCodingBands;
3750 3996 : numDirections = hMasa->config.numberOfDirections;
3751 3996 : IF( EQ_16( hMasa->config.joinedSubframes, TRUE ) )
3752 : {
3753 0 : numSf = 1;
3754 : }
3755 : ELSE
3756 : {
3757 3996 : numSf = 4;
3758 : }
3759 3996 : move16();
3760 3996 : move16();
3761 3996 : move16();
3762 3996 : hMeta = &( hMasa->masaMetadata );
3763 :
3764 19980 : FOR( sf = 0; sf < numSf; sf++ )
3765 : {
3766 396000 : FOR( band = 0; band < numCodingBands; band++ )
3767 : {
3768 : Word16 merge_dest;
3769 : Word32 dir_sum_fx; /*dir_sum_e*/
3770 : Word16 dir_sum_e;
3771 : UWord8 band_n_dirs;
3772 380016 : test();
3773 380016 : test();
3774 380016 : IF( EQ_16( numDirections, 1 ) || ( EQ_16( numDirections, 2 ) && hMasa->data.twoDirBands[band] == 0 ) )
3775 : {
3776 380016 : band_n_dirs = 1;
3777 : }
3778 : ELSE
3779 : {
3780 0 : band_n_dirs = 2;
3781 : }
3782 380016 : move16();
3783 :
3784 : /* Compute energies */
3785 380016 : eneBand_fx = hMasa->data.energy_fx[sf][band];
3786 380016 : eneBand_e = hMasa->data.energy_e[sf][band];
3787 380016 : move32();
3788 380016 : move16();
3789 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] );
3790 380016 : move32();
3791 :
3792 : /* Compute weights */
3793 380016 : energyTimesRatioMASA_fx[0] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[0].energy_ratio_fx[sf][band] );
3794 380016 : energyTimesRatioMASA_e[0] = add( eneBand_e, 1 );
3795 380016 : move32();
3796 380016 : move16();
3797 380016 : IF( EQ_16( band_n_dirs, 2 ) )
3798 : {
3799 0 : energyTimesRatioMASA_fx[1] = Mpy_32_32( eneBand_fx, hMeta->directional_meta[1].energy_ratio_fx[sf][band] ); // energyTimesRatioMASA_e
3800 0 : energyTimesRatioMASA_e[1] = add( eneBand_e, 1 );
3801 : }
3802 : ELSE
3803 : {
3804 380016 : energyTimesRatioMASA_fx[1] = 0; // energyTimesRatioMASA_e
3805 380016 : energyTimesRatioMASA_e[1] = 0;
3806 : }
3807 380016 : move32();
3808 380016 : move16();
3809 :
3810 : /* target is original MASA diffuseness */
3811 380016 : total_diff_nrg_fx = Mpy_32_32( eneBand_fx, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] ); // total_diff_nrg_e
3812 380016 : total_diff_nrg_e = add( eneBand_e, 1 );
3813 :
3814 : /* criterion is mean of ISM ratio and new ratio */
3815 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]*/
3816 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] )*/
3817 380016 : temp2_e = add( temp2_e, sub( total_diff_nrg_e, temp1_e ) );
3818 380016 : IF( temp2_e < 0 )
3819 : {
3820 305004 : temp2 = L_shl( temp2, temp2_e );
3821 305004 : temp2_e = 0;
3822 305004 : move16();
3823 : }
3824 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] ) )*/
3825 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] ) )*/
3826 380016 : energyTimesRatioISM_fx = Mpy_32_32( L_shr( temp2, 1 ), hMasa->data.hOmasaData->energy_ism_fx[sf][band] ); /*energyTimesRatioISM_e*/
3827 380016 : energyTimesRatioISM_e = add( temp2_e, hMasa->data.hOmasaData->energy_ism_fx_e[sf][band] );
3828 : /*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];*/
3829 :
3830 : /* Determine combined metadata based on the weights */
3831 380016 : merge_dest = -1;
3832 380016 : move16();
3833 380016 : test();
3834 380016 : test();
3835 380016 : test();
3836 380016 : test();
3837 380016 : test();
3838 380016 : test();
3839 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 ) ) ||
3840 : ( 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 ) ) )
3841 : {
3842 : /* 1dir and ISM the most energetic, or 2dir and ISM the more energetic than MASA1 */
3843 140970 : merge_dest = 0;
3844 : }
3845 239046 : 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 ) )
3846 : {
3847 : /* 2dir and ISM the most energetic and MASA2 the least energetic */
3848 0 : merge_dest = 1;
3849 : }
3850 380016 : move16();
3851 :
3852 380016 : IF( merge_dest >= 0 ) /* replace one MASA with ISM */
3853 : {
3854 140970 : hMeta->directional_meta[merge_dest].azimuth_fx[sf][band] = hOMasaMeta->directional_meta[0].azimuth_fx[sf][band]; /*q22*/
3855 140970 : hMeta->directional_meta[merge_dest].elevation_fx[sf][band] = hOMasaMeta->directional_meta[0].elevation_fx[sf][band]; /*q22*/
3856 140970 : move32();
3857 140970 : move32();
3858 : /* limit with the earlier direct-energy ratio */
3859 140970 : dir_sum_fx = temp2; /* new dir ratio */
3860 140970 : dir_sum_e = temp2_e;
3861 140970 : move32();
3862 140970 : move16();
3863 : /*dir_sum = 1.0f - total_diff_nrg / ( EPSILON + eneBand + hMasa->data.hOmasaData->energy_ism[sf][band] )*/
3864 140970 : IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( dir_sum_fx, dir_sum_e, hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band], 1 ), -1 ) )
3865 : {
3866 0 : hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = L_shl( dir_sum_fx, sub( dir_sum_e, 1 ) ); /*scaling to Q30*/
3867 : }
3868 : ELSE
3869 : {
3870 140970 : hMeta->directional_meta[merge_dest].energy_ratio_fx[sf][band] = hOMasaMeta->directional_meta[0].energy_ratio_fx[sf][band]; /*q30*/
3871 140970 : move32();
3872 : }
3873 : /* clip with original ISM dir */
3874 140970 : 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*/
3875 140970 : move32();
3876 140970 : move32(); /*hMeta->directional_meta[merge_dest].energy_ratio_fx*/
3877 :
3878 140970 : IF( hMasa->config.useCoherence )
3879 : {
3880 0 : hMeta->directional_meta[merge_dest].spread_coherence_fx[sf][band] = hOMasaMeta->directional_meta[0].spread_coherence_fx[sf][band]; /*q15*/
3881 0 : hMeta->common_meta.surround_coherence_fx[sf][band] = hOMasaMeta->common_meta.surround_coherence_fx[sf][band]; /*q15*/
3882 0 : move16();
3883 0 : move16();
3884 : }
3885 :
3886 : /* recompute direct energy ratios to match the diffuse ratio */
3887 : Word32 direct_quota_fx, direct_scaler_fx;
3888 : Word16 direct_scaler_e;
3889 140970 : direct_quota_fx = L_sub( ONE_IN_Q30, hMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
3890 140970 : IF( EQ_16( band_n_dirs, 1 ) )
3891 : {
3892 140970 : hMeta->directional_meta[0].energy_ratio_fx[sf][band] = direct_quota_fx; /*q30*/
3893 140970 : move32();
3894 : }
3895 : ELSE
3896 : {
3897 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*/
3898 0 : direct_scaler_fx = BASOP_Util_Divide3232_Scale( direct_quota_fx, L_add( EPSILON_FX, dir_sum_fx ), &direct_scaler_e );
3899 0 : direct_scaler_fx = L_shl( direct_scaler_fx, direct_scaler_e ); /*q31*/
3900 0 : direct_scaler_e = 0;
3901 0 : move16();
3902 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*/
3903 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*/
3904 0 : move32();
3905 0 : move32();
3906 : }
3907 : }
3908 : }
3909 : }
3910 :
3911 19980 : FOR( sf = 0; sf < numSf; sf++ )
3912 : {
3913 396000 : FOR( band = 0; band < numCodingBands; band++ )
3914 : {
3915 380016 : hMasa->data.energy_fx[sf][band] = energyMerged_fx[sf][band];
3916 380016 : hMasa->data.energy_e[sf][band] = energyMerged_e[sf][band];
3917 380016 : move32();
3918 380016 : move16();
3919 : }
3920 : }
3921 :
3922 3996 : return;
3923 : }
3924 30442 : static void quantize_ratio_ism_vector_ivas_fx(
3925 : const Word16 *ratio_ism, /* ratio_ism_e */
3926 : Word16 ratio_ism_e,
3927 : Word16 *idx, /* Q0 */
3928 : const Word16 nchan_ism,
3929 : const Word32 masa_to_total_energy_ratio,
3930 : const Word16 idx_sep_object )
3931 : {
3932 : Word16 i, j, best_i, best_i2;
3933 : Word16 dist, div, tmp, dist2, best_dist, temp, temp_e, tmp_e, idx_e, best_dist_e, dist_e, dist2_e;
3934 : Word16 part_idx_sum, max_sum_idx;
3935 : Word16 ratio_ism_loc[MAX_NUM_OBJECTS];
3936 : Word16 no_ism_loc;
3937 :
3938 30442 : max_sum_idx = sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 );
3939 :
3940 30442 : test();
3941 30442 : IF( GT_16( idx_sep_object, -1 ) )
3942 : {
3943 30442 : temp = BASOP_Util_Divide1616_Scale( 1, max_sum_idx, &temp_e );
3944 30442 : BASOP_Util_Add_MantExp( ratio_ism[idx_sep_object], ratio_ism_e, negate( temp ), temp_e, &tmp );
3945 :
3946 30442 : test();
3947 30442 : IF( tmp < 0 )
3948 : {
3949 : /* take it out from quantize function */
3950 28839 : Copy( ratio_ism, ratio_ism_loc, idx_sep_object ); // Q(15 - ratio_ism_e)
3951 28839 : Copy( &ratio_ism[idx_sep_object + 1], &ratio_ism_loc[idx_sep_object], nchan_ism - idx_sep_object - 1 );
3952 28839 : no_ism_loc = sub( nchan_ism, 1 );
3953 : }
3954 : ELSE
3955 : {
3956 1603 : no_ism_loc = nchan_ism;
3957 1603 : move16();
3958 1603 : Copy( ratio_ism, ratio_ism_loc, nchan_ism );
3959 : }
3960 : }
3961 : ELSE
3962 : {
3963 0 : no_ism_loc = nchan_ism;
3964 0 : move16();
3965 0 : Copy( ratio_ism, ratio_ism_loc, nchan_ism );
3966 : }
3967 :
3968 30442 : test();
3969 30442 : IF( GT_16( nchan_ism, 1 ) )
3970 : {
3971 30442 : test();
3972 30442 : IF( GE_32( masa_to_total_energy_ratio, MASA2TOTAL_THR_Q30 ) )
3973 : {
3974 3593 : distribute_evenly_ism_fx( idx, max_sum_idx, nchan_ism );
3975 : }
3976 : ELSE
3977 : {
3978 26849 : test();
3979 26849 : IF( GT_16( no_ism_loc, 1 ) )
3980 : {
3981 :
3982 26135 : dist = 0;
3983 26135 : dist_e = 0;
3984 26135 : div = div_s( 1, max_sum_idx ); // Q15
3985 26135 : move16();
3986 26135 : move16();
3987 :
3988 26135 : part_idx_sum = 0;
3989 26135 : move16();
3990 :
3991 95154 : FOR( i = 0; i < no_ism_loc; i++ )
3992 : {
3993 69019 : idx[i] = extract_l( L_shr( L_mult0( ratio_ism_loc[i], max_sum_idx ), sub( 15, ratio_ism_e ) ) ); // Q0
3994 69019 : move16();
3995 69019 : part_idx_sum = add( part_idx_sum, idx[i] );
3996 :
3997 69019 : tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( imult1616( idx[i], div ) ), 0, &tmp ); // tmp_e
3998 69019 : dist_e = BASOP_Util_Add_MantExp( dist, dist_e, mult( tmp, tmp ), add( tmp_e, tmp_e ), &dist ); // dist_e
3999 : }
4000 :
4001 26135 : best_dist = dist;
4002 26135 : best_dist_e = dist_e;
4003 26135 : best_i2 = -1;
4004 26135 : move16();
4005 26135 : move16();
4006 26135 : move16();
4007 :
4008 54119 : WHILE( ( part_idx_sum < max_sum_idx ) )
4009 : {
4010 27984 : best_i = -1;
4011 27984 : move16();
4012 : /* check which index to increase by 1 for a possible improvement */
4013 :
4014 102676 : FOR( i = 0; i < no_ism_loc; i++ )
4015 : {
4016 74692 : idx[i] = add( idx[i], 1 );
4017 74692 : move16();
4018 74692 : dist2 = 0;
4019 74692 : dist2_e = 0;
4020 74692 : move16();
4021 74692 : move16();
4022 :
4023 282124 : FOR( j = 0; j < no_ism_loc; j++ )
4024 : {
4025 207432 : Word32 temp1 = L_mult( idx[i], div ); // Q : 15 + 0 + 1
4026 207432 : Word16 temp1_n = norm_l( temp1 );
4027 207432 : Word16 temp1_16 = extract_h( L_shl( temp1, temp1_n ) ); // Q : Q + temp1_n - 16
4028 207432 : tmp_e = BASOP_Util_Add_MantExp( ratio_ism_loc[i], ratio_ism_e, negate( temp1_16 ), sub( 15, temp1_n ), &tmp ); // tmp_e
4029 207432 : dist2_e = BASOP_Util_Add_MantExp( dist2, dist2_e, mult_sat( tmp, tmp ), add( tmp_e, tmp_e ), &dist2 ); // dist_e
4030 : }
4031 :
4032 74692 : BASOP_Util_Add_MantExp( dist2, dist2_e, negate( best_dist ), best_dist_e, &tmp );
4033 74692 : test();
4034 74692 : IF( tmp < 0 )
4035 : {
4036 22944 : best_i2 = best_i;
4037 22944 : best_i = i;
4038 22944 : best_dist = dist2;
4039 22944 : best_dist_e = dist2_e;
4040 22944 : move16();
4041 22944 : move16();
4042 22944 : move16();
4043 22944 : move16();
4044 : }
4045 74692 : idx[i] = sub( idx[i], 1 );
4046 74692 : move16();
4047 : }
4048 :
4049 27984 : test();
4050 27984 : IF( GT_16( best_i, -1 ) )
4051 : {
4052 21738 : idx[best_i] = add( idx[best_i], 1 );
4053 21738 : move16();
4054 21738 : part_idx_sum = add( part_idx_sum, 1 );
4055 : }
4056 : ELSE
4057 : {
4058 6246 : test();
4059 6246 : IF( GT_16( best_i2, -1 ) )
4060 : {
4061 1043 : idx[best_i2] = add( idx[best_i2], 1 );
4062 1043 : move16();
4063 1043 : part_idx_sum = add( part_idx_sum, 1 );
4064 : }
4065 : ELSE
4066 : {
4067 5203 : idx[no_ism_loc - 1] = add( idx[no_ism_loc - 1], sub( max_sum_idx, part_idx_sum ) );
4068 5203 : move16();
4069 5203 : part_idx_sum = max_sum_idx;
4070 5203 : move16();
4071 : }
4072 : }
4073 : }
4074 26135 : assert( sum_s( idx, no_ism_loc ) == max_sum_idx );
4075 : }
4076 : ELSE
4077 : {
4078 714 : idx[0] = max_sum_idx;
4079 714 : move16();
4080 : }
4081 :
4082 26849 : test();
4083 26849 : IF( LT_16( no_ism_loc, nchan_ism ) )
4084 : {
4085 : /* insert back the ratio of the separated object */
4086 70971 : FOR( i = nchan_ism - 1; i > idx_sep_object; i-- )
4087 : {
4088 45655 : idx[i] = idx[i - 1];
4089 45655 : move16();
4090 : }
4091 25316 : idx[idx_sep_object] = 0;
4092 25316 : move16();
4093 : }
4094 : }
4095 : }
4096 : ELSE
4097 : {
4098 : // idx[0] = (int16_t) ( ( ratio_ism[0] ) * ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) + 0.5f );
4099 0 : tmp = imult1616( ratio_ism[0], sub( shl( 1, PARAM_ISM_POW_RATIO_NBITS ), 1 ) ); // tmp_e
4100 0 : tmp_e = ratio_ism_e;
4101 0 : move16();
4102 0 : idx_e = BASOP_Util_Add_MantExp( tmp, tmp_e, 16384 /* 0.5 in Q15 */, 0, &idx[0] ); // idx_e
4103 0 : idx[0] = shl( idx[0], sub( idx_e, 15 ) ); // Q0
4104 0 : move16();
4105 : }
4106 :
4107 30442 : return;
4108 : }
4109 6665 : static Word16 index_slice_enum_fx(
4110 : const Word16 *ratio_ism_idx,
4111 : const Word16 nchan_ism )
4112 : {
4113 : Word16 i;
4114 : Word16 x, index;
4115 : Word16 base;
4116 :
4117 6665 : IF( EQ_16( nchan_ism, 2 ) )
4118 : {
4119 308 : index = ratio_ism_idx[0];
4120 308 : move16();
4121 : }
4122 : ELSE
4123 : {
4124 6357 : x = ratio_ism_idx[nchan_ism - 2];
4125 6357 : base = 10;
4126 6357 : move16();
4127 6357 : move16();
4128 17248 : FOR( i = nchan_ism - 3; i >= 0; i-- )
4129 : {
4130 10891 : x = add( x, imult1616( ratio_ism_idx[i], base ) );
4131 10891 : base = imult1616( base, 10 );
4132 : }
4133 :
4134 6357 : index = 0;
4135 6357 : i = 0;
4136 6357 : move16();
4137 6357 : move16();
4138 928936 : WHILE( LE_16( i, x ) )
4139 : {
4140 922579 : IF( valid_ratio_index_fx( i, 7, nchan_ism - 1 ) )
4141 : {
4142 252732 : index = add( index, 1 );
4143 : }
4144 922579 : i = add( i, 1 );
4145 : }
4146 6357 : index = sub( index, 1 );
4147 : }
4148 :
4149 6665 : return index;
4150 : }
4151 :
4152 61502 : static void transform_difference_index_ivas_fx(
4153 : const Word16 *diff_idx,
4154 : Word16 *idx,
4155 : const Word16 len )
4156 : {
4157 : Word16 i;
4158 189070 : FOR( i = 0; i < len; i++ )
4159 : {
4160 127568 : IF( diff_idx[i] <= 0 )
4161 : {
4162 99612 : idx[i] = negate( shl( diff_idx[i], 1 ) );
4163 99612 : move16();
4164 : }
4165 : ELSE
4166 : {
4167 27956 : idx[i] = sub( shl( diff_idx[i], 1 ), 1 );
4168 27956 : move16();
4169 : }
4170 : }
4171 :
4172 61502 : return;
4173 : }
4174 20139 : static void transform_index_and_GR_encode_ivas_fx(
4175 : Word16 *diff_idx, /* i : differenc eindex to encode */
4176 : const Word16 len, /* i : input length */
4177 : const Word16 GR_order, /* i : GR order */
4178 : BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */
4179 : )
4180 : {
4181 : Word16 i;
4182 : Word16 idx[IVAS_MAX_NUM_OBJECTS];
4183 :
4184 : /* transform difference index into positive */
4185 20139 : transform_difference_index_ivas_fx( diff_idx, idx, len );
4186 :
4187 : /* GR encoding */
4188 61030 : FOR( i = 0; i < len; i++ )
4189 : {
4190 40891 : ivas_qmetadata_encode_extended_gr_fx( hMetaData, idx[i], 100, GR_order );
4191 : }
4192 :
4193 20139 : return;
4194 : }
4195 1862 : static Word16 try_differential_fx(
4196 : const Word16 numCodingBands,
4197 : const Word32 *masa_to_total_energy_ratio, /* Q30 */
4198 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4199 : const Word16 nchan_ism,
4200 : const Word16 bits_index,
4201 : Word16 *p_b_signif )
4202 : {
4203 : Word16 b, i;
4204 : Word16 nbits0;
4205 : Word16 b_signif;
4206 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4207 : Word16 diff_idx[MAX_NUM_OBJECTS];
4208 :
4209 1862 : b_signif = 0;
4210 1862 : move16();
4211 2162 : WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
4212 : {
4213 300 : test();
4214 300 : b_signif = add( b_signif, 1 );
4215 : }
4216 :
4217 1862 : nbits0 = 0;
4218 1862 : move16();
4219 :
4220 1862 : IF( LT_16( b_signif, numCodingBands ) )
4221 : {
4222 1806 : nbits0 = bits_index;
4223 1806 : move16();
4224 1806 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4225 :
4226 11560 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4227 : {
4228 9754 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4229 : {
4230 8627 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4231 8627 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4232 :
4233 : /* transform difference index into positive */
4234 8627 : transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( nchan_ism, 1 ) );
4235 :
4236 : /* GR encoding */
4237 30122 : FOR( i = 0; i < nchan_ism - 1; i++ )
4238 : {
4239 21495 : nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
4240 : }
4241 : }
4242 : }
4243 : }
4244 1862 : *p_b_signif = b_signif;
4245 1862 : move16();
4246 :
4247 1862 : return nbits0;
4248 : }
4249 :
4250 666 : static void differential_coding_first_subframe_ivas_fx(
4251 : BSTR_ENC_HANDLE hMetaData,
4252 : const Word32 *masa_to_total_energy_ratio, // Q30
4253 : const Word16 b_signif,
4254 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4255 : const Word16 nchan_ism,
4256 : const Word16 numCodingBands,
4257 : const Word16 bits_index )
4258 : {
4259 : Word16 index, b;
4260 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4261 : Word16 diff_idx[MAX_NUM_OBJECTS];
4262 :
4263 : /* differential encoding*/
4264 666 : push_next_indice( hMetaData, 0, 1 );
4265 :
4266 666 : IF( LT_16( b_signif, numCodingBands ) )
4267 : {
4268 666 : index = index_slice_enum_fx( ratio_ism_idx[b_signif], nchan_ism );
4269 666 : push_next_indice( hMetaData, index, bits_index );
4270 :
4271 666 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4272 :
4273 4892 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4274 : {
4275 4226 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4276 : {
4277 3768 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4278 3768 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4279 :
4280 : /* transform difference index into positive */
4281 3768 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( nchan_ism, 1 ), 0, hMetaData );
4282 : }
4283 : }
4284 : }
4285 :
4286 666 : return;
4287 : }
4288 1140 : static void independent_coding_ratio_ism_idx_fx(
4289 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], /* i : ISM ratios */
4290 : const Word32 *masa_to_total_energy_ratio, /* i : MASA to total ratios, Q30 */
4291 : const Word16 nchan_ism, /* i : number of objects */
4292 : const Word16 numCodingBands, /* i : number of subbands */
4293 : const Word16 bits_index, /* i : number of bits per index */
4294 : BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */
4295 : )
4296 : {
4297 : Word16 b, index;
4298 :
4299 7844 : FOR( b = 0; b < numCodingBands; b++ )
4300 : {
4301 6704 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4302 : {
4303 5999 : index = index_slice_enum_fx( ratio_ism_idx[b], nchan_ism );
4304 5999 : push_next_indice( hMetaData, index, bits_index );
4305 : }
4306 : }
4307 :
4308 1140 : return;
4309 : }
4310 :
4311 29124 : static void remove_sep_obj_fx(
4312 : Word16 *diff_idx, /* i/o: array of difference of indexes */
4313 : const Word16 nchan_ism, /* i : number of objects */
4314 : const Word16 idx_sep_obj /* i : index of separated object, to be taken out of array */
4315 : )
4316 : {
4317 : Word16 i;
4318 :
4319 88197 : FOR( i = idx_sep_obj; i < nchan_ism - 1; i++ )
4320 : {
4321 59073 : diff_idx[i] = diff_idx[i + 1];
4322 59073 : move16();
4323 : }
4324 :
4325 29124 : return;
4326 : }
4327 :
4328 32736 : static void estimate_bits_subband_ism_ratio_fx(
4329 : const Word16 *ratio_ism_idx,
4330 : const Word16 *ratio_ism_idx_ref, /* ( i/o ) */
4331 : const Word16 nchan_ism,
4332 : const Word16 shift_one,
4333 : const Word16 idx_sep_obj,
4334 : Word16 *p_nbits0,
4335 : Word16 *p_nbits1 )
4336 : {
4337 : Word16 diff_idx[MAX_NUM_OBJECTS];
4338 : Word16 nbits0, nbits1;
4339 : Word16 i;
4340 :
4341 32736 : nbits0 = 0;
4342 32736 : nbits1 = 0;
4343 32736 : move16();
4344 32736 : move16();
4345 :
4346 : /* take difference with respect to previous subframe */
4347 32736 : v_sub_s16_fx( ratio_ism_idx, ratio_ism_idx_ref, diff_idx, nchan_ism );
4348 :
4349 32736 : IF( shift_one )
4350 : {
4351 19416 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj );
4352 : }
4353 :
4354 : /* transform difference index into positive */
4355 32736 : transform_difference_index_ivas_fx( diff_idx, diff_idx, sub( sub( nchan_ism, 1 ), shift_one ) );
4356 :
4357 : /* GR encoding */
4358 97918 : FOR( i = 0; i < nchan_ism - 1 - shift_one; i++ )
4359 : {
4360 65182 : nbits0 = add( nbits0, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 0 ) );
4361 65182 : nbits1 = add( nbits1, ivas_qmetadata_encode_extended_gr_length_fx( diff_idx[i], 100, 1 ) );
4362 : }
4363 :
4364 32736 : *p_nbits0 = nbits0;
4365 32736 : *p_nbits1 = nbits1;
4366 32736 : move16();
4367 32736 : move16();
4368 :
4369 32736 : return;
4370 : }
4371 :
4372 5636 : static Word16 encode_ratio_ism_subframe_fx(
4373 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4374 : const Word16 nchan_ism,
4375 : const UWord8 numCodingBands,
4376 : const Word16 sf,
4377 : Word16 ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS],
4378 : BSTR_ENC_HANDLE hMetaData,
4379 : const Word32 *masa_to_total_energy_ratio, /* Q30 */
4380 : const Word16 shift_one,
4381 : const Word16 idx_separated_obj )
4382 : {
4383 : Word16 b, b_signif;
4384 : Word16 diff_idx[MAX_NUM_OBJECTS];
4385 : Word16 nbits, nbits0, nbits1, GR_order, GR_order_sb;
4386 : Word16 differential_subframe;
4387 : Word16 ratio_ism_idx_ref[MAX_NUM_OBJECTS];
4388 : Word16 bits_index;
4389 : Word16 nbits00, nbits11;
4390 : Word16 idx_sep_obj_local;
4391 :
4392 5636 : idx_sep_obj_local = idx_separated_obj;
4393 5636 : move16();
4394 5636 : IF( GT_16( idx_separated_obj, -1 ) )
4395 : {
4396 5636 : if ( EQ_16( idx_separated_obj, sub( nchan_ism, 1 ) ) )
4397 : {
4398 803 : idx_sep_obj_local = 0;
4399 803 : move16();
4400 : }
4401 : }
4402 5636 : nbits = 0;
4403 5636 : nbits0 = 0;
4404 5636 : nbits1 = 0;
4405 5636 : move16();
4406 5636 : move16();
4407 5636 : move16();
4408 :
4409 5636 : differential_subframe = 1; /* the differences are taken with respect to previous subframe */
4410 5636 : move16();
4411 :
4412 : /* first subframe */
4413 5636 : bits_index = 0;
4414 5636 : move16();
4415 5636 : IF( sf == 0 )
4416 : {
4417 1862 : bits_index = bits_index_ism_ratio_fx( nchan_ism );
4418 :
4419 1862 : nbits = 0;
4420 1862 : move16();
4421 13722 : FOR( b = 0; b < numCodingBands; b++ )
4422 : {
4423 11860 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4424 : {
4425 10433 : nbits = add( nbits, bits_index );
4426 : }
4427 : }
4428 :
4429 1862 : nbits0 = try_differential_fx( numCodingBands, masa_to_total_energy_ratio, ratio_ism_idx, nchan_ism, bits_index, &b_signif );
4430 :
4431 1862 : test();
4432 1862 : IF( LE_16( nbits, nbits0 ) && nbits > 0 )
4433 : {
4434 : /* independent encoding */
4435 1140 : push_next_indice( hMetaData, 1, 1 );
4436 1140 : independent_coding_ratio_ism_idx_fx( ratio_ism_idx, masa_to_total_energy_ratio, nchan_ism, numCodingBands, bits_index, hMetaData );
4437 1140 : nbits = add( nbits, 1 );
4438 : }
4439 : ELSE
4440 : {
4441 722 : IF( nbits > 0 )
4442 : {
4443 666 : differential_coding_first_subframe_ivas_fx( hMetaData, masa_to_total_energy_ratio, b_signif, ratio_ism_idx, nchan_ism, numCodingBands, bits_index );
4444 :
4445 666 : nbits = add( nbits0, 1 );
4446 : }
4447 : }
4448 : }
4449 : ELSE
4450 : {
4451 : /* not first subframe */
4452 3774 : test();
4453 3774 : IF( EQ_16( shift_one, 1 ) && EQ_16( nchan_ism, 2 ) )
4454 : {
4455 45 : nbits = 0;
4456 45 : move16();
4457 : }
4458 : ELSE
4459 : {
4460 3729 : nbits0 = 0;
4461 3729 : nbits1 = 0;
4462 3729 : move16();
4463 3729 : move16();
4464 :
4465 22266 : FOR( b = 0; b < numCodingBands; b++ )
4466 : {
4467 18537 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4468 : {
4469 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 );
4470 16371 : nbits0 = add( nbits0, nbits00 );
4471 16371 : nbits1 = add( nbits1, nbits11 );
4472 : }
4473 : }
4474 3729 : IF( LT_16( nbits0, nbits1 ) )
4475 : {
4476 2691 : GR_order = 0;
4477 2691 : nbits = nbits0;
4478 2691 : move16();
4479 2691 : move16();
4480 : }
4481 : ELSE
4482 : {
4483 1038 : GR_order = 1;
4484 1038 : nbits = nbits1;
4485 1038 : move16();
4486 1038 : move16();
4487 : }
4488 :
4489 3729 : IF( GT_16( numCodingBands, 1 ) )
4490 : {
4491 : /* try the difference from subband to subband; first subband is compared to previous subframe first subband*/
4492 : /* take difference with respect to previous subframe only for first subband */
4493 3702 : nbits0 = 0;
4494 3702 : nbits1 = 0;
4495 3702 : b_signif = 0;
4496 3702 : move16();
4497 3702 : move16();
4498 3702 : move16();
4499 3963 : WHILE( ( b_signif < numCodingBands ) && ( masa_to_total_energy_ratio[b_signif] >= MASA2TOTAL_THR_Q30 ) )
4500 : {
4501 261 : test();
4502 261 : b_signif = add( b_signif, 1 );
4503 : }
4504 :
4505 3702 : IF( LT_16( b_signif, numCodingBands ) )
4506 : {
4507 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 );
4508 :
4509 3690 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, nchan_ism );
4510 :
4511 18249 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4512 : {
4513 14559 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4514 : {
4515 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 );
4516 12675 : nbits0 = add( nbits0, nbits00 );
4517 12675 : nbits1 = add( nbits1, nbits11 );
4518 12675 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, nchan_ism );
4519 : }
4520 : }
4521 :
4522 3690 : IF( LT_16( nbits0, nbits1 ) )
4523 : {
4524 529 : GR_order_sb = 0;
4525 529 : move16();
4526 : }
4527 : ELSE
4528 : {
4529 3161 : GR_order_sb = 1;
4530 3161 : nbits0 = nbits1;
4531 3161 : move16();
4532 3161 : move16();
4533 : }
4534 :
4535 3690 : IF( LT_16( nbits0, nbits ) )
4536 : {
4537 343 : differential_subframe = 0;
4538 343 : nbits = nbits0;
4539 343 : GR_order = GR_order_sb;
4540 343 : move16();
4541 343 : move16();
4542 343 : move16();
4543 : }
4544 :
4545 3690 : IF( nbits > 0 )
4546 : {
4547 : /* write prediction type */
4548 3690 : push_next_indice( hMetaData, differential_subframe, 1 );
4549 : /* write GR order */
4550 3690 : push_next_indice( hMetaData, GR_order, 1 );
4551 3690 : nbits = add( nbits, 1 ); /* for the prediction type */
4552 3690 : nbits = add( nbits, 1 ); /* for GR_order */
4553 :
4554 : /* write data */
4555 3690 : IF( differential_subframe )
4556 : {
4557 20082 : FOR( b = 0; b < numCodingBands; b++ )
4558 : {
4559 16735 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4560 : {
4561 : /* take difference with respect to previous subframe */
4562 14850 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_prev_sf[b], diff_idx, nchan_ism );
4563 :
4564 14850 : IF( shift_one )
4565 : {
4566 9289 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4567 : }
4568 :
4569 14850 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4570 : }
4571 : }
4572 : }
4573 : ELSE
4574 : {
4575 343 : v_sub_s16_fx( ratio_ism_idx[b_signif], ratio_ism_idx_prev_sf[b_signif], diff_idx, nchan_ism );
4576 :
4577 343 : IF( shift_one )
4578 : {
4579 87 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4580 : }
4581 :
4582 343 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4583 :
4584 343 : Copy( ratio_ism_idx[b_signif], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
4585 :
4586 1709 : FOR( b = b_signif + 1; b < numCodingBands; b++ )
4587 : {
4588 : /* take difference with respect to previous subband */
4589 1366 : IF( LT_32( masa_to_total_energy_ratio[b], MASA2TOTAL_THR_Q30 ) )
4590 : {
4591 1172 : v_sub_s16_fx( ratio_ism_idx[b], ratio_ism_idx_ref, diff_idx, nchan_ism );
4592 :
4593 1172 : IF( shift_one )
4594 : {
4595 332 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4596 : }
4597 :
4598 1172 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4599 :
4600 1172 : Copy( ratio_ism_idx[b], ratio_ism_idx_ref, sub( nchan_ism, shift_one ) );
4601 : }
4602 : }
4603 : }
4604 : }
4605 : }
4606 : }
4607 : ELSE
4608 : {
4609 : /* only differential wrt previous subframe is possible */
4610 : /* write the differential to subframe case and no bit to signal the difference type */
4611 :
4612 27 : IF( nbits > 0 )
4613 : {
4614 : /* write GR order */
4615 6 : push_next_indice( hMetaData, GR_order, 1 );
4616 6 : nbits = add( nbits, 1 ); /* for GR_order */
4617 : /* write data */
4618 : /* only one subband */
4619 6 : IF( LT_32( masa_to_total_energy_ratio[0], MASA2TOTAL_THR_Q30 ) )
4620 : {
4621 : /* take difference with respect to previous subframe */
4622 6 : v_sub_s16_fx( ratio_ism_idx[0], ratio_ism_idx_prev_sf[0], diff_idx, nchan_ism );
4623 :
4624 6 : IF( shift_one )
4625 : {
4626 0 : remove_sep_obj_fx( diff_idx, nchan_ism, idx_sep_obj_local );
4627 : }
4628 :
4629 6 : transform_index_and_GR_encode_ivas_fx( diff_idx, sub( sub( nchan_ism, 1 ), shift_one ), GR_order, hMetaData );
4630 : }
4631 : }
4632 : }
4633 : }
4634 : }
4635 :
4636 5636 : return nbits;
4637 : }
4638 1862 : static void ivas_encode_masaism_metadata_fx(
4639 : MASA_ENCODER_HANDLE hMasa,
4640 : IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */
4641 : BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */
4642 : ISM_METADATA_HANDLE hIsmMeta[], /* i/o: ISM metadata handles */
4643 : const Word16 nchan_ism, /* i : number of ISM channels */
4644 : const Word16 low_bitrate_mode, /* i : is low bitrate more? 1/0 */
4645 : const Word16 omasa_nbands,
4646 : const Word16 omasa_nblocks,
4647 : const Word16 idx_separated_object,
4648 : const Word16 ism_imp )
4649 : {
4650 : Word16 sf, band;
4651 : UWord8 numCodingBands;
4652 : UWord8 numSf;
4653 : Word16 brange[2];
4654 : Word64 eneBand;
4655 : Word32 eneBand32;
4656 : Word16 eneBand_exp, shift;
4657 : Word16 bin;
4658 : Word16 obj;
4659 : Word16 bits_ism[MAX_NUM_OBJECTS];
4660 : UWord16 idx_sph;
4661 : Word32 theta_q, phi_q;
4662 : UWord16 index_theta, index_phi;
4663 : Word16 ratio_ism_fx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
4664 : Word16 ratio_ism_idx[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS], ratio_ism_idx_prev_sf[MASA_FREQUENCY_BANDS][MAX_NUM_OBJECTS];
4665 : Word16 step;
4666 : Word32 energy_ism, energy_ism_ind[MAX_NUM_OBJECTS];
4667 : Word16 tmp, rotate, energy_ism_e, energy_ism_ind_e[MAX_NUM_OBJECTS];
4668 : Word16 n_ism_tmp, i;
4669 1862 : OMASA_ENCODER_DATA_HANDLE hOmasaData = hMasa->data.hOmasaData;
4670 : Word16 nbands_work;
4671 : Word32 L_tmp;
4672 : Word16 L_tmp_e;
4673 :
4674 : /* use the values from hQMetaData */
4675 1862 : numCodingBands = (UWord8) hQMetaData->q_direction->cfg.nbands;
4676 1862 : numSf = (Word8) hQMetaData->q_direction->cfg.nblocks;
4677 1862 : nbands_work = s_min( numCodingBands, omasa_nbands );
4678 1862 : move16();
4679 1862 : move16();
4680 1862 : IF( EQ_16( numCodingBands, 1 ) )
4681 : {
4682 120 : FOR( sf = 0; sf < numSf; sf++ )
4683 : {
4684 96 : L_tmp = 0;
4685 96 : L_tmp_e = 0;
4686 96 : move32();
4687 96 : move16();
4688 576 : FOR( i = 0; i < omasa_nbands; i++ )
4689 : {
4690 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 );
4691 : }
4692 : /* if ( sum_f( hOmasaData->energy_ism[sf], omasa_nbands ) == 0.0f ) */
4693 96 : IF( L_tmp == 0 )
4694 : {
4695 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
4696 0 : move32();
4697 : }
4698 : ELSE
4699 : {
4700 96 : brange[0] = hMasa->data.band_mapping[0];
4701 96 : brange[1] = hMasa->data.band_mapping[omasa_nbands];
4702 96 : eneBand = 0;
4703 96 : move16();
4704 96 : move16();
4705 96 : move64();
4706 2400 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4707 : {
4708 2304 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4709 : }
4710 96 : shift = W_norm( eneBand );
4711 96 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4712 96 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4713 :
4714 96 : energy_ism = 0;
4715 96 : energy_ism_e = 0;
4716 96 : move32();
4717 96 : move16();
4718 288 : FOR( obj = 0; obj < nchan_ism; obj++ )
4719 : {
4720 192 : energy_ism_ind[obj] = 0;
4721 192 : energy_ism_ind_e[obj] = 0;
4722 192 : move32();
4723 192 : move16();
4724 : }
4725 :
4726 576 : FOR( band = 0; band < omasa_nbands; band++ )
4727 : {
4728 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 );
4729 1440 : FOR( obj = 0; obj < nchan_ism; obj++ )
4730 : {
4731 :
4732 960 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30; // 1.0f in Q30
4733 960 : move32();
4734 : }
4735 : }
4736 :
4737 288 : FOR( obj = 0; obj < nchan_ism; obj++ )
4738 : {
4739 192 : hOmasaData->energy_ratio_ism_fx[sf][0][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
4740 192 : move32();
4741 192 : L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
4742 : /* Scaling to Q30 */
4743 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
4744 192 : move32();
4745 : }
4746 96 : L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
4747 96 : IF( L_tmp != 0 )
4748 : {
4749 96 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4750 96 : move32();
4751 96 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4752 : /* Scaling to Q30 */
4753 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
4754 96 : move32();
4755 : }
4756 : ELSE
4757 : {
4758 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][0] = ONE_IN_Q30;
4759 0 : move32();
4760 : }
4761 : }
4762 : }
4763 : }
4764 1838 : ELSE IF( EQ_16( numSf, 1 ) )
4765 : {
4766 6270 : FOR( band = 0; band < nbands_work; band++ )
4767 : {
4768 5666 : energy_ism = 0; /* ISM energy for current subband */ // energy_ism_e
4769 5666 : energy_ism_e = 0; /* ISM energy for current subband */
4770 5666 : move32();
4771 5666 : move16();
4772 24246 : FOR( obj = 0; obj < nchan_ism; obj++ )
4773 : {
4774 18580 : energy_ism_ind[obj] = 0;
4775 18580 : energy_ism_ind_e[obj] = 0;
4776 18580 : move32();
4777 18580 : move16();
4778 : }
4779 14722 : FOR( sf = 0; sf < omasa_nblocks; sf++ )
4780 : {
4781 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 );
4782 34416 : FOR( obj = 0; obj < nchan_ism; obj++ )
4783 : {
4784 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
4785 25360 : L_tmp_e = add( 1, hOmasaData->energy_ism_fx_e[sf][band] );
4786 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] );
4787 25360 : move32();
4788 : }
4789 : }
4790 :
4791 5666 : IF( energy_ism == 0 )
4792 : {
4793 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30; // 1.0f in Q30
4794 0 : move32();
4795 : }
4796 : ELSE
4797 : {
4798 24246 : FOR( obj = 0; obj < nchan_ism; obj++ )
4799 : {
4800 18580 : hOmasaData->energy_ratio_ism_fx[0][band][obj] = BASOP_Util_Divide3232_Scale_newton( energy_ism_ind[obj], energy_ism, &L_tmp_e );
4801 18580 : move32();
4802 18580 : L_tmp_e = add( L_tmp_e, sub( energy_ism_ind_e[obj], energy_ism_e ) );
4803 : /* Scaling to Q30 */
4804 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
4805 18580 : move32();
4806 : }
4807 5666 : brange[0] = hMasa->data.band_mapping[band];
4808 5666 : brange[1] = hMasa->data.band_mapping[band + 1];
4809 5666 : move16();
4810 5666 : move16();
4811 :
4812 5666 : eneBand = 0;
4813 5666 : move64();
4814 14722 : FOR( sf = 0; sf < omasa_nblocks; sf++ )
4815 : {
4816 39748 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4817 : {
4818 30692 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4819 : }
4820 : }
4821 5666 : shift = W_norm( eneBand );
4822 5666 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4823 5666 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4824 :
4825 5666 : L_tmp = BASOP_Util_Add_Mant32Exp( eneBand32, eneBand_exp, energy_ism, energy_ism_e, &L_tmp_e );
4826 5666 : IF( L_tmp != 0 )
4827 : {
4828 5666 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4829 5666 : move32();
4830 5666 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4831 : /* Scaling to Q30 */
4832 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
4833 5666 : move32();
4834 : }
4835 : ELSE
4836 : {
4837 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
4838 0 : move32();
4839 : }
4840 : }
4841 : }
4842 604 : FOR( band = nbands_work; band < numCodingBands; band++ )
4843 : {
4844 0 : hOmasaData->masa_to_total_energy_ratio_fx[0][band] = ONE_IN_Q30;
4845 0 : move32();
4846 :
4847 0 : FOR( obj = 0; obj < nchan_ism; obj++ )
4848 : {
4849 0 : hOmasaData->energy_ratio_ism_fx[0][band][obj] = hOmasaData->energy_ratio_ism_fx[0][nbands_work - 1][obj];
4850 0 : move32();
4851 : }
4852 : }
4853 : }
4854 : ELSE
4855 : {
4856 6170 : FOR( sf = 0; sf < numSf; sf++ )
4857 : {
4858 29616 : FOR( band = 0; band < nbands_work; band++ )
4859 : {
4860 24680 : IF( hOmasaData->energy_ism_fx[sf][band] == 0 )
4861 : {
4862 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
4863 0 : move32();
4864 : }
4865 : ELSE
4866 : {
4867 24680 : brange[0] = hMasa->data.band_mapping[band];
4868 24680 : brange[1] = hMasa->data.band_mapping[band + 1];
4869 24680 : move16();
4870 24680 : move16();
4871 :
4872 24680 : eneBand = 0;
4873 24680 : move64();
4874 141656 : FOR( bin = brange[0]; bin < brange[1]; bin++ )
4875 : {
4876 116976 : eneBand = W_mac_32_32( eneBand, hMasa->data.energy_fx[sf][bin], 1 ); // hMasa->data.q_energy + 1
4877 : }
4878 24680 : shift = W_norm( eneBand );
4879 24680 : eneBand32 = W_extract_h( W_shl( eneBand, shift ) );
4880 24680 : eneBand_exp = sub( 63, add( add( hMasa->data.q_energy, 1 ), shift ) );
4881 :
4882 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 );
4883 24680 : IF( L_tmp != 0 )
4884 : {
4885 24680 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = BASOP_Util_Divide3232_Scale_newton( eneBand32, L_tmp, &tmp );
4886 24680 : move32();
4887 24680 : tmp = add( tmp, sub( eneBand_exp, L_tmp_e ) );
4888 : /* Scaling to Q30 */
4889 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
4890 24680 : move32();
4891 : }
4892 : ELSE
4893 : {
4894 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
4895 0 : move32();
4896 : }
4897 : }
4898 : }
4899 4936 : FOR( band = nbands_work; band < numCodingBands; band++ )
4900 : {
4901 0 : hOmasaData->masa_to_total_energy_ratio_fx[sf][band] = ONE_IN_Q30;
4902 0 : move32();
4903 :
4904 0 : FOR( obj = 0; obj < nchan_ism; obj++ )
4905 : {
4906 0 : hOmasaData->energy_ratio_ism_fx[sf][band][obj] = hOmasaData->energy_ratio_ism_fx[sf][nbands_work - 1][obj];
4907 0 : move32();
4908 : }
4909 : }
4910 : }
4911 : }
4912 :
4913 1862 : ivas_omasa_encode_masa_to_total_fx( hOmasaData->masa_to_total_energy_ratio_fx, hMetaData, low_bitrate_mode, numCodingBands, numSf );
4914 :
4915 : /* quantize ism_ratios */
4916 1862 : IF( GT_16( nchan_ism, 1 ) )
4917 : {
4918 : /* inv_step = ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ); *
4919 : * step = 1.0f / inv_step; */
4920 1862 : step = 4681; // 1.f / ( ( 1 << PARAM_ISM_POW_RATIO_NBITS ) - 1 ) => 1.f / 7 in Q15
4921 1862 : move16();
4922 :
4923 1862 : rotate = 0;
4924 1862 : n_ism_tmp = 0;
4925 1862 : move16();
4926 1862 : move16();
4927 :
4928 7498 : FOR( sf = 0; sf < numSf; sf++ )
4929 : {
4930 36078 : FOR( band = 0; band < numCodingBands; band++ )
4931 : {
4932 137614 : FOR( obj = 0; obj < nchan_ism; obj++ )
4933 : {
4934 107172 : assert( ( hOmasaData->energy_ratio_ism_fx[sf][band][obj] >= 0 ) && ( hOmasaData->energy_ratio_ism_fx[sf][band][obj] <= ONE_IN_Q30 ) );
4935 107172 : ratio_ism_fx[band][obj] = extract_h( hOmasaData->energy_ratio_ism_fx[sf][band][obj] ); // Q14
4936 107172 : move16();
4937 : }
4938 :
4939 : /* Quantize ISM ratios */
4940 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 );
4941 :
4942 30442 : test();
4943 30442 : test();
4944 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 ) )
4945 : {
4946 92 : i = 0;
4947 92 : move16();
4948 697 : WHILE( ratio_ism_idx[band][idx_separated_object] > 0 )
4949 : {
4950 605 : IF( NE_16( i, idx_separated_object ) )
4951 : {
4952 410 : ratio_ism_idx[band][i] = add( ratio_ism_idx[band][i], 1 );
4953 410 : ratio_ism_idx[band][idx_separated_object] = sub( ratio_ism_idx[band][idx_separated_object], 1 );
4954 410 : move16();
4955 410 : move16();
4956 : }
4957 605 : i = add( i, 1 );
4958 605 : if ( EQ_16( i, nchan_ism ) )
4959 : {
4960 138 : i = 0;
4961 138 : move16();
4962 : }
4963 : }
4964 : }
4965 :
4966 : /* reconstructed values */
4967 30442 : reconstruct_ism_ratios_fx( ratio_ism_idx[band], nchan_ism, step, hMasa->data.hOmasaData->q_energy_ratio_ism_fx[sf][band] );
4968 : }
4969 5636 : test();
4970 5636 : IF( GT_16( nchan_ism, 2 ) && EQ_16( idx_separated_object, sub( nchan_ism, 1 ) ) )
4971 : {
4972 : /* rotate components */
4973 766 : rotate = 1;
4974 766 : move16();
4975 4610 : FOR( band = 0; band < numCodingBands; band++ )
4976 : {
4977 3844 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
4978 : {
4979 3352 : tmp = ratio_ism_idx[band][nchan_ism - 1];
4980 3352 : ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
4981 3352 : ratio_ism_idx[band][0] = tmp;
4982 3352 : move16();
4983 3352 : move16();
4984 3352 : move16();
4985 3352 : test();
4986 3352 : IF( sf == 0 && tmp == 0 )
4987 : {
4988 799 : n_ism_tmp = add( n_ism_tmp, 1 );
4989 : }
4990 :
4991 3352 : if ( EQ_16( n_ism_tmp, numCodingBands ) )
4992 : {
4993 1753 : assert( tmp == 0 );
4994 : }
4995 : }
4996 : }
4997 : }
4998 : ELSE
4999 : {
5000 4870 : IF( GT_16( idx_separated_object, -1 ) )
5001 : {
5002 31468 : FOR( band = 0; band < numCodingBands; band++ )
5003 : {
5004 26598 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5005 : {
5006 23497 : test();
5007 23497 : IF( ratio_ism_idx[band][idx_separated_object] == 0 && sf == 0 )
5008 : {
5009 8636 : n_ism_tmp = add( n_ism_tmp, 1 );
5010 : }
5011 : }
5012 : }
5013 : }
5014 : }
5015 :
5016 : /* encode data for current subframe */
5017 5636 : test();
5018 5636 : IF( sf > 0 && EQ_16( n_ism_tmp, numCodingBands ) )
5019 : {
5020 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 );
5021 : }
5022 : ELSE
5023 : {
5024 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 );
5025 : }
5026 :
5027 : /* calculate quantized ISM ratios */
5028 : /* save previous subframe indexes */
5029 36078 : FOR( band = 0; band < numCodingBands; band++ )
5030 : {
5031 30442 : Copy( ratio_ism_idx[band], ratio_ism_idx_prev_sf[band], nchan_ism );
5032 : }
5033 :
5034 5636 : IF( rotate )
5035 : {
5036 4610 : FOR( band = 0; band < numCodingBands; band++ )
5037 : {
5038 3844 : IF( LT_32( hOmasaData->masa_to_total_energy_ratio_fx[sf][band], MASA2TOTAL_THR_Q30 ) )
5039 : {
5040 3352 : tmp = ratio_ism_idx[band][nchan_ism - 1];
5041 3352 : ratio_ism_idx[band][nchan_ism - 1] = ratio_ism_idx[band][0];
5042 3352 : ratio_ism_idx[band][0] = tmp;
5043 3352 : move16();
5044 3352 : move16();
5045 3352 : move16();
5046 : }
5047 : }
5048 : }
5049 : }
5050 : }
5051 :
5052 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 );
5053 :
5054 : /* quantize directions */
5055 8142 : FOR( obj = 0; obj < nchan_ism; obj++ )
5056 : {
5057 6280 : IF( LT_16( bits_ism[obj], 8 ) )
5058 : {
5059 : /* check is same as previous */
5060 2009 : test();
5061 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 */ ) )
5062 : {
5063 201 : push_next_indice( hMetaData, 1, 1 );
5064 : /* the old stays the same */
5065 : }
5066 : ELSE
5067 : {
5068 1808 : push_next_indice( hMetaData, 0, 1 );
5069 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 );
5070 1808 : push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
5071 1808 : hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
5072 1808 : hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
5073 1808 : move32();
5074 1808 : move32();
5075 : }
5076 : }
5077 : ELSE
5078 : {
5079 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 );
5080 4271 : push_next_indice( hMetaData, idx_sph, bits_ism[obj] );
5081 4271 : hIsmMeta[obj]->q_elevation_old_fx = hIsmMeta[obj]->elevation_fx;
5082 4271 : hIsmMeta[obj]->q_azimuth_old_fx = hIsmMeta[obj]->azimuth_fx;
5083 4271 : move32();
5084 4271 : move32();
5085 : }
5086 : }
5087 :
5088 1862 : return;
5089 : }
5090 :
5091 : /*-------------------------------------------------------------------*
5092 : * ivas_merge_masa_transports()
5093 : *
5094 : * Merge MASA transport channels
5095 : *-------------------------------------------------------------------*/
5096 5858 : void ivas_merge_masa_transports_fx(
5097 : Word32 data_in_f1_fx[][L_FRAME48k], // Qx
5098 : Word32 *data_in_f2_fx[], // Qx
5099 : Word32 *data_out_f_fx[], // Qx
5100 : const Word16 input_frame,
5101 : const Word16 num_transport_channels )
5102 : {
5103 : Word16 i, j;
5104 :
5105 17574 : FOR( i = 0; i < num_transport_channels; i++ )
5106 : {
5107 10588356 : FOR( j = 0; j < input_frame; j++ )
5108 : {
5109 10576640 : data_out_f_fx[i][j] = L_add( data_in_f1_fx[i][j], data_in_f2_fx[i][j] );
5110 10576640 : move32();
5111 : }
5112 : }
5113 :
5114 5858 : return;
5115 : }
|