/******************************************************************************
**
**   ITU-T G.722.1 (2005-05) - Fixed point implementation for main body and Annex C
**   > Software Release 2.1 (2008-06)
**     (Simple repackaging; no change from 2005-05 Release 2.0 code)
**
**    2004 Polycom, Inc.
**
**	 All rights reserved.
**
******************************************************************************/

/******************************************************************************
* Filename: samples_to_rmlt_coefs.c
*
* Purpose:  Convert Samples to Reversed MLT (Modulated Lapped Transform) 
*           Coefficients
*
*     The "Reversed MLT" is an overlapped block transform which uses
*     even symmetry * on the left, odd symmetry on the right and a
*     Type IV DCT as the block transform.  * It is thus similar to a
*     MLT which uses odd symmetry on the left, even symmetry * on the
*     right and a Type IV DST as the block transform.  In fact, it is
*     equivalent * to reversing the order of the samples, performing
*     an MLT and then negating all * the even-numbered coefficients.
*
******************************************************************************/

/***************************************************************************
 Include files                                                           
***************************************************************************/
#include "defs.h"
#include "tables.h"
#include "count.h"

/***************************************************************************
 Function:    samples_to_rmlt_coefs 

 Syntax:      Word16 samples_to_rmlt_coefs(new_samples, 
                                           old_samples,
                                           coefs,
                                           dct_length)
                    Word16 *new_samples;           
                    Word16 *old_samples;           
                    Word16 *coefs;                 
                    Word16 dct_length;

 Description: Convert samples to MLT coefficients

 Design Notes:

 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    1.40      |     1.40
          -------|--------------|----------------  
            MAX  |    1.40      |     1.40
          -------|--------------|---------------- 
				
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    3.07      |     3.07       |     3.07
          -------|--------------|----------------|----------------
            MAX  |    3.10      |     3.10       |     3.10
          -------|--------------|----------------|----------------
				
***************************************************************************/

Word16 samples_to_rmlt_coefs(const Word16 *new_samples,Word16 *old_samples,Word16 *coefs,Word16 dct_length)
{

    Word16	index, vals_left,mag_shift,n;
    Word16	windowed_data[MAX_DCT_LENGTH];
    Word16	*old_ptr;
    const Word16 *new_ptr, *sam_low, *sam_high;
    Word16	*win_low, *win_high;
    Word16	*dst_ptr;
    Word16  neg_win_low;
    Word16  samp_high;
    Word16  half_dct_size;
    
    Word32	acca;
    Word32	accb;
    Word16	temp;
    Word16	temp1;
    Word16	temp2;
    Word16	temp5;
   
    half_dct_size = shr_nocheck(dct_length,1);
   
    /*++++++++++++++++++++++++++++++++++++++++++++*/
    /* Get the first half of the windowed samples */
    /*++++++++++++++++++++++++++++++++++++++++++++*/
    
    dst_ptr  = windowed_data;
    move16();
    
    /* address arithmetic */
    test();
    if (dct_length==DCT_LENGTH)
    {
        win_high = samples_to_rmlt_window + half_dct_size;
    }
    else
    {
        win_high = max_samples_to_rmlt_window + half_dct_size;
    }
    
    win_low  = win_high;
    move16();
    
    /* address arithmetic */
    sam_high = old_samples + half_dct_size;
    
    sam_low  = sam_high;
    move16();
    
    for (vals_left = half_dct_size;vals_left > 0;vals_left--)
    {
        acca = 0L;
        move32();
        
        acca = L_mac(acca,*--win_low, *--sam_low);
        acca = L_mac(acca,*win_high++, *sam_high++);
        temp = itu_round(acca); 
        
        *dst_ptr++ = temp;
        move16();
    }           
    
    /*+++++++++++++++++++++++++++++++++++++++++++++*/
    /* Get the second half of the windowed samples */
    /*+++++++++++++++++++++++++++++++++++++++++++++*/
    
    sam_low  = new_samples;
    move16();

    /* address arithmetic */
    sam_high = new_samples + dct_length;
    
    for (vals_left = half_dct_size;    vals_left > 0;    vals_left--)
    {
        acca = 0L;
        move32();

        acca = L_mac(acca,*--win_high, *sam_low++);
        neg_win_low = negate(*win_low++);
        samp_high = *--sam_high;
        acca = L_mac(acca, neg_win_low, samp_high);
        temp = itu_round(acca); 
        
        *dst_ptr++=temp;
        move16();
    }
       
    /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    /* Save the new samples for next time, when they will be the old samples */
    /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    
    new_ptr = new_samples;
    move16();

    old_ptr = old_samples;
    move16();

    for (vals_left = dct_length;vals_left > 0;vals_left--)
    {
        *old_ptr++ = *new_ptr++;
        move16();
    }
    
    /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    /* Calculate how many bits to shift up the input to the DCT.             */
    /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    
    temp1=0;
    move16();

    for(index=0;index<dct_length;index++)
    {
        temp2 = abs_s(windowed_data[index]);
        temp = sub(temp2,temp1);
        test();
        if(temp > 0)
        {
            move16();
            temp1 = temp2;
        }
    }
    
    mag_shift=0;
    move16();

    temp = sub(temp1,14000);
    test();
    if (temp >= 0)
    {
        mag_shift = 0;
        move16();
    }
    else
    {
        temp = sub(temp1,438);
        test();
        if(temp < 0)
            temp = add(temp1,1);
        else 
        {
            temp = temp1;
            move16();
        }
        accb = L_mult(temp,9587);
        acca = L_shr_nocheck(accb,20);
        temp5 = extract_l(acca);
        temp = norm_s(temp5);
        test();
        if (temp == 0)
        {
            mag_shift = 9;
            move16();
        }
        else
            mag_shift = sub(temp,6);
        
    }

    acca = 0L;
    move32();
    for(index=0; index<dct_length; index++)
    {
        temp = abs_s( windowed_data[index]);
        acca = L_add(acca,temp);
    }
    
    acca = L_shr_nocheck(acca,7);
    
    test();
    if (temp1 < acca)
    {
        mag_shift = sub(mag_shift,1);
    }

    test();
    if (mag_shift > 0) 
    {
        for(index=0;index<dct_length;index++)
        {
            windowed_data[index] = shl_nocheck(windowed_data[index],mag_shift);
        }
    }
    else 
    {
        test();
        if (mag_shift < 0) 
        {
            n = negate(mag_shift);
            for(index=0;index<dct_length;index++)
            {
                windowed_data[index] = shr_nocheck(windowed_data[index],n);
                move16();
            }
        }
    }

    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    /* Perform a Type IV DCT on the windowed data to get the coefficients */
    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

    dct_type_iv_a(windowed_data, coefs, dct_length);

    return(mag_shift);
}
