LCOV - code coverage report
Current view: top level - lib_dec - jbm_pcmdsp_apa_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main @ da9cc8ead0679b4682d329fdff98cf1616159273 Lines: 555 929 59.7 %
Date: 2025-10-13 22:24:20 Functions: 19 23 82.6 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : /*====================================================================================
      34             :     EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
      35             :   ====================================================================================*/
      36             : 
      37             : /*! @file jbm_pcmdsp_apa.c Adaptive Playout for Audio (apa). */
      38             : 
      39             : /* system headers */
      40             : #include <assert.h>
      41             : #include <math.h>
      42             : #include <stdlib.h>
      43             : #include <stdio.h>
      44             : #include <stdint.h>
      45             : #include <string.h>
      46             : #include "options.h"
      47             : #include "prot_fx.h"
      48             : #include "wmc_auto.h"
      49             : /* local headers */
      50             : #include "jbm_pcmdsp_apa.h"
      51             : #include "jbm_pcmdsp_similarityestimation.h"
      52             : #include "jbm_pcmdsp_window.h"
      53             : #include "cnst.h"
      54             : #include "rom_dec.h"
      55             : 
      56             : 
      57             : #define INV_100_Q15 328
      58             : #define INV_400_Q15 82
      59             : #define INV_80_Q15  410
      60             : 
      61             : 
      62             : /*---------------------------------------------------------------------*
      63             :  * Local state structure
      64             :  *---------------------------------------------------------------------*/
      65             : 
      66             : /* maximum number of segments/iterations in extend_frm() */
      67             : #define MAXN 10
      68             : 
      69             : /* definition of state struct */
      70             : struct apa_state_t
      71             : {
      72             :     Word16 signalScaleForCorrelation;
      73             :     Word16 frmInScaled[6 * 2 * 48000 / 50 * 2];
      74             : 
      75             :     /* output buffer */
      76             :     bool evs_compat_mode;
      77             : 
      78             :     Word16 *buf_out_fx;
      79             :     Word16 Q_buf_out; /* stores the scaling of buf_out_fx */
      80             : #ifdef FIX1998_APA_EXEC_SCALING
      81             :     Word16 Q_a_out_init_old; /* stores initially determined max. scaling of data in buf_out_fx, before beeing adjusted to previous frame scaling */
      82             : #endif
      83             :     UWord16 buf_out_capacity;
      84             :     UWord16 l_buf_out;
      85             : 
      86             :     /* Hann window */
      87             :     const Word16 *win_fx;
      88             :     // const Word16 *win_fx;
      89             :     UWord16 l_halfwin;
      90             : 
      91             :     Word16 win_incrementor;
      92             : 
      93             :     /* sampling rate [Hz] */
      94             :     UWord16 rate;
      95             : 
      96             :     /* length of a segment [samples] */
      97             :     UWord16 l_seg;
      98             : 
      99             :     /* length of a frame [samples] */
     100             :     UWord16 l_frm;
     101             : 
     102             :     /* total number of processed input samples since apa_reset() */
     103             :     UWord32 l_in_total;
     104             : 
     105             :     /* time resolution in samples of the IVAS renderer*/
     106             :     UWord16 l_ts;
     107             : 
     108             :     /* samples already available in the renderer buffer */
     109             :     UWord16 l_r_buf;
     110             : 
     111             :     /* sum of inserted/removed samples since last apa_set_scale() */
     112             :     Word32 diffSinceSetScale;
     113             :     /* number of input frames since last apa_set_scale() */
     114             :     UWord32 nFramesSinceSetScale;
     115             : 
     116             :     /* current and previous  scaling ratio [%] */
     117             :     UWord16 scale;
     118             : 
     119             :     /* minimum pitch length [samples] */
     120             :     UWord16 p_min;
     121             : 
     122             :     /* search length [samples] */
     123             :     UWord16 l_search;
     124             : 
     125             :     UWord16 wss; /* waveform subsampling per channel */
     126             :     UWord16 css; /* correlation subsampling per channel */
     127             : 
     128             :     Word32 targetQuality_fx; /* Q16 */
     129             :     UWord16 qualityred;      /* quality reduction threshold */
     130             :     UWord16 qualityrise;     /* quality rising for adaptive quality thresholds */
     131             : 
     132             :     UWord16 last_pitch;       /* last pitch/sync position */
     133             :     UWord16 bad_frame_count;  /* # frames before quality threshold is lowered */
     134             :     UWord16 good_frame_count; /* # scaled frames */
     135             : 
     136             :     UWord16 num_channels; /* number of input/output channels */
     137             : };
     138             : 
     139             : 
     140             : /*---------------------------------------------------------------------*
     141             :  * Local function prototypes
     142             :  *---------------------------------------------------------------------*/
     143             : 
     144             : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len );
     145             : 
     146             : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydB );
     147             : 
     148             : static Word8 logarithmic_search_fx( const apa_state_t *ps, const Word16 *signal, Word16 s_start, Word16 inlen, Word16 offset, Word16 fixed_pos, Word16 corr_len, Word16 wss, Word16 css, Word16 *synchpos );
     149             : 
     150             : static Word16 find_synch_fx( apa_state_t *ps, const Word16 *in, Word16 l_in, Word16 s_start, Word16 s_len, Word16 fixed_pos, Word16 corr_len, Word16 offset, Word16 *energydBQ8, Word32 *qualityQ16, Word16 *synch_pos );
     151             : 
     152             : static bool copy_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out );
     153             : 
     154             : static bool shrink_frm_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], UWord16 *l_frm_out );
     155             : 
     156             : 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 );
     157             : 
     158             : static bool extend_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out );
     159             : 
     160             : 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 );
     161             : 
     162             : /*---------------------------------------------------------------------*
     163             :  * Public functions
     164             :  *---------------------------------------------------------------------*/
     165             : 
     166             : /* Allocates memory for state struct and initializes elements. */
     167          28 : ivas_error apa_init(
     168             :     apa_state_t **pps,
     169             :     const Word32 num_channels )
     170             : {
     171          28 :     apa_state_t *ps = NULL;
     172             : 
     173             :     /* make sure pointer is valid */
     174          28 :     IF( !pps )
     175             :     {
     176           0 :         return 1;
     177             :     }
     178             : 
     179             :     /* allocate state struct */
     180          28 :     IF( ( ps = (apa_state_t *) malloc( sizeof( apa_state_t ) ) ) == NULL )
     181             :     {
     182           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
     183             :     }
     184             : 
     185          28 :     ps->num_channels = (UWord16) num_channels;
     186          28 :     move16();
     187          28 :     ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
     188          28 :     move16();
     189             : 
     190          28 :     IF( ( ps->buf_out_fx = malloc( sizeof( Word16 ) * ps->buf_out_capacity ) ) == NULL )
     191             :     {
     192           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
     193             :     }
     194          28 :     memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
     195          28 :     ps->Q_buf_out = Q15;
     196             : #ifdef FIX1998_APA_EXEC_SCALING
     197          28 :     ps->Q_a_out_init_old = Q15;
     198          28 :     move16();
     199             : #endif
     200          28 :     move16();
     201             : 
     202          28 :     ps->evs_compat_mode = false;
     203          28 :     move16();
     204             : 
     205          28 :     apa_reset( ps );
     206          28 :     *pps = ps;
     207             : 
     208          28 :     return IVAS_ERR_OK;
     209             : }
     210             : 
     211             : 
     212             : /* Sets state variables to initial value. */
     213          56 : void apa_reset(
     214             :     apa_state_t *ps )
     215             : {
     216             :     /* init state struct */
     217          56 :     ps->signalScaleForCorrelation = 0;
     218          56 :     move16();
     219          56 :     ps->l_buf_out = 0;
     220          56 :     move16();
     221          56 :     ps->l_halfwin = 0;
     222          56 :     move16();
     223          56 :     ps->rate = 0;
     224          56 :     move16();
     225          56 :     ps->l_seg = 0;
     226          56 :     move16();
     227          56 :     ps->l_frm = 0;
     228          56 :     move16();
     229          56 :     ps->l_in_total = 0;
     230          56 :     move32();
     231          56 :     ps->diffSinceSetScale = 0;
     232          56 :     move32();
     233          56 :     ps->nFramesSinceSetScale = 0;
     234          56 :     move32();
     235          56 :     ps->scale = 100;
     236          56 :     move16();
     237          56 :     ps->p_min = 0;
     238          56 :     move16();
     239          56 :     ps->l_search = 0;
     240          56 :     move16();
     241          56 :     ps->wss = 1;
     242          56 :     move16();
     243          56 :     ps->css = 1;
     244          56 :     move16();
     245          56 :     ps->targetQuality_fx = 0;
     246          56 :     move32();
     247             : 
     248          56 :     ps->qualityred = 0;
     249          56 :     move16();
     250          56 :     ps->qualityrise = 0;
     251          56 :     move16();
     252          56 :     ps->last_pitch = 0;
     253          56 :     move16();
     254          56 :     ps->bad_frame_count = 0;
     255          56 :     move16();
     256          56 :     ps->good_frame_count = 0;
     257          56 :     move16();
     258             : 
     259          56 :     ps->l_ts = 1;
     260          56 :     move16();
     261          56 :     ps->l_r_buf = 0;
     262          56 :     move16();
     263          56 :     return;
     264             : }
     265             : 
     266         941 : UWord8 apa_reconfigure(
     267             :     apa_state_t *ps,
     268             :     UWord16 num_channels,
     269             :     UWord16 l_ts )
     270             : {
     271             : 
     272             :     /* realloc buffer */
     273         941 :     ps->num_channels = (UWord16) num_channels;
     274         941 :     move16();
     275         941 :     ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
     276         941 :     move16();
     277             : 
     278         941 :     free( ps->buf_out_fx );
     279         941 :     ps->buf_out_fx = (Word16 *) malloc( sizeof( Word16 ) * ps->buf_out_capacity );
     280         941 :     memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
     281         941 :     ps->Q_buf_out = Q15;
     282             : #ifdef FIX1998_APA_EXEC_SCALING
     283         941 :     ps->Q_a_out_init_old = Q15;
     284         941 :     move16();
     285             : #endif
     286         941 :     move16();
     287         941 :     IF( !ps->buf_out_fx )
     288             :     {
     289           0 :         return 2;
     290             :     }
     291             : 
     292         941 :     ps->l_buf_out = 0;
     293         941 :     ps->l_in_total = 0;
     294         941 :     move16();
     295         941 :     move32();
     296         941 :     ps->l_ts = (UWord16) imult3216( l_ts, ps->num_channels );
     297         941 :     move16();
     298             : 
     299             :     /* set everything else dependent on the number of channels */
     300             :     /* set segment size */
     301             :     /* in the order of a pitch, set to 160 samples at 16 kHz */
     302             :     /* used for windowing and as the correlation length, i.e., */
     303             :     /* the size of the template segment. */
     304         941 :     ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), (Word16) ps->num_channels ); // Q0
     305         941 :     move16();
     306             : 
     307             :     /* set frame size */
     308             :     /* set to 320 samples at 16 kHz */
     309         941 :     ps->l_frm = (UWord16) imult3216( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ), (Word16) ps->num_channels ); // Q0
     310         941 :     move16();
     311             : 
     312             :     /* set minimum pitch */
     313             :     /* set to 40 samples at 16 kHz */
     314             :     /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
     315         941 :     ps->p_min = (UWord16) imult3216( Mult_32_16( ps->rate, INV_400_Q15 ), (Word16) ps->num_channels ); // Q0
     316         941 :     move16();
     317             : 
     318             :     /* set search length */
     319             :     /* must cover one pitch, set to 200 samples at 16 kHz */
     320             :     /* (the resulting maximum pitch is then p_min+l_search = 240 samples at 16 kHz) */
     321         941 :     ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), (Word16) ps->num_channels ); // Q0
     322         941 :     move16();
     323             : 
     324         941 :     return 0;
     325             : }
     326             : 
     327             : /* Sets the audio configuration. */
     328          28 : bool apa_set_rate(
     329             :     apa_state_t *ps,
     330             :     const Word32 output_Fs )
     331             : {
     332             :     /* make sure pointer is valid */
     333          28 :     IF( ps == NULL )
     334             :     {
     335           0 :         return 1;
     336             :     }
     337             : 
     338             :     /* check range */
     339          28 :     test();
     340          28 :     IF( ( LT_32( output_Fs, APA_MIN_RATE ) ) || ( GT_32( output_Fs, APA_MAX_RATE ) ) )
     341             :     {
     342           0 :         return 1;
     343             :     }
     344             : 
     345             :     /* reset state struct */
     346          28 :     apa_reset( ps );
     347             : 
     348             :     /* copy rate to state struct */
     349          28 :     ps->rate = (UWord16) output_Fs;
     350          28 :     move16();
     351             : 
     352          28 :     IF( GT_32( ps->num_channels, APA_MAX_NUM_CHANNELS ) )
     353             :     {
     354           0 :         return 1;
     355             :     }
     356             : 
     357             :     /*
     358             :      * several other parameters depend on the sampling rate
     359             :      * and are set below. Some "magic numbers" are used here
     360             :      * which are based on typical values of a "pitch" in
     361             :      * human voice. The pitch length is the period of the
     362             :      * base frequency and is usually assumed to be 40-240
     363             :      * samples at 16 kHz.
     364             :      */
     365             : 
     366             :     /* set segment size */
     367             :     /* in the order of a pitch, set to 160 samples at 16 kHz */
     368             :     /* used for windowing and as the correlation length, i.e., */
     369             :     /* the size of the template segment. */
     370          28 :     ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), ps->num_channels ); // Q0
     371          28 :     move16();
     372             : 
     373             :     /* init Hann window */
     374             :     /* Note: l_win < APA_BUF_PER_CHANNEL is required */
     375             :     /* Length of Hann window should be independent of
     376             :      * number of channels - same window applied to all channels */
     377          28 :     ps->l_halfwin = (UWord16) Mult_32_16( ps->rate, INV_100_Q15 ); // Q0
     378          28 :     move16();
     379             : 
     380             :     /* set frame size */
     381             :     /* set to 320 samples at 16 kHz */
     382          28 :     ps->l_frm = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ) ), ps->num_channels ); // Q0
     383          28 :     move16();
     384             : 
     385             :     /* set minimum pitch */
     386             :     /* set to 40 samples at 16 kHz */
     387             :     /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
     388          28 :     ps->p_min = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_400_Q15 ) ), ps->num_channels ); // Q0
     389          28 :     move16();
     390             : 
     391             :     /* set search length */
     392             :     /* must cover one pitch, set to 200 samples at 16 kHz */
     393             :     /* (the resulting maximum pitch is then p_min+l_search = 240 samples at 16 kHz) */
     394          28 :     ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), ps->num_channels ); // Q0
     395          28 :     move16();
     396             : 
     397          28 :     ps->win_fx = pcmdsp_window_hann_640;
     398          28 :     ps->l_halfwin = 320;
     399          28 :     move16();
     400          28 :     ps->win_incrementor = 1;
     401          28 :     move16();
     402          28 :     IF( EQ_32( ps->rate, 48000 ) )
     403             :     {
     404          16 :         ps->win_fx = pcmdsp_window_hann_960;
     405          16 :         ps->l_halfwin = 480;
     406          16 :         move16();
     407             :     }
     408          28 :     IF( EQ_32( ps->rate, 24000 ) )
     409             :     {
     410           0 :         ps->win_fx = pcmdsp_window_hann_960;
     411           0 :         ps->l_halfwin = 480;
     412           0 :         move16();
     413           0 :         ps->win_incrementor = 2;
     414           0 :         move16();
     415             :     }
     416             :     /* sample rates 8k, 16k & 32k use a Hann window of length of 640,
     417             :      * where 8k and 16k subsample */
     418          28 :     if ( EQ_32( ps->rate, 16000 ) )
     419             :     {
     420           3 :         ps->win_incrementor = 2;
     421           3 :         move16();
     422             :     }
     423          28 :     if ( EQ_32( ps->rate, 8000 ) )
     424             :     {
     425           0 :         ps->win_incrementor = 4;
     426           0 :         move16();
     427             :     }
     428             : 
     429             :     /* set minimum pitch */
     430             :     /* set to 40 samples at 16 kHz */
     431             :     /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
     432             :     /* before basop port was originally: ps->p_min = (ps->rate * ps->num_channels) / 400;
     433             :      * but for simplicity can be taken as l_seg / 4 */
     434          28 :     ps->signalScaleForCorrelation = getSignalScaleForCorrelation( ps->rate );
     435          28 :     move16();
     436          28 :     return 0;
     437             : }
     438             : 
     439             : /* Set scaling. */
     440       19551 : bool apa_set_scale_fx(
     441             :     apa_state_t *ps,
     442             :     UWord16 scale )
     443             : {
     444             :     /* make sure pointer is valid */
     445       19551 :     IF( ps == NULL )
     446             :     {
     447           0 :         return 1;
     448             :     }
     449             : 
     450             :     /* check range */
     451       19551 :     test();
     452       19551 :     IF( ( LT_32( (Word32) scale, APA_MIN_SCALE ) ) || GT_32( (Word32) scale, APA_MAX_SCALE ) )
     453             :     {
     454           0 :         return 1;
     455             :     }
     456             : 
     457             :     /* do nothing if same scale is set multiple times */
     458             :     /* (otherwise scale control is confused) */
     459       19551 :     IF( EQ_32( (Word32) ps->scale, (Word32) scale ) )
     460             :     {
     461       19460 :         return 0;
     462             :     }
     463             : 
     464             :     /* copy to state struct */
     465          91 :     ps->scale = scale;
     466          91 :     move16();
     467             : 
     468             :     /* reset scaling statistics */
     469          91 :     ps->diffSinceSetScale = 0;
     470          91 :     move32();
     471          91 :     ps->nFramesSinceSetScale = 0;
     472          91 :     move32();
     473             : 
     474          91 :     return 0;
     475             : }
     476             : 
     477          28 : bool apa_set_renderer_granularity(
     478             :     apa_state_t *ps,
     479             :     UWord16 l_ts )
     480             : {
     481             :     /* make sure pointer is valid */
     482          28 :     IF( ps == NULL )
     483             :     {
     484           0 :         return 1;
     485             :     }
     486             : 
     487             : 
     488             :     /* copy to state struct */
     489          28 :     ps->l_ts = (UWord16) imult3216( l_ts, (Word16) ps->num_channels );
     490          28 :     move16();
     491          28 :     return 0;
     492             : }
     493             : 
     494       19551 : bool apa_set_renderer_residual_samples(
     495             :     apa_state_t *ps,
     496             :     UWord16 l_r_buf )
     497             : {
     498             :     /* make sure pointer is valid */
     499       19551 :     IF( ps == NULL )
     500             :     {
     501           0 :         return 1;
     502             :     }
     503             : 
     504             : 
     505             :     /* copy to state struct */
     506       19551 :     ps->l_r_buf = (UWord16) imult3216( l_r_buf, (Word16) ps->num_channels );
     507       19551 :     move16();
     508       19551 :     return 0;
     509             : }
     510             : 
     511             : 
     512           0 : bool apa_set_evs_compat_mode(
     513             :     apa_state_t *ps,
     514             :     bool mode )
     515             : {
     516             :     /* make sure pointer is valid */
     517           0 :     IF( ps == NULL )
     518             :     {
     519           0 :         return 1;
     520             :     }
     521             : 
     522           0 :     ps->evs_compat_mode = mode;
     523           0 :     move16();
     524             : 
     525           0 :     return 0;
     526             : }
     527             : 
     528             : 
     529             : /*
     530             : ********************************************************************************
     531             : *
     532             : *     Function        : apa_set_quality
     533             : *     Tables          : <none>
     534             : *     Compile Defines : <none>
     535             : *     Return          : 0 on success, 1 on failure
     536             : *     Information     : Set quality thresholds.
     537             : *
     538             : *                       quality is lower limit for minimum quality
     539             : *                       Range is [-2;2] - where positive values allow
     540             : *                       only pasting with same phase information
     541             : *                       Negative values would yield cross phased pasting
     542             : *
     543             : *                       qualityred allows dynamic lowering of lower quality
     544             : *                       bound - this gives better results for rhythmic signals
     545             : *                       Range is [0;20], meaning 0.1 lowering*qualityred
     546             : *
     547             : *                       undocumented: qualityrise (same as qualityred - other
     548             : *                       direction)
     549             : *
     550             : ********************************************************************************
     551             : */
     552          28 : bool apa_set_quality(
     553             :     apa_state_t *ps,
     554             :     Word32 quality, // Q16
     555             :     UWord16 qualityred,
     556             :     UWord16 qualityrise )
     557             : {
     558          28 :     assert( ps != NULL );
     559          28 :     assert( -131072 /*-2.0f in Q16*/ <= quality && quality <= 203161 /*3.1f in Q16*/ );
     560          28 :     assert( qualityred > 0 && qualityred <= 20 );
     561          28 :     assert( qualityrise > 0 && qualityrise <= 20 );
     562             : 
     563          28 :     ps->targetQuality_fx = quality;
     564          28 :     move32();
     565          28 :     ps->qualityred = qualityred;
     566          28 :     move16();
     567          28 :     ps->qualityrise = qualityrise;
     568          28 :     move16();
     569          28 :     ps->bad_frame_count = 0;
     570          28 :     move16();
     571          28 :     ps->good_frame_count = 0;
     572          28 :     move16();
     573             : 
     574          28 :     return 0;
     575             : }
     576             : 
     577             : /*
     578             : ********************************************************************************
     579             : *
     580             : *     Function        : apa_set_complexity_options
     581             : *     Tables          : <none>
     582             : *     Compile Defines : <none>
     583             : *     Return          : 0 on success, 1 on failure
     584             : *     Information     : Set complexity options
     585             : *                       Waveform subsampling computes the correlation function
     586             : *                         for certain positions only
     587             : *                       Correlation function subsampling computes the maxima
     588             : *                         for certain positions only
     589             : *
     590             : ********************************************************************************
     591             : */
     592          28 : bool apa_set_complexity_options(
     593             :     apa_state_t *ps,
     594             :     UWord16 wss,
     595             :     UWord16 css )
     596             : {
     597             :     /* make sure pointer is valid */
     598          28 :     IF( ps == NULL )
     599             :     {
     600           0 :         return 1;
     601             :     }
     602             : 
     603          28 :     test();
     604          28 :     IF( wss == 0 || GT_32( wss, 1000 ) )
     605             :     {
     606           0 :         return 1;
     607             :     }
     608             : 
     609          28 :     test();
     610          28 :     IF( css == 0 || GT_32( css, 1000 ) )
     611             :     {
     612           0 :         return 1;
     613             :     }
     614             : 
     615          28 :     ps->wss = wss;
     616          28 :     move16();
     617          28 :     ps->css = css;
     618          28 :     move16();
     619             : 
     620          28 :     return 0;
     621             : }
     622             : 
     623             : 
     624             : /*
     625             : ********************************************************************************
     626             : *
     627             : *     Function        : apa_exit
     628             : *     Tables          : <none>
     629             : *     Compile Defines : <none>
     630             : *     Return          : 0 on success, 1 on failure
     631             : *     Information     : The memory used for storing the state is freed.
     632             : *                       The state struct pointer is set to NULL.
     633             : *
     634             : ********************************************************************************
     635             : */
     636         614 : bool apa_exit(
     637             :     apa_state_t **pps )
     638             : {
     639             :     /* ignore NULL pointer input */
     640         614 :     IF( *pps == NULL )
     641             :     {
     642         586 :         return 0;
     643             :     }
     644             : 
     645             :     /* deallocate state struct members */
     646          28 :     free( ( *pps )->buf_out_fx );
     647             : 
     648             :     /* deallocate state struct */
     649          28 :     free( *pps );
     650             : 
     651             :     /* set pointer to NULL */
     652          28 :     *pps = NULL;
     653             : 
     654          28 :     return 0;
     655             : }
     656             : 
     657             : /*
     658             : ********************************************************************************
     659             : *
     660             : *     Function        : apa_exec
     661             : *     Tables          : <none>
     662             : *     Compile Defines : <none>
     663             : *     Return          : 0 on success, 1 on failure
     664             : *     Information     : Execute adaptive playout for audio, i.e., audio scaling.
     665             : *                       Will take l_in input samples from a_in[] and
     666             : *                       try to extend/shrink the amount of samples according
     667             : *                       to the last scaling set by using apa_set_scale().
     668             : *                       The actual amount of samples after scaling may vary
     669             : *                       and is given in l_out. The scaled audio samples
     670             : *                       are contained in a_out[]. Note that the scaling is
     671             : *                       achieved only in average. The input buffer must be
     672             : *                       filled with 20ms audio. The output buffer must be
     673             : *                       allocated externally and must be at least of size
     674             : *                       APA_BUF.
     675             : *                       Scaling can only be performed when a sampling rate
     676             : *                       is specified using apa_set_rate(). Otherwise,
     677             : *                       an error is returned.
     678             : *
     679             : *                       The amount of scaling is achieved by controlling the
     680             : *                       frequency of scaling. Note that the exact amount of
     681             : *                       scaling is signal dependent and is an integer
     682             : *                       multiple of a pitch. Hence, when we want to achieve
     683             : *                       a scaling of e.g. 110% then the APA module will typically
     684             : *                       forward several frames without any modification and
     685             : *                       then scale one frame by a higher amount, e.g. 143%.
     686             : *
     687             : ********************************************************************************
     688             : */
     689           0 : UWord8 apa_exec_fx(
     690             :     apa_state_t *ps,     /* i/o: state struct                                  */
     691             :     const Word16 a_in[], /* i  : input samples                                Q0 */
     692             :     UWord16 l_in,        /* i  : number of input samples                       */
     693             :     UWord16 maxScaling,  /* i  : allowed number of inserted/removed samples    */
     694             :     Word16 a_out[],      /* o  : output samples                                Q0*/
     695             :     UWord16 *l_out       /* o  : number of output samples                      */
     696             : )
     697             : {
     698             :     UWord16 i;
     699             :     Word16 frm_in[APA_BUF]; /* TODO(mcjbm): this buffer could be smaller - always allocates space for 16 channels */
     700             :     UWord16 l_frm_out;
     701             :     Word16 l_rem;
     702             :     Word32 dl_scaled, dl_copied, l_frm_out_target;
     703             :     Word32 expScaling, actScaling;
     704             :     UWord32 statsResetThreshold, statsResetShift;
     705             : 
     706           0 :     statsResetThreshold = 1637;
     707           0 :     move32();
     708           0 :     statsResetShift = 2;
     709           0 :     move32();
     710             : 
     711             :     /* Convert max_scaling from "per channel" to total */
     712           0 :     maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
     713             : 
     714             :     /* make sure no invalid output is used */
     715           0 :     *l_out = 0;
     716           0 :     move16();
     717           0 :     l_frm_out = 0;
     718           0 :     move16();
     719             : 
     720             :     /* make sure pointer is valid */
     721           0 :     IF( ps == NULL )
     722             :     {
     723           0 :         return 1;
     724             :     }
     725             :     /* check available rate */
     726           0 :     IF( ps->rate == 0 )
     727             :     {
     728           0 :         return 2;
     729             :     }
     730             :     /* check size of input */
     731           0 :     IF( NE_32( l_in, ps->l_frm ) )
     732             :     {
     733           0 :         return 3;
     734             :     }
     735             : 
     736             :     /* get target length */
     737           0 :     test();
     738           0 :     test();
     739           0 :     IF( EQ_16( ps->l_frm, 480 ) || EQ_16( ps->l_frm, 960 ) || EQ_16( ps->l_frm, 1920 ) )
     740             :     {
     741             :         /* decomposite ps->l_frm into 15<<i, e.g. 480=15<<5 */
     742           0 :         i = sub( 15 - 4, norm_s( ps->l_frm ) );
     743             :         /* this only works for 20ms framing */
     744           0 :         assert( ps->l_frm == shl( shr( ps->l_frm, i ), i ) );
     745             :         // assert( i_mult2( sub( ps->scale, 100 ), add( ps->nFramesSinceSetScale, 1 ) ) == ( ps->scale - 100 ) * ( ps->nFramesSinceSetScale + 1 ) );
     746           0 :         expScaling = L_shr_r( L_mult0( i_mult2( sub( ps->scale, 100 ), add( (Word16) ps->nFramesSinceSetScale, 1 ) ), 19661 /*15*(1<<2)/100.0 Q15*/ ), sub( 15 + 2, i ) );
     747             :     }
     748             :     ELSE
     749             :     {
     750             :         /* decomposite ps->l_frm into 5<<i, e.g. 320=5<<6 */
     751           0 :         i = sub( 15 - 3, norm_s( ps->l_frm ) );
     752             :         /* this only works for 20ms framing */
     753           0 :         assert( ps->l_frm == shl( shr( ps->l_frm, i ), i ) );
     754             :         // assert( i_mult2( sub( ps->scale, 100 ), add( ps->nFramesSinceSetScale, 1 ) ) == ( ps->scale - 100 ) * ( ps->nFramesSinceSetScale + 1 ) );
     755           0 :         expScaling = L_shr_r( L_mult0( i_mult2( sub( ps->scale, 100 ), add( (Word16) ps->nFramesSinceSetScale, 1 ) ), 13107 /*5*(1<<3)/100.0 Q15*/ ), sub( 15 + 3, i ) );
     756             :     }
     757           0 :     actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
     758           0 :     l_frm_out_target = L_sub( expScaling, actScaling );
     759             : 
     760             :     /* Wait until we have l_frm outputs samples */
     761             :     /* (required to search for correlation in the past). */
     762             :     /* If we don't have enough samples, simply copy input to output */
     763           0 :     IF( LT_32( ps->l_buf_out, ps->l_frm ) )
     764             :     {
     765           0 :         FOR( i = 0; i < ps->l_frm; i++ )
     766             :         {
     767           0 :             a_out[i] = a_in[i];
     768           0 :             move16();
     769             :         }
     770           0 :         l_frm_out = ps->l_frm;
     771           0 :         move16();
     772             :     }
     773             :     ELSE
     774             :     {
     775           0 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
     776           0 :         Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
     777             : 
     778             :         /* fill input frame */
     779             :         /* 1st input frame: previous output samples */
     780           0 :         FOR( i = 0; i < ps->l_frm; i++ )
     781             :         {
     782           0 :             frm_in[i] = buf_out_ptr[i];
     783           0 :             move16();
     784             :         }
     785             :         /* 2nd input frame: new input samples */
     786           0 :         FOR( i = 0; i < ps->l_frm; i++ )
     787             :         {
     788           0 :             frm_in_ptr[i] = a_in[i];
     789           0 :             move16();
     790             :         }
     791             :         /* no scaling */
     792           0 :         IF( EQ_32( ps->scale, 100 ) )
     793             :         {
     794           0 :             copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
     795             :         }
     796             :         /* shrink */
     797           0 :         ELSE IF( LT_32( ps->scale, 100 ) )
     798             :         {
     799           0 :             shrink_frm_fx( ps, frm_in, maxScaling, a_out, &l_frm_out );
     800             :         }
     801             :         /* extend */
     802             :         ELSE
     803             :         {
     804           0 :             extend_frm_fx( ps, frm_in, a_out, &l_frm_out );
     805             :         }
     806             :         /* control the amount/frequency of scaling */
     807           0 :         IF( NE_32( l_frm_out, ps->l_frm ) )
     808             :         {
     809           0 :             test();
     810           0 :             IF( maxScaling != 0 &&
     811             :                 GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
     812             :             {
     813             :                 /* maxScaling exceeded -> discard scaled frame */
     814           0 :                 copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
     815             :             }
     816           0 :             ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
     817             :             {
     818           0 :                 dl_copied = L_sub( l_frm_out_target, ps->l_frm );
     819           0 :                 dl_scaled = L_sub( l_frm_out_target, l_frm_out );
     820             :                 /* discard scaled frame if copied frame is closer to target length */
     821           0 :                 IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
     822             :                 {
     823           0 :                     copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
     824             :                 }
     825             :             }
     826             :         }
     827             :     }
     828             : 
     829             :     /* copy output to internal buffer */
     830             :     /* avoid buffer overflow: */
     831             :     /* discard old samples; always keep at least most recent l_frm samples */
     832           0 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
     833             :     {
     834           0 :         Word16 *buf_out_ptr1 = ps->buf_out_fx;
     835             :         Word16 *buf_out_ptr2;
     836             : 
     837           0 :         l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
     838           0 :         if ( l_rem < 0 )
     839             :         {
     840           0 :             l_rem = 0;
     841           0 :             move16();
     842             :         }
     843           0 :         buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
     844           0 :         FOR( i = 0; i < l_rem; i++ )
     845             :         {
     846           0 :             buf_out_ptr1[i] = buf_out_ptr2[i];
     847           0 :             move16();
     848             :         }
     849           0 :         ps->l_buf_out = l_rem;
     850           0 :         move16();
     851             :     }
     852             :     /* append new output samples */
     853           0 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
     854             :     {
     855           0 :         return 5;
     856             :     }
     857             :     {
     858           0 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
     859           0 :         FOR( i = 0; i < l_frm_out; i++ )
     860             :         {
     861           0 :             buf_out_ptr[i] = a_out[i];
     862           0 :             move16();
     863             :         }
     864             :     }
     865           0 :     ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
     866           0 :     move16();
     867             : 
     868           0 :     *l_out = l_frm_out;
     869           0 :     move16();
     870             :     /* update time */
     871           0 :     ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
     872           0 :     move32();
     873             : 
     874           0 :     test();
     875           0 :     IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
     876             :         LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
     877             :     {
     878           0 :         ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
     879           0 :         move32();
     880           0 :         ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
     881           0 :         move32();
     882             :     }
     883             :     ELSE /* scale statistics down to avoid overflow */
     884             :     {
     885           0 :         ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
     886           0 :         move32();
     887           0 :         ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
     888           0 :         move32();
     889             :     }
     890             : 
     891           0 :     return 0;
     892             : }
     893             : 
     894       19551 : UWord8 apa_exec_ivas_fx(
     895             :     apa_state_t *ps,     /* i/o: state struct                                  */
     896             :     const Word32 a_in[], /* i  : input samples                             Q(-1) */
     897             :     UWord16 l_in,        /* i  : number of input samples                       */
     898             :     UWord16 maxScaling,  /* i  : allowed number of inserted/removed samples    */
     899             :     Word32 a_out[],      /* o  : output samples                            Q(-1)  */
     900             :     UWord16 *l_out       /* o  : number of output samples                      */
     901             : )
     902             : {
     903             :     UWord16 i;
     904             :     Word16 frm_in[APA_BUF]; /* TODO(mcjbm): this buffer could be smaller - always allocates space for 16 channels */
     905             :     UWord16 l_frm_out;
     906             :     Word16 l_rem;
     907             :     Word32 dl_scaled, dl_copied, l_frm_out_target;
     908             :     Word32 expScaling, actScaling;
     909             :     UWord32 statsResetThreshold, statsResetShift;
     910             :     Word16 Q_a_out;
     911             : #ifdef FIX1998_APA_EXEC_SCALING
     912             :     Word16 Q_a_out_init_old;
     913             : #endif
     914             : 
     915       19551 :     Q_a_out = add( getScaleFactor32_copy( a_in, L_mult0( ps->num_channels, APA_BUF_PER_CHANNEL ) ), Q11 - Q16 - Q1 );
     916             : #ifdef FIX1998_APA_EXEC_SCALING
     917       19551 :     Q_a_out_init_old = Q_a_out; /* store the possible scaling of a_in, to be re-used in the next frame */
     918       19551 :     move16();
     919             : #endif
     920       19551 :     statsResetThreshold = 1637;
     921       19551 :     move32();
     922       19551 :     statsResetShift = 2;
     923       19551 :     move32();
     924             : 
     925             :     /* Convert max_scaling from "per channel" to total */
     926       19551 :     maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
     927             : 
     928             :     /* make sure no invalid output is used */
     929       19551 :     *l_out = 0;
     930       19551 :     move16();
     931       19551 :     l_frm_out = 0;
     932       19551 :     move16();
     933             : 
     934             :     /* make sure pointer is valid */
     935       19551 :     IF( ps == NULL )
     936             :     {
     937           0 :         return 1;
     938             :     }
     939             :     /* check available rate */
     940       19551 :     IF( ps->rate == 0 )
     941             :     {
     942           0 :         return 2;
     943             :     }
     944             :     /* check size of input */
     945       19551 :     IF( NE_32( l_in, ps->l_frm ) )
     946             :     {
     947           0 :         return 3;
     948             :     }
     949             : 
     950             :     /* get target length */
     951       19551 :     IF( GT_32( ps->scale, 100 ) )
     952             :     {
     953             :         // expScaling = (int32_t) ( ( ps->l_frm * ( ps->scale - 100.0f ) / 100.0f ) * ( ps->nFramesSinceSetScale + 1 ) + 0.5f );
     954         436 :         expScaling = W_extract_l( W_shr( W_add( W_mult_32_32( Mpy_32_16_1( imult3216( ps->l_frm, sub( ps->scale, 100 ) ), 328 /* 1 / 100.0f in Q15 */ ), UL_addNsD( ps->nFramesSinceSetScale, 1 ) ), 1 ), 1 ) );
     955             :     }
     956       19115 :     ELSE IF( LT_32( ps->scale, 100 ) )
     957             :     {
     958         141 :         expScaling = L_negate( W_extract_l( W_shr( W_abs( W_sub( W_mult_32_32( Mpy_32_16_1( imult3216( ps->l_frm, sub( ps->scale, 100 ) ), 328 /* 1 / 100.0f in Q15 */ ), UL_addNsD( ps->nFramesSinceSetScale, 1 ) ), 1 ) ), 1 ) ) );
     959             :     }
     960             :     ELSE
     961             :     {
     962       18974 :         expScaling = 0;
     963       18974 :         move32();
     964             :     }
     965       19551 :     actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
     966       19551 :     l_frm_out_target = L_sub( expScaling, actScaling );
     967             : 
     968             :     /* Wait until we have l_frm outputs samples */
     969             :     /* (required to search for correlation in the past). */
     970             :     /* If we don't have enough samples, simply copy input to output */
     971       19551 :     IF( LT_32( ps->l_buf_out, ps->l_frm ) )
     972             :     {
     973     2296329 :         FOR( i = 0; i < ps->l_frm; i++ )
     974             :         {
     975     2295360 :             a_out[i] = a_in[i];
     976     2295360 :             move32();
     977             :         }
     978         969 :         l_frm_out = ps->l_frm;
     979         969 :         move16();
     980             :     }
     981             :     ELSE
     982             :     {
     983             :         Word16 a_tmp[APA_BUF];
     984       18582 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
     985             : 
     986             : #ifdef FIX1998_APA_EXEC_SCALING
     987             :         /*
     988             :            don't compare against actual scaling in ps->Q_buf_out, but possible scaling in ps->Q_a_out_init_old; otherwise we are constantly reducing the scaling over time, leading to precision issues
     989             :            alternative approach: determine scaling of ps->buf_out_fx, but this is costly due to the sheer amount of samples stored there...
     990             :         */
     991       18582 :         Q_a_out = s_min( Q_a_out, ps->Q_a_out_init_old );
     992             : #else
     993             :         Q_a_out = s_min( Q_a_out, ps->Q_buf_out );
     994             : #endif
     995       18582 :         Scale_sig( ps->buf_out_fx, ps->buf_out_capacity, sub( Q_a_out, ps->Q_buf_out ) ); // Q_buf_out -> Q_a_out
     996       18582 :         IF( EQ_32( ps->scale, 100 ) )
     997             :         {
     998   118293950 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
     999             :             {
    1000   118275840 :                 a_out[i] = a_in[i]; // Q11
    1001   118275840 :                 move32();
    1002             :             }
    1003       18110 :             l_frm_out = ps->l_frm;
    1004       18110 :             move16();
    1005             :         }
    1006             :         ELSE
    1007             :         {
    1008         472 :             Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
    1009             : 
    1010     3151192 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
    1011             :             {
    1012     3150720 :                 a_tmp[i] = extract_h( L_shl( a_in[i], add( Q_a_out, Q5 ) ) ); // Q_a_out
    1013     3150720 :                 move16();
    1014             :             }
    1015             :             /* fill input frame */
    1016             :             /* 1st input frame: previous output samples */
    1017      791832 :             FOR( i = 0; i < ps->l_frm; i++ )
    1018             :             {
    1019      791360 :                 frm_in[i] = buf_out_ptr[i];
    1020      791360 :                 move16();
    1021             :             }
    1022             :             /* 2nd input frame: new input samples */
    1023      791832 :             FOR( i = 0; i < ps->l_frm; i++ )
    1024             :             {
    1025      791360 :                 frm_in_ptr[i] = a_tmp[i];
    1026      791360 :                 move16();
    1027             :             }
    1028             :             /* shrink */
    1029         472 :             IF( LT_32( ps->scale, 100 ) )
    1030             :             {
    1031         139 :                 shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out );
    1032             :             }
    1033             :             /* extend */
    1034             :             ELSE
    1035             :             {
    1036         333 :                 extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out );
    1037             :             }
    1038             :             /* control the amount/frequency of scaling */
    1039         472 :             IF( NE_32( l_frm_out, ps->l_frm ) )
    1040             :             {
    1041          86 :                 test();
    1042          86 :                 IF( ( maxScaling != 0 ) &&
    1043             :                     GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
    1044             :                 {
    1045             :                     /* maxScaling exceeded -> discard scaled frame */
    1046          40 :                     copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
    1047             :                 }
    1048          46 :                 ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
    1049             :                 {
    1050          41 :                     dl_copied = L_sub( l_frm_out_target, ps->l_frm );
    1051          41 :                     dl_scaled = L_sub( l_frm_out_target, l_frm_out );
    1052             :                     /* discard scaled frame if copied frame is closer to target length */
    1053          41 :                     IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
    1054             :                     {
    1055           0 :                         copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
    1056             :                     }
    1057             :                 }
    1058             :             }
    1059             : 
    1060     3151192 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
    1061             :             {
    1062     3150720 :                 a_out[i] = L_shl( a_tmp[i], sub( Q11, Q_a_out ) ); // Q0 -> Q11
    1063     3150720 :                 move32();
    1064             :             }
    1065             :         }
    1066             :     }
    1067             : 
    1068             :     /* copy output to internal buffer */
    1069             :     /* avoid buffer overflow: */
    1070             :     /* discard old samples; always keep at least most recent l_frm samples */
    1071       19551 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
    1072             :     {
    1073        4763 :         Word16 *buf_out_ptr1 = ps->buf_out_fx;
    1074             :         Word16 *buf_out_ptr2;
    1075             : 
    1076        4763 :         l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
    1077        4763 :         if ( l_rem < 0 )
    1078             :         {
    1079          21 :             l_rem = 0;
    1080          21 :             move16();
    1081             :         }
    1082        4763 :         buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
    1083        5339 :         FOR( i = 0; i < l_rem; i++ )
    1084             :         {
    1085         576 :             buf_out_ptr1[i] = buf_out_ptr2[i];
    1086         576 :             move16();
    1087             :         }
    1088        4763 :         ps->l_buf_out = l_rem;
    1089        4763 :         move16();
    1090             :     }
    1091             :     /* append new output samples */
    1092       19551 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
    1093             :     {
    1094           0 :         return 5;
    1095             :     }
    1096             :     {
    1097       19551 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
    1098    35850720 :         FOR( i = 0; i < l_frm_out; i++ )
    1099             :         {
    1100    35831169 :             buf_out_ptr[i] = extract_h( L_shl( a_out[i], add( Q_a_out, Q16 - Q11 ) ) ); // Q_a_out
    1101    35831169 :             move16();
    1102             :         }
    1103       19551 :         ps->Q_buf_out = Q_a_out;
    1104       19551 :         move16();
    1105             :     }
    1106       19551 :     ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
    1107       19551 :     move16();
    1108             : #ifdef FIX1998_APA_EXEC_SCALING
    1109       19551 :     ps->Q_a_out_init_old = Q_a_out_init_old;
    1110       19551 :     move16();
    1111             : #endif
    1112             : 
    1113       19551 :     *l_out = l_frm_out;
    1114       19551 :     move16();
    1115             :     /* update time */
    1116       19551 :     ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
    1117       19551 :     move32();
    1118             : 
    1119             : 
    1120       19551 :     test();
    1121       19551 :     IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
    1122             :         LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
    1123             :     {
    1124       19551 :         ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
    1125       19551 :         move32();
    1126       19551 :         ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
    1127       19551 :         move32();
    1128             :     }
    1129             :     ELSE /* scale statistics down to avoid overflow */
    1130             :     {
    1131           0 :         ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
    1132           0 :         move32();
    1133           0 :         ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
    1134           0 :         move32();
    1135             :     }
    1136             : 
    1137       19551 :     return 0;
    1138             : }
    1139             : 
    1140             : 
    1141             : /*---------------------------------------------------------------------*
    1142             :  * Local functions
    1143             :  *---------------------------------------------------------------------*/
    1144             : 
    1145             : /*
    1146             : ********************************************************************************
    1147             : *
    1148             : *     Function        : get_scaling_quality
    1149             : *     Tables          : <none>
    1150             : *     Compile Defines : <none>
    1151             : *     Return          : 0 on success, 1 on failure
    1152             : *     Information     : Uses pitch, half pitch, three halves and double pitch
    1153             : *                       to evaluate the quality of the scaled frame by checking
    1154             : *                       periodicity.
    1155             : *                       Silence can be detected as additional feature. This must
    1156             : *                       be set in global struct apa_state.
    1157             : *
    1158             : *                       If search length is very narrow then use fewer points
    1159             : *                       to evaluate periodicity and silence.
    1160             : *
    1161             : *                       Computationally not very efficient by using normalized
    1162             : *                       cross-correlation: Using sqrt() for energy calculation
    1163             : *                       adds complexity.
    1164             : *
    1165             : *     03-AUG-04  S.Doehla        initial version
    1166             : *
    1167             : ********************************************************************************
    1168             : */
    1169         472 : static void get_scaling_quality_fx( const apa_state_t *ps,
    1170             :                                     const Word16 *signal,
    1171             :                                     Word16 s_len,
    1172             :                                     Word16 offset,
    1173             :                                     Word16 corr_len,
    1174             :                                     Word16 pitch,
    1175             :                                     Word16 *energydBQ8, // Q8
    1176             :                                     Word32 *qualityQ16  // Q16
    1177             : )
    1178             : {
    1179             :     Word32 energy, maxEnergy;
    1180             :     Word32 qualityOfMaxEnergy; /* we measure the quality for all channels and select the one with highest energy */
    1181             :     Word16 half_pitch_cn;
    1182             :     Word16 pitch_cn;
    1183             :     Word16 three_halves_pitch_cn;
    1184             :     Word16 double_pitch_cn;
    1185             :     Word32 pitch_energy;
    1186             :     Word32 half_pitch_energy;
    1187             :     Word32 three_halves_pitch_energy;
    1188             :     Word32 double_pitch_energy;
    1189             :     Word16 i;
    1190             : 
    1191             : 
    1192         472 :     maxEnergy = 0;
    1193         472 :     qualityOfMaxEnergy = 0;
    1194         472 :     move32();
    1195         472 :     move32();
    1196             : 
    1197        1566 :     FOR( i = 0; i < ps->num_channels; i++ )
    1198             :     {
    1199        1094 :         offset = 0;
    1200        1094 :         move16();
    1201             : 
    1202        1094 :         pitch_cn = normalized_cross_correlation_self_fx( signal, add( pitch, offset ), offset, corr_len,
    1203        1094 :                                                          shl( ps->num_channels, 1 ), &pitch_energy );
    1204        1094 :         IF( pitch_cn > 0 )
    1205             :         {
    1206             :             /* calculate correlation for double pitch */
    1207         766 :             IF( LE_16( add( add( shl( pitch, 1 ), offset ), corr_len ), s_len ) )
    1208             :             {
    1209         635 :                 double_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shl( pitch, 1 ), offset ),
    1210         635 :                                                                         offset, corr_len, shl( ps->num_channels, 1 ), &double_pitch_energy );
    1211             :             }
    1212             :             ELSE
    1213             :             {
    1214         131 :                 double_pitch_cn = pitch_cn;
    1215         131 :                 move16();
    1216         131 :                 double_pitch_energy = L_add( pitch_energy, 0 );
    1217             :             }
    1218             :             /* calculate correlation for three/half pitch */
    1219         766 :             IF( LE_16( add( add( shr( i_mult2( pitch, 3 ), 1 ), offset ), corr_len ), s_len ) )
    1220             :             {
    1221         669 :                 three_halves_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( i_mult2( pitch, 3 ), 1 ), offset ), offset, corr_len, shl( ps->num_channels, 1 ), &three_halves_pitch_energy );
    1222             :             }
    1223             :             ELSE
    1224             :             {
    1225          97 :                 three_halves_pitch_cn = pitch_cn;
    1226          97 :                 move16();
    1227          97 :                 three_halves_pitch_energy = L_add( pitch_energy, 0 );
    1228             :             }
    1229             :             /* calculate correlation for half pitch */
    1230         766 :             IF( LE_16( add( add( shr( pitch, 1 ), offset ), corr_len ), s_len ) )
    1231             :             {
    1232         766 :                 half_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( pitch, 1 ), offset ),
    1233         766 :                                                                       offset, corr_len, shl( ps->num_channels, 1 ), &half_pitch_energy );
    1234             :             }
    1235             :             ELSE
    1236             :             {
    1237           0 :                 half_pitch_cn = pitch_cn;
    1238           0 :                 move16();
    1239           0 :                 half_pitch_energy = L_add( pitch_energy, 0 );
    1240             :             }
    1241             : 
    1242             :             /* combine correlation results: Q15.16 */
    1243         766 :             *qualityQ16 = L_shr( L_mac0( L_mult0( half_pitch_cn, three_halves_pitch_cn ),
    1244             :                                          pitch_cn, double_pitch_cn ),
    1245             :                                  14 );
    1246         766 :             move32();
    1247             :             BASOP_SATURATE_WARNING_OFF_EVS
    1248         766 :             energy = L_add( L_add( L_add( pitch_energy, half_pitch_energy ), three_halves_pitch_energy ), double_pitch_energy );
    1249             :             BASOP_SATURATE_WARNING_ON_EVS
    1250             :         }
    1251             :         ELSE
    1252             :         {
    1253         328 :             *qualityQ16 = L_shl( L_deposit_l( pitch_cn ), 1 ); /* value is negative, thus pass it */
    1254         328 :             move32();
    1255         328 :             energy = L_add( pitch_energy, 0 );
    1256             :         }
    1257             : 
    1258             :         /* update the quality by the quality of the signal with the highest energy */
    1259        1094 :         IF( GT_32( energy, maxEnergy ) )
    1260             :         {
    1261         699 :             qualityOfMaxEnergy = L_add( *qualityQ16, 0 );
    1262         699 :             maxEnergy = L_add( energy, 0 );
    1263             :         }
    1264             : 
    1265             :         /* go to next channel */
    1266        1094 :         ++signal;
    1267             :     }
    1268         472 :     *qualityQ16 = qualityOfMaxEnergy;
    1269         472 :     move32();
    1270             : 
    1271             :     /* increase calculated quality of signals with low energy */
    1272         472 :     *energydBQ8 = apa_corrEnergy2dB_fx( maxEnergy, shl( ps->signalScaleForCorrelation, 1 ), corr_len );
    1273         472 :     *qualityQ16 = L_add( *qualityQ16, L_shl( L_deposit_l( apa_getQualityIncreaseForLowEnergy_fx( *energydBQ8 ) ), 8 ) );
    1274         472 :     move16();
    1275         472 :     move32();
    1276         472 : }
    1277             : 
    1278             : /* Converts the correlation energy to dB. */
    1279         472 : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len )
    1280             : {
    1281             : 
    1282             :     Word16 result, tmpScale;
    1283             : 
    1284             :     /* normalise before dividing */
    1285         472 :     tmpScale = norm_l( energy );
    1286         472 :     energy = L_shl( energy, tmpScale );
    1287         472 :     energyExp = sub( energyExp, tmpScale );
    1288             : 
    1289             :     /* divide energy by corr_len */
    1290         472 :     result = BASOP_Util_Divide3216_Scale( energy, corr_len, &tmpScale );
    1291         472 :     energyExp = add( energyExp, tmpScale );
    1292             : 
    1293         472 :     result = BASOP_Util_lin2dB( L_deposit_l( result ), energyExp, 1 );
    1294         472 :     return result;
    1295             : }
    1296             : 
    1297             : /* Increases the calculated quality of signals with low energy. */
    1298         472 : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydBQ8 )
    1299             : {
    1300             :     Word16 qualIncreaseMinEnergy, qualIncreaseMaxEnergy, qualIncForLowEnergy; /* Q8 */
    1301             : 
    1302         472 :     qualIncreaseMinEnergy = -65 * ( 1 << 8 ); // Q8
    1303         472 :     move16();
    1304         472 :     qualIncreaseMaxEnergy = -40 * ( 1 << 8 ); // Q8
    1305         472 :     move16();
    1306         472 :     qualIncForLowEnergy = 0;
    1307         472 :     move16();
    1308             : 
    1309             :     /* increase calculated quality of signals with low energy */
    1310         472 :     IF( LT_16( energydBQ8, qualIncreaseMaxEnergy ) )
    1311             :     {
    1312         124 :         qualIncForLowEnergy = energydBQ8;
    1313         124 :         move16();
    1314         124 :         if ( LT_16( qualIncForLowEnergy, qualIncreaseMinEnergy ) )
    1315             :         {
    1316           0 :             qualIncForLowEnergy = qualIncreaseMinEnergy;
    1317           0 :             move16();
    1318             :         }
    1319         124 :         if ( GT_16( qualIncForLowEnergy, qualIncreaseMaxEnergy ) )
    1320             :         {
    1321           0 :             qualIncForLowEnergy = qualIncreaseMaxEnergy;
    1322           0 :             move16();
    1323             :         }
    1324             :         /* -50:   (-50 - -40) / (-65 - -40) * 20
    1325             :          *      = -10 / -25 * 20
    1326             :          */
    1327         124 :         qualIncForLowEnergy = divide1616( sub( qualIncForLowEnergy, qualIncreaseMaxEnergy ),
    1328         124 :                                           sub( qualIncreaseMinEnergy, qualIncreaseMaxEnergy ) );
    1329             :         /* apply factor 2 and scale back to Q8 */
    1330         124 :         assert( qualIncForLowEnergy >= 0 );
    1331         124 :         qualIncForLowEnergy = shr( qualIncForLowEnergy, 7 - 1 );
    1332         124 :         assert( qualIncForLowEnergy >= 0 && qualIncForLowEnergy <= ( 2 << 8 ) );
    1333             :     }
    1334         472 :     return qualIncForLowEnergy;
    1335             : }
    1336             : 
    1337             : 
    1338             : /*
    1339             : ********************************************************************************
    1340             : *
    1341             : *     Function        : logarithmic_search
    1342             : *     Tables          : <none>
    1343             : *     Compile Defines : <none>
    1344             : *     Return          : 0 on success, 1 on failure
    1345             : *     Information     : Search for best match of a template segment using
    1346             : *                       hierarchical search method:
    1347             : *                       Parameter css is used for sampling every css'd correlation
    1348             : *                       value. The area around the best match so far is used for
    1349             : *                       further correlation value with half css-value until css=1.
    1350             : *                       Search area length is always half previous search length.
    1351             : *                       Parameter wss is passed to the correlation computation
    1352             : *                       If the search area passes the boundaries, the search
    1353             : *                       window is reduced so that it's entirely inside the
    1354             : *                       boundaries.
    1355             : *
    1356             : ********************************************************************************
    1357             : */
    1358         472 : static Word8 logarithmic_search_fx( const apa_state_t *ps,
    1359             :                                     const Word16 *signal,
    1360             :                                     Word16 s_start,
    1361             :                                     Word16 inlen,
    1362             :                                     Word16 offset,
    1363             :                                     Word16 fixed_pos,
    1364             :                                     Word16 corr_len,
    1365             :                                     Word16 wss,
    1366             :                                     Word16 css,
    1367             :                                     Word16 *synchpos )
    1368             : {
    1369             :     Word16 i;
    1370             :     Word32 coeff;
    1371             :     Word32 coeff_max;
    1372             :     Word16 s_start_old, s_len_old;
    1373             : 
    1374             :     DO
    1375             :     {
    1376         472 :         coeff_max = 0x80000000; /* will always be overwritten with result of first correlation */
    1377         472 :         move32();
    1378             : 
    1379       83752 :         FOR( i = s_start; i < s_start + inlen; i += css * ps->num_channels )
    1380             :         {
    1381       83280 :             test();
    1382       83280 :             IF( EQ_16( wss, 1 ) && EQ_16( ps->num_channels, 1 ) )
    1383             :             {
    1384           0 :                 coeff = cross_correlation_self_fx( signal, add( i, offset ), add( fixed_pos, offset ), corr_len );
    1385             :             }
    1386             :             ELSE
    1387             :             {
    1388       83280 :                 coeff = cross_correlation_subsampled_self_fx( signal, add( i, offset ), add( fixed_pos, offset ),
    1389       83280 :                                                               corr_len, i_mult2( wss, ps->num_channels ) );
    1390             :             }
    1391             : 
    1392             :             /* update max corr */
    1393       83280 :             IF( LT_16( ps->scale, 100 ) )
    1394             :             {
    1395             :                 /* shrinking: prefer greater synchpos for equal coeff */
    1396             :                 BASOP_SATURATE_WARNING_OFF_EVS;
    1397       16680 :                 IF( GE_32( coeff, coeff_max ) )
    1398             :                 {
    1399        1773 :                     coeff_max = L_add( coeff, 0 );
    1400        1773 :                     *synchpos = i;
    1401        1773 :                     move16();
    1402             :                 }
    1403             :                 BASOP_SATURATE_WARNING_ON_EVS;
    1404             :             }
    1405             :             ELSE
    1406             :             {
    1407             :                 /* extending: prefer smaller synchpos for equal coeff */
    1408             :                 BASOP_SATURATE_WARNING_OFF_EVS;
    1409       66600 :                 IF( GT_32( coeff, coeff_max ) )
    1410             :                 {
    1411        6772 :                     coeff_max = L_add( coeff, 0 );
    1412        6772 :                     *synchpos = i;
    1413        6772 :                     move16();
    1414             :                 }
    1415             :                 BASOP_SATURATE_WARNING_ON_EVS;
    1416             :             }
    1417             :         }
    1418             :         /* backup old search range */
    1419         472 :         s_start_old = s_start;
    1420         472 :         move16();
    1421         472 :         s_len_old = inlen;
    1422         472 :         move16();
    1423             : 
    1424         472 :         css = shr( css, 1 );
    1425         472 :         inlen = shr( inlen, 1 );
    1426         472 :         s_start_old = s_start;
    1427         472 :         move16();
    1428         472 :         s_start = sub( *synchpos, shr( inlen, 1 ) );
    1429             : 
    1430         472 :         if ( LT_16( s_start, s_start_old ) )
    1431             :         {
    1432         142 :             s_start = s_start_old;
    1433         142 :             move16();
    1434             :         }
    1435             : 
    1436         472 :         IF( GT_16( add( s_start, inlen ), add( s_start_old, s_len_old ) ) )
    1437             :         {
    1438         121 :             inlen = add( sub( s_start_old, s_start ), s_len_old );
    1439             :         }
    1440             :     }
    1441         472 :     WHILE( ( css > 2 ) );
    1442         472 :     return 0;
    1443             : }
    1444             : 
    1445             : /*
    1446             : ********************************************************************************
    1447             : *
    1448             : *     Function        : find_synch
    1449             : *     Tables          : <none>
    1450             : *     Compile Defines : <none>
    1451             : *     Return          : 0 on success, 1 on failure
    1452             : *     Information     : Find the best match of an template segment within
    1453             : *                       a search region by similarity measures.
    1454             : *
    1455             : *                       Typical example:
    1456             : *
    1457             : *         0         10        20        30        40        50        60
    1458             : *  in[] = abcdefghijk_abcdefghijk_abcdefghijk_abcdEFGHIJk_abcdefghijk_a
    1459             : *  l_in = 61
    1460             : *  offset = 30                          |
    1461             : *  s_start = -20    <-------------------|
    1462             : *  s_len   = 15     <------------->     |
    1463             : *  search range:    ***************     |
    1464             : *  fixed_pos = 10                       |--------->
    1465             : *  corr_len = 6                         |         <---->
    1466             : *  template segment:                    |         ******
    1467             : *  synch_pos: -14         <-------------|
    1468             : *
    1469             : *                       All positions are given relative to offset. The
    1470             : *                       search region starts at offset+s_start and ends
    1471             : *                       at offset+s_start+s_len. The template segment
    1472             : *                       starts at offset+fixed_pos and ends at
    1473             : *                       offset+fixed_pos+corr_len. For correlation, the
    1474             : *                       template segment (EFGHIJ) is matched against the
    1475             : *                       segment in the search region, e.g., against (k_abcd)
    1476             : *                       in the first search position. The search position
    1477             : *                       with the best match (-14: EFGHIJ <-> efghij) is
    1478             : *                       returned.
    1479             : *
    1480             : *      19-JUN-03  N.Faerber       initial version
    1481             : *      23-APR-04  S.Doehla        added subsampling
    1482             : *
    1483             : ********************************************************************************
    1484             : */
    1485         472 : static Word16 find_synch_fx( apa_state_t *ps,
    1486             :                              const Word16 *in,
    1487             :                              Word16 l_in,
    1488             :                              Word16 s_start,
    1489             :                              Word16 s_len,
    1490             :                              Word16 fixed_pos,
    1491             :                              Word16 corr_len,
    1492             :                              Word16 offset,
    1493             :                              Word16 *energydBQ8, // Q8
    1494             :                              Word32 *qualityQ16, // Q16
    1495             :                              Word16 *synch_pos )
    1496             : {
    1497         472 :     assert( ( corr_len - 1 + s_start + s_len - 1 + offset ) < l_in );
    1498         472 :     assert( ( corr_len - 1 + fixed_pos + offset ) < l_in );
    1499             : 
    1500             :     /* pass last pitch to search function as prediction value */
    1501         472 :     *synch_pos = ps->last_pitch;
    1502         472 :     move16();
    1503         472 :     logarithmic_search_fx( ps,
    1504             :                            in,
    1505             :                            s_start,
    1506             :                            s_len,
    1507             :                            offset,
    1508             :                            fixed_pos,
    1509             :                            corr_len,
    1510         472 :                            ps->wss,
    1511             :                            // i_mult2( ps->css, ps->num_channels ),
    1512         472 :                            ps->css,
    1513             :                            synch_pos );
    1514             :     /* assert synch_pos is cleanly divisible by number of channels */
    1515         472 :     assert( *synch_pos % ps->num_channels == 0 );
    1516             : 
    1517         472 :     *qualityQ16 = 0;
    1518         472 :     move32();
    1519         472 :     get_scaling_quality_fx( ps, in, l_in, offset, corr_len,
    1520         472 :                             abs_s( sub( *synch_pos, fixed_pos ) ), energydBQ8, qualityQ16 );
    1521         472 :     ps->last_pitch = *synch_pos;
    1522         472 :     move16();
    1523         472 :     return 0;
    1524             : }
    1525             : 
    1526             : 
    1527             : /*
    1528             : ********************************************************************************
    1529             : *
    1530             : *     Function        : copy_frm
    1531             : *     Tables          : <none>
    1532             : *     Compile Defines : <none>
    1533             : *     Return          : 0 on success, 1 on failure
    1534             : *     Information     : Copy an audio.
    1535             : *
    1536             : *                       The frame size is fixed to ps->l_frm. The input data
    1537             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1538             : *                       shall include the previous output frame and the second
    1539             : *                       ps->l_frm samples shall contain the current input frame.
    1540             : *                       The output frame is stored in frm_out[] and contains
    1541             : *                       l_frm_out = ps->l_frm.
    1542             : *
    1543             : *                       The first ps->l_frm input samples are not used by
    1544             : *                       this function and are only provided for a consistent
    1545             : *                       function call with shrink_frm() and extend_frm().
    1546             : *
    1547             : ********************************************************************************
    1548             : */
    1549          40 : static bool copy_frm_fx(
    1550             :     apa_state_t *ps,
    1551             :     const Word16 frm_in_fx[], // Qx
    1552             :     Word16 frm_out_fx[],      // Qx
    1553             :     UWord16 *l_frm_out )
    1554             : {
    1555             :     UWord16 i;
    1556             : 
    1557             :     /* only 2nd input frame is used */
    1558          40 :     frm_in_fx += ps->l_frm;
    1559             : 
    1560             :     /* copy frame */
    1561       25640 :     FOR( i = 0; i < ps->l_frm; i++ )
    1562             :     {
    1563       25600 :         frm_out_fx[i] = frm_in_fx[i];
    1564       25600 :         move16();
    1565             :     }
    1566             : 
    1567             :     /* set output length */
    1568          40 :     *l_frm_out = ps->l_frm;
    1569          40 :     move16();
    1570             : 
    1571          40 :     return 0;
    1572             : }
    1573             : 
    1574             : /*
    1575             : ********************************************************************************
    1576             : *
    1577             : *     Function        : shrink_frm
    1578             : *     Tables          : <none>
    1579             : *     Compile Defines : <none>
    1580             : *     Return          : 0 on success, 1 on failure
    1581             : *     Information     : Shrink the length of an audio frame using the WSOLA
    1582             : *                       algorithm.
    1583             : *
    1584             : *                       The frame size is fixed to ps->l_frm. The input data
    1585             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1586             : *                       shall include the previous output frame and the second
    1587             : *                       ps->l_frm samples shall contain the current input frame.
    1588             : *                       The output frame is stored in frm_out[] and contains
    1589             : *                       l_frm_out samples. The amount of shrinking is signal
    1590             : *                       dependent.
    1591             : *
    1592             : *                       The first ps->l_frm input samples are not used by
    1593             : *                       this function and are only provided for a consistent
    1594             : *                       function call with extend_frm().
    1595             : *
    1596             : ********************************************************************************
    1597             : */
    1598           0 : static bool shrink_frm_fx(
    1599             :     apa_state_t *ps,
    1600             :     const Word16 frm_in_fx[], // Qx
    1601             :     UWord16 maxScaling,
    1602             :     Word16 frm_out_fx[], // Qx
    1603             :     UWord16 *l_frm_out )
    1604             : {
    1605           0 :     bool findSynchResult = 0;
    1606             :     Word16 xtract, l_rem, s_start, s_end;
    1607             :     UWord16 i;
    1608             :     UWord16 over;
    1609           0 :     Word16 energy_fx = 0;
    1610           0 :     Word32 quality_fx = 0;
    1611             :     UWord16 l_frm;
    1612             :     UWord16 l_seg;
    1613           0 :     move16();
    1614           0 :     move32();
    1615             : 
    1616           0 :     l_frm = ps->l_frm;
    1617           0 :     move16();
    1618           0 :     l_seg = ps->l_seg;
    1619           0 :     move16();
    1620             : 
    1621             :     /* only 2nd input frame is used */
    1622           0 :     frm_in_fx += l_frm;
    1623             : 
    1624             :     /* set search range */
    1625             :     // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
    1626             :     Word16 tmp, tmp_e;
    1627           0 :     tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
    1628           0 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1629           0 :     s_start = i_mult( tmp, extract_l( ps->num_channels ) );
    1630           0 :     s_end = add( s_start, extract_l( ps->l_search ) );
    1631           0 :     IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
    1632             :     {
    1633           0 :         s_end = extract_l( L_sub( l_frm, l_seg ) );
    1634             :     }
    1635             : 
    1636             :     /* calculate overlap position */
    1637           0 :     IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
    1638             :     {
    1639             :         /* maximum scaling */
    1640           0 :         energy_fx = -65 * ( 1 << 8 ); // Q8
    1641           0 :         move16();
    1642           0 :         quality_fx = 5 << Q16; // Q16
    1643           0 :         move32();
    1644           0 :         IF( ps->evs_compat_mode == false )
    1645             :         {
    1646             : 
    1647           0 :             xtract = maxScaling;
    1648           0 :             move16();
    1649             :             /* take samples already in the renderer buf into account */
    1650           0 :             xtract = add( xtract, extract_l( ps->l_r_buf ) );
    1651             :             /* snap to renderer time slot borders */
    1652           0 :             xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) );
    1653           0 :             WHILE( xtract < 0 )
    1654             :             {
    1655           0 :                 xtract = add( xtract, extract_l( ps->l_ts ) );
    1656             :             }
    1657           0 :             WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
    1658             :             {
    1659             :                 /* exceeded the possible shrinking, go back one renderer ts*/
    1660           0 :                 xtract = sub( xtract, extract_l( ps->l_ts ) );
    1661             :             }
    1662             :         }
    1663           0 :         ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
    1664             :         {
    1665           0 :             xtract = maxScaling;
    1666           0 :             move16();
    1667             :         }
    1668             :         ELSE
    1669             :         {
    1670             :             /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
    1671           0 :             xtract = sub( s_end, extract_l( ps->num_channels ) );
    1672             :         }
    1673             :     }
    1674             :     ELSE
    1675             :     {
    1676             :         /* find synch */
    1677           0 :         scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
    1678           0 :         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 );
    1679             :     }
    1680             : 
    1681             :     /* assert synch_pos is cleanly divisible by number of channels */
    1682           0 :     assert( xtract % ps->num_channels == 0 );
    1683             : 
    1684             :     /* set frame overlappable - reset if necessary */
    1685           0 :     over = 1;
    1686           0 :     move16();
    1687             : 
    1688             :     /* test whether frame has sufficient quality */
    1689           0 :     IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    1690             :                                          L_mult0( ps->bad_frame_count, 6554 ) ),
    1691             :                                   L_mult0( ps->good_frame_count, 13107 ) ) ) )
    1692             :     {
    1693             :         /* not sufficient */
    1694           0 :         over = 0;
    1695           0 :         move16();
    1696           0 :         IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    1697             :         {
    1698           0 :             ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    1699           0 :             move16();
    1700             :         }
    1701           0 :         IF( GT_32( ps->good_frame_count, 0 ) )
    1702             :         {
    1703           0 :             ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    1704           0 :             move16();
    1705             :         }
    1706             :     }
    1707             :     ELSE
    1708             :     {
    1709             :         /* sufficient quality */
    1710           0 :         IF( GT_32( ps->bad_frame_count, 0 ) )
    1711             :         {
    1712           0 :             ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    1713           0 :             move16();
    1714             :         }
    1715           0 :         IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    1716             :         {
    1717           0 :             ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    1718           0 :             move16();
    1719             :         }
    1720             :     }
    1721             : 
    1722             :     /* Calculate output data */
    1723           0 :     test();
    1724           0 :     IF( over && xtract )
    1725             :     {
    1726           0 :         IF( findSynchResult == 1 )
    1727             :         {
    1728           0 :             return 1;
    1729             :         }
    1730           0 :         IF( ps->evs_compat_mode == true )
    1731             :         {
    1732             :             // 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 );
    1733           0 :             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 );
    1734             :         }
    1735             :         ELSE
    1736             :         {
    1737           0 :             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 );
    1738             :         }
    1739             :     }
    1740             :     ELSE
    1741             :     {
    1742           0 :         xtract = 0;
    1743           0 :         move16();
    1744           0 :         FOR( i = 0; i < l_seg; i++ )
    1745             :         {
    1746           0 :             frm_out_fx[i] = frm_in_fx[i];
    1747           0 :             move16();
    1748             :         }
    1749             :     }
    1750             : 
    1751             :     /* append remaining samples */
    1752           0 :     l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
    1753           0 :     FOR( i = 0; i < l_rem; i++ )
    1754             :     {
    1755           0 :         frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
    1756           0 :         move16();
    1757             :     }
    1758             : 
    1759             :     /* set output length */
    1760           0 :     *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
    1761           0 :     move16();
    1762             : 
    1763           0 :     return 0;
    1764             : }
    1765             : 
    1766         139 : static bool shrink_frm_ivas_fx(
    1767             :     apa_state_t *ps,
    1768             :     const Word16 frm_in_fx[], // Qx
    1769             :     UWord16 maxScaling,
    1770             :     Word16 frm_out_fx[], // Qx
    1771             :     Word16 Q_frm_in,
    1772             :     UWord16 *l_frm_out )
    1773             : {
    1774         139 :     bool findSynchResult = 0;
    1775         139 :     move16();
    1776             :     Word16 xtract, l_rem, s_start, s_end;
    1777             :     UWord16 i;
    1778             :     UWord16 over;
    1779         139 :     Word16 energy_fx = 0;
    1780         139 :     Word32 quality_fx = 0;
    1781             :     UWord16 l_frm;
    1782             :     UWord16 l_seg;
    1783         139 :     move16();
    1784         139 :     move32();
    1785             : 
    1786         139 :     l_frm = ps->l_frm;
    1787         139 :     move16();
    1788         139 :     l_seg = ps->l_seg;
    1789         139 :     move16();
    1790             : 
    1791             :     /* only 2nd input frame is used */
    1792         139 :     frm_in_fx += l_frm;
    1793             : 
    1794             :     /* set search range */
    1795             :     // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
    1796             :     Word16 tmp, tmp_e;
    1797         139 :     tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
    1798         139 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1799         139 :     s_start = i_mult( tmp, extract_l( ps->num_channels ) );
    1800         139 :     s_end = add( s_start, extract_l( ps->l_search ) );
    1801         139 :     IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
    1802             :     {
    1803         139 :         s_end = extract_l( L_sub( l_frm, l_seg ) );
    1804             :     }
    1805             : 
    1806             :     /* calculate overlap position */
    1807         139 :     IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
    1808             :     {
    1809             :         /* maximum scaling */
    1810           0 :         energy_fx = -65 * ( 1 << 8 ); // Q8
    1811           0 :         move16();
    1812           0 :         quality_fx = 5 << Q16; // Q16
    1813           0 :         move32();
    1814           0 :         IF( ps->evs_compat_mode == false )
    1815             :         {
    1816             : 
    1817           0 :             xtract = maxScaling;
    1818           0 :             move16();
    1819             :             /* take samples already in the renderer buf into account */
    1820           0 :             xtract = add( xtract, extract_l( ps->l_r_buf ) );
    1821             :             /* snap to renderer time slot borders */
    1822           0 :             xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) );
    1823           0 :             WHILE( xtract < 0 )
    1824             :             {
    1825           0 :                 xtract = add( xtract, extract_l( ps->l_ts ) );
    1826             :             }
    1827           0 :             WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
    1828             :             {
    1829             :                 /* exceeded the possible shrinking, go back one renderer ts*/
    1830           0 :                 xtract = sub( xtract, extract_l( ps->l_ts ) );
    1831             :             }
    1832             :         }
    1833           0 :         ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
    1834             :         {
    1835           0 :             xtract = maxScaling;
    1836           0 :             move16();
    1837             :         }
    1838             :         ELSE
    1839             :         {
    1840             :             /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
    1841           0 :             xtract = sub( s_end, extract_l( ps->num_channels ) );
    1842             :         }
    1843             :     }
    1844             :     ELSE
    1845             :     {
    1846             :         /* find synch */
    1847         139 :         scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
    1848         139 :         ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
    1849         139 :         move16();
    1850         139 :         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 );
    1851         139 :         ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
    1852         139 :         move16();
    1853             :     }
    1854             : 
    1855             :     /* assert synch_pos is cleanly divisible by number of channels */
    1856         139 :     assert( xtract % ps->num_channels == 0 );
    1857             : 
    1858             :     /* set frame overlappable - reset if necessary */
    1859         139 :     over = 1;
    1860         139 :     move16();
    1861             : 
    1862             :     /* test whether frame has sufficient quality */
    1863         139 :     IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    1864             :                                          L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ),
    1865             :                                   L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) )
    1866             :     {
    1867             :         /* not sufficient */
    1868          94 :         over = 0;
    1869          94 :         move16();
    1870          94 :         IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    1871             :         {
    1872          50 :             ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    1873          50 :             move16();
    1874             :         }
    1875          94 :         IF( GT_32( ps->good_frame_count, 0 ) )
    1876             :         {
    1877          46 :             ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    1878          46 :             move16();
    1879             :         }
    1880             :     }
    1881             :     ELSE
    1882             :     {
    1883             :         /* sufficient quality */
    1884          45 :         IF( ps->bad_frame_count > 0 )
    1885             :         {
    1886          44 :             ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    1887          44 :             move16();
    1888             :         }
    1889          45 :         IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    1890             :         {
    1891          45 :             ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    1892          45 :             move16();
    1893             :         }
    1894             :     }
    1895             : 
    1896             :     /* Calculate output data */
    1897         139 :     test();
    1898         139 :     IF( over && xtract )
    1899             :     {
    1900          45 :         IF( findSynchResult == 1 )
    1901             :         {
    1902           0 :             return 1;
    1903             :         }
    1904          45 :         IF( EQ_16( ps->evs_compat_mode, true ) )
    1905             :         {
    1906             :             // 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 );
    1907           0 :             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 );
    1908             :         }
    1909             :         ELSE
    1910             :         {
    1911          45 :             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 );
    1912             :         }
    1913             :     }
    1914             :     ELSE
    1915             :     {
    1916          94 :         xtract = 0;
    1917          94 :         move16();
    1918       40414 :         FOR( i = 0; i < l_seg; i++ )
    1919             :         {
    1920       40320 :             frm_out_fx[i] = frm_in_fx[i];
    1921       40320 :             move16();
    1922             :         }
    1923             :     }
    1924             : 
    1925             :     /* append remaining samples */
    1926         139 :     l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
    1927       47447 :     FOR( i = 0; i < l_rem; i++ )
    1928             :     {
    1929       47308 :         frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
    1930       47308 :         move16();
    1931             :     }
    1932             : 
    1933             :     /* set output length */
    1934         139 :     *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
    1935         139 :     move16();
    1936             : 
    1937         139 :     return 0;
    1938             : }
    1939             : 
    1940             : /*
    1941             : ********************************************************************************
    1942             : *
    1943             : *     Function        : extend_frm
    1944             : *     Tables          : <none>
    1945             : *     Compile Defines : <none>
    1946             : *     Return          : 0 on success, 1 on failure
    1947             : *     Information     : Extend the length of an audio frame using the WSOLA
    1948             : *                       algorithm.
    1949             : *
    1950             : *                       The frame size is fixed to ps->l_frm. The input data
    1951             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1952             : *                       shall include the previous output frame and the second
    1953             : *                       ps->l_frm samples shall contain the current input frame.
    1954             : *                       The output frame is stored in frm_out[] and contains
    1955             : *                       l_frm_out samples. The amount of extension is signal
    1956             : *                       dependent.
    1957             : *
    1958             : ********************************************************************************
    1959             : */
    1960           0 : static bool extend_frm_fx(
    1961             :     apa_state_t *ps,
    1962             :     const Word16 frm_in_fx[], // Qx
    1963             :     Word16 frm_out_fx[],      // Qx
    1964             :     UWord16 *l_frm_out )
    1965             : {
    1966           0 :     bool findSynchResult = 0;
    1967             :     UWord16 l_frm_out_target;
    1968             :     UWord16 n, i;
    1969             :     Word16 N;
    1970             :     Word16 s[MAXN + 2], s_max, s_min;
    1971             :     Word16 xtract[MAXN + 2], sync_start, s_end;
    1972             :     UWord16 over[MAXN + 2];
    1973             :     Word16 l_rem;
    1974           0 :     Word16 s_start = 0;
    1975           0 :     move16();
    1976             :     Word16 energy_fx;
    1977           0 :     Word32 quality_fx = 0;
    1978           0 :     move32();
    1979             :     UWord16 l_frm, l_seg;
    1980             :     const Word16 *fadeOut_fx, *fadeIn_fx;
    1981             :     Word16 *out_fx;
    1982             : 
    1983           0 :     l_frm = ps->l_frm;
    1984           0 :     l_seg = ps->l_seg;
    1985           0 :     move16();
    1986           0 :     move16();
    1987             :     /* number of segments/iterations */
    1988           0 :     l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
    1989             :     //(l_frm_out_target/l_seg -1 )
    1990             :     Word16 tmp, tmp_e;
    1991           0 :     tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
    1992           0 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1993           0 :     N = sub( ( tmp ), 1 );
    1994           0 :     if ( LT_16( N, 1 ) )
    1995             :     {
    1996           0 :         N = 1;
    1997           0 :         move16();
    1998             :     }
    1999           0 :     IF( GT_16( N, MAXN ) )
    2000             :     {
    2001           0 :         return 1;
    2002             :     }
    2003             :     /* calculate equally spaced search regions */
    2004             :     /* s[n] are given relative to 2nd frame and point to the start of */
    2005             :     /* the search region. The first segment (n=1) will not be moved. */
    2006             :     /* Hence, the iterations will start with n=2. */
    2007           0 :     s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
    2008             :     /* (make sure not to exceed array dimension) */
    2009           0 :     IF( L_add( l_frm, s_min ) < 0 )
    2010             :     {
    2011           0 :         s_min = extract_l( L_negate( l_frm ) );
    2012             :     }
    2013           0 :     s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
    2014           0 :     if ( s_max < s_min )
    2015             :     {
    2016           0 :         N = 1;
    2017           0 :         move16();
    2018             :     }
    2019             :     /* for just one segment start at s_min */
    2020           0 :     if ( N == 1 )
    2021             :     {
    2022           0 :         s[2] = s_min;
    2023           0 :         move16();
    2024             :     }
    2025             :     /* else, spread linear in between s_min and s_max */
    2026             :     /* (including s_min and s_max) */
    2027             :     ELSE
    2028             :     {
    2029           0 :         FOR( n = 2; n <= ( N + 1 ); n++ )
    2030             :         {
    2031             :             // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
    2032             :             Word16 tmp2, tmp2_e;
    2033           0 :             tmp2 = sub( s_max, s_min );
    2034           0 :             tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
    2035           0 :             tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
    2036           0 :             tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
    2037           0 :             s[n] = add( s_min, tmp2 );
    2038           0 :             move16();
    2039             :         }
    2040             :     }
    2041             : 
    2042             :     /*
    2043             :      *  Planning Phase
    2044             :      */
    2045             : 
    2046           0 :     xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
    2047           0 :     move16();
    2048           0 :     n = 2;
    2049           0 :     move16();
    2050             :     /* define synch segment (to be correlated with search region) */
    2051           0 :     sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
    2052           0 :     over[n] = 1; /* will be reset if overlap is not required */
    2053           0 :     move16();
    2054             :     /* check end of search region: should be at least p_min */
    2055             :     /* samples on the left of synch_start */
    2056           0 :     IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
    2057             :     {
    2058           0 :         s_start = s[n];
    2059           0 :         move16();
    2060           0 :         s_end = extract_l( L_add( s_start, ps->l_search ) );
    2061             :     }
    2062             :     ELSE
    2063             :     {
    2064             :         /* shrink search region to enforce minimum shift */
    2065           0 :         s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
    2066           0 :         IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
    2067             :         {
    2068           0 :             s_start = s[n]; /* just do it with normal start position */
    2069           0 :             move16();
    2070             :         }
    2071           0 :         ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
    2072             :         {
    2073           0 :             s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
    2074             :         }
    2075             :         ELSE
    2076             :         {
    2077           0 :             over[n] = 0; /* don't search/overlap (just copy down) */
    2078           0 :             move16();
    2079             :         }
    2080             :     }
    2081             : 
    2082           0 :     IF( over[n] )
    2083             :     {
    2084             :         /* calculate overlap position */
    2085           0 :         IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
    2086             :         {
    2087             :             /* maximum scaling */
    2088           0 :             energy_fx = -65 * ( 1 << 8 ); // Q8
    2089           0 :             move16();
    2090           0 :             quality_fx = 5 << 16; // Q16
    2091           0 :             move32();
    2092           0 :             xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
    2093           0 :             move16();
    2094           0 :             IF( ps->evs_compat_mode == false )
    2095             :             {
    2096             :                 /* take renderer buffer samples into accout */
    2097           0 :                 xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
    2098             :                 /* snap to next renderer time slot border to resynchronize */
    2099             :                 // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
    2100             :                 Word16 tmp3;
    2101           0 :                 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 ) );
    2102           0 :                 xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
    2103           0 :                 move16();
    2104           0 :                 move16();
    2105             :             }
    2106             :         }
    2107             :         ELSE
    2108             :         {
    2109             :             Word16 *frmInScaled;
    2110           0 :             frmInScaled = ps->frmInScaled;
    2111           0 :             assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
    2112           0 :             scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
    2113           0 :             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] );
    2114             :         }
    2115             :         /* assert synch_pos is cleanly divisible by number of channels */
    2116           0 :         assert( xtract[n] % ps->num_channels == 0 );
    2117             : 
    2118             :         /* test for sufficient quality */
    2119           0 :         IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    2120             :                                              L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
    2121             :                                       L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
    2122             :         {
    2123             :             /* not sufficient */
    2124           0 :             over[n] = 0;
    2125           0 :             move16();
    2126           0 :             xtract[n] = sync_start;
    2127           0 :             move16();
    2128           0 :             IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    2129             :             {
    2130           0 :                 ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    2131           0 :                 move16();
    2132             :             }
    2133           0 :             IF( GT_32( ps->good_frame_count, 0 ) )
    2134             :             {
    2135           0 :                 ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    2136           0 :                 move16();
    2137             :             }
    2138             :         }
    2139             :         ELSE
    2140             :         {
    2141             :             /* sufficient quality */
    2142           0 :             IF( GT_32( ps->bad_frame_count, 0 ) )
    2143             :             {
    2144           0 :                 ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    2145           0 :                 move16();
    2146             :             }
    2147           0 :             IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    2148             :             {
    2149           0 :                 ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    2150           0 :                 move16();
    2151             :             }
    2152             :         }
    2153           0 :         IF( findSynchResult )
    2154             :         {
    2155           0 :             return 1;
    2156             :         }
    2157             :     }
    2158             :     ELSE
    2159             :     {
    2160           0 :         xtract[n] = sync_start;
    2161           0 :         move16();
    2162             :     }
    2163             : 
    2164             : 
    2165             :     /* Calculate output data */
    2166           0 :     FOR( n = 2; n <= N; n++ )
    2167             :     {
    2168           0 :         test();
    2169           0 :         IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
    2170             :         {
    2171             :             /* mix 2nd half of previous segment with 1st half of current segment */
    2172           0 :             fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
    2173           0 :             fadeIn_fx = frm_in_fx + l_frm + xtract[n];
    2174           0 :             out_fx = frm_out_fx + ( n - 2 ) * l_seg;
    2175           0 :             IF( ps->evs_compat_mode == true )
    2176             :             {
    2177             :                 // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
    2178           0 :                 overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
    2179             :             }
    2180             :             ELSE
    2181             :             {
    2182           0 :                 overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
    2183             :             }
    2184             :         }
    2185             :         ELSE
    2186             :         {
    2187             :             /* just copy down 1st half of current segment (= 2nd half of previous segment) */
    2188             :             Word16 *frm_out_ptr;
    2189             :             const Word16 *frm_in_ptr;
    2190           0 :             frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
    2191           0 :             frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
    2192           0 :             FOR( i = 0; i < l_seg; i++ )
    2193             :             {
    2194           0 :                 frm_out_ptr[i] = frm_in_ptr[i];
    2195           0 :                 move16();
    2196             :             }
    2197             :         }
    2198             :     }
    2199             : 
    2200             :     /* append remaining samples */
    2201           0 :     l_rem = l_frm - ( xtract[N] + l_seg );
    2202           0 :     FOR( i = 0; i < l_rem; i++ )
    2203             :     {
    2204           0 :         frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
    2205           0 :         move16();
    2206             :     }
    2207             : 
    2208             :     /* set output length */
    2209           0 :     *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
    2210           0 :     move16();
    2211           0 :     return 0;
    2212             : }
    2213             : 
    2214             : 
    2215         333 : static bool extend_frm_ivas_fx(
    2216             :     apa_state_t *ps,
    2217             :     const Word16 frm_in_fx[], // Qx
    2218             :     Word16 frm_out_fx[],      // Qx
    2219             :     Word16 Q_frm_in,
    2220             :     UWord16 *l_frm_out )
    2221             : {
    2222         333 :     bool findSynchResult = 0;
    2223         333 :     move16();
    2224             :     UWord16 l_frm_out_target;
    2225             :     UWord16 n, i;
    2226             :     Word16 N;
    2227             :     Word16 s[MAXN + 2], s_max, s_min;
    2228             :     Word16 xtract[MAXN + 2], sync_start, s_end;
    2229             :     UWord16 over[MAXN + 2];
    2230             :     Word16 l_rem;
    2231         333 :     Word16 s_start = 0;
    2232         333 :     move16();
    2233             :     Word16 energy_fx;
    2234         333 :     Word32 quality_fx = 0;
    2235         333 :     move32();
    2236             :     UWord16 l_frm, l_seg;
    2237             :     const Word16 *fadeOut_fx, *fadeIn_fx;
    2238             :     Word16 *out_fx;
    2239             : 
    2240         333 :     l_frm = ps->l_frm;
    2241         333 :     l_seg = ps->l_seg;
    2242         333 :     move16();
    2243         333 :     move16();
    2244             :     /* number of segments/iterations */
    2245         333 :     l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
    2246             :     //(l_frm_out_target/l_seg -1 )
    2247             :     Word16 tmp, tmp_e;
    2248         333 :     tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
    2249         333 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    2250         333 :     N = sub( ( tmp ), 1 );
    2251         333 :     if ( LT_16( N, 1 ) )
    2252             :     {
    2253           0 :         N = 1;
    2254           0 :         move16();
    2255             :     }
    2256         333 :     IF( GT_16( N, MAXN ) )
    2257             :     {
    2258           0 :         return 1;
    2259             :     }
    2260             :     /* calculate equally spaced search regions */
    2261             :     /* s[n] are given relative to 2nd frame and point to the start of */
    2262             :     /* the search region. The first segment (n=1) will not be moved. */
    2263             :     /* Hence, the iterations will start with n=2. */
    2264         333 :     s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
    2265             :     /* (make sure not to exceed array dimension) */
    2266         333 :     IF( L_add( l_frm, s_min ) < 0 )
    2267             :     {
    2268           0 :         s_min = extract_l( L_negate( l_frm ) );
    2269             :     }
    2270         333 :     s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
    2271         333 :     if ( s_max < s_min )
    2272             :     {
    2273           0 :         N = 1;
    2274           0 :         move16();
    2275             :     }
    2276             :     /* for just one segment start at s_min */
    2277         333 :     if ( N == 1 )
    2278             :     {
    2279           0 :         s[2] = s_min;
    2280           0 :         move16();
    2281             :     }
    2282             :     /* else, spread linear in between s_min and s_max */
    2283             :     /* (including s_min and s_max) */
    2284             :     ELSE
    2285             :     {
    2286         999 :         FOR( n = 2; n <= ( N + 1 ); n++ )
    2287             :         {
    2288             :             // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
    2289             :             Word16 tmp2, tmp2_e;
    2290         666 :             tmp2 = sub( s_max, s_min );
    2291         666 :             tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
    2292         666 :             tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
    2293         666 :             tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
    2294         666 :             s[n] = add( s_min, tmp2 );
    2295         666 :             move16();
    2296             :         }
    2297             :     }
    2298             : 
    2299             :     /*
    2300             :      *  Planning Phase
    2301             :      */
    2302             : 
    2303         333 :     xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
    2304         333 :     move16();
    2305         333 :     n = 2;
    2306         333 :     move16();
    2307             :     /* define synch segment (to be correlated with search region) */
    2308         333 :     sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
    2309         333 :     over[n] = 1; /* will be reset if overlap is not required */
    2310         333 :     move16();
    2311             :     /* check end of search region: should be at least p_min */
    2312             :     /* samples on the left of synch_start */
    2313         333 :     IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
    2314             :     {
    2315           0 :         s_start = s[n];
    2316           0 :         move16();
    2317           0 :         s_end = extract_l( L_add( s_start, ps->l_search ) );
    2318             :     }
    2319             :     ELSE
    2320             :     {
    2321             :         /* shrink search region to enforce minimum shift */
    2322         333 :         s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
    2323         333 :         IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
    2324             :         {
    2325         333 :             s_start = s[n]; /* just do it with normal start position */
    2326         333 :             move16();
    2327             :         }
    2328           0 :         ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
    2329             :         {
    2330           0 :             s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
    2331             :         }
    2332             :         ELSE
    2333             :         {
    2334           0 :             over[n] = 0; /* don't search/overlap (just copy down) */
    2335           0 :             move16();
    2336             :         }
    2337             :     }
    2338             : 
    2339         333 :     IF( over[n] )
    2340             :     {
    2341             :         /* calculate overlap position */
    2342         333 :         IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
    2343             :         {
    2344             :             /* maximum scaling */
    2345           0 :             energy_fx = -65 * ( 1 << 8 ); // Q8
    2346           0 :             move16();
    2347           0 :             quality_fx = 5 << 16; // Q16
    2348           0 :             move32();
    2349           0 :             xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
    2350           0 :             move16();
    2351           0 :             IF( ps->evs_compat_mode == false )
    2352             :             {
    2353             :                 /* take renderer buffer samples into accout */
    2354           0 :                 xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
    2355             :                 /* snap to next renderer time slot border to resynchronize */
    2356             :                 // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
    2357             :                 Word16 tmp3;
    2358           0 :                 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 ) );
    2359           0 :                 xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
    2360           0 :                 move16();
    2361           0 :                 move16();
    2362             :             }
    2363             :         }
    2364             :         ELSE
    2365             :         {
    2366             :             Word16 *frmInScaled;
    2367         333 :             frmInScaled = ps->frmInScaled;
    2368         333 :             assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
    2369         333 :             scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
    2370         333 :             ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
    2371         333 :             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] );
    2372         333 :             ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
    2373             :         }
    2374             :         /* assert synch_pos is cleanly divisible by number of channels */
    2375         333 :         assert( xtract[n] % ps->num_channels == 0 );
    2376             : 
    2377             :         /* test for sufficient quality */
    2378         333 :         IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    2379             :                                              L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
    2380             :                                       L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
    2381             :         {
    2382             :             /* not sufficient */
    2383         292 :             over[n] = 0;
    2384         292 :             move16();
    2385         292 :             xtract[n] = sync_start;
    2386         292 :             move16();
    2387         292 :             IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    2388             :             {
    2389          99 :                 ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    2390          99 :                 move16();
    2391             :             }
    2392         292 :             IF( GT_32( ps->good_frame_count, 0 ) )
    2393             :             {
    2394          17 :                 ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    2395          17 :                 move16();
    2396             :             }
    2397             :         }
    2398             :         ELSE
    2399             :         {
    2400             :             /* sufficient quality */
    2401          41 :             IF( GT_32( ps->bad_frame_count, 0 ) )
    2402             :             {
    2403          38 :                 ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    2404          38 :                 move16();
    2405             :             }
    2406          41 :             IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    2407             :             {
    2408          41 :                 ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    2409          41 :                 move16();
    2410             :             }
    2411             :         }
    2412         333 :         IF( findSynchResult )
    2413             :         {
    2414           0 :             return 1;
    2415             :         }
    2416             :     }
    2417             :     ELSE
    2418             :     {
    2419           0 :         xtract[n] = sync_start;
    2420           0 :         move16();
    2421             :     }
    2422             : 
    2423             : 
    2424             :     /* Calculate output data */
    2425         666 :     FOR( n = 2; n <= N; n++ )
    2426             :     {
    2427         333 :         test();
    2428         333 :         IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
    2429             :         {
    2430             :             /* mix 2nd half of previous segment with 1st half of current segment */
    2431          41 :             fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
    2432          41 :             fadeIn_fx = frm_in_fx + l_frm + xtract[n];
    2433          41 :             out_fx = frm_out_fx + ( n - 2 ) * l_seg;
    2434          41 :             IF( EQ_16( ps->evs_compat_mode, true ) )
    2435             :             {
    2436             :                 // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
    2437           0 :                 overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
    2438             :             }
    2439             :             ELSE
    2440             :             {
    2441          41 :                 overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
    2442             :             }
    2443             :         }
    2444             :         ELSE
    2445             :         {
    2446             :             /* just copy down 1st half of current segment (= 2nd half of previous segment) */
    2447             :             Word16 *frm_out_ptr;
    2448             :             const Word16 *frm_in_ptr;
    2449         292 :             frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
    2450         292 :             frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
    2451      292292 :             FOR( i = 0; i < l_seg; i++ )
    2452             :             {
    2453      292000 :                 frm_out_ptr[i] = frm_in_ptr[i];
    2454      292000 :                 move16();
    2455             :             }
    2456             :         }
    2457             :     }
    2458             : 
    2459             :     /* append remaining samples */
    2460         333 :     l_rem = l_frm - ( xtract[N] + l_seg );
    2461      381768 :     FOR( i = 0; i < l_rem; i++ )
    2462             :     {
    2463      381435 :         frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
    2464      381435 :         move16();
    2465             :     }
    2466             : 
    2467             :     /* set output length */
    2468         333 :     *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
    2469         333 :     move16();
    2470         333 :     return 0;
    2471             : }

Generated by: LCOV version 1.14