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

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 MMFIRFlt;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29.     Windows,
  30.     MMSystem,
  31.     MMUtils,
  32.     MMRegs;
  33. {========================================================================}
  34. const
  35.      { constants for the DataType fields }
  36.      DT_8BIT   = $00;  { x0 b }
  37.      DT_16BIT  = $01;  { x1 b }
  38.      DT_MONO   = $00;  { 0x b }
  39.      DT_STEREO = $02;  { 1x b }
  40.      { constants for channels }
  41.      CH_BOTH   = $00;
  42.      CH_LEFT   = $01;
  43.      CH_RIGHT  = $02;
  44. function GetDataType(pwfx: PWaveFormatEx): integer;
  45. {==============================================================================}
  46. const
  47.     MAXTAPS = 4096;
  48. type
  49.     PFIRFilter = ^TFIRFilter;
  50.     TFIRFilter = packed record
  51.        DataType   : integer;             { DT_8BIT,DT_16BIT,DT_MONO,DT_STEREO  }
  52.        Channel    : integer;             { on which channel do the filtering   }
  53.        DLine      : array[0..8*MAXTAPS-1] of Smallint; { DelayLine             }
  54.        fTaps      : array[0..MAXTAPS-1] of Float;    { array with float coeffs }
  55.        sTaps      : array[0..4*MAXTAPS-1] of Smallint;{ array with short coeffs}
  56.        pTaps      : Pointer;             { pointer to actual taps              }
  57.        nTaps      : integer;             { number of coeffs in array           }
  58.        uTaps      : integer;             { original number of taps             }
  59.        TapsFactor : integer;             { ScaleFactor for short Taps          }
  60.        Routine16M : Pointer;             { internal for asm stuff              }
  61.        Routine16S : Pointer;
  62.        RoutineFM  : Pointer;
  63.        RoutineFS  : Pointer;
  64.     end;
  65. function  InitFIRFilter(pwfx: PWaveFormatEx): PFIRFilter;
  66. procedure DoneFIRFilter(var pfir: PFIRFilter);
  67. procedure SetFIRFilter(pfir: PFIRFilter; pCoeffs: PFloatArray; nCoeffs, iChannel: integer);
  68. procedure ResetFIRFilter(pfir: PFIRFilter);
  69. function  DoFIRFilterShort(pfir: PFIRFilter; BufIn, BufOut: PChar; Len: Longint): Boolean; pascal;
  70. procedure DoFIRFilterFloat(pfir: PFIRFilter; BufIn, BufOut: PFloatArray; Len: Longint); pascal;
  71. implementation
  72. {========================================================================}
  73. function GetDataType(pwfx: PWaveFormatEx): Integer;
  74. begin
  75.    Result := -1;
  76.    if (pwfx <> Nil) and (pwfx^.wFormatTag = WAVE_FORMAT_PCM) then
  77.    begin
  78.       Result := 0;
  79.       if (pwfx^.wBitsPerSample = 16) then Result := Result or DT_16BIT;
  80.       if (pwfx^.nChannels = 2) then Result := Result or DT_STEREO;
  81.    end;
  82. end;
  83. {==============================================================================}
  84. { -- FIR Filter --                                                             }
  85. {==============================================================================}
  86. {$IFDEF USEASM}
  87. {$L MMFIRL.OBJ}
  88. {$F+}
  89. procedure SetFIRProc(pfir: PFIRFilter; CPUType: integer); pascal; external;
  90. {$F-}
  91. {$ENDIF}
  92. {==============================================================================}
  93. function InitFIRFilter(pwfx: PWaveFormatEx): PFIRFilter;
  94. begin
  95.    Result := GlobalAllocPtr(GHND, sizeOf(TFIRFilter));
  96.    if (Result <> nil) then
  97.    with Result^ do
  98.    begin
  99.       DataType  := GetDataType(pwfx);
  100.       Channel   := CH_BOTH;
  101.       if (DataType and DT_16BIT = DT_8BIT) then
  102.       begin
  103.          DoneFIRFilter(Result);
  104.          exit;
  105.       end;
  106.       uTaps := 0;
  107.       nTaps := 0;
  108.       TapsFactor := 0;
  109.       {$IFDEF USEASM}
  110.       SetFIRProc(Result,GetCPUMode);
  111.       {$ENDIF}
  112.       ResetFIRFilter(Result);
  113.    end;
  114. end;
  115. {========================================================================}
  116. procedure DoneFIRFilter(var pfir: PFIRFilter);
  117. begin
  118.    if (pfir <> nil) then
  119.    begin
  120.       GlobalFreePtr(pfir);
  121.       pfir := nil;
  122.    end;
  123. end;
  124. {========================================================================}
  125. procedure ResetFIRFilter(pfir: PFIRFilter);
  126. begin
  127.    if (pfir <> nil) then
  128.    with pfir^ do
  129.    begin
  130.       FillChar(DLine,8*MAXTAPS*sizeOf(Smallint),0);
  131.    end;
  132. end;
  133. {========================================================================}
  134. procedure SetFIRFilter(pfir: PFIRFilter; pCoeffs: PFloatArray; nCoeffs, iChannel: integer);
  135. var
  136.    i,j,k: integer;
  137.    sum: Float;
  138.    TempTaps: array[0..MAXTAPS+6] of Smallint;
  139. begin
  140.    if (pfir <> nil) then
  141.    with pfir^ do
  142.    begin
  143.       Channel := iChannel;
  144.       uTaps := nCoeffs;
  145.       if (uTaps > MAXTAPS) then uTaps := MAXTAPS;
  146.       { simply copy the taps to our structure }
  147.       nTaps := uTaps;
  148.       for i := 0 to uTaps-1 do fTaps[i] := pCoeffs^[i];
  149.       pTaps := @fTaps;
  150.       {$IFDEF USEASM}
  151.       if _USECPUEXT_ and ((_CPU_ > PENTIUM) or _MMX_) then
  152.       begin
  153.          { find the scale factor for short Taps }
  154.          sum := 0;
  155.          for i := 0 to uTaps-1 do sum := sum + abs(pCoeffs[i]);
  156.          TapsFactor := 1;
  157.          if (sum > 0) then
  158.             while Round(sum * (1 shl TapsFactor)) < MAXSMALLINT do inc(TapsFactor);
  159.          dec(TapsFactor);
  160.          if _MMX_ then
  161.          begin
  162.             { MMX }
  163.             nTaps := ((uTaps+6)div 4)*4;
  164.             FillChar(TempTaps,sizeOf(TempTaps),0);
  165.             { Scale the Taps and copy to Temp }
  166.             for i := 0 to nCoeffs-1 do
  167.                 TempTaps[3+i] := Round(pCoeffs[i]*(1 shl TapsFactor));
  168.             { reorder the Taps for fast asm calculation }
  169.             k := 3;
  170.             for i := 0 to (nTaps div 4)-1 do
  171.             begin
  172.                for j := 0 to 3 do
  173.                begin
  174.                   sTaps[4*(nTaps-4*i-j)-1] := TempTaps[k];
  175.                   sTaps[4*(nTaps-4*i-j)-2] := TempTaps[k+1];
  176.                   sTaps[4*(nTaps-4*i-j)-3] := TempTaps[k+2];
  177.                   sTaps[4*(nTaps-4*i-j)-4] := TempTaps[k+3];
  178.                   dec(k);
  179.                end;
  180.                inc(k,8);
  181.             end;
  182.          end
  183.          else
  184.          begin
  185.             { Pentium PRO }
  186.             nTaps := (uTaps+3)and not 3;
  187.             for i := 0 to uTaps-1 do
  188.                 sTaps[nTaps-i] := Round(pCoeffs^[i]*(1 shl TapsFactor));
  189.          end;
  190.          pTaps := @sTaps;
  191.       end;
  192.       {$ENDIF}
  193.    end;
  194. end;
  195. {==============================================================================}
  196. {$IFDEF USEASM}
  197. {$F+}
  198. function DoFIRFilterShort(pfir: PFIRFilter; BufIn, BufOut: PChar; Len: Longint): Boolean; external;
  199. {$F-}
  200. {$ELSE}
  201. function DoFIRFilterShort(pfir: PFIRFilter; BufIn, BufOut: PChar; Len: Longint): Boolean;
  202. var
  203.    n: Longint;
  204.    {===========================================================================}
  205.    procedure FillDLine(DLine,Input: PSmallArray; Count: integer);
  206.    var
  207.       i: integer;
  208.    begin
  209.       for i := 0 to Count-1 do DLine[i]:= Input[i];
  210.    end;
  211.    {===========================================================================}
  212.    procedure FIRSegM(Input,Output: PSmallArray; Count: integer);
  213.    var
  214.       i,j: integer;
  215.       sum: Double;
  216.       s: Longint;
  217.    begin
  218.       for i := 0 to Count-1 do
  219.       begin
  220.          sum := 0;
  221.          for j := pfir.nTaps-1 downto 0 do
  222.              sum := sum + Input[i+j]*pfir.fTaps[j];
  223.          s := Round(sum);
  224.          if s > 32767 then
  225.          begin
  226.             Result := True;
  227.             Output[i] := 32767;
  228.          end
  229.          else if s < -32768 then
  230.          begin
  231.             Result := True;
  232.             Output[i] := -32768;
  233.          end
  234.          else Output[i] := s;
  235.       end;
  236.    end;
  237.    {===========================================================================}
  238.    procedure FIRSegSB(Input,Output: PSmallArray; Count: integer);
  239.    var
  240.       i,j: integer;
  241.       sum,sum2: Double;
  242.       s: Longint;
  243.    begin
  244.       for i := 0 to Count-1 do
  245.       begin
  246.          sum := 0;
  247.          sum2:= 0;
  248.          for j := pfir.nTaps-1 downto 0 do
  249.          begin
  250.              sum := sum + Input[2*(i+j)]*pfir.fTaps[j];
  251.              sum2:= sum2 + Input[2*(i+j)+1]*pfir.fTaps[j];
  252.          end;
  253.          s := Round(sum);
  254.          if s > 32767 then
  255.          begin
  256.             Result := True;
  257.             Output[2*i] := 32767;
  258.          end
  259.          else if s < -32768 then
  260.          begin
  261.             Result := True;
  262.             Output[2*i] := -32768;
  263.          end
  264.          else Output[2*i] := s;
  265.          s := Round(sum2);
  266.          if s > 32767 then
  267.          begin
  268.             Result := True;
  269.             Output[2*i+1] := 32767;
  270.          end
  271.          else if s < -32768 then
  272.          begin
  273.             Result := True;
  274.             Output[2*i+1] := -32768;
  275.          end
  276.          else Output[2*i+1] := s;
  277.       end;
  278.    end;
  279.    {===========================================================================}
  280.    procedure FIRSegSC(Input,Output: PSmallArray; Count,Channel: integer);
  281.    var
  282.       i,j,c: integer;
  283.       sum: Double;
  284.       s: Longint;
  285.    begin
  286.       c := Channel-1;
  287.       for i := 0 to Count-1 do
  288.       begin
  289.          sum := 0;
  290.          for j := pfir.nTaps-1 downto 0 do
  291.          begin
  292.              sum := sum + Input[2*(i+j)+c]*pfir.fTaps[j];
  293.          end;
  294.          s := Round(sum);
  295.          if s > 32767 then
  296.          begin
  297.             Result := True;
  298.             Output[2*i+c] := 32767;
  299.          end
  300.          else if s < -32768 then
  301.          begin
  302.             Result := True;
  303.             Output[2*i+c] := -32768;
  304.          end
  305.          else Output[2*i+c] := s;
  306.       end;
  307.    end;
  308.    {===========================================================================}
  309.    procedure CopyData16(iChannel: integer; pIn,pOut: PSmallint; Len: Longint);
  310.    var
  311.       ci: integer;
  312.    begin
  313.       ci := iChannel+1;
  314.       if (iChannel and CH_RIGHT = CH_RIGHT) then
  315.       begin
  316.          inc(pIn);
  317.          inc(pOut);
  318.          dec(Len,2);
  319.          dec(ci);
  320.       end;
  321.       while Len > 0 do
  322.       begin
  323.          pOut^ := pIn^;
  324.          inc(pOut,ci);
  325.          inc(pIn,ci);
  326.          dec(Len,2*ci);
  327.       end;
  328.    end;
  329. begin
  330.    { returns true on internal overflow }
  331.    Result := False;
  332.    if (pfir <> nil) and (pfir^.nTaps > 0) then
  333.    with pfir^ do
  334.    begin
  335.       if (DataType and DT_STEREO = DT_STEREO) then    { stereo }
  336.       begin
  337.          Len := Len div 4;
  338.          n := nTaps-1;
  339.          if n > Len then n := Len;
  340.          if (Channel = CH_BOTH) then
  341.          begin
  342.             { both channels }
  343.             FillDLine(@DLine[2*(nTaps-1)],Pointer(BufIn),2*n);
  344.             FIRSegSB(@DLine,Pointer(BufOut),n);
  345.             FIRSegSB(Pointer(BufIn),Pointer(BufOut+4*n),Len-n);
  346.             if n < nTaps-1 then
  347.                FillDLine(@DLine[0],@DLine[2*n],2*(nTaps-n))
  348.             else
  349.                FillDLine(@DLine[0],Pointer(PChar(BufIn)+4*(Len-n)),2*(nTaps-1));
  350.          end
  351.          else
  352.          begin
  353.             { one channel only }
  354.             FillDLine(@DLine[2*(nTaps-1)],Pointer(BufIn),2*n);
  355.             FIRSegSC(@DLine,Pointer(BufOut),n,Channel);
  356.             FIRSegSC(Pointer(BufIn),Pointer(BufOut+4*n),Len-n,Channel);
  357.             if n < nTaps-1 then
  358.                FillDLine(@DLine[0],@DLine[2*n],2*(nTaps-n))
  359.             else
  360.                FillDLine(@DLine[0],Pointer(PChar(BufIn)+4*(Len-n)),2*(nTaps-1));
  361.             if (Channel and CH_LEFT = CH_LEFT) then
  362.                 CopyData16(CH_RIGHT,Pointer(BufIn),Pointer(BufOut),4*Len)
  363.             else
  364.                 CopyData16(CH_LEFT,Pointer(BufIn),Pointer(BufOut),4*Len);
  365.          end;
  366.       end
  367.       else                                            { Mono        }
  368.       begin
  369.          Len := Len div 2;
  370.          n := nTaps-1;
  371.          if n > Len then n := Len;
  372.          FillDLine(@DLine[nTaps-1],Pointer(BufIn),n);
  373.          FIRSegM(@DLine,Pointer(BufOut),n);
  374.          FIRSegM(Pointer(BufIn),Pointer(BufOut+2*n),Len-n);
  375.          if n < nTaps-1 then
  376.              FillDLine(@DLine[0],@DLine[n],nTaps-n)
  377.          else
  378.              FillDLine(@DLine[0],Pointer(PChar(BufIn)+2*(Len-n)),nTaps-1);
  379.       end;
  380.    end;
  381. end;
  382. {$ENDIF}
  383. {==============================================================================}
  384. {$IFDEF USEASM}
  385. {$F+}
  386. procedure DoFIRFilterFloat(pfir: PFIRFilter; BufIn, BufOut: PFloatArray; Len: Longint); external;
  387. {$F-}
  388. {$ELSE}
  389. procedure DoFIRFilterFloat(pfir: PFIRFilter; BufIn, BufOut: PFloatArray; Len: Longint);
  390. var
  391.    n: Longint;
  392.    DLineF: PFloatArray;
  393.    {===========================================================================}
  394.    procedure FillDLine(DLine,Input: PFloatArray; Count: integer);
  395.    var
  396.       i: integer;
  397.    begin
  398.       for i := 0 to Count-1 do DLine[i]:= Input[i];
  399.    end;
  400.    {===========================================================================}
  401.    procedure FIRSegM(Input,Output: PFloatArray; Count: integer);
  402.    var
  403.       i,j: integer;
  404.       sum: Double;
  405.    begin
  406.       for i := 0 to Count-1 do
  407.       begin
  408.          sum := 0;
  409.          for j := pfir.nTaps-1 downto 0 do
  410.              sum := sum + Input[i+j]*pfir.fTaps[j];
  411.          Output[i] := sum;
  412.       end;
  413.    end;
  414.    {===========================================================================}
  415.    procedure FIRSegSB(Input,Output: PFloatArray; Count: integer);
  416.    var
  417.       i,j: integer;
  418.       sum,sum2: Double;
  419.    begin
  420.       for i := 0 to Count-1 do
  421.       begin
  422.          sum := 0;
  423.          sum2:= 0;
  424.          for j := pfir.nTaps-1 downto 0 do
  425.          begin
  426.              sum := sum + Input[2*(i+j)]*pfir.fTaps[j];
  427.              sum2:= sum2 + Input[2*(i+j)+1]*pfir.fTaps[j];
  428.          end;
  429.          Output[2*i]   := sum;
  430.          Output[2*i+1] := sum2;
  431.       end;
  432.    end;
  433.    {===========================================================================}
  434.    procedure FIRSegSC(Input,Output: PFloatArray; Count,Channel: integer);
  435.    var
  436.       i,j,c: integer;
  437.       sum: Double;
  438.    begin
  439.       c := Channel-1;
  440.       for i := 0 to Count-1 do
  441.       begin
  442.          sum := 0;
  443.          for j := pfir.nTaps-1 downto 0 do
  444.          begin
  445.              sum := sum + Input[2*(i+j)+c]*pfir.fTaps[j];
  446.          end;
  447.          Output[2*i+c] := sum;
  448.       end;
  449.    end;
  450.    {===========================================================================}
  451.    procedure CopyData16(iChannel: integer; pIn,pOut: PFloat; Len: Longint);
  452.    var
  453.       ci: integer;
  454.    begin
  455.       ci := iChannel+1;
  456.       if (iChannel and CH_RIGHT = CH_RIGHT) then
  457.       begin
  458.          inc(pIn);
  459.          inc(pOut);
  460.          dec(Len,sizeOf(Float));
  461.          dec(ci);
  462.       end;
  463.       while Len > 0 do
  464.       begin
  465.          pOut^ := pIn^;
  466.          inc(pOut,ci);
  467.          inc(pIn,ci);
  468.          dec(Len,sizeOf(Float)*ci);
  469.       end;
  470.    end;
  471. begin
  472.    { returns true on internal overflow }
  473.    if (pfir <> nil) and (pfir^.nTaps > 0) then
  474.    with pfir^ do
  475.    begin
  476.       DLineF := @pfir.DLine;
  477.       
  478.       if (DataType and DT_STEREO = DT_STEREO) then    { stereo }
  479.       begin
  480.          Len := Len div 2*sizeOf(Float);
  481.          n := nTaps-1;
  482.          if n > Len then n := Len;
  483.          if (Channel = CH_BOTH) then
  484.          begin
  485.             { both channels }
  486.             FillDLine(@DLineF[2*(nTaps-1)],BufIn,2*n);
  487.             FIRSegSB(DLineF,Pointer(BufOut),n);
  488.             FIRSegSB(BufIn,@BufOut[2*n],Len-n);
  489.             if n < nTaps-1 then
  490.                FillDLine(DLineF,@DLineF[2*n],2*(nTaps-n))
  491.             else
  492.                FillDLine(DLineF,Pointer(PChar(BufIn)+2*sizeOf(Float)*(Len-n)),2*(nTaps-1));
  493.          end
  494.          else
  495.          begin
  496.             { one channel only }
  497.             FillDLine(@DLineF[2*(nTaps-1)],BufIn,2*n);
  498.             FIRSegSC(DLineF,BufOut,n,Channel);
  499.             FIRSegSC(BufIn,@BufOut[2*n],Len-n,Channel);
  500.             if n < nTaps-1 then
  501.                FillDLine(DLineF,@DLineF[2*n],2*(nTaps-n))
  502.             else
  503.                FillDLine(DLineF,@BufIn[2*(Len-n)],2*(nTaps-1));
  504.             if (Channel and CH_LEFT = CH_LEFT) then
  505.                 CopyData16(CH_RIGHT,@BufIn[0],@BufOut[0],2*sizeOf(Float)*Len)
  506.             else
  507.                 CopyData16(CH_LEFT,@BufIn[0],@BufOut[0],2*sizeOf(Float)*Len);
  508.          end;
  509.       end
  510.       else                                            { Mono        }
  511.       begin
  512.          Len := Len div sizeOf(Float);
  513.          n := nTaps-1;
  514.          if n > Len then n := Len;
  515.          FillDLine(@DLineF[nTaps-1],BufIn,n);
  516.          FIRSegM(DLineF,BufOut,n);
  517.          FIRSegM(BufIn,@BufOut[n],Len-n);
  518.          if n < nTaps-1 then
  519.              FillDLine(DLineF,@DLineF[n],nTaps-n)
  520.          else
  521.              FillDLine(DLineF,@BufIn[Len-n],nTaps-1);
  522.       end;
  523.    end;
  524. end;
  525. {$ENDIF}
  526. end.