/*====================================================================*/
/*         MPEG-4 Audio (ISO/IEC 14496-3) Copyright Header            */
/*====================================================================*/
/*
This software module was originally developed by Rakesh Taori and Andy
Gerrits (Philips Research Laboratories, Eindhoven, The Netherlands) in
the course of development of the MPEG-4 Audio (ISO/IEC 14496-3). This
software module is an implementation of a part of one or more MPEG-4
Audio (ISO/IEC 14496-3) tools as specified by the MPEG-4 Audio
(ISO/IEC 14496-3). ISO/IEC gives users of the MPEG-4 Audio (ISO/IEC
14496-3) free license to this software module or modifications thereof
for use in hardware or software products claiming conformance to the
MPEG-4 Audio (ISO/IEC 14496-3). Those intending to use this software
module in hardware or software products are advised that its use may
infringe existing patents. The original developer of this software
module and his/her company, 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-4 Audio (ISO/IEC 14496-3) conforming products.
CN1 retains full right to use the code for his/her own purpose, assign
or donate the code to a third party and to inhibit third parties from
using the code for non MPEG-4 Audio (ISO/IEC 14496-3) conforming
products.  This copyright notice must be included in all copies or
derivative works. Copyright 1996.
*/
/*====================================================================*/

/*====================================================================*/
/*                                                                    */
/*      SOURCE_FILE:    CELP_BITSTREAM_MUX.C                          */
/*                                                                    */
/*====================================================================*/
    
/*====================================================================*/
/*      I N C L U D E S                                               */
/*====================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "phi_cons.h"   
#include "lpc_common.h"  /* Common LPC core Defined Constants           */
#include "celp_bitstream_mux.h"    /* Parameter to bitstream conversion routines  */

#include "phi_freq.h"   
#include "vlr_enc.h"

#define FRAMES_UPDATE_RATE   1000
#define FRAMES_LOOKBACK      1000

/*======================================================================*/
/*      G L O B A L    D A T A   D E F I N I T I O N S                  */
/*======================================================================*/

/*----------------------------------------------------------------------*/
/* Number of levels for the indices                                     */
/*----------------------------------------------------------------------*/
static int levels[ORDER_LPC+1] =
{
    0, 36, 28, 15, 14, 13, 
    13, 12, 11,  9,  8, 
     8,  7,  7,  8,  7,
     6,  6,  7,  6,  6       
}; 

/*----------------------------------------------------------------------*/
/* Arrays for index counting                                            */
/*----------------------------------------------------------------------*/
static short freq[ORDER_LPC+1][36];
static int counter[ORDER_LPC+1];
static long frame_count = 1;

static long huff_tab[ORDER_LPC + 1][36];
static short codesize[ORDER_LPC + 1][36];


/*======================================================================*/
/* Function Definition: write_celp_bitstream_header                     */
/*======================================================================*/
void write_celp_bitstream_header(
    BITSTREAM  * const p_bitstream,  /* In/Out: Bitstream               */
    const long SampleRateMode,       /* In: SampleRate Mode             */
    const long QuantizationMode,     /* In: Type of Quantization        */
    const long FineRateControl,      /* In: Fine Rate Control switch    */
	const long LosslessCodingMode,   /* In: Lossless Coding Mode        */   
    const long WB_Configuration,     /* In: Wideband configuration      */
    const long Wideband_VQ,          /* In: Wideband VQ mode            */
    const long NB_Configuration,     /* In: Narrowband configuration    */
	const long NumEnhLayers,         /* In: Number of Enhancement Layers*/
	const long BandwidthScalabilityMode, /* In: bandwidth switch        */
	const long BWS_Configuration     /* In: BWS_configuration           */
)
{

    PutBit(p_bitstream, SampleRateMode, 1);
    PutBit(p_bitstream, QuantizationMode, 1);
    PutBit(p_bitstream, FineRateControl, 1);

    if ((QuantizationMode == ScalarQuantizer) && (FineRateControl == ON))
	{
        PutBit(p_bitstream, LosslessCodingMode, 1);
	}
	
	if (SampleRateMode == fs16kHz)   /* 16 khz sampling frequency */
	{
        PutBit(p_bitstream, WB_Configuration, 3);
        PutBit(p_bitstream, Wideband_VQ, 1);
	}
	
	if (SampleRateMode == fs8kHz)   /* 8 khz sampling frequency */
	{
        PutBit(p_bitstream, NB_Configuration, 5);
        PutBit(p_bitstream, NumEnhLayers, 2);
        PutBit(p_bitstream, BandwidthScalabilityMode, 1);
		if (BandwidthScalabilityMode == 1)
		{
            PutBit(p_bitstream, BWS_Configuration, 2);
		}
	}
    if (LosslessCodingMode == ON)
    {    
        int i, j, index;

        index = 0;
        for(i=1; i <= ORDER_LPC; i++)
        {
            counter[i] = 0;
            for (j=0; j < (int)levels[i]; j++)
            {
                 freq[i][j]  = init_freq[index];  
                 counter[i] += init_freq[index];
                 index++; 
            }
        }

        /* Calculate tables */
        for (i=1; i < ORDER_LPC + 1; i++)
        {
            short freq_copy[36];
            int j;

            for(j=0; j < levels[i]; j++)
            {
                 freq_copy[j] = freq[i][j];
            }

            hufflen(levels[i], freq_copy, codesize[i]);
            huff_len_to_cwrds(levels[i], codesize[i], huff_tab[i]);

        }
    }
}

/*======================================================================*/
/* Function Definition: Write_LosslessCoded_LPC                         */
/*======================================================================*/
void Write_LosslessCoded_LPC
(
    BITSTREAM * p_bitstream,           /* Out: Bitstream                */
	const long num_lpc_indices,        /* In: Number of LPC indices     */
	const long lpc_indices[],           /* In: indices                   */
	float	*bits			/* In/Out: #bits */
)
{
	/* Check if statistics need to be updated */
	if (frame_count % FRAMES_UPDATE_RATE == 0)
	{
    	int i;
    	int overhead_bits = 0;

    	/* Indicate that statistics update is needed */
    	PutBit(p_bitstream, 1, 1);

    	/* Calculate tables */
    	for (i=1; i < num_lpc_indices + 1; i++)
    	{
        	short freq_copy[36];
        	int j;

        	for(j=0; j < levels[i]; j++)
        	{
            	 freq_copy[j] = freq[i][j];
        	}

        	hufflen(levels[i], freq_copy, codesize[i]);
        	huff_len_to_cwrds(levels[i], codesize[i], huff_tab[i]);

        	/* Put codesize table on bitstream */
        	for(j=0; j < levels[i]; j++)
        	{
            	PutBit(p_bitstream, (long)(codesize[i][j]-1), MAX_VLC_BITS);
        	}

        	/* 4 bits per level overhead table */
        	overhead_bits += MAX_VLC_BITS * levels[i];

        	*bits += (float)(MAX_VLC_BITS * levels[i] + 1);

    	}

	}
	else
	{
       	  /* Indicate no statistics update */
    	  PutBit(p_bitstream, 0, 1);
    	  *bits += (float)1.0;
	}


	if (frame_count % FRAMES_LOOKBACK == 0)
	{
    	int i, j;
    	/* Clear current tables */
    	for(i=1; i <= num_lpc_indices; i++)
    	{

        	for (j=0; j < (int)levels[i]; j++)
        	{
            	 freq[i][j] = 0;   
        	}
        	counter[i] = 0;
    	}
	}
	frame_count++;

	/* write lpc indices to the bitstream */
	{   
        long k;
        for (k = 1; k <= num_lpc_indices; k++)
        {
            long codeword;
            short  codeword_length;

            /* Update frequency tables */
            freq[k][lpc_indices[k-1]] += 1;   
            counter[k] += 1;

            codeword = huff_tab[k][lpc_indices[k-1]];
            codeword_length = codesize[k][lpc_indices[k-1]];

            PutBit(p_bitstream, codeword, (long)codeword_length);

            *bits += (float)codeword_length;
        }
	}
 	
}

/*======================================================================*/
/* Function Definition: Write_WidebandPacked_LPC                        */
/*======================================================================*/
void Write_WidebandPacked_LPC
(
    BITSTREAM * p_bitstream,           /* In: Bitstream                 */
	const long num_lpc_indices,        /* In: Number of LPC indices     */
	const long indices[]               /* In: indices                   */
)
{
    /*==================================================================*/
    /*     Write the Parameters to the Bitstream                        */
	/*           These represent the packed LPC Indices                 */           
    /*==================================================================*/
	PutBit(p_bitstream, indices[0], 9);
	PutBit(p_bitstream, indices[1], 15);
	PutBit(p_bitstream, indices[2], 11);
	PutBit(p_bitstream, indices[3], 6);
	PutBit(p_bitstream, indices[4], 3);
	PutBit(p_bitstream, indices[5], 3);
	PutBit(p_bitstream, indices[6], 3);
	PutBit(p_bitstream, indices[7], 8);
	PutBit(p_bitstream, indices[8], 8);
}

/*======================================================================*/
/* Function Definition: Write_NarrowbandPacked_LPC                      */
/*======================================================================*/
void Write_NarrowbandPacked_LPC
(
    BITSTREAM * p_bitstream,           /* In: Bitstream                 */
	const long  indices[]              /* In: indices                   */
)
{
    /*==================================================================*/
    /*     Read the Parameters from the Bitstream                       */
	/*           These represent the packed LPC Indices                 */           
    /*==================================================================*/
	PutBit(p_bitstream, indices[0], 12);
	PutBit(p_bitstream, indices[1], 12);
	PutBit(p_bitstream, indices[2], 12);
	PutBit(p_bitstream, indices[3], 3);
}

/*======================================================================*/
/* Function Definition: Write_Narrowband_LSP                            */
/*======================================================================*/
void Write_NarrowBand_LSP
(
    BITSTREAM * p_bitstream,           /* In: Bitstream                 */
	const long indices[]               /* In: indices                   */
)
{
    /*==================================================================*/
    /*     Read the Parameters from the Bitstream                       */
	/*           These represent the packed LPC Indices                 */           
    /*==================================================================*/
	PutBit(p_bitstream, indices[0], 4);
	PutBit(p_bitstream, indices[1], 4);
	PutBit(p_bitstream, indices[2], 7);
	PutBit(p_bitstream, indices[3], 6);
	PutBit(p_bitstream, indices[4], 1);
}

/*======================================================================*/
/* Function Definition: Write_Narrowband_LSP                            */
/*======================================================================*/
void Write_BandScalable_LSP
(
    BITSTREAM * p_bitstream,           /* In: Bitstream                 */
	   const long indices[]            /* In: indices                   */
)
{
    /*==================================================================*/
    /*     Read the Parameters from the Bitstream                       */
	/*           These represent the packed LPC Indices                 */           
    /*==================================================================*/
	PutBit(p_bitstream, indices[0], 4);
	PutBit(p_bitstream, indices[1], 7);
	PutBit(p_bitstream, indices[2], 4);
	PutBit(p_bitstream, indices[3], 6);
	PutBit(p_bitstream, indices[4], 7);
	PutBit(p_bitstream, indices[5], 4);
}

/*======================================================================*/
/* Function Definition: Write_Wideband_LSP                              */
/*======================================================================*/
void Write_Wideband_LSP
(
    BITSTREAM * p_bitstream,           /* In: Bitstream                 */
	const long indices[]               /* In: indices                   */
)
{
    /*==================================================================*/
    /*     This mode is reserved for future use                         */
    /*==================================================================*/
	fprintf(stderr,"The wideband optimized VQ mode is reserved for future use\n");
	exit(0);
}

/*======================================================================*/
/* PutBit: Put length bits of c in bitstream bs                         */
/*======================================================================*/
void PutBit(
    BITSTREAM * const bs,
    const long c,
    const long length
)
{
    int j;
    
    if (bs != NULL)
    {
        if ((( (unsigned long)c >> (length-1)) >> 1) != 0)
        {
            fprintf(stderr,"ERROR: cannot pack code %d in %d bits\n", (unsigned long)c,
            length);
            exit(1);
        }
        for (j = (int)length-1; j>=0; j-=1)
        {
            int index = bs->valid_bits/8;
            int bit = 7 - (bs->valid_bits%8);
            
            if (index >= bs->buffer_length)
            {
                fprintf(stderr, "Error: Not enough bits available to encode frame\n");
                exit(1);
            }
            
            if (bit == 7)
            {
               (bs->p_bitstream_buffer_start)[index] = (unsigned char)0; 
            }
            
            if (((unsigned long)c >> j) & 1)
            {
                (bs->p_bitstream_buffer_start)[index] |= (unsigned char)(1 << bit);
            }            
            bs->valid_bits += 1;
        }
        
    }
}


 
/*======================================================================*/
/*      H I S T O R Y                                                   */
/*======================================================================*/
/* 07-06-96  R. Taori & A.Gerrits    Initial Version                    */
/* 18-09-96  R. Taori & A.Gerrits    MPEG bitstream used                */
