/******************************************************************************

    wavfilt --- SSKFバンクによる8帯域分割と非線形量子化

      version 3.50                           by とご(電脳わ〜るど:DW0243)

    02/19/1995                                           "stereo16.c"

    16ビットステレオの属性を持つwaveファイルを処理するルーチンを定義します。
  左右のトラックを別々に処理するため同形のルーチンが２つ並んでます(笑)。
  また全体にコードがすごく冗長ですが(^^;)初心者の作るものですからお許しくださ
  いませ。

 *****************************************************************************/

#include "common.h"
#include "table.h"
#include "buffer.h"
#include "yomikaki.h"
#include "filter.h"
#include "misc.h"

void suppression_s(void)
{
// -24dBの音量差がある時に小さいほうを抑制する
// ↑は16分の1に相当する(間違っていませんように(笑))
// 大抵の場合は最低音帯域に対する他帯域の音量の比較となる
// sup_valueで最大値をシフトしたものとの比較
  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;

    /* 右側 */
    tmp = INT_MIN;
    /* 最大値を探す */
    if(_abs(r_low3_1[i]) > tmp)tmp = _abs(r_low3_1[i]);
    if(_abs(r_low3_2[i]) > tmp)tmp = _abs(r_low3_2[i]);
    if(_abs(r_low3_3[i]) > tmp)tmp = _abs(r_low3_3[i]);
    if(_abs(r_low3_4[i]) > tmp)tmp = _abs(r_low3_4[i]);
    if(_abs(r_high3_1[i]) > tmp)tmp = _abs(r_high3_1[i]);
    if(_abs(r_high3_2[i]) > tmp)tmp = _abs(r_high3_2[i]);
    if(_abs(r_high3_3[i]) > tmp)tmp = _abs(r_high3_3[i]);
    if(_abs(r_high3_4[i]) > tmp)tmp = _abs(r_high3_4[i]);
    /* 最大値の2^n分の1と他の値を比較し、他の値が小さい場合0に抑制する */
    tmp = tmp >> sup_value;
    if(tmp > _abs(r_low3_1[i]))r_low3_1[i] = 0;
    if(tmp > _abs(r_low3_2[i]))r_low3_2[i] = 0;
    if(tmp > _abs(r_low3_3[i]))r_low3_3[i] = 0;
    if(tmp > _abs(r_low3_1[i]))r_low3_4[i] = 0;
    if(tmp > _abs(r_high3_1[i]))r_high3_1[i] = 0;
    if(tmp > _abs(r_high3_2[i]))r_high3_2[i] = 0;
    if(tmp > _abs(r_high3_3[i]))r_high3_3[i] = 0;
    if(tmp > _abs(r_high3_4[i]))r_high3_4[i] = 0;
  }
}

void CellSet_stereo_16(void)
{
  buffer = (short *)__calloc(1,sizeof(short)*2*(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)));

  r_lowhigh0 = (int *)__calloc(1,sizeof(int)*(CellSize+FilterSize-1));
  r_low1  = (int *)__calloc(1,sizeof(int)*(CellSize/2+FilterSize-1));
  r_high1  = (int *)__calloc(1,sizeof(int)*(CellSize/2+FilterSize-1));
  r_low2_1  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  r_low2_2  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  r_high2_1  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  r_high2_2  = (int *)__calloc(1,sizeof(int)*(CellSize/4+FilterSize-1));
  r_low3_1  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_low3_2  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_low3_3  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_low3_4  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_high3_1  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_high3_2  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_high3_3  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
  r_high3_4  = (int *)__calloc(1,sizeof(int)*(CellSize/8+(FilterSize/2-1)));
}

void encode_stereo_16(unsigned long numSample)
{
  unsigned long i,j;
  unsigned long m = numSample / CellSize;
  unsigned long n = numSample % CellSize;

  CellSet_stereo_16();

  for(i = 0; i < m; ++i){
    fread((void *)&buffer[0],CellSize*2*2,1,infile);
    for(j = 0; j < CellSize; j++){
     l_lowhigh0[j+FilterSize-1] = (int)buffer[j*2];
     r_lowhigh0[j+FilterSize-1] = (int)buffer[j*2+1];
    }
      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);

      filtering(r_lowhigh0,r_low1+(FilterSize - 1),
                       r_high1+(FilterSize - 1),CellSize/2);
      filtering(r_high1,r_high2_1+(FilterSize - 1),
                      r_high2_2+(FilterSize - 1),CellSize/4);
      filtering(r_low1,r_low2_1+(FilterSize - 1),
                     r_low2_2+(FilterSize - 1),CellSize/4);
      filtering(r_high2_1,r_high3_1,r_high3_2,CellSize/8);
      filtering(r_high2_2,r_high3_3,r_high3_4,CellSize/8);
      filtering(r_low2_1,r_low3_1,r_low3_2,CellSize/8);
      filtering(r_low2_2,r_low3_3,r_low3_4,CellSize/8);

    suppression_s();

    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);

    cswrite_16(r_low3_1,first_band_encode);
    cswrite_16(r_low3_2,second_band_encode);
    cswrite_16(r_low3_3,third_band_encode);
    cswrite_16(r_low3_4,fourth_band_encode);
    cswrite_16(r_high3_1,fifth_band_encode);
    cswrite_16(r_high3_2,sixth_band_encode);
    cswrite_16(r_high3_3,seventh_band_encode);
    cswrite_16(r_high3_4,eighth_band_encode);

  }

  memset((void *)&l_lowhigh0[FilterSize-1],0,CellSize*2*2);
  memset((void *)&r_lowhigh0[FilterSize-1],0,CellSize*2*2);

  fread((void *)&buffer[0],n*2*2,1,infile);
  for(j = 0; j < CellSize; j++){
    l_lowhigh0[j+FilterSize-1] = (int)buffer[j*2];
    r_lowhigh0[j+FilterSize-1] = (int)buffer[j*2+1];
  }
    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);

    filtering(r_lowhigh0,r_low1+(FilterSize - 1),
                     r_high1+(FilterSize - 1),CellSize/2);
    filtering(r_high1,r_high2_1+(FilterSize - 1),
                    r_high2_2+(FilterSize - 1),CellSize/4);
    filtering(r_low1,r_low2_1+(FilterSize - 1),
                   r_low2_2+(FilterSize - 1),CellSize/4);
    filtering(r_high2_1,r_high3_1,r_high3_2,CellSize/8);
    filtering(r_high2_2,r_high3_3,r_high3_4,CellSize/8);
    filtering(r_low2_1,r_low3_1,r_low3_2,CellSize/8);
    filtering(r_low2_2,r_low3_3,r_low3_4,CellSize/8);

  suppression_s();

  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);

  cswrite_16(r_low3_1,first_band_encode);
  cswrite_16(r_low3_2,second_band_encode);
  cswrite_16(r_low3_3,third_band_encode);
  cswrite_16(r_low3_4,fourth_band_encode);
  cswrite_16(r_high3_1,fifth_band_encode);
  cswrite_16(r_high3_2,sixth_band_encode);
  cswrite_16(r_high3_3,seventh_band_encode);
  cswrite_16(r_high3_4,eighth_band_encode);

}

void decode_stereo_16(unsigned long numSample)
{
  unsigned long i,j;

  unsigned long m = numSample / CellSize;
  unsigned long n = numSample % CellSize;

  CellSet_stereo_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);

    csread_16(r_low3_1,first_band_decode);
    csread_16(r_low3_2,second_band_decode);
    csread_16(r_low3_3,third_band_decode);
    csread_16(r_low3_4,fourth_band_decode);
    csread_16(r_high3_1,fifth_band_decode);
    csread_16(r_high3_2,sixth_band_decode);
    csread_16(r_high3_3,seventh_band_decode);
    csread_16(r_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);

      untifilt(r_low3_1,r_low3_2,r_low2_1+(FilterSize/2-1),CellSize/4);
      untifilt(r_low3_3,r_low3_4,r_low2_2+(FilterSize/2-1),CellSize/4);
      untifilt(r_high3_1,r_high3_2,r_high2_1+(FilterSize/2-1),CellSize/4);
      untifilt(r_high3_3,r_high3_4,r_high2_2+(FilterSize/2-1),CellSize/4);
      untifilt(r_low2_1,r_low2_2,r_low1+(FilterSize/2-1),CellSize/2);
      untifilt(r_high2_1,r_high2_2,r_high1+(FilterSize/2-1),CellSize/2);
      untifilt(r_low1,r_high1,r_lowhigh0,CellSize);

    for(j = 0; j < CellSize; j++){
      buffer[j*2] = limitter(l_lowhigh0[j]);
      buffer[j*2+1] = limitter(r_lowhigh0[j]);
    }
    fwrite((void *)&buffer[0],CellSize*2*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);

  csread_16(r_low3_1,first_band_decode);
  csread_16(r_low3_2,second_band_decode);
  csread_16(r_low3_3,third_band_decode);
  csread_16(r_low3_4,fourth_band_decode);
  csread_16(r_high3_1,fifth_band_decode);
  csread_16(r_high3_2,sixth_band_decode);
  csread_16(r_high3_3,seventh_band_decode);
  csread_16(r_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);

    untifilt(r_low3_1,r_low3_2,r_low2_1+(FilterSize/2-1),CellSize/4);
    untifilt(r_low3_3,r_low3_4,r_low2_2+(FilterSize/2-1),CellSize/4);
    untifilt(r_high3_1,r_high3_2,r_high2_1+(FilterSize/2-1),CellSize/4);
    untifilt(r_high3_3,r_high3_4,r_high2_2+(FilterSize/2-1),CellSize/4);
    untifilt(r_low2_1,r_low2_2,r_low1+(FilterSize/2-1),CellSize/2);
    untifilt(r_high2_1,r_high2_2,r_high1+(FilterSize/2-1),CellSize/2);
    untifilt(r_low1,r_high1,r_lowhigh0,CellSize);

  for(j = 0; j < CellSize; j++){ /*** pcm音声の再構成 ***/
    buffer[j*2] = limitter(l_lowhigh0[j]);
    buffer[j*2+1] = limitter(r_lowhigh0[j]);
  }
  fwrite((void *)&buffer[0],n*2*2,1,outfile);
}

