www.pudn.com > T-REC-G.722.1-200505-I!!SOFT-ZST-E.zip > dct4_s.c


/******************************************************************************** 
********************************************************************************* 
** 
**   ITU-T 7/14kHz Audio Coder Candidate (G.722.1 Annex C) Source Code 
** 
**   © 2004 Polycom, Inc. 
** 
**   All rights reserved. 
** 
********************************************************************************* 
********************************************************************************/ 
 
/********************************************************************************
* Filename: dct_type_iv_s.c 
* 
* Purpose:  Discrete Cosine Transform, Type IV used for inverse MLT
*
* The basis functions are
*
*	 cos(PI*(t+0.5)*(k+0.5)/block_length)
*
* for time t and basis function number k.  Due to the symmetry of the expression
* in t and k, it is clear that the forward and inverse transforms are the same.
*
*********************************************************************************/

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

/*************************************************************************** 
 External variable declarations                                           
***************************************************************************/ 
extern Word16    syn_bias_7khz[DCT_LENGTH];
extern Word16    dither[DCT_LENGTH]; 
extern Word16    max_dither[MAX_DCT_LENGTH]; 

extern Word16       dct_core_s[DCT_LENGTH_DIV_32][DCT_LENGTH_DIV_32]; 
extern cos_msin_t	s_cos_msin_2[DCT_LENGTH_DIV_32]; 
extern cos_msin_t	s_cos_msin_4[DCT_LENGTH_DIV_16]; 
extern cos_msin_t	s_cos_msin_8[DCT_LENGTH_DIV_8]; 
extern cos_msin_t	s_cos_msin_16[DCT_LENGTH_DIV_4]; 
extern cos_msin_t	s_cos_msin_32[DCT_LENGTH_DIV_2]; 
extern cos_msin_t	s_cos_msin_64[DCT_LENGTH]; 
extern cos_msin_t	*s_cos_msin_table[];

/******************************************************************************** 
 Function:    dct_type_iv_s 
 
 Syntax:      void dct_type_iv_s (Word16 *input,Word16 *output,Word16 dct_length) 
               
 
 Description: Discrete Cosine Transform, Type IV used for inverse MLT 
 
 Design Notes: 
  
 WMOPS:     7kHz |    24kbit    |    32kbit 
          -------|--------------|---------------- 
            AVG  |     1.74     |     1.74 
          -------|--------------|----------------   
            MAX  |     1.74     |     1.74 
          -------|--------------|----------------  
				 
           14kHz |    24kbit    |    32kbit      |     48kbit 
          -------|--------------|----------------|---------------- 
            AVG  |     3.62     |     3.62       |      3.62    
          -------|--------------|----------------|---------------- 
            MAX  |     3.62     |     3.62       |      3.62    
          -------|--------------|----------------|---------------- 
 
********************************************************************************/ 

void dct_type_iv_s (Word16 *input,Word16 *output,Word16 dct_length)
{
    Word16   buffer_a[MAX_DCT_LENGTH], buffer_b[MAX_DCT_LENGTH], buffer_c[MAX_DCT_LENGTH];
    Word16   *in_ptr, *in_ptr_low, *in_ptr_high, *next_in_base;
    Word16   *out_ptr_low, *out_ptr_high, *next_out_base;
    Word16   *out_buffer, *in_buffer, *buffer_swap;
    Word16   in_val_low, in_val_high;
    Word16   out_val_low, out_val_high;
    Word16   in_low_even, in_low_odd;
    Word16   in_high_even, in_high_odd;
    Word16   out_low_even, out_low_odd;
    Word16   out_high_even, out_high_odd;
    Word16   *pair_ptr;
    Word16   cos_even, cos_odd, msin_even, msin_odd;
    Word16   set_span, set_count, set_count_log, pairs_left, sets_left;
    Word16   i,k;
    Word16   index;
    Word16   dummy;
    Word32 	 sum; 
    cos_msin_t	**table_ptr_ptr, *cos_msin_ptr; 

    Word32 acca; 
    Word16 temp;
 
    Word16   dct_length_log; 
    Word16   *dither_ptr; 
     
    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    /* Do the sum/difference butterflies, the first part of */
    /* converting one N-point transform into 32 - 10 point transforms  */
    /* transforms, where N = 1 << DCT_LENGTH_LOG.           */
    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    test(); 
    if (dct_length==DCT_LENGTH) 
    { 
        dct_length_log = DCT_LENGTH_LOG; 
        move16(); 
        dither_ptr = dither; 
        move16(); 
    } 
    else 
    { 
        dct_length_log = MAX_DCT_LENGTH_LOG; 
        move16(); 
        dither_ptr = max_dither; 
        move16(); 
    } 
    
    in_buffer  = input; 
    move16();
    out_buffer = buffer_a; 
    move16();
     
    index=0;
    move16(); 
     
    i=0; 
    move16();

    for (set_count_log = 0;    set_count_log <= dct_length_log - 2;    set_count_log++)  
    {

        /*===========================================================*/
        /* Initialization for the loop over sets at the current size */
        /*===========================================================*/
        
        /*    set_span      = 1 << (DCT_LENGTH_LOG - set_count_log); */
        set_span = shr(dct_length,set_count_log);
           
        set_count     = shl(1,set_count_log);
        in_ptr        = in_buffer; 
        move16(); 
        next_out_base = out_buffer;
        move16();
         
        /*=====================================*/
        /* Loop over all the sets of this size */
        /*=====================================*/
        temp = sub(index,1); 
        test(); 
        if(temp < 0)
        {
            for (sets_left = set_count;sets_left > 0;sets_left--)  
            {
    
                /*||||||||||||||||||||||||||||||||||||||||||||*/
                /* Set up output pointers for the current set */
                /*||||||||||||||||||||||||||||||||||||||||||||*/
                /* pointer arithmetic */
                out_ptr_low    = next_out_base; 
                move16(); 
                next_out_base += set_span;
                move16(); 
                out_ptr_high   = next_out_base;
                move16(); 

                /*||||||||||||||||||||||||||||||||||||||||||||||||||*/
                /* Loop over all the butterflies in the current set */
                /*||||||||||||||||||||||||||||||||||||||||||||||||||*/
                    
                do  
                {
                    in_val_low      = *in_ptr++;
                    move16(); 
                    in_val_high     = *in_ptr++;
                    move16(); 

                    /* BEST METHOD OF GETTING RID OF BIAS, BUT COMPUTATIONALLY UNPLEASANT */
                    /* ALTERNATIVE METHOD, SMEARS BIAS OVER THE ENTIRE FRAME, COMPUTATIONALLY SIMPLEST. */
                    /* IF THIS WORKS, IT'S PREFERABLE */
                        
                    dummy = add(in_val_low,dither_ptr[i++]);
                    acca = L_add(dummy,in_val_high); 
                    out_val_low = extract_l(L_shr(acca,1));
                     
                    dummy = add(in_val_low,dither_ptr[i++]); 
                    acca = L_add(dummy,-in_val_high); 
                    out_val_high = extract_l(L_shr(acca,1)); 
                     
                    *out_ptr_low++  = out_val_low; 
                    move16();
                    *--out_ptr_high = out_val_high;
                    move16(); 
 
                    test(); 
                     
                    /* this involves comparison of pointers */ 
                    /* pointer arithmetic */ 
 
                } while (out_ptr_low < out_ptr_high);
    
            } /* End of loop over sets of the current size */
        }
        else
        {
            for (sets_left = set_count;    sets_left > 0;    sets_left--)  
            {
                /*||||||||||||||||||||||||||||||||||||||||||||*/
                /* Set up output pointers for the current set */
                /*||||||||||||||||||||||||||||||||||||||||||||*/
                
                out_ptr_low    = next_out_base; 
                move16();
                next_out_base += set_span; 
                move16();
                out_ptr_high   = next_out_base;
                move16(); 

            	/*||||||||||||||||||||||||||||||||||||||||||||||||||*/
            	/* Loop over all the butterflies in the current set */
            	/*||||||||||||||||||||||||||||||||||||||||||||||||||*/
                
                do  
                {
                    in_val_low      = *in_ptr++; 
                    move16();
                    in_val_high     = *in_ptr++;
                    move16(); 

                    out_val_low     = add(in_val_low,in_val_high);
                    out_val_high    = add(in_val_low,negate(in_val_high));
                    
                    *out_ptr_low++  = out_val_low; 
                    move16();
                    *--out_ptr_high = out_val_high;
                    move16(); 
 
                    test(); 
                } while (out_ptr_low < out_ptr_high);
    
            } /* End of loop over sets of the current size */
        }

        /*============================================================*/
        /* Decide which buffers to use as input and output next time. */
        /* Except for the first time (when the input buffer is the    */
        /* subroutine input) we just alternate the local buffers.     */
        /*============================================================*/
        
        in_buffer = out_buffer; 
        move16();
         
        test(); 
        if (out_buffer == buffer_a)
        { 
            out_buffer = buffer_b; 
            move16(); 
        } 
        else
        { 
            out_buffer = buffer_a; 
            move16(); 
        } 
        
        index = add(index,1);
    } /* End of loop over set sizes */


    /*++++++++++++++++++++++++++++++++*/
    /* Do 32 - 10 point transforms */
    /*++++++++++++++++++++++++++++++++*/
    
    pair_ptr = in_buffer; 
    move16();
    buffer_swap = buffer_c;
    move16(); 
 
    for (pairs_left = 1 << (dct_length_log - 1);    pairs_left > 0;    pairs_left--) 
    {
        for ( k=0; k= 0;    set_count_log--)  
    {

        /*===========================================================*/
        /* Initialization for the loop over sets at the current size */
        /*===========================================================*/
        
        /*    set_span      = 1 << (DCT_LENGTH_LOG - set_count_log); */
        set_span = shr(dct_length,set_count_log);
        
        set_count     = shl(1,set_count_log);
        next_in_base  = in_buffer; 
        move16();
        test(); 
        if (set_count_log == 0)
        { 
            next_out_base = output; 
            move16(); 
        } 
        else 
        { 
            next_out_base = out_buffer; 
            move16();
        } 
        
        /*=====================================*/
        /* Loop over all the sets of this size */
        /*=====================================*/

        for (sets_left = set_count;    sets_left > 0;    sets_left--)  
        {

            /*|||||||||||||||||||||||||||||||||||||||||*/
            /* Set up the pointers for the current set */
            /*|||||||||||||||||||||||||||||||||||||||||*/
            
            in_ptr_low     = next_in_base; 
            move16();
             
            temp = shr(set_span,1); 
            in_ptr_high    = in_ptr_low + temp;
            move16(); 
             
            next_in_base  += set_span;
            move16(); 
             
            out_ptr_low    = next_out_base;
            move16(); 
             
            next_out_base += set_span;
            move16(); 
            out_ptr_high   = next_out_base;
            move16(); 
             
            cos_msin_ptr   = *table_ptr_ptr; 
            move16(); 

            /*||||||||||||||||||||||||||||||||||||||||||||||||||||||*/
            /* Loop over all the butterfly pairs in the current set */
            /*||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

	        do  
            {
                in_low_even     = *in_ptr_low++;
                move16(); 
                in_low_odd      = *in_ptr_low++;
                move16(); 
                in_high_even    = *in_ptr_high++;
                move16(); 
                in_high_odd     = *in_ptr_high++;
                move16(); 
                cos_even        = cos_msin_ptr[0].cosine;
                move16(); 
                msin_even       = cos_msin_ptr[0].minus_sine;
                move16(); 
                cos_odd         = cos_msin_ptr[1].cosine;
                move16(); 
                msin_odd        = cos_msin_ptr[1].minus_sine;
                move16(); 
                cos_msin_ptr   += 2;
                
                sum = 0L; 
                move32();
                 
                sum = L_mac(sum,cos_even,in_low_even); 
                sum = L_mac(sum,negate(msin_even),in_high_even); 
                out_low_even = round(L_shl(sum,1));
                 
                sum = 0L; 
                move32();
                sum = L_mac(sum,msin_even,in_low_even);
                sum = L_mac(sum,cos_even,in_high_even);
                out_high_even = round(L_shl(sum,1)); 
                 
                sum = 0L; 
                move32();
                sum = L_mac(sum,cos_odd,in_low_odd);
                sum = L_mac(sum,msin_odd,in_high_odd);
                out_low_odd = round(L_shl(sum,1));
                
                sum = 0L; 
                move32();
                sum = L_mac(sum,msin_odd,in_low_odd);
                sum = L_mac(sum,negate(cos_odd),in_high_odd);
                out_high_odd = round(L_shl(sum,1));
                
                *out_ptr_low++  = out_low_even;
                move16(); 
                *--out_ptr_high = out_high_even;
                move16(); 
                *out_ptr_low++  = out_low_odd;
                move16(); 
                *--out_ptr_high = out_high_odd;
                move16(); 
             
                test(); 
            } while (out_ptr_low < out_ptr_high);

	    } /* End of loop over sets of the current size */

        /*=============================================*/
        /* Swap input and output buffers for next time */
        /*=============================================*/
        
        buffer_swap = in_buffer;
        move16(); 
        in_buffer   = out_buffer;
        move16(); 
        out_buffer  = buffer_swap;
        move16(); 
         
        index = add(index,1);
        table_ptr_ptr++; 
    }
    /*------------------------------------
    
         ADD IN BIAS FOR OUTPUT
         
    -----------------------------------*/
    if (dct_length==DCT_LENGTH) 
    { 
        for(i=0;i<320;i++)  
        {
           sum = L_add(output[i],syn_bias_7khz[i]);
           acca = L_sub(sum,32767); 
           test(); 
           if (acca > 0)  
           {
               sum = 32767L; 
               move32();
           }
           acca = L_add(sum,32768L); 
           test(); 
           if (acca < 0)  
           {
               sum = -32768L; 
               move32();
           }
           output[i] = extract_l(sum); 
        } 
    }
}