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

Generated by: LCOV version 1.14