/* ------------------------------------------------------------------------- */
/*                                                                           */
/* Bitmux.c  : Handling of bistream format for AAC Raw and AAC SCALEABLE     */
/*                                                                           */
/* ------------------------------------------------------------------------- */

#include "bitmux.h"

int sort_book_numbers(int book_vector[],
                      int output_book_vector[],
		      int nr_of_sfb, int qdebug,
		      WINDOW_TYPE block_type,
		      BsBitStream *fixed_stream,
		      int write_flag
		      )
{

  /*
    This function inputs the vector, 'book_vector[]', which is of length SFB_NUM_MAX,
    and contains the optimal huffman tables of each sfb.  It returns the vector, 'output_book_vector[]', which
    has it's elements formatted for the encoded bit stream.  It's syntax is:
   
    {sect_cb[0], length_segment[0], ... ,sect_cb[num_of_sections], length_segment[num_of_sections]}

    The above syntax is true, unless there is an escape sequence.  An
    escape sequence occurs when a section is longer than 2 ^ (bit_len)
    long in units of scalefactor bands.  Also, the integer returned from
    this function is the number of bits written in the bitstream, 
    'bit_count'.  

    This function supports both long and short blocks.
  */

  int i;
  int repeat_counter = 1;
  int bit_count = 0;
  int previous;
  int max, bit_len;

  if (block_type == ONLY_SHORT_WINDOW){
    max = 7;
    bit_len = 3;
  }
  else {  /* the block_type is a long,start, or stop window */
    max = 31;
    bit_len = 5;
  }

  previous = book_vector[0];
  if (write_flag) {   
    BsPutBit(fixed_stream,book_vector[0],4);  
    if (qdebug > 1 )
      fprintf(stderr,"\nbookNrs:\n%d = ",book_vector[0]);
  }
  bit_count += 4;		/* bug fix TK */

  for (i=1;i<nr_of_sfb;i++) {
    if( (book_vector[i] != previous)) {
      if (write_flag) {
	BsPutBit(fixed_stream,repeat_counter,bit_len);  
	if (qdebug > 1 )
	  fprintf(stderr,"%d\n%d = ",i,book_vector[i]);
      }
      bit_count += bit_len;

      if (repeat_counter == max){  /* in case you need to terminate an escape sequence */
	if (write_flag) BsPutBit(fixed_stream,0,bit_len);  
	bit_count += bit_len;
      }
	
      if (write_flag) BsPutBit(fixed_stream,book_vector[i],4);
      bit_count += 4;		/* bug fix TK */
      previous = book_vector[i];
      repeat_counter=1;

    }
    /* if the length of the section is longer than the amount of bits available in */
    /* the bitsream, "max", then start up an escape sequence */
    else if ((book_vector[i] == previous) && (repeat_counter == max)) { 
      if (write_flag) {
	BsPutBit(fixed_stream,repeat_counter,bit_len);  
	if (qdebug > 1 )
	  fprintf(stderr,"(esc)");	
      }
      bit_count += bit_len;
      repeat_counter = 1;
    }
    else {
      repeat_counter++;
    }
  }

  if (write_flag) {
    BsPutBit(fixed_stream,repeat_counter,bit_len);  
    if (qdebug > 1 )
      fprintf(stderr,"%d\n",i);  
  }
  bit_count += bit_len;
  if (repeat_counter == max) {  /* special case if the last section length is an */
    /* escape sequence */
    if (write_flag) BsPutBit(fixed_stream,0,bit_len);  
    bit_count += bit_len;
  }
  return(bit_count);
}

int find_grouping_bits(int window_group_length[],
		     int num_window_groups)
{

  /* This function inputs the grouping information and outputs the seven bit 
     'grouping_bits' field that the NBC decoder expects.  */


  int grouping_bits = 0;
  int tmp[8];
  int i,j;
  int index=0;

  for(i=0; i<num_window_groups; i++){
    for (j=0; j<window_group_length[i];j++){
      tmp[index++] = i;
      /*      printf("tmp[%d] = %d\n",index-1,tmp[index-1]);*/
    }
  }

  for(i=1; i<8; i++){
    grouping_bits = grouping_bits << 1;
    if(tmp[i] == tmp[i-1]) {
      grouping_bits++;
    }
  }
  
  /*  printf("grouping_bits = %d  [i=%d]\n",grouping_bits,i);*/
  return(grouping_bits);
}

int write_scalefactor_bitstream(int nr_of_sfb,
                              int scale_factors[],
                              int book_vector[],
                              BsBitStream *fixed_stream,
                              int write_flag,
                              int window_group_length[],
                              int num_window_groups,
                              int global_gain,
                              WINDOW_TYPE block_type,
                              int noise_nrg[],
                              int qdebug, int huff[13][1090][4])
{

  /* this function takes care of counting the number of bits necessary */
  /* to encode the scalefactors.  In addition, if the write_flag == 1, */
  /* then the scalefactors are written out the fixed_stream output bit */
  /* stream.  it returns k, the number of bits written to the bitstream*/

  int i,j,k=0;
  int diff,length,codeword;
  int previous_scale_factor;
  int index = 0;
  int sf_out = 0;
  int sf_not_out = 0;
  int nr_of_sfb_per_group=0;
  int pns_pcm_flag = 1;
  int previous_noise_nrg = global_gain;

  if (block_type == ONLY_SHORT_WINDOW) { /* short windows */
    nr_of_sfb_per_group = nr_of_sfb/num_window_groups;
  }
  else {
    nr_of_sfb_per_group = nr_of_sfb;
    num_window_groups = 1;
    window_group_length[0] = 1;
  }

  previous_scale_factor = scale_factors[0];
  previous_scale_factor = global_gain;
  if ( (qdebug > 2) && write_flag ) {
    fprintf(stderr,"\nscalefacs :");	
  }
    
  for(j=0; j<num_window_groups; j++){
    for(i=0;i<nr_of_sfb_per_group;i++) {  
      /* test to see if any codebooks in a group are zero */
      if ( (qdebug > 1) && write_flag ) {
	fprintf(stderr," %d:%d",index,scale_factors[index]);	
      }
      if (book_vector[index] == PNS_HCB) {
        /* send PNS pseudo scalefactors  */
        diff = noise_nrg[index] - previous_noise_nrg;
        if (pns_pcm_flag) {
          pns_pcm_flag = 0;
          if (diff+PNS_PCM_OFFSET<0  ||  diff+PNS_PCM_OFFSET>=(1<<PNS_PCM_BITS))
            fprintf(stderr,"%3d (PNS PCM Overflow0) *****\n", diff);
          length = PNS_PCM_BITS;
          codeword = diff + PNS_PCM_OFFSET;
        } else {
          if (diff<-60  ||  diff>60)
            printf("%3d (PNS Overflow0) *****\n", diff);
          length = huff[12][diff+60][2];    
	  codeword = huff[12][diff+60][3];
        }
	k += length;
        previous_noise_nrg = noise_nrg[index];
	if (write_flag == 1 ) {   
	  /*	  printf("  scale_factor[%d] = %d\n",index,scale_factors[index]);*/
	  BsPutBit(fixed_stream,codeword,length); 
	  sf_out++;
	}
      } else

      if (book_vector[index]) {
        /* only send scalefactors if using non-zero codebooks ,*/
	diff = scale_factors[index] - previous_scale_factor;
	length = huff[12][diff+60][2];    
	k+=length;
	previous_scale_factor = scale_factors[index];
	if (write_flag == 1 ) {   
	  /*	  printf("  scale_factor[%d] = %d\n",index,scale_factors[index]);*/
	  codeword = huff[12][diff+60][3];
	  BsPutBit(fixed_stream,codeword,length); 
	  sf_out++;
	}
      }
      else {
	/*	if (write_flag) printf("  zero_flag = 1, [j=%d index=%d i=%d]\n",j,index,i);*/
	sf_not_out++;
      }
      index++;
    }
  }
  /*  if (write_flag) printf("sf_out = %d  sf_not_out = %d\n",sf_out,sf_not_out);*/
  return(k);
}

int write_ics_info (int nr_of_sfb, WINDOW_TYPE block_type, BsBitStream *fixed_stream, 
                    int window_shape, int num_window_groups, int window_group_length[])
{

  int bit_count = 0;
  int grouping_bits;
  int max_sfb;

  /* reserved Bit*/
  BsPutBit(fixed_stream, 0, 1); 
  bit_count +=1;

  /* write out WINDOW_SEQUENCE */
  switch (block_type) 
    {
    case ONLY_SHORT_WINDOW:
      BsPutBit(fixed_stream,2,2);  /* short window */
      bit_count += 2;
      break;
    case ONLY_LONG_WINDOW:
      BsPutBit(fixed_stream,0,2);  
      bit_count += 2;
      break;
    case   LONG_SHORT_WINDOW:
      BsPutBit(fixed_stream,1,2);  
      bit_count += 2;
      break;
    case  SHORT_LONG_WINDOW:
      BsPutBit(fixed_stream,3,2);  
      bit_count += 2;
      break;
      
    default:
      CommonExit(-1,"\n unknown blocktype : %d",block_type);
    }

  /* write out WINDOW SHAPE */
  if (window_shape != 0)
    CommonExit(-1,"\nunknow windowshape");

  BsPutBit(fixed_stream, window_shape, 1);  /* window shape */
  bit_count += 1;

  /* write out SCALE_FACTOR_GROUPING and MAX_SFB */
  max_sfb =   nr_of_sfb/num_window_groups;
  if (max_sfb*num_window_groups != nr_of_sfb)
    CommonExit(-1,"\nwrong num of nr_of_sfb");

  if (block_type == ONLY_SHORT_WINDOW){
    BsPutBit(fixed_stream, max_sfb, 4); /* let max_sfb_l = 14, the max number of sfb's */
    bit_count += 4;

    grouping_bits = find_grouping_bits(window_group_length, num_window_groups);
    BsPutBit(fixed_stream, grouping_bits, 7);  /* the grouping bits */
    bit_count += 7;

  } else {    /* block type is either start, stop, or long */
    BsPutBit(fixed_stream, max_sfb, 6); /* let max_sfb_l = 49, the max number of sfb's */

    /* no prediction supported ! */
    BsPutBit(fixed_stream, 0, 1);  /* no prediction_data_present */
    bit_count += 7;
  }
}


static int write_spectral_data(int counter, int len[], int data[], 
                               BsBitStream *fixed_stream)
{
  int bit_count = 0;
  int i;

  for(i=0; i<counter; i++) {
    if (len[i] > 0) {  /* only send out non-zero codebook data */
      BsPutBit(fixed_stream,data[i],len[i]);
      bit_count += len[i];
    }
  }
  return (bit_count);
}

/* write single channel element header */
int write_aac_sce(BsBitStream *fixed_stream)
{
  int bit_count = 0;

  /* write ID_SCE, single_element_channel() identifier */
  BsPutBit(fixed_stream,0,3);  
  bit_count += 3;

  /* write the element_identifier_tag */
  BsPutBit(fixed_stream,0,4);  
  bit_count += 4;

  return (bit_count);
}

int write_aac_cpe(int nr_of_sfb, WINDOW_TYPE block_type, BsBitStream *fixed_stream, int num_window_groups,
                  int window_group_length[], int window_shape, int common_window, int ms_mask, int ms_used[10][10])
{
  int bit_count = 0;
  int i,j;

  /* write ID_CPE, channel_pair_element identifier */
  BsPutBit(fixed_stream,1,3);  
  bit_count += 3;

  /* write the element_instance_tag */
  BsPutBit(fixed_stream,0,4);
  bit_count += 4;

  /* write the common_window flag */
  BsPutBit(fixed_stream, common_window, 1);
  bit_count += 1;

  if (common_window) {
    bit_count += write_ics_info(nr_of_sfb, block_type, fixed_stream, window_shape,
                                num_window_groups, window_group_length);

    /* write the ms_mask_present flags */
    BsPutBit(fixed_stream,ms_mask,2);
    bit_count += 2;
    
    if (ms_mask == 1) {
      for (i=0; i<num_window_groups; i++) {
        for (j=0; j<nr_of_sfb; j++) {
          BsPutBit(fixed_stream, ms_used[i][j],1);
          bit_count += 1;
        }
      }
    }
  }
  return (bit_count);
}


int write_ind_cha_stream(int nr_of_sfb, WINDOW_TYPE block_type, int scale_factors[], BsBitStream *fixed_stream,
                         BsBitBuffer *gcBitBufCh, int book_vector[], int data[], int len[], int qdebug, int scale_flag,
                         int huff[13][1090][4], int counter, int num_window_groups, int window_group_length[],
                         int global_gain, int window_shape, int noise_nrg[],  PRED_TYPE predictor_type,
                         NOK_LT_PRED_STATUS *nok_lt_status, NOK_BW_PRED_STATUS *nok_bwp_status, int common_window)
{
  int output_book_vector[SFB_NUM_MAX*2];
  int i;
  int grouping_bits;
  int max_sfb;
  int bit_count = 0;

  /* the 8-bit global_gain is the first scalefactor */
  /*  BsPutBit(fixed_stream,scale_factors[0],8);  */
  BsPutBit(fixed_stream,global_gain,8);  
  bit_count += 8;
  if ( (qdebug > 2)  ) {
    fprintf(stderr,"\nglobal_gain %d ",global_gain);
  }

  if ((!common_window) && (!scale_flag)) {
    /* write out ICS Info block */  
    bit_count += write_ics_info(nr_of_sfb, block_type, fixed_stream, window_shape, num_window_groups, window_group_length);
  }

  /* write out section_data() information to the bitstream */
  bit_count += sort_book_numbers(book_vector, output_book_vector, nr_of_sfb, qdebug, block_type, fixed_stream, 1);

  /* scale_factor_data() information */
  bit_count += write_scalefactor_bitstream(nr_of_sfb, scale_factors, book_vector, fixed_stream, 1,
                                             window_group_length, num_window_groups, global_gain,
                                             block_type, noise_nrg, qdebug, huff);

  
  /* no pulse_data_present() */
  BsPutBit(fixed_stream,0,1);
  bit_count += 1;
  
  if (!scale_flag) {
    /* deal with turning off the TNS data */
    BsPutBit(fixed_stream,0,1); /* switches on TNS for long blocks */
    bit_count += 1;             /* changed by alm 97/11/12 (no TNS present !) */

    /* write gain_control_data()  TK */
    if (gcBitBufCh && (gcBitBufCh->numBit > 0)) {		/* gain_control_data() present */
      BsPutBit(fixed_stream,1,1);		/* switches on the gain control */
      bit_count += 1;
      BsPutBuffer(fixed_stream, gcBitBufCh); /* gain_control_data() */
      bit_count += gcBitBufCh->numBit;
    }
    else {
      BsPutBit(fixed_stream,0,1);		/* switches off the gain control */
      bit_count += 1;
    }
  }

  /* write out the spectral_data() */
  bit_count += write_spectral_data(counter, len, data, fixed_stream);

  return(bit_count);
}

int write_aac_end_id(BsBitStream *fixed_stream)
{
  BsPutBit(fixed_stream,7,3);

  return (3);
}


