/*
 * Siren Encoder/Decoder library
 *
 *   @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include "siren7.h"

SirenDecoder Siren7_NewDecoder(int sample_rate) {
  SirenDecoder decoder = (SirenDecoder) malloc(sizeof(struct stSirenDecoder));
  decoder->sample_rate = sample_rate;

  decoder->WavHeader.riff.RiffId = ME_TO_LE32(RIFF_ID);
  decoder->WavHeader.riff.RiffSize = sizeof(PCMWavHeader) - 2*sizeof(int);
  decoder->WavHeader.riff.RiffSize = ME_TO_LE32(decoder->WavHeader.riff.RiffSize);
  decoder->WavHeader.WaveId = ME_TO_LE32(WAVE_ID);

  decoder->WavHeader.FmtId = ME_TO_LE32(FMT__ID);
  decoder->WavHeader.FmtSize = ME_TO_LE32(sizeof(FmtChunk));

  decoder->WavHeader.fmt.Format = ME_TO_LE16(0x01);
  decoder->WavHeader.fmt.Channels = ME_TO_LE16(1);
  decoder->WavHeader.fmt.SampleRate = ME_TO_LE32(16000);
  decoder->WavHeader.fmt.ByteRate = ME_TO_LE32(32000);
  decoder->WavHeader.fmt.BlockAlign = ME_TO_LE16(2);
  decoder->WavHeader.fmt.BitsPerSample = ME_TO_LE16(16);

  decoder->WavHeader.FactId = ME_TO_LE32(FACT_ID);
  decoder->WavHeader.FactSize = ME_TO_LE32(sizeof(int));
  decoder->WavHeader.Samples = ME_TO_LE32(0);

  decoder->WavHeader.DataId = ME_TO_LE32(DATA_ID);
  decoder->WavHeader.DataSize = ME_TO_LE32(0);

  memset(decoder->context, 0, sizeof(decoder->context));
  memset(decoder->backup_frame, 0, sizeof(decoder->backup_frame));

  decoder->dw1 = 1;
  decoder->dw2 = 1;
  decoder->dw3 = 1;
  decoder->dw4 = 1;

  siren_init();
  return decoder;
}

void Siren7_CloseDecoder(SirenDecoder decoder) {
  free(decoder);
}

int Siren7_DecodeFrame(SirenDecoder decoder, unsigned char *DataIn, unsigned char *DataOut) {
  int number_of_coefs,
      sample_rate_bits,
      rate_control_bits,
      rate_control_possibilities,
      checksum_bits,
      esf_adjustment,
      scale_factor,
      number_of_regions,
      sample_rate_code,
      bits_per_frame;
  int decoded_sample_rate_code;

  static int absolute_region_power_index[28] = {0};
  static float decoder_standard_deviation[28] = {0};
  static int power_categories[28] = {0};
  static int category_balance[28] = {0};
  int ChecksumTable[4] = {0x7F80, 0x7878, 0x6666, 0x5555};
  int i, j;

  int dwRes = 0;
  int envelope_bits = 0;
  int rate_control = 0;
  int number_of_available_bits;
  int number_of_valid_coefs;
  int frame_error = 0;

  int In[20];
  float coefs[320];
  float BufferOut[320];
  int sum;
  int checksum;
  int calculated_checksum;
  int idx;
  int temp1;
  int temp2;

  for (i = 0; i < 20; i++)
#ifdef __BIG_ENDIAN__
    In[i] = ((short *) DataIn)[i];
#else
  In[i] = ((((short *) DataIn)[i] << 8) & 0xFF00) | ((((short *) DataIn)[i] >> 8) & 0x00FF);
#endif

  dwRes = GetSirenCodecInfo(1, decoder->sample_rate, &number_of_coefs, &sample_rate_bits, &rate_control_bits, &rate_control_possibilities, &checksum_bits, &esf_adjustment, &scale_factor,  &number_of_regions, &sample_rate_code, &bits_per_frame );

  if (dwRes != 0)
    return dwRes;


  set_bitstream(In);

  decoded_sample_rate_code = 0;
  for (i = 0; i < sample_rate_bits; i++) {
    decoded_sample_rate_code <<= 1;
    decoded_sample_rate_code |= next_bit();
  }


  if (decoded_sample_rate_code != sample_rate_code)
    return 7;

  number_of_valid_coefs = region_size * number_of_regions;
  number_of_available_bits = bits_per_frame - sample_rate_bits  - checksum_bits ;


  envelope_bits = decode_envelope(number_of_regions, decoder_standard_deviation, absolute_region_power_index, esf_adjustment);

  number_of_available_bits -= envelope_bits;

  for (i = 0; i < rate_control_bits; i++) {
    rate_control <<= 1;
    rate_control |= next_bit();
  }

  number_of_available_bits -= rate_control_bits;

  categorize_regions(number_of_regions, number_of_available_bits, absolute_region_power_index, power_categories, category_balance);

  for (i = 0; i < rate_control; i++) {
    power_categories[category_balance[i]]++;
  }

  number_of_available_bits = decode_vector(decoder, number_of_regions, number_of_available_bits, decoder_standard_deviation, power_categories, coefs, scale_factor);


  frame_error = 0;
  if (number_of_available_bits > 0) {
    for (i = 0; i < number_of_available_bits; i++) {
      if (next_bit() == 0)
        frame_error = 1;
    }
  } else if (number_of_available_bits < 0 && rate_control + 1 < rate_control_possibilities) {
    frame_error |= 2;
  }

  for (i = 0; i < number_of_regions; i++) {
    if (absolute_region_power_index[i] > 33 || absolute_region_power_index[i] < -31)
      frame_error |= 4;
  }

  if (checksum_bits > 0) {
    bits_per_frame >>= 4;
    checksum = In[bits_per_frame - 1] & ((1 << checksum_bits)  - 1);
    In[bits_per_frame - 1] &= ~checksum;
    sum = 0;
    idx = 0;
    do {
      sum ^= (In[idx] & 0xFFFF) << (idx % 15);
    } while (++idx < bits_per_frame);

    sum = (sum >> 15) ^ (sum & 0x7FFF);
    calculated_checksum = 0;
    for (i = 0; i < 4; i++) {
      temp1 = ChecksumTable[i] & sum;
      for (j = 8; j > 0; j >>= 1) {
        temp2 = temp1 >> j;
        temp1 ^= temp2;
      }
      calculated_checksum <<= 1;
      calculated_checksum |= temp1 & 1;
    }

    if (checksum != calculated_checksum)
      frame_error |= 8;
  }

  if (frame_error  != 0) {
    for (i = 0; i < number_of_valid_coefs; i++) {
      coefs[i] = decoder->backup_frame[i];
      decoder->backup_frame[i] = 0;
    }
  } else {
    for (i = 0; i < number_of_valid_coefs; i++)
      decoder->backup_frame[i] = coefs[i];
  }


  for (i = number_of_valid_coefs; i < number_of_coefs; i++)
    coefs[i] = 0;


  dwRes = siren_rmlt_decode_samples(coefs, decoder->context, 320, BufferOut);


  for (i = 0; i < 320; i++) {
    if (BufferOut[i] > 32767.0)
      ((short *)DataOut)[i] =  (short) ME_TO_LE16((short) 32767);
    else if (BufferOut[i] <= -32768.0)
      ((short *)DataOut)[i] =  (short) ME_TO_LE16((short) 32768);
    else
      ((short *)DataOut)[i] = (short) ME_TO_LE16((short) BufferOut[i]);
  }

  decoder->WavHeader.Samples = ME_FROM_LE32(decoder->WavHeader.Samples);
  decoder->WavHeader.Samples += 320;
  decoder->WavHeader.Samples = ME_TO_LE32(decoder->WavHeader.Samples);
  decoder->WavHeader.DataSize = ME_FROM_LE32(decoder->WavHeader.DataSize);
  decoder->WavHeader.DataSize += 640;
  decoder->WavHeader.DataSize = ME_TO_LE32(decoder->WavHeader.DataSize);
  decoder->WavHeader.riff.RiffSize = ME_FROM_LE32(decoder->WavHeader.riff.RiffSize);
  decoder->WavHeader.riff.RiffSize += 640;
  decoder->WavHeader.riff.RiffSize = ME_TO_LE32(decoder->WavHeader.riff.RiffSize);


  return 0;
}

