Loading lib_dec/jbm_pcmdsp_apa.c +439 −2 Original line number Diff line number Diff line Loading @@ -151,8 +151,12 @@ static bool copy_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[ static bool shrink_frm_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], UWord16 *l_frm_out ); static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out ); static bool extend_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out ); static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out ); /*---------------------------------------------------------------------* * Public functions *---------------------------------------------------------------------*/ Loading Loading @@ -991,12 +995,12 @@ UWord8 apa_exec_ivas_fx( /* shrink */ ELSE IF( LT_32( ps->scale, 100 ) ) { shrink_frm_fx( ps, frm_in, maxScaling, a_tmp, &l_frm_out ); shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out ); } /* extend */ ELSE { extend_frm_fx( ps, frm_in, a_tmp, &l_frm_out ); extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out ); } /* control the amount/frequency of scaling */ IF( NE_32( l_frm_out, ps->l_frm ) ) Loading Loading @@ -1721,6 +1725,180 @@ static bool shrink_frm_fx( return 0; } static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in_fx[], // Qx UWord16 maxScaling, Word16 frm_out_fx[], // Qx Word16 Q_frm_in, UWord16 *l_frm_out ) { bool findSynchResult = 0; move16(); Word16 xtract, l_rem, s_start, s_end; UWord16 i; UWord16 over; Word16 energy_fx = 0; Word32 quality_fx = 0; UWord16 l_frm; UWord16 l_seg; move16(); move32(); l_frm = ps->l_frm; move16(); l_seg = ps->l_seg; move16(); /* only 2nd input frame is used */ frm_in_fx += l_frm; /* set search range */ // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels; Word16 tmp, tmp_e; tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e ); tmp = shr( tmp, sub( 15, tmp_e ) ); s_start = i_mult( tmp, extract_l( ps->num_channels ) ); s_end = add( s_start, extract_l( ps->l_search ) ); IF( GE_32( L_add( s_end, l_seg ), l_frm ) ) { s_end = extract_l( L_sub( l_frm, l_seg ) ); } /* calculate overlap position */ IF( isSilence_fx( frm_in_fx, l_seg, 10 ) ) { /* maximum scaling */ energy_fx = -65 * ( 1 << 8 ); // Q8 move16(); quality_fx = 5 << Q16; // Q16 move32(); IF( ps->evs_compat_mode == false ) { xtract = maxScaling; move16(); /* take samples already in the renderer buf into account */ xtract = add( xtract, extract_l( ps->l_r_buf ) ); /* snap to renderer time slot borders */ xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) ); WHILE( xtract < 0 ) { xtract = add( xtract, extract_l( ps->l_ts ) ); } WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) ) { /* exceeded the possible shrinking, go back one renderer ts*/ xtract = sub( xtract, extract_l( ps->l_ts ) ); } } ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) ) { xtract = maxScaling; move16(); } ELSE { /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */ xtract = sub( s_end, extract_l( ps->num_channels ) ); } } ELSE { /* find synch */ scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation ); ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in ); move16(); findSynchResult = find_synch_fx( ps, ps->frmInScaled, l_frm, s_start, (UWord16) ( sub( s_end, s_start ) ), 0, l_seg, 0, &energy_fx, &quality_fx, &xtract ); ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in ); move16(); } /* assert synch_pos is cleanly divisible by number of channels */ assert( xtract % ps->num_channels == 0 ); /* set frame overlappable - reset if necessary */ over = 1; move16(); /* test whether frame has sufficient quality */ IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx, L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ), L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) ) { /* not sufficient */ over = 0; move16(); IF( LT_32( ps->bad_frame_count, ps->qualityred ) ) { ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( GT_32( ps->good_frame_count, 0 ) ) { ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) ); move16(); } } ELSE { /* sufficient quality */ IF( ps->bad_frame_count > 0 ) { ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( LT_32( ps->good_frame_count, ps->qualityrise ) ) { ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) ); move16(); } } /* Calculate output data */ test(); IF( over && xtract ) { IF( findSynchResult == 1 ) { return 1; } IF( EQ_16( ps->evs_compat_mode, true ) ) { // overlapAddEvs_fx( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx ); overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } ELSE { overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } } ELSE { xtract = 0; move16(); FOR( i = 0; i < l_seg; i++ ) { frm_out_fx[i] = frm_in_fx[i]; move16(); } } /* append remaining samples */ l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) ); FOR( i = 0; i < l_rem; i++ ) { frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i]; move16(); } /* set output length */ *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) ); move16(); return 0; } /* ******************************************************************************** * Loading Loading @@ -1994,3 +2172,262 @@ static bool extend_frm_fx( move16(); return 0; } static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in_fx[], // Qx Word16 frm_out_fx[], // Qx Word16 Q_frm_in, UWord16 *l_frm_out ) { bool findSynchResult = 0; move16(); UWord16 l_frm_out_target; UWord16 n, i; Word16 N; Word16 s[MAXN + 2], s_max, s_min; Word16 xtract[MAXN + 2], sync_start, s_end; UWord16 over[MAXN + 2]; Word16 l_rem; Word16 s_start = 0; move16(); Word16 energy_fx; Word32 quality_fx = 0; move32(); UWord16 l_frm, l_seg; const Word16 *fadeOut_fx, *fadeIn_fx; Word16 *out_fx; l_frm = ps->l_frm; l_seg = ps->l_seg; move16(); move16(); /* number of segments/iterations */ l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) ); //(l_frm_out_target/l_seg -1 ) Word16 tmp, tmp_e; tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e ); tmp = shr( tmp, sub( 15, tmp_e ) ); N = sub( ( tmp ), 1 ); if ( LT_16( N, 1 ) ) { N = 1; move16(); } IF( GT_16( N, MAXN ) ) { return 1; } /* calculate equally spaced search regions */ /* s[n] are given relative to 2nd frame and point to the start of */ /* the search region. The first segment (n=1) will not be moved. */ /* Hence, the iterations will start with n=2. */ s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) ); /* (make sure not to exceed array dimension) */ IF( L_add( l_frm, s_min ) < 0 ) { s_min = extract_l( L_negate( l_frm ) ); } s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) ); if ( s_max < s_min ) { N = 1; move16(); } /* for just one segment start at s_min */ if ( N == 1 ) { s[2] = s_min; move16(); } /* else, spread linear in between s_min and s_max */ /* (including s_min and s_max) */ ELSE { FOR( n = 2; n <= ( N + 1 ); n++ ) { // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 ); Word16 tmp2, tmp2_e; tmp2 = sub( s_max, s_min ); tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) ); tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e ); tmp2 = shr( tmp2, sub( 15, tmp2_e ) ); s[n] = add( s_min, tmp2 ); move16(); } } /* * Planning Phase */ xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */ move16(); n = 2; move16(); /* define synch segment (to be correlated with search region) */ sync_start = extract_l( L_add( xtract[n - 1], l_seg ) ); over[n] = 1; /* will be reset if overlap is not required */ move16(); /* check end of search region: should be at least p_min */ /* samples on the left of synch_start */ IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) ) { s_start = s[n]; move16(); s_end = extract_l( L_add( s_start, ps->l_search ) ); } ELSE { /* shrink search region to enforce minimum shift */ s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) ); IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) ) { s_start = s[n]; /* just do it with normal start position */ move16(); } ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */ { s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) ); } ELSE { over[n] = 0; /* don't search/overlap (just copy down) */ move16(); } } IF( over[n] ) { /* calculate overlap position */ IF( isSilence_fx( frm_in_fx, l_seg, 10 ) ) { /* maximum scaling */ energy_fx = -65 * ( 1 << 8 ); // Q8 move16(); quality_fx = 5 << 16; // Q16 move32(); xtract[n] = extract_l( L_add( s_start, ps->num_channels ) ); move16(); IF( ps->evs_compat_mode == false ) { /* take renderer buffer samples into accout */ xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) ); /* snap to next renderer time slot border to resynchronize */ // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts; Word16 tmp3; tmp3 = extract_l( L_add( L_sub( W_extract_l( W_mult0_32_32( L_sub( N, 1 ), l_seg ) ), xtract[n] ), ps->l_r_buf ) ); xtract[n] = sub( xtract[n], tmp3 % ps->l_ts ); move16(); move16(); } } ELSE { Word16 *frmInScaled; frmInScaled = ps->frmInScaled; assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm ); scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation ); ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in ); findSynchResult = find_synch_fx( ps, frmInScaled, extract_l( L_shl( l_frm, 1 ) ), s_start, sub( s_end, s_start ), sync_start, l_seg, l_frm, &energy_fx, &quality_fx, &xtract[n] ); ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in ); } /* assert synch_pos is cleanly divisible by number of channels */ assert( xtract[n] % ps->num_channels == 0 ); /* test for sufficient quality */ IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx, L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ), L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) ) { /* not sufficient */ over[n] = 0; move16(); xtract[n] = sync_start; move16(); IF( LT_32( ps->bad_frame_count, ps->qualityred ) ) { ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( GT_32( ps->good_frame_count, 0 ) ) { ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) ); move16(); } } ELSE { /* sufficient quality */ IF( GT_32( ps->bad_frame_count, 0 ) ) { ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( LT_32( ps->good_frame_count, ps->qualityrise ) ) { ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) ); move16(); } } IF( findSynchResult ) { return 1; } } ELSE { xtract[n] = sync_start; move16(); } /* Calculate output data */ FOR( n = 2; n <= N; n++ ) { test(); IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) ) { /* mix 2nd half of previous segment with 1st half of current segment */ fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg; fadeIn_fx = frm_in_fx + l_frm + xtract[n]; out_fx = frm_out_fx + ( n - 2 ) * l_seg; IF( EQ_16( ps->evs_compat_mode, true ) ) { // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx ); overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } ELSE { overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } } ELSE { /* just copy down 1st half of current segment (= 2nd half of previous segment) */ Word16 *frm_out_ptr; const Word16 *frm_in_ptr; frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] ); frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] ); FOR( i = 0; i < l_seg; i++ ) { frm_out_ptr[i] = frm_in_ptr[i]; move16(); } } } /* append remaining samples */ l_rem = l_frm - ( xtract[N] + l_seg ); FOR( i = 0; i < l_rem; i++ ) { frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i]; move16(); } /* set output length */ *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) ); move16(); return 0; } Loading
lib_dec/jbm_pcmdsp_apa.c +439 −2 Original line number Diff line number Diff line Loading @@ -151,8 +151,12 @@ static bool copy_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[ static bool shrink_frm_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], UWord16 *l_frm_out ); static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out ); static bool extend_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out ); static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out ); /*---------------------------------------------------------------------* * Public functions *---------------------------------------------------------------------*/ Loading Loading @@ -991,12 +995,12 @@ UWord8 apa_exec_ivas_fx( /* shrink */ ELSE IF( LT_32( ps->scale, 100 ) ) { shrink_frm_fx( ps, frm_in, maxScaling, a_tmp, &l_frm_out ); shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out ); } /* extend */ ELSE { extend_frm_fx( ps, frm_in, a_tmp, &l_frm_out ); extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out ); } /* control the amount/frequency of scaling */ IF( NE_32( l_frm_out, ps->l_frm ) ) Loading Loading @@ -1721,6 +1725,180 @@ static bool shrink_frm_fx( return 0; } static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in_fx[], // Qx UWord16 maxScaling, Word16 frm_out_fx[], // Qx Word16 Q_frm_in, UWord16 *l_frm_out ) { bool findSynchResult = 0; move16(); Word16 xtract, l_rem, s_start, s_end; UWord16 i; UWord16 over; Word16 energy_fx = 0; Word32 quality_fx = 0; UWord16 l_frm; UWord16 l_seg; move16(); move32(); l_frm = ps->l_frm; move16(); l_seg = ps->l_seg; move16(); /* only 2nd input frame is used */ frm_in_fx += l_frm; /* set search range */ // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels; Word16 tmp, tmp_e; tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e ); tmp = shr( tmp, sub( 15, tmp_e ) ); s_start = i_mult( tmp, extract_l( ps->num_channels ) ); s_end = add( s_start, extract_l( ps->l_search ) ); IF( GE_32( L_add( s_end, l_seg ), l_frm ) ) { s_end = extract_l( L_sub( l_frm, l_seg ) ); } /* calculate overlap position */ IF( isSilence_fx( frm_in_fx, l_seg, 10 ) ) { /* maximum scaling */ energy_fx = -65 * ( 1 << 8 ); // Q8 move16(); quality_fx = 5 << Q16; // Q16 move32(); IF( ps->evs_compat_mode == false ) { xtract = maxScaling; move16(); /* take samples already in the renderer buf into account */ xtract = add( xtract, extract_l( ps->l_r_buf ) ); /* snap to renderer time slot borders */ xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) ); WHILE( xtract < 0 ) { xtract = add( xtract, extract_l( ps->l_ts ) ); } WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) ) { /* exceeded the possible shrinking, go back one renderer ts*/ xtract = sub( xtract, extract_l( ps->l_ts ) ); } } ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) ) { xtract = maxScaling; move16(); } ELSE { /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */ xtract = sub( s_end, extract_l( ps->num_channels ) ); } } ELSE { /* find synch */ scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation ); ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in ); move16(); findSynchResult = find_synch_fx( ps, ps->frmInScaled, l_frm, s_start, (UWord16) ( sub( s_end, s_start ) ), 0, l_seg, 0, &energy_fx, &quality_fx, &xtract ); ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in ); move16(); } /* assert synch_pos is cleanly divisible by number of channels */ assert( xtract % ps->num_channels == 0 ); /* set frame overlappable - reset if necessary */ over = 1; move16(); /* test whether frame has sufficient quality */ IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx, L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ), L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) ) { /* not sufficient */ over = 0; move16(); IF( LT_32( ps->bad_frame_count, ps->qualityred ) ) { ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( GT_32( ps->good_frame_count, 0 ) ) { ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) ); move16(); } } ELSE { /* sufficient quality */ IF( ps->bad_frame_count > 0 ) { ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( LT_32( ps->good_frame_count, ps->qualityrise ) ) { ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) ); move16(); } } /* Calculate output data */ test(); IF( over && xtract ) { IF( findSynchResult == 1 ) { return 1; } IF( EQ_16( ps->evs_compat_mode, true ) ) { // overlapAddEvs_fx( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx ); overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } ELSE { overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } } ELSE { xtract = 0; move16(); FOR( i = 0; i < l_seg; i++ ) { frm_out_fx[i] = frm_in_fx[i]; move16(); } } /* append remaining samples */ l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) ); FOR( i = 0; i < l_rem; i++ ) { frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i]; move16(); } /* set output length */ *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) ); move16(); return 0; } /* ******************************************************************************** * Loading Loading @@ -1994,3 +2172,262 @@ static bool extend_frm_fx( move16(); return 0; } static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in_fx[], // Qx Word16 frm_out_fx[], // Qx Word16 Q_frm_in, UWord16 *l_frm_out ) { bool findSynchResult = 0; move16(); UWord16 l_frm_out_target; UWord16 n, i; Word16 N; Word16 s[MAXN + 2], s_max, s_min; Word16 xtract[MAXN + 2], sync_start, s_end; UWord16 over[MAXN + 2]; Word16 l_rem; Word16 s_start = 0; move16(); Word16 energy_fx; Word32 quality_fx = 0; move32(); UWord16 l_frm, l_seg; const Word16 *fadeOut_fx, *fadeIn_fx; Word16 *out_fx; l_frm = ps->l_frm; l_seg = ps->l_seg; move16(); move16(); /* number of segments/iterations */ l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) ); //(l_frm_out_target/l_seg -1 ) Word16 tmp, tmp_e; tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e ); tmp = shr( tmp, sub( 15, tmp_e ) ); N = sub( ( tmp ), 1 ); if ( LT_16( N, 1 ) ) { N = 1; move16(); } IF( GT_16( N, MAXN ) ) { return 1; } /* calculate equally spaced search regions */ /* s[n] are given relative to 2nd frame and point to the start of */ /* the search region. The first segment (n=1) will not be moved. */ /* Hence, the iterations will start with n=2. */ s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) ); /* (make sure not to exceed array dimension) */ IF( L_add( l_frm, s_min ) < 0 ) { s_min = extract_l( L_negate( l_frm ) ); } s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) ); if ( s_max < s_min ) { N = 1; move16(); } /* for just one segment start at s_min */ if ( N == 1 ) { s[2] = s_min; move16(); } /* else, spread linear in between s_min and s_max */ /* (including s_min and s_max) */ ELSE { FOR( n = 2; n <= ( N + 1 ); n++ ) { // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 ); Word16 tmp2, tmp2_e; tmp2 = sub( s_max, s_min ); tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) ); tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e ); tmp2 = shr( tmp2, sub( 15, tmp2_e ) ); s[n] = add( s_min, tmp2 ); move16(); } } /* * Planning Phase */ xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */ move16(); n = 2; move16(); /* define synch segment (to be correlated with search region) */ sync_start = extract_l( L_add( xtract[n - 1], l_seg ) ); over[n] = 1; /* will be reset if overlap is not required */ move16(); /* check end of search region: should be at least p_min */ /* samples on the left of synch_start */ IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) ) { s_start = s[n]; move16(); s_end = extract_l( L_add( s_start, ps->l_search ) ); } ELSE { /* shrink search region to enforce minimum shift */ s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) ); IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) ) { s_start = s[n]; /* just do it with normal start position */ move16(); } ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */ { s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) ); } ELSE { over[n] = 0; /* don't search/overlap (just copy down) */ move16(); } } IF( over[n] ) { /* calculate overlap position */ IF( isSilence_fx( frm_in_fx, l_seg, 10 ) ) { /* maximum scaling */ energy_fx = -65 * ( 1 << 8 ); // Q8 move16(); quality_fx = 5 << 16; // Q16 move32(); xtract[n] = extract_l( L_add( s_start, ps->num_channels ) ); move16(); IF( ps->evs_compat_mode == false ) { /* take renderer buffer samples into accout */ xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) ); /* snap to next renderer time slot border to resynchronize */ // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts; Word16 tmp3; tmp3 = extract_l( L_add( L_sub( W_extract_l( W_mult0_32_32( L_sub( N, 1 ), l_seg ) ), xtract[n] ), ps->l_r_buf ) ); xtract[n] = sub( xtract[n], tmp3 % ps->l_ts ); move16(); move16(); } } ELSE { Word16 *frmInScaled; frmInScaled = ps->frmInScaled; assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm ); scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation ); ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in ); findSynchResult = find_synch_fx( ps, frmInScaled, extract_l( L_shl( l_frm, 1 ) ), s_start, sub( s_end, s_start ), sync_start, l_seg, l_frm, &energy_fx, &quality_fx, &xtract[n] ); ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in ); } /* assert synch_pos is cleanly divisible by number of channels */ assert( xtract[n] % ps->num_channels == 0 ); /* test for sufficient quality */ IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx, L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ), L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) ) { /* not sufficient */ over[n] = 0; move16(); xtract[n] = sync_start; move16(); IF( LT_32( ps->bad_frame_count, ps->qualityred ) ) { ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( GT_32( ps->good_frame_count, 0 ) ) { ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) ); move16(); } } ELSE { /* sufficient quality */ IF( GT_32( ps->bad_frame_count, 0 ) ) { ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) ); move16(); } IF( LT_32( ps->good_frame_count, ps->qualityrise ) ) { ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) ); move16(); } } IF( findSynchResult ) { return 1; } } ELSE { xtract[n] = sync_start; move16(); } /* Calculate output data */ FOR( n = 2; n <= N; n++ ) { test(); IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) ) { /* mix 2nd half of previous segment with 1st half of current segment */ fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg; fadeIn_fx = frm_in_fx + l_frm + xtract[n]; out_fx = frm_out_fx + ( n - 2 ) * l_seg; IF( EQ_16( ps->evs_compat_mode, true ) ) { // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx ); overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } ELSE { overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor ); } } ELSE { /* just copy down 1st half of current segment (= 2nd half of previous segment) */ Word16 *frm_out_ptr; const Word16 *frm_in_ptr; frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] ); frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] ); FOR( i = 0; i < l_seg; i++ ) { frm_out_ptr[i] = frm_in_ptr[i]; move16(); } } } /* append remaining samples */ l_rem = l_frm - ( xtract[N] + l_seg ); FOR( i = 0; i < l_rem; i++ ) { frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i]; move16(); } /* set output length */ *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) ); move16(); return 0; }