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

  Purpose:     Contains the functions used for both G.722.1 Annex C encoder and decoder
		
  Design Notes:

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

/****************************************************************************************
 Function:    categorize

 Syntax:      void categorize(Word16 number_of_available_bits,   
                              Word16 number_of_regions,
                              Word16 num_categorization_control_possibilities,
                              Word16 rms_index,                  
                              Word16 power_categories,           
                              Word16 category_balances)          

                  inputs:   number_of_regions
                            num_categorization_control_possibilities
                            number_of_available_bits
                            rms_index[MAX_NUMBER_OF_REGIONS]                              
                  
                  outputs:  power_categories[MAX_NUMBER_OF_REGIONS]                       
                            category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1]

 Description: Computes a series of categorizations 

 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.14      |     0.14
          -------|--------------|----------------  
            MAX  |    0.15      |     0.15
          -------|--------------|---------------- 
   			
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.42      |     0.45       |     0.48   
          -------|--------------|----------------|----------------
            MAX  |    0.47      |     0.52       |     0.52   
          -------|--------------|----------------|----------------

****************************************************************************************/
void categorize(Word16 number_of_available_bits,
		        Word16 number_of_regions,
		        Word16 num_categorization_control_possibilities,
		        Word16 *rms_index,
		        Word16 *power_categories,
		        Word16 *category_balances)
{
    
    Word16 offset;
    Word16 temp;
    Word16 frame_size;

    /* At higher bit rates, there is an increase for most categories in average bit
       consumption per region. We compensate for this by pretending we have fewer
       available bits. */
    test();
    if (number_of_regions == NUMBER_OF_REGIONS)
    {
        frame_size = DCT_LENGTH;
    }
    else
    {
        frame_size = MAX_DCT_LENGTH;
    }

    temp = sub(number_of_available_bits,frame_size);
    
    test();
    if (temp > 0)
    {
        number_of_available_bits = sub(number_of_available_bits,frame_size);
        number_of_available_bits = extract_l(L_mult0(number_of_available_bits,5));
        number_of_available_bits = shr(number_of_available_bits,3);
        number_of_available_bits = add(number_of_available_bits,frame_size);
    }

    /* calculate the offset using the original category assignments */
    offset = calc_offset(rms_index,number_of_regions,number_of_available_bits);



    /* compute the power categories based on the uniform offset */
    compute_raw_pow_categories(power_categories,rms_index,number_of_regions,offset);
    
    
    /* adjust the category assignments */
    /* compute the new power categories and category balances */
    comp_powercat_and_catbalance(power_categories,category_balances,rms_index,number_of_available_bits,number_of_regions,num_categorization_control_possibilities,offset);

}
    
/***************************************************************************
 Function:    comp_powercat_and_catbalance

 Syntax:      void comp_powercat_and_catbalance(Word16 *power_categories,
                                                Word16 *category_balances,
                                                Word16 *rms_index,  
                                                Word16 number_of_available_bits,                                  
                                                Word16 number_of_regions,
                                                Word16 num_categorization_control_possibilities,
                                                Word16 offset)                                                    

                
                inputs:   *rms_index                              
                          number_of_available_bits                 
                          number_of_regions
                          num_categorization_control_possibilities
                          offset
                           
                outputs:  *power_categories  
                          *category_balances 
                
                
 Description: Computes the power_categories and the category balances

 WMOPS:     7kHz |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.10      |     0.10
          -------|--------------|----------------  
            MAX  |    0.11      |     0.11
          -------|--------------|---------------- 
				
           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.32      |     0.35       |     0.38   
          -------|--------------|----------------|----------------
            MAX  |    0.38      |     0.42       |     0.43   
          -------|--------------|----------------|----------------

***************************************************************************/
void comp_powercat_and_catbalance(Word16 *power_categories,
                                  Word16 *category_balances,
                                  Word16 *rms_index,
                                  Word16 number_of_available_bits,
                                  Word16 number_of_regions,
                                  Word16 num_categorization_control_possibilities,
								  Word16 offset)
{
    
    Word16 expected_number_of_code_bits;
    Word16 region;
    Word16 max_region;
    Word16 j;
    Word16 max_rate_categories[MAX_NUMBER_OF_REGIONS];
    Word16 min_rate_categories[MAX_NUMBER_OF_REGIONS];
    Word16 temp_category_balances[2*MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES];
    Word16 raw_max, raw_min;
    Word16 raw_max_index, raw_min_index;
    Word16 max_rate_pointer, min_rate_pointer;
    Word16 max, min;
    Word16 itemp0;
    Word16 itemp1;
    Word16 min_plus_max;
    Word16 two_x_number_of_available_bits;

    Word16 temp;

    expected_number_of_code_bits = 0;
    move16();

    for (region=0; region<number_of_regions; region++)
        expected_number_of_code_bits = add(expected_number_of_code_bits,expected_bits_table[power_categories[region]]);


    for (region=0; region<number_of_regions; region++) 
    {
        max_rate_categories[region] = power_categories[region];
        move16();
        
        min_rate_categories[region] = power_categories[region];
        move16();
    }
    
    max = expected_number_of_code_bits;
    move16();
    min = expected_number_of_code_bits;
    move16();
    max_rate_pointer = num_categorization_control_possibilities;
    move16();
    min_rate_pointer = num_categorization_control_possibilities;
    move16();
    
    for (j=0; j<num_categorization_control_possibilities-1; j++) 
    {
        min_plus_max = add(max,min);
        two_x_number_of_available_bits = shl(number_of_available_bits,1);
        
        temp = sub(min_plus_max,two_x_number_of_available_bits);
        test();
        if (temp <= 0) 
        {
            raw_min = 99;
            move16();
            /* Search from lowest freq regions to highest for best */
            /* region to reassign to a higher bit rate category.   */
            for (region=0; region<number_of_regions; region++) 
            {
                test();
                if (max_rate_categories[region] > 0) 
                {
                    itemp0 = shl(max_rate_categories[region],1);
                    itemp1 = sub(offset,rms_index[region]);
                    itemp0 = sub(itemp1,itemp0);
                    
                    temp = sub(itemp0,raw_min);
                    test();
                    if (temp < 0) 
                    {
                        raw_min = itemp0;
                        raw_min_index = region;
                    }
                }
            }
            max_rate_pointer = sub(max_rate_pointer,1);
            temp_category_balances[max_rate_pointer] = raw_min_index;
            move16();

        	max = sub(max,expected_bits_table[max_rate_categories[raw_min_index]]);
        	max_rate_categories[raw_min_index] = sub(max_rate_categories[raw_min_index],1);
        	move16();

            max = add(max,expected_bits_table[max_rate_categories[raw_min_index]]);
        }
        else 
        {
            raw_max = -99;
            move16();
            /* Search from highest freq regions to lowest for best region to reassign to
            a lower bit rate category. */
            max_region = sub(number_of_regions,1);
            for (region= max_region; region >= 0; region--) 
            {
                temp = sub(min_rate_categories[region],(NUM_CATEGORIES-1));
                test();
                if (temp < 0)
                {
                    itemp0 = shl(min_rate_categories[region],1);
                    itemp1 = sub(offset,rms_index[region]);
                    itemp0 = sub(itemp1,itemp0);
                    
                    temp = sub(itemp0,raw_max);
                    test();
                    if (temp > 0) 
                    {
                        raw_max = itemp0;
                        move16();
                        raw_max_index = region;
                        move16();
                    }
                }
            }
            temp_category_balances[min_rate_pointer] = raw_max_index;
            move16();
            
            min_rate_pointer = add(min_rate_pointer,1);
            min = sub(min,expected_bits_table[min_rate_categories[raw_max_index]]);
            
            min_rate_categories[raw_max_index] = add(min_rate_categories[raw_max_index],1);
            move16();
            
            min = add(min,expected_bits_table[min_rate_categories[raw_max_index]]);
        }
    }
    
    for (region=0; region<number_of_regions; region++)
    {
        power_categories[region] = max_rate_categories[region];
        move16();
    }
    
    for (j=0; j<num_categorization_control_possibilities-1; j++)
    {
        category_balances[j] = temp_category_balances[max_rate_pointer++];
        move16();
    }

}
/***************************************************************************
 Function:    calc_offset

 Syntax:      offset=calc_offset(Word16 *rms_index,Word16 number_of_regions,Word16 available_bits)  

                input:  Word16 *rms_index
                        Word16 number_of_regions
                        Word16 available_bits
                        
                output: Word16 offset                        

 Description: Calculates the the category offset.  This is the shift required
              To get the most out of the number of available bits.  A binary 
              type search is used to find the offset.

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

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.08      |     0.08       |     0.08   
          -------|--------------|----------------|----------------
            MAX  |    0.09      |     0.09       |     0.09   
          -------|--------------|----------------|----------------

***************************************************************************/
Word16 calc_offset(Word16 *rms_index,Word16 number_of_regions,Word16 available_bits)    
{

    Word16 answer;
    Word16 delta;
    Word16 test_offset;
    Word16 region,j;
    Word16 power_cats[MAX_NUMBER_OF_REGIONS];
    Word16 bits;
    Word16 offset;
    Word16 temp;

    /* initialize vars */
    answer = -32;
    move16();
    delta = 32;
    move16();
    
    do 
    {
        test_offset = add(answer,delta);
        
        /* obtain a category for each region */
        /* using the test offset             */
        for (region=0; region<number_of_regions; region++) 
        {
            j = sub(test_offset,rms_index[region]);
            j = shr(j,1);
            
            /* Ensure j is between 0 and NUM_CAT-1 */
            test();
            if (j < 0) 
            {
                j = 0;
                move16();
            }
            temp = sub(j,NUM_CATEGORIES-1);
            test();
            if (temp > 0) 
            {
                j = sub(NUM_CATEGORIES,1);
                move16();
            }
            power_cats[region] = j;
            move16();
        }
        bits = 0;
        move16();

        /* compute the number of bits that will be used given the cat assignments */
        for (region=0; region<number_of_regions; region++)
            bits = add(bits,expected_bits_table[power_cats[region]]);

        /* if (bits > available_bits - 32) then divide the offset region for the bin search */
        offset = sub(available_bits,32);
        temp = sub(bits,offset);
        test();
        if (temp >= 0)
        {
            answer = test_offset;
            move16();
        }
        delta = shr(delta,1);
        test(); /* for the while loop */
    } while (delta > 0);

    return(answer);
}
/***************************************************************************
 Function:    compute_raw_pow_categories

 Syntax:      void compute_raw_pow_categories(Word16 *power_categories,
                                              Word16 *rms_index,
                                              Word16 number_of_regions,
                                              Word16 offset)
              inputs:  *rms_index
                       number_of_regions
                       offset
                    
              outputs: *power_categories                    



 Description: This function computes the power categories given the offset
              This is kind of redundant since they were already computed
              in calc_offset to determine the offset.

 WMOPS:          |    24kbit    |     32kbit
          -------|--------------|----------------
            AVG  |    0.01      |     0.01
          -------|--------------|----------------  
            MAX  |    0.01      |     0.01
          -------|--------------|---------------- 

           14kHz |    24kbit    |     32kbit     |     48kbit
          -------|--------------|----------------|----------------
            AVG  |    0.01      |     0.01       |     0.01   
          -------|--------------|----------------|----------------
            MAX  |    0.01      |     0.01       |     0.01   
          -------|--------------|----------------|----------------

***************************************************************************/
void compute_raw_pow_categories(Word16 *power_categories,Word16 *rms_index,Word16 number_of_regions,Word16 offset)
{
    Word16 region;
    Word16 j;
    Word16 temp;

    for (region=0; region<number_of_regions; region++) 
    {
        j = sub(offset,rms_index[region]);
        j = shr(j,1);
        
        /* make sure j is between 0 and NUM_CAT-1 */
        test();
        if (j < 0) 
        {
            j = 0;
            move16();
        }
        temp = sub(j,(NUM_CATEGORIES-1));
        test();
        if (temp > 0) 
            j = sub(NUM_CATEGORIES,1);
        
        power_categories[region] = j;
        move16();
    }
}

