diff --git a/lib_dec/ivas_dirac_dec.c b/lib_dec/ivas_dirac_dec.c index f018c11986f7d90f5433ddd2b69c796215609429..92647bd4f3aef12b86c04ecf05142cd3d3a6acdb 100644 --- a/lib_dec/ivas_dirac_dec.c +++ b/lib_dec/ivas_dirac_dec.c @@ -947,8 +947,7 @@ static ivas_error ivas_dirac_rend_config_fx( return error; } -#endif - +#else static ivas_error ivas_dirac_rend_config( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ const DIRAC_CONFIG_FLAG flag_config_inp, /* i/ : Flag determining if we open or reconfigure the DirAC decoder */ @@ -1372,7 +1371,6 @@ static ivas_error ivas_dirac_rend_config( { vbap_free_data(&(st_ivas->hVBAPdata)); } - if ((error = vbap_init_data(&(st_ivas->hVBAPdata), ls_azimuth, ls_elevation, nchan_out_woLFE, st_ivas->ivas_format)) != IVAS_ERR_OK) { return error; @@ -1580,7 +1578,7 @@ static ivas_error ivas_dirac_rend_config( return error; } - +#endif /*------------------------------------------------------------------------- * ivas_dirac_dec_config() * diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index f8738483b9d8f92a52ed4ceea68aeb2a0d413015..8e92869e9e912d158aaa29c62cb4b05d18874743 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1623,8 +1623,10 @@ ivas_error ivas_init_decoder( } ELSE { +#ifndef IVAS_FLOAT_FIXED /*TODO/observation : not hit by decoder tests*/ vbap_determine_gains( st_ivas->hVBAPdata, st_ivas->hLsSetupCustom->separate_ch_gains, 0, 0, 0 ); +#endif } } diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index bde5bff2351f834c3f358fd7c07c5950cf6cc4c6..2925fc64dd871a0f888760b392d03bae24fac228 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -242,25 +242,6 @@ void efap_determine_gains_fixed( * Amplitude Panning VBAP prototypes *----------------------------------------------------------------------------------*/ -ivas_error vbap_init_data( - VBAP_HANDLE *hVBAPdata, /* i/o: handle for VBAP data structure that will be initialized */ - const float *speaker_node_azi_deg, /* i : vector of speaker node azimuths (positive left) */ - const float *speaker_node_ele_deg, /* i : vector of speaker node elevations (positive up) */ - const int16_t num_speaker_nodes, /* i : number of speaker nodes in the set */ - const IVAS_FORMAT ivas_format /* i : IVAS format */ -); - -void vbap_free_data( - VBAP_HANDLE *hVBAPdata /* i/o: VBAP handle to be freed */ -); - -void vbap_determine_gains( - const VBAP_HANDLE hVBAPdata, /* i : VBAP structure */ - float *gains, /* o : gain vector for speaker nodes for given direction */ - const int16_t azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ - const int16_t ele_deg, /* i : elevation in degrees for panning direction (positive up) */ - const int16_t use_object_mode /* i : select between object mode panning and spatial mode panning */ -); #ifdef IVAS_FLOAT_FIXED ivas_error vbap_init_data_fx( VBAP_HANDLE *hVBAPdata, /* i/o: handle for VBAP data structure that will be initialized */ @@ -269,7 +250,6 @@ ivas_error vbap_init_data_fx( const Word16 num_speaker_nodes, /* i : number of speaker nodes in the set */ const IVAS_FORMAT ivas_format /* i : IVAS format */ ); - void vbap_determine_gains_fx( const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ Word32 *gains_fx, /* o : gain vector for loudspeakers for given direction */ @@ -280,6 +260,26 @@ void vbap_determine_gains_fx( void vbap_free_data_fx( VBAP_HANDLE *hVBAPdata /* i/o: VBAP handle to be freed */ ); +#else +ivas_error vbap_init_data( + VBAP_HANDLE *hVBAPdata, /* i/o: handle for VBAP data structure that will be initialized */ + const float *speaker_node_azi_deg, /* i : vector of speaker node azimuths (positive left) */ + const float *speaker_node_ele_deg, /* i : vector of speaker node elevations (positive up) */ + const int16_t num_speaker_nodes, /* i : number of speaker nodes in the set */ + const IVAS_FORMAT ivas_format /* i : IVAS format */ +); + +void vbap_determine_gains( + const VBAP_HANDLE hVBAPdata, /* i : VBAP structure */ + float *gains, /* o : gain vector for speaker nodes for given direction */ + const int16_t azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ + const int16_t ele_deg, /* i : elevation in degrees for panning direction (positive up) */ + const int16_t use_object_mode /* i : select between object mode panning and spatial mode panning */ +); + +void vbap_free_data( + VBAP_HANDLE *hVBAPdata /* i/o: VBAP handle to be freed */ +); #endif diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 7a26d9ea3679c838523aaee41f0dad84cb2be25c..cef2c9c67ed305ca4ad189784b7c06d703ae7967 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -600,12 +600,6 @@ typedef struct vbap_data_structure int16_t top_virtual_speaker_node_index; /* These indices can be negative */ int16_t bottom_virtual_speaker_node_index; int16_t back_virtual_speaker_node_index; - float *bottom_virtual_speaker_node_division_gains; - float *top_virtual_speaker_node_division_gains; - float *back_virtual_speaker_node_division_gains; - float *object_mode_bottom_virtual_speaker_node_division_gains; - float *object_mode_top_virtual_speaker_node_division_gains; - float *object_mode_back_virtual_speaker_node_division_gains; #ifdef IVAS_FLOAT_FIXED Word16 *bottom_virtual_speaker_node_division_gains_fx; Word16 *top_virtual_speaker_node_division_gains_fx; @@ -613,6 +607,13 @@ typedef struct vbap_data_structure Word16 *object_mode_bottom_virtual_speaker_node_division_gains_fx; Word16 *object_mode_top_virtual_speaker_node_division_gains_fx; Word16 *object_mode_back_virtual_speaker_node_division_gains_fx; +#else + float *bottom_virtual_speaker_node_division_gains; + float *top_virtual_speaker_node_division_gains; + float *back_virtual_speaker_node_division_gains; + float *object_mode_bottom_virtual_speaker_node_division_gains; + float *object_mode_top_virtual_speaker_node_division_gains; + float *object_mode_back_virtual_speaker_node_division_gains; #endif } VBAP_DATA, *VBAP_HANDLE; diff --git a/lib_rend/ivas_vbap.c b/lib_rend/ivas_vbap.c index fc8be403af3586bec778abef48cb91eea7148e09..4affe738462cb2b9b4a9db0847f26e9117b33c01 100644 --- a/lib_rend/ivas_vbap.c +++ b/lib_rend/ivas_vbap.c @@ -93,13 +93,14 @@ enum ConnectionClass typedef struct connection_option { - int16_t chA; - int16_t chB; - float arc; - float arc_weighted; + Word16 chA; + Word16 chB; #ifdef IVAS_FLOAT_FIXED Word32 arc_weighted_fx; Word32 arc_fx; +#else + float arc; + float arc_weighted; #endif } ConnectionOption; @@ -115,14 +116,15 @@ enum SpeakerNodeGroup /* Defines a single speaker node */ typedef struct vbap_speaker_node_structure { - float azi_deg; - float ele_deg; #ifdef IVAS_FLOAT_FIXED Word32 azi_deg_fx; Word32 ele_deg_fx; Word32 unit_vec_fx[3]; -#endif +#else + float azi_deg; + float ele_deg; float unit_vec[3]; +#endif enum SpeakerNodeGroup group; } VBAP_SPEAKER_NODE; @@ -132,32 +134,6 @@ typedef struct vbap_speaker_node_structure * Local function prototypes *-----------------------------------------------------------------------*/ -static uint8_t vector_matrix_multiply_3x3( const float *src_vector, float matrix[3][3], float *result ); - -static void init_speaker_node_direction_data( VBAP_SPEAKER_NODE *speaker_node_data, const float *speaker_node_azi_deg, const float *speaker_node_ele_deg, const int16_t num_speaker_nodes ); - -static int16_t determine_virtual_surface_triplets( const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *speaker_node_data, int16_t connections[][2], const int16_t max_num_connections, VBAP_VS_TRIPLET *triplets, int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS], enum SpeakerNodeGroup allowed_group ); - -static void determine_initial_search_indices( const int16_t num_triplets, const float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS], int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS] ); - -static ivas_error determine_connections( const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *speaker_node_data, int16_t connections[][2], const int16_t max_num_connections, int16_t *group1_count, int16_t *group2_start, int16_t *group2_count ); - -static void formulate_horizontal_connections( const VBAP_SPEAKER_NODE *speaker_node_data, const int16_t num_speaker_nodes, int16_t connections[][2], int16_t *connection_write_index ); - -static ivas_error get_half_sphere_connection_options( const VBAP_SPEAKER_NODE *speaker_node_data, const enum SpeakerNodeGroup group, const int16_t num_speaker_nodes, const int16_t num_non_crossing_planes, const float *non_crossing_plane_elevation_deg, ConnectionOption **connection_options_pr, int16_t *num_connection_options ); - -static ivas_error formulate_half_sphere_connections( const VBAP_SPEAKER_NODE *speaker_node_data, const int16_t num_speaker_nodes, const enum SpeakerNodeGroup group, int16_t connections[][2], int16_t *connection_write_index, const int16_t max_num_connections, const int16_t num_non_crossing_planes, const float *non_crossing_plane_elevation_deg ); - -static int16_t determine_non_crossing_planes( const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *node_data, float *non_crossing_plane_elevation_deg ); - -static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node( VBAP_HANDLE hVBAPdata, const float *speaker_node_azi_deg, const float *speaker_node_ele_deg, enum SpeakerNodeGroup group ); - -static int16_t determine_best_triplet_and_gains( VBAP_SEARCH_STRUCT *search_struct, const float panning_unit_vec[3], const int16_t azi_deg, float gains[3] ); - -static void determine_virtual_speaker_node_division_gains(const int16_t virtual_speaker_node_index, float *virtual_node_division_gains, int16_t connections[][2], const enum VirtualSpeakerNodeType type, const int16_t max_num_connections, const int16_t num_speaker_nodes, const int16_t use_object_mode); - -static void reorder_triplets(VBAP_VS_TRIPLET *triplets, const int16_t *target_order, const int16_t num_triplets); - #ifdef IVAS_FLOAT_FIXED static UWord8 vector_matrix_multiply_3x3_fx( const Word16 *src_vector, Word32 matrix[3][3], Word32 *result, Word16 q_matrix ); @@ -186,6 +162,32 @@ static Word16 determine_best_triplet_and_gains_fx( VBAP_SEARCH_STRUCT *search_st static void determine_virtual_speaker_node_division_gains_fx( const Word16 virtual_speaker_node_index, Word16 *virtual_node_division_gains_fx, Word16 *max_exp, int16_t connections[][2], const enum VirtualSpeakerNodeType type, const Word16 max_num_connections, const Word16 num_speaker_nodes, const Word16 use_object_mode ); static void reorder_triplets_fx( VBAP_VS_TRIPLET *triplets, const Word16 *target_order, const Word16 num_triplets ); +#else +static uint8_t vector_matrix_multiply_3x3(const float *src_vector, float matrix[3][3], float *result); + +static void init_speaker_node_direction_data(VBAP_SPEAKER_NODE *speaker_node_data, const float *speaker_node_azi_deg, const float *speaker_node_ele_deg, const int16_t num_speaker_nodes); + +static int16_t determine_virtual_surface_triplets(const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *speaker_node_data, int16_t connections[][2], const int16_t max_num_connections, VBAP_VS_TRIPLET *triplets, int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS], enum SpeakerNodeGroup allowed_group); + +static void determine_initial_search_indices(const int16_t num_triplets, const float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS], int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS]); + +static ivas_error determine_connections(const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *speaker_node_data, int16_t connections[][2], const int16_t max_num_connections, int16_t *group1_count, int16_t *group2_start, int16_t *group2_count); + +static void formulate_horizontal_connections(const VBAP_SPEAKER_NODE *speaker_node_data, const int16_t num_speaker_nodes, int16_t connections[][2], int16_t *connection_write_index); + +static ivas_error get_half_sphere_connection_options(const VBAP_SPEAKER_NODE *speaker_node_data, const enum SpeakerNodeGroup group, const int16_t num_speaker_nodes, const int16_t num_non_crossing_planes, const float *non_crossing_plane_elevation_deg, ConnectionOption **connection_options_pr, int16_t *num_connection_options); + +static ivas_error formulate_half_sphere_connections(const VBAP_SPEAKER_NODE *speaker_node_data, const int16_t num_speaker_nodes, const enum SpeakerNodeGroup group, int16_t connections[][2], int16_t *connection_write_index, const int16_t max_num_connections, const int16_t num_non_crossing_planes, const float *non_crossing_plane_elevation_deg); + +static int16_t determine_non_crossing_planes(const int16_t num_speaker_nodes, const VBAP_SPEAKER_NODE *node_data, float *non_crossing_plane_elevation_deg); + +static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node(VBAP_HANDLE hVBAPdata, const float *speaker_node_azi_deg, const float *speaker_node_ele_deg, enum SpeakerNodeGroup group); + +static int16_t determine_best_triplet_and_gains(VBAP_SEARCH_STRUCT *search_struct, const float panning_unit_vec[3], const int16_t azi_deg, float gains[3]); + +static void determine_virtual_speaker_node_division_gains(const int16_t virtual_speaker_node_index, float *virtual_node_division_gains, int16_t connections[][2], const enum VirtualSpeakerNodeType type, const int16_t max_num_connections, const int16_t num_speaker_nodes, const int16_t use_object_mode); + +static void reorder_triplets(VBAP_VS_TRIPLET *triplets, const int16_t *target_order, const int16_t num_triplets); #endif /*-------------------------------------------------------------------------* @@ -229,7 +231,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( GT_16(num_speaker_nodes , VBAP_MAX_NUM_SPEAKER_NODES) || LT_16(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(); @@ -265,15 +267,7 @@ ivas_error vbap_init_data_fx( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx = NULL; vbap->object_mode_top_virtual_speaker_node_division_gains_fx = NULL; vbap->object_mode_back_virtual_speaker_node_division_gains_fx = NULL; -#ifdef TRUE - /*Clean up float code*/ - vbap->bottom_virtual_speaker_node_division_gains = NULL; - vbap->top_virtual_speaker_node_division_gains = NULL; - vbap->back_virtual_speaker_node_division_gains = NULL; - vbap->object_mode_bottom_virtual_speaker_node_division_gains = NULL; - vbap->object_mode_top_virtual_speaker_node_division_gains = NULL; - vbap->object_mode_back_virtual_speaker_node_division_gains = NULL; -#endif + /* Check if the speaker node setup needs a virtual top or bottom node (function also increments vbap->num_speaker_nodes_internal when necessary) */ virtual_bottom_type = check_need_of_virtual_speaker_node_fx( vbap, speaker_node_azi_deg_fx, speaker_node_ele_deg_fx, SPEAKER_NODE_BOTTOM_HALF ); @@ -285,7 +279,7 @@ ivas_error vbap_init_data_fx( 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 ); test(); - IF( is_success && NE_16(virtual_bottom_type , NO_VIRTUAL_SPEAKER_NODE) ) + 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 ) { @@ -294,7 +288,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( EQ_16(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 ) { @@ -303,30 +297,11 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx != NULL; } - speaker_node_azi_deg_internal_fx[vbap->bottom_virtual_speaker_node_index] = float_to_fix( 0.0f, Q22 ); - speaker_node_ele_deg_internal_fx[vbap->bottom_virtual_speaker_node_index] = float_to_fix( -90.0f, Q22 ); -#ifdef TRUE - /*Clean up float code*/ - IF( ( vbap->bottom_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->bottom_virtual_speaker_node_division_gains, num_speaker_nodes ); - is_success &= vbap->bottom_virtual_speaker_node_division_gains != NULL; - - IF( ivas_format == MASA_ISM_FORMAT ) - { - IF( ( vbap->object_mode_bottom_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->object_mode_bottom_virtual_speaker_node_division_gains, num_speaker_nodes ); - is_success &= vbap->object_mode_bottom_virtual_speaker_node_division_gains != NULL; - } -#endif + speaker_node_azi_deg_internal_fx[vbap->bottom_virtual_speaker_node_index] = 0; + speaker_node_ele_deg_internal_fx[vbap->bottom_virtual_speaker_node_index] = -377487360; /*-90.0f in Q22*/ } test(); - IF( is_success && NE_16(virtual_top_type , NO_VIRTUAL_SPEAKER_NODE) ) + 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 ) { @@ -342,7 +317,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( EQ_16(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 ) { @@ -351,30 +326,11 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->object_mode_top_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->object_mode_top_virtual_speaker_node_division_gains_fx != NULL; } - speaker_node_azi_deg_internal_fx[vbap->top_virtual_speaker_node_index] = float_to_fix( 0.0f, 22 ); - 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 ) - { - 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( ( 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" ) ); - } - set_zero( vbap->object_mode_top_virtual_speaker_node_division_gains, num_speaker_nodes ); - is_success &= vbap->object_mode_top_virtual_speaker_node_division_gains != NULL; - } + speaker_node_azi_deg_internal_fx[vbap->top_virtual_speaker_node_index] = 0; + speaker_node_ele_deg_internal_fx[vbap->top_virtual_speaker_node_index] = 377487360; /*90.0f in Q22*/ } -#endif test(); - IF( is_success && NE_16(virtual_back_type , NO_VIRTUAL_SPEAKER_NODE) ) + 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 ) { @@ -383,7 +339,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( EQ_16(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 ) { @@ -392,30 +348,11 @@ ivas_error vbap_init_data_fx( set16_fx( vbap->object_mode_back_virtual_speaker_node_division_gains_fx, 0, num_speaker_nodes ); is_success &= vbap->object_mode_back_virtual_speaker_node_division_gains_fx != NULL; } - speaker_node_azi_deg_internal_fx[vbap->back_virtual_speaker_node_index] = float_to_fix( 180.0f, Q22 ); - 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 ) - { - 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( ( 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" ) ); - } - set_zero( vbap->object_mode_back_virtual_speaker_node_division_gains, num_speaker_nodes ); - is_success &= vbap->object_mode_back_virtual_speaker_node_division_gains != NULL; - } -#endif + speaker_node_azi_deg_internal_fx[vbap->back_virtual_speaker_node_index] = 754974720; + speaker_node_ele_deg_internal_fx[vbap->back_virtual_speaker_node_index] = 0; } init_speaker_node_direction_data_fx( speaker_node_data, speaker_node_azi_deg_internal_fx, speaker_node_ele_deg_internal_fx, vbap->num_speaker_nodes_internal ); -#ifdef TRUE +#ifdef TRUE0 /*TODO: Clean up of update float buffers*/ for ( int ch = 0; ch < vbap->num_speaker_nodes_internal; ch++ ) { @@ -428,7 +365,7 @@ ivas_error vbap_init_data_fx( #endif /* Allocate and determine node-node connections */ - max_num_connections = mult0(( sub(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; @@ -459,16 +396,16 @@ ivas_error vbap_init_data_fx( move16(); BREAK; case SPEAKER_NODE_BOTTOM_HALF: - speaker_nodes_group1_internal = add(speaker_nodes_group1_internal, 1); + speaker_nodes_group1_internal = add( speaker_nodes_group1_internal, 1 ); BREAK; case SPEAKER_NODE_TOP_HALF: - speaker_nodes_group2_internal = add(speaker_nodes_group2_internal, 1); + speaker_nodes_group2_internal = add( speaker_nodes_group2_internal, 1 ); BREAK; case SPEAKER_NODE_HORIZONTAL: case SPEAKER_NODE_BACK: - 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); + 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; } } @@ -479,7 +416,7 @@ ivas_error vbap_init_data_fx( } is_success &= vbap->search_struct[0].triplets != NULL; - IF( GT_16(speaker_nodes_group2_internal , 0 ) ) + IF( GT_16( speaker_nodes_group2_internal, 0 ) ) { vbap->num_search_structs = 2; move16(); @@ -499,7 +436,7 @@ ivas_error vbap_init_data_fx( IF( is_success ) { - IF( EQ_16(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 ); @@ -515,92 +452,30 @@ ivas_error vbap_init_data_fx( /* Determine how the virtual node gains should be distributed to real nodes, if necessary (checked within function). */ IF( is_success ) { - Word16 max_exp = 31, i; + Word16 max_exp = 31; determine_virtual_speaker_node_division_gains_fx( vbap->top_virtual_speaker_node_index, vbap->top_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_top_type, max_num_connections, num_speaker_nodes, 0 ); -#ifdef TRUE - IF( vbap->top_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->top_virtual_speaker_node_division_gains[i] = me2f_16( vbap->top_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif determine_virtual_speaker_node_division_gains_fx( vbap->bottom_virtual_speaker_node_index, vbap->bottom_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_bottom_type, max_num_connections, num_speaker_nodes, 0 ); -#ifdef TRUE - IF( vbap->bottom_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->bottom_virtual_speaker_node_division_gains[i] = me2f_16( vbap->bottom_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif determine_virtual_speaker_node_division_gains_fx( vbap->back_virtual_speaker_node_index, vbap->back_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_back_type, max_num_connections, num_speaker_nodes, 0 ); -#ifdef TRUE - IF( vbap->back_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->back_virtual_speaker_node_division_gains[i] = me2f_16( vbap->back_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif IF( ivas_format == MASA_ISM_FORMAT ) { determine_virtual_speaker_node_division_gains_fx( vbap->top_virtual_speaker_node_index, vbap->object_mode_top_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_top_type == NO_VIRTUAL_SPEAKER_NODE ? NO_VIRTUAL_SPEAKER_NODE : VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY, max_num_connections, num_speaker_nodes, 1 ); - -#ifdef TRUE - IF( vbap->object_mode_top_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->object_mode_top_virtual_speaker_node_division_gains[i] = me2f_16( vbap->object_mode_top_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif determine_virtual_speaker_node_division_gains_fx( vbap->bottom_virtual_speaker_node_index, vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_bottom_type == NO_VIRTUAL_SPEAKER_NODE ? NO_VIRTUAL_SPEAKER_NODE : VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY, max_num_connections, num_speaker_nodes, 1 ); -#ifdef TRUE - IF( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->object_mode_bottom_virtual_speaker_node_division_gains[i] = me2f_16( vbap->object_mode_bottom_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif determine_virtual_speaker_node_division_gains_fx( vbap->back_virtual_speaker_node_index, vbap->object_mode_back_virtual_speaker_node_division_gains_fx, &max_exp, connections, virtual_back_type == NO_VIRTUAL_SPEAKER_NODE ? NO_VIRTUAL_SPEAKER_NODE : VIRTUAL_SPEAKER_NODE_DISTRIBUTE_ENERGY, max_num_connections, num_speaker_nodes, 1 ); -#ifdef TRUE - IF( vbap->object_mode_back_virtual_speaker_node_division_gains_fx != NULL ) - { - FOR( i = 0; i < num_speaker_nodes; i++ ) - { - vbap->object_mode_back_virtual_speaker_node_division_gains[i] = me2f_16( vbap->object_mode_back_virtual_speaker_node_division_gains_fx[i], max_exp ); - } - } -#endif } } - pop_wmops(); - IF( is_success ) { *hVBAPdata = vbap; } ELSE { -#ifdef IVAS_FLOAT_FIXED - vbap_free_data_fx(&vbap); -#else - vbap_free_data( &vbap ); -#endif + vbap_free_data_fx( &vbap ); } return IVAS_ERR_OK; } -#endif - +#else ivas_error vbap_init_data( VBAP_HANDLE *hVBAPdata, /* i/o: handle for VBAP data structure that will be initialized */ const float *speaker_node_azi_deg, /* i : vector of speaker node azimuths (positive left) */ @@ -851,6 +726,7 @@ ivas_error vbap_init_data( return IVAS_ERR_OK; } +#endif /*-------------------------------------------------------------------------* * vbap_free_data() * @@ -867,40 +743,6 @@ void vbap_free_data_fx( return; } - IF( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains ); - } - IF( ( *hVBAPdata )->top_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->top_virtual_speaker_node_division_gains ); - } - IF( ( *hVBAPdata )->back_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->back_virtual_speaker_node_division_gains ); - } - IF( ( *hVBAPdata )->object_mode_bottom_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->object_mode_bottom_virtual_speaker_node_division_gains ); - } - IF( ( *hVBAPdata )->object_mode_top_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->object_mode_top_virtual_speaker_node_division_gains ); - } - IF( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains != NULL ) - { - free( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains ); - } - - IF( ( *hVBAPdata )->search_struct[0].triplets != NULL ) - { - free( ( *hVBAPdata )->search_struct[0].triplets ); - } - IF( ( *hVBAPdata )->num_search_structs == 2 && ( *hVBAPdata )->search_struct[1].triplets != NULL ) - { - free( ( *hVBAPdata )->search_struct[1].triplets ); - } -#ifdef IVAS_FLOAT_FIXED IF( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains_fx != NULL ) { free( ( *hVBAPdata )->bottom_virtual_speaker_node_division_gains_fx ); @@ -925,14 +767,12 @@ void vbap_free_data_fx( { free( ( *hVBAPdata )->object_mode_back_virtual_speaker_node_division_gains_fx ); } -#endif free( *hVBAPdata ); *hVBAPdata = NULL; return; } -#endif - +#else void vbap_free_data( VBAP_HANDLE *hVBAPdata /* i/o: VBAP handle to be freed */ ) @@ -980,134 +820,142 @@ void vbap_free_data( return; } - +#endif /*-------------------------------------------------------------------------* * vbap_determine_gains() * * Obtain panning gains for all speaker nodes based on the given direction *-------------------------------------------------------------------------*/ - -void vbap_determine_gains( - const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ - float *gains, /* o : gain vector for loudspeakers for given direction */ - const int16_t azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ - const int16_t ele_deg, /* i : elevation in degrees for panning direction (positive up) */ - const int16_t use_object_mode /* i : select between object mode panning and spatial mode panning */ +#ifdef IVAS_FLOAT_FIXED +void vbap_determine_gains_fx( + const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ + Word32 *gains_fx, /* o : gain vector for loudspeakers for given direction */ + const Word16 azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ + const Word16 ele_deg, /* i : elevation in degrees for panning direction (positive up) */ + const Word16 use_object_mode /* i : select between object mode panning and spatial mode panning */ ) { /* This function formulates gains for the given angle. The triplet-selection has been pre-formulated. */ - int16_t ch, ch2; - int16_t triplet_ch; - int16_t triplet_index; - float panning_unit_vec[3]; - float gain_triplet[3]; - float norm_value; - float gain_ene; - float azi_rad; - float ele_rad; - float azi_temp; - float ele_temp; - int16_t num_speaker_nodes; - int16_t bottom_virtual_speaker_node_index; - int16_t top_virtual_speaker_node_index; - int16_t back_virtual_speaker_node_index; + Word16 ch, ch2; + Word16 triplet_ch; + Word16 triplet_index; + Word16 panning_unit_vec_fx[3]; + Word32 gain_triplet_fx[3]; + Word32 norm_value_fx; + Word32 gain_ene_fx; + Word32 azi_norm; + Word32 ele_norm; + Word32 azi_temp_fx; + Word32 ele_temp_fx; + Word16 num_speaker_nodes; + Word16 bottom_virtual_speaker_node_index; + Word16 top_virtual_speaker_node_index; + Word16 back_virtual_speaker_node_index; VBAP_VS_TRIPLET *selected_triplet; - float *bottom_virtual_speaker_node_division_gains; - float *top_virtual_speaker_node_division_gains; - float *back_virtual_speaker_node_division_gains; + Word16 *bottom_virtual_speaker_node_division_gains_fx; + Word16 *top_virtual_speaker_node_division_gains_fx; + Word16 *back_virtual_speaker_node_division_gains_fx; push_wmops( "vbap_gains" ); num_speaker_nodes = hVBAPdata->num_speaker_nodes; + move16(); bottom_virtual_speaker_node_index = hVBAPdata->bottom_virtual_speaker_node_index; + move16(); top_virtual_speaker_node_index = hVBAPdata->top_virtual_speaker_node_index; + move16(); back_virtual_speaker_node_index = hVBAPdata->back_virtual_speaker_node_index; - if ( use_object_mode ) + move16(); + + IF( use_object_mode ) { - bottom_virtual_speaker_node_division_gains = hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains; - top_virtual_speaker_node_division_gains = hVBAPdata->object_mode_top_virtual_speaker_node_division_gains; - back_virtual_speaker_node_division_gains = hVBAPdata->object_mode_back_virtual_speaker_node_division_gains; + bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains_fx; + top_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_top_virtual_speaker_node_division_gains_fx; + back_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_back_virtual_speaker_node_division_gains_fx; } - else + ELSE { - bottom_virtual_speaker_node_division_gains = hVBAPdata->bottom_virtual_speaker_node_division_gains; - top_virtual_speaker_node_division_gains = hVBAPdata->top_virtual_speaker_node_division_gains; - back_virtual_speaker_node_division_gains = hVBAPdata->back_virtual_speaker_node_division_gains; + bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->bottom_virtual_speaker_node_division_gains_fx; + top_virtual_speaker_node_division_gains_fx = hVBAPdata->top_virtual_speaker_node_division_gains_fx; + back_virtual_speaker_node_division_gains_fx = hVBAPdata->back_virtual_speaker_node_division_gains_fx; } - panning_wrap_angles( (float) azi_deg, (float) ele_deg, &azi_temp, &ele_temp ); - azi_rad = azi_temp * PI_OVER_180; - ele_rad = ele_temp * PI_OVER_180; + panning_wrap_angles_fixed( (Word32) azi_deg * ( 1 << 22 ), (Word32) ele_deg * ( 1 << 22 ), &azi_temp_fx, &ele_temp_fx ); + azi_norm = L_shr( Mpy_32_16_1( azi_temp_fx, 91 ), 7 ); + ele_norm = L_shr( Mpy_32_16_1( ele_temp_fx, 91 ), 7 ); - panning_unit_vec[0] = cosf( azi_rad ) * cosf( ele_rad ); - panning_unit_vec[1] = sinf( azi_rad ) * cosf( ele_rad ); - panning_unit_vec[2] = sinf( ele_rad ); + panning_unit_vec_fx[0] = mult( getCosWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm ) ); + panning_unit_vec_fx[1] = mult( getSineWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm ) ); + panning_unit_vec_fx[2] = getSineWord16R2( (Word16) ele_norm ); /* Find the best VS triplet and speaker node gains for the panning direction using the prepared search structures. */ - if ( hVBAPdata->num_search_structs == 2 && ele_deg > 0 ) + IF( EQ_16( hVBAPdata->num_search_structs, 2 ) && GT_16( ele_deg, 0 ) ) { - triplet_index = determine_best_triplet_and_gains( &( hVBAPdata->search_struct[1] ), panning_unit_vec, azi_deg, gain_triplet ); + triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[1] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); + move16(); selected_triplet = &hVBAPdata->search_struct[1].triplets[triplet_index]; } - else + ELSE { - triplet_index = determine_best_triplet_and_gains( &( hVBAPdata->search_struct[0] ), panning_unit_vec, azi_deg, gain_triplet ); + triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[0] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); + move16(); selected_triplet = &hVBAPdata->search_struct[0].triplets[triplet_index]; } /* Normalize to unit energy */ - gain_ene = 1e-12f; /* Add small value to avoid divide by zero. */ - for ( ch = 0; ch < 3; ch++ ) + gain_ene_fx = 1; /* Add small value to avoid divide by zero. */ + move32(); + FOR( ch = 0; ch < 3; ch++ ) { - gain_ene += gain_triplet[ch] * gain_triplet[ch]; + gain_ene_fx = L_add( gain_ene_fx, Mpy_32_32( gain_triplet_fx[ch], gain_triplet_fx[ch] ) ); // 2q -31 = 27 } - norm_value = inv_sqrt( gain_ene ); + norm_value_fx = Isqrt( L_shr( gain_ene_fx, 1 ) ); // q = 47 - hVBAPdata->search_struct[0].triplets->q_inverse_matrix = 18 - for ( ch = 0; ch < 3; ch++ ) + FOR( ch = 0; ch < 3; ch++ ) { - gain_triplet[ch] *= norm_value; + gain_triplet_fx[ch] = Mpy_32_32( gain_triplet_fx[ch], norm_value_fx ); // Q16 /* Sanity check for rounding issues */ - if ( gain_triplet[ch] < 0.0f ) + IF( LT_32( gain_triplet_fx[ch], 0 ) ) { - gain_triplet[ch] = 0.0f; + gain_triplet_fx[ch] = 0; } } /* Flush gain target */ - set_zero( gains, num_speaker_nodes ); + set32_fx( gains_fx, 0, num_speaker_nodes ); /* Map gain triplet (internal speaker node configuration) to speaker node output (actual speaker node configuration) */ - for ( ch = 0; ch < 3; ch++ ) + FOR( ch = 0; ch < 3; ch++ ) { triplet_ch = selected_triplet->speaker_node[ch]; - if ( triplet_ch == bottom_virtual_speaker_node_index ) + IF( EQ_16( triplet_ch, bottom_virtual_speaker_node_index ) ) { - for ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + FOR( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) { - gains[ch2] += bottom_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; + gains_fx[ch2] = L_add( gains_fx[ch2], L_shl( Mpy_32_16_1( gain_triplet_fx[ch], bottom_virtual_speaker_node_division_gains_fx[ch2] ), 13 ) ); // Q29 } } - else if ( triplet_ch == top_virtual_speaker_node_index ) + ELSE IF( EQ_16( triplet_ch, top_virtual_speaker_node_index ) ) { - for ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + FOR( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) { - gains[ch2] += top_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; + gains_fx[ch2] = L_add( gains_fx[ch2], L_shl( Mpy_32_16_1( gain_triplet_fx[ch], top_virtual_speaker_node_division_gains_fx[ch2] ), 13 ) ); // Q29 } } - else if ( triplet_ch == back_virtual_speaker_node_index ) + ELSE IF( EQ_16( triplet_ch, back_virtual_speaker_node_index ) ) { - for ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + FOR( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) { - gains[ch2] += back_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; + gains_fx[ch2] = L_add( gains_fx[ch2], L_shl( Mpy_32_16_1( gain_triplet_fx[ch], back_virtual_speaker_node_division_gains_fx[ch2] ), 13 ) ); // Q29 } } - else + ELSE { - gains[triplet_ch] += gain_triplet[ch]; + gains_fx[triplet_ch] = L_add( gains_fx[triplet_ch], L_shl( gain_triplet_fx[ch], 13 ) ); // Q29 } } @@ -1115,136 +963,127 @@ void vbap_determine_gains( return; } - -#ifdef IVAS_FLOAT_FIXED -void vbap_determine_gains_fx( +#else +void vbap_determine_gains( const VBAP_HANDLE hVBAPdata, /* i : prepared VBAP structure */ - Word32 *gains_fx, /* o : gain vector for loudspeakers for given direction */ - const Word16 azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ - const Word16 ele_deg, /* i : elevation in degrees for panning direction (positive up) */ - const Word16 use_object_mode /* i : select between object mode panning and spatial mode panning */ + float *gains, /* o : gain vector for loudspeakers for given direction */ + const int16_t azi_deg, /* i : azimuth in degrees for panning direction (positive left) */ + const int16_t ele_deg, /* i : elevation in degrees for panning direction (positive up) */ + const int16_t use_object_mode /* i : select between object mode panning and spatial mode panning */ ) { /* This function formulates gains for the given angle. The triplet-selection has been pre-formulated. */ - Word16 ch, ch2; - Word16 triplet_ch; - Word16 triplet_index; - Word16 panning_unit_vec_fx[3]; - Word32 gain_triplet_fx[3]; - Word32 norm_value_fx; - Word32 gain_ene_fx; - Word32 azi_norm; - Word32 ele_norm; - Word32 azi_temp_fx; - Word32 ele_temp_fx; - Word16 num_speaker_nodes; - Word16 bottom_virtual_speaker_node_index; - Word16 top_virtual_speaker_node_index; - Word16 back_virtual_speaker_node_index; + int16_t ch, ch2; + int16_t triplet_ch; + int16_t triplet_index; + float panning_unit_vec[3]; + float gain_triplet[3]; + float norm_value; + float gain_ene; + float azi_rad; + float ele_rad; + float azi_temp; + float ele_temp; + int16_t num_speaker_nodes; + int16_t bottom_virtual_speaker_node_index; + int16_t top_virtual_speaker_node_index; + int16_t back_virtual_speaker_node_index; VBAP_VS_TRIPLET *selected_triplet; - Word16 *bottom_virtual_speaker_node_division_gains_fx; - Word16 *top_virtual_speaker_node_division_gains_fx; - Word16 *back_virtual_speaker_node_division_gains_fx; + float *bottom_virtual_speaker_node_division_gains; + float *top_virtual_speaker_node_division_gains; + float *back_virtual_speaker_node_division_gains; - push_wmops( "vbap_gains" ); + push_wmops("vbap_gains"); num_speaker_nodes = hVBAPdata->num_speaker_nodes; - move16(); bottom_virtual_speaker_node_index = hVBAPdata->bottom_virtual_speaker_node_index; - move16(); top_virtual_speaker_node_index = hVBAPdata->top_virtual_speaker_node_index; - move16(); back_virtual_speaker_node_index = hVBAPdata->back_virtual_speaker_node_index; - move16(); - - IF ( use_object_mode ) + if (use_object_mode) { - bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains_fx; - top_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_top_virtual_speaker_node_division_gains_fx; - back_virtual_speaker_node_division_gains_fx = hVBAPdata->object_mode_back_virtual_speaker_node_division_gains_fx; + bottom_virtual_speaker_node_division_gains = hVBAPdata->object_mode_bottom_virtual_speaker_node_division_gains; + top_virtual_speaker_node_division_gains = hVBAPdata->object_mode_top_virtual_speaker_node_division_gains; + back_virtual_speaker_node_division_gains = hVBAPdata->object_mode_back_virtual_speaker_node_division_gains; } - ELSE + else { - bottom_virtual_speaker_node_division_gains_fx = hVBAPdata->bottom_virtual_speaker_node_division_gains_fx; - top_virtual_speaker_node_division_gains_fx = hVBAPdata->top_virtual_speaker_node_division_gains_fx; - back_virtual_speaker_node_division_gains_fx = hVBAPdata->back_virtual_speaker_node_division_gains_fx; + bottom_virtual_speaker_node_division_gains = hVBAPdata->bottom_virtual_speaker_node_division_gains; + top_virtual_speaker_node_division_gains = hVBAPdata->top_virtual_speaker_node_division_gains; + back_virtual_speaker_node_division_gains = hVBAPdata->back_virtual_speaker_node_division_gains; } - panning_wrap_angles_fixed( (Word32)azi_deg * (1 << 22), (Word32)ele_deg * (1<<22), &azi_temp_fx, &ele_temp_fx ); - azi_norm = L_shr(Mpy_32_16_1(azi_temp_fx, 91), 7); - ele_norm = L_shr(Mpy_32_16_1(ele_temp_fx, 91), 7); + panning_wrap_angles((float)azi_deg, (float)ele_deg, &azi_temp, &ele_temp); + azi_rad = azi_temp * PI_OVER_180; + ele_rad = ele_temp * PI_OVER_180; - panning_unit_vec_fx[0] = mult(getCosWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm )); - panning_unit_vec_fx[1] = mult(getSineWord16R2( (Word16) azi_norm ), getCosWord16R2( (Word16) ele_norm )); - panning_unit_vec_fx[2] = getSineWord16R2( (Word16) ele_norm ); + panning_unit_vec[0] = cosf(azi_rad) * cosf(ele_rad); + panning_unit_vec[1] = sinf(azi_rad) * cosf(ele_rad); + panning_unit_vec[2] = sinf(ele_rad); /* Find the best VS triplet and speaker node gains for the panning direction using the prepared search structures. */ - IF ( EQ_16(hVBAPdata->num_search_structs, 2) && GT_16(ele_deg, 0) ) + if (hVBAPdata->num_search_structs == 2 && ele_deg > 0) { - triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[1] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); - move16(); + triplet_index = determine_best_triplet_and_gains(&(hVBAPdata->search_struct[1]), panning_unit_vec, azi_deg, gain_triplet); selected_triplet = &hVBAPdata->search_struct[1].triplets[triplet_index]; } - ELSE + else { - triplet_index = determine_best_triplet_and_gains_fx( &( hVBAPdata->search_struct[0] ), panning_unit_vec_fx, azi_deg, gain_triplet_fx ); - move16(); + triplet_index = determine_best_triplet_and_gains(&(hVBAPdata->search_struct[0]), panning_unit_vec, azi_deg, gain_triplet); selected_triplet = &hVBAPdata->search_struct[0].triplets[triplet_index]; } /* Normalize to unit energy */ - gain_ene_fx = 1; /* Add small value to avoid divide by zero. */ - move32(); - FOR ( ch = 0; ch < 3; ch++ ) + gain_ene = 1e-12f; /* Add small value to avoid divide by zero. */ + for (ch = 0; ch < 3; ch++) { - gain_ene_fx = L_add(gain_ene_fx, Mpy_32_32(gain_triplet_fx[ch], gain_triplet_fx[ch])); // 2q -31 = 27 + gain_ene += gain_triplet[ch] * gain_triplet[ch]; } - norm_value_fx = Isqrt( L_shr(gain_ene_fx, 1) ); // q = 47 - hVBAPdata->search_struct[0].triplets->q_inverse_matrix = 18 + norm_value = inv_sqrt(gain_ene); - FOR ( ch = 0; ch < 3; ch++ ) + for (ch = 0; ch < 3; ch++) { - gain_triplet_fx[ch] = Mpy_32_32(gain_triplet_fx[ch], norm_value_fx); // Q16 + gain_triplet[ch] *= norm_value; /* Sanity check for rounding issues */ - IF ( LT_32(gain_triplet_fx[ch], 0) ) + if (gain_triplet[ch] < 0.0f) { - gain_triplet_fx[ch] = 0; + gain_triplet[ch] = 0.0f; } } /* Flush gain target */ - set32_fx( gains_fx, 0, num_speaker_nodes ); + set_zero(gains, num_speaker_nodes); /* Map gain triplet (internal speaker node configuration) to speaker node output (actual speaker node configuration) */ - FOR ( ch = 0; ch < 3; ch++ ) + for (ch = 0; ch < 3; ch++) { triplet_ch = selected_triplet->speaker_node[ch]; - IF ( EQ_16(triplet_ch, bottom_virtual_speaker_node_index) ) + if (triplet_ch == bottom_virtual_speaker_node_index) { - FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + for (ch2 = 0; ch2 < num_speaker_nodes; ch2++) { - gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_16_1(gain_triplet_fx[ch] , bottom_virtual_speaker_node_division_gains_fx[ch2]), 13)); // Q29 + gains[ch2] += bottom_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; } } - ELSE IF ( EQ_16(triplet_ch, top_virtual_speaker_node_index) ) + else if (triplet_ch == top_virtual_speaker_node_index) { - FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + for (ch2 = 0; ch2 < num_speaker_nodes; ch2++) { - gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_16_1(gain_triplet_fx[ch] , top_virtual_speaker_node_division_gains_fx[ch2]), 13)); // Q29 + gains[ch2] += top_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; } } - ELSE IF ( EQ_16(triplet_ch, back_virtual_speaker_node_index) ) + else if (triplet_ch == back_virtual_speaker_node_index) { - FOR ( ch2 = 0; ch2 < num_speaker_nodes; ch2++ ) + for (ch2 = 0; ch2 < num_speaker_nodes; ch2++) { - gains_fx[ch2] = L_add(gains_fx[ch2], L_shl(Mpy_32_16_1(gain_triplet_fx[ch] , back_virtual_speaker_node_division_gains_fx[ch2] ), 13)); // Q29 + gains[ch2] += back_virtual_speaker_node_division_gains[ch2] * gain_triplet[ch]; } } - ELSE + else { - gains_fx[triplet_ch] = L_add(gains_fx[triplet_ch], L_shl(gain_triplet_fx[ch], 13)); // Q29 + gains[triplet_ch] += gain_triplet[ch]; } } @@ -1280,8 +1119,7 @@ static void vbap_crossp_fx( return; } -#endif - +#else static void vbap_crossp( const float *vec1, /* i : input vector 1 */ const float *vec2, /* i : input vector 2 */ @@ -1294,6 +1132,7 @@ static void vbap_crossp( return; } +#endif /*-------------------------------------------------------------------------* * vector_matrix_multiply_3x3() @@ -1301,42 +1140,6 @@ static void vbap_crossp( * 3-by-3 vector multiply with matrix *-------------------------------------------------------------------------*/ -/*! r: Status result if triplet is usable for panning. Allows early exit. */ -static uint8_t vector_matrix_multiply_3x3( - const float *src_vector, /* i : input vector */ - float matrix[3][3], /* i : input matrix */ - float *result /* o : output vector */ -) -{ - result[0] = src_vector[0] * matrix[0][0]; - result[0] += src_vector[1] * matrix[1][0]; - result[0] += src_vector[2] * matrix[2][0]; - - if ( result[0] < -0.01f ) - { - return 0; - } - - result[1] = src_vector[0] * matrix[0][1]; - result[1] += src_vector[1] * matrix[1][1]; - result[1] += src_vector[2] * matrix[2][1]; - - if ( result[1] < -0.01f ) - { - return 0; - } - - result[2] = src_vector[0] * matrix[0][2]; - result[2] += src_vector[1] * matrix[1][2]; - result[2] += src_vector[2] * matrix[2][2]; - - if ( result[2] < -0.01f ) - { - return 0; - } - - return 1; -} #ifdef IVAS_FLOAT_FIXED /*! r: Status result if triplet is usable for panning. Allows early exit. */ @@ -1410,91 +1213,53 @@ static uint8_t vector_matrix_multiply_3x3_32_fx( return 1; } -#endif -/*----------------------------------------------------------------------------------------------* - * determine_best_triplet_and_gains() - * - * Determine the best speaker node triplet and associated gains for panning to defined direction - *----------------------------------------------------------------------------------------------*/ - -/*! r: triplet id */ -static int16_t determine_best_triplet_and_gains( - VBAP_SEARCH_STRUCT *search_struct, /* i : VBAP search struct */ - const float panning_unit_vec[3], /* i : panning unit vector */ - const int16_t azi_deg, /* i : panning azimuth */ - float gains[3] /* o : panning gains */ +#else + /*! r: Status result if triplet is usable for panning. Allows early exit. */ +static uint8_t vector_matrix_multiply_3x3( + const float *src_vector, /* i : input vector */ + float matrix[3][3], /* i : input matrix */ + float *result /* o : output vector */ ) { - int16_t i, tr, k; - uint8_t triplet_ok; - int16_t best_triplet; - float best_min_gain; - float min_gain_this; - float unnormalized_gains[3]; - int16_t sector; - int16_t first_triplet; - int16_t jump; - int16_t num_triplets; - - num_triplets = search_struct->num_triplets; - best_min_gain = -999.9f; - best_triplet = 0; - set_zero( gains, 3 ); + result[0] = src_vector[0] * matrix[0][0]; + result[0] += src_vector[1] * matrix[1][0]; + result[0] += src_vector[2] * matrix[2][0]; - /* Determine the correct search sector for that target panning direction using an optimized algorithm for - * the chosen four sectors. */ - if ( abs( azi_deg ) > 90 ) + if (result[0] < -0.01f) { - sector = azi_deg < 0 ? 2 : 1; + return 0; } - else + + result[1] = src_vector[0] * matrix[0][1]; + result[1] += src_vector[1] * matrix[1][1]; + result[1] += src_vector[2] * matrix[2][1]; + + if (result[1] < -0.01f) { - sector = azi_deg < 0 ? 3 : 0; + return 0; } - first_triplet = search_struct->initial_search_indices[sector]; - tr = first_triplet; - jump = 1; - for ( i = 0; i < num_triplets; i++ ) + result[2] = src_vector[0] * matrix[0][2]; + result[2] += src_vector[1] * matrix[1][2]; + result[2] += src_vector[2] * matrix[2][2]; + + if (result[2] < -0.01f) { - triplet_ok = vector_matrix_multiply_3x3( panning_unit_vec, search_struct->triplets[tr].inverse_matrix, unnormalized_gains ); - if ( triplet_ok ) - { - min_gain_this = min( ( min( unnormalized_gains[0], unnormalized_gains[1] ) ), unnormalized_gains[2] ); + return 0; + } - if ( min_gain_this > best_min_gain ) - { - best_min_gain = min_gain_this; - best_triplet = tr; - for ( k = 0; k < 3; k++ ) - { - gains[k] = unnormalized_gains[k]; - } - if ( !( best_min_gain < 0.00f ) ) - { - return best_triplet; - } - } - } - tr = first_triplet + jump; - if ( tr < 0 ) - { - tr += num_triplets; - } - else if ( tr >= num_triplets ) - { - tr -= num_triplets; - } + return 1; +} - jump *= -1; - if ( jump > 0 ) - { - jump += 1; - } - } +#endif +/*----------------------------------------------------------------------------------------------* + * determine_best_triplet_and_gains() + * + * Determine the best speaker node triplet and associated gains for panning to defined direction + *----------------------------------------------------------------------------------------------*/ + +/*! r: triplet id */ - return best_triplet; -} #ifdef IVAS_FLOAT_FIXED static Word16 determine_best_triplet_and_gains_fx( @@ -1586,6 +1351,84 @@ static Word16 determine_best_triplet_and_gains_fx( return best_triplet; } +#else +static int16_t determine_best_triplet_and_gains( + VBAP_SEARCH_STRUCT *search_struct, /* i : VBAP search struct */ + const float panning_unit_vec[3], /* i : panning unit vector */ + const int16_t azi_deg, /* i : panning azimuth */ + float gains[3] /* o : panning gains */ +) +{ + int16_t i, tr, k; + uint8_t triplet_ok; + int16_t best_triplet; + float best_min_gain; + float min_gain_this; + float unnormalized_gains[3]; + int16_t sector; + int16_t first_triplet; + int16_t jump; + int16_t num_triplets; + + num_triplets = search_struct->num_triplets; + best_min_gain = -999.9f; + best_triplet = 0; + set_zero(gains, 3); + + /* Determine the correct search sector for that target panning direction using an optimized algorithm for + * the chosen four sectors. */ + if (abs(azi_deg) > 90) + { + sector = azi_deg < 0 ? 2 : 1; + } + else + { + sector = azi_deg < 0 ? 3 : 0; + } + first_triplet = search_struct->initial_search_indices[sector]; + + tr = first_triplet; + jump = 1; + for (i = 0; i < num_triplets; i++) + { + triplet_ok = vector_matrix_multiply_3x3(panning_unit_vec, search_struct->triplets[tr].inverse_matrix, unnormalized_gains); + if (triplet_ok) + { + min_gain_this = min((min(unnormalized_gains[0], unnormalized_gains[1])), unnormalized_gains[2]); + + if (min_gain_this > best_min_gain) + { + best_min_gain = min_gain_this; + best_triplet = tr; + for (k = 0; k < 3; k++) + { + gains[k] = unnormalized_gains[k]; + } + if (!(best_min_gain < 0.00f)) + { + return best_triplet; + } + } + } + tr = first_triplet + jump; + if (tr < 0) + { + tr += num_triplets; + } + else if (tr >= num_triplets) + { + tr -= num_triplets; + } + + jump *= -1; + if (jump > 0) + { + jump += 1; + } + } + + return best_triplet; +} #endif /*-------------------------------------------------------------------------* * determine_virtual_speaker_node_division_gains() @@ -1704,8 +1547,7 @@ static void determine_virtual_speaker_node_division_gains_fx( return; } -#endif - +#else static void determine_virtual_speaker_node_division_gains( const int16_t virtual_speaker_node_index, /* i : virtual speaker node index */ float *virtual_node_division_gains, /* o : virtual speaker node division gains */ @@ -1765,6 +1607,7 @@ static void determine_virtual_speaker_node_division_gains( return; } +#endif /*-------------------------------------------------------------------------* * check_need_of_virtual_speaker_node() @@ -1878,8 +1721,7 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node_fx( return VIRTUAL_SPEAKER_NODE_DISCARD_ENERGY; } -#endif - +#else static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node( VBAP_HANDLE hVBAPdata, /* i/o: VBAP structure */ const float *speaker_node_azi_deg, /* i : vector of speaker node azimuths */ @@ -1959,6 +1801,7 @@ static enum VirtualSpeakerNodeType check_need_of_virtual_speaker_node( return VIRTUAL_SPEAKER_NODE_DISCARD_ENERGY; } +#endif @@ -2108,8 +1951,7 @@ static void init_speaker_node_direction_data_fx( return; } -#endif - +#else static void init_speaker_node_direction_data( VBAP_SPEAKER_NODE *speaker_node_data, /* o : storage for speaker node data */ const float *speaker_node_azi_deg, /* i : vector of speaker node azimuths */ @@ -2206,7 +2048,7 @@ static void init_speaker_node_direction_data( return; } - +#endif /*-------------------------------------------------------------------------* * matrix_inverse_3x3() * @@ -2282,77 +2124,7 @@ static void matrix_inverse_3x3_32_fx( return; } - -static void matrix_inverse_3x3_fx( - const Word32 **input_matrix_fx, /* i : input matrix */ - Word16 inverse_matrix_fx[3][3], /* o : output matrix */ - Word16 *exp_inv_mat ) -{ - Word16 k; - Word32 determinant_fx; - Word32 cross_vec_fx[3]; - Word16 exp_inverse_matrix_fx[3][3]; - vbap_crossp_fx( input_matrix_fx[1], input_matrix_fx[2], cross_vec_fx ); - determinant_fx = dotp_fixed( input_matrix_fx[0], cross_vec_fx, 3 ); // Q30 + Q29 - Q31 = Q28 - Word16 inv_mat_exp = 0; - - FOR( k = 0; k < 3; k++ ) - { - inverse_matrix_fx[k][0] = BASOP_Util_Divide3232_Scale( cross_vec_fx[k], determinant_fx, &inv_mat_exp ); - inv_mat_exp = inv_mat_exp + ( ( 31 - 29 ) - ( 31 - 28 ) ); - exp_inverse_matrix_fx[k][0] = inv_mat_exp; - } - - vbap_crossp_fx( input_matrix_fx[2], input_matrix_fx[0], cross_vec_fx ); - - FOR( k = 0; k < 3; k++ ) - { - inverse_matrix_fx[k][1] = BASOP_Util_Divide3232_Scale( cross_vec_fx[k], determinant_fx, &inv_mat_exp ); - inv_mat_exp = inv_mat_exp + ( ( 31 - 29 ) - ( 31 - 28 ) ); - exp_inverse_matrix_fx[k][1] = inv_mat_exp; - } - - vbap_crossp_fx( input_matrix_fx[0], input_matrix_fx[1], cross_vec_fx ); - - FOR( k = 0; k < 3; k++ ) - { - inverse_matrix_fx[k][2] = BASOP_Util_Divide3232_Scale( cross_vec_fx[k], determinant_fx, &inv_mat_exp ); - inv_mat_exp = inv_mat_exp + ( ( 31 - 29 ) - ( 31 - 28 ) ); - exp_inverse_matrix_fx[k][2] = inv_mat_exp; - } - - /*Find common exponant*/ - Word16 max_exp = 0, i, j; - FOR( i = 0; i < 3; i++ ) - { - FOR( j = 0; j < 3; j++ ) - { - max_exp = s_max( max_exp, exp_inverse_matrix_fx[i][j] ); - } - } - - *exp_inv_mat = max_exp; - - FOR( i = 0; i < 3; i++ ) - { - FOR( j = 0; j < 3; j++ ) - { - IF( exp_inverse_matrix_fx[i][j] < -15 && inverse_matrix_fx[i][j] != 0 ) - { - inverse_matrix_fx[i][j] = 1; - exp_inverse_matrix_fx[i][j] = 0; - } - ELSE - { - inverse_matrix_fx[i][j] = shr( inverse_matrix_fx[i][j], max_exp - exp_inverse_matrix_fx[i][j] ); - } - } - } - - return; -} -#endif - +#else static void matrix_inverse_3x3( const float **input_matrix, /* i : input matrix */ float inverse_matrix[3][3] /* o : output matrix */ @@ -2387,6 +2159,7 @@ static void matrix_inverse_3x3( return; } +#endif /*-------------------------------------------------------------------------* * check_and_store_triplet() * @@ -2481,7 +2254,7 @@ static Word16 check_and_store_triplet_fx( /* Triplet was not good */ return 0; } -#endif +#else static int16_t check_and_store_triplet( const int16_t chA, /* i : first channel index that forms the loudspeaker triplet */ @@ -2541,119 +2314,28 @@ static int16_t check_and_store_triplet( speaker_node_data[chA].unit_vec[0] + speaker_node_data[chB].unit_vec[0] + speaker_node_data[chC].unit_vec[0]) * _180_OVER_PI; - /* Store increasing order indices for the later sorting step. */ - triplet_order[*triplet_index] = *triplet_index; - - (*triplet_index)++; - - return 1; - } - - /* Triplet was not good */ - return 0; -} -/*-------------------------------------------------------------------------* - * determine_virtual_surface_triplets() - * - * Determine virtual surface triples that are used for panning. This - * function is optimized for the use in cases where speaker nodes are in - * one group or divided into two separate groups divided by a horizontal - * layer. - *-------------------------------------------------------------------------*/ - -/*! r: number of virtual surface triplets */ -static int16_t determine_virtual_surface_triplets( - const int16_t num_speaker_nodes, /* i : number of speaker nodes */ - const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data structure */ - int16_t connections[][2], /* i : vector of all connections */ - const int16_t max_num_connections, /* i : max number of connections */ - VBAP_VS_TRIPLET *triplets, /* o : vector of virtual surface triplets */ - int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS], /* o : initial search indices for this set of triplets corresponding to the search struct */ - enum SpeakerNodeGroup allowed_group /* i : group of allowed speaker nodes for forming the triplets in this call */ -) -{ - int16_t chA, chB, chC, k, l, m; - int16_t num_triplets = 0; - int16_t num_connected_to_chA; - int16_t connected_to_chA[VBAP_MAX_NUM_SPEAKER_NODES]; - int16_t connection_uses_left[VBAP_MAX_NUM_SPEAKER_NODES]; - float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS]; - int16_t triplet_order[VBAP_MAX_NUM_TRIPLETS]; - - /* Each connection can be used exactly by two different virtual surface triplets. */ - set_s(connection_uses_left, 2, VBAP_MAX_NUM_SPEAKER_NODES); - - for (chA = 0; chA < num_speaker_nodes; chA++) - { - /* Early skip if not in correct group. */ - if (speaker_node_data[chA].group != allowed_group) - { - continue; - } - - /* Get all connections connected to current chA that have not been used by - * two triplets yet. */ - num_connected_to_chA = 0; - for (k = 0; k < max_num_connections; k++) - { - if ((connections[k][0] == chA || connections[k][1] == chA) && connection_uses_left[k] > 0) - { - connected_to_chA[num_connected_to_chA] = k; - num_connected_to_chA++; - } - } - - /* Check that we have enough connections to use. We need at least two available connections to form a triplet. - * This can fail in later stages when all connections are already used. */ - if (num_connected_to_chA < 2) - { - continue; - } - - /* Try to form triplets from each valid connection. */ - for (k = 0; k < num_connected_to_chA; k++) - { - int16_t connect_index_k = connected_to_chA[k]; - chB = 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++) - { - int16_t connect_index_l = connected_to_chA[l]; - chC = 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++) - { - if ((connections[m][0] == chB && connections[m][1] == chC) || (connections[m][1] == chB && connections[m][0] == chC)) - { - if (check_and_store_triplet(chA, chB, chC, num_speaker_nodes, speaker_node_data, triplets, &num_triplets, triplet_azidegs, triplet_order)) - { - connection_uses_left[connect_index_k]--; - connection_uses_left[connect_index_l]--; - connection_uses_left[m]--; - break; - } - } - } - - /* Check if chA-chB connection has been used in two triplets already. If yes, then break out of loop - * as this connection cannot be used for more triplets and we need to continue with another chA-chB - * connection. */ - if (connection_uses_left[connect_index_k] < 1) - { - break; - } - } - } - } + /* Store increasing order indices for the later sorting step. */ + triplet_order[*triplet_index] = *triplet_index; - /* All triplets should be stored now. Sort them for search use and then determine the initial search indices for - * each search sector for this search struct. */ - v_sort_ind(triplet_azidegs, triplet_order, num_triplets); - reorder_triplets(triplets, triplet_order, num_triplets); - determine_initial_search_indices(num_triplets, triplet_azidegs, initial_search_indices); + (*triplet_index)++; - return num_triplets; + return 1; + } + + /* Triplet was not good */ + return 0; } +#endif +/*-------------------------------------------------------------------------* + * determine_virtual_surface_triplets() + * + * Determine virtual surface triples that are used for panning. This + * function is optimized for the use in cases where speaker nodes are in + * one group or divided into two separate groups divided by a horizontal + * layer. + *-------------------------------------------------------------------------*/ + +/*! r: number of virtual surface triplets */ #ifdef IVAS_FLOAT_FIXED static Word16 determine_virtual_surface_triplets_fx( @@ -2761,60 +2443,108 @@ static Word16 determine_virtual_surface_triplets_fx( return num_triplets; } -#endif -/*-------------------------------------------------------------------------* - * determine_initial_search_indices() - * - * Determine initial search indices used for fast search of correct triangle - *-------------------------------------------------------------------------*/ -static void determine_initial_search_indices( - const int16_t num_triplets, /* i : number of triplets */ - const float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS], /* i : azimuths of triplets (in degrees) */ - int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS] /* o : initial search indices */ +#else +static int16_t determine_virtual_surface_triplets( + const int16_t num_speaker_nodes, /* i : number of speaker nodes */ + const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data structure */ + int16_t connections[][2], /* i : vector of all connections */ + const int16_t max_num_connections, /* i : max number of connections */ + VBAP_VS_TRIPLET *triplets, /* o : vector of virtual surface triplets */ + int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS], /* o : initial search indices for this set of triplets corresponding to the search struct */ + enum SpeakerNodeGroup allowed_group /* i : group of allowed speaker nodes for forming the triplets in this call */ ) { - int16_t i, j; - float sector_reference_azideg; - float sector_border_start_azideg; - float sector_border_end_azideg; - int16_t best_index; - float min_azideg_diff; - float azideg_diff; + int16_t chA, chB, chC, k, l, m; + int16_t num_triplets = 0; + int16_t num_connected_to_chA; + int16_t connected_to_chA[VBAP_MAX_NUM_SPEAKER_NODES]; + int16_t connection_uses_left[VBAP_MAX_NUM_SPEAKER_NODES]; + float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS]; + int16_t triplet_order[VBAP_MAX_NUM_TRIPLETS]; - for (i = 0; i < VBAP_NUM_SEARCH_SECTORS; i++) + /* Each connection can be used exactly by two different virtual surface triplets. */ + set_s(connection_uses_left, 2, VBAP_MAX_NUM_SPEAKER_NODES); + + for (chA = 0; chA < num_speaker_nodes; chA++) { - sector_border_start_azideg = i * VBAP_SEARCH_SECTOR_SIZE; - sector_border_end_azideg = (i + 1) * VBAP_SEARCH_SECTOR_SIZE; - sector_reference_azideg = (sector_border_start_azideg + sector_border_end_azideg) / 2.0f; - best_index = 0; - min_azideg_diff = 9999.9f; + /* Early skip if not in correct group. */ + if (speaker_node_data[chA].group != allowed_group) + { + continue; + } - for (j = 0; j < num_triplets; j++) + /* Get all connections connected to current chA that have not been used by + * two triplets yet. */ + num_connected_to_chA = 0; + for (k = 0; k < max_num_connections; k++) { - azideg_diff = sector_reference_azideg - triplet_azidegs[j]; - if (azideg_diff > 180.0f) - { - azideg_diff -= 360.0f; - } - else if (azideg_diff < -180.0f) + if ((connections[k][0] == chA || connections[k][1] == chA) && connection_uses_left[k] > 0) { - azideg_diff += 360.0f; + connected_to_chA[num_connected_to_chA] = k; + num_connected_to_chA++; } - azideg_diff = fabsf(azideg_diff); + } - if (azideg_diff < min_azideg_diff) + /* Check that we have enough connections to use. We need at least two available connections to form a triplet. + * This can fail in later stages when all connections are already used. */ + if (num_connected_to_chA < 2) + { + continue; + } + + /* Try to form triplets from each valid connection. */ + for (k = 0; k < num_connected_to_chA; k++) + { + int16_t connect_index_k = connected_to_chA[k]; + chB = 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++) { - min_azideg_diff = azideg_diff; - best_index = j; + int16_t connect_index_l = connected_to_chA[l]; + chC = 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++) + { + if ((connections[m][0] == chB && connections[m][1] == chC) || (connections[m][1] == chB && connections[m][0] == chC)) + { + if (check_and_store_triplet(chA, chB, chC, num_speaker_nodes, speaker_node_data, triplets, &num_triplets, triplet_azidegs, triplet_order)) + { + connection_uses_left[connect_index_k]--; + connection_uses_left[connect_index_l]--; + connection_uses_left[m]--; + break; + } + } + } + + /* Check if chA-chB connection has been used in two triplets already. If yes, then break out of loop + * as this connection cannot be used for more triplets and we need to continue with another chA-chB + * connection. */ + if (connection_uses_left[connect_index_k] < 1) + { + break; + } } } - - initial_search_indices[i] = best_index; } - return; + /* All triplets should be stored now. Sort them for search use and then determine the initial search indices for + * each search sector for this search struct. */ + v_sort_ind(triplet_azidegs, triplet_order, num_triplets); + reorder_triplets(triplets, triplet_order, num_triplets); + determine_initial_search_indices(num_triplets, triplet_azidegs, initial_search_indices); + + return num_triplets; } +#endif +/*-------------------------------------------------------------------------* + * determine_initial_search_indices() + * + * Determine initial search indices used for fast search of correct triangle + *-------------------------------------------------------------------------*/ + + #ifdef IVAS_FLOAT_FIXED static void determine_initial_search_indices_fx( const Word16 num_triplets, /* i : number of triplets */ @@ -2871,6 +2601,54 @@ static void determine_initial_search_indices_fx( return; } +#else +static void determine_initial_search_indices( + const int16_t num_triplets, /* i : number of triplets */ + const float triplet_azidegs[VBAP_MAX_NUM_TRIPLETS], /* i : azimuths of triplets (in degrees) */ + int16_t initial_search_indices[VBAP_NUM_SEARCH_SECTORS] /* o : initial search indices */ +) +{ + int16_t i, j; + float sector_reference_azideg; + float sector_border_start_azideg; + float sector_border_end_azideg; + int16_t best_index; + float min_azideg_diff; + float azideg_diff; + + for (i = 0; i < VBAP_NUM_SEARCH_SECTORS; i++) + { + sector_border_start_azideg = i * VBAP_SEARCH_SECTOR_SIZE; + sector_border_end_azideg = (i + 1) * VBAP_SEARCH_SECTOR_SIZE; + sector_reference_azideg = (sector_border_start_azideg + sector_border_end_azideg) / 2.0f; + best_index = 0; + min_azideg_diff = 9999.9f; + + for (j = 0; j < num_triplets; j++) + { + azideg_diff = sector_reference_azideg - triplet_azidegs[j]; + if (azideg_diff > 180.0f) + { + azideg_diff -= 360.0f; + } + else if (azideg_diff < -180.0f) + { + azideg_diff += 360.0f; + } + azideg_diff = fabsf(azideg_diff); + + if (azideg_diff < min_azideg_diff) + { + min_azideg_diff = azideg_diff; + best_index = j; + } + } + + initial_search_indices[i] = best_index; + } + + return; +} #endif /*-------------------------------------------------------------------------* @@ -2941,8 +2719,7 @@ static ivas_error determine_connections_fx( return IVAS_ERR_OK; } -#endif - +#else static ivas_error determine_connections( const int16_t num_speaker_nodes, /* i : number of speaker nodes */ const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data */ @@ -2999,6 +2776,7 @@ static ivas_error determine_connections( return IVAS_ERR_OK; } +#endif /*-------------------------------------------------------------------------* * determine_connection_class() * @@ -3184,7 +2962,7 @@ static enum ConnectionClass determine_connection_class_fx( return REGULAR_CONNECTION; } -#endif +#else /*! r: type of connection */ static enum ConnectionClass determine_connection_class( const VBAP_SPEAKER_NODE *node_data, /* i : speaker node data */ @@ -3286,6 +3064,7 @@ static enum ConnectionClass determine_connection_class( return REGULAR_CONNECTION; } +#endif /*-------------------------------------------------------------------------* * formulate_horizontal_connections() @@ -3351,8 +3130,7 @@ static void formulate_horizontal_connections_fx( return; } -#endif - +#else static void formulate_horizontal_connections( const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data */ const int16_t num_speaker_nodes, /* i : number of speaker nodes */ @@ -3396,6 +3174,7 @@ static void formulate_horizontal_connections( return; } +#endif /*-------------------------------------------------------------------------* * check_plane_crossing() @@ -3429,8 +3208,7 @@ static Word16 check_plane_crossing_fx( return 0; } -#endif - +#else static int16_t check_plane_crossing( const float ele1_deg, /* i : speaker node 1 elevation */ const float ele2_deg, /* i : speaker node 2 elevation */ @@ -3456,7 +3234,7 @@ static int16_t check_plane_crossing( return 0; } - +#endif /*-------------------------------------------------------------------------* * get_half_sphere_connection_options() @@ -3618,8 +3396,7 @@ static ivas_error get_half_sphere_connection_options_fx( return IVAS_ERR_OK; } -#endif - +#else static ivas_error get_half_sphere_connection_options( const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data */ const enum SpeakerNodeGroup group, /* i : speaker node group */ @@ -3738,6 +3515,7 @@ static ivas_error get_half_sphere_connection_options( return IVAS_ERR_OK; } +#endif /*-------------------------------------------------------------------------* * formulate_half_sphere_connections() @@ -4011,8 +3789,7 @@ static ivas_error formulate_half_sphere_connections_fx( return IVAS_ERR_OK; } -#endif - +#else static ivas_error formulate_half_sphere_connections( const VBAP_SPEAKER_NODE *speaker_node_data, /* i : speaker node data */ const int16_t num_speaker_nodes, /* i : number of speaker nodes */ @@ -4157,7 +3934,7 @@ static ivas_error formulate_half_sphere_connections( return IVAS_ERR_OK; } - +#endif /*-------------------------------------------------------------------------* * determine_non_crossing_planes() @@ -4264,8 +4041,7 @@ static Word16 determine_non_crossing_planes_fx( return num_planes; } -#endif - +#else static int16_t determine_non_crossing_planes( const int16_t num_speaker_nodes, /* i : number of speaker nodes */ const VBAP_SPEAKER_NODE *node_data, /* i : speaker node data */ @@ -4347,7 +4123,7 @@ static int16_t determine_non_crossing_planes( return num_planes; } - +#endif /*-------------------------------------------------------------------------* * reorder_triplets() @@ -4355,52 +4131,53 @@ static int16_t determine_non_crossing_planes( * Reorder virtual surface triplets into provided target order. *-------------------------------------------------------------------------*/ -static void reorder_triplets( - VBAP_VS_TRIPLET *triplets, /* i/o: VS triplets to be reordered */ - const int16_t *target_order, /* i : Target order for VS triplets */ - const int16_t num_triplets /* i : Number of VS triplets */ +#ifdef IVAS_FLOAT_FIXED +static void reorder_triplets_fx( + VBAP_VS_TRIPLET *triplets, /* i/o: VS triplets to be reordered */ + const Word16 *target_order, /* i : Target order for VS triplets */ + const Word16 num_triplets /* i : Number of VS triplets */ ) { VBAP_VS_TRIPLET tempTriplets[VBAP_MAX_NUM_TRIPLETS]; - int16_t c; + Word16 c; /* First copy to temp array */ - for ( c = 0; c < num_triplets; c++ ) + FOR( c = 0; c < num_triplets; c++ ) { tempTriplets[c] = triplets[c]; } /* Then move back in sorted order */ - for ( c = 0; c < num_triplets; c++ ) + FOR( c = 0; c < num_triplets; c++ ) { triplets[c] = tempTriplets[target_order[c]]; } return; } - -#ifdef IVAS_FLOAT_FIXED -static void reorder_triplets_fx( - VBAP_VS_TRIPLET *triplets, /* i/o: VS triplets to be reordered */ - const Word16 *target_order, /* i : Target order for VS triplets */ - const Word16 num_triplets /* i : Number of VS triplets */ +#else +static void reorder_triplets( + VBAP_VS_TRIPLET *triplets, /* i/o: VS triplets to be reordered */ + const int16_t *target_order, /* i : Target order for VS triplets */ + const int16_t num_triplets /* i : Number of VS triplets */ ) { VBAP_VS_TRIPLET tempTriplets[VBAP_MAX_NUM_TRIPLETS]; - Word16 c; + int16_t c; /* First copy to temp array */ - FOR( c = 0; c < num_triplets; c++ ) + for (c = 0; c < num_triplets; c++) { tempTriplets[c] = triplets[c]; } /* Then move back in sorted order */ - FOR( c = 0; c < num_triplets; c++ ) + for (c = 0; c < num_triplets; c++) { triplets[c] = tempTriplets[target_order[c]]; } return; } + #endif \ No newline at end of file diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 1079b7c2c6792f7b3b10953cb7d5e528364912aa..064f4f07de1b9756c74fb5b99e01787698b39e8f 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -9034,10 +9034,29 @@ static ivas_error ivas_masa_ext_rend_dirac_rend_init( if ( hDirACRend->panningConf == DIRAC_PANNING_VBAP ) { +#ifdef IVAS_FLOAT_FIXED + Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; + Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + ls_azimuth_fx[i] = (Word32) float_to_fix( ls_azimuth[i], Q22 ); + ls_elevation_fx[i] = (Word32) float_to_fix( ls_elevation[i], Q22 ); + } + IF( ( error = vbap_init_data_fx( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth_fx, ls_elevation_fx, nchan_out_woLFE, MASA_FORMAT ) ) != IVAS_ERR_OK ) + { + return error; + } + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + ls_azimuth[i] = (float) fix_to_float( ls_azimuth_fx[i], Q22 ); + ls_elevation[i] = (float) fix_to_float( ls_elevation_fx[i], Q22 ); + } +#else if ( ( error = vbap_init_data( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth, ls_elevation, nchan_out_woLFE, MASA_FORMAT ) ) != IVAS_ERR_OK ) { return error; } +#endif } /* HOA panning/dec */ @@ -9468,7 +9487,11 @@ static void freeMasaExtRenderer( if ( hMasaExtRend->hVBAPdata != NULL ) { - vbap_free_data( &hMasaExtRend->hVBAPdata ); +#ifdef IVAS_FLOAT_FIXED + vbap_free_data_fx( &hMasaExtRend->hVBAPdata ); +#else + vbap_free_data(&hMasaExtRend->hVBAPdata); +#endif } if ( hMasaExtRend->hoa_dec_mtx != NULL )