unit _SndEff;

interface

uses
  _fft_c60_single,_Vis_const;

// Speana ユニット Ver.0.11 Copyright & Programmed by C60
// ------------------------------------------------------
const
  Samples=2048;
  Band=64;
  BandScale64:Array[0..63] of Integer=(
				   6,    7,    8,    9,   10,   11,   12,   13,
				  14,   15,   16,   18,   19,   21,   22,   24,
				  26,   28,   30,   33,   36,   38,   42,   45,
				  49,   52,   57,   61,   66,   72,   77,   84,
				  90,   98,  105,  114,  123,  133,  144,  156,
				 168,  182,  196,  212,  229,  248,  268,  289,
				 313,  338,  365,  395,  427,  461,  499,  539,
				 582,  629,  680,  735,  794,  858,  928, 1003);

const BitRate:integer=$7FFF; // 分解能/2

type
  TSndEff = class
  private
    { Private 宣言 }
    FFT:TFFT;
    HummingWindow:Array[0..2048] of single;
    FFTBuf:array[0..Samples*4] of smallint;
    FFTCount:integer;
    procedure CalcHummingWindow;
  public
    { Public 宣言 }
    NowVolume:LongInt;
    VolumeTableUse:boolean;
    VolumeTable:array[0..$ffff] of SmallInt;
    procedure Init;
    procedure FreeMemory;
    procedure CalcVolumeTable(vol:LongInt);
    procedure CalcFFT(FFTFrame:integer;var Visual:PVisual;var buf:array of SmallInt;offset,len:integer);
    procedure CalcFFTDataSetOnly(var buf:array of SmallInt;offset,len:integer);
  end;

implementation

// Speana ユニット Ver.0.11 Copyright & Programmed by C60
// ------------------------------------------------------

procedure TSndEff.Init;
begin
  FFT:=TFFT.Create;
  CalcHummingWindow;
  CalcVolumeTable(1024);
end;

procedure TSndEff.FreeMemory;
begin
  FFT.FreeMemory;
  FFT.Free;
  FFT:=nil;
end;

procedure TSndEff.CalcHummingWindow;
var
  i:integer;
begin
  for i:=0 to Samples-1 do begin
    HummingWindow[i]:=0.54 - 0.46 * cos(2*PI*i/(Samples-1));
  end;
end;

procedure TSndEff.CalcVolumeTable(vol:LongInt);
var
  cnt:smallint;
  v:LongInt;
begin
  NowVolume:=vol;
  if vol=1024 then begin
    VolumeTableUse:=False;
    for cnt:=-BitRate-1 to BitRate do begin
      VolumeTable[word(cnt)]:=cnt;
    end;
    end else begin
    VolumeTableUse:=True;
    for cnt:=-BitRate-1 to BitRate do begin
      v:=LongInt(cnt)*NowVolume div 1024;
      if v<-32768 then v:=-32768;
      if v>32767 then v:=32767;
      VolumeTable[word(cnt)]:=SmallInt(v);
    end;
  end;
end;

procedure TSndEff.CalcFFTDataSetOnly(var buf:array of SmallInt;offset,len:integer);
begin
  if (Samples*8)>(len*4) then begin
    move(FFTBuf[len*2],FFTBuf[0],Samples*8-len*4);
    move(buf[offset*2],FFTBuf[Samples*4-len*2],len*4);
    end else begin
    move(buf[offset*2],FFTBuf[0],Samples*8);
  end;
end;

procedure TSndEff.CalcFFT(FFTFrame:integer;var Visual:PVisual;var buf:array of SmallInt;offset,len:integer);
var
  adr:integer;
  x,y:Array[0..Samples-1] of single; // FFT 実数部，虚数部，２乗和
  v2:Array[0..Band-1] of single;
  Level:integer;
  i,j:Integer;
begin
  if (Samples*8)>(len*4) then begin
    move(FFTBuf[len*2],FFTBuf[0],Samples*8-len*4);
    move(buf[offset*2],FFTBuf[Samples*4-len*2],len*4);
    end else begin
    move(buf[offset*2],FFTBuf[0],Samples*8);
  end;
  inc(FFTCount);
  if FFTCount<FFTFrame then exit;
  FFTCount:=0;

  adr:=0;
  for i:=0 to Samples-1 do begin
    x[i]:=(integer(FFTBuf[adr+0])+FFTBuf[adr+1])*HummingWindow[i]; // 左右チャネルの上位８ビットのみ有効
    y[i]:=0.0;
    inc(adr,4);
  end;

  FFT.FFT(Samples,x,y);
  j:=0;
  for i:=0 to Band-1 do begin
    v2[i]:=0.0;
  end;
  for i:=1 to (Samples div 2)-1 do begin
    if (i=BandScale64[j]) then begin
      if (j=0) then begin
        v2[j]:=v2[j]/(BandScale64[j]);
        end else begin
        v2[j]:=v2[j]/(BandScale64[j]-BandScale64[j-1]);
      end;
      inc(j);
      if j>=(Band-1) then break;
    end;
    v2[j]:=v2[j]+x[i]*x[i]+y[i]*y[i];
  end;
  for i:=0 to Band-1 do begin
    v2[i]:=ln(v2[i]+1.00)*10.0-60.0;
  end;
  for i:=0 to Band-1 do begin
    Level:=trunc(v2[i]*((i/(Band-1)-0.5)+1.0)*1024/200);
    if Level>=255 then Level:=255;
    if Level<=0 then Level:=0;
    with Visual.SpeAna[i] do begin
      if NowY<Level then
        NowY:=Level
        else
        NowY:=(NowY+Level) div 2;
    end;
  end;
end;

end.
