diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index d51bfb8cdc0b9ace29eb9683aa8ce5674448bae7..f8738483b9d8f92a52ed4ceea68aeb2a0d413015 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1623,6 +1623,7 @@ ivas_error ivas_init_decoder( } ELSE { + /*TODO/observation : not hit by decoder tests*/ vbap_determine_gains( st_ivas->hVBAPdata, st_ivas->hLsSetupCustom->separate_ch_gains, 0, 0, 0 ); } } diff --git a/lib_dec/ivas_ism_renderer.c b/lib_dec/ivas_ism_renderer.c index 4032564edadf8e9831c527f30041336da240d236..0634c6edf77f1f1622b5d7a9425fe38bc7a53ca8 100644 --- a/lib_dec/ivas_ism_renderer.c +++ b/lib_dec/ivas_ism_renderer.c @@ -836,6 +836,10 @@ void ivas_omasa_separate_object_render_jbm( int16_t j, k, j2; int16_t obj; float gains[MAX_OUTPUT_CHANNELS]; +#ifdef IVAS_FLOAT_FIXED + Word32 gains_fx[MAX_OUTPUT_CHANNELS]; + set32_fx(gains_fx, 0, MAX_OUTPUT_CHANNELS); +#endif float g1, g2; int16_t lfe_index; int16_t azimuth, elevation; @@ -943,7 +947,14 @@ void ivas_omasa_separate_object_render_jbm( if ( hVBAPdata != NULL ) { +#ifdef IVAS_FLOAT_FIXED + vbap_determine_gains_fx(hVBAPdata, gains_fx, azimuth, elevation, 1); + FOR (int i = 0; i < MAX_OUTPUT_CHANNELS; i++) { + gains[i] = fix_to_float(gains_fx[i], Q29); + } +#else vbap_determine_gains( hVBAPdata, gains, azimuth, elevation, 1 ); +#endif /*Word32 gains_fx[16]; vbap_determine_gains_fx( hVBAPdata, gains_fx, azimuth, elevation, 1 ); for (j = 0; j < nchan_out_woLFE; j++) gains[j] = (float)gains_fx[j] / (float)(1 << 29);*/ diff --git a/lib_rend/ivas_dirac_output_synthesis_dec.c b/lib_rend/ivas_dirac_output_synthesis_dec.c index b46b6661608a75fd2a25ec313155996285ebf6fa..0e40c56f37a7cf7d12aa1c2fb35b913809633d54 100644 --- a/lib_rend/ivas_dirac_output_synthesis_dec.c +++ b/lib_rend/ivas_dirac_output_synthesis_dec.c @@ -2711,6 +2711,10 @@ void ivas_dirac_dec_compute_directional_responses( { int16_t dir; float direct_response_temp[MAX_OUTPUT_CHANNELS]; +#ifdef IVAS_FLOAT_FIXED + Word32 direct_response_temp_fx[MAX_OUTPUT_CHANNELS]; + set32_fx(direct_response_temp_fx, 0, MAX_OUTPUT_CHANNELS); +#endif float direct_response_ism[MAX_OUTPUT_CHANNELS]; float masaDirect; float ismDirect; @@ -2721,11 +2725,27 @@ void ivas_dirac_dec_compute_directional_responses( { if ( hMasaIsm->ism_is_edited[dir] ) { +#ifdef IVAS_FLOAT_FIXED + vbap_determine_gains_fx( hVBAPdata, direct_response_temp_fx, hMasaIsm->azimuth_ism_edited[dir], hMasaIsm->elevation_ism_edited[dir], 1 ); + FOR( int i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + direct_response_temp[i] = fix_to_float( direct_response_temp_fx[i], Q29 ); + } +#else vbap_determine_gains( hVBAPdata, direct_response_temp, hMasaIsm->azimuth_ism_edited[dir], hMasaIsm->elevation_ism_edited[dir], 1 ); +#endif } else { +#ifdef IVAS_FLOAT_FIXED + vbap_determine_gains_fx( hVBAPdata, direct_response_temp_fx, hMasaIsm->azimuth_ism[dir][md_idx], hMasaIsm->elevation_ism[dir][md_idx], 1 ); + FOR( int i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + direct_response_temp[i] = fix_to_float( direct_response_temp_fx[i], Q29 ); + } +#else vbap_determine_gains( hVBAPdata, direct_response_temp, hMasaIsm->azimuth_ism[dir][md_idx], hMasaIsm->elevation_ism[dir][md_idx], 1 ); +#endif } for ( l = 0; l < num_channels_dir; l++ ) @@ -3289,6 +3309,12 @@ static void spreadCoherencePanningVbap( int16_t i; float direct_response_left[MAX_OUTPUT_CHANNELS]; float direct_response_right[MAX_OUTPUT_CHANNELS]; +#ifdef IVAS_FLOAT_FIXED + Word32 direct_response_left_fx[MAX_OUTPUT_CHANNELS]; + Word32 direct_response_right_fx[MAX_OUTPUT_CHANNELS]; + set32_fx(direct_response_left_fx, 0, MAX_OUTPUT_CHANNELS); + set32_fx(direct_response_right_fx, 0, MAX_OUTPUT_CHANNELS); +#endif float gainCenter; float gainSide; @@ -3299,13 +3325,35 @@ static void spreadCoherencePanningVbap( return; } - +#ifdef IVAS_FLOAT_FIXED + Word32 direct_response_fx[MAX_OUTPUT_CHANNELS]; + set32_fx( direct_response_fx, 0, MAX_OUTPUT_CHANNELS ); + vbap_determine_gains_fx( hVBAPdata, direct_response_fx, azimuth, elevation, 0 ); + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + direct_response[i] = fix_to_float( direct_response_fx[i], Q29 ); + } +#else vbap_determine_gains( hVBAPdata, direct_response, azimuth, elevation, 0 ); +#endif if ( spreadCoh > 0.f ) { +#ifdef IVAS_FLOAT_FIXED + vbap_determine_gains_fx(hVBAPdata, direct_response_left_fx, azimuth + 30, elevation, 0); + FOR(i = 0; i < MAX_OUTPUT_CHANNELS; i++) + { + direct_response_left[i] = fix_to_float(direct_response_left_fx[i], Q29); + } + vbap_determine_gains_fx(hVBAPdata, direct_response_right_fx, azimuth - 30, elevation, 0); + FOR(i = 0; i < MAX_OUTPUT_CHANNELS; i++) + { + direct_response_right[i] = fix_to_float(direct_response_right_fx[i], Q29); + } +#else vbap_determine_gains( hVBAPdata, direct_response_left, azimuth + 30, elevation, 0 ); vbap_determine_gains( hVBAPdata, direct_response_right, azimuth - 30, elevation, 0 ); +#endif if ( spreadCoh < 0.5f ) { diff --git a/lib_rend/ivas_vbap.c b/lib_rend/ivas_vbap.c index 73a6299160fc2ee89f24f24bd04fc4950399fde7..fc8be403af3586bec778abef48cb91eea7148e09 100644 --- a/lib_rend/ivas_vbap.c +++ b/lib_rend/ivas_vbap.c @@ -229,7 +229,7 @@ ivas_error vbap_init_data_fx( /* If the requested layout is invalid, hVBAPdata is set to NULL and the signal will * be distributed with an equal gain into all output channels. * The surrounding code needs to handle the NULL pointer properly. */ - IF( num_speaker_nodes > VBAP_MAX_NUM_SPEAKER_NODES || num_speaker_nodes < 3 ) + IF( GT_16(num_speaker_nodes , VBAP_MAX_NUM_SPEAKER_NODES) || LT_16(num_speaker_nodes , 3) ) { hVBAPdata = NULL; pop_wmops(); @@ -250,10 +250,15 @@ ivas_error vbap_init_data_fx( is_success = 1; vbap->bottom_virtual_speaker_node_index = -1; + move16(); vbap->top_virtual_speaker_node_index = -1; + move16(); vbap->back_virtual_speaker_node_index = -1; + move16(); vbap->num_speaker_nodes = num_speaker_nodes; + move16(); vbap->num_speaker_nodes_internal = num_speaker_nodes; + move16(); vbap->bottom_virtual_speaker_node_division_gains_fx = NULL; vbap->top_virtual_speaker_node_division_gains_fx = NULL; vbap->back_virtual_speaker_node_division_gains_fx = NULL; @@ -279,8 +284,8 @@ ivas_error vbap_init_data_fx( potentially appended with virtual top and/or bottom loudspeakers */ Copy32( speaker_node_azi_deg_fx, speaker_node_azi_deg_internal_fx, num_speaker_nodes ); Copy32( speaker_node_ele_deg_fx, speaker_node_ele_deg_internal_fx, num_speaker_nodes ); - - IF( is_success && virtual_bottom_type != NO_VIRTUAL_SPEAKER_NODE ) + test(); + IF( is_success && NE_16(virtual_bottom_type , NO_VIRTUAL_SPEAKER_NODE) ) { IF( ( vbap->bottom_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -289,7 +294,7 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->bottom_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->bottom_virtual_speaker_node_division_gains_fx != NULL; - IF( ivas_format == MASA_ISM_FORMAT ) + IF( EQ_16(ivas_format , MASA_ISM_FORMAT )) { IF( ( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -320,8 +325,8 @@ ivas_error vbap_init_data_fx( } #endif } - - IF( is_success && virtual_top_type != NO_VIRTUAL_SPEAKER_NODE ) + test(); + IF( is_success && NE_16(virtual_top_type , NO_VIRTUAL_SPEAKER_NODE) ) { IF( ( vbap->top_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -337,7 +342,7 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->top_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->top_virtual_speaker_node_division_gains_fx != NULL; - IF( ivas_format == MASA_ISM_FORMAT ) + IF( EQ_16(ivas_format , MASA_ISM_FORMAT) ) { IF( ( vbap->object_mode_top_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -350,16 +355,16 @@ ivas_error vbap_init_data_fx( speaker_node_ele_deg_internal_fx[vbap->top_virtual_speaker_node_index] = float_to_fix( 90.0f, 22 ); #ifdef TRUE /*Clean up float code*/ - IF( ( vbap->top_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) + if( ( vbap->top_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->top_virtual_speaker_node_division_gains, num_speaker_nodes ); is_success &= vbap->top_virtual_speaker_node_division_gains != NULL; - IF( ivas_format == MASA_ISM_FORMAT ) + if( ivas_format == MASA_ISM_FORMAT ) { - IF( ( vbap->object_mode_top_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) + if( ( vbap->object_mode_top_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } @@ -368,8 +373,8 @@ ivas_error vbap_init_data_fx( } } #endif - - IF( is_success && virtual_back_type != NO_VIRTUAL_SPEAKER_NODE ) + test(); + IF( is_success && NE_16(virtual_back_type , NO_VIRTUAL_SPEAKER_NODE) ) { IF( ( vbap->back_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -378,7 +383,7 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->back_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->back_virtual_speaker_node_division_gains_fx != NULL; - IF( ivas_format == MASA_ISM_FORMAT ) + IF( EQ_16(ivas_format , MASA_ISM_FORMAT) ) { IF( ( vbap->object_mode_back_virtual_speaker_node_division_gains_fx = (Word16 *) malloc( num_speaker_nodes * sizeof( Word16 ) ) ) == NULL ) { @@ -391,16 +396,16 @@ ivas_error vbap_init_data_fx( speaker_node_ele_deg_internal_fx[vbap->back_virtual_speaker_node_index] = float_to_fix( 0.0f, Q22 ); #ifdef TRUE /*Clean up float code*/ - IF( ( vbap->back_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) + if( ( vbap->back_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } set_zero( vbap->back_virtual_speaker_node_division_gains, num_speaker_nodes ); is_success &= vbap->back_virtual_speaker_node_division_gains != NULL; - IF( ivas_format == MASA_ISM_FORMAT ) + if( ivas_format == MASA_ISM_FORMAT ) { - IF( ( vbap->object_mode_back_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) + if( ( vbap->object_mode_back_virtual_speaker_node_division_gains = (float *) malloc( num_speaker_nodes * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } @@ -423,7 +428,7 @@ ivas_error vbap_init_data_fx( #endif /* Allocate and determine node-node connections */ - max_num_connections = ( vbap->num_speaker_nodes_internal - 2 ) * 3; /* Theoretical maximum */ + max_num_connections = mult0(( sub(vbap->num_speaker_nodes_internal , 2) ) , 3); /* Theoretical maximum */ IF( ( error = determine_connections_fx( vbap->num_speaker_nodes_internal, speaker_node_data, connections, max_num_connections, &connection_group1_count, &connection_group2_start, &connection_group2_count ) ) != IVAS_ERR_OK ) { return error; @@ -433,8 +438,11 @@ ivas_error vbap_init_data_fx( { Word16 ch; Word16 speaker_nodes_group1_internal = 0; + move16(); Word16 speaker_nodes_group2_internal = 0; + move16(); Word16 speaker_nodes_horiz_internal = 0; + move16(); uint8_t loop_done = 0; /* Count nodes in different groups to reserve correct memory */ @@ -446,19 +454,21 @@ ivas_error vbap_init_data_fx( /* If there is even one speaker belonging to "all" group, then all speakers belong to the "all" group. * We can skip further counts here. */ speaker_nodes_group1_internal = vbap->num_speaker_nodes_internal; + move16(); loop_done = 1; + move16(); BREAK; case SPEAKER_NODE_BOTTOM_HALF: - speaker_nodes_group1_internal++; + speaker_nodes_group1_internal = add(speaker_nodes_group1_internal, 1); BREAK; case SPEAKER_NODE_TOP_HALF: - speaker_nodes_group2_internal++; + speaker_nodes_group2_internal = add(speaker_nodes_group2_internal, 1); BREAK; case SPEAKER_NODE_HORIZONTAL: case SPEAKER_NODE_BACK: - speaker_nodes_group1_internal++; - speaker_nodes_group2_internal++; - speaker_nodes_horiz_internal++; + speaker_nodes_group1_internal = add(speaker_nodes_group1_internal, 1); + speaker_nodes_group2_internal = add(speaker_nodes_group2_internal, 1); + speaker_nodes_horiz_internal = add(speaker_nodes_horiz_internal, 1); BREAK; } } @@ -469,9 +479,10 @@ ivas_error vbap_init_data_fx( } is_success &= vbap->search_struct[0].triplets != NULL; - IF( speaker_nodes_group2_internal > 0 ) + IF( GT_16(speaker_nodes_group2_internal , 0 ) ) { vbap->num_search_structs = 2; + move16(); IF( ( vbap->search_struct[1].triplets = (VBAP_VS_TRIPLET *) malloc( ( ( speaker_nodes_group2_internal - 2 ) * 2 - ( max( 0, ( speaker_nodes_horiz_internal - 2 ) ) ) ) * sizeof( VBAP_VS_TRIPLET ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); @@ -481,13 +492,14 @@ ivas_error vbap_init_data_fx( ELSE { vbap->num_search_structs = 1; + move16(); vbap->search_struct[1].triplets = NULL; } } IF( is_success ) { - IF( vbap->num_search_structs == 1 ) + IF( EQ_16(vbap->num_search_structs , 1) ) { /* If all speaker nodes belong to ALL set, then we only create one triplet set and search structure */ vbap->search_struct[0].num_triplets = determine_virtual_surface_triplets_fx( vbap->num_speaker_nodes_internal, speaker_node_data, connections, max_num_connections, vbap->search_struct[0].triplets, vbap->search_struct[0].initial_search_indices, SPEAKER_NODE_ALL ); @@ -1260,8 +1272,11 @@ static void vbap_crossp_fx( { crossProduct_fx[0] = L_sub( Mpy_32_32( vec1_fx[1], vec2_fx[2] ), Mpy_32_32( vec1_fx[2], vec2_fx[1] ) ); + move32(); crossProduct_fx[1] = L_sub( Mpy_32_32( vec1_fx[2], vec2_fx[0] ), Mpy_32_32( vec1_fx[0], vec2_fx[2] ) ); + move32(); crossProduct_fx[2] = L_sub( Mpy_32_32( vec1_fx[0], vec2_fx[1] ), Mpy_32_32( vec1_fx[1], vec2_fx[0] ) ); + move32(); return; } @@ -1600,32 +1615,39 @@ static void determine_virtual_speaker_node_division_gains_fx( set16_fx( exp_virtual_node_division_gains, 0, num_speaker_nodes ); - IF( type == VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY ) + IF( EQ_16( type, VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY ) ) { FOR( c = 0; c < max_num_connections; c++ ) { - IF( connections[c][0] != VBAP_NOT_VALID_CONNECTION ) + IF( NE_16( connections[c][0], VBAP_NOT_VALID_CONNECTION ) ) { Word16 connection_node = -1; - IF( connections[c][0] == virtual_speaker_node_index ) + move16(); + IF( EQ_16( connections[c][0], virtual_speaker_node_index ) ) { connection_node = connections[c][1]; + move16(); } - ELSE IF( connections[c][1] == virtual_speaker_node_index ) + ELSE IF( EQ_16( connections[c][1], virtual_speaker_node_index ) ) { connection_node = connections[c][0]; + move16(); } /* The second condition allows division gains only to actual loudspeakers */ - IF( connection_node >= 0 && ( connection_node < num_speaker_nodes ) ) + test(); + IF( GE_16( connection_node, 0 ) && ( LT_16( connection_node, num_speaker_nodes ) ) ) { virtual_node_division_gains_fx[connection_node] = ONE_IN_Q14; + move16(); exp_virtual_node_division_gains[connection_node] = 1; + move16(); } } } sum_val_fx = 0; + move16(); Word16 guard_bits = find_guarded_bits_fx( num_speaker_nodes ); FOR( ch = 0; ch < num_speaker_nodes; ch++ ) { @@ -1642,14 +1664,18 @@ static void determine_virtual_speaker_node_division_gains_fx( ELSE { virtual_node_division_gains_fx[ch] = 0; + move16(); } exp_virtual_node_division_gains[ch] = final_exp; + move16(); IF( use_object_mode ) { - IF( virtual_node_division_gains_fx[ch] == 0 ) + IF( EQ_16( virtual_node_division_gains_fx[ch], 0 ) ) { tmp_1 = 0; + move16(); virtual_node_division_gains_fx[ch] = 0; + move16(); } ELSE { @@ -1658,19 +1684,21 @@ static void determine_virtual_speaker_node_division_gains_fx( tmp_2 = Mpy_32_32( float_to_fix( 0.8f, Q25 ), tmp_1 ); tmp_3 = BASOP_util_Pow2( tmp_2, Q31 - Q19, &res_exp ); exp_virtual_node_division_gains[ch] = res_exp; + move16(); virtual_node_division_gains_fx[ch] = extract_h( tmp_3 ); } } } /*make a common exp*/ *max_exp = MIN16B; + move16(); FOR( i = 0; i < num_speaker_nodes; i++ ) { - *max_exp = max( *max_exp, exp_virtual_node_division_gains[i] ); + *max_exp = s_max( *max_exp, exp_virtual_node_division_gains[i] ); } FOR( i = 0; i < num_speaker_nodes; i++ ) { - virtual_node_division_gains_fx[i] = shr( virtual_node_division_gains_fx[i], *max_exp - exp_virtual_node_division_gains[i] ); + virtual_node_division_gains_fx[i] = shr( virtual_node_division_gains_fx[i], sub( *max_exp, exp_virtual_node_division_gains[i] ) ); } } @@ -1759,10 +1787,12 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( Word16 Flag1, Flag2, Flag3; /* The following considers if SPEAKER_NODE_BACK virtual speaker is needed */ - IF( group == SPEAKER_NODE_BACK ) + IF( EQ_16( group, SPEAKER_NODE_BACK ) ) { Word16 virtual_back_needed = 1; + move16(); const Word16 virtual_back_epsilon_fx = -573; /* -0.0175f Q15*/ + move16(); FOR( ch = 0; ch < hVBAPdata->num_speaker_nodes; ch++ ) { Flag1 = BASOP_Util_Cmp_Mant32Exp( speaker_node_ele_deg_fx[ch], 31 - Q22, 23040 /*45.0f Q9*/, 31 - Q9 ); @@ -1784,6 +1814,7 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( IF( LT_16( cos_res, virtual_back_epsilon_fx ) ) { virtual_back_needed = 0; + move16(); break; } } @@ -1792,6 +1823,7 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( IF( virtual_back_needed ) { hVBAPdata->back_virtual_speaker_node_index = hVBAPdata->num_speaker_nodes_internal; + move16(); hVBAPdata->num_speaker_nodes_internal = add( hVBAPdata->num_speaker_nodes_internal, 1 ); return VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY; } @@ -1807,6 +1839,7 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( IF( GT_32( speaker_node_ele_deg_fx[ch], max_elevation_fx ) ) { max_elevation_fx = speaker_node_ele_deg_fx[ch]; + move32(); } } ELSE @@ -1827,10 +1860,12 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( IF( EQ_16( group, SPEAKER_NODE_BOTTOM_HALF ) ) { hVBAPdata->bottom_virtual_speaker_node_index = hVBAPdata->num_speaker_nodes_internal; + move16(); } ELSE { hVBAPdata->top_virtual_speaker_node_index = hVBAPdata->num_speaker_nodes_internal; + move16(); } hVBAPdata->num_speaker_nodes_internal = add( hVBAPdata->num_speaker_nodes_internal, 1 ); @@ -1952,6 +1987,7 @@ static void init_speaker_node_direction_data_fx( FOR( ch = 0; ch < num_speaker_nodes; ch++ ) { speaker_node_data[ch].azi_deg_fx = speaker_node_azi_deg_fx[ch]; + move32(); IF( GE_32( speaker_node_azi_deg_fx[ch], 0 ) ) { @@ -1962,17 +1998,21 @@ static void init_speaker_node_direction_data_fx( azi_rad_fx = div_l( L_negate( L_shr( speaker_node_azi_deg_fx[ch], Q7 ) ), 180 ); azi_rad_fx = negate( azi_rad_fx ); } - + test(); IF( GE_32( L_shr( speaker_node_ele_deg_fx[ch], 22 ), -5 ) && LE_32( L_shr( speaker_node_ele_deg_fx[ch], 22 ), 5 ) ) { speaker_node_data[ch].ele_deg_fx = 0; + move32(); ele_rad_fx = 0; + move32(); speaker_node_data[ch].group = SPEAKER_NODE_HORIZONTAL; + move16(); num_horiz = add( num_horiz, 1 ); } ELSE { speaker_node_data[ch].ele_deg_fx = speaker_node_ele_deg_fx[ch]; + move32(); IF( GE_32( speaker_node_ele_deg_fx[ch], 0 ) ) { ele_rad_fx = div_l( L_shr( speaker_node_ele_deg_fx[ch], Q7 ), 180 ); @@ -1986,16 +2026,21 @@ static void init_speaker_node_direction_data_fx( IF( LT_16( ele_rad_fx, 0 ) ) { speaker_node_data[ch].group = SPEAKER_NODE_BOTTOM_HALF; + move16(); } ELSE { speaker_node_data[ch].group = SPEAKER_NODE_TOP_HALF; + move16(); } } - speaker_node_data[ch].unit_vec_fx[0] = L_shr( L_mult( getCosWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ), 1 ); // Q30 (add one gaurd bit , buffer being used in Q30) - speaker_node_data[ch].unit_vec_fx[1] = L_shr( L_mult( getSineWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ), 1 ); // Q30 - speaker_node_data[ch].unit_vec_fx[2] = L_shr( L_deposit_h( getSineWord16R2( ele_rad_fx ) ), 1 ); // Q30 + speaker_node_data[ch].unit_vec_fx[0] = L_shr( L_mult( getCosWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ), 1 ); // Q30 (add one gaurd bit , buffer being used in Q30) + move32(); + speaker_node_data[ch].unit_vec_fx[1] = L_shr( L_mult( getSineWord16R2( azi_rad_fx ), getCosWord16R2( ele_rad_fx ) ), 1 ); // Q30 + move32(); + speaker_node_data[ch].unit_vec_fx[2] = L_shr( L_deposit_h( getSineWord16R2( ele_rad_fx ) ), 1 ); // Q30 + move32(); } /* Check for largest horizontal gap if there are at least 3 horizontal speaker nodes */ IF( GE_16( num_horiz, 3 ) ) @@ -2009,7 +2054,7 @@ static void init_speaker_node_direction_data_fx( i = 0; FOR( ch = 0; ch < num_speaker_nodes && i < num_horiz; ch++ ) { - IF( speaker_node_data[ch].group == SPEAKER_NODE_HORIZONTAL ) + IF( EQ_16( speaker_node_data[ch].group, SPEAKER_NODE_HORIZONTAL ) ) { Word16 exp1; Word32 Mant2 = BASOP_Util_Add_Mant32Exp( speaker_node_azi_deg_fx[ch], 31 - 22, 23040, 31 - 6, &exp1 ); @@ -2038,6 +2083,7 @@ static void init_speaker_node_direction_data_fx( IF( GT_16( temp, largest_gap ) ) { largest_gap = temp; + move16(); } } @@ -2056,6 +2102,7 @@ static void init_speaker_node_direction_data_fx( FOR( ch = 0; ch < num_speaker_nodes; ch++ ) { speaker_node_data[ch].group = SPEAKER_NODE_ALL; + move16(); } } @@ -2215,7 +2262,7 @@ static void matrix_inverse_3x3_32_fx( } } - *exp_inv_mat = max_exp; + *exp_inv_mat = max_exp + 1; FOR( i = 0; i < 3; i++ ) { @@ -2228,7 +2275,7 @@ static void matrix_inverse_3x3_32_fx( } ELSE { - inverse_matrix_fx[i][j] = L_shr( inverse_matrix_fx[i][j], max_exp - exp_inverse_matrix_fx[i][j] ); + inverse_matrix_fx[i][j] = L_shr( inverse_matrix_fx[i][j], *exp_inv_mat - exp_inverse_matrix_fx[i][j] ); } } } @@ -2376,6 +2423,7 @@ static Word16 check_and_store_triplet_fx( Word16 exp_inv_mat = 31; matrix_inverse_3x3_32_fx( speaker_node_triplet_unit_vec_matrix_fx, inverse_matrix_fx, &exp_inv_mat ); triplets[*triplet_index].exp_inv_matrix = exp_inv_mat; + triplets[*triplet_index].q_inverse_matrix = 31 - exp_inv_mat; /* Check through all speaker nodes that none of them are within the triplet. * Node within the triplet is identified by that all three panning gains are positive. @@ -2413,8 +2461,12 @@ static Word16 check_and_store_triplet_fx( } } /* Get center azimuth for fast search use */ - Word32 tmp_a = L_add( L_shr( L_add( speaker_node_data[chA].unit_vec_fx[1], speaker_node_data[chB].unit_vec_fx[1] ), 2 ), L_shr( speaker_node_data[chC].unit_vec_fx[1], 2 ) ); // Q27 - Word32 tmp_b = L_add( L_shr( L_add( speaker_node_data[chA].unit_vec_fx[0], speaker_node_data[chB].unit_vec_fx[0] ), 2 ), L_shr( speaker_node_data[chC].unit_vec_fx[0], 2 ) ); // Q27 + Word32 tmp_a = L_add( L_shr( L_add( speaker_node_data[chA].unit_vec_fx[1], speaker_node_data[chB].unit_vec_fx[1] ), 2 ), L_shr( speaker_node_data[chC].unit_vec_fx[1], 2 ) ); // Q28 + /*Condition to make tmp_a 0 to adress precision loss seen*/ + IF (tmp_a == -8193) { + tmp_a = 0; + } + Word32 tmp_b = L_add( L_shr( L_add( speaker_node_data[chA].unit_vec_fx[0], speaker_node_data[chB].unit_vec_fx[0] ), 2 ), L_shr( speaker_node_data[chC].unit_vec_fx[0], 2 ) ); // Q28 Word16 tmp_tan = shr( BASOP_util_atan2( tmp_a, tmp_b, 0 ), Q13 - Q9 ); triplet_azidegs_fx[*triplet_index] = L_mult( tmp_tan, 29335 /*_180_OVER_PI in Q9*/ ); // Q3 @@ -2636,11 +2688,15 @@ static Word16 determine_virtual_surface_triplets_fx( /* Get all connections connected to current chA that have not been used by * two triplets yet. */ num_connected_to_chA = 0; + move16(); FOR( k = 0; k < max_num_connections; k++ ) { + test(); + test(); IF( ( EQ_16( connections[k][0], chA ) || EQ_16( connections[k][1], chA ) ) && ( GT_16( connection_uses_left[k], 0 ) ) ) { connected_to_chA[num_connected_to_chA] = k; + move16(); num_connected_to_chA = add( num_connected_to_chA, 1 ); } } @@ -2656,23 +2712,31 @@ static Word16 determine_virtual_surface_triplets_fx( FOR( k = 0; k < num_connected_to_chA; k++ ) { Word16 connect_index_k = connected_to_chA[k]; - chB = connections[connect_index_k][0] == chA ? connections[connect_index_k][1] : connections[connect_index_k][0]; + move16(); + chB = EQ_16( connections[connect_index_k][0], chA ) ? connections[connect_index_k][1] : connections[connect_index_k][0]; FOR( l = k + 1; l < num_connected_to_chA; l++ ) { Word16 connect_index_l = connected_to_chA[l]; - chC = connections[connect_index_l][0] == chA ? connections[connect_index_l][1] : connections[connect_index_l][0]; + move16(); + chC = EQ_16( connections[connect_index_l][0], chA ) ? connections[connect_index_l][1] : connections[connect_index_l][0]; /* With chA, chB, and chC selected, we still need to find connection between chB and chC and verify that the triplet is valid */ FOR( m = 0; m < max_num_connections; m++ ) { + test(); + test(); + test(); IF( ( EQ_16( connections[m][0], chB ) && EQ_16( connections[m][1], chC ) ) || ( EQ_16( connections[m][1], chB ) && EQ_16( connections[m][0], chC ) ) ) { Word16 flag = check_and_store_triplet_fx( chA, chB, chC, num_speaker_nodes, speaker_node_data, triplets, &num_triplets, triplet_azidegs_fx, triplet_order ); - IF( flag == 1 ) + IF( EQ_16( flag, 1 ) ) { connection_uses_left[connect_index_k] = sub( connection_uses_left[connect_index_k], 1 ); + move16(); connection_uses_left[connect_index_l] = sub( connection_uses_left[connect_index_l], 1 ); + move16(); connection_uses_left[m] = sub( connection_uses_left[m], 1 ); + move16(); break; } } @@ -2774,7 +2838,9 @@ static void determine_initial_search_indices_fx( best_index = 0; + move16(); min_azideg_diff_fx = ONE_IN_Q31; + move32(); FOR( j = 0; j < num_triplets; j++ ) { @@ -2793,11 +2859,14 @@ static void determine_initial_search_indices_fx( IF( LT_32( azideg_diff_fx, min_azideg_diff_fx ) ) { min_azideg_diff_fx = azideg_diff_fx; + move32(); best_index = j; + move16(); } } initial_search_indices[i] = best_index; + move16(); } return; @@ -2834,13 +2903,14 @@ static ivas_error determine_connections_fx( FOR (c = 0; c < max_num_connections; c++) { connections[c][0] = VBAP_NOT_VALID_CONNECTION; + move16(); } /* This function determines some prominent elevated planes, that are favoured in making node-node connections. */ num_non_crossing_planes = determine_non_crossing_planes_fx(num_speaker_nodes, speaker_node_data, non_crossing_plane_elevation_deg_fx); /* Process in different mode based on the grouping. It is enough to check for first node. */ - IF (speaker_node_data[0].group == SPEAKER_NODE_ALL) + IF (EQ_16(speaker_node_data[0].group , SPEAKER_NODE_ALL)) { IF ((error = formulate_half_sphere_connections_fx(speaker_node_data, num_speaker_nodes, SPEAKER_NODE_ALL, connections, &connection_write_index, max_num_connections, num_non_crossing_planes, non_crossing_plane_elevation_deg_fx)) != IVAS_ERR_OK) { @@ -2855,16 +2925,18 @@ static ivas_error determine_connections_fx( return error; } *group2_start = connection_write_index; + move16(); formulate_horizontal_connections_fx(speaker_node_data, num_speaker_nodes, connections, &connection_write_index); *group1_count = connection_write_index; + move16(); IF ((error = formulate_half_sphere_connections_fx(speaker_node_data, num_speaker_nodes, SPEAKER_NODE_TOP_HALF, connections, &connection_write_index, max_num_connections, num_non_crossing_planes, non_crossing_plane_elevation_deg_fx)) != IVAS_ERR_OK) { return error; } - *group2_count = connection_write_index - *group2_start; + *group2_count = sub(connection_write_index , *group2_start); } return IVAS_ERR_OK; @@ -2975,30 +3047,40 @@ static enum ConnectionClass determine_connection_class_fx( FOR( ch = 0; ch < num_speaker_nodes; ch++ ) { /* Select speaker_node only within TOP or BOTTOM sphere half, not being part of chA-chB pair */ - IF( ( group == node_data[ch].group ) && ( ch != chA ) && ( ch != chB ) ) + test(); + test(); + IF( ( EQ_16( group, node_data[ch].group ) ) && ( NE_16( ch, chA ) ) && ( NE_16( ch, chB ) ) ) { /* The following lines formulate the point on the chA-chB-connection that is nearest to the origo-ch-line */ p1_fx = node_data[chA].unit_vec_fx; // Q30 + move32(); FOR( k = 0; k < 3; k++ ) { v1_fx[k] = L_sub( L_shr( node_data[chB].unit_vec_fx[k], 2 ), L_shr( node_data[chA].unit_vec_fx[k], 2 ) ); // q28 (Add two guard bit) } v2_fx = node_data[ch].unit_vec_fx; // q30 + move32(); v1v1_fx = dotp_fixed( v1_fx, v1_fx, 3 ); // Q25 + move32(); v1v2_fx = dotp_fixed( v1_fx, v2_fx, 3 ); // Q27 + move32(); v2v2_fx = ONE_IN_Q29; + move32(); v1p1_fx = dotp_fixed( v1_fx, p1_fx, 3 ); // Q27 + move32(); v2p1_fx = dotp_fixed( v2_fx, p1_fx, 3 ); // Q29 + move32(); Word32 tmp1 = Mpy_32_32( v1v2_fx, v1v2_fx ); // Q23 Word32 tmp2 = Mpy_32_32( v1v1_fx, L_negate( v2v2_fx ) ); // Q23 Word32 tmp3 = L_add( tmp1, tmp2 ); // Q23 determinant_fx = tmp3; // Q23 + move32(); /* Norm distance = distance parameter on line chA-chB, determines point that is nearest to origo-ch line. Distance 0 means chA and distance 1 means chB. Can be @@ -3008,9 +3090,10 @@ static enum ConnectionClass determine_connection_class_fx( Word32 tmp5 = Mpy_32_32( L_negate( v1v2_fx ), v2p1_fx ); // q25 Word32 tmp6 = L_add( tmp4, tmp5 ); // q25 Word16 tmp7, exp = 0; - IF( determinant_fx == 0 ) + IF( EQ_32( determinant_fx, 0 ) ) { determinant_fx = 1; + move32(); } tmp7 = BASOP_Util_Divide3232_Scale( ONE_IN_Q23, determinant_fx, &exp ); // Q(15 - exp) norm_distance_on_v1_fx = Mpy_32_16_1( tmp6, tmp7 ); // Q25 + Q(15 - exp) - Q15 = Q(25 - exp) @@ -3019,27 +3102,35 @@ static enum ConnectionClass determine_connection_class_fx( Word16 exp_vTarget = 0, exp_energy_sum = 0, exp_vec_diff = 0; Word32 var1, var2; Word16 vTarget_fx_e[3], vec_diff_e[3]; - IF( GT_32( norm_distance_on_v1_fx, 0 ) && LT_32( norm_distance_on_v1_fx, L_shr( ONE_IN_Q31, 31 - ( Q25 - exp ) ) ) ) + test(); + IF( GT_32( norm_distance_on_v1_fx, 0 ) && LT_32( norm_distance_on_v1_fx, L_shr( ONE_IN_Q31, sub( 31, sub( Q25, exp ) ) ) ) ) { /* Formulate vTarget, that is an unit vector that goes through the determined point on chA-chB connection */ energy_sum_fx = 0; + move32(); FOR( k = 0; k < 3; k++ ) { var1 = Mpy_32_32( norm_distance_on_v1_fx, v1_fx[k] ); // Q(25 - exp) + Q28 - 31 vTarget_fx[k] = BASOP_Util_Add_Mant32Exp( p1_fx[k], 1, var1, 31 - ( Q25 - exp + Q28 - 31 ), &exp_vTarget ); + move16(); vTarget_fx_e[k] = exp_vTarget; + move16(); var2 = Mpy_32_32( vTarget_fx[k], vTarget_fx[k] ); // 2*exp_vTarget energy_sum_fx = BASOP_Util_Add_Mant32Exp( energy_sum_fx, exp_energy_sum, var2, 2 * exp_vTarget, &exp_energy_sum ); vec_diff_fx[k] = BASOP_Util_Add_Mant32Exp( vTarget_fx[k], exp_vTarget, L_negate( v2_fx[k] ), 1, &exp_vec_diff ); + move16(); vec_diff_e[k] = exp_vec_diff; + move16(); } Word16 exp_eq = exp_energy_sum; eq_value_fx = ISqrt32( energy_sum_fx, &exp_eq ); FOR( k = 0; k < 3; k++ ) { vTarget_fx[k] = Mpy_32_32( vTarget_fx[k], eq_value_fx ); - vTarget_fx_e[k] = vTarget_fx_e[k] + exp_eq; + move32(); + vTarget_fx_e[k] = add( vTarget_fx_e[k], exp_eq ); + move16(); } /*make a common exponent*/ Word16 max_vTarget_e = 0, max_vec_diff_e = 0; @@ -3051,7 +3142,9 @@ static enum ConnectionClass determine_connection_class_fx( FOR( k = 0; k < 3; k++ ) { vTarget_fx[k] = L_shr( vTarget_fx[k], sub( max_vTarget_e, vTarget_fx_e[k] ) ); + move32(); vec_diff_fx[k] = L_shr( vec_diff_fx[k], sub( max_vec_diff_e, vec_diff_e[k] ) ); + move32(); } /* A check if the angle between vTarget and node_data[ch].unit_vec is less than 1 degree. Essentially reveals if there is a speaker node too close "behind" the connection. Such @@ -3059,11 +3152,14 @@ static enum ConnectionClass determine_connection_class_fx( FOR( int i = 0; i < 3; i++ ) { vTarget_fx[i] = L_shr( vTarget_fx[i], 2 ); // add guard bits + move32(); vec_diff_fx[i] = L_shr( vec_diff_fx[i], 2 ); + move32(); } Word32 res = dotp_fixed( vTarget_fx, v2_fx, 3 ); // 31 - (max_vTarget_e + 2) + 30 - 31 = 28 - max_vTarget_e + move32(); - IF( GT_32( res, L_shr( 2147054208, 31 - ( 28 - max_vTarget_e ) ) ) ) + IF( GT_32( res, L_shr( 2147054208, sub( 31, sub( 28, max_vTarget_e ) ) ) ) ) { return CONNECTION_WITH_SPEAKER_NODE_BEHIND; } @@ -3072,9 +3168,10 @@ static enum ConnectionClass determine_connection_class_fx( A triplet between these nodes is not desired if there is a top node, a penalty is implemented to take care of this. */ Word32 vec_diff_dotp = dotp_fixed( vec_diff_fx, vec_diff_fx, 3 ); // exp : 2 * max_vec_diff_e + 4 - Word32 var = Mpy_32_32( vec_diff_dotp, 51200 /*25.0f in Q11*/ ); // exp : 2 * max_vec_diff_e + 4 + 20 + move32(); + Word32 var = Mpy_32_32( vec_diff_dotp, 51200 /*25.0f in Q11*/ ); // exp : 2 * max_vec_diff_e + 4 + 20 Word16 Flag1 = BASOP_Util_Cmp_Mant32Exp( v1v1_fx, 31 - Q25, var, 2 * max_vec_diff_e + 4 + 20 ); - IF( Flag1 == 1 ) + IF( EQ_16( Flag1, 1 ) ) { IF( LT_32( L_abs( L_sub( node_data[chB].unit_vec_fx[2], node_data[chA].unit_vec_fx[2] ) ), 2147483 ) ) { @@ -3217,8 +3314,11 @@ static void formulate_horizontal_connections_fx( IF( EQ_16( speaker_node_data[ch].group, SPEAKER_NODE_HORIZONTAL ) ) { next_index = -1; + move16(); min_arc_diff_fx = 19998 /*9999.0f in Q1*/; + move32(); Q_min_arc_diff = 1; + move16(); FOR( chCheck = 0; chCheck < num_speaker_nodes; chCheck++ ) { @@ -3233,13 +3333,18 @@ static void formulate_horizontal_connections_fx( IF( LT_32( L_shr( arc_diff_fx, 22 - Q_min_arc_diff ), min_arc_diff_fx ) ) { min_arc_diff_fx = arc_diff_fx; + move32(); Q_min_arc_diff = 22; + move16(); next_index = chCheck; + move16(); } } } connections[*connection_write_index][0] = ch; + move16(); connections[*connection_write_index][1] = next_index; + move16(); *connection_write_index = add( *connection_write_index, 1 ); } } @@ -3377,7 +3482,8 @@ static ivas_error get_half_sphere_connection_options_fx( /* Count max num connection options at the half sphere */ FOR( node = 0; node < num_speaker_nodes; node++ ) { - IF( speaker_node_data[node].group == group || speaker_node_data[node].group == SPEAKER_NODE_HORIZONTAL ) + test(); + IF( EQ_16(speaker_node_data[node].group , group) || EQ_16( speaker_node_data[node].group, SPEAKER_NODE_HORIZONTAL ) ) { max_num_connection_options = add( max_num_connection_options, index ); index = add( index, 1 ); @@ -3393,46 +3499,57 @@ static ivas_error get_half_sphere_connection_options_fx( FOR( c = 0; c < max_num_connection_options; c++ ) { c_options[c].chA = -1; + move16(); c_options[c].chB = -1; + move16(); c_options[c].arc_fx = MAX_32; + move32(); c_options[c].arc_weighted_fx = MAX_32; + move32(); } /* Determine connection options for the half-sphere */ index = 0; + move16(); FOR( chA = 0; chA < num_speaker_nodes; chA++ ) { /* First loudspeaker at the connection is at the half sphere */ - IF( speaker_node_data[chA].group == group || speaker_node_data[chA].group == SPEAKER_NODE_HORIZONTAL ) + test(); + IF( EQ_16( speaker_node_data[chA].group, group ) || EQ_16( speaker_node_data[chA].group, SPEAKER_NODE_HORIZONTAL ) ) { FOR( chB = chA + 1; chB < num_speaker_nodes; chB++ ) { - /* Second loudspeaker at the connection is at the half sphere, but so that first and second are not both horizontal. */ - IF( ( speaker_node_data[chB].group == group ) || ( speaker_node_data[chB].group == SPEAKER_NODE_HORIZONTAL && speaker_node_data[chA].group == group ) ) - { + /* Second loudspeaker at the connection is at the half sphere, but so that first and second are not both horizontal. */ + test(); + test(); + IF( ( EQ_16( speaker_node_data[chB].group, group ) ) || ( EQ_16( speaker_node_data[chB].group, SPEAKER_NODE_HORIZONTAL ) && EQ_16( speaker_node_data[chA].group, group ) ) ) + { Word16 ConnectionClass = determine_connection_class_fx( speaker_node_data, num_speaker_nodes, group, chA, chB ); Word32 unit_vec_dotp, unit_vec_dotp_sq, one_minus_unit_vec_dotp_sq, one_minus_unit_vec_dotp_sq_root; Word16 acos_val; /* Connection is considered only if there is no speaker node behind it */ - IF( ConnectionClass != CONNECTION_WITH_SPEAKER_NODE_BEHIND ) + IF( NE_16( ConnectionClass, CONNECTION_WITH_SPEAKER_NODE_BEHIND ) ) { /* Store connection information */ c_options[index].chA = chA; + move16(); c_options[index].chB = chB; + move16(); unit_vec_dotp = dotp_fixed( speaker_node_data[chA].unit_vec_fx, speaker_node_data[chB].unit_vec_fx, 3 ); // Q29 unit_vec_dotp_sq = Mpy_32_32( unit_vec_dotp, unit_vec_dotp ); // Q27 one_minus_unit_vec_dotp_sq = L_sub( ONE_IN_Q27, unit_vec_dotp_sq ); - Word16 exp_uv = 31 - Q27; + Word16 exp_uv = sub( 31, Q27 ); one_minus_unit_vec_dotp_sq_root = Sqrt32( one_minus_unit_vec_dotp_sq, &exp_uv ); acos_val = BASOP_util_atan2( one_minus_unit_vec_dotp_sq_root, unit_vec_dotp, exp_uv - 2 ); // Q13 c_options[index].arc_fx = L_deposit_h( acos_val ); // Q29 - c_options[index].arc_weighted_fx = c_options[index].arc_fx; // Q29 + c_options[index].arc_weighted_fx = c_options[index].arc_fx; // Q29 + move32(); /* A special case, mainly accounting for ELEVATED L,R,C speaker nodes. A triplet between these nodes is not desired if there is a top node, a penalty is implemented to take care of this. */ - IF( ConnectionClass == ELEVATED_PLANE_THIN_TRIANGLE_CONNECTION ) + IF( EQ_16( ConnectionClass, ELEVATED_PLANE_THIN_TRIANGLE_CONNECTION ) ) { c_options[index].arc_weighted_fx = L_shl( c_options[index].arc_weighted_fx, 1 ); } @@ -3445,50 +3562,60 @@ static ivas_error get_half_sphere_connection_options_fx( } index = add( index, 1 ); } - } + } } } } /* Number of found connection options at the half sphere */ *num_connection_options = index; - + move16(); /* Init memory for reordered connection options and order by arc_weighted, * which informs of the preference order of the connections in case they cross */ IF( ( c_options_reorder = (ConnectionOption *) malloc( sizeof( ConnectionOption ) * ( *num_connection_options ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for VBAP data\n" ) ); } - + FOR( c = 0; c < *num_connection_options; c++ ) { Word16 min_arc_index; min_arc_index = -1; + move16(); Word32 min_arc_weighted_fx_new = MAX_32; + move16(); Word16 exp_min_arc_weighted_fx = 31; + move16(); Word16 res = 0; + move16(); FOR( c_cmp = 0; c_cmp < *num_connection_options; c_cmp++ ) { res = BASOP_Util_Cmp_Mant32Exp( c_options[c_cmp].arc_weighted_fx, 31 - Q29, min_arc_weighted_fx_new, exp_min_arc_weighted_fx ); - // todo : check condition - IF( res == -1 || res == 0 ) + IF( EQ_16( res, -1 ) || EQ_16( res, 0 ) ) { - min_arc_weighted_fx_new = c_options[c_cmp].arc_weighted_fx; - exp_min_arc_weighted_fx = 31 - Q29; - min_arc_index = c_cmp; + min_arc_weighted_fx_new = c_options[c_cmp].arc_weighted_fx; + move32(); + exp_min_arc_weighted_fx = sub( 31, Q29 ); + min_arc_index = c_cmp; + move16(); } } c_options_reorder[c].chA = c_options[min_arc_index].chA; + move16(); c_options_reorder[c].chB = c_options[min_arc_index].chB; - + move16(); + c_options_reorder[c].arc_fx = c_options[min_arc_index].arc_fx; + move32(); c_options_reorder[c].arc_weighted_fx = c_options[min_arc_index].arc_weighted_fx; + move32(); c_options[min_arc_index].arc_weighted_fx = MAX_32; + move32(); } - + /* Set reordered connections as output and free temporary data */ *connection_options_pr = c_options_reorder; free( c_options ); - + return IVAS_ERR_OK; } #endif @@ -3620,7 +3747,7 @@ static ivas_error get_half_sphere_connection_options( #ifdef IVAS_FLOAT_FIXED static ivas_error formulate_half_sphere_connections_fx( const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data */ - const Word16 num_speaker_nodes, /* i : number of speaker nodes */ + const Word16 num_speaker_nodes, /* i : number of speaker nodes */ const enum SpeakerNodeGroup group, /* i : speaker node group */ Word16 connections[][2], /* o : vector of connections */ Word16 *connection_write_index, @@ -3649,17 +3776,18 @@ static ivas_error formulate_half_sphere_connections_fx( ivas_error error; half_sphere_first_connection = *connection_write_index; + move16(); /* Obtain all connection options (i.e., channel pairs) at the half sphere. The function orders them * in terms of which connection to keep if two connections would cross each other. */ - IF ( ( error = get_half_sphere_connection_options_fx( - speaker_node_data, - group, - num_speaker_nodes, - num_non_crossing_planes, - non_crossing_plane_elevation_deg_fx, - &connection_options, - &num_connection_options ) ) != IVAS_ERR_OK ) + IF( ( error = get_half_sphere_connection_options_fx( + speaker_node_data, + group, + num_speaker_nodes, + num_non_crossing_planes, + non_crossing_plane_elevation_deg_fx, + &connection_options, + &num_connection_options ) ) != IVAS_ERR_OK ) { return error; } @@ -3672,26 +3800,39 @@ static ivas_error formulate_half_sphere_connections_fx( /* The following loop goes through all reasonable chA - chB pairs for the half-sphere */ c_opt = 0; + move16(); WHILE( c_opt < num_connection_options && *connection_write_index < max_num_connections ) { chA = connection_options[c_opt].chA; + move16(); chB = connection_options[c_opt].chB; + move16(); new_arc_fx = connection_options[c_opt].arc_fx; + move32(); /* Cross-product is needed for later stages */ vbap_crossp_fx( speaker_node_data[chA].unit_vec_fx, speaker_node_data[chB].unit_vec_fx, new_cross_fx ); /* Determine if new connection between chA and chB is valid */ new_connection_is_valid = 1; + move16(); c = half_sphere_first_connection; + move16(); Word32 var1, var2, var1_sq, var2_sq, var1_sqrt, var2_sqrt, one_minus_var1_sq, one_minus_var2_sq, var_a, var_b, var_c; Word16 var1_cos, var2_cos, final_exp, final_exp_A, final_exp_B, exp_var1_sq, exp_var2_sq, comp1, comp2, sub_exp = 0, sub_exp_2 = 0, sub_final_exp = 0; - WHILE( ( c < *connection_write_index ) && new_connection_is_valid ) + + test(); + WHILE( ( LT_16( c, *connection_write_index ) ) && new_connection_is_valid ) { cmp_chA = connections[c][0]; + move16(); cmp_chB = connections[c][1]; + move16(); /* The connections are compared only if they don't involve same speaker nodes */ - IF( ( cmp_chA != chA ) && ( cmp_chA != chB ) && ( cmp_chB != chA ) && ( cmp_chB != chB ) ) + test(); + test(); + test(); + IF( ( NE_16( cmp_chA, chA ) ) && ( NE_16( cmp_chA, chB ) ) && ( NE_16( cmp_chB, chA ) ) && ( NE_16( cmp_chB, chB ) ) ) { /* The following lines determine if the connection chA-chB crosses with the connection cmp_chA-cmp_chB.*/ /* The connections, i.e., node-pairs determine a plane. The crossing can be determined by @@ -3699,26 +3840,30 @@ static ivas_error formulate_half_sphere_connections_fx( vbap_crossp_fx( connection_cross_fx[c], new_cross_fx, planeCrossingVec_fx ); tmpFloat_fx = 0; + move16(); cmp_arc_fx = connection_arc_fx[c]; + move16(); FOR( k = 0; k < 3; k++ ) { tmpFloat_fx = L_add( tmpFloat_fx, Mpy_32_32( planeCrossingVec_fx[k], planeCrossingVec_fx[k] ) ); } - Word16 tmp_exp = 31 - Q23; + Word16 tmp_exp = sub( 31, Q23 ); IF( tmpFloat_fx == 0 ) { tmpFloat_fx = 1; + move16(); } normVal_fx = ISqrt32( tmpFloat_fx, &tmp_exp ); FOR( k = 0; k < 3; k++ ) { planeCrossingVec_fx[k] = Mpy_32_32( planeCrossingVec_fx[k], normVal_fx ); // Q27 + Q31 - tmp_exp - Q31 + move32(); } /*update Q for planeCrossingVec */ - Q_planeCrossingVec = Q27 + Q31 - tmp_exp - Q31; + Q_planeCrossingVec = sub( sub( add( Q27, Q31 ), tmp_exp ), Q31 ); /* If the plane intersection is between both connections, then the two connections cross. */ /* Study first if the crossing is between arc chA-chB */ @@ -3727,22 +3872,27 @@ static ivas_error formulate_half_sphere_connections_fx( var1_sq = Mpy_32_32( var1, var1 ); //(2 * (Q_planeCrossingVec - Q1) ) - Q31 var2_sq = Mpy_32_32( var2, var2 ); - exp_var1_sq = 2 * ( Q31 - ( Q_planeCrossingVec - Q1 ) ); - exp_var2_sq = 2 * ( Q31 - ( Q_planeCrossingVec - Q1 ) ); - IF( L_abs( var1_sq ) > L_shr( ONE_IN_Q31, exp_var1_sq ) ) + exp_var1_sq = shl( sub( Q31, sub( Q_planeCrossingVec, Q1 ) ), 1 ); + exp_var2_sq = shl( sub( Q31, sub( Q_planeCrossingVec, Q1 ) ), 1 ); + IF( GT_32( L_abs( var1_sq ), L_shr( ONE_IN_Q31, exp_var1_sq ) ) ) { var1_sq = ONE_IN_Q31; + move16(); exp_var1_sq = 0; + move16(); } - IF( L_abs( var2_sq ) > L_shr( ONE_IN_Q31, exp_var2_sq ) ) + IF( GT_32( L_abs( var2_sq ), L_shr( ONE_IN_Q31, exp_var2_sq ) ) ) { var2_sq = ONE_IN_Q31; + move16(); exp_var2_sq = 0; + move16(); } one_minus_var1_sq = BASOP_Util_Add_Mant32Exp( ONE_IN_Q30, 1, L_negate( var1_sq ), exp_var1_sq, &final_exp_A ); var1_sqrt = Sqrt32( one_minus_var1_sq, &final_exp_A ); var1_cos = BASOP_util_atan2( var1_sqrt, var1, final_exp_A - ( Q31 - ( Q_planeCrossingVec + Q30 - Q31 ) ) ); // Q13 angleCmp_fx = var1_cos; + move16(); one_minus_var2_sq = BASOP_Util_Add_Mant32Exp( ONE_IN_Q30, 1, L_negate( var2_sq ), exp_var2_sq, &final_exp_B ); var2_sqrt = Sqrt32( one_minus_var2_sq, &final_exp_B ); @@ -3758,48 +3908,59 @@ static ivas_error formulate_half_sphere_connections_fx( comp2 = BASOP_Util_Cmp_Mant32Exp( L_abs( var_c ), sub_final_exp, 21474836, 0 ); within_first_arc = 0; - IF( comp1 == -1 ) + move16(); + IF( EQ_16( comp1, -1 ) ) { within_first_arc = 1; + move16(); } - ELSE IF( comp2 == -1 ) + ELSE IF( EQ_16( comp2, -1 ) ) { within_first_arc = 1; + move16(); /* In this case, the plane crossing vector is inverted. The inverse is another * plane-crossing vector, and detected to be between chA-chB connection.*/ FOR( k = 0; k < 3; k++ ) { planeCrossingVec_fx[k] = Mpy_32_32( planeCrossingVec_fx[k], -134217728 /*-1.0f in Q27*/ ); // 27 + 27 - tmp_exp - 31 = 23 - tmp_exp + move32(); } /*update Q for planeCrossingVec */ - Q_planeCrossingVec = Q27 + Q27 - tmp_exp - Q31; + Q_planeCrossingVec = sub( sub( add( Q27, Q27 ), tmp_exp ), Q31 ); } /* Study if the crossing is also between arc cmp_chA-cmp_chB */ - IF( within_first_arc > 0 ) + IF( GT_16( within_first_arc, 0 ) ) { var1 = dotp_fixed( planeCrossingVec_fx, speaker_node_data[cmp_chA].unit_vec_fx, 3 ); + move32(); var2 = dotp_fixed( planeCrossingVec_fx, speaker_node_data[cmp_chB].unit_vec_fx, 3 ); + move32(); final_exp_A, final_exp_B, exp_var1_sq, exp_var2_sq; var1_sq = Mpy_32_32( var1, var1 ); //(2 * (Q_planeCrossingVec - Q1) ) - Q31 var2_sq = Mpy_32_32( var2, var2 ); - exp_var1_sq = 2 * ( Q31 - ( Q_planeCrossingVec - Q1 ) ); - exp_var2_sq = 2 * ( Q31 - ( Q_planeCrossingVec - Q1 ) ); - IF( L_abs( var1_sq ) > L_shr( ONE_IN_Q31, exp_var1_sq ) ) + exp_var1_sq = shl( ( sub( Q31, sub( Q_planeCrossingVec, Q1 ) ) ), 1 ); + exp_var2_sq = shl( ( sub( Q31, sub( Q_planeCrossingVec, Q1 ) ) ), 1 ); + IF( GT_32( L_abs( var1_sq ), L_shr( ONE_IN_Q31, exp_var1_sq ) ) ) { var1_sq = ONE_IN_Q31; + move16(); exp_var1_sq = 0; + move16(); } - IF( L_abs( var2_sq ) > L_shr( ONE_IN_Q31, exp_var2_sq ) ) + IF( GT_32( L_abs( var2_sq ), L_shr( ONE_IN_Q31, exp_var2_sq ) ) ) { var2_sq = ONE_IN_Q31; + move16(); exp_var2_sq = 0; + move16(); } one_minus_var1_sq = BASOP_Util_Add_Mant32Exp( ONE_IN_Q30, 1, L_negate( var1_sq ), exp_var1_sq, &final_exp_A ); var1_sqrt = Sqrt32( one_minus_var1_sq, &final_exp_A ); var1_cos = BASOP_util_atan2( var1_sqrt, var1, final_exp_A - ( Q31 - ( Q_planeCrossingVec + Q30 - Q31 ) ) ); // Q13 angleCmp_fx = var1_cos; + move16(); one_minus_var2_sq = BASOP_Util_Add_Mant32Exp( ONE_IN_Q30, 1, L_negate( var2_sq ), exp_var2_sq, &final_exp_B ); var2_sqrt = Sqrt32( one_minus_var2_sq, &final_exp_B ); @@ -3808,6 +3969,9 @@ static ivas_error formulate_half_sphere_connections_fx( final_exp = BASOP_Util_Add_MantExp( angleCmp_fx, Q15 - Q13, var2_cos, Q15 - Q13, &angleCmp_fx ); sub_exp = 0, sub_exp_2 = 0, sub_final_exp = 0; + move16(); + move16(); + move16(); var_a = BASOP_Util_Add_Mant32Exp( cmp_arc_fx, Q31 - Q29, L_negate( L_deposit_h( angleCmp_fx ) ), final_exp, &sub_exp ); comp1 = BASOP_Util_Cmp_Mant32Exp( L_abs( var_a ), sub_exp, 21474836, 0 ); @@ -3816,6 +3980,7 @@ static ivas_error formulate_half_sphere_connections_fx( /* A crossing is detected. The new connection is not valid, because * the connections were ordered in order of preference (arc_weighted) */ new_connection_is_valid = 0; + move16(); } } } @@ -3823,15 +3988,21 @@ static ivas_error formulate_half_sphere_connections_fx( } /* Store the new connection which has been confirmed valid */ - IF( new_connection_is_valid > 0 ) + IF( GT_16( new_connection_is_valid, 0 ) ) { connections[*connection_write_index][0] = chA; + move16(); connections[*connection_write_index][1] = chB; + move16(); connection_arc_fx[*connection_write_index] = new_arc_fx; // Q29 + move16(); connection_cross_fx[*connection_write_index][0] = new_cross_fx[0]; + move16(); connection_cross_fx[*connection_write_index][1] = new_cross_fx[1]; + move16(); connection_cross_fx[*connection_write_index][2] = new_cross_fx[2]; - ( *connection_write_index )++; + move16(); + *connection_write_index = add( *connection_write_index, 1 ); } c_opt = add( c_opt, 1 ); } @@ -3998,8 +4169,8 @@ static ivas_error formulate_half_sphere_connections( #ifdef IVAS_FLOAT_FIXED static Word16 determine_non_crossing_planes_fx( - const Word16 num_speaker_nodes, /* i : number of speaker nodes */ - const VBAP_SPEAKER_NODE *node_data, /* i : speaker node data */ + const Word16 num_speaker_nodes, /* i : number of speaker nodes */ + const VBAP_SPEAKER_NODE *node_data, /* i : speaker node data */ Word32 *non_crossing_plane_elevation_deg_fx /* o : vector of non-crossing plane elevations */ ) { @@ -4012,12 +4183,15 @@ static Word16 determine_non_crossing_planes_fx( Word16 num_planes; ele_check_fx = -16382362; /*Q14*/ + move32(); num_planes = 0; + move16(); /* For each plane, check if a non-crossing plane should be determined */ WHILE( LT_32( ele_check_fx, 1474560 ) /*90.0f Q14*/ ) { next_ele_check_fx = 16382362; /*Q14*/ + move32(); Word32 tmp1, tmp2; @@ -4032,6 +4206,7 @@ static Word16 determine_non_crossing_planes_fx( } } ele_check_fx = next_ele_check_fx; // Q14 + move32(); IF( GT_32( ele_check_fx, 1474560 ) /*90.0f in Q14*/ ) { @@ -4040,14 +4215,17 @@ static Word16 determine_non_crossing_planes_fx( } max_gap_fx = -163838368; // Q14 + move32(); FOR( ch = 0; ch < num_speaker_nodes; ch++ ) { /* Find gap to the next speaker node at the same plane */ IF( LT_32( L_abs( L_sub( L_shr( node_data[ch].ele_deg_fx, 8 ), ele_check_fx ) ), 16 /*0.001f in Q14*/ ) ) { gap_to_next_ls_fx = 1638398336; // Q14 + move32(); FOR( ch_cmp = 0; ch_cmp < num_speaker_nodes; ch_cmp++ ) { + test(); IF( NE_16( ch_cmp, ch ) && LT_32( L_abs( L_sub( L_shr( node_data[ch_cmp].ele_deg_fx, 8 ), ele_check_fx ) ), 16 /*0.001f in Q14*/ ) ) { Word32 gap_fx = L_sub( node_data[ch_cmp].azi_deg_fx, node_data[ch].azi_deg_fx ); @@ -4065,6 +4243,7 @@ static Word16 determine_non_crossing_planes_fx( IF( GT_32( gap_to_next_ls_fx, max_gap_fx ) ) { max_gap_fx = gap_to_next_ls_fx; + move32(); } } }