/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/*

 Filename: long_term_prediction.cpp

------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    win_seq = type of window sequence (WINDOW_SEQUENCE).

    weight_index = index (Int) of LTP coefficient table for all windows in
                   current frame.

    delay = buffer (Int) containing delays for each window.

    buffer = history buffer (Int16) containing the reconstructed time domain
             signals of previous frames.

    buffer_offset = value (Int) that indicates the location of the first
                    element in the LTP circular buffer.  (Either 0 or 1024)

    time_quant    = filterbank buffer (Int32) This buffer is used by the
                    filterbank, but it's first 1024 elements are equivalent
                    to the last 1024 elements in the conventionally
                    implemented LTP buffer.  Using this buffer directly avoids
                    costly duplication of memory.

    predicted_samples = buffer (Int32) with length of 2048 to hold
                        predicted time domain signals.

    buffer_index = index into buffer where the first sample of data from
                   the frame (t-2) (two frames ago) resides.  (Int)

    frame_length = length of one frame, type of Int.

 Local Stores/Buffers/Pointers Needed:
    None

 Global Stores/Buffers/Pointers Needed:
    None

 Outputs:
    Amount of shifting needed to grab the top 16 MSB from teh predicted buffer

 Pointers and Buffers Modified:
    predicted_samples contents are the newly calculated predicted time
    domain signals

 Local Stores Modified:
    None

 Global Stores Modified:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 Long term prediction (LTP) is used to reduce the redundancy of a signal
 between successive coding frames. This function performs prediction by
 applying 1-tap IIR filtering to calculate the predicted time domain
 signals of current frame from previous reconstructed frames stored in
 time domain history buffer.

 The equation used for IIR filter is as following.

            y(n) = weight * x(n - delay)

    where   y(n) ----- predicted time domain signals
            x(n) ----- reconstructed time domain signals
            weight ----- LTP coefficient
            delay ----- optimal delay from 0 to 2047

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 (1) ISO/IEC 14496-3:1999(E)
     Part 3: Audio
        Subpart 4.6.6   Long Term Prediction (LTP)

 (2) MPEG-2 NBC Audio Decoder
     "This software module was originally developed by Nokia in the course
     of development of the MPEG-2 AAC/MPEG-4 Audio standard ISO/IEC13818-7,
     14496-1, 2 and 3. This software module is an implementation of a part
     of one or more MPEG-2 AAC/MPEG-4 Audio tools as specified by the MPEG-2
     aac/MPEG-4 Audio standard. ISO/IEC  gives users of the MPEG-2aac/MPEG-4
     Audio standards free license to this software module or modifications
     thereof for use in hardware or software products claiming conformance
     to the MPEG-2 aac/MPEG-4 Audio  standards. Those intending to use this
     software module in hardware or software products are advised that this
     use may infringe existing patents. The original developer of this
     software module, the subsequent editors and their companies, and ISO/IEC
     have no liability for use of this software module or modifications
     thereof in an implementation. Copyright is not released for non MPEG-2
     aac/MPEG-4 Audio conforming products. The original developer retains
     full right to use the code for the developer's own purpose, assign or
     donate the code to a third party and to inhibit third party from using
     the code for non MPEG-2 aac/MPEG-4 Audio conforming products. This
     copyright notice must be included in all copies or derivative works.
     Copyright (c)1997.

------------------------------------------------------------------------------
 PSEUDO-CODE

    pPredicted_samples = &predicted_samples[0];

    weight = codebook[weight_index];

    IF (win_seq != EIGHT_SHORT_SEQUENCE)
    THEN

        block_length = frame_length << 1;

        lag = delay[0];

        j = block_length - lag;

        IF (lag < frame_length)
        THEN

            num_samples = frame_length + lag;

        ELSE

            num_samples = block_length;

        ENDIF

        pBuffer = &buffer[j];

        FOR (i = num_samples; i>0; i--)

            *pPredicted_samples = weight * (*pBuffer);
            pPredicted_samples = pPredicted_samples + 1;
            pBuffer = pBuffer + 1;

        ENDFOR

        FOR (i = block_length - num_samples; i>0; i--)

            *pPredicted_samples = 0;
            pPredicted_samples = pPredicted_samples + 1;

        ENDFOR

    ELSE

        FOR (wnd = 0; wnd < short_window_num; wnd++)

            IF (win_prediction_used[wnd] != FALSE)
            THEN

                delay[wnd] = delay[0] + ltp_short_lag[wnd];

                lag = delay[wnd];

                j = wnd*short_block_length - lag;

                IF (lag < short_frame_length)
                THEN

                    num_samples = short_frame_length + lag;

                ELSE

                    num_samples = short_block_length;

                ENDIF

                pBuffer = &buffer[j];

                FOR (i = num_samples; i>0; i--)

                    *pPredicted_samples = weight * (*pBuffer);
                    pPredicted_samples = pPredicted_samples + 1;
                    pBuffer = pBuffer + 1;

                ENDFOR

                FOR (i = short_block_length - num_samples; i>0; i--)

                    *pPredicted_samples = 0;
                    pPredicted_samples = pPredicted_samples + 1;

                ENDFOR

            ELSE

                CALL pv_memset(
                        pPredicted_samples,
                        0,
                        sizeof(*pPredicted_samples)*short_block_length);
                MODIFYING (predicted_samples[]);

                pPredicted_samples = pPredicted_samples + short_block_length;

            ENDIF [ IF (win_prediction_used[wnd] != FALSE) ]

        ENDFOR [ FOR (wnd=0; wnd<short_window_num; wnd++) ]

    ENDIF [ IF (win_seq != EIGHT_SHORT_SEQUENCE) ]

    RETURN

------------------------------------------------------------------------------
*/


/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include "pv_audio_type_defs.h"
#include "e_window_sequence.h"
#include "ltp_common_internal.h"
#include "long_term_prediction.h"
#include "aac_mem_funcs.h"
#include "pv_normalize.h"
#include "window_block_fxp.h"


/*----------------------------------------------------------------------------
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; DEFINES
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; Function Prototype declaration
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL STORE/BUFFER/POINTER DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/
/* Purpose: Codebook for LTP weight coefficients. Stored in Q15 format */
const UInt codebook[CODESIZE] =
{
    18705,  /* 0 */
    22827,  /* 1 */
    26641,  /* 2 */
    29862,  /* 3 */
    32273,  /* 4 */
    34993,  /* 5 */
    39145,  /* 6 */
    44877   /* 7 */
};

/*----------------------------------------------------------------------------
; EXTERNAL FUNCTION REFERENCES
; Declare functions defined elsewhere and referenced in this module
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES
; Declare variables used in this module but defined elsewhere
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
Int long_term_prediction(
    WINDOW_SEQUENCE     win_seq,
    const Int           weight_index,
    const Int           delay[],
    const Int16         buffer[],
    const Int           buffer_offset,
    const Int32         time_quant[],
    Int32         predicted_samples[],    /* Q15 */
    const Int           frame_length)
{
    /*----------------------------------------------------------------------------
    ; Define all local variables
    ----------------------------------------------------------------------------*/
    /*
     * Window index
     *
     * Int wnd;
     *
     * will be enabled when short window information is available.
     */

    /* Pointer to time domain history buffer */

    const Int16 *pBuffer;

    const Int32 *pTimeQuant = time_quant;

    /* Pointer to array containing predicted samples */
    Int32 *pPredicted_samples;

    Int32   test;
    Int32   datum;

    /* IIR coefficient with Q15 format */
    UInt    weight;

    /* Length of one block (two frames) */
    Int     block_length;

    Int     shift;
    Int     k;
    Int     ltp_buffer_index;
    Int     jump_point;
    Int     lag;
    Int     num_samples;

    Int32   max = 0;

    /*----------------------------------------------------------------------------
    ; Function body here
    ----------------------------------------------------------------------------*/
    /* Initialize pointers */
    pPredicted_samples = &predicted_samples[0];

    weight = codebook[weight_index];

    /****************************************/
    /* LTP decoding process for long window */
    /****************************************/

    if (win_seq != EIGHT_SHORT_SEQUENCE)
    {
        /****************************************************/
        /* Prediction based on previous time domain signals */
        /****************************************************/
        block_length = frame_length << 1;

        /* Calculate time lag for 1-tap IIR filter */
        lag = delay[0];

        ltp_buffer_index = block_length - lag;

        /* Calculate number of samples used in IIR filter */
        if (lag < frame_length)
        {
            num_samples = frame_length + lag;
        }
        else
        {
            num_samples = block_length;
        }


        /*
         * Calculate the predicted time domain signals from the
         * reconstructed time domain signals of previous frames.
         */

        /* The data is stored in TWO buffers, either as...
         *
         *                                       [   t ==  0  ]
         *
         * [   t == -1   ][   t == -2   ]
         *
         * OR...
         *                                       [   t ==  0  ]
         *
         * [   t == -2   ][   t == -1   ]
         *
         *
         *
         * In the first case, all of the buffers are non-contiguous,
         * and each must be handled separately.  Code for this first case
         * will function correctly for both cases.
         *
         * In the second case, the buffers storing t == -2, and t == -1
         * data are contiguous, and an optimization could take advantage
         * of this, at the cost of an increase in code size for this function.
         */

        /* Decrement block_length by num_samples.  This is important
         * for the loop at the end of the "ACCESS DATA IN THE LTP BUFFERS"
         * section that sets all remaining samples in the block to zero.
         */

        block_length -= num_samples;






        /*
         ************************************ ACCESS DATA IN THE LTP BUFFERS
         */

        /*
         * This section of the code handles the t == -2
         * buffer, which corresponds to 0 <= ltp_buffer_index < 1024
         *
         * BUFFER t == -2
         *
         * [0][][][][][][][][][][][...][][][][][][][][][][][][1023]
         *
         */

        jump_point = (frame_length - ltp_buffer_index);

        if (jump_point > 0)
        {
            pBuffer = &(buffer[ltp_buffer_index + buffer_offset]);

            for (k = jump_point; k > 0; k--)
            {
                /* Q15 = Q15 * Q0 */
                test = (Int32) weight * (*(pBuffer++));
                *(pPredicted_samples++) =  test;
                max                   |= (test >> 31) ^ test;
            }

            num_samples -= jump_point;

            ltp_buffer_index += jump_point;
        }

        /*
         * This section of the code handles the t == -1
         * buffer, which corresponds to 1024 <= ltp_buffer_index < 2048
         *
         * BUFFER t == -1
         *
         * [1024][][][][][][][][][][][...][][][][][][][][][][][][2047]
         *
         */

        jump_point = 2 * frame_length - ltp_buffer_index;

        pBuffer = &(buffer[ltp_buffer_index - buffer_offset]);

        if (num_samples < jump_point)
        {
            jump_point = num_samples;
        }

        for (k = jump_point; k > 0; k--)
        {
            /* Q15 = Q15 * Q0 */
            test = (Int32) weight * (*(pBuffer++));
            *(pPredicted_samples++) =  test;
            max                   |= (test >> 31) ^ test;
        }

        num_samples -= jump_point;

        ltp_buffer_index += jump_point;

        /*
         * This section of the code handles the t == 0
         * buffer, which corresponds to 2048 <= ltp_buffer_index < 3072
         *
         * BUFFER t == 0
         *
         * [2048][][][][][][][][][][][...][][][][][][][][][][][][3071]
         *
         */
        for (k = num_samples; k > 0; k--)
        {

            datum = *(pTimeQuant++) >> SCALING;

            /*
             * Limit the values in the 32-bit filterbank's buffer to
             * 16-bit resolution.
             *
             * Value's greater than 32767 or less than -32768 are saturated
             * to 32767 and -32768, respectively.
             */

            test                    = (Int32)datum * weight;
            *(pPredicted_samples++) =  test;
            max                    |= (test >> 31) ^ test;

        }

        /* Set any remaining samples in the block to 0. */

        pv_memset(
            pPredicted_samples,
            0,
            block_length*sizeof(*pPredicted_samples));

    } /* if (win_seq != EIGHT_SHORT_SEQUENCE) */


    /*****************************************/
    /* LTP decoding process for short window */
    /*****************************************/

    /*
     * For short window LTP, since there is no "ltp_short_lag"
     * information being passed, the following code for short
     * window LTP will be applied in the future when those
     * information are available.
     */

    /*
     *----------------------------------------------------------------------------
     *  else
     *  {
     *      for (wnd = 0; wnd < short_window_num; wnd++)
     *      {
     *          if (win_prediction_used[wnd] != FALSE)
     *          {
     *              delay[wnd] = delay[0] + ltp_short_lag[wnd];
     *
     *              lag = delay[wnd];
     *
     *              j = wnd*short_block_length - lag;
     *
     *              if (lag < short_frame_length)
     *              {
     *                  num_samples = short_frame_length + lag;
     *              }
     *              else
     *              {
     *                  num_samples = short_block_length;
     *              }
     *
     *              pBuffer = &buffer[j];
     *
     *              for(i = num_samples; i>0; i--)
     *              {
     *                  *(pPredicted_samples++) = weight * (*(pBuffer++));
     *              }
     *
     *              for(i = short_block_length - num_samples; i>0; i--)
     *              {
     *                  *(pPredicted_samples++) = 0;
     *              }
     *          }
     *          else
     *          {
     *              pv_memset(
     *                  pPredicted_samples,
     *                  0,
     *                  sizeof(*pPredicted_samples)*short_block_length);
     *
     *              pPredicted_samples += short_block_length;
     *          }
     *      }
     *  }
     *----------------------------------------------------------------------------
     */

    shift = 16 - pv_normalize(max);

    if (shift < 0)
    {
        shift = 0;
    }

    /*----------------------------------------------------------------------------
    ; Return nothing or data or data pointer
    ----------------------------------------------------------------------------*/
    return (shift);
} /* long_term_prediction */




