/*====================================================================*/
/*         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:    PHI_P2BS.C                                    */
/*      PACKAGE:        WDBxx                                         */
/*      COMPONENT:      Parameter to Bitstream converter              */
/*                                                                    */
/*====================================================================*/
    
/*====================================================================*/
/*      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 "phi_p2bs.h"    /* Parameter to bitstream conversion routines  */

/*======================================================================*/
/*      L O C A L  F U N C T I O N  P R O T O T Y P E S                 */
/*======================================================================*/
/*======================================================================*/
/* Pack Header                                                          */
/*======================================================================*/
static void PHI_pack_header(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */ 
    const long code,            /* In: Interpolation Flag               */
    const long num_bits         /* In: Number of bits used for header   */
    );
    
/*======================================================================*/
/* Pack lar codes                                                       */
/*======================================================================*/
static void PHI_pack_LPC(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */ 
    const long num_lpc_indices, /* In: Number of packed LPC             */
    const long lpc_codes[],     /* In: Packed LPC Codes                 */
    const long bit_allocation[] /* In: Number of bits for each LPC code */
    );

/*======================================================================*/
/* Pack Excitation Paramaters                                           */
/*======================================================================*/
static void PHI_pack_excitation(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */
    const long n_subframes,     /* In: Number of subframes              */
    const long num_shape_cbks,  /* In: Number of Shape Codebooks        */
    const long num_gain_cbks,   /* In: Number of Gain Codebooks         */
    const long shape_indices[], /* In: Adaptive Cbk lag and Fcbk index  */
    const long gain_indices[],  /* In: Adaptive and Fixed Codebook Gain */
    const long bit_allocation[] /* In: Number of bits for excitation    */
    );
    
/*======================================================================*/
/* Put length bits of c in bitstream bs                                 */
/*======================================================================*/
static void PutBit(
    BITSTREAM * const bs,
    const long c,
    const long length
    );


/*======================================================================*/
/* Function Definition: celp_bitstream_mux                              */
/*======================================================================*/
void celp_bitstream_mux(
    const long signal_mode,          /* In: Signal mode (NOT USED)      */
    const long frame_bit_allocation[],/* In: Bit Alloc.                 */ 
    const long interpol,             /* In: Interpolation flag          */
    const long num_lpc_indices,      /* In: Number of packed LPC        */
    const long lpc_indices[],        /* In: LP coefficients             */
    const long rms_index,            /* In: RMS index (NOT USED)        */
    const long shape_indices[],      /* In: Shape indices               */
    const long gain_indices[],       /* In: Gain indices                */
    const long num_shape_cbks,       /* In: Number of shape codebooks   */
    const long num_gain_cbks,        /* In: Number of gain codebooks    */
    const long n_sbfrms,             /* In: Number of subframes         */
    BITSTREAM  * const p_bitstream   /* Out: Bitstream                  */
    )
{
    /* -----------------------------------------------------------------*/
    /* Pack Header Info into bitstream  (interpolation flag)            */
    /* -----------------------------------------------------------------*/
    PHI_pack_header(p_bitstream, interpol, frame_bit_allocation[0]);
    
    /* -----------------------------------------------------------------*/
    /* Pack LPC parameters into bitstream                               */
    /* -----------------------------------------------------------------*/
    PHI_pack_LPC(p_bitstream, num_lpc_indices, lpc_indices, &(frame_bit_allocation[1]));

    /* -----------------------------------------------------------------*/
    /* Pack Excitation  parameters into bitstream                       */
    /* -----------------------------------------------------------------*/
    PHI_pack_excitation(p_bitstream, n_sbfrms, num_shape_cbks, num_gain_cbks, shape_indices, gain_indices,
                    &(frame_bit_allocation[num_lpc_indices+1]) );
}
    


/*======================================================================*/
/* Pack Header                                                          */
/*======================================================================*/
static void PHI_pack_header(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */ 
    const long code,            /* In: Interpolation Flag               */
    const long num_bits         /* In: Number of bits used for header   */
    )
{
    PutBit(bs, code, num_bits);
}

/*======================================================================*/
/* Pack lar codes                                                       */
/*======================================================================*/
static void PHI_pack_LPC(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */ 
    const long num_lpc_indices, /* In: Number of packed LPC             */
    const long lpc_codes[],     /* In: Packed LPC Codes                 */
    const long bit_allocation[] /* In: Number of bits for each LPC code */
    )
{
    long send_lpc_flag = lpc_codes[0];
    
    PutBit(bs, send_lpc_flag, bit_allocation[0]);
    
    if (send_lpc_flag)
    {
        long k;
        for (k = 1; k < num_lpc_indices; k++)
        {
            PutBit(bs, lpc_codes[k],  bit_allocation[k]); 
        }
    }
}


/*======================================================================*/
/* Pack Excitation Paramaters                                           */
/*======================================================================*/
static void PHI_pack_excitation(
    BITSTREAM * const bs,       /* In: Bitstream Pointer                */
    const long n_subframes,     /* In: Number of subframes              */
    const long num_shape_cbks,  /* In: Number of Shape Codebooks        */
    const long num_gain_cbks,   /* In: Number of Gain Codebooks         */
    const long shape_indices[], /* In: Adaptive Cbk lag and Fcbk index  */
    const long gain_indices[],  /* In: Adaptive and Fixed Codebook Gain */
    const long bit_allocation[] /* In: Number of bits for excitation    */
    )
{
    long k;
    
    /*==================================================================*/
    /* Make sure the number of shape and gain codebooks is correct      */
    /*==================================================================*/
    if (num_shape_cbks != 2)
    { 
        fprintf(stderr, "Wrong number of shape codebooks in Block: wdb_p2bs\n");
        exit(1);
    }    
    if (num_gain_cbks != 2)
    { 
        fprintf(stderr, "Wrong number of gain codebooks in Block: wdb_p2bs\n");
        exit(1);
    }    
    
    for(k = 0; k < n_subframes; k++)
    {
        long shape_index = k * num_shape_cbks;
        long gain_index  = k * num_gain_cbks;
        long bit_index   = k * (num_shape_cbks + num_gain_cbks);
        long acbk_lag    = shape_indices[shape_index]; 
        long fcbk_index  = shape_indices[shape_index + 1]; 
        long acbk_gain   = gain_indices[gain_index];
        long fcbk_gain   = gain_indices[gain_index + 1];

        PutBit(bs, acbk_lag,   bit_allocation[bit_index + 0]);
        PutBit(bs, fcbk_index, bit_allocation[bit_index + 1]);
        PutBit(bs, acbk_gain,  bit_allocation[bit_index + 2]);
        PutBit(bs, fcbk_gain,  bit_allocation[bit_index + 3]);
    }
}
    
/*======================================================================*/
/* Put length bits of c in bitstream bs                                 */
/*======================================================================*/
static void PutBit(
    BITSTREAM * const bs,
    const long c,
    const long length
)
{
    int j;
    
    if (bs != NULL)
    {
        if ((c >> length) != 0)
        {
            fprintf(stderr,"ERROR: cannot pack code %d in %d bits\n", 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 avaibable to encode frame\n");
                exit(1);
            }
            
            if (bit == 7)
            {
               (bs->p_bitstream_buffer_start)[index] = (unsigned char)0; 
            }
            
            if ((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                */
