From 585c5dcc237fbdad137513c968a2f20327835fd9 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Mon, 12 Feb 2024 19:05:22 +0530 Subject: [PATCH] Converted few common functions to fixed point. Converted cmplx_matrix_square, matrix_diag_product, diag_matrix_product and matrix_product_diag to fixed point. --- lib_com/ivas_prot_fx.h | 47 ++++ lib_com/ivas_tools.c | 273 ++++++++++++++++++++++ lib_dec/ivas_dirac_output_synthesis_cov.c | 270 ++++++++++++++++++++- lib_dec/ivas_ism_param_dec.c | 22 ++ lib_dec/ivas_mc_param_dec.c | 100 ++++++++ lib_dec/ivas_out_setup_conversion.c | 42 ++++ 6 files changed, 753 insertions(+), 1 deletion(-) diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index a36b84109..d0ddaeccd 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -942,4 +942,51 @@ void ivas_decision_matrix_dec_fx( const Word16 nchan_out /* i : Number of output channels */ ); +void cmplx_matrix_square_fx( + const Word32 *realX, /* i : real part of the matrix */ + const Word32 *imagX, /* i : imaginary part of the matrix */ + const Word16 mRows, /* i : number of rows of the matrix */ + const Word16 nCols, /* i : number of columns of the matrix */ + Word32 *realZ, /* o : real part of the resulting matrix */ + Word32 *imagZ, /* o : imaginary part of the resulting matrix */ + Word16 input_exp, + Word16 *output_exp ); + +Word16 matrix_diag_product_fx( + const Word32 *X, /* i : left hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the left hand matrix */ + const Word16 colsX, /* i : number of columns of the left hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the left hand matrix prior to the multiplication */ + const Word32 *Y, /* i : right hand diagonal matrix as vector containing the diagonal elements */ + Word16 Y_e, + const Word16 entriesY, /* i : number of entries in the diagonal */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ); + +Word16 diag_matrix_product_fx( + const Word32 *Y, /* i : left hand diagonal matrix as vector containing the diagonal elements */ + Word16 Y_e, + const Word16 entriesY, /* i : length of the diagonal of the left hand matrix */ + const Word32 *X, /* i : right hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the right hand matrix */ + const Word16 colsX, /* i : number of columns of the right hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the right hand matrix prior to the multiplication */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ); + +Word16 matrix_product_diag_fx( + const Word32 *X, /* i : left hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the left hand matrix */ + const Word16 colsX, /* i : number of columns of the left hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the left hand matrix prior to the multiplication */ + const Word32 *Y, /* i : right hand matrix */ + Word16 Y_e, + const Word16 rowsY, /* i : number of rows of the right hand matrix */ + const Word16 colsY, /* i : number of columns of the right hand matrix */ + const Word16 transpY, /* i : flag indicating the transposition of the right hand matrix prior to the multiplication */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ); #endif diff --git a/lib_com/ivas_tools.c b/lib_com/ivas_tools.c index 3039ac303..e5e27e8ad 100644 --- a/lib_com/ivas_tools.c +++ b/lib_com/ivas_tools.c @@ -860,6 +860,62 @@ int16_t matrix_diag_product( return EXIT_SUCCESS; } +#ifdef IVAS_FLOAT_FIXED +Word16 matrix_diag_product_fx( + const Word32 *X, /* i : left hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the left hand matrix */ + const Word16 colsX, /* i : number of columns of the left hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the left hand matrix prior to the multiplication */ + const Word32 *Y, /* i : right hand diagonal matrix as vector containing the diagonal elements */ + Word16 Y_e, + const Word16 entriesY, /* i : number of entries in the diagonal */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ) +{ + Word16 i, j; + Word32 *Zp = Z; + + /* Processing */ + IF( EQ_16(transpX, 1 )) /* We use X transpose */ + { + IF( NE_16(rowsX, entriesY )) + { + return EXIT_FAILURE; + } + FOR( j = 0; j < entriesY; ++j ) + { + FOR( i = 0; i < colsX; ++i ) + { + *( Zp ) = Mpy_32_32( X[j + i * rowsX], Y[j] ); + Zp++; + } + } + } + ELSE /* Regular case */ + { + IF(NE_16(colsX, entriesY )) + { + return EXIT_FAILURE; + } + + FOR( j = 0; j < entriesY; ++j ) + { + FOR( i = 0; i < rowsX; ++i ) + { + *( Zp ) = Mpy_32_32( *( X ), Y[j] ); + Zp++; + X++; + } + } + } + + *Z_e = add( X_e, Y_e ); + + return EXIT_SUCCESS; +} +#endif + /*---------------------------------------------------------------------* * diag_matrix_product() * @@ -913,6 +969,61 @@ int16_t diag_matrix_product( return EXIT_SUCCESS; } +#ifdef IVAS_FLOAT_FIXED +Word16 diag_matrix_product_fx( + const Word32 *Y, /* i : left hand diagonal matrix as vector containing the diagonal elements */ + Word16 Y_e, + const Word16 entriesY, /* i : length of the diagonal of the left hand matrix */ + const Word32 *X, /* i : right hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the right hand matrix */ + const Word16 colsX, /* i : number of columns of the right hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the right hand matrix prior to the multiplication */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ) +{ + Word16 i, j; + Word32 *Zp = Z; + + /* Processing */ + IF( EQ_16( transpX, 1 ) ) /* We use X transpose */ + { + IF( NE_16( colsX, entriesY ) ) + { + return EXIT_FAILURE; + } + FOR( i = 0; i < rowsX; ++i ) + { + FOR( j = 0; j < entriesY; ++j ) + { + *( Zp ) = Mpy_32_32( X[i + j * rowsX], Y[j] ); + Zp++; + } + } + } + ELSE /* Regular case */ + { + IF( NE_16( rowsX, entriesY ) ) + { + return EXIT_FAILURE; + } + FOR( i = 0; i < colsX; ++i ) + { + FOR( j = 0; j < entriesY; ++j ) + { + *( Zp ) = Mpy_32_32( *( X ), Y[j] ); + Zp++; + X++; + } + } + } + + *Z_e = add(Y_e, X_e); + + return EXIT_SUCCESS; +} +#endif + /*---------------------------------------------------------------------* * matrix_product_diag() @@ -1010,6 +1121,103 @@ int16_t matrix_product_diag( return EXIT_SUCCESS; } +#ifdef IVAS_FLOAT_FIXED +Word16 matrix_product_diag_fx( + const Word32 *X, /* i : left hand matrix */ + Word16 X_e, + const Word16 rowsX, /* i : number of rows of the left hand matrix */ + const Word16 colsX, /* i : number of columns of the left hand matrix */ + const Word16 transpX, /* i : flag indicating the transposition of the left hand matrix prior to the multiplication */ + const Word32 *Y, /* i : right hand matrix */ + Word16 Y_e, + const Word16 rowsY, /* i : number of rows of the right hand matrix */ + const Word16 colsY, /* i : number of columns of the right hand matrix */ + const Word16 transpY, /* i : flag indicating the transposition of the right hand matrix prior to the multiplication */ + Word32 *Z, /* o : resulting matrix after the matrix multiplication */ + Word16 *Z_e ) +{ + Word16 j, k; + Word32 *Zp = Z; + + /* Processing */ + test(); + test(); + test(); + IF( EQ_16( transpX, 1 ) && EQ_16( transpY, 0 ) ) /* We use X transpose */ + { + IF( NE_16( rowsX, rowsY ) ) + { + return EXIT_FAILURE; + } + + FOR( j = 0; j < colsY; ++j ) + { + ( *Zp ) = 0; + FOR( k = 0; k < rowsX; ++k ) + { + ( *Zp ) = L_add( ( *Zp ), Mpy_32_32( X[k + j * rowsX], Y[k + j * rowsY] ) ); + } + Zp++; + } + } + ELSE IF( EQ_16( transpX, 0 ) && EQ_16( transpY, 1 ) ) /* We use Y transpose */ + { + IF( NE_16( colsX, colsY ) ) + { + return EXIT_FAILURE; + } + FOR( j = 0; j < rowsY; ++j ) + { + ( *Zp ) = 0; + FOR( k = 0; k < colsX; ++k ) + { + ( *Zp ) = L_add( ( *Zp ), Mpy_32_32( X[j + k * rowsX], Y[j + k * rowsY] ) ); + } + Zp++; + } + } + ELSE IF( EQ_16( transpX, 1 ) && EQ_16( transpY, 1 ) ) /* We use both transpose */ + { + IF( NE_16( rowsX, colsY ) ) + { + return EXIT_FAILURE; + } + + FOR( j = 0; j < rowsY; ++j ) + { + + ( *Zp ) = 0; + FOR( k = 0; k < colsX; ++k ) + { + ( *Zp ) = L_add( ( *Zp ), Mpy_32_32( X[k + j * rowsX], Y[j + k * rowsY] ) ); + } + + Zp++; + } + } + ELSE /* Regular case */ + { + IF( NE_16( colsX, rowsY ) ) + { + return EXIT_FAILURE; + } + + FOR( j = 0; j < colsY; ++j ) + { + ( *Zp ) = 0; + FOR( k = 0; k < colsX; ++k ) + { + ( *Zp ) = L_add( ( *Zp ), Mpy_32_32( X[j + k * rowsX], Y[k + j * rowsY] ) ); + } + Zp++; + } + } + + *Z_e = add( X_e, Y_e ); + + return EXIT_SUCCESS; +} +#endif /*---------------------------------------------------------------------* * cmplx_matrix_square() @@ -1018,6 +1226,71 @@ int16_t matrix_product_diag( *---------------------------------------------------------------------*/ /*! r: success or failure */ +#ifdef IVAS_FLOAT_FIXED +void cmplx_matrix_square_fx( + const Word32 *realX, /* i : real part of the matrix */ + const Word32 *imagX, /* i : imaginary part of the matrix */ + const Word16 mRows, /* i : number of rows of the matrix */ + const Word16 nCols, /* i : number of columns of the matrix */ + Word32 *realZ, /* o : real part of the resulting matrix */ + Word32 *imagZ, /* o : imaginary part of the resulting matrix */ + Word16 input_exp, + Word16 *output_exp ) +{ + Word16 i, j, k; + Word32 *realZp, *imagZp; + const Word32 *p_real1, *p_real2, *p_imag1, *p_imag2; + + /* resulting matrix is hermitean, we only need to calc the upper triangle */ + /* we assume transposition needed */ + + /* column*column = column/column */ + FOR( i = 0; i < nCols; i++ ) + { + FOR( j = i; j < nCols; j++ ) + { + p_real1 = realX + i * mRows; + p_imag1 = imagX + i * mRows; + p_real2 = realX + j * mRows; + p_imag2 = imagX + j * mRows; + realZp = realZ + ( i + nCols * j ); + imagZp = imagZ + ( i + nCols * j ); + *( realZp ) = 0; + move32(); + *( imagZp ) = 0; + move32(); + + FOR( k = 0; k < mRows; k++ ) + { + *( imagZp ) = L_add( *( imagZp ), L_sub( Mpy_32_32( *( p_real1 ), *( p_imag2 ) ), Mpy_32_32( *( p_real2 ), *( p_imag1 ) ) ) ); + *( realZp ) = L_add( *( realZp ), L_add( Mpy_32_32( *( p_real1 ), *( p_real2 ) ), Mpy_32_32( *( p_imag1 ), *( p_imag2 ) ) ) ); + p_real1++; + p_real2++; + p_imag1++; + p_imag2++; + } + } + } + + /* fill lower triangle */ + FOR( i = 1; i < nCols; i++ ) + { + FOR( j = 0; j < i; j++ ) + { + realZ[i + nCols * j] = realZ[j + nCols * i]; + move32(); + imagZ[i + nCols * j] = imagZ[j + nCols * i]; + move32(); + } + } + + *output_exp = shl( input_exp, 1 ); + move16(); + + return; +} +#endif + void cmplx_matrix_square( const float *realX, /* i : real part of the matrix */ const float *imagX, /* i : imaginary part of the matrix */ diff --git a/lib_dec/ivas_dirac_output_synthesis_cov.c b/lib_dec/ivas_dirac_output_synthesis_cov.c index 092ffe411..57a6d0aad 100644 --- a/lib_dec/ivas_dirac_output_synthesis_cov.c +++ b/lib_dec/ivas_dirac_output_synthesis_cov.c @@ -47,6 +47,11 @@ #include "ivas_rom_dec.h" #include "wmc_auto.h" #include "rom_dec.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_prot_fx.h" +#endif /*-------------------------------------------------------------------* @@ -340,7 +345,49 @@ void ivas_dirac_dec_output_synthesis_cov_param_mc_collect_slot( } } +#ifdef IVAS_FLOAT_FIXED + Word32 real_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * MAX_TRANSPORT_CHANNELS]; + Word32 imag_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * MAX_TRANSPORT_CHANNELS]; + Word32 real_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word32 imag_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word16 real_exp, imag_exp, input_exp, output_exp; + Word16 shift = find_guarded_bits_fx( num_bands + 1 ); + + f2me_buf( real_in_buffer, real_in_buffer_fx, &real_exp, num_bands * nchan_in ); + f2me_buf( imag_in_buffer, imag_in_buffer_fx, &imag_exp, num_bands * nchan_in ); + + IF( real_exp > imag_exp ) + { + FOR( Word16 i = 0; i < num_bands * nchan_in; ++i ) + { + imag_in_buffer_fx[i] = L_shr( imag_in_buffer_fx[i], real_exp - imag_exp ); + } + input_exp = real_exp; + } + ELSE + { + FOR( Word16 i = 0; i < num_bands * nchan_in; ++i ) + { + real_in_buffer_fx[i] = L_shr( real_in_buffer_fx[i], imag_exp - real_exp ); + } + input_exp = imag_exp; + } + + FOR( Word16 i = 0; i < num_bands * nchan_in; ++i ) + { + real_in_buffer_fx[i] = L_shr( real_in_buffer_fx[i], shift ); + imag_in_buffer_fx[i] = L_shr( imag_in_buffer_fx[i], shift ); + } + + input_exp += shift; + + cmplx_matrix_square_fx( real_in_buffer_fx, imag_in_buffer_fx, num_bands, nchan_in, real_buffer_fx, imag_buffer_fx, input_exp, &output_exp ); + + me2f_buf( real_buffer_fx, output_exp, real_buffer, nchan_in * nchan_in ); + me2f_buf( imag_buffer_fx, output_exp, imag_buffer, nchan_in * nchan_in ); +#else cmplx_matrix_square( real_in_buffer, imag_in_buffer, num_bands, nchan_in, real_buffer, imag_buffer ); +#endif v_add( cx[param_band], real_buffer, cx[param_band], nchan_in * nchan_in ); @@ -604,7 +651,43 @@ int16_t computeMixingMatrices( /* Computing Q*Cx*Q' */ matrix_product( Q, lengthCy, lengthCx, 0, Cx, lengthCx, lengthCx, 0, Q_Cx ); +#ifdef IVAS_FLOAT_FIXED + Word32 Q_Cx_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Q_fx[PARAM_MC_MAX_TRANSPORT_CHANS * MAX_CICP_CHANNELS]; + Word32 Cy_hat_diag_fx[MAX_OUTPUT_CHANNELS]; + Word16 Q_Cx_e, Q_e, Cy_hat_diag_e; + Word16 guard_bits = find_guarded_bits_fx( lengthCx + 1 ); + + f2me_buf( Q_Cx, Q_Cx_fx, &Q_Cx_e, lengthCy * lengthCx ); + f2me_buf( Q, Q_fx, &Q_e, lengthCy * lengthCx ); + + for ( i = 0; i < lengthCy * lengthCx; ++i ) + { + if ( Q_Cx_e > Q_e ) + { + Q_fx[i] = L_shr( Q_fx[i], guard_bits ); + } + else + { + Q_Cx_fx[i] = L_shr( Q_Cx_fx[i], guard_bits ); + } + } + + if ( Q_Cx_e > Q_e ) + { + Q_e += guard_bits; + } + else + { + Q_Cx_e += guard_bits; + } + + matrix_product_diag_fx( Q_Cx_fx, Q_Cx_e, lengthCy, lengthCx, 0, Q_fx, Q_e, lengthCy, lengthCx, 1, Cy_hat_diag_fx, &Cy_hat_diag_e ); + + me2f_buf( Cy_hat_diag_fx, Cy_hat_diag_e, Cy_hat_diag, lengthCy ); +#else matrix_product_diag( Q_Cx, lengthCy, lengthCx, 0, Q, lengthCy, lengthCx, 1, Cy_hat_diag ); +#endif /* Computing Cy_hat_diag */ for ( i = 0; i < lengthCy; ++i ) @@ -634,7 +717,21 @@ int16_t computeMixingMatrices( /* Computing the input matrix Kx'*Q'*G_hat'*Ky */ matrix_product( Kx, lengthCx, lengthCx, 1, Q, lengthCy, lengthCx, 1, mat_mult_buffer1 ); +#ifdef IVAS_FLOAT_FIXED + Word32 mat_mult_buffer1_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer2_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 G_hat_fx[MAX_OUTPUT_CHANNELS]; + Word16 mat_mult_buffer1_e, mat_mult_buffer2_e, G_hat_e; + + f2me_buf( mat_mult_buffer1, mat_mult_buffer1_fx, &mat_mult_buffer1_e, lengthCx * lengthCy); + f2me_buf( G_hat, G_hat_fx, &G_hat_e, lengthCy); + + matrix_diag_product_fx( mat_mult_buffer1_fx, mat_mult_buffer1_e, lengthCx, lengthCy, 0, G_hat_fx, G_hat_e, lengthCy, mat_mult_buffer2_fx, &mat_mult_buffer2_e ); + + me2f_buf( mat_mult_buffer2_fx, mat_mult_buffer2_e, mat_mult_buffer2, lengthCx * lengthCy); +#else matrix_diag_product( mat_mult_buffer1, lengthCx, lengthCy, 0, G_hat, lengthCy, mat_mult_buffer2 ); +#endif matrix_product( mat_mult_buffer2, lengthCx, lengthCy, 0, Ky, lengthCy, lengthCy, 0, mat_mult_buffer1 ); if ( lengthCx < lengthCy ) @@ -726,7 +823,21 @@ int16_t computeMixingMatrices( } } +#ifdef IVAS_FLOAT_FIXED + Word32 adj_fx[MAX_OUTPUT_CHANNELS]; + Word32 mixing_matrix_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer3_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word16 adj_e, mixing_matrix_e, mat_mult_buffer3_e; + + f2me_buf( adj, adj_fx, &adj_e, lengthCy ); + f2me_buf( mixing_matrix, mixing_matrix_fx, &mixing_matrix_e, lengthCy * lengthCx ); + + diag_matrix_product_fx( adj_fx, adj_e, lengthCy, mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 0, mat_mult_buffer3_fx, &mat_mult_buffer3_e ); + + me2f_buf( mat_mult_buffer3_fx, mat_mult_buffer3_e, mat_mult_buffer3, lengthCx * lengthCy ); +#else diag_matrix_product( adj, lengthCy, mixing_matrix, lengthCy, lengthCx, 0, mat_mult_buffer3 ); +#endif mvr2r( mat_mult_buffer3, mixing_matrix, lengthCy * lengthCx ); } @@ -773,6 +884,15 @@ int16_t computeMixingMatricesResidual( push_wmops( "dirac_cov_mix_mat_r" ); +#ifdef IVAS_FLOAT_FIXED + Word32 mixing_matrix_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Cx_fx[MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer1_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 adj_fx[MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer3_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word16 mixing_matrix_e, Cx_e, mat_mult_buffer1_e, adj_e, mat_mult_buffer3_e; +#endif + /*-----------------------------------------------------------------* * Decomposition of Cy *-----------------------------------------------------------------*/ @@ -906,9 +1026,46 @@ int16_t computeMixingMatricesResidual( *-----------------------------------------------------------------*/ /* Compute Cy_tilde = M*Cx*M' */ - matrix_diag_product( mixing_matrix, lengthCy, lengthCx, 0, Cx, lengthCx, mat_mult_buffer1 ); +#ifdef IVAS_FLOAT_FIXED + Word32 Cy_tilde_fx[MAX_OUTPUT_CHANNELS]; + Word16 Cy_tilde_e; + + f2me_buf( mixing_matrix, mixing_matrix_fx, &mixing_matrix_e, lengthCy * lengthCx ); + f2me_buf( Cx, Cx_fx, &Cx_e, lengthCx ); + + matrix_diag_product_fx( mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 0, Cx_fx, Cx_e, lengthCx, mat_mult_buffer1_fx, &mat_mult_buffer1_e ); + + Word16 guard_bits = find_guarded_bits_fx( lengthCx + 1 ); + + for ( i = 0; i < lengthCy * lengthCx; ++i ) + { + if ( mat_mult_buffer1_e > mixing_matrix_e ) + { + mixing_matrix_fx[i] = L_shr( mixing_matrix_fx[i], guard_bits ); + } + else + { + mat_mult_buffer1_fx[i] = L_shr( mat_mult_buffer1_fx[i], guard_bits ); + } + } + + if ( mat_mult_buffer1_e > mixing_matrix_e ) + { + mixing_matrix_e += guard_bits; + } + else + { + mat_mult_buffer1_e += guard_bits; + } + + matrix_product_diag_fx( mat_mult_buffer1_fx, mat_mult_buffer1_e, lengthCy, lengthCx, 0, mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 1, Cy_tilde_fx, &Cy_tilde_e ); + me2f_buf( Cy_tilde_fx, Cy_tilde_e, Cy_tilde, lengthCy ); +#else + matrix_diag_product( mixing_matrix, lengthCy, lengthCx, 0, Cx, lengthCx, mat_mult_buffer1 ); matrix_product_diag( mat_mult_buffer1, lengthCy, lengthCx, 0, mixing_matrix, lengthCy, lengthCx, 1, Cy_tilde ); +#endif + /*-----------------------------------------------------------------* * Energy Compensation @@ -925,7 +1082,16 @@ int16_t computeMixingMatricesResidual( } } +#ifdef IVAS_FLOAT_FIXED + f2me_buf( adj, adj_fx, &adj_e, lengthCy ); + f2me_buf( mixing_matrix, mixing_matrix_fx, &mixing_matrix_e, lengthCy * lengthCx ); + + diag_matrix_product_fx( adj_fx, adj_e, lengthCy, mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 0, mat_mult_buffer3_fx, &mat_mult_buffer3_e ); + + me2f_buf( mat_mult_buffer3_fx, mat_mult_buffer3_e, mat_mult_buffer3, lengthCx * lengthCy ); +#else diag_matrix_product( adj, lengthCy, mixing_matrix, lengthCy, lengthCx, 0, mat_mult_buffer3 ); +#endif mvr2r( mat_mult_buffer3, mixing_matrix, lengthCy * lengthCx ); @@ -974,6 +1140,23 @@ int16_t computeMixingMatricesISM( float mat_mult_buffer2[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; float mat_mult_buffer3[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; int16_t nL, nC; +#ifdef IVAS_FLOAT_FIXED + Word32 responses_fx[PARAM_ISM_MAX_CHAN * MAX_NUM_OBJECTS]; + Word32 ener_fx[MAX_NUM_OBJECTS]; + Word32 Ky_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Q_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Cx_diag_fx[MAX_OUTPUT_CHANNELS]; + Word32 Q_Cx_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer1_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 G_hat_fx[MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer2_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Kx_reg_inv_fx[MAX_TRANSPORT_CHANNELS]; + Word32 mixing_matrix_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 adj_fx[MAX_OUTPUT_CHANNELS]; + Word32 mat_mult_buffer3_fx[MAX_OUTPUT_CHANNELS * MAX_OUTPUT_CHANNELS]; + Word32 Kx_fx[MAX_TRANSPORT_CHANNELS]; + Word16 responses_e, ener_e, Ky_e, Q_e, Cx_diag_e, Q_Cx_e, mat_mult_buffer1_e, G_hat_e, mat_mult_buffer2_e, Kx_reg_inv_e, mixing_matrix_e, adj_e, mat_mult_buffer3_e, Kx_e; +#endif push_wmops( "dirac_cov_mix_mat" ); @@ -991,7 +1174,16 @@ int16_t computeMixingMatricesISM( /* Decomposition of Cy = Ky*Ky' */ /* Ky = responses*diag(ener) */ +#ifdef IVAS_FLOAT_FIXED + f2me_buf( responses, responses_fx, &responses_e, lengthCy * num_responses ); + f2me_buf( ener, ener_fx, &ener_e, num_responses ); + + matrix_diag_product_fx(responses_fx, responses_e, lengthCy, num_responses, 0, ener_fx, ener_e, num_responses, Ky_fx, &Ky_e ); + + me2f_buf(Ky_fx, Ky_e, Ky, lengthCy * num_responses ); +#else matrix_diag_product( responses, lengthCy, num_responses, 0, ener, num_responses, Ky ); +#endif /* Decomposition of Cx -> Computing Kx */ v_sqrt( Cx_diag, Kx, lengthCx ); @@ -1018,8 +1210,44 @@ int16_t computeMixingMatricesISM( /************************ normalization matrix G hat **********************/ /* Computing Q*Cx*Q' */ +#ifdef IVAS_FLOAT_FIXED + Word32 Cy_hat_diag_fx[MAX_OUTPUT_CHANNELS]; + Word16 Cy_hat_diag_e; + + f2me_buf( Q, Q_fx, &Q_e, lengthCy * lengthCx ); + f2me_buf( Cx_diag, Cx_diag_fx, &Cx_diag_e, lengthCx ); + + matrix_diag_product_fx( Q_fx, Q_e, lengthCy, lengthCx, 0, Cx_diag_fx, Cx_diag_e, lengthCx, Q_Cx_fx, &Q_Cx_e ); + + Word16 guard_bits = find_guarded_bits_fx( lengthCx + 1 ); + + for ( i = 0; i < lengthCy * lengthCx; ++i ) + { + if ( Q_Cx_e > Q_e ) + { + Q_fx[i] = L_shr( Q_fx[i], guard_bits ); + } + else + { + Q_Cx_fx[i] = L_shr( Q_Cx_fx[i], guard_bits ); + } + } + + if ( Q_Cx_e > Q_e ) + { + Q_e += guard_bits; + } + else + { + Q_Cx_e += guard_bits; + } + matrix_product_diag_fx( Q_Cx_fx, Q_Cx_e, lengthCy, lengthCx, 0, Q_fx, Q_e, lengthCy, lengthCx, 1, Cy_hat_diag_fx, &Cy_hat_diag_e ); + + me2f_buf( Cy_hat_diag_fx, Cy_hat_diag_e, Cy_hat_diag, lengthCy ); +#else matrix_diag_product( Q, lengthCy, lengthCx, 0, Cx_diag, lengthCx, Q_Cx ); matrix_product_diag( Q_Cx, lengthCy, lengthCx, 0, Q, lengthCy, lengthCx, 1, Cy_hat_diag ); +#endif /* Computing Cy_hat_diag */ for ( i = 0; i < lengthCy; ++i ) @@ -1046,8 +1274,21 @@ int16_t computeMixingMatricesISM( /************************ Formulate optimal P **********************/ /* Computing the input matrix Kx'*Q'*G_hat'*Ky */ +#ifdef IVAS_FLOAT_FIXED + f2me_buf( Kx, Kx_fx, &Kx_e, lengthCx ); + f2me_buf( Q, Q_fx, &Q_e, lengthCy * lengthCx ); + + diag_matrix_product_fx( Kx_fx, Kx_e, lengthCx, Q_fx, Q_e, lengthCy, lengthCx, 1, mat_mult_buffer1_fx, &mat_mult_buffer1_e ); + + f2me_buf( G_hat, G_hat_fx, &G_hat_e, lengthCy ); + + matrix_diag_product_fx( mat_mult_buffer1_fx, mat_mult_buffer1_e, lengthCx, lengthCy, 0, G_hat_fx, G_hat_e, lengthCy, mat_mult_buffer2_fx, &mat_mult_buffer2_e ); + + me2f_buf( mat_mult_buffer2_fx, mat_mult_buffer2_e, mat_mult_buffer2, lengthCx * lengthCy ); +#else diag_matrix_product( Kx, lengthCx, Q, lengthCy, lengthCx, 1, mat_mult_buffer1 ); matrix_diag_product( mat_mult_buffer1, lengthCx, lengthCy, 0, G_hat, lengthCy, mat_mult_buffer2 ); +#endif matrix_product( mat_mult_buffer2, lengthCx, lengthCy, 0, Ky, lengthCy, num_responses, 0, mat_mult_buffer1 ); if ( lengthCx < num_responses ) @@ -1077,12 +1318,30 @@ int16_t computeMixingMatricesISM( matrix_product( Ky, lengthCy, num_responses, 0, mat_mult_buffer3, num_responses, lengthCx, 0, mat_mult_buffer1 ); +#ifdef IVAS_FLOAT_FIXED + f2me_buf( mat_mult_buffer1, mat_mult_buffer1_fx, &mat_mult_buffer1_e, lengthCx * lengthCy ); + f2me_buf( Kx_reg_inv, Kx_reg_inv_fx, &Kx_reg_inv_e, lengthCx ); + + matrix_diag_product_fx( mat_mult_buffer1_fx, mat_mult_buffer1_e, lengthCy, lengthCx, 0, Kx_reg_inv_fx, Kx_reg_inv_e, lengthCx, mixing_matrix_fx, &mixing_matrix_e ); + + me2f_buf( mixing_matrix_fx, mixing_matrix_e, mixing_matrix, lengthCy * lengthCx ); +#else matrix_diag_product( mat_mult_buffer1, lengthCy, lengthCx, 0, Kx_reg_inv, lengthCx, mixing_matrix ); +#endif /*********************** Energy Compensation ****************/ /* Compute Cy_tilde = M*Cx*M' */ +#ifdef IVAS_FLOAT_FIXED + f2me_buf( mixing_matrix, mixing_matrix_fx, &mixing_matrix_e, lengthCx * lengthCy ); + f2me_buf( Cx_diag, Cx_diag_fx, &Cx_diag_e, lengthCx ); + + matrix_diag_product_fx( mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 0, Cx_diag_fx, Cx_diag_e, lengthCx, mat_mult_buffer1_fx, &mat_mult_buffer1_e ); + + me2f_buf( mat_mult_buffer1_fx, mat_mult_buffer1_e, mat_mult_buffer1, lengthCx * lengthCy ); +#else matrix_diag_product( mixing_matrix, lengthCy, lengthCx, 0, Cx_diag, lengthCx, mat_mult_buffer1 ); +#endif matrix_product( mat_mult_buffer1, lengthCy, lengthCx, 0, mixing_matrix, lengthCy, lengthCx, 1, mat_mult_buffer2 ); if ( energy_compensation_flag == 1 ) @@ -1107,7 +1366,16 @@ int16_t computeMixingMatricesISM( } } +#ifdef IVAS_FLOAT_FIXED + f2me_buf( adj, adj_fx, &adj_e, lengthCy ); + f2me_buf( mixing_matrix, mixing_matrix_fx, &mixing_matrix_e, lengthCy * lengthCx ); + + diag_matrix_product_fx( adj_fx, adj_e, lengthCy, mixing_matrix_fx, mixing_matrix_e, lengthCy, lengthCx, 0, mat_mult_buffer3_fx, &mat_mult_buffer3_e ); + + me2f_buf( mat_mult_buffer3_fx, mat_mult_buffer3_e, mat_mult_buffer3, lengthCx * lengthCy ); +#else diag_matrix_product( adj, lengthCy, mixing_matrix, lengthCy, lengthCx, 0, mat_mult_buffer3 ); +#endif mvr2r( mat_mult_buffer3, mixing_matrix, lengthCy * lengthCx ); } diff --git a/lib_dec/ivas_ism_param_dec.c b/lib_dec/ivas_ism_param_dec.c index e9ae7005d..bfc1ef6c2 100644 --- a/lib_dec/ivas_ism_param_dec.c +++ b/lib_dec/ivas_ism_param_dec.c @@ -210,6 +210,11 @@ static void ivas_param_ism_compute_mixing_matrix( float *proto_matrix; float response_matrix[PARAM_ISM_MAX_CHAN * MAX_NUM_OBJECTS]; int16_t num_wave; +#ifdef IVAS_FLOAT_FIXED + Word32 dir_res_ptr_fx[PARAM_ISM_MAX_CHAN]; + Word32 cy_diag_tmp_fx[PARAM_ISM_MAX_CHAN]; + Word16 dir_res_ptr_e, cy_diag_tmp_e; +#endif proto_matrix = hParamIsmDec->hParamIsmRendering->proto_matrix; @@ -248,7 +253,24 @@ static void ivas_param_ism_compute_mixing_matrix( } mvr2r( dir_res_ptr, response_matrix + w * nchan_out_woLFE, nchan_out_woLFE ); /* we only need the diagonal of Cy*/ +#ifdef IVAS_FLOAT_FIXED + f2me_buf( dir_res_ptr, dir_res_ptr_fx, &dir_res_ptr_e, nchan_out_woLFE ); + + Word16 guard_bits = 1; + + for ( i = 0; i < nchan_out_woLFE; ++i ) + { + dir_res_ptr_fx[i] = L_shr( dir_res_ptr_fx[i], guard_bits ); + } + + dir_res_ptr_e += guard_bits; + + matrix_product_diag_fx( dir_res_ptr_fx, dir_res_ptr_e, nchan_out_woLFE, 1, 0, dir_res_ptr_fx, dir_res_ptr_e, 1, nchan_out_woLFE, 0, cy_diag_tmp_fx, &cy_diag_tmp_e ); + + me2f_buf( cy_diag_tmp_fx, cy_diag_tmp_e, cy_diag_tmp[w], nchan_out_woLFE ); +#else matrix_product_diag( dir_res_ptr, nchan_out_woLFE, 1, 0, dir_res_ptr, 1, nchan_out_woLFE, 0, cy_diag_tmp[w] ); +#endif } for ( bin_idx = brange[0]; bin_idx < brange[1]; bin_idx++ ) diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index 270c4138b..e4affbed3 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -2424,7 +2424,44 @@ static void ivas_param_mc_get_mixing_matrices( matrix_product( proto_matrix_ptr, nY_band, nX, 0, Cx, nX, nX, 0, mat_mult_buffer1 ); +#ifdef IVAS_FLOAT_FIXED + Word32 mat_mult_buffer1_fx[MAX_CICP_CHANNELS * MAX_CICP_CHANNELS]; + Word32 proto_matrix_ptr_fx[PARAM_MC_MAX_TRANSPORT_CHANS * MAX_CICP_CHANNELS]; + Word32 Cproto_diag_fx[MAX_CICP_CHANNELS]; + Word16 mat_mult_buffer1_e, proto_matrix_ptr_e, Cproto_diag_e; + + Word16 guard_bits = find_guarded_bits_fx( nY_band + 1 ); + + f2me_buf( mat_mult_buffer1, mat_mult_buffer1_fx, &mat_mult_buffer1_e, nY_band * nX ); + f2me_buf( proto_matrix_ptr, proto_matrix_ptr_fx, &proto_matrix_ptr_e, nY_band * nX ); + + for ( i = 0; i < nY_band * nX; ++i ) + { + if ( mat_mult_buffer1_e > proto_matrix_ptr_e ) + { + proto_matrix_ptr_fx[i] = L_shr( proto_matrix_ptr_fx[i], guard_bits ); + } + else + { + mat_mult_buffer1_fx[i] = L_shr( mat_mult_buffer1_fx[i], guard_bits ); + } + } + + if ( mat_mult_buffer1_e > proto_matrix_ptr_e ) + { + proto_matrix_ptr_e += guard_bits; + } + else + { + mat_mult_buffer1_e += guard_bits; + } + + matrix_product_diag_fx(mat_mult_buffer1_fx, mat_mult_buffer1_e, nY_band, nX, 0, proto_matrix_ptr_fx, proto_matrix_ptr_e, nY_band, nX, 1, Cproto_diag_fx,&Cproto_diag_e); + + me2f_buf(Cproto_diag_fx, Cproto_diag_e, Cproto_diag, nY_band); +#else matrix_product_diag( mat_mult_buffer1, nY_band, nX, 0, proto_matrix_ptr, nY_band, nX, 1, Cproto_diag ); +#endif /* make sure we have no negative entries in Cproto_diag due to rounding errors */ for ( ch_idx1 = 0; ch_idx1 < nY_band; ch_idx1++ ) @@ -2487,7 +2524,21 @@ static void ivas_param_mc_get_mixing_matrices( Cy_diag[i] = sqrtf( Cy_diag[i] / ( Cproto_diag[i] + EPSILON ) ); } +#ifdef IVAS_FLOAT_FIXED + Word32 Cy_diag_fx[MAX_OUTPUT_CHANNELS]; + Word32 proto_matrix_ptr_fx[PARAM_MC_MAX_TRANSPORT_CHANS * MAX_CICP_CHANNELS]; + Word32 mixing_matrix_local_fx[MAX_CICP_CHANNELS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word16 Cy_diag_e, proto_matrix_ptr_e, mixing_matrix_local_e; + + f2me_buf( Cy_diag, Cy_diag_fx, &Cy_diag_e, nY_band ); + f2me_buf( proto_matrix_ptr, proto_matrix_ptr_fx, &proto_matrix_ptr_e, nY_band * nX ); + + diag_matrix_product_fx( Cy_diag_fx, Cy_diag_e, nY_band, proto_matrix_ptr_fx, proto_matrix_ptr_e, nY_band, nX, 0, mixing_matrix_local_fx, &mixing_matrix_local_e ); + + me2f_buf( mixing_matrix_local_fx, mixing_matrix_local_e, mixing_matrix_local, nY_band * nX ); +#else diag_matrix_product( Cy_diag, nY_band, proto_matrix_ptr, nY_band, nX, 0, mixing_matrix_local ); +#endif } if ( remove_lfe ) { @@ -2547,6 +2598,14 @@ static void ivas_param_mc_get_mono_stereo_mixing_matrices( int16_t nY_band; float proto_matrix[PARAM_MC_MAX_TRANSPORT_CHANS * MAX_CICP_CHANNELS]; uint16_t i; +#ifdef IVAS_FLOAT_FIXED + Word32 Cy_diag_fx[MAX_OUTPUT_CHANNELS]; + Word32 proto_matrix_fx[PARAM_MC_MAX_TRANSPORT_CHANS * MAX_CICP_CHANNELS]; + Word32 mixing_matrix_woLFE_fx[MAX_CICP_CHANNELS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word32 mat_mult_buffer1_fx[MAX_CICP_CHANNELS * MAX_CICP_CHANNELS]; + Word32 Cproto_diag_fx[MAX_CICP_CHANNELS]; + Word16 Cy_diag_e, proto_matrix_e, mixing_matrix_woLFE_e, mat_mult_buffer1_e, Cproto_diag_e; +#endif set_zero( Cproto, MAX_CICP_CHANNELS * MAX_CICP_CHANNELS ); set_zero( mat_mult_buffer1, MAX_CICP_CHANNELS * MAX_CICP_CHANNELS ); @@ -2618,7 +2677,39 @@ static void ivas_param_mc_get_mono_stereo_mixing_matrices( matrix_product( proto_matrix, nY_band, nX, 0, Cx, nX, nX, 0, mat_mult_buffer1 ); +#ifdef IVAS_FLOAT_FIXED + Word16 guard_bits = find_guarded_bits_fx( nY_band + 1 ); + + f2me_buf( mat_mult_buffer1, mat_mult_buffer1_fx, &mat_mult_buffer1_e, nY_band * nX ); + f2me_buf( proto_matrix, proto_matrix_fx, &proto_matrix_e, nY_band * nX ); + + for ( i = 0; i < nY_band * nX; ++i ) + { + if ( mat_mult_buffer1_e > proto_matrix_e ) + { + proto_matrix_fx[i] = L_shr( proto_matrix_fx[i], guard_bits ); + } + else + { + mat_mult_buffer1_fx[i] = L_shr( mat_mult_buffer1_fx[i], guard_bits ); + } + } + + if ( mat_mult_buffer1_e > proto_matrix_e ) + { + proto_matrix_e += guard_bits; + } + else + { + mat_mult_buffer1_e += guard_bits; + } + + matrix_product_diag_fx( mat_mult_buffer1_fx, mat_mult_buffer1_e, nY_band, nX, 0, proto_matrix_fx, proto_matrix_e, nY_band, nX, 1, Cproto_diag_fx, &Cproto_diag_e ); + + me2f_buf( Cproto_diag_fx, Cproto_diag_e, Cproto_diag, nY_band ); +#else matrix_product_diag( mat_mult_buffer1, nY_band, nX, 0, proto_matrix, nY_band, nX, 1, Cproto_diag ); +#endif /* Computing the mixing matrices */ for ( i = 0; i < nY_band; i++ ) @@ -2627,7 +2718,16 @@ static void ivas_param_mc_get_mono_stereo_mixing_matrices( Cy_diag[i] = sqrtf( Cy_diag[i] / ( Cproto_diag[i] + EPSILON ) ); } +#ifdef IVAS_FLOAT_FIXED + f2me_buf( Cy_diag, Cy_diag_fx, &Cy_diag_e, nY_band ); + f2me_buf( proto_matrix, proto_matrix_fx, &proto_matrix_e, nY_band * nX ); + + diag_matrix_product_fx( Cy_diag_fx, Cy_diag_e, nY_band, proto_matrix_fx, proto_matrix_e, nY_band, nX, 0, mixing_matrix_woLFE_fx, &mixing_matrix_woLFE_e ); + + me2f_buf( mixing_matrix_woLFE_fx, mixing_matrix_woLFE_e, mixing_matrix_woLFE, nY_band * nX ); +#else diag_matrix_product( Cy_diag, nY_band, proto_matrix, nY_band, nX, 0, mixing_matrix_woLFE ); +#endif mvr2r( mixing_matrix_woLFE, mixing_matrix[param_band_idx], nY_cov * nX ); if ( hParamMC->band_grouping[param_band_idx] < hParamMC->h_output_synthesis_params.max_band_decorr ) diff --git a/lib_dec/ivas_out_setup_conversion.c b/lib_dec/ivas_out_setup_conversion.c index e713af665..4ac9e15af 100644 --- a/lib_dec/ivas_out_setup_conversion.c +++ b/lib_dec/ivas_out_setup_conversion.c @@ -1881,7 +1881,49 @@ void ivas_ls_setup_conversion_process_mdct_param_mc( } } +#ifdef IVAS_FLOAT_FIXED + Word32 real_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS]; + Word32 imag_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS]; + Word32 real_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word32 imag_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS]; + Word16 real_exp, imag_exp, input_exp, output_exp; + Word16 shift = find_guarded_bits_fx( num_bands + 1 ); + + f2me_buf( real_in_buffer, real_in_buffer_fx, &real_exp, num_bands * nchan_transport ); + f2me_buf( imag_in_buffer, imag_in_buffer_fx, &imag_exp, num_bands * nchan_transport ); + + IF( real_exp > imag_exp ) + { + FOR( Word16 i = 0; i < num_bands * nchan_transport; ++i ) + { + imag_in_buffer_fx[i] = L_shr( imag_in_buffer_fx[i], real_exp - imag_exp ); + } + input_exp = real_exp; + } + ELSE + { + FOR( Word16 i = 0; i < num_bands * nchan_transport; ++i ) + { + real_in_buffer_fx[i] = L_shr( real_in_buffer_fx[i], imag_exp - real_exp ); + } + input_exp = imag_exp; + } + + FOR( Word16 i = 0; i < num_bands * nchan_transport; ++i ) + { + real_in_buffer_fx[i] = L_shr( real_in_buffer_fx[i], shift ); + imag_in_buffer_fx[i] = L_shr( imag_in_buffer_fx[i], shift ); + } + + input_exp += shift; + + cmplx_matrix_square_fx( real_in_buffer_fx, imag_in_buffer_fx, num_bands, nchan_transport, real_buffer_fx, imag_buffer_fx, input_exp, &output_exp ); + + me2f_buf( real_buffer_fx, output_exp, real_buffer, nchan_transport * nchan_transport ); + me2f_buf( imag_buffer_fx, output_exp, imag_buffer, nchan_transport * nchan_transport ); +#else cmplx_matrix_square( real_in_buffer, imag_in_buffer, num_bands, nchan_transport, real_buffer, imag_buffer ); +#endif v_add( cx[bandIdx], real_buffer, cx[bandIdx], nchan_transport * nchan_transport ); -- GitLab