LCOV - code coverage report
Current view: top level - lib_dec - jbm_pcmdsp_apa_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 548 921 59.5 %
Date: 2025-08-23 01:22:27 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          28 : ivas_error apa_init(
     165             :     apa_state_t **pps,
     166             :     const Word32 num_channels )
     167             : {
     168          28 :     apa_state_t *ps = NULL;
     169             : 
     170             :     /* make sure pointer is valid */
     171          28 :     IF( !pps )
     172             :     {
     173           0 :         return 1;
     174             :     }
     175             : 
     176             :     /* allocate state struct */
     177          28 :     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          28 :     ps->num_channels = (UWord16) num_channels;
     183          28 :     move16();
     184          28 :     ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
     185          28 :     move16();
     186             : 
     187          28 :     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          28 :     memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
     192          28 :     ps->Q_buf_out = Q15;
     193          28 :     move16();
     194             : 
     195          28 :     ps->evs_compat_mode = false;
     196          28 :     move16();
     197             : 
     198          28 :     apa_reset( ps );
     199          28 :     *pps = ps;
     200             : 
     201          28 :     return IVAS_ERR_OK;
     202             : }
     203             : 
     204             : 
     205             : /* Sets state variables to initial value. */
     206          56 : void apa_reset(
     207             :     apa_state_t *ps )
     208             : {
     209             :     /* init state struct */
     210          56 :     ps->signalScaleForCorrelation = 0;
     211          56 :     move16();
     212          56 :     ps->l_buf_out = 0;
     213          56 :     move16();
     214          56 :     ps->l_halfwin = 0;
     215          56 :     move16();
     216          56 :     ps->rate = 0;
     217          56 :     move16();
     218          56 :     ps->l_seg = 0;
     219          56 :     move16();
     220          56 :     ps->l_frm = 0;
     221          56 :     move16();
     222          56 :     ps->l_in_total = 0;
     223          56 :     move32();
     224          56 :     ps->diffSinceSetScale = 0;
     225          56 :     move32();
     226          56 :     ps->nFramesSinceSetScale = 0;
     227          56 :     move32();
     228          56 :     ps->scale = 100;
     229          56 :     move16();
     230          56 :     ps->p_min = 0;
     231          56 :     move16();
     232          56 :     ps->l_search = 0;
     233          56 :     move16();
     234          56 :     ps->wss = 1;
     235          56 :     move16();
     236          56 :     ps->css = 1;
     237          56 :     move16();
     238          56 :     ps->targetQuality_fx = 0;
     239          56 :     move32();
     240             : 
     241          56 :     ps->qualityred = 0;
     242          56 :     move16();
     243          56 :     ps->qualityrise = 0;
     244          56 :     move16();
     245          56 :     ps->last_pitch = 0;
     246          56 :     move16();
     247          56 :     ps->bad_frame_count = 0;
     248          56 :     move16();
     249          56 :     ps->good_frame_count = 0;
     250          56 :     move16();
     251             : 
     252          56 :     ps->l_ts = 1;
     253          56 :     move16();
     254          56 :     ps->l_r_buf = 0;
     255          56 :     move16();
     256          56 :     return;
     257             : }
     258             : 
     259         941 : UWord8 apa_reconfigure(
     260             :     apa_state_t *ps,
     261             :     UWord16 num_channels,
     262             :     UWord16 l_ts )
     263             : {
     264             : 
     265             :     /* realloc buffer */
     266         941 :     ps->num_channels = (UWord16) num_channels;
     267         941 :     move16();
     268         941 :     ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
     269         941 :     move16();
     270             : 
     271         941 :     free( ps->buf_out_fx );
     272         941 :     ps->buf_out_fx = (Word16 *) malloc( sizeof( Word16 ) * ps->buf_out_capacity );
     273         941 :     memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
     274         941 :     ps->Q_buf_out = Q15;
     275         941 :     move16();
     276         941 :     IF( !ps->buf_out_fx )
     277             :     {
     278           0 :         return 2;
     279             :     }
     280             : 
     281         941 :     ps->l_buf_out = 0;
     282         941 :     ps->l_in_total = 0;
     283         941 :     move16();
     284         941 :     move32();
     285         941 :     ps->l_ts = (UWord16) imult3216( l_ts, ps->num_channels );
     286         941 :     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         941 :     ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), (Word16) ps->num_channels ); // Q0
     294         941 :     move16();
     295             : 
     296             :     /* set frame size */
     297             :     /* set to 320 samples at 16 kHz */
     298         941 :     ps->l_frm = (UWord16) imult3216( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ), (Word16) ps->num_channels ); // Q0
     299         941 :     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         941 :     ps->p_min = (UWord16) imult3216( Mult_32_16( ps->rate, INV_400_Q15 ), (Word16) ps->num_channels ); // Q0
     305         941 :     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         941 :     ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), (Word16) ps->num_channels ); // Q0
     311         941 :     move16();
     312             : 
     313         941 :     return 0;
     314             : }
     315             : 
     316             : /* Sets the audio configuration. */
     317          28 : bool apa_set_rate(
     318             :     apa_state_t *ps,
     319             :     const Word32 output_Fs )
     320             : {
     321             :     /* make sure pointer is valid */
     322          28 :     IF( ps == NULL )
     323             :     {
     324           0 :         return 1;
     325             :     }
     326             : 
     327             :     /* check range */
     328          28 :     test();
     329          28 :     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          28 :     apa_reset( ps );
     336             : 
     337             :     /* copy rate to state struct */
     338          28 :     ps->rate = (UWord16) output_Fs;
     339          28 :     move16();
     340             : 
     341          28 :     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          28 :     ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), ps->num_channels ); // Q0
     360          28 :     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          28 :     ps->l_halfwin = (UWord16) Mult_32_16( ps->rate, INV_100_Q15 ); // Q0
     367          28 :     move16();
     368             : 
     369             :     /* set frame size */
     370             :     /* set to 320 samples at 16 kHz */
     371          28 :     ps->l_frm = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ) ), ps->num_channels ); // Q0
     372          28 :     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          28 :     ps->p_min = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_400_Q15 ) ), ps->num_channels ); // Q0
     378          28 :     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          28 :     ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), ps->num_channels ); // Q0
     384          28 :     move16();
     385             : 
     386          28 :     ps->win_fx = pcmdsp_window_hann_640;
     387          28 :     ps->l_halfwin = 320;
     388          28 :     move16();
     389          28 :     ps->win_incrementor = 1;
     390          28 :     move16();
     391          28 :     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          28 :     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          28 :     if ( EQ_32( ps->rate, 16000 ) )
     408             :     {
     409           3 :         ps->win_incrementor = 2;
     410           3 :         move16();
     411             :     }
     412          28 :     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          28 :     ps->signalScaleForCorrelation = getSignalScaleForCorrelation( ps->rate );
     424          28 :     move16();
     425          28 :     return 0;
     426             : }
     427             : 
     428             : /* Set scaling. */
     429       19553 : bool apa_set_scale_fx(
     430             :     apa_state_t *ps,
     431             :     UWord16 scale )
     432             : {
     433             :     /* make sure pointer is valid */
     434       19553 :     IF( ps == NULL )
     435             :     {
     436           0 :         return 1;
     437             :     }
     438             : 
     439             :     /* check range */
     440       19553 :     test();
     441       19553 :     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       19553 :     IF( EQ_32( (Word32) ps->scale, (Word32) scale ) )
     449             :     {
     450       19474 :         return 0;
     451             :     }
     452             : 
     453             :     /* copy to state struct */
     454          79 :     ps->scale = scale;
     455          79 :     move16();
     456             : 
     457             :     /* reset scaling statistics */
     458          79 :     ps->diffSinceSetScale = 0;
     459          79 :     move32();
     460          79 :     ps->nFramesSinceSetScale = 0;
     461          79 :     move32();
     462             : 
     463          79 :     return 0;
     464             : }
     465             : 
     466          28 : bool apa_set_renderer_granularity(
     467             :     apa_state_t *ps,
     468             :     UWord16 l_ts )
     469             : {
     470             :     /* make sure pointer is valid */
     471          28 :     IF( ps == NULL )
     472             :     {
     473           0 :         return 1;
     474             :     }
     475             : 
     476             : 
     477             :     /* copy to state struct */
     478          28 :     ps->l_ts = (UWord16) imult3216( l_ts, (Word16) ps->num_channels );
     479          28 :     move16();
     480          28 :     return 0;
     481             : }
     482             : 
     483       19553 : bool apa_set_renderer_residual_samples(
     484             :     apa_state_t *ps,
     485             :     UWord16 l_r_buf )
     486             : {
     487             :     /* make sure pointer is valid */
     488       19553 :     IF( ps == NULL )
     489             :     {
     490           0 :         return 1;
     491             :     }
     492             : 
     493             : 
     494             :     /* copy to state struct */
     495       19553 :     ps->l_r_buf = (UWord16) imult3216( l_r_buf, (Word16) ps->num_channels );
     496       19553 :     move16();
     497       19553 :     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          28 : bool apa_set_quality(
     542             :     apa_state_t *ps,
     543             :     Word32 quality, // Q16
     544             :     UWord16 qualityred,
     545             :     UWord16 qualityrise )
     546             : {
     547          28 :     assert( ps != NULL );
     548          28 :     assert( -131072 /*-2.0f in Q16*/ <= quality && quality <= 203161 /*3.1f in Q16*/ );
     549          28 :     assert( qualityred > 0 && qualityred <= 20 );
     550          28 :     assert( qualityrise > 0 && qualityrise <= 20 );
     551             : 
     552          28 :     ps->targetQuality_fx = quality;
     553          28 :     move32();
     554          28 :     ps->qualityred = qualityred;
     555          28 :     move16();
     556          28 :     ps->qualityrise = qualityrise;
     557          28 :     move16();
     558          28 :     ps->bad_frame_count = 0;
     559          28 :     move16();
     560          28 :     ps->good_frame_count = 0;
     561          28 :     move16();
     562             : 
     563          28 :     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          28 : bool apa_set_complexity_options(
     582             :     apa_state_t *ps,
     583             :     UWord16 wss,
     584             :     UWord16 css )
     585             : {
     586             :     /* make sure pointer is valid */
     587          28 :     IF( ps == NULL )
     588             :     {
     589           0 :         return 1;
     590             :     }
     591             : 
     592          28 :     test();
     593          28 :     IF( wss == 0 || GT_32( wss, 1000 ) )
     594             :     {
     595           0 :         return 1;
     596             :     }
     597             : 
     598          28 :     test();
     599          28 :     IF( css == 0 || GT_32( css, 1000 ) )
     600             :     {
     601           0 :         return 1;
     602             :     }
     603             : 
     604          28 :     ps->wss = wss;
     605          28 :     move16();
     606          28 :     ps->css = css;
     607          28 :     move16();
     608             : 
     609          28 :     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         613 : bool apa_exit(
     626             :     apa_state_t **pps )
     627             : {
     628             :     /* ignore NULL pointer input */
     629         613 :     IF( *pps == NULL )
     630             :     {
     631         585 :         return 0;
     632             :     }
     633             : 
     634             :     /* deallocate state struct members */
     635          28 :     free( ( *pps )->buf_out_fx );
     636             : 
     637             :     /* deallocate state struct */
     638          28 :     free( *pps );
     639             : 
     640             :     /* set pointer to NULL */
     641          28 :     *pps = NULL;
     642             : 
     643          28 :     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       19553 : 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       19553 :     Q_a_out = add( getScaleFactor32_copy( a_in, L_mult0( ps->num_channels, APA_BUF_PER_CHANNEL ) ), Q11 - Q16 - Q1 );
     902       19553 :     statsResetThreshold = 1637;
     903       19553 :     move32();
     904       19553 :     statsResetShift = 2;
     905       19553 :     move32();
     906             : 
     907             :     /* Convert max_scaling from "per channel" to total */
     908       19553 :     maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
     909             : 
     910             :     /* make sure no invalid output is used */
     911       19553 :     *l_out = 0;
     912       19553 :     move16();
     913       19553 :     l_frm_out = 0;
     914       19553 :     move16();
     915             : 
     916             :     /* make sure pointer is valid */
     917       19553 :     IF( ps == NULL )
     918             :     {
     919           0 :         return 1;
     920             :     }
     921             :     /* check available rate */
     922       19553 :     IF( ps->rate == 0 )
     923             :     {
     924           0 :         return 2;
     925             :     }
     926             :     /* check size of input */
     927       19553 :     IF( NE_32( l_in, ps->l_frm ) )
     928             :     {
     929           0 :         return 3;
     930             :     }
     931             : 
     932             :     /* get target length */
     933       19553 :     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         486 :         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       19067 :     ELSE IF( LT_32( ps->scale, 100 ) )
     939             :     {
     940         109 :         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       18958 :         expScaling = 0;
     945       18958 :         move32();
     946             :     }
     947       19553 :     actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
     948       19553 :     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       19553 :     IF( LT_32( ps->l_buf_out, ps->l_frm ) )
     954             :     {
     955     2296329 :         FOR( i = 0; i < ps->l_frm; i++ )
     956             :         {
     957     2295360 :             a_out[i] = a_in[i];
     958     2295360 :             move32();
     959             :         }
     960         969 :         l_frm_out = ps->l_frm;
     961         969 :         move16();
     962             :     }
     963             :     ELSE
     964             :     {
     965             :         Word16 a_tmp[APA_BUF];
     966       18584 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
     967             : 
     968       18584 :         Q_a_out = s_min( Q_a_out, ps->Q_buf_out );
     969       18584 :         Scale_sig( ps->buf_out_fx, ps->buf_out_capacity, sub( Q_a_out, ps->Q_buf_out ) ); // Q_buf_out -> Q_a_out
     970       18584 :         IF( EQ_32( ps->scale, 100 ) )
     971             :         {
     972   118219090 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
     973             :             {
     974   118200960 :                 a_out[i] = a_in[i]; // Q11
     975   118200960 :                 move32();
     976             :             }
     977       18130 :             l_frm_out = ps->l_frm;
     978       18130 :             move16();
     979             :         }
     980             :         ELSE
     981             :         {
     982         454 :             Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
     983             : 
     984     3226054 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
     985             :             {
     986     3225600 :                 a_tmp[i] = extract_h( L_shl( a_in[i], add( Q_a_out, Q5 ) ) ); // Q_a_out
     987     3225600 :                 move16();
     988             :             }
     989             :             /* fill input frame */
     990             :             /* 1st input frame: previous output samples */
     991      915334 :             FOR( i = 0; i < ps->l_frm; i++ )
     992             :             {
     993      914880 :                 frm_in[i] = buf_out_ptr[i];
     994      914880 :                 move16();
     995             :             }
     996             :             /* 2nd input frame: new input samples */
     997      915334 :             FOR( i = 0; i < ps->l_frm; i++ )
     998             :             {
     999      914880 :                 frm_in_ptr[i] = a_tmp[i];
    1000      914880 :                 move16();
    1001             :             }
    1002             :             /* shrink */
    1003         454 :             IF( LT_32( ps->scale, 100 ) )
    1004             :             {
    1005         103 :                 shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out );
    1006             :             }
    1007             :             /* extend */
    1008             :             ELSE
    1009             :             {
    1010         351 :                 extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out );
    1011             :             }
    1012             :             /* control the amount/frequency of scaling */
    1013         454 :             IF( NE_32( l_frm_out, ps->l_frm ) )
    1014             :             {
    1015          65 :                 test();
    1016          65 :                 IF( ( maxScaling != 0 ) &&
    1017             :                     GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
    1018             :                 {
    1019             :                     /* maxScaling exceeded -> discard scaled frame */
    1020          15 :                     copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
    1021             :                 }
    1022          50 :                 ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
    1023             :                 {
    1024          42 :                     dl_copied = L_sub( l_frm_out_target, ps->l_frm );
    1025          42 :                     dl_scaled = L_sub( l_frm_out_target, l_frm_out );
    1026             :                     /* discard scaled frame if copied frame is closer to target length */
    1027          42 :                     IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
    1028             :                     {
    1029           1 :                         copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
    1030             :                     }
    1031             :                 }
    1032             :             }
    1033             : 
    1034     3226054 :             FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
    1035             :             {
    1036     3225600 :                 a_out[i] = L_shl( a_tmp[i], sub( Q11, Q_a_out ) ); // Q0 -> Q11
    1037     3225600 :                 move32();
    1038             :             }
    1039             :         }
    1040             :     }
    1041             : 
    1042             :     /* copy output to internal buffer */
    1043             :     /* avoid buffer overflow: */
    1044             :     /* discard old samples; always keep at least most recent l_frm samples */
    1045       19553 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
    1046             :     {
    1047        4765 :         Word16 *buf_out_ptr1 = ps->buf_out_fx;
    1048             :         Word16 *buf_out_ptr2;
    1049             : 
    1050        4765 :         l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
    1051        4765 :         if ( l_rem < 0 )
    1052             :         {
    1053          21 :             l_rem = 0;
    1054          21 :             move16();
    1055             :         }
    1056        4765 :         buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
    1057        5551 :         FOR( i = 0; i < l_rem; i++ )
    1058             :         {
    1059         786 :             buf_out_ptr1[i] = buf_out_ptr2[i];
    1060         786 :             move16();
    1061             :         }
    1062        4765 :         ps->l_buf_out = l_rem;
    1063        4765 :         move16();
    1064             :     }
    1065             :     /* append new output samples */
    1066       19553 :     IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
    1067             :     {
    1068           0 :         return 5;
    1069             :     }
    1070             :     {
    1071       19553 :         Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
    1072    35847328 :         FOR( i = 0; i < l_frm_out; i++ )
    1073             :         {
    1074    35827775 :             buf_out_ptr[i] = extract_h( L_shl( a_out[i], add( Q_a_out, Q16 - Q11 ) ) ); // Q_a_out
    1075    35827775 :             move16();
    1076             :         }
    1077       19553 :         ps->Q_buf_out = Q_a_out;
    1078       19553 :         move16();
    1079             :     }
    1080       19553 :     ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
    1081       19553 :     move16();
    1082             : 
    1083       19553 :     *l_out = l_frm_out;
    1084       19553 :     move16();
    1085             :     /* update time */
    1086       19553 :     ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
    1087       19553 :     move32();
    1088             : 
    1089       19553 :     test();
    1090       19553 :     IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
    1091             :         LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
    1092             :     {
    1093       19553 :         ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
    1094       19553 :         move32();
    1095       19553 :         ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
    1096       19553 :         move32();
    1097             :     }
    1098             :     ELSE /* scale statistics down to avoid overflow */
    1099             :     {
    1100           0 :         ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
    1101           0 :         move32();
    1102           0 :         ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
    1103           0 :         move32();
    1104             :     }
    1105             : 
    1106       19553 :     return 0;
    1107             : }
    1108             : 
    1109             : 
    1110             : /*---------------------------------------------------------------------*
    1111             :  * Local functions
    1112             :  *---------------------------------------------------------------------*/
    1113             : 
    1114             : /*
    1115             : ********************************************************************************
    1116             : *
    1117             : *     Function        : get_scaling_quality
    1118             : *     Tables          : <none>
    1119             : *     Compile Defines : <none>
    1120             : *     Return          : 0 on success, 1 on failure
    1121             : *     Information     : Uses pitch, half pitch, three halves and double pitch
    1122             : *                       to evaluate the quality of the scaled frame by checking
    1123             : *                       periodicity.
    1124             : *                       Silence can be detected as additional feature. This must
    1125             : *                       be set in global struct apa_state.
    1126             : *
    1127             : *                       If search length is very narrow then use fewer points
    1128             : *                       to evaluate periodicity and silence.
    1129             : *
    1130             : *                       Computationally not very efficient by using normalized
    1131             : *                       cross-correlation: Using sqrt() for energy calculation
    1132             : *                       adds complexity.
    1133             : *
    1134             : *     03-AUG-04  S.Doehla        initial version
    1135             : *
    1136             : ********************************************************************************
    1137             : */
    1138         454 : static void get_scaling_quality_fx( const apa_state_t *ps,
    1139             :                                     const Word16 *signal,
    1140             :                                     Word16 s_len,
    1141             :                                     Word16 offset,
    1142             :                                     Word16 corr_len,
    1143             :                                     Word16 pitch,
    1144             :                                     Word16 *energydBQ8, // Q8
    1145             :                                     Word32 *qualityQ16  // Q16
    1146             : )
    1147             : {
    1148             :     Word32 energy, maxEnergy;
    1149             :     Word32 qualityOfMaxEnergy; /* we measure the quality for all channels and select the one with highest energy */
    1150             :     Word16 half_pitch_cn;
    1151             :     Word16 pitch_cn;
    1152             :     Word16 three_halves_pitch_cn;
    1153             :     Word16 double_pitch_cn;
    1154             :     Word32 pitch_energy;
    1155             :     Word32 half_pitch_energy;
    1156             :     Word32 three_halves_pitch_energy;
    1157             :     Word32 double_pitch_energy;
    1158             :     Word16 i;
    1159             : 
    1160             : 
    1161         454 :     maxEnergy = 0;
    1162         454 :     qualityOfMaxEnergy = 0;
    1163         454 :     move32();
    1164         454 :     move32();
    1165             : 
    1166        1574 :     FOR( i = 0; i < ps->num_channels; i++ )
    1167             :     {
    1168        1120 :         offset = 0;
    1169        1120 :         move16();
    1170             : 
    1171        1120 :         pitch_cn = normalized_cross_correlation_self_fx( signal, add( pitch, offset ), offset, corr_len,
    1172        1120 :                                                          shl( ps->num_channels, 1 ), &pitch_energy );
    1173        1120 :         IF( pitch_cn > 0 )
    1174             :         {
    1175             :             /* calculate correlation for double pitch */
    1176         779 :             IF( LE_16( add( add( shl( pitch, 1 ), offset ), corr_len ), s_len ) )
    1177             :             {
    1178         659 :                 double_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shl( pitch, 1 ), offset ),
    1179         659 :                                                                         offset, corr_len, shl( ps->num_channels, 1 ), &double_pitch_energy );
    1180             :             }
    1181             :             ELSE
    1182             :             {
    1183         120 :                 double_pitch_cn = pitch_cn;
    1184         120 :                 move16();
    1185         120 :                 double_pitch_energy = L_add( pitch_energy, 0 );
    1186             :             }
    1187             :             /* calculate correlation for three/half pitch */
    1188         779 :             IF( LE_16( add( add( shr( i_mult2( pitch, 3 ), 1 ), offset ), corr_len ), s_len ) )
    1189             :             {
    1190         693 :                 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 );
    1191             :             }
    1192             :             ELSE
    1193             :             {
    1194          86 :                 three_halves_pitch_cn = pitch_cn;
    1195          86 :                 move16();
    1196          86 :                 three_halves_pitch_energy = L_add( pitch_energy, 0 );
    1197             :             }
    1198             :             /* calculate correlation for half pitch */
    1199         779 :             IF( LE_16( add( add( shr( pitch, 1 ), offset ), corr_len ), s_len ) )
    1200             :             {
    1201         779 :                 half_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( pitch, 1 ), offset ),
    1202         779 :                                                                       offset, corr_len, shl( ps->num_channels, 1 ), &half_pitch_energy );
    1203             :             }
    1204             :             ELSE
    1205             :             {
    1206           0 :                 half_pitch_cn = pitch_cn;
    1207           0 :                 move16();
    1208           0 :                 half_pitch_energy = L_add( pitch_energy, 0 );
    1209             :             }
    1210             : 
    1211             :             /* combine correlation results: Q15.16 */
    1212         779 :             *qualityQ16 = L_shr( L_mac0( L_mult0( half_pitch_cn, three_halves_pitch_cn ),
    1213             :                                          pitch_cn, double_pitch_cn ),
    1214             :                                  14 );
    1215         779 :             move32();
    1216             :             BASOP_SATURATE_WARNING_OFF_EVS
    1217         779 :             energy = L_add( L_add( L_add( pitch_energy, half_pitch_energy ), three_halves_pitch_energy ), double_pitch_energy );
    1218             :             BASOP_SATURATE_WARNING_ON_EVS
    1219             :         }
    1220             :         ELSE
    1221             :         {
    1222         341 :             *qualityQ16 = L_shl( L_deposit_l( pitch_cn ), 1 ); /* value is negative, thus pass it */
    1223         341 :             move32();
    1224         341 :             energy = L_add( pitch_energy, 0 );
    1225             :         }
    1226             : 
    1227             :         /* update the quality by the quality of the signal with the highest energy */
    1228        1120 :         IF( GT_32( energy, maxEnergy ) )
    1229             :         {
    1230         659 :             qualityOfMaxEnergy = L_add( *qualityQ16, 0 );
    1231         659 :             maxEnergy = L_add( energy, 0 );
    1232             :         }
    1233             : 
    1234             :         /* go to next channel */
    1235        1120 :         ++signal;
    1236             :     }
    1237         454 :     *qualityQ16 = qualityOfMaxEnergy;
    1238         454 :     move32();
    1239             : 
    1240             :     /* increase calculated quality of signals with low energy */
    1241         454 :     *energydBQ8 = apa_corrEnergy2dB_fx( maxEnergy, shl( ps->signalScaleForCorrelation, 1 ), corr_len );
    1242         454 :     *qualityQ16 = L_add( *qualityQ16, L_shl( L_deposit_l( apa_getQualityIncreaseForLowEnergy_fx( *energydBQ8 ) ), 8 ) );
    1243         454 :     move16();
    1244         454 :     move32();
    1245         454 : }
    1246             : 
    1247             : /* Converts the correlation energy to dB. */
    1248         454 : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len )
    1249             : {
    1250             : 
    1251             :     Word16 result, tmpScale;
    1252             : 
    1253             :     /* normalise before dividing */
    1254         454 :     tmpScale = norm_l( energy );
    1255         454 :     energy = L_shl( energy, tmpScale );
    1256         454 :     energyExp = sub( energyExp, tmpScale );
    1257             : 
    1258             :     /* divide energy by corr_len */
    1259         454 :     result = BASOP_Util_Divide3216_Scale( energy, corr_len, &tmpScale );
    1260         454 :     energyExp = add( energyExp, tmpScale );
    1261             : 
    1262         454 :     result = BASOP_Util_lin2dB( L_deposit_l( result ), energyExp, 1 );
    1263         454 :     return result;
    1264             : }
    1265             : 
    1266             : /* Increases the calculated quality of signals with low energy. */
    1267         454 : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydBQ8 )
    1268             : {
    1269             :     Word16 qualIncreaseMinEnergy, qualIncreaseMaxEnergy, qualIncForLowEnergy; /* Q8 */
    1270             : 
    1271         454 :     qualIncreaseMinEnergy = -65 * ( 1 << 8 ); // Q8
    1272         454 :     move16();
    1273         454 :     qualIncreaseMaxEnergy = -40 * ( 1 << 8 ); // Q8
    1274         454 :     move16();
    1275         454 :     qualIncForLowEnergy = 0;
    1276         454 :     move16();
    1277             : 
    1278             :     /* increase calculated quality of signals with low energy */
    1279         454 :     IF( LT_16( energydBQ8, qualIncreaseMaxEnergy ) )
    1280             :     {
    1281         108 :         qualIncForLowEnergy = energydBQ8;
    1282         108 :         move16();
    1283         108 :         if ( LT_16( qualIncForLowEnergy, qualIncreaseMinEnergy ) )
    1284             :         {
    1285           0 :             qualIncForLowEnergy = qualIncreaseMinEnergy;
    1286           0 :             move16();
    1287             :         }
    1288         108 :         if ( GT_16( qualIncForLowEnergy, qualIncreaseMaxEnergy ) )
    1289             :         {
    1290           0 :             qualIncForLowEnergy = qualIncreaseMaxEnergy;
    1291           0 :             move16();
    1292             :         }
    1293             :         /* -50:   (-50 - -40) / (-65 - -40) * 20
    1294             :          *      = -10 / -25 * 20
    1295             :          */
    1296         108 :         qualIncForLowEnergy = divide1616( sub( qualIncForLowEnergy, qualIncreaseMaxEnergy ),
    1297         108 :                                           sub( qualIncreaseMinEnergy, qualIncreaseMaxEnergy ) );
    1298             :         /* apply factor 2 and scale back to Q8 */
    1299         108 :         assert( qualIncForLowEnergy >= 0 );
    1300         108 :         qualIncForLowEnergy = shr( qualIncForLowEnergy, 7 - 1 );
    1301         108 :         assert( qualIncForLowEnergy >= 0 && qualIncForLowEnergy <= ( 2 << 8 ) );
    1302             :     }
    1303         454 :     return qualIncForLowEnergy;
    1304             : }
    1305             : 
    1306             : 
    1307             : /*
    1308             : ********************************************************************************
    1309             : *
    1310             : *     Function        : logarithmic_search
    1311             : *     Tables          : <none>
    1312             : *     Compile Defines : <none>
    1313             : *     Return          : 0 on success, 1 on failure
    1314             : *     Information     : Search for best match of a template segment using
    1315             : *                       hierarchical search method:
    1316             : *                       Parameter css is used for sampling every css'd correlation
    1317             : *                       value. The area around the best match so far is used for
    1318             : *                       further correlation value with half css-value until css=1.
    1319             : *                       Search area length is always half previous search length.
    1320             : *                       Parameter wss is passed to the correlation computation
    1321             : *                       If the search area passes the boundaries, the search
    1322             : *                       window is reduced so that it's entirely inside the
    1323             : *                       boundaries.
    1324             : *
    1325             : ********************************************************************************
    1326             : */
    1327         454 : static Word8 logarithmic_search_fx( const apa_state_t *ps,
    1328             :                                     const Word16 *signal,
    1329             :                                     Word16 s_start,
    1330             :                                     Word16 inlen,
    1331             :                                     Word16 offset,
    1332             :                                     Word16 fixed_pos,
    1333             :                                     Word16 corr_len,
    1334             :                                     Word16 wss,
    1335             :                                     Word16 css,
    1336             :                                     Word16 *synchpos )
    1337             : {
    1338             :     Word16 i;
    1339             :     Word32 coeff;
    1340             :     Word32 coeff_max;
    1341             :     Word16 s_start_old, s_len_old;
    1342             : 
    1343             :     DO
    1344             :     {
    1345         454 :         coeff_max = 0x80000000; /* will always be overwritten with result of first correlation */
    1346         454 :         move32();
    1347             : 
    1348       83014 :         FOR( i = s_start; i < s_start + inlen; i += css * ps->num_channels )
    1349             :         {
    1350       82560 :             test();
    1351       82560 :             IF( EQ_16( wss, 1 ) && EQ_16( ps->num_channels, 1 ) )
    1352             :             {
    1353           0 :                 coeff = cross_correlation_self_fx( signal, add( i, offset ), add( fixed_pos, offset ), corr_len );
    1354             :             }
    1355             :             ELSE
    1356             :             {
    1357       82560 :                 coeff = cross_correlation_subsampled_self_fx( signal, add( i, offset ), add( fixed_pos, offset ),
    1358       82560 :                                                               corr_len, i_mult2( wss, ps->num_channels ) );
    1359             :             }
    1360             : 
    1361             :             /* update max corr */
    1362       82560 :             IF( LT_16( ps->scale, 100 ) )
    1363             :             {
    1364             :                 /* shrinking: prefer greater synchpos for equal coeff */
    1365             :                 BASOP_SATURATE_WARNING_OFF_EVS;
    1366       12360 :                 IF( GE_32( coeff, coeff_max ) )
    1367             :                 {
    1368        1588 :                     coeff_max = L_add( coeff, 0 );
    1369        1588 :                     *synchpos = i;
    1370        1588 :                     move16();
    1371             :                 }
    1372             :                 BASOP_SATURATE_WARNING_ON_EVS;
    1373             :             }
    1374             :             ELSE
    1375             :             {
    1376             :                 /* extending: prefer smaller synchpos for equal coeff */
    1377             :                 BASOP_SATURATE_WARNING_OFF_EVS;
    1378       70200 :                 IF( GT_32( coeff, coeff_max ) )
    1379             :                 {
    1380        7141 :                     coeff_max = L_add( coeff, 0 );
    1381        7141 :                     *synchpos = i;
    1382        7141 :                     move16();
    1383             :                 }
    1384             :                 BASOP_SATURATE_WARNING_ON_EVS;
    1385             :             }
    1386             :         }
    1387             :         /* backup old search range */
    1388         454 :         s_start_old = s_start;
    1389         454 :         move16();
    1390         454 :         s_len_old = inlen;
    1391         454 :         move16();
    1392             : 
    1393         454 :         css = shr( css, 1 );
    1394         454 :         inlen = shr( inlen, 1 );
    1395         454 :         s_start_old = s_start;
    1396         454 :         move16();
    1397         454 :         s_start = sub( *synchpos, shr( inlen, 1 ) );
    1398             : 
    1399         454 :         if ( LT_16( s_start, s_start_old ) )
    1400             :         {
    1401         116 :             s_start = s_start_old;
    1402         116 :             move16();
    1403             :         }
    1404             : 
    1405         454 :         IF( GT_16( add( s_start, inlen ), add( s_start_old, s_len_old ) ) )
    1406             :         {
    1407         116 :             inlen = add( sub( s_start_old, s_start ), s_len_old );
    1408             :         }
    1409             :     }
    1410         454 :     WHILE( ( css > 2 ) );
    1411         454 :     return 0;
    1412             : }
    1413             : 
    1414             : /*
    1415             : ********************************************************************************
    1416             : *
    1417             : *     Function        : find_synch
    1418             : *     Tables          : <none>
    1419             : *     Compile Defines : <none>
    1420             : *     Return          : 0 on success, 1 on failure
    1421             : *     Information     : Find the best match of an template segment within
    1422             : *                       a search region by similarity measures.
    1423             : *
    1424             : *                       Typical example:
    1425             : *
    1426             : *         0         10        20        30        40        50        60
    1427             : *  in[] = abcdefghijk_abcdefghijk_abcdefghijk_abcdEFGHIJk_abcdefghijk_a
    1428             : *  l_in = 61
    1429             : *  offset = 30                          |
    1430             : *  s_start = -20    <-------------------|
    1431             : *  s_len   = 15     <------------->     |
    1432             : *  search range:    ***************     |
    1433             : *  fixed_pos = 10                       |--------->
    1434             : *  corr_len = 6                         |         <---->
    1435             : *  template segment:                    |         ******
    1436             : *  synch_pos: -14         <-------------|
    1437             : *
    1438             : *                       All positions are given relative to offset. The
    1439             : *                       search region starts at offset+s_start and ends
    1440             : *                       at offset+s_start+s_len. The template segment
    1441             : *                       starts at offset+fixed_pos and ends at
    1442             : *                       offset+fixed_pos+corr_len. For correlation, the
    1443             : *                       template segment (EFGHIJ) is matched against the
    1444             : *                       segment in the search region, e.g., against (k_abcd)
    1445             : *                       in the first search position. The search position
    1446             : *                       with the best match (-14: EFGHIJ <-> efghij) is
    1447             : *                       returned.
    1448             : *
    1449             : *      19-JUN-03  N.Faerber       initial version
    1450             : *      23-APR-04  S.Doehla        added subsampling
    1451             : *
    1452             : ********************************************************************************
    1453             : */
    1454         454 : static Word16 find_synch_fx( apa_state_t *ps,
    1455             :                              const Word16 *in,
    1456             :                              Word16 l_in,
    1457             :                              Word16 s_start,
    1458             :                              Word16 s_len,
    1459             :                              Word16 fixed_pos,
    1460             :                              Word16 corr_len,
    1461             :                              Word16 offset,
    1462             :                              Word16 *energydBQ8, // Q8
    1463             :                              Word32 *qualityQ16, // Q16
    1464             :                              Word16 *synch_pos )
    1465             : {
    1466         454 :     assert( ( corr_len - 1 + s_start + s_len - 1 + offset ) < l_in );
    1467         454 :     assert( ( corr_len - 1 + fixed_pos + offset ) < l_in );
    1468             : 
    1469             :     /* pass last pitch to search function as prediction value */
    1470         454 :     *synch_pos = ps->last_pitch;
    1471         454 :     move16();
    1472         454 :     logarithmic_search_fx( ps,
    1473             :                            in,
    1474             :                            s_start,
    1475             :                            s_len,
    1476             :                            offset,
    1477             :                            fixed_pos,
    1478             :                            corr_len,
    1479         454 :                            ps->wss,
    1480             :                            // i_mult2( ps->css, ps->num_channels ),
    1481         454 :                            ps->css,
    1482             :                            synch_pos );
    1483             :     /* assert synch_pos is cleanly divisible by number of channels */
    1484         454 :     assert( *synch_pos % ps->num_channels == 0 );
    1485             : 
    1486         454 :     *qualityQ16 = 0;
    1487         454 :     move32();
    1488         454 :     get_scaling_quality_fx( ps, in, l_in, offset, corr_len,
    1489         454 :                             abs_s( sub( *synch_pos, fixed_pos ) ), energydBQ8, qualityQ16 );
    1490         454 :     ps->last_pitch = *synch_pos;
    1491         454 :     move16();
    1492         454 :     return 0;
    1493             : }
    1494             : 
    1495             : 
    1496             : /*
    1497             : ********************************************************************************
    1498             : *
    1499             : *     Function        : copy_frm
    1500             : *     Tables          : <none>
    1501             : *     Compile Defines : <none>
    1502             : *     Return          : 0 on success, 1 on failure
    1503             : *     Information     : Copy an audio.
    1504             : *
    1505             : *                       The frame size is fixed to ps->l_frm. The input data
    1506             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1507             : *                       shall include the previous output frame and the second
    1508             : *                       ps->l_frm samples shall contain the current input frame.
    1509             : *                       The output frame is stored in frm_out[] and contains
    1510             : *                       l_frm_out = ps->l_frm.
    1511             : *
    1512             : *                       The first ps->l_frm input samples are not used by
    1513             : *                       this function and are only provided for a consistent
    1514             : *                       function call with shrink_frm() and extend_frm().
    1515             : *
    1516             : ********************************************************************************
    1517             : */
    1518          16 : static bool copy_frm_fx(
    1519             :     apa_state_t *ps,
    1520             :     const Word16 frm_in_fx[], // Qx
    1521             :     Word16 frm_out_fx[],      // Qx
    1522             :     UWord16 *l_frm_out )
    1523             : {
    1524             :     UWord16 i;
    1525             : 
    1526             :     /* only 2nd input frame is used */
    1527          16 :     frm_in_fx += ps->l_frm;
    1528             : 
    1529             :     /* copy frame */
    1530       20496 :     FOR( i = 0; i < ps->l_frm; i++ )
    1531             :     {
    1532       20480 :         frm_out_fx[i] = frm_in_fx[i];
    1533       20480 :         move16();
    1534             :     }
    1535             : 
    1536             :     /* set output length */
    1537          16 :     *l_frm_out = ps->l_frm;
    1538          16 :     move16();
    1539             : 
    1540          16 :     return 0;
    1541             : }
    1542             : 
    1543             : /*
    1544             : ********************************************************************************
    1545             : *
    1546             : *     Function        : shrink_frm
    1547             : *     Tables          : <none>
    1548             : *     Compile Defines : <none>
    1549             : *     Return          : 0 on success, 1 on failure
    1550             : *     Information     : Shrink the length of an audio frame using the WSOLA
    1551             : *                       algorithm.
    1552             : *
    1553             : *                       The frame size is fixed to ps->l_frm. The input data
    1554             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1555             : *                       shall include the previous output frame and the second
    1556             : *                       ps->l_frm samples shall contain the current input frame.
    1557             : *                       The output frame is stored in frm_out[] and contains
    1558             : *                       l_frm_out samples. The amount of shrinking is signal
    1559             : *                       dependent.
    1560             : *
    1561             : *                       The first ps->l_frm input samples are not used by
    1562             : *                       this function and are only provided for a consistent
    1563             : *                       function call with extend_frm().
    1564             : *
    1565             : ********************************************************************************
    1566             : */
    1567           0 : static bool shrink_frm_fx(
    1568             :     apa_state_t *ps,
    1569             :     const Word16 frm_in_fx[], // Qx
    1570             :     UWord16 maxScaling,
    1571             :     Word16 frm_out_fx[], // Qx
    1572             :     UWord16 *l_frm_out )
    1573             : {
    1574           0 :     bool findSynchResult = 0;
    1575             :     Word16 xtract, l_rem, s_start, s_end;
    1576             :     UWord16 i;
    1577             :     UWord16 over;
    1578           0 :     Word16 energy_fx = 0;
    1579           0 :     Word32 quality_fx = 0;
    1580             :     UWord16 l_frm;
    1581             :     UWord16 l_seg;
    1582           0 :     move16();
    1583           0 :     move32();
    1584             : 
    1585           0 :     l_frm = ps->l_frm;
    1586           0 :     move16();
    1587           0 :     l_seg = ps->l_seg;
    1588           0 :     move16();
    1589             : 
    1590             :     /* only 2nd input frame is used */
    1591           0 :     frm_in_fx += l_frm;
    1592             : 
    1593             :     /* set search range */
    1594             :     // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
    1595             :     Word16 tmp, tmp_e;
    1596           0 :     tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
    1597           0 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1598           0 :     s_start = i_mult( tmp, extract_l( ps->num_channels ) );
    1599           0 :     s_end = add( s_start, extract_l( ps->l_search ) );
    1600           0 :     IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
    1601             :     {
    1602           0 :         s_end = extract_l( L_sub( l_frm, l_seg ) );
    1603             :     }
    1604             : 
    1605             :     /* calculate overlap position */
    1606           0 :     IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
    1607             :     {
    1608             :         /* maximum scaling */
    1609           0 :         energy_fx = -65 * ( 1 << 8 ); // Q8
    1610           0 :         move16();
    1611           0 :         quality_fx = 5 << Q16; // Q16
    1612           0 :         move32();
    1613           0 :         IF( ps->evs_compat_mode == false )
    1614             :         {
    1615             : 
    1616           0 :             xtract = maxScaling;
    1617           0 :             move16();
    1618             :             /* take samples already in the renderer buf into account */
    1619           0 :             xtract = add( xtract, extract_l( ps->l_r_buf ) );
    1620             :             /* snap to renderer time slot borders */
    1621           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 ) ) );
    1622           0 :             WHILE( xtract < 0 )
    1623             :             {
    1624           0 :                 xtract = add( xtract, extract_l( ps->l_ts ) );
    1625             :             }
    1626           0 :             WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
    1627             :             {
    1628             :                 /* exceeded the possible shrinking, go back one renderer ts*/
    1629           0 :                 xtract = sub( xtract, extract_l( ps->l_ts ) );
    1630             :             }
    1631             :         }
    1632           0 :         ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
    1633             :         {
    1634           0 :             xtract = maxScaling;
    1635           0 :             move16();
    1636             :         }
    1637             :         ELSE
    1638             :         {
    1639             :             /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
    1640           0 :             xtract = sub( s_end, extract_l( ps->num_channels ) );
    1641             :         }
    1642             :     }
    1643             :     ELSE
    1644             :     {
    1645             :         /* find synch */
    1646           0 :         scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
    1647           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 );
    1648             :     }
    1649             : 
    1650             :     /* assert synch_pos is cleanly divisible by number of channels */
    1651           0 :     assert( xtract % ps->num_channels == 0 );
    1652             : 
    1653             :     /* set frame overlappable - reset if necessary */
    1654           0 :     over = 1;
    1655           0 :     move16();
    1656             : 
    1657             :     /* test whether frame has sufficient quality */
    1658           0 :     IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    1659             :                                          L_mult0( ps->bad_frame_count, 6554 ) ),
    1660             :                                   L_mult0( ps->good_frame_count, 13107 ) ) ) )
    1661             :     {
    1662             :         /* not sufficient */
    1663           0 :         over = 0;
    1664           0 :         move16();
    1665           0 :         IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    1666             :         {
    1667           0 :             ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    1668           0 :             move16();
    1669             :         }
    1670           0 :         IF( GT_32( ps->good_frame_count, 0 ) )
    1671             :         {
    1672           0 :             ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    1673           0 :             move16();
    1674             :         }
    1675             :     }
    1676             :     ELSE
    1677             :     {
    1678             :         /* sufficient quality */
    1679           0 :         IF( GT_32( ps->bad_frame_count, 0 ) )
    1680             :         {
    1681           0 :             ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    1682           0 :             move16();
    1683             :         }
    1684           0 :         IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    1685             :         {
    1686           0 :             ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    1687           0 :             move16();
    1688             :         }
    1689             :     }
    1690             : 
    1691             :     /* Calculate output data */
    1692           0 :     test();
    1693           0 :     IF( over && xtract )
    1694             :     {
    1695           0 :         IF( findSynchResult == 1 )
    1696             :         {
    1697           0 :             return 1;
    1698             :         }
    1699           0 :         IF( ps->evs_compat_mode == true )
    1700             :         {
    1701             :             // 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 );
    1702           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 );
    1703             :         }
    1704             :         ELSE
    1705             :         {
    1706           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 );
    1707             :         }
    1708             :     }
    1709             :     ELSE
    1710             :     {
    1711           0 :         xtract = 0;
    1712           0 :         move16();
    1713           0 :         FOR( i = 0; i < l_seg; i++ )
    1714             :         {
    1715           0 :             frm_out_fx[i] = frm_in_fx[i];
    1716           0 :             move16();
    1717             :         }
    1718             :     }
    1719             : 
    1720             :     /* append remaining samples */
    1721           0 :     l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
    1722           0 :     FOR( i = 0; i < l_rem; i++ )
    1723             :     {
    1724           0 :         frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
    1725           0 :         move16();
    1726             :     }
    1727             : 
    1728             :     /* set output length */
    1729           0 :     *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
    1730           0 :     move16();
    1731             : 
    1732           0 :     return 0;
    1733             : }
    1734             : 
    1735         103 : static bool shrink_frm_ivas_fx(
    1736             :     apa_state_t *ps,
    1737             :     const Word16 frm_in_fx[], // Qx
    1738             :     UWord16 maxScaling,
    1739             :     Word16 frm_out_fx[], // Qx
    1740             :     Word16 Q_frm_in,
    1741             :     UWord16 *l_frm_out )
    1742             : {
    1743         103 :     bool findSynchResult = 0;
    1744         103 :     move16();
    1745             :     Word16 xtract, l_rem, s_start, s_end;
    1746             :     UWord16 i;
    1747             :     UWord16 over;
    1748         103 :     Word16 energy_fx = 0;
    1749         103 :     Word32 quality_fx = 0;
    1750             :     UWord16 l_frm;
    1751             :     UWord16 l_seg;
    1752         103 :     move16();
    1753         103 :     move32();
    1754             : 
    1755         103 :     l_frm = ps->l_frm;
    1756         103 :     move16();
    1757         103 :     l_seg = ps->l_seg;
    1758         103 :     move16();
    1759             : 
    1760             :     /* only 2nd input frame is used */
    1761         103 :     frm_in_fx += l_frm;
    1762             : 
    1763             :     /* set search range */
    1764             :     // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
    1765             :     Word16 tmp, tmp_e;
    1766         103 :     tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
    1767         103 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1768         103 :     s_start = i_mult( tmp, extract_l( ps->num_channels ) );
    1769         103 :     s_end = add( s_start, extract_l( ps->l_search ) );
    1770         103 :     IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
    1771             :     {
    1772         103 :         s_end = extract_l( L_sub( l_frm, l_seg ) );
    1773             :     }
    1774             : 
    1775             :     /* calculate overlap position */
    1776         103 :     IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
    1777             :     {
    1778             :         /* maximum scaling */
    1779           0 :         energy_fx = -65 * ( 1 << 8 ); // Q8
    1780           0 :         move16();
    1781           0 :         quality_fx = 5 << Q16; // Q16
    1782           0 :         move32();
    1783           0 :         IF( ps->evs_compat_mode == false )
    1784             :         {
    1785             : 
    1786           0 :             xtract = maxScaling;
    1787           0 :             move16();
    1788             :             /* take samples already in the renderer buf into account */
    1789           0 :             xtract = add( xtract, extract_l( ps->l_r_buf ) );
    1790             :             /* snap to renderer time slot borders */
    1791           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 ) ) );
    1792           0 :             WHILE( xtract < 0 )
    1793             :             {
    1794           0 :                 xtract = add( xtract, extract_l( ps->l_ts ) );
    1795             :             }
    1796           0 :             WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
    1797             :             {
    1798             :                 /* exceeded the possible shrinking, go back one renderer ts*/
    1799           0 :                 xtract = sub( xtract, extract_l( ps->l_ts ) );
    1800             :             }
    1801             :         }
    1802           0 :         ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
    1803             :         {
    1804           0 :             xtract = maxScaling;
    1805           0 :             move16();
    1806             :         }
    1807             :         ELSE
    1808             :         {
    1809             :             /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
    1810           0 :             xtract = sub( s_end, extract_l( ps->num_channels ) );
    1811             :         }
    1812             :     }
    1813             :     ELSE
    1814             :     {
    1815             :         /* find synch */
    1816         103 :         scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
    1817         103 :         ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
    1818         103 :         move16();
    1819         103 :         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 );
    1820         103 :         ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
    1821         103 :         move16();
    1822             :     }
    1823             : 
    1824             :     /* assert synch_pos is cleanly divisible by number of channels */
    1825         103 :     assert( xtract % ps->num_channels == 0 );
    1826             : 
    1827             :     /* set frame overlappable - reset if necessary */
    1828         103 :     over = 1;
    1829         103 :     move16();
    1830             : 
    1831             :     /* test whether frame has sufficient quality */
    1832         103 :     IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    1833             :                                          L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ),
    1834             :                                   L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) )
    1835             :     {
    1836             :         /* not sufficient */
    1837          79 :         over = 0;
    1838          79 :         move16();
    1839          79 :         IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    1840             :         {
    1841          31 :             ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    1842          31 :             move16();
    1843             :         }
    1844          79 :         IF( GT_32( ps->good_frame_count, 0 ) )
    1845             :         {
    1846          25 :             ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    1847          25 :             move16();
    1848             :         }
    1849             :     }
    1850             :     ELSE
    1851             :     {
    1852             :         /* sufficient quality */
    1853          24 :         IF( ps->bad_frame_count > 0 )
    1854             :         {
    1855          24 :             ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    1856          24 :             move16();
    1857             :         }
    1858          24 :         IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    1859             :         {
    1860          24 :             ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    1861          24 :             move16();
    1862             :         }
    1863             :     }
    1864             : 
    1865             :     /* Calculate output data */
    1866         103 :     test();
    1867         103 :     IF( over && xtract )
    1868             :     {
    1869          24 :         IF( findSynchResult == 1 )
    1870             :         {
    1871           0 :             return 1;
    1872             :         }
    1873          24 :         IF( EQ_16( ps->evs_compat_mode, true ) )
    1874             :         {
    1875             :             // 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 );
    1876           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 );
    1877             :         }
    1878             :         ELSE
    1879             :         {
    1880          24 :             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 );
    1881             :         }
    1882             :     }
    1883             :     ELSE
    1884             :     {
    1885          79 :         xtract = 0;
    1886          79 :         move16();
    1887       58319 :         FOR( i = 0; i < l_seg; i++ )
    1888             :         {
    1889       58240 :             frm_out_fx[i] = frm_in_fx[i];
    1890       58240 :             move16();
    1891             :         }
    1892             :     }
    1893             : 
    1894             :     /* append remaining samples */
    1895         103 :     l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
    1896       65015 :     FOR( i = 0; i < l_rem; i++ )
    1897             :     {
    1898       64912 :         frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
    1899       64912 :         move16();
    1900             :     }
    1901             : 
    1902             :     /* set output length */
    1903         103 :     *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
    1904         103 :     move16();
    1905             : 
    1906         103 :     return 0;
    1907             : }
    1908             : 
    1909             : /*
    1910             : ********************************************************************************
    1911             : *
    1912             : *     Function        : extend_frm
    1913             : *     Tables          : <none>
    1914             : *     Compile Defines : <none>
    1915             : *     Return          : 0 on success, 1 on failure
    1916             : *     Information     : Extend the length of an audio frame using the WSOLA
    1917             : *                       algorithm.
    1918             : *
    1919             : *                       The frame size is fixed to ps->l_frm. The input data
    1920             : *                       is stored in frm_in[], where the first ps->l_frm samples
    1921             : *                       shall include the previous output frame and the second
    1922             : *                       ps->l_frm samples shall contain the current input frame.
    1923             : *                       The output frame is stored in frm_out[] and contains
    1924             : *                       l_frm_out samples. The amount of extension is signal
    1925             : *                       dependent.
    1926             : *
    1927             : ********************************************************************************
    1928             : */
    1929           0 : static bool extend_frm_fx(
    1930             :     apa_state_t *ps,
    1931             :     const Word16 frm_in_fx[], // Qx
    1932             :     Word16 frm_out_fx[],      // Qx
    1933             :     UWord16 *l_frm_out )
    1934             : {
    1935           0 :     bool findSynchResult = 0;
    1936             :     UWord16 l_frm_out_target;
    1937             :     UWord16 n, i;
    1938             :     Word16 N;
    1939             :     Word16 s[MAXN + 2], s_max, s_min;
    1940             :     Word16 xtract[MAXN + 2], sync_start, s_end;
    1941             :     UWord16 over[MAXN + 2];
    1942             :     Word16 l_rem;
    1943           0 :     Word16 s_start = 0;
    1944           0 :     move16();
    1945             :     Word16 energy_fx;
    1946           0 :     Word32 quality_fx = 0;
    1947           0 :     move32();
    1948             :     UWord16 l_frm, l_seg;
    1949             :     const Word16 *fadeOut_fx, *fadeIn_fx;
    1950             :     Word16 *out_fx;
    1951             : 
    1952           0 :     l_frm = ps->l_frm;
    1953           0 :     l_seg = ps->l_seg;
    1954           0 :     move16();
    1955           0 :     move16();
    1956             :     /* number of segments/iterations */
    1957           0 :     l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
    1958             :     //(l_frm_out_target/l_seg -1 )
    1959             :     Word16 tmp, tmp_e;
    1960           0 :     tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
    1961           0 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    1962           0 :     N = sub( ( tmp ), 1 );
    1963           0 :     if ( LT_16( N, 1 ) )
    1964             :     {
    1965           0 :         N = 1;
    1966           0 :         move16();
    1967             :     }
    1968           0 :     IF( GT_16( N, MAXN ) )
    1969             :     {
    1970           0 :         return 1;
    1971             :     }
    1972             :     /* calculate equally spaced search regions */
    1973             :     /* s[n] are given relative to 2nd frame and point to the start of */
    1974             :     /* the search region. The first segment (n=1) will not be moved. */
    1975             :     /* Hence, the iterations will start with n=2. */
    1976           0 :     s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
    1977             :     /* (make sure not to exceed array dimension) */
    1978           0 :     IF( L_add( l_frm, s_min ) < 0 )
    1979             :     {
    1980           0 :         s_min = extract_l( L_negate( l_frm ) );
    1981             :     }
    1982           0 :     s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
    1983           0 :     if ( s_max < s_min )
    1984             :     {
    1985           0 :         N = 1;
    1986           0 :         move16();
    1987             :     }
    1988             :     /* for just one segment start at s_min */
    1989           0 :     if ( N == 1 )
    1990             :     {
    1991           0 :         s[2] = s_min;
    1992           0 :         move16();
    1993             :     }
    1994             :     /* else, spread linear in between s_min and s_max */
    1995             :     /* (including s_min and s_max) */
    1996             :     ELSE
    1997             :     {
    1998           0 :         FOR( n = 2; n <= ( N + 1 ); n++ )
    1999             :         {
    2000             :             // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
    2001             :             Word16 tmp2, tmp2_e;
    2002           0 :             tmp2 = sub( s_max, s_min );
    2003           0 :             tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
    2004           0 :             tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
    2005           0 :             tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
    2006           0 :             s[n] = add( s_min, tmp2 );
    2007           0 :             move16();
    2008             :         }
    2009             :     }
    2010             : 
    2011             :     /*
    2012             :      *  Planning Phase
    2013             :      */
    2014             : 
    2015           0 :     xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
    2016           0 :     move16();
    2017           0 :     n = 2;
    2018           0 :     move16();
    2019             :     /* define synch segment (to be correlated with search region) */
    2020           0 :     sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
    2021           0 :     over[n] = 1; /* will be reset if overlap is not required */
    2022           0 :     move16();
    2023             :     /* check end of search region: should be at least p_min */
    2024             :     /* samples on the left of synch_start */
    2025           0 :     IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
    2026             :     {
    2027           0 :         s_start = s[n];
    2028           0 :         move16();
    2029           0 :         s_end = extract_l( L_add( s_start, ps->l_search ) );
    2030             :     }
    2031             :     ELSE
    2032             :     {
    2033             :         /* shrink search region to enforce minimum shift */
    2034           0 :         s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
    2035           0 :         IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
    2036             :         {
    2037           0 :             s_start = s[n]; /* just do it with normal start position */
    2038           0 :             move16();
    2039             :         }
    2040           0 :         ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
    2041             :         {
    2042           0 :             s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
    2043             :         }
    2044             :         ELSE
    2045             :         {
    2046           0 :             over[n] = 0; /* don't search/overlap (just copy down) */
    2047           0 :             move16();
    2048             :         }
    2049             :     }
    2050             : 
    2051           0 :     IF( over[n] )
    2052             :     {
    2053             :         /* calculate overlap position */
    2054           0 :         IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
    2055             :         {
    2056             :             /* maximum scaling */
    2057           0 :             energy_fx = -65 * ( 1 << 8 ); // Q8
    2058           0 :             move16();
    2059           0 :             quality_fx = 5 << 16; // Q16
    2060           0 :             move32();
    2061           0 :             xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
    2062           0 :             move16();
    2063           0 :             IF( ps->evs_compat_mode == false )
    2064             :             {
    2065             :                 /* take renderer buffer samples into accout */
    2066           0 :                 xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
    2067             :                 /* snap to next renderer time slot border to resynchronize */
    2068             :                 // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
    2069             :                 Word16 tmp3;
    2070           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 ) );
    2071           0 :                 xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
    2072           0 :                 move16();
    2073           0 :                 move16();
    2074             :             }
    2075             :         }
    2076             :         ELSE
    2077             :         {
    2078             :             Word16 *frmInScaled;
    2079           0 :             frmInScaled = ps->frmInScaled;
    2080           0 :             assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
    2081           0 :             scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
    2082           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] );
    2083             :         }
    2084             :         /* assert synch_pos is cleanly divisible by number of channels */
    2085           0 :         assert( xtract[n] % ps->num_channels == 0 );
    2086             : 
    2087             :         /* test for sufficient quality */
    2088           0 :         IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    2089             :                                              L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
    2090             :                                       L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
    2091             :         {
    2092             :             /* not sufficient */
    2093           0 :             over[n] = 0;
    2094           0 :             move16();
    2095           0 :             xtract[n] = sync_start;
    2096           0 :             move16();
    2097           0 :             IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    2098             :             {
    2099           0 :                 ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    2100           0 :                 move16();
    2101             :             }
    2102           0 :             IF( GT_32( ps->good_frame_count, 0 ) )
    2103             :             {
    2104           0 :                 ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    2105           0 :                 move16();
    2106             :             }
    2107             :         }
    2108             :         ELSE
    2109             :         {
    2110             :             /* sufficient quality */
    2111           0 :             IF( GT_32( ps->bad_frame_count, 0 ) )
    2112             :             {
    2113           0 :                 ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    2114           0 :                 move16();
    2115             :             }
    2116           0 :             IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    2117             :             {
    2118           0 :                 ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    2119           0 :                 move16();
    2120             :             }
    2121             :         }
    2122           0 :         IF( findSynchResult )
    2123             :         {
    2124           0 :             return 1;
    2125             :         }
    2126             :     }
    2127             :     ELSE
    2128             :     {
    2129           0 :         xtract[n] = sync_start;
    2130           0 :         move16();
    2131             :     }
    2132             : 
    2133             : 
    2134             :     /* Calculate output data */
    2135           0 :     FOR( n = 2; n <= N; n++ )
    2136             :     {
    2137           0 :         test();
    2138           0 :         IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
    2139             :         {
    2140             :             /* mix 2nd half of previous segment with 1st half of current segment */
    2141           0 :             fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
    2142           0 :             fadeIn_fx = frm_in_fx + l_frm + xtract[n];
    2143           0 :             out_fx = frm_out_fx + ( n - 2 ) * l_seg;
    2144           0 :             IF( ps->evs_compat_mode == true )
    2145             :             {
    2146             :                 // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
    2147           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 );
    2148             :             }
    2149             :             ELSE
    2150             :             {
    2151           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 );
    2152             :             }
    2153             :         }
    2154             :         ELSE
    2155             :         {
    2156             :             /* just copy down 1st half of current segment (= 2nd half of previous segment) */
    2157             :             Word16 *frm_out_ptr;
    2158             :             const Word16 *frm_in_ptr;
    2159           0 :             frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
    2160           0 :             frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
    2161           0 :             FOR( i = 0; i < l_seg; i++ )
    2162             :             {
    2163           0 :                 frm_out_ptr[i] = frm_in_ptr[i];
    2164           0 :                 move16();
    2165             :             }
    2166             :         }
    2167             :     }
    2168             : 
    2169             :     /* append remaining samples */
    2170           0 :     l_rem = l_frm - ( xtract[N] + l_seg );
    2171           0 :     FOR( i = 0; i < l_rem; i++ )
    2172             :     {
    2173           0 :         frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
    2174           0 :         move16();
    2175             :     }
    2176             : 
    2177             :     /* set output length */
    2178           0 :     *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
    2179           0 :     move16();
    2180           0 :     return 0;
    2181             : }
    2182             : 
    2183             : 
    2184         351 : static bool extend_frm_ivas_fx(
    2185             :     apa_state_t *ps,
    2186             :     const Word16 frm_in_fx[], // Qx
    2187             :     Word16 frm_out_fx[],      // Qx
    2188             :     Word16 Q_frm_in,
    2189             :     UWord16 *l_frm_out )
    2190             : {
    2191         351 :     bool findSynchResult = 0;
    2192         351 :     move16();
    2193             :     UWord16 l_frm_out_target;
    2194             :     UWord16 n, i;
    2195             :     Word16 N;
    2196             :     Word16 s[MAXN + 2], s_max, s_min;
    2197             :     Word16 xtract[MAXN + 2], sync_start, s_end;
    2198             :     UWord16 over[MAXN + 2];
    2199             :     Word16 l_rem;
    2200         351 :     Word16 s_start = 0;
    2201         351 :     move16();
    2202             :     Word16 energy_fx;
    2203         351 :     Word32 quality_fx = 0;
    2204         351 :     move32();
    2205             :     UWord16 l_frm, l_seg;
    2206             :     const Word16 *fadeOut_fx, *fadeIn_fx;
    2207             :     Word16 *out_fx;
    2208             : 
    2209         351 :     l_frm = ps->l_frm;
    2210         351 :     l_seg = ps->l_seg;
    2211         351 :     move16();
    2212         351 :     move16();
    2213             :     /* number of segments/iterations */
    2214         351 :     l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
    2215             :     //(l_frm_out_target/l_seg -1 )
    2216             :     Word16 tmp, tmp_e;
    2217         351 :     tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
    2218         351 :     tmp = shr( tmp, sub( 15, tmp_e ) );
    2219         351 :     N = sub( ( tmp ), 1 );
    2220         351 :     if ( LT_16( N, 1 ) )
    2221             :     {
    2222           0 :         N = 1;
    2223           0 :         move16();
    2224             :     }
    2225         351 :     IF( GT_16( N, MAXN ) )
    2226             :     {
    2227           0 :         return 1;
    2228             :     }
    2229             :     /* calculate equally spaced search regions */
    2230             :     /* s[n] are given relative to 2nd frame and point to the start of */
    2231             :     /* the search region. The first segment (n=1) will not be moved. */
    2232             :     /* Hence, the iterations will start with n=2. */
    2233         351 :     s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
    2234             :     /* (make sure not to exceed array dimension) */
    2235         351 :     IF( L_add( l_frm, s_min ) < 0 )
    2236             :     {
    2237           0 :         s_min = extract_l( L_negate( l_frm ) );
    2238             :     }
    2239         351 :     s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
    2240         351 :     if ( s_max < s_min )
    2241             :     {
    2242           0 :         N = 1;
    2243           0 :         move16();
    2244             :     }
    2245             :     /* for just one segment start at s_min */
    2246         351 :     if ( N == 1 )
    2247             :     {
    2248           0 :         s[2] = s_min;
    2249           0 :         move16();
    2250             :     }
    2251             :     /* else, spread linear in between s_min and s_max */
    2252             :     /* (including s_min and s_max) */
    2253             :     ELSE
    2254             :     {
    2255        1053 :         FOR( n = 2; n <= ( N + 1 ); n++ )
    2256             :         {
    2257             :             // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
    2258             :             Word16 tmp2, tmp2_e;
    2259         702 :             tmp2 = sub( s_max, s_min );
    2260         702 :             tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
    2261         702 :             tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
    2262         702 :             tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
    2263         702 :             s[n] = add( s_min, tmp2 );
    2264         702 :             move16();
    2265             :         }
    2266             :     }
    2267             : 
    2268             :     /*
    2269             :      *  Planning Phase
    2270             :      */
    2271             : 
    2272         351 :     xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
    2273         351 :     move16();
    2274         351 :     n = 2;
    2275         351 :     move16();
    2276             :     /* define synch segment (to be correlated with search region) */
    2277         351 :     sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
    2278         351 :     over[n] = 1; /* will be reset if overlap is not required */
    2279         351 :     move16();
    2280             :     /* check end of search region: should be at least p_min */
    2281             :     /* samples on the left of synch_start */
    2282         351 :     IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
    2283             :     {
    2284           0 :         s_start = s[n];
    2285           0 :         move16();
    2286           0 :         s_end = extract_l( L_add( s_start, ps->l_search ) );
    2287             :     }
    2288             :     ELSE
    2289             :     {
    2290             :         /* shrink search region to enforce minimum shift */
    2291         351 :         s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
    2292         351 :         IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
    2293             :         {
    2294         351 :             s_start = s[n]; /* just do it with normal start position */
    2295         351 :             move16();
    2296             :         }
    2297           0 :         ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
    2298             :         {
    2299           0 :             s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
    2300             :         }
    2301             :         ELSE
    2302             :         {
    2303           0 :             over[n] = 0; /* don't search/overlap (just copy down) */
    2304           0 :             move16();
    2305             :         }
    2306             :     }
    2307             : 
    2308         351 :     IF( over[n] )
    2309             :     {
    2310             :         /* calculate overlap position */
    2311         351 :         IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
    2312             :         {
    2313             :             /* maximum scaling */
    2314           0 :             energy_fx = -65 * ( 1 << 8 ); // Q8
    2315           0 :             move16();
    2316           0 :             quality_fx = 5 << 16; // Q16
    2317           0 :             move32();
    2318           0 :             xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
    2319           0 :             move16();
    2320           0 :             IF( ps->evs_compat_mode == false )
    2321             :             {
    2322             :                 /* take renderer buffer samples into accout */
    2323           0 :                 xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
    2324             :                 /* snap to next renderer time slot border to resynchronize */
    2325             :                 // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
    2326             :                 Word16 tmp3;
    2327           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 ) );
    2328           0 :                 xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
    2329           0 :                 move16();
    2330           0 :                 move16();
    2331             :             }
    2332             :         }
    2333             :         ELSE
    2334             :         {
    2335             :             Word16 *frmInScaled;
    2336         351 :             frmInScaled = ps->frmInScaled;
    2337         351 :             assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
    2338         351 :             scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
    2339         351 :             ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
    2340         351 :             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] );
    2341         351 :             ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
    2342             :         }
    2343             :         /* assert synch_pos is cleanly divisible by number of channels */
    2344         351 :         assert( xtract[n] % ps->num_channels == 0 );
    2345             : 
    2346             :         /* test for sufficient quality */
    2347         351 :         IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
    2348             :                                              L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
    2349             :                                       L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
    2350             :         {
    2351             :             /* not sufficient */
    2352         310 :             over[n] = 0;
    2353         310 :             move16();
    2354         310 :             xtract[n] = sync_start;
    2355         310 :             move16();
    2356         310 :             IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
    2357             :             {
    2358          97 :                 ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
    2359          97 :                 move16();
    2360             :             }
    2361         310 :             IF( GT_32( ps->good_frame_count, 0 ) )
    2362             :             {
    2363          16 :                 ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
    2364          16 :                 move16();
    2365             :             }
    2366             :         }
    2367             :         ELSE
    2368             :         {
    2369             :             /* sufficient quality */
    2370          41 :             IF( GT_32( ps->bad_frame_count, 0 ) )
    2371             :             {
    2372          40 :                 ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
    2373          40 :                 move16();
    2374             :             }
    2375          41 :             IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
    2376             :             {
    2377          41 :                 ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
    2378          41 :                 move16();
    2379             :             }
    2380             :         }
    2381         351 :         IF( findSynchResult )
    2382             :         {
    2383           0 :             return 1;
    2384             :         }
    2385             :     }
    2386             :     ELSE
    2387             :     {
    2388           0 :         xtract[n] = sync_start;
    2389           0 :         move16();
    2390             :     }
    2391             : 
    2392             : 
    2393             :     /* Calculate output data */
    2394         702 :     FOR( n = 2; n <= N; n++ )
    2395             :     {
    2396         351 :         test();
    2397         351 :         IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
    2398             :         {
    2399             :             /* mix 2nd half of previous segment with 1st half of current segment */
    2400          41 :             fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
    2401          41 :             fadeIn_fx = frm_in_fx + l_frm + xtract[n];
    2402          41 :             out_fx = frm_out_fx + ( n - 2 ) * l_seg;
    2403          41 :             IF( EQ_16( ps->evs_compat_mode, true ) )
    2404             :             {
    2405             :                 // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
    2406           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 );
    2407             :             }
    2408             :             ELSE
    2409             :             {
    2410          41 :                 overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
    2411             :             }
    2412             :         }
    2413             :         ELSE
    2414             :         {
    2415             :             /* just copy down 1st half of current segment (= 2nd half of previous segment) */
    2416             :             Word16 *frm_out_ptr;
    2417             :             const Word16 *frm_in_ptr;
    2418         310 :             frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
    2419         310 :             frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
    2420      335030 :             FOR( i = 0; i < l_seg; i++ )
    2421             :             {
    2422      334720 :                 frm_out_ptr[i] = frm_in_ptr[i];
    2423      334720 :                 move16();
    2424             :             }
    2425             :         }
    2426             :     }
    2427             : 
    2428             :     /* append remaining samples */
    2429         351 :     l_rem = l_frm - ( xtract[N] + l_seg );
    2430      422626 :     FOR( i = 0; i < l_rem; i++ )
    2431             :     {
    2432      422275 :         frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
    2433      422275 :         move16();
    2434             :     }
    2435             : 
    2436             :     /* set output length */
    2437         351 :     *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
    2438         351 :     move16();
    2439         351 :     return 0;
    2440             : }

Generated by: LCOV version 1.14