/******************************************************************************

    wavfilt --- SSKFバンクによる8帯域分割と非線形量子化

      version 3.50                           by とご(電脳わ〜るど:DW0243)

    02/19/1995                                           "mono_16.h"

    16ビットモノラルのファイルを処理するためのルーチンを定義します。ステレオ
  ファイルの処理と同様にコードがひどく冗長ですが我慢してください(笑)(^^;)。

 *****************************************************************************/

#include "common.h"
#include "table.h"
#include "buffer.h"
#include "yomikaki.h"
#include "filter.h"
#include "misc.h"

void suppression_m(void)
{
// -24dBの音量差がある時に小さいほうを抑制する
// ↑は16分の1に相当する(間違ってたら最悪(^^;)
// 大抵の場合は最低音帯域に対する他帯域の音量の比較となる
  int i,tmp;
  for(i = 0; i < M; ++i){
    /* 左側 */
    tmp = INT_MIN;
    /* 最大値を探す */
    if(_abs(l_low3_1[i]) > tmp)tmp = _abs(l_low3_1[i]);
    if(_abs(l_low3_2[i]) > tmp)tmp = _abs(l_low3_2[i]);
    if(_abs(l_low3_3[i]) > tmp)tmp = _abs(l_low3_3[i]);
    if(_abs(l_low3_4[i]) > tmp)tmp = _abs(l_low3_4[i]);
    if(_abs(l_high3_1[i]) > tmp)tmp = _abs(l_high3_1[i]);
    if(_abs(l_high3_2[i]) > tmp)tmp = _abs(l_high3_2[i]);
    if(_abs(l_high3_3[i]) > tmp)tmp = _abs(l_high3_3[i]);
    if(_abs(l_high3_4[i]) > tmp)tmp = _abs(l_high3_4[i]);
    /* 最大値の2^n分の1と他の値を比較し、他の値が小さい場合0に抑制する */
    tmp = tmp >> sup_value;
    if(tmp > _abs(l_low3_1[i]))l_low3_1[i] = 0;
    if(tmp > _abs(l_low3_2[i]))l_low3_2[i] = 0;
    if(tmp > _abs(l_low3_3[i]))l_low3_3[i] = 0;
    if(tmp > _abs(l_low3_1[i]))l_low3_4[i] = 0;
    if(tmp > _abs(l_high3_1[i]))l_high3_1[i] = 0;
    if(tmp > _abs(l_high3_2[i]))l_high3_2[i] = 0;
    if(tmp > _abs(l_high3_3[i]))l_high3_3[i] = 0;
    if(tmp > _abs(l_high3_4[i]))l_high3_4[i] = 0;
  }
}

void CellSet_mono_16(void)
{
  buffer = (short *)__calloc(1,sizeof(short)*(CellSize+FilterSize-1));
  l_lowhigh0 = (int *)__calloc(1,sizeof(int)*(CellSize+FilterSize-1));
  l_low1  = (int *)__calloc(1,sizeof(int)*(CellSize/2+FilterSize-1));
  l_high1  = (int *)__calloc(1,sizeof(int)*(CellSize/2+FilterSize-1));
  l_low2_1  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  l_low2_2  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  l_high2_1  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  l_high2_2  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  l_low3_1  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_low3_2  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_low3_3  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_low3_4  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_high3_1  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_high3_2  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_high3_3  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  l_high3_4  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
}


void encode_mono_16(unsigned long size)
{
  unsigned long i,j;
  unsigned long m = size / CellSize;
  unsigned long n = size % CellSize;

  CellSet_mono_16();

  for(i = 0; i < m; ++i){
    fread((void *)&buffer[0],CellSize*2,1,infile);
    for(j = 0; j < CellSize; j++){
      l_lowhigh0[j + FilterSize-1] = (signed int)buffer[j];
    }
      filtering(l_lowhigh0,l_low1+(FilterSize - 1),
                       l_high1+(FilterSize - 1),CellSize/2);
      filtering(l_high1,l_high2_1+(FilterSize - 1),
                      l_high2_2+(FilterSize - 1),CellSize/4);
      filtering(l_low1,l_low2_1+(FilterSize - 1),
                     l_low2_2+(FilterSize - 1),CellSize/4);
      filtering(l_high2_1,l_high3_1,l_high3_2,CellSize/8);
      filtering(l_high2_2,l_high3_3,l_high3_4,CellSize/8);
      filtering(l_low2_1,l_low3_1,l_low3_2,CellSize/8);
      filtering(l_low2_2,l_low3_3,l_low3_4,CellSize/8);

    suppression_m();

    cswrite_16(l_low3_1,first_band_encode);
    cswrite_16(l_low3_2,second_band_encode);
    cswrite_16(l_low3_3,third_band_encode);
    cswrite_16(l_low3_4,fourth_band_encode);
    cswrite_16(l_high3_1,fifth_band_encode);
    cswrite_16(l_high3_2,sixth_band_encode);
    cswrite_16(l_high3_3,seventh_band_encode);
    cswrite_16(l_high3_4,eighth_band_encode);
  }

  memset((void *)&l_lowhigh0[FilterSize-1],0,CellSize*2);

  fread((void *)&buffer[0],n*2,1,infile);
  for(j = 0; j < CellSize; j++){
    l_lowhigh0[j + FilterSize-1] = (signed int)buffer[j];
  }
    filtering(l_lowhigh0,l_low1+(FilterSize - 1),
                     l_high1+(FilterSize - 1),CellSize/2);
    filtering(l_high1,l_high2_1+(FilterSize - 1),
                    l_high2_2+(FilterSize - 1),CellSize/4);
    filtering(l_low1,l_low2_1+(FilterSize - 1),
                   l_low2_2+(FilterSize - 1),CellSize/4);
    filtering(l_high2_1,l_high3_1,l_high3_2,CellSize/8);
    filtering(l_high2_2,l_high3_3,l_high3_4,CellSize/8);
    filtering(l_low2_1,l_low3_1,l_low3_2,CellSize/8);
    filtering(l_low2_2,l_low3_3,l_low3_4,CellSize/8);

  suppression_m();

  cswrite_16(l_low3_1,first_band_encode);
  cswrite_16(l_low3_2,second_band_encode);
  cswrite_16(l_low3_3,third_band_encode);
  cswrite_16(l_low3_4,fourth_band_encode);
  cswrite_16(l_high3_1,fifth_band_encode);
  cswrite_16(l_high3_2,sixth_band_encode);
  cswrite_16(l_high3_3,seventh_band_encode);
  cswrite_16(l_high3_4,eighth_band_encode);
}

void decode_mono_16(unsigned long size)
{
  unsigned long i,j;

  unsigned long m = size / CellSize;
  unsigned long n = size % CellSize;

  CellSet_mono_16();

  for(i = 0; i < m; ++i){
    csread_16(l_low3_1,first_band_decode);
    csread_16(l_low3_2,second_band_decode);
    csread_16(l_low3_3,third_band_decode);
    csread_16(l_low3_4,fourth_band_decode);
    csread_16(l_high3_1,fifth_band_decode);
    csread_16(l_high3_2,sixth_band_decode);
    csread_16(l_high3_3,seventh_band_decode);
    csread_16(l_high3_4,eighth_band_decode);
      untifilt(l_low3_1,l_low3_2,l_low2_1+(FilterSize/2-1),CellSize/4);
      untifilt(l_low3_3,l_low3_4,l_low2_2+(FilterSize/2-1),CellSize/4);
      untifilt(l_high3_1,l_high3_2,l_high2_1+(FilterSize/2-1),CellSize/4);
      untifilt(l_high3_3,l_high3_4,l_high2_2+(FilterSize/2-1),CellSize/4);
      untifilt(l_low2_1,l_low2_2,l_low1+(FilterSize/2-1),CellSize/2);
      untifilt(l_high2_1,l_high2_2,l_high1+(FilterSize/2-1),CellSize/2);
      untifilt(l_low1,l_high1,l_lowhigh0,CellSize);
    for(j = 0; j < CellSize; j++){
      buffer[j] = limitter(l_lowhigh0[j]);
    }
    fwrite((void *)&buffer[0],CellSize*2,1,outfile);
  }
  csread_16(l_low3_1,first_band_decode);
  csread_16(l_low3_2,second_band_decode);
  csread_16(l_low3_3,third_band_decode);
  csread_16(l_low3_4,fourth_band_decode);
  csread_16(l_high3_1,fifth_band_decode);
  csread_16(l_high3_2,sixth_band_decode);
  csread_16(l_high3_3,seventh_band_decode);
  csread_16(l_high3_4,eighth_band_decode);
    untifilt(l_low3_1,l_low3_2,l_low2_1+(FilterSize/2-1),CellSize/4);
    untifilt(l_low3_3,l_low3_4,l_low2_2+(FilterSize/2-1),CellSize/4);
    untifilt(l_high3_1,l_high3_2,l_high2_1+(FilterSize/2-1),CellSize/4);
    untifilt(l_high3_3,l_high3_4,l_high2_2+(FilterSize/2-1),CellSize/4);
    untifilt(l_low2_1,l_low2_2,l_low1+(FilterSize/2-1),CellSize/2);
    untifilt(l_high2_1,l_high2_2,l_high1+(FilterSize/2-1),CellSize/2);
    untifilt(l_low1,l_high1,l_lowhigh0,CellSize);
  for(j = 0; j < n; j++){
    buffer[j] = limitter(l_lowhigh0[j]);
  }
  fwrite((void *)&buffer[0],n*2,1,outfile);
}

