#include "mpa_header.h"




const MPAHeader mpa_header;

union RAWHeader
{
  RAWHeader() {};
  RAWHeader(uint32_t i) { raw = i; }

  uint32_t raw;
  struct
  {
    unsigned emphasis           : 2;
    unsigned original           : 1;
    unsigned copyright          : 1;
    unsigned mode_ext           : 2;
    unsigned mode               : 2;

    unsigned extension          : 1;
    unsigned padding            : 1;
    unsigned sampling_frequency : 2;
    unsigned bitrate_index      : 4;

    unsigned error_protection   : 1;
    unsigned layer              : 2;
    unsigned version            : 1;
    unsigned sync               : 12;
  };
};

static const int bitrate_tbl[2][3][15] =
{
  { 
    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384 },
    { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320 }
  }, 
  { 
    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256 },
    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 }
  }
};

static const int freq_tbl[2][3] =
{
  { 44100, 48000, 32000 },  
  { 22050, 24000, 16000 }   
};

static const int slots_tbl[3] = { 12, 144, 144 };

bool
MPAHeader::parse_header(const uint8_t *hdr, HeaderInfo *hinfo) const
{
  RAWHeader h;
  int bs_type;

  
  
  

  
  if ((hdr[0] == 0xff)         && 
     ((hdr[1] & 0xf0) == 0xf0) && 
     ((hdr[1] & 0x06) != 0x00) && 
     ((hdr[2] & 0xf0) != 0xf0) && 
     ((hdr[2] & 0x0c) != 0x0c))   
  {
    uint32_t header = *(uint32_t *)hdr;
    h = swab_u32(header);
    bs_type = BITSTREAM_8;
  }
  else
  
  if ((hdr[1] == 0xff)         && 
     ((hdr[0] & 0xf0) == 0xf0) && 
     ((hdr[0] & 0x06) != 0x00) && 
     ((hdr[3] & 0xf0) != 0xf0) && 
     ((hdr[3] & 0x0c) != 0x0c))   
  {
    uint32_t header = *(uint32_t *)hdr;
    h = (header >> 16) | (header << 16);
    bs_type = BITSTREAM_16LE;
  }
  else
    return false;

  if (!hinfo)
    return true;

  
  int ver = 1 - h.version;
  int layer = 3 - h.layer;
  int bitrate = bitrate_tbl[ver][layer][h.bitrate_index] * 1000;
  int sample_rate = freq_tbl[ver][h.sampling_frequency];

  hinfo->spk = Speakers(FORMAT_MPA, (h.mode == 3)? MODE_MONO: MODE_STEREO, sample_rate);

  if (bitrate)
  {
    hinfo->frame_size = bitrate * slots_tbl[layer] / sample_rate + h.padding;
    hinfo->scan_size = 0; 
  }
  else
  {
    hinfo->frame_size = 0;
    hinfo->scan_size = 1728; 
  }

  if (layer == 0) 
    hinfo->frame_size *= 4;

  hinfo->nsamples = layer == 0? 384: 1152;
  hinfo->bs_type = bs_type;

  if (ver)
  {
    
    if (layer == 0)
      hinfo->spdif_type = 0x0008; 
    else
      hinfo->spdif_type = 0x0009; 
  }
  else
  {
    
    if (layer == 0)
      hinfo->spdif_type = 0x0004; 
    else
      hinfo->spdif_type = 0x0005; 
  }

  return true;
}

bool
MPAHeader::compare_headers(const uint8_t *hdr1, const uint8_t *hdr2) const
{
  
  
  
  
  
  static const int nch[4] = { 2, 2, 2, 1 };

  
  if ((hdr1[0] == 0xff)         && 
     ((hdr1[1] & 0xf0) == 0xf0) && 
     ((hdr1[1] & 0x06) != 0x00) && 
     ((hdr1[2] & 0xf0) != 0xf0) && 
     ((hdr1[2] & 0x0c) != 0x0c))   
  {
    return 
      hdr1[0] == hdr2[0] && 
      hdr1[1] == hdr2[1] &&
      (hdr1[2] & 0x0c) == (hdr2[2] & 0x0c) && 
      nch[hdr1[3] >> 6] == nch[hdr2[3] >> 6]; 
  }
  else
  
  if ((hdr1[1] == 0xff)         && 
     ((hdr1[0] & 0xf0) == 0xf0) && 
     ((hdr1[0] & 0x06) != 0x00) && 
     ((hdr1[3] & 0xf0) != 0xf0) && 
     ((hdr1[3] & 0x0c) != 0x0c))   
  {
    return
      hdr1[1] == hdr2[1] && 
      hdr1[0] == hdr2[0] &&
      (hdr1[3] & 0x0c) == (hdr2[3] & 0x0c) && 
      nch[hdr1[2] >> 6] == nch[hdr2[2] >> 6]; 
  }
  else
    return false;
}
