/******************************************************************************

    wavfilt --- SSKFバンクによる8帯域分割と非線形量子化

      version 3.50                           by とご(電脳わ〜るど:DW0243)

    02/19/1995                                           "yomikaki.c"

    ヘッダ以外の処理データの読み書きは、ここで定義されるルーチンによって行い
  ます。非線形量子化やランレングス圧縮・伸長はここで行います。
    ランレングス圧縮の概念は次のとおりです。
    量子化されたデータは1から255の値を持ちます。同じ値が4つ以上連続している場
  合にこの連続数値列を(0,数値,文字数)に置換します。実際のルーチンでは大きさが
  4のフレームを設定してフレーム内の数値がすべて同じ場合に｢ランレングスモード｣
  に入ると定義します。そうでなかった場合は｢非ランレングスモード｣に入ると定義し
  ます。
    また従来の(ver 3.00以降)線形量子化ルーチンも残っており、組み合わせて使うこ
  とで高圧縮率が期待できます。(^^;
    詳細はソースをじっくりご覧ください(^^;)。

 *****************************************************************************/

#include "common.h"

void cswrite_16(int *buf,int *a)
{
  int ctr;
  int tmp,high,low;
  char pack[M];

  int square;
  char sigma;

  int encode_length;
  char RL_flag,RL_length;
  char RL_code,RLpack[M];


  if(QMAX != 1){ /*** 一帯域内の線形量子化を行う ***/
//  標準偏差を求めて(平均を0と仮定する)正規分布に規格化する(近似的に(笑))
    square = 0;
    for(ctr = 0;ctr < M;ctr++){
      square += buf[ctr]*buf[ctr];
    }
    sigma = (char)sqrt((double)(square/M))+1; /* div by 0を避ける */
    if(sigma < QMIN)sigma = QMIN;
    if(sigma > QMAX)sigma = QMAX;
    for(ctr = 0;ctr < M;ctr++){
      buf[ctr] /= (int)sigma; /* 規格化 */
    }
  }else{
    sigma = 1;
  }


// テーブルによる非線形量子化
  for(ctr = 0;ctr < M;ctr++){
  /* 聴覚の振幅に対する鈍性を利用したものに置き換えた(table.c参照) */
  /* 2分法(?)による配列アクセススピードアップ */
    for(high = 254,low = 0;(high - low) != 1;){
      tmp = (high + low)/2;
      if(buf[ctr] <= a[tmp]){
        high = tmp;
      }else{
        low = tmp;
      }
    }
    pack[ctr] = high;
  }


// ランレングス圧縮
  RL_flag = 1; /* ランレングスモードのときゼロ */
  encode_length = 0;
  for(ctr = 0;ctr < M;){
  /* 同一帯域内において */
    if(RL_flag==1){
    /* 非ランレングスモードのとき */
      for(tmp = 1;tmp < 4;tmp++){
        if(ctr+tmp == M)break;
        if(pack[ctr+tmp] != pack[ctr])break;
      }

      if(tmp == 4){
      /* 4文字連続して同じ文字が続いた場合 */
        RL_flag = 0;
        RL_code = pack[ctr];
        RL_length = 0; /* 4少ない値 */
        ctr += 4;
      }else{
        RLpack[encode_length] = pack[ctr];
        encode_length++;
        ctr++;
      }        
    }else{
    /* ランレングスモードのとき */
      for(tmp = 0;tmp < 4;tmp++){
        if(ctr+tmp == M)break;
        if(pack[ctr+tmp] != RL_code)break;
      }
      RL_length += tmp; /* 真値より4少ない */
      ctr += tmp;

      if((pack[ctr] != RL_code)||(RL_length == 252)||(ctr == M)){
        RLpack[encode_length] = 0;  encode_length++;
        RLpack[encode_length] = RL_code;  encode_length++;
        RLpack[encode_length] = RL_length;  encode_length++;
        RL_flag = 1;
        RL_length = 0;
      }
    }
  }
  if(RL_flag == 0){ /*** 残りをフラッシュする ***/
    RLpack[encode_length] = 0;  encode_length++;
    RLpack[encode_length] = RL_code;  encode_length++;
    RLpack[encode_length] = RL_length;  encode_length++;
  }

  fwrite(&sigma,1,1,outfile);
  fwrite(&encode_length,4,1,outfile);
  fwrite(&RLpack[0],encode_length,1,outfile);
}

void csread_16(int *buf,int *a)
{
  int ctr,tmp,t;
  char pack[M];

  char sigma;

  int encode_length;
  char RL_length;
  char RL_code,RLpack[M]; /* RL_code == 0 はランレングスフラグ */

  fread(&sigma,1,1,infile);
  fread(&encode_length,4,1,infile);
  fread(&RLpack[0],encode_length,1,infile);

// ランレングス符号の復元
  tmp = 0;
  for(ctr = 0;ctr < M;){
    RL_code = RLpack[tmp];
    tmp++;
    switch(RL_code){
      case 0x00: /*** ランレングス符号 ***/
        RL_code = RLpack[tmp];
        tmp++;
        RL_length = RLpack[tmp];
        tmp++;
        for(t = 0; t < (RL_length & 0xff)+4; t++){
          pack[ctr] = RL_code;
          ctr++;
        }
        break;
      default:
          pack[ctr] = RL_code;
          ctr++;
        break;
    }
  }


// 両量子化の展開
  for(ctr = 1;ctr < M+1;++ctr){
    buf[ctr] = a[pack[ctr-1]]*(int)sigma;	/* デコードテーブルによる展開 */
  }
}

