/***************************************************************************
**
**   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:    encoder.c    

  Purpose:     Contains files used to implement the G.722.1 Annex C encoder

  Design Notes:

***************************************************************************/

/***************************************************************************
 Include files                                                           
***************************************************************************/

#include <stdio.h>
#include <math.h>
#include "defs.h"
#include "huff_def.h"
#include "tables.h"
#include "count.h"

/***************************************************************************
 Function:    encoder                                                     
                                                                         
 Syntax:      void encoder(Word16 number_of_available_bits,                     
                           Word16 number_of_regions,
                           Word16 mlt_coefs,                                        
                           Word16 mag_shift,                                        
                           Word16 out_words)                                        
              
              inputs:   number_of_available_bits
                        number_of_regions
                        mag_shift
                        mlt_coefs[DCT_LENGTH]
                        
              outputs:  out_words[MAX_BITS_PER_FRAME/16]
                                                                         
                                                                         
 Description: Encodes the mlt coefs into out_words using G.722.1 Annex C
                                                           
                                                                         
 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.93      |     1.04
          -------|--------------|----------------  
            MAX  |    1.20      |     1.28
          -------|--------------|---------------- 
                                                                        
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    1.39      |     1.71       |     2.01
          -------|--------------|----------------|----------------
            MAX  |    2.00      |     2.30       |     2.52
          -------|--------------|----------------|----------------
                                                                         
***************************************************************************/

void encoder(Word16  number_of_available_bits,
             Word16  number_of_regions,
             Word16  *mlt_coefs,
             Word16  mag_shift,
             Word16  *out_words)
{

    Word16  num_categorization_control_bits;
    Word16  num_categorization_control_possibilities;
    Word16  number_of_bits_per_frame;
    Word16  number_of_envelope_bits;
    Word16  categorization_control;
    Word16  region;
    Word16  absolute_region_power_index[MAX_NUMBER_OF_REGIONS];
    Word16  power_categories[MAX_NUMBER_OF_REGIONS];
    Word16  category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1];
    Word16  drp_num_bits[MAX_NUMBER_OF_REGIONS+1];
    UWord16 drp_code_bits[MAX_NUMBER_OF_REGIONS+1];
    Word16  region_mlt_bit_counts[MAX_NUMBER_OF_REGIONS];
    UWord32 region_mlt_bits[4*MAX_NUMBER_OF_REGIONS];
    Word16  mag_shift_offset;

    Word16 temp;

    /* initialize variables */
    test();
    if (number_of_regions == NUMBER_OF_REGIONS)
    {
        num_categorization_control_bits = NUM_CATEGORIZATION_CONTROL_BITS;
        move16();
        num_categorization_control_possibilities = NUM_CATEGORIZATION_CONTROL_POSSIBILITIES;
        move16();
    } 
    else
    {
        num_categorization_control_bits = MAX_NUM_CATEGORIZATION_CONTROL_BITS;
        move16();
        num_categorization_control_possibilities = MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES;
        move16();
    }

    number_of_bits_per_frame = number_of_available_bits;
    move16();

    for (region=0; region<number_of_regions; region++)
    {
        region_mlt_bit_counts[region] = 0;
        move16();
    }
    
    /* Estimate power envelope. */
    number_of_envelope_bits = compute_region_powers(mlt_coefs,
                                                    mag_shift,
                                                    drp_num_bits,
                                                    drp_code_bits,
                                                    absolute_region_power_index,
                                                    number_of_regions);

    /* Adjust number of available bits based on power envelope estimate */
    temp = sub(number_of_available_bits,number_of_envelope_bits);
    number_of_available_bits = sub(temp,num_categorization_control_bits);

    /* get categorizations */
    categorize(number_of_available_bits,
               number_of_regions,
               num_categorization_control_possibilities,
               absolute_region_power_index,
               power_categories,
               category_balances);

    /* Adjust absolute_region_category_index[] for mag_shift.
       This assumes that REGION_POWER_STEPSIZE_DB is defined
       to be exactly 3.010299957 or 20.0 times log base 10
       of square root of 2. */
    temp = shl(mag_shift,1);
    mag_shift_offset = add(temp,REGION_POWER_TABLE_NUM_NEGATIVES);
    
    for (region=0; region<number_of_regions; region++)
    {
        absolute_region_power_index[region] = add(absolute_region_power_index[region],mag_shift_offset);
        move16();
    }

    /* adjust the absolute power region index based on the mlt coefs */
    adjust_abs_region_power_index(absolute_region_power_index,mlt_coefs,number_of_regions);


    /* quantize and code the mlt coefficients based on categorizations */
    vector_quantize_mlts(number_of_available_bits,
                         number_of_regions,
                         num_categorization_control_possibilities,
                         mlt_coefs,
                         absolute_region_power_index,
                         power_categories,
                         category_balances,
                         &categorization_control,
                         region_mlt_bit_counts,
                         region_mlt_bits);

    /* stuff bits into words */
    bits_to_words(region_mlt_bits,
                  region_mlt_bit_counts,
                  drp_num_bits,
                  drp_code_bits,
                  out_words,
                  categorization_control,
                  number_of_regions,
                  num_categorization_control_bits,
                  number_of_bits_per_frame);

}

/***************************************************************************
 Function:    bits_to_words

 Syntax:      bits_to_words(UWord32 *region_mlt_bits,              
                            Word16  *region_mlt_bit_counts,                                                             
                            Word16  *drp_num_bits,                                                                      
                            UWord16 *drp_code_bits,                                                                     
                            Word16  *out_words,                                                                         
                            Word16  categorization_control,                                                                         
                            Word16  number_of_regions,
                            Word16  num_categorization_control_bits,
                            Word16  number_of_bits_per_frame)                                                           
                                                                   
                                                                   
 Description: Stuffs the bits into words for output

 WMOPS:     7kHz |    24kbit    |      32kbit
          -------|--------------|----------------
            AVG  |    0.09      |     0.12
          -------|--------------|----------------  
            MAX  |    0.10      |     0.13
          -------|--------------|---------------- 
          
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.12      |     0.15       |     0.19
          -------|--------------|----------------|----------------
            MAX  |    0.14      |     0.17       |     0.21
          -------|--------------|----------------|----------------

***************************************************************************/
void bits_to_words(UWord32 *region_mlt_bits,
                   Word16  *region_mlt_bit_counts,
                   Word16  *drp_num_bits,
                   UWord16 *drp_code_bits,
                   Word16  *out_words,
                   Word16  categorization_control,
                   Word16  number_of_regions,
                   Word16  num_categorization_control_bits,
                   Word16  number_of_bits_per_frame)
{
    Word16  out_word_index = 0;
    Word16  j;
    Word16  region;
    Word16  out_word;
    Word16  region_bit_count;
    Word16  current_word_bits_left;
    UWord16 slice;
    Word16  out_word_bits_free = 16;
    UWord32 *in_word_ptr;
    UWord32 current_word;
    
    Word32  acca;
    Word32  accb;
    Word16  temp;

    /* First set up the categorization control bits to look like one more set of region power bits. */
    out_word = 0;
    move16();

    drp_num_bits[number_of_regions] = num_categorization_control_bits;
    move16();
    
    drp_code_bits[number_of_regions] = (UWord16)categorization_control;
    move16();

    /* These code bits are right justified. */
    for (region=0; region <= number_of_regions; region++)
    {
        current_word_bits_left = drp_num_bits[region];
        move16();
        
        current_word = (UWord32)drp_code_bits[region];
        move16();
        
        j = sub(current_word_bits_left,out_word_bits_free);

        test();
        if (j >= 0)
        {
            temp = extract_l(L_shr(current_word,j));
            out_word = add(out_word,temp);

            out_words[out_word_index++] = out_word;
            move16();
            
            out_word_bits_free = 16;
            move16();
            
            out_word_bits_free = sub(out_word_bits_free,j);
            
            acca = (current_word << out_word_bits_free);
            out_word = extract_l(acca);
        }
        else
        {
            j = negate(j);

            acca = (current_word << j);
            accb = L_deposit_l(out_word);
            acca = L_add(accb,acca);
            out_word = extract_l(acca);
            
            out_word_bits_free = sub(out_word_bits_free,current_word_bits_left);
        }
    }

    /* These code bits are left justified. */
    
    for (region=0;region<number_of_regions; region++)
    {
        accb = L_deposit_l(out_word_index);
        accb = L_shl(accb,4);
        accb = L_sub(accb,number_of_bits_per_frame);
        test();
        if(accb < 0)        
        {
            temp = shl(region,2);
            in_word_ptr = &region_mlt_bits[temp];
            region_bit_count = region_mlt_bit_counts[region];
            move16();

            temp = sub(32,region_bit_count);
            test();
            if(temp > 0)
                current_word_bits_left = region_bit_count;
            else
                current_word_bits_left = 32;

            current_word = *in_word_ptr++;
    
            acca = L_deposit_l(out_word_index);
            acca = L_shl(acca,4);
            acca = L_sub(acca,number_of_bits_per_frame);
            
            /* from while loop */
            test();
            test();
            logic16(); 
            while ((region_bit_count > 0) && (acca < 0))
            {
                /* from while loop */
                test();
                test();
                logic16(); 
                
                temp = sub(current_word_bits_left,out_word_bits_free);
                test();
                if (temp >= 0)
                {
                    temp = sub(32,out_word_bits_free);
                    accb = LU_shr(current_word,temp);
                    slice = (UWord16)extract_l(accb);
                    
                    out_word = add(out_word,slice);
    
                    test();
                    current_word <<= out_word_bits_free;

                    current_word_bits_left = sub(current_word_bits_left,out_word_bits_free);
                    out_words[out_word_index++] = extract_l(out_word);
                    move16();

                    out_word = 0;
                    move16();

                    out_word_bits_free = 16;
                    move16();
                }
                else
                {
                    temp = sub(32,current_word_bits_left);
                    accb = LU_shr(current_word,temp);
                    slice = (UWord16)extract_l(accb);
                    
                    temp = sub(out_word_bits_free,current_word_bits_left);
                    test();
                    accb = slice << temp;
                    acca = L_deposit_l(out_word);
                    acca = L_add(acca,accb);
                    out_word = extract_l(acca);
                    out_word_bits_free = sub(out_word_bits_free,current_word_bits_left);
                    
                    current_word_bits_left = 0;
                    move16();
                }
    
                test();
                if (current_word_bits_left == 0)
                {
                    current_word = *in_word_ptr++;
                    region_bit_count = sub(region_bit_count,32);
                    
                    /* current_word_bits_left = MIN(32,region_bit_count); */
                    temp = sub(32,region_bit_count);
                    test();
                    if(temp > 0)
                        current_word_bits_left = region_bit_count;
                    else
                        current_word_bits_left = 32;
                    
                }
                acca = L_deposit_l(out_word_index);
                acca = L_shl(acca,4);
                acca = L_sub(acca,number_of_bits_per_frame);
            }
            accb = L_deposit_l(out_word_index);
            accb = L_shl(accb,4);
            accb = L_sub(accb,number_of_bits_per_frame);
        }
    }

    /* Fill out with 1's. */

    test();
    while (acca < 0)
    {
        test();
        current_word = 0x0000ffff;
        move32();

        temp = sub(16,out_word_bits_free);
        acca = LU_shr(current_word,temp);
        slice = (UWord16)extract_l(acca);

        out_word = add(out_word,slice);
        out_words[out_word_index++] = out_word;
        move16();

        out_word = 0;
        move16();
        
        out_word_bits_free = 16;
        move16();
        
        acca = L_deposit_l(out_word_index);
        acca = L_shl(acca,4);
        acca = L_sub(acca,number_of_bits_per_frame);
    }
}
/***************************************************************************
 Function:    adjust_abs_region_power_index

 Syntax:      adjust_abs_region_power_index(Word16 *absolute_region_power_index,
                                            Word16 *mlt_coefs,
                                            Word16 number_of_regions)

              inputs:   *mlt_coefs
                        *absolute_region_power_index
                        number_of_regions
            
              outputs:  *absolute_region_power_index
 
 Description: Adjusts the absolute power index
 
 
 WMOPS:     7kHz |    24kbit    |      32kbit
          -------|--------------|----------------
            AVG  |    0.03      |      0.03
          -------|--------------|----------------  
            MAX  |    0.12      |      0.12
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.03      |     0.03       |     0.03
          -------|--------------|----------------|----------------
            MAX  |    0.14      |     0.14       |     0.14
          -------|--------------|----------------|----------------

***************************************************************************/
void adjust_abs_region_power_index(Word16 *absolute_region_power_index,Word16 *mlt_coefs,Word16 number_of_regions)
{
    Word16 n,i;
    Word16 region;
    Word16 *raw_mlt_ptr;
    
    Word32 acca;
    Word16 temp;

    for (region=0; region<number_of_regions; region++)
    {
        n = sub(absolute_region_power_index[region],39);
        n = shr(n,1);
        
        test();
        if (n > 0)
        {
            temp = extract_l(L_mult0(region,REGION_SIZE));

            raw_mlt_ptr = &mlt_coefs[temp];

            for (i=0; i<REGION_SIZE; i++)
            {
                acca = L_shl(*raw_mlt_ptr,16);
                acca = L_add(acca,32768L);
                acca = L_shr(acca,n);
                acca = L_shr(acca,16);
                *raw_mlt_ptr++ = extract_l(acca);
            }

            temp = shl(n,1);
            temp = sub(absolute_region_power_index[region],temp);
            absolute_region_power_index[region] = temp;
            move16();
        }
    }
}

/***************************************************************************
 Function:    compute_region_powers

 Syntax:      Word16 compute_region_powers(Word16  *mlt_coefs,                         
                                           Word16  mag_shift,                         
                                           Word16  *drp_num_bits,                      
                                           UWord16 *drp_code_bits,                     
                                           Word16  *absolute_region_power_index,       
                                           Word16  number_of_regions)
                mlt_coefs[DCT_LENGTH];                      
                mag_shift;                                          
                drp_num_bits[MAX_NUMBER_OF_REGIONS];                      
                drp_code_bits[MAX_NUMBER_OF_REGIONS];                     
                absolute_region_power_index[MAX_NUMBER_OF_REGIONS];       
                number_of_regions;
                                                                   
 Description: Computes the power for each of the regions

 
 WMOPS:     7kHz |    24kbit    |    32kbit
          -------|--------------|----------------
            AVG  |    0.09      |    0.09
          -------|--------------|----------------  
            MAX  |    0.13      |    0.13
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.20      |     0.20       |     0.20
          -------|--------------|----------------|----------------
            MAX  |    0.29      |     0.29       |     0.29
          -------|--------------|----------------|----------------

***************************************************************************/

Word16 compute_region_powers(Word16  *mlt_coefs,
                             Word16  mag_shift,
                             Word16  *drp_num_bits,
                             UWord16 *drp_code_bits,
                             Word16  *absolute_region_power_index,
                             Word16  number_of_regions)
{

    Word16 *input_ptr;
    Word32 long_accumulator;
    Word16 itemp1;
    Word16 power_shift;
    Word16 region;
    Word16 j;
    Word16 differential_region_power_index[MAX_NUMBER_OF_REGIONS];
    Word16 number_of_bits;
    
    Word32 acca;
    Word16 temp;
    Word16 temp1;
    Word16 temp2;


    input_ptr = mlt_coefs;
    for (region=0; region<number_of_regions; region++)
    {
        long_accumulator = L_deposit_l(0);

        for (j=0; j<REGION_SIZE; j++)
        {
            itemp1 = *input_ptr++;
            move16();
            long_accumulator = L_mac0(long_accumulator,itemp1,itemp1);
        }

        power_shift = 0;
        move16();

        acca = (long_accumulator & 0x7fff0000L);
        logic32();

        test();
        while (acca > 0)
        {
            test();
            long_accumulator = L_shr(long_accumulator,1);
            
            acca = (long_accumulator & 0x7fff0000L);
            logic32();

            power_shift = add(power_shift,1);
        }
        
        acca = L_sub(long_accumulator,32767);
        
        temp = add(power_shift,15);
        test();
        test();
        logic16();
        while ((acca <= 0) && (temp >= 0))
        {
            test();
            test();
            logic16();
            
            long_accumulator = L_shl(long_accumulator,1);
            acca = L_sub(long_accumulator,32767);
            power_shift--;
            temp = add(power_shift,15);
        }
        long_accumulator = L_shr(long_accumulator,1);
        /* 28963 corresponds to square root of 2 times REGION_SIZE(20). */
        acca = L_sub(long_accumulator,28963);
        
        test();
        if (acca >= 0)
            power_shift = add(power_shift,1);
        
        acca = L_deposit_l(mag_shift);
        acca = L_shl(acca,1);
        acca = L_sub(power_shift,acca);
        acca = L_add(35,acca);
        acca = L_sub(acca,REGION_POWER_TABLE_NUM_NEGATIVES);
        absolute_region_power_index[region] = extract_l(acca);
    }


    /* Before we differentially encode the quantized region powers, adjust upward the
    valleys to make sure all the peaks can be accurately represented. */
    temp = sub(number_of_regions,2);

    for (region = temp; region >= 0; region--)
    {
        temp1 = sub(absolute_region_power_index[region+1],DRP_DIFF_MAX);
        temp2 = sub(absolute_region_power_index[region],temp1);
        test();
        if (temp2 < 0)
        {
            absolute_region_power_index[region] = temp1;
            move16();
        }
    }

    /* The MLT is currently scaled too low by the factor
       ENCODER_SCALE_FACTOR(=18318)/32768 * (1./sqrt(160).
       This is the ninth power of 1 over the square root of 2.
       So later we will add ESF_ADJUSTMENT_TO_RMS_INDEX (now 9)
       to drp_code_bits[0]. */

    /* drp_code_bits[0] can range from 1 to 31. 0 will be used only as an escape sequence. */
    temp1 = sub(1,ESF_ADJUSTMENT_TO_RMS_INDEX);
    temp2 = sub(absolute_region_power_index[0],temp1);
    test();
    if (temp2 < 0)
    {
        absolute_region_power_index[0] = temp1;
        move16();
    }
    
    temp1 = sub(31,ESF_ADJUSTMENT_TO_RMS_INDEX);

	/*
	 * The next line was corrected in Release 1.2 
	 */

    temp2 = sub(absolute_region_power_index[0], temp1);  
    test();
    if (temp2 > 0)
    {
        absolute_region_power_index[0] = temp1;
        move16();
    }

    differential_region_power_index[0] = absolute_region_power_index[0];
    move16();
    
    number_of_bits = 5;
    move16();
    
    drp_num_bits[0] = 5;
    move16();
    
    drp_code_bits[0] = (UWord16)add(absolute_region_power_index[0],ESF_ADJUSTMENT_TO_RMS_INDEX);
    move16();

    /* Lower limit the absolute region power indices to -8 and upper limit them to 31. Such extremes
     may be mathematically impossible anyway.*/
    for (region=1; region<number_of_regions; region++)
    {
        temp1 = sub(-8,ESF_ADJUSTMENT_TO_RMS_INDEX);
        temp2 = sub(absolute_region_power_index[region],temp1);
        test();
        if (temp2 < 0)
        {
            absolute_region_power_index[region] = temp1;
            move16();
        }

        temp1 = sub(31,ESF_ADJUSTMENT_TO_RMS_INDEX);
        temp2 = sub(absolute_region_power_index[region],temp1);
        test();
        if (temp2 > 0)
        {
            absolute_region_power_index[region] = temp1;
            move16();
        }
    }

    for (region=1; region<number_of_regions; region++)
    {
        j = sub(absolute_region_power_index[region],absolute_region_power_index[region-1]);
        temp = sub(j,DRP_DIFF_MIN);
        test();
        if (temp < 0)
        {
            j = DRP_DIFF_MIN;
        }
        j = sub(j,DRP_DIFF_MIN);
        move16();
        differential_region_power_index[region] = j;
        move16();
        
        temp = add(absolute_region_power_index[region-1],differential_region_power_index[region]);
        temp = add(temp,DRP_DIFF_MIN);
        absolute_region_power_index[region] = temp;
        move16();

        number_of_bits = add(number_of_bits,differential_region_power_bits[region][j]);
        drp_num_bits[region] = differential_region_power_bits[region][j];
        move16();
        drp_code_bits[region] = differential_region_power_codes[region][j];
        move16();
    }

    return (number_of_bits);
}

/***************************************************************************
 Function:    vector_quantize_mlts

 Syntax:      void vector_quantize_mlts(number_of_available_bits,
                                        number_of_regions,                     
                                        num_categorization_control_possibilities,
                                        mlt_coefs,                                    
                                        absolute_region_power_index,                  
                                        power_categories,                             
                                        category_balances,                            
                                        p_categorization_control,                               
                                        region_mlt_bit_counts,                        
                                        region_mlt_bits)                              
                                                                                    
              Word16 number_of_available_bits;                                        
              Word16 number_of_regions;
              Word16 num_categorization_control_possibilities;
              Word16 mlt_coefs[DCT_LENGTH];                                         
              Word16 absolute_region_power_index[MAX_NUMBER_OF_REGIONS];                  
              Word16 power_categories[MAX_NUMBER_OF_REGIONS];                             
              Word16 category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1];         
              Word16 *p_categorization_control;                                                 
              Word16 region_mlt_bit_counts[MAX_NUMBER_OF_REGIONS];                        
              Word32 region_mlt_bits[4*MAX_NUMBER_OF_REGIONS];                            

 Description: Scalar quantized vector Huffman coding (SQVH)

 
 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.57      |     0.65
          -------|--------------|----------------  
            MAX  |    0.78      |     0.83
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.62      |     0.90       |     1.11
          -------|--------------|----------------|----------------
            MAX  |    1.16      |     1.39       |     1.54
          -------|--------------|----------------|----------------

***************************************************************************/

void vector_quantize_mlts(Word16 number_of_available_bits,
                          Word16 number_of_regions,
                          Word16 num_categorization_control_possibilities,
                          Word16 *mlt_coefs,
                          Word16 *absolute_region_power_index,
                          Word16 *power_categories,
                          Word16 *category_balances,
                          Word16 *p_categorization_control,
                          Word16 *region_mlt_bit_counts,
                          UWord32 *region_mlt_bits)
{

    Word16 *raw_mlt_ptr;
    Word16 region;
    Word16 category;
    Word16 total_mlt_bits = 0;

    Word16 temp;
    Word16 temp1;
    Word16 temp2;

    /* Start in the middle of the categorization control range. */
    temp = shr(num_categorization_control_possibilities,1);
    temp = sub(temp,1);
    for (*p_categorization_control = 0; *p_categorization_control < temp; (*p_categorization_control)++)
    {
        region = category_balances[*p_categorization_control];
        move16();
        power_categories[region] = add(power_categories[region],1);
        move16();
    }

    for (region=0; region<number_of_regions; region++)
    {
        category = power_categories[region];
        move16();
        temp = extract_l(L_mult0(region,REGION_SIZE));
        raw_mlt_ptr = &mlt_coefs[temp];
        move16();
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
            vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
    }


    /* If too few bits... */
    temp = sub(total_mlt_bits,number_of_available_bits);
    test();
    test();
    logic16();
    while ((temp < 0) && (*p_categorization_control > 0))
    {
        test();
        test();
        logic16();
        (*p_categorization_control)--;
        region = category_balances[*p_categorization_control];
        move16();
        
        power_categories[region] = sub(power_categories[region],1);
        move16();

        total_mlt_bits = sub(total_mlt_bits,region_mlt_bit_counts[region]);
        category = power_categories[region];
        move16();
        
        raw_mlt_ptr = &mlt_coefs[region*REGION_SIZE];
        move16();
        
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
                vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
        temp = sub(total_mlt_bits,number_of_available_bits);
    }

    /* If too many bits... */
    /* Set up for while loop test */
    temp1 = sub(total_mlt_bits,number_of_available_bits);
    temp2 = sub(*p_categorization_control,sub(num_categorization_control_possibilities,1));
    test();
    test();
    logic16();
    
    while ((temp1 > 0) && (temp2 < 0))
    {
        /* operations for while contitions */
        test();
        test();
        logic16();
        
        region = category_balances[*p_categorization_control];
        move16();
        
        power_categories[region] = add(power_categories[region],1);
        move16();

        total_mlt_bits = sub(total_mlt_bits,region_mlt_bit_counts[region]);
        category = power_categories[region];
        move16();
        
        temp = extract_l(L_mult0(region,REGION_SIZE));
        raw_mlt_ptr = &mlt_coefs[temp];
        move16();
        
        temp = sub(category,(NUM_CATEGORIES-1));
        test();
        if (temp < 0)
        {
            region_mlt_bit_counts[region] =
                vector_huffman(category, absolute_region_power_index[region],raw_mlt_ptr,
                           &region_mlt_bits[shl(region,2)]);
        }
        else
        {
            region_mlt_bit_counts[region] = 0;
            move16();
        }
        total_mlt_bits = add(total_mlt_bits,region_mlt_bit_counts[region]);
        (*p_categorization_control)++;
        
        temp1 = sub(total_mlt_bits,number_of_available_bits);
        temp2 = sub(*p_categorization_control,sub(num_categorization_control_possibilities,1));
    }
}

/***************************************************************************
 Function:    vector_huffman

 Syntax:      Word16 vector_huffman(Word16  category,     
                                    Word16  power_index,  
                                    Word16  *raw_mlt_ptr,  
                                    UWord32 *word_ptr)     
                                              
              inputs:     Word16  category
                          Word16  power_index
                          Word16  *raw_mlt_ptr
             
              outputs:    number_of_region_bits
                          *word_ptr
                                      

 Description: Huffman encoding for each region based on category and power_index  

 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.03      |     0.03
          -------|--------------|----------------  
            MAX  |    0.04      |     0.04
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.03      |     0.03       |     0.03
          -------|--------------|----------------|----------------
            MAX  |    0.04      |     0.04       |     0.04
          -------|--------------|----------------|----------------

***************************************************************************/
Word16 vector_huffman(Word16 category,
                      Word16 power_index,
                      Word16 *raw_mlt_ptr,
                      UWord32 *word_ptr)
{
 

    Word16  inv_of_step_size_times_std_dev;
    Word16  j,n;
    Word16  k;
    Word16  number_of_region_bits;
    Word16  number_of_non_zero;
    Word16  vec_dim;
    Word16  num_vecs;
    Word16  kmax, kmax_plus_one;
    Word16  index,signs_index;
    Word16  *bitcount_table_ptr;
    UWord16 *code_table_ptr;
    Word32  code_bits;
    Word16  number_of_code_bits;
    UWord32 current_word;
    Word16  current_word_bits_free;
    
    Word32 acca;
    Word32 accb;
    Word16 temp;

    Word16 mytemp;			 /* new variable in Release 1.2 */
    Word16 myacca;			 /* new variable in Release 1.2 */


    /* initialize variables */
    vec_dim = vector_dimension[category];
    move16();

    num_vecs = number_of_vectors[category];
    move16();

    kmax = max_bin[category];
    move16();

    kmax_plus_one = add(kmax,1);
    move16();

    current_word = 0L;
    move16();

    current_word_bits_free = 32;
    move16();

    number_of_region_bits = 0;
    move16();

    /* set up table pointers */
    bitcount_table_ptr = (Word16 *)table_of_bitcount_tables[category];
    code_table_ptr = (UWord16 *) table_of_code_tables[category];

    /* compute inverse of step size * standard deviation */
    acca = L_mult(step_size_inverse_table[category],standard_deviation_inverse_table[power_index]);
    acca = L_shr(acca,1);
    acca = L_add(acca,4096);
    acca = L_shr(acca,13);

	/*
	 *  The next two lines are new to Release 1.2 
	 */
     
    mytemp = (Word16)(acca & 0x3);
    acca = L_shr(acca,2);

    inv_of_step_size_times_std_dev = extract_l(acca);


    for (n=0; n<num_vecs; n++)
    {
        index = 0;
        move16();
        
        signs_index = 0;
        move16();
        
        number_of_non_zero = 0;
        move16();
        
        for (j=0; j<vec_dim; j++)
        {
            k = abs_s(*raw_mlt_ptr);
            
            acca = L_mult(k,inv_of_step_size_times_std_dev);
            acca = L_shr(acca,1);
		    
			/*
			 *  The next four lines are new to Release 1.2
			 */

			myacca = (Word16)L_mult(k,mytemp);
			myacca = (Word16)L_shr(myacca,1);
			myacca = (Word16)L_add(myacca,int_dead_zone_low_bits[category]);
			myacca = (Word16)L_shr(myacca,2);

            acca = L_add(acca,int_dead_zone[category]);

			/*
			 *  The next two lines are new to Release 1.2
			 */

			acca = L_add(acca,myacca);
			acca = L_shr(acca,13);

            k = extract_l(acca);

            test();
            if (k != 0)
            {
                number_of_non_zero = add(number_of_non_zero,1);
                signs_index = shl(signs_index,1);
                
                test();
                if (*raw_mlt_ptr > 0)
                {
                    signs_index = add(signs_index,1);
                }
                
                temp = sub(k,kmax);
                test();
                if (temp > 0)
                {
                    k = kmax;
                    move16();
                }
            }
            acca = L_shr(L_mult(index,(kmax_plus_one)),1);
            index = extract_l(acca);
            index = add(index,k);
            raw_mlt_ptr++;
        }

        code_bits = *(code_table_ptr+index);
        number_of_code_bits = add((*(bitcount_table_ptr+index)),number_of_non_zero);
        number_of_region_bits = add(number_of_region_bits,number_of_code_bits);

        acca = code_bits << number_of_non_zero;
        accb = L_deposit_l(signs_index);
        acca = L_add(acca,accb);
        code_bits = acca;
        move32();

        /* msb of codebits is transmitted first. */
        j = sub(current_word_bits_free,number_of_code_bits);
        test();
        if (j >= 0)
        {
            test();
            acca = code_bits << j;
            current_word = L_add(current_word,acca);
            current_word_bits_free = j;
            move16();
        }
        else
        {
            j = negate(j);
            acca = L_shr(code_bits,j);
            current_word = L_add(current_word,acca);
            
            *word_ptr++ = current_word;
            move16();

            current_word_bits_free = sub(32,j);
            test();
            current_word = code_bits << current_word_bits_free;
        }
    }

    *word_ptr++ = current_word;
    move16();

    return (number_of_region_bits);
}


