MMFFTFlt.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:17k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Tel.: +0351-8012255                   =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 20.01.1998 - 18:00:00 $                                      =}
  24. {========================================================================}
  25. unit MMFFTFlt;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     MMSystem,
  37.     MMRegs,
  38.     MMUtils,
  39.     MMMath,
  40.     MMFFT;
  41. {========================================================================}
  42. const
  43.      { constants for the DataType fields }
  44.      DT_8BIT   = $00;  { x0 b }
  45.      DT_16BIT  = $01;  { x1 b }
  46.      DT_MONO   = $00;  { 0x b }
  47.      DT_STEREO = $02;  { 1x b }
  48.      { constants for channels }
  49.      CH_BOTH   = $00;
  50.      CH_LEFT   = $01;
  51.      CH_RIGHT  = $02;
  52. function GetDataType(pwfx: PWaveFormatEx): integer;
  53. {========================================================================}
  54. const
  55.     {$IFDEF CBUILDER3} {$EXTERNALSYM DESM} {$ENDIF}
  56.     DESM           = 8;
  57.     {$IFDEF CBUILDER3} {$EXTERNALSYM MAX_FFTLEN} {$ENDIF}
  58.     MAX_FFTLEN     = 1024;         { Define the maximum FFT buffer length.}
  59.     {$IFDEF CBUILDER3} {$EXTERNALSYM MAX_CHANNELS} {$ENDIF}
  60.     MAX_CHANNELS   = 2;
  61. type
  62.     PFFTCplxArray  = ^TFFTCplxArray;
  63.     TFFTCplxArray  = array[0..MAX_FFTLEN+1] of TfCplx;
  64.     TFFTLongArray  = array[0..MAX_FFTLEN+1] of Longint;
  65.     TFFTFloatArray = array[0..MAX_FFTLEN+1] of Float;
  66.     {-- TFilterParams ---------------------------------------------------------}
  67.     PFilterParams  = ^TFilterParams;
  68.     TFilterParams  = packed record
  69.        Out_Buf     : TFFTLongArray;
  70.        old_r       : TFFTFloatArray;
  71.     end;
  72.     {-- TFFTFilter ------------------------------------------------------------}
  73.     PFFTFilter      = ^TFFTFilter;
  74.     TFFTFilter      = packed record
  75.        DataType     : integer;            { DT_8BIT,DT_16BIT,DT_MONO,DT_STEREO  }
  76.        SampleRate   : Longint;            { SampleRate for the samples          }
  77.        Channels     : integer;            { number of Channels                  }
  78.        FFTLen       : integer;
  79.        FFTLen_2     : integer;            { actual FFTlength                    }
  80.        Order        : integer;
  81.        pfft         : PFFTCplx;           { instance for FFT calculation        }
  82.        BufIn        : PChar;
  83.        BufIn_Bytes  : Longint;
  84.        BufOut       : PChar;
  85.        BufOut_Bytes : Longint;
  86.        MaxBufferSize: Longint;
  87.        WindowFunc   : Longint;
  88.        Params       : array[0..MAX_CHANNELS-1] of TFilterParams;
  89.        {-- var for FFT ------------}
  90.        ampl         : TFFTFloatArray;
  91.        fh           : TFFTCplxArray;
  92.        fx           : TFFTCplxArray;
  93.        DataSection  : TRtlCriticalSection;
  94.     end;
  95. function  InitFFTFilter(pwfx: PWaveFormatEx; FFTLength, MaxBufSize: integer): PFFTFilter;
  96. procedure DoneFFTFilter(var pflt: PFFTFilter);
  97. procedure SetFFTFilterWindow(pflt: PFFTFilter; Window: integer);
  98. procedure SetFFTFilterBand(pflt: PFFTFilter; f1, f2, Gain: Float);
  99. procedure ResetFFTFilter(pflt: PFFTFilter);
  100. function  DoFFTFilter(pflt: PFFTFilter; Channel: TMMChannel; pIn: PChar; Len: Cardinal): Boolean;
  101. implementation
  102. uses
  103.     MMAlloc;
  104. var
  105.    Allocator: TMMAllocator;
  106. {==============================================================================}
  107. function GetDataType(pwfx: PWaveFormatEx): Integer;
  108. begin
  109.    Result := -1;
  110.    if (pwfx <> Nil) and (pwfx^.wFormatTag = WAVE_FORMAT_PCM) then
  111.    begin
  112.       Result := 0;
  113.       if (pwfx^.wBitsPerSample = 16) then Result := Result or DT_16BIT;
  114.       if (pwfx^.nChannels = 2) then Result := Result or DT_STEREO;
  115.    end;
  116. end;
  117. {==============================================================================}
  118. { -- FFT Filter --                                                             }
  119. {==============================================================================}
  120. function InitFFTFilter(pwfx: PWaveFormatEx; FFTLength,MaxBufSize: integer): PFFTFilter;
  121. begin
  122.    Result := Allocator.AllocBufferEx(GHND,SizeOf(TFFTFilter));
  123.    if (Result <> nil) then
  124.    with Result^ do
  125.    begin
  126.       DataType   := GetDataType(pwfx);
  127.       SampleRate := pwfx^.nSamplesPerSec;
  128.       Channels   := pwfx^.nChannels;
  129.       FFTLength  := Min(FFTLength, MAX_FFTLEN);
  130.       FFTLen     := 1;
  131.       { Convert FFTLen to a power of 2 }
  132.       Order := 0;
  133.       while FFTLength > 1 do
  134.       begin
  135.          FFTLength := FFTLength shr 1;
  136.          inc(Order);
  137.       end;
  138.       if (Order > 0) then FFTLen := FFTLen shl Order;
  139.       FFTLen_2 := FFTlen div 2;
  140.       WindowFunc := 1;
  141.       pfft   := InitCplxFFT(Order);
  142.       MaxBufferSize := MaxBufSize;
  143.       BufIn  := Allocator.AllocBufferEx(GHND,2*MaxBufSize*sizeOf(Byte));
  144.       BufOut := Allocator.AllocBufferEx(GHND,2*MaxBufSize*sizeOf(Byte));
  145.       FillChar(DataSection, SizeOf(DataSection), 0);
  146.       InitializeCriticalSection(DataSection);
  147.       ResetFFTFilter(Result);
  148.       SetFFTFilterBand(Result,0,SampleRate div 2,0);
  149.    end;
  150. end;
  151. {==============================================================================}
  152. procedure DoneFFTFilter(var pflt: PFFTFilter);
  153. begin
  154.    if (pflt <> nil) then
  155.    begin
  156.       DeleteCriticalSection(pflt^.DataSection);
  157.       DoneCplxFFT(pflt^.pfft);
  158.       Allocator.FreeBuffer(Pointer(pflt.BufIn));
  159.       Allocator.FreeBuffer(Pointer(pflt.BufOut));
  160.       Allocator.FreeBuffer(Pointer(pflt));
  161.    end;
  162. end;
  163. {==============================================================================}
  164. procedure re_im_Init(pflt: PFFTFilter; amp: PFloatArray);
  165. var
  166.    i: integer;
  167.    ampl_1: TFFTFloatArray;
  168. begin
  169.    with pflt^ do
  170.    begin
  171.       for i := 0 to FFTLen_2 do
  172.       begin
  173.          ampl_1[i] := amp[i];
  174.          ampl_1[FFTLen_2+1+i] := 0
  175.       end;
  176.       ampl_1[0] := ampl_1[0] * 0.5;
  177.       ampl_1[FFTLen_2] := ampl_1[FFTLen_2] * 0.5;
  178.       for i := 0 to FFTLen_2 do
  179.       begin
  180.          fx[i].re := ampl_1[i]*cos(2*M_PI*i/4.0);
  181.          fx[i].im := ampl_1[i]*sin(2*M_PI*i/4.0);
  182.          fx[FFTLen_2+1+i].re := 0;
  183.          fx[FFTLen_2+1+i].im := 0;
  184.       end;
  185.       DoCplxFFTb(pfft,@fx,1);
  186.       {-- OTOBRASENIE 1 -------------------------------------------------}
  187.       for i := 0 to FFTLen-1 do
  188.       begin
  189.          ampl_1[i] := fx[i].re*CalcWindowFunc(WindowFunc, i, FFTLen_2);
  190.          fx[i].re := 0;
  191.          fx[i].im := 0;
  192.       end;
  193.       for i := 0 to FFTlen_2 do fx[i].re := ampl_1[i];
  194.       doCplxFFTb(pfft,@fx,-2);
  195.    end;
  196. end;
  197. {==== INIT IMP-REACTION =======================================================}
  198. procedure InitImp(pflt: PFFTFilter; dx,dy: integer; Gain: Float);
  199. var
  200.    i: integer;
  201. begin
  202.    with pflt^ do
  203.    begin
  204.       EnterCriticalSection(DataSection);
  205.       try
  206.          for i := dx to dy do
  207.          begin
  208.             ampl[i] := pow(10.0,(Gain+6)/20.0);
  209.          end;
  210.          re_im_Init(pflt,@ampl);
  211.          for i := 0 to FFTLen-1 do
  212.          begin
  213.             {-- No Normalization ---}
  214.             fh[i].re := fx[i].re;
  215.             fh[i].im := fx[i].im;
  216.          end;
  217.       finally
  218.          LeaveCriticalSection(DataSection);
  219.       end;
  220.    end;
  221. end;
  222. {== SetFFTFilter ==============================================================}
  223. procedure SetFFTFilterWindow(pflt: PFFTFilter; Window: integer);
  224. var
  225.    i: integer;
  226. begin
  227.    with pflt^ do
  228.    begin
  229.       EnterCriticalSection(DataSection);
  230.       try
  231.          WindowFunc := Window;
  232.          re_im_Init(pflt,@ampl);
  233.          for i := 0 to FFTLen-1 do
  234.          begin
  235.             {-- No Normalization ---}
  236.             fh[i].re := fx[i].re;
  237.             fh[i].im := fx[i].im;
  238.          end;
  239.       finally
  240.          LeaveCriticalSection(DataSection);
  241.       end;
  242.    end;
  243. end;
  244. {== SetFFTFilter ==============================================================}
  245. procedure SetFFTFilterBand(pflt: PFFTFilter; f1,f2,Gain: Float);
  246. var
  247.    dx,dy: integer;
  248.    f,fshag: FLoat;
  249. begin
  250.    with pflt^ do
  251.    begin
  252.       if f1 >= SampleRate div 2 then f1 := SampleRate div 2-1;
  253.       if f2 > SampleRate div 2 then f2 := SampleRate div 2;
  254.       if f1 > f2 then
  255.       begin
  256.          f := f1;
  257.          f1 := f2;
  258.          f2 := f;
  259.       end;
  260.       if (f2 = f1) then f2 := f2+1;
  261.       fshag:= SampleRate/FFTLen;
  262.       dx := Trunc(f1/fshag);
  263.       dy := Trunc(f2/fshag);
  264.       InitImp(pflt,dx,dy,Gain);
  265.    end;
  266. end;
  267. {== ResetFFTFilter ============================================================}
  268. procedure ResetFFTFilter(pflt: PFFTFilter);
  269. var
  270.    i: integer;
  271. begin
  272.    with pflt^ do
  273.    begin
  274.       BufIn_Bytes := 0;
  275.       BufOut_Bytes:= 0;
  276.       for i := 0 to Channels-1 do
  277.       with Params[i] do
  278.       begin
  279.          FillChar(Out_Buf, sizeOf(Out_Buf),0);
  280.          FillChar(Old_r, sizeOf(Old_r),0);
  281.       end;
  282.    end;
  283. end;
  284. {== FFT Filter ================================================================}
  285. procedure FFT_Filter(pflt: PFFTFilter; pIn, pOut: PLongArray; channel: integer);
  286. var
  287.    i: integer;
  288. begin
  289.    with pflt^,pflt^.Params[channel] do
  290.    begin
  291.       EnterCriticalSection(DataSection);
  292.       try
  293.          {-- ZApolnenie dlya fft --}
  294.          for i := 0 to FFTLen_2-1 do
  295.          begin
  296.             fx[i].re := pIn[i];
  297.             fx[i].im := pIn[FFTLen_2+i];
  298.             fx[FFTLen_2+i].re :=0;
  299.             fx[FFTLen_2+i].im :=0;
  300.          end;
  301.          {-- DIRECT FFT SIGNAL --}
  302.          DoCplxFFTb(pfft,@fx,1);
  303.          {-- PEREMNOSENIE Na Impl. Reaction --}
  304.          fvecMul2(@fh, @fx, FFTLen);
  305.          {-- IFFT ---------------}
  306.          DoCplxFFTb(pfft,@fx,-1);
  307.          {-- SUMMIR s Hvostom IMPuls reactsi --}
  308.          for i := 0 to FFTLen_2-1 do
  309.          begin
  310.             pOut[i] := Trunc(fx[i].re+old_r[i]);
  311.             pOut[FFTLen_2+i] := Trunc(fx[FFTLen_2+i].re+fx[i].im);
  312.             old_r[i] := fx[FFTLen_2+i].im;
  313.          end;
  314.       finally
  315.          LeaveCriticalSection(DataSection);
  316.       end;
  317.    end;
  318. end;
  319. {== GetSignal =================================================================}
  320. procedure GetSignal(pflt: PFFTFilter; pIn: PSmallint; pOut: PIntArray);
  321. {$IFNDEF USEASM}
  322. var
  323.    i: integer;
  324. begin
  325.    with pflt^ do
  326.    for i := 0 to FFTlen-1 do
  327.    begin
  328.       pOut[i] := pIn^;
  329.       inc(pIn,Channels);
  330.    end;
  331. {$ELSE}
  332. const
  333.    ParmSize = sizeOf(TFilterParams);
  334. asm
  335.    // EAX = pflt
  336.    // EDX = pIn
  337.    // ECX = pOut
  338.    push  ebx
  339.    push  esi
  340.    push  edi
  341.    mov   esi, TFFTFilter(eax).Channels
  342.    mov   edi, TFFTFilter(eax).FFTLen
  343.    shl   esi, 1
  344.    xor   ebx, ebx
  345. @@loop:
  346.    movsx eax, word ptr [edx]
  347.    add   edx, esi
  348.    mov   [ecx+4*ebx], eax
  349.    movsx eax, word ptr [edx]
  350.    add   edx, esi
  351.    mov   [ecx+4*ebx+4], eax
  352.    movsx eax, word ptr [edx]
  353.    add   edx, esi
  354.    mov   [ecx+4*ebx+8], eax
  355.    movsx eax, word ptr [edx]
  356.    add   edx, esi
  357.    mov   [ecx+4*ebx+12], eax
  358.    add   ebx, 4
  359.    cmp   ebx, edi
  360.    jl    @@loop
  361. @@exit:
  362.    pop   edi
  363.    pop   esi
  364.    pop   ebx
  365. {$ENDIF}
  366. end;
  367. {== Clip Output ===============================================================}
  368. function ClipOutput(pflt: PFFTFilter; pOut: PSmallArray; channel: integer): Boolean;
  369. {$IFNDEF USEASM}
  370. var
  371.    i: integer;
  372.    outval: Longint;
  373.    pS: PSmallint;
  374. begin
  375.    Result := False;
  376.    with pflt^,pflt^.Params[channel] do
  377.    begin
  378.       pS := Pointer(pOut);
  379.       for i := 0 to FFTLen-1 do
  380.       begin
  381.          outval := Out_Buf[i];
  382.          if outval > 32767 then
  383.          begin
  384.             Result := True;
  385.             pS^ := 32767;
  386.          end
  387.          else if outval < -32767 then
  388.          begin
  389.             Result := True;
  390.             pS^ := -32767;
  391.          end
  392.          else
  393.             pS^ := outval;
  394.          inc(pS,Channels);
  395.       end;
  396.    end;
  397. {$ELSE}
  398. const
  399.    ParmSize = sizeOf(TFilterParams);
  400. asm
  401.    // EAX = pflt
  402.    // EDX = pOut
  403.    // ECX = channel
  404.    push  ebx
  405.    push  edi
  406.    push  esi
  407.    push  ebp
  408.    imul  ecx, ParmSize/8
  409.    lea   esi, TFFTFilter(eax).Params+8*ecx
  410.    mov   ebx, TFFTFilter(eax).Channels
  411.    shl   ebx, 1
  412.    mov   ebp, TFFTFilter(eax).FFTLen
  413.    xor   eax, eax
  414.    xor   ecx, ecx
  415. @@loop:
  416.    {--- 1. sample ---}
  417.    mov   edi, dword ptr TFilterParams(esi).Out_Buf[4*ecx]
  418.    cmp   edi, 32767
  419.    jle   @@skip1
  420.    mov   di, 32767
  421.    mov   eax, True
  422.    jmp   @@set1
  423. @@skip1:
  424.    cmp   edi, -32768
  425.    jge   @@set1
  426.    mov   di, -32768
  427.    mov   eax, True
  428. @@set1:
  429.    mov   word ptr [edx], di
  430.    add   edx, ebx
  431.    {--- 2. sample ---}
  432.    mov   edi, dword ptr TFilterParams(esi).Out_Buf[4*ecx+4]
  433.    cmp   edi, 32767
  434.    jle   @@skip2
  435.    mov   di, 32767
  436.    mov   eax, True
  437.    jmp   @@set2
  438. @@skip2:
  439.    cmp   edi, -32768
  440.    jge   @@set2
  441.    mov   di, -32768
  442.    mov   eax, True
  443. @@set2:
  444.    mov   word ptr [edx], di
  445.    add   edx, ebx
  446.    {--- 3. sample ---}
  447.    mov   edi, dword ptr TFilterParams(esi).Out_Buf[4*ecx+8]
  448.    cmp   edi, 32767
  449.    jle   @@skip3
  450.    mov   di, 32767
  451.    mov   eax, True
  452.    jmp   @@set3
  453. @@skip3:
  454.    cmp   edi, -32768
  455.    jge   @@set3
  456.    mov   di, -32768
  457.    mov   eax, True
  458. @@set3:
  459.    mov   word ptr [edx], di
  460.    add   edx, ebx
  461.    {--- 4. sample ---}
  462.    mov   edi, dword ptr TFilterParams(esi).Out_Buf[4*ecx+12]
  463.    cmp   edi, 32767
  464.    jle   @@skip4
  465.    mov   di, 32767
  466.    mov   eax, True
  467.    jmp   @@set4
  468. @@skip4:
  469.    cmp   edi, -32768
  470.    jge   @@set4
  471.    mov   di, -32768
  472.    mov   eax, True
  473. @@set4:
  474.    mov   word ptr [edx], di
  475.    add   edx, ebx
  476.    add   ecx, 4
  477.    cmp   ecx, ebp
  478.    jl    @@loop
  479.    pop   ebp
  480.    pop   esi
  481.    pop   edi
  482.    pop   ebx
  483. {$ENDIF}
  484. end;
  485. var
  486.    p: PFFTFilter;
  487. {== FFT Filter ================================================================}
  488. function DoFFTFilter(pflt: PFFTFilter; Channel: TMMChannel; pIn: PChar; Len: Cardinal): Boolean;
  489. var
  490.    i,ch,KOL,Count,chMin,chMax,BytesDone,nBytes: integer;
  491.    pW,pS: PSmallArray;
  492. begin
  493.    Result := False;
  494.    if (pflt <> nil) then
  495.    with pflt^ do
  496.    begin
  497.       p := pflt;
  498.       GlobalMoveMem(pIn^,(BufIn+BufIn_Bytes)^,Len);
  499.       inc(BufIn_Bytes,Len);
  500.       KOL := BufIn_Bytes div (Channels*sizeOf(Smallint)) div FFTlen;
  501.       chMax := Channels;
  502.       if (Channel = chLeft) then chMax := 1;
  503.       chMin := 0;
  504.       if (Channels = 2) and (Channel = chRight) then chMin := 1;
  505.       for ch := chMin to chMax-1 do
  506.       with Params[ch] do
  507.       begin
  508.          Count := 0;
  509.          while (Count < KOL) do
  510.          begin
  511.             pW := @PSmallArray(BufIn)^[FFTLen*Count*Channels+ch];
  512.             {-- get signal -------------------------------------------------}
  513.             GetSignal(pflt,PSmallint(pW),@Out_Buf);
  514.             {-- filter ---}
  515.             FFT_Filter(pflt,@Out_Buf,@Out_Buf,ch);
  516.             pW := @PSmallArray(PChar(BufOut+BufOut_Bytes))^[FFTLen*Count*Channels+ch];
  517.             {-- formirov vixod signala -------------------------------------}
  518.             if ClipOutput(pflt,pW,ch) then Result := True;
  519.             inc(count);
  520.          end;
  521.       end;
  522.       // TODO: Alles nochmal pr黤en
  523.       BytesDone := KOL * (Channels*sizeOf(Smallint)) * FFTlen;
  524.       if (BytesDone > 0) then
  525.       begin
  526.          inc(BufOut_Bytes,BytesDone);
  527.          dec(BufIn_Bytes,BytesDone);
  528.          GlobalMoveMem((BufIn+BytesDone)^,BufIn^,BufIn_Bytes);
  529.       end;
  530.       nBytes := Min(Len,BufOut_Bytes);
  531.       GlobalFillMem(pIn^,Len-nBytes,0);
  532.       if (Channels = 2) and (Channel <> chBoth) then
  533.       begin
  534.          pS := Pointer(BufOut+(Len-nBytes)+2*chMin);
  535.          pW := Pointer(pIn+(Len-nBytes)+2*chMin);
  536.          i := 0;
  537.          while i < nBytes div 2 do
  538.          begin
  539.             pW^[i] := pS^[i];
  540.             inc(i,2);
  541.          end;
  542.       end
  543.       else GlobalMoveMem((BufOut+(Len-nBytes))^,(pIn+(Len-nBytes))^,nBytes);
  544.       dec(BufOut_Bytes,nBytes);
  545.       GlobalMoveMem((BufOut+nBytes)^,BufOut^,BufOut_Bytes);
  546.    end;
  547. end;
  548. initialization
  549.    Allocator := TMMAllocator.Create;
  550. finalization
  551.    Allocator.Free;
  552. end.