/*
   File: header.cc

*/

#ifdef __GNUG__
#pragma implementation
#endif

#include <stdio.h>
#include <stdlib.h>
#include <fstream.h>
#include <iomanip.h>

#include "athread.hh"

#include "error.hh"
#include "debug.hh"
#include "util.hh"

#include "sync.hh"
#include "mpeg2const.hh"
#include "mpeg2buff.hh"

#include "astream.hh"
#include "crc.hh"
#include "header.hh"


const uint32 Header::frequencies[3] = { 44100, 48000, 32000 };


int Header::read_header(AudioStream *stream, Crc16 **crcp){
  TRACER("bool Header::read_header(AudioStream *stream, Crc16 **crcp)");
  uint32 headerstring=0;

  if (stream->get_header(headerstring)==False){
    cerr << "invalid syncword 0x" << hex << setw (3) << setfill ('0')
         << ((headerstring & 0xfff00000) >> 20)
         << " found at fileoffset " << dec << '\n';
    TRACER("could not get_header");
    return 0;
  }

  if ((headerstring & 0xf0000000) == 0x80000000)
    return 2;    /* Ac-3 audio */

#ifdef NOT // moved to get_header to recover from errors  
  if ((headerstring & 0xfff00000) != 0xfff00000){
    cerr << "invalid syncword 0x" << hex << setw (3) << setfill ('0')
         << ((headerstring & 0xfff00000) >> 20)
         << " found at fileoffset " << dec << '\n';    

    // Try to recover from errors
    while ((headerstring & 0xFFF00000) != 0xFFF00000)
      if (!stream->get_header(headerstring)) return False;
  }
#endif

  if ((h_layer = (headerstring >> 17) & 3) == 0){
    cerr << "unknown layer identifier found!\n";
    exit (1);
  }
  h_layer = 4 - h_layer;		// now 1 means Layer I and 3 means Layer III
  if (h_layer == 3){
    cerr << "Sorry, Layer III not implemented!\n";
    exit (1);
  }
  h_protection_bit = (headerstring >> 16) & 1;
  if ((h_bitrate_index = (headerstring >> 12) & 0xF) == 15){
    cerr << "unknown bitrate index found!\n";
    exit (1);
  }
  if (!h_bitrate_index){
    cerr << "free format not yet implemented!\n";
    exit (1);
  }

  if ((h_sample_frequency = (e_sample_frequency)((headerstring >> 10) & 3)) == 3){
    cerr << "unknown sample frequency!\n";
    exit (1);
  }
  h_padding_bit = (headerstring >> 9) & 1;
  h_mode = (e_mode)((headerstring >> 6) & 3);
  if (h_layer == 2)
    // testing validity of mode and bitrate:
    if ((((h_bitrate_index >= 1 && h_bitrate_index <= 3) || h_bitrate_index == 5) &&
	 h_mode != single_channel) ||
	(h_bitrate_index >= 11 && h_mode == single_channel))
    {
      cerr << "illegal combination of mode and bitrate in a layer II stream:\n"
	      "  mode: " << mode_string ()
	   << "\n  bitrate: " << bitrate_string () << '\n';
      exit (1);
    }
  h_mode_extension = (headerstring >> 4) & 3;
  if (h_mode == joint_stereo)
        h_intensity_stereo_bound = (h_mode_extension << 2) + 4;
  else  h_intensity_stereo_bound = 0;		// should never be used
  h_copyright = ((headerstring >> 3) & 1) ? True : False;
  h_original = ((headerstring >> 2) & 1) ? True : False;

  // calculate number of subbands:
  if (h_layer == 1) h_number_of_subbands = 32;
  else {
    uint32 channel_bitrate = h_bitrate_index;

    // calculate bitrate per channel:
    if (h_mode != single_channel)
      if (channel_bitrate == 4)
	channel_bitrate = 1;
      else
	channel_bitrate -= 4;

    if (channel_bitrate == 1 || channel_bitrate == 2)
      if (h_sample_frequency == thirtytwo)
	h_number_of_subbands = 12;
      else
	h_number_of_subbands = 8;
    else
      if (h_sample_frequency == fourtyeight || (channel_bitrate >= 3 && channel_bitrate <= 5))
	h_number_of_subbands = 27;
      else
	h_number_of_subbands = 30;
  }

  if (h_intensity_stereo_bound > h_number_of_subbands)
    h_intensity_stereo_bound = h_number_of_subbands;

  // read framedata:
  if (!stream->read_frame (calculate_framesize ())) return False;

  if (!h_protection_bit){
    // frame contains a crc checksum
    checksum = (uint16)stream->get_bits (16);
    if (!crc) crc = new Crc16;
    crc->add_bits (headerstring, 16);
    *crcp = crc;
  }
  else *crcp = (Crc16 *)0;

  return 1;
}


uint32 Header::calculate_framesize(){
/* calculates framesize in bytes excluding header size */
  static const uint32 bitrates_layer_1[15] = {
    0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000,
    224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000 };
  static const uint32 bitrates_layer_2[15] = {
    0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,
    112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000 };
  static const uint32 samplefrequencies[3] = { 44100, 48000, 32000 };
  uint32 framesize;

  if (h_layer == 1)
  {
    framesize = (12 * bitrates_layer_1[h_bitrate_index]) / samplefrequencies[h_sample_frequency];
    if (h_sample_frequency == fourtyfour_point_one && h_padding_bit)
      ++framesize;
    framesize <<= 2;		// one slot is 4 bytes long
  }
  else
  {
    framesize = (144 * bitrates_layer_2[h_bitrate_index]) / samplefrequencies[h_sample_frequency];
    if (h_sample_frequency == fourtyfour_point_one && h_padding_bit)
      ++framesize;
  }

  return framesize - 4;		// subtract header size
}


const char *Header::layer_string (void){
  switch (h_layer){
  case 1: return "I";
  case 2: return "II";
  case 3: return "III (not implemented!)";
  }
  return NULL;			// dummy
}


const char *Header::bitrate_string (void){
  static const char *layer1_bitrates[16] = {
    "free format", "32 kbis/s", "64 kbit/s", "96 kbit/s", "128 kbit/s", "160 kbit/s", 
    "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s", "320 kbit/s", "352 kbit/s",
    "384 kbit/s", "416 kbit/s", "448 kbit/s", "forbidden"
  };
  static const char *layer2_bitrates[16] = {
    "free format", "32 kbis/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", 
    "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s", "224 kbit/s",
    "256 kbit/s", "320 kbit/s", "384 kbit/s", "forbidden"
  };

  if (h_layer == 1)
    return layer1_bitrates[h_bitrate_index];
  else
    return layer2_bitrates[h_bitrate_index];
}


const char *Header::sample_frequency_string (void)
{
  switch (h_sample_frequency)
  {
    case thirtytwo:
      return "32 kHz";
    case fourtyfour_point_one:
      return "44.1 kHz";
    case fourtyeight:
      return "48 kHz";
  }
  return NULL;			// dummy
}


const char *Header::mode_string (void)
{
  switch (h_mode)
  {
    case stereo:
      return "stereo";
    case joint_stereo:
      return "joint stereo";
    case dual_channel:
      return "dual channel";
    case single_channel:
      return "single channel";
  }
  return NULL;			// dummy
}
