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

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49(0)351-8037944               =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/index.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: 17.11.98 - 22:06:17 $                                        =}
  24. {========================================================================}
  25. unit MMPeak;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     Classes,
  37.     Controls,
  38.     MMSystem,
  39.     MMRegs,
  40.     MMObj,
  41.     MMString,
  42.     MMDSPObj,
  43.     MMMath,
  44.     MMUtils,
  45.     MMMulDiv,
  46.     MMWaveIO,
  47.     MMPCMSup,
  48.     MMFFT;
  49. const
  50.    {$IFDEF CBUILDER3} {$EXTERNALSYM MAX_FFTLEN} {$ENDIF}
  51.     MAX_FFTLEN  = 16384; { Define the maximum FFT length. }
  52. type
  53.    EMMPeakError  = class(Exception);
  54.    TMMPeakEvent  = procedure(Sender: TObject; index: integer; Value: Longint) of object;
  55.    {-- TMMPeakDetect ---------------------------------------------------------}
  56.    TMMPeakDetect = class(TMMDSPComponent)
  57.    private
  58.       FEnabled       : Boolean;
  59.       FOpen          : Boolean;
  60.       FStarted       : Boolean;
  61.       FpFFT          : PFFTReal;    { the instance for the FFT               }
  62.       FData          : PSmallArray; { Array for FFT data                     }
  63.       FWinBuf        : PIntArray;   { Array storing windowing function       }
  64.       FPeaks         : PLongArray;  { Array storing peak values              }
  65.       FPeakLeft      : Smallint;    { Total left peak                        }
  66.       FPeakRight     : Smallint;    { Total right peak                       }
  67.       FFTLen         : integer;     { Number of points for FFT               }
  68.       FWindow        : TMMFFTWindow;{ selected window function               }
  69.       FChannel       : TMMChannel;  { chBoth, chLeft or chRigth              }
  70.       FSilence       : Byte;
  71.       FDetectPeaks   : Boolean;
  72.       FOnPeak        : TMMPeakEvent;
  73.       procedure CreateDataBuffers(Length: Cardinal);
  74.       procedure FreeDataBuffers;
  75.       procedure SetEnabled(aValue: Boolean);
  76.       procedure SetFFTLen(aLength: integer);
  77.       procedure SetWindow(aValue: TMMFFTWindow);
  78.       procedure SetChannel(aValue: TMMChannel);
  79.       function  GetNumPeaks: integer;
  80.       function  Getpeaks(index: integer): Longint;
  81.       function  GetResolution: Float;
  82.    protected
  83.       procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
  84.       procedure Opened; override;
  85.       procedure Closed; override;
  86.       procedure Started; override;
  87.       procedure Stopped; override;
  88.       procedure BufferReady(lpwh: PWaveHdr); override;
  89.       procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); override;
  90.    public
  91.       constructor Create(aOwner: TComponent); override;
  92.       destructor Destroy; override;
  93.       procedure Open;
  94.       procedure Close;
  95.       procedure Start;
  96.       procedure Stop;
  97.       procedure Process(Buffer: PChar; Length: integer);
  98.       procedure ResetData;
  99.       function  GetBytesPerFFT: Longint;
  100.       function  GetPeakIndex(Freq: Float): integer;
  101.       property  Resolution: Float read GetResolution;
  102.       property  NumPeaks: integer read GetNumPeaks;
  103.       property  Peaks[index: integer]: Longint read GetPeaks;
  104.       property  PeakLeft : Smallint read FPeakLeft;
  105.       property  PeakRight: Smallint read FPeakRight;
  106.       property  IsOpen: Boolean read FOpen;
  107.    published
  108.       property Input;
  109.       property Output;
  110.       property OnPeakReady: TMMPeakEvent read FOnPeak write FOnPeak;
  111.       property Enabled: Boolean read FEnabled write SetEnabled default True;
  112.       property FFTLength: integer read FFTLen write SetFFTLen default 128;
  113.       property Window: TMMFFTWindow read FWindow write SetWindow default fwHamming;
  114.       property Channel: TMMChannel read FChannel write SetChannel default chBoth;
  115.       property DetectPeaks: Boolean read FDetectPeaks write FDetectPeaks default True;
  116.    end;
  117. implementation
  118. {== TMMPeakDetect ============================================================}
  119. constructor TMMPeakDetect.Create(aOwner: TComponent);
  120. begin
  121.    inherited Create(aOwner);
  122.    CreateDataBuffers(MAX_FFTLEN);
  123.    FEnabled     := True;
  124.    FOpen        := False;
  125.    FStarted     := False;
  126.    FpFFT        := InitRealFFT(8);
  127.    FEnabled     := True;
  128.    FFTLen       := 8;
  129.    FWindow      := fwHamming;
  130.    FChannel     := chBoth;
  131.    FSilence     := 0;
  132.    FDetectPeaks := True;
  133.    FFTLength    := 128;
  134.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  135.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  136. end;
  137. {-- TMMPeakDetect ------------------------------------------------------------}
  138. destructor TMMPeakDetect.Destroy;
  139. begin
  140.    Close;
  141.    FreeDataBuffers;
  142.    DoneRealFFT(FpFFT);
  143.    inherited Destroy;
  144. end;
  145. {-- TMMPeakDetect ------------------------------------------------------------}
  146. procedure TMMPeakDetect.CreateDataBuffers(Length: Cardinal);
  147. begin
  148.    if (Length > 0) then
  149.    begin
  150.       FData   := GlobalAllocMem(Length * 2*sizeOf(SmallInt));
  151.       FWinBuf := GlobalAllocMem(Length * sizeOf(Integer));
  152.       FPeaks  := GlobalAllocMem(Length div 2 * sizeOf(Longint));
  153.    end;
  154. end;
  155. {-- TMMPeakDetect ------------------------------------------------------------}
  156. procedure TMMPeakDetect.FreeDataBuffers;
  157. begin
  158.    GlobalFreeMem(Pointer(FData));
  159.    GlobalFreeMem(Pointer(FWinBuf));
  160.    GlobalFreeMem(Pointer(FPeaks));
  161. end;
  162. {-- TMMPeakDetect ------------------------------------------------------------}
  163. procedure TMMPeakDetect.ResetData;
  164. begin
  165.    FPeakLeft  := FSilence;
  166.    FPeakRight := FSilence;
  167.    GlobalFillMem(FPeaks^,MAX_FFTLEN*sizeOf(Longint)div 2,0);
  168. end;
  169. {-- TMMPeakDetect ------------------------------------------------------------}
  170. procedure TMMPeakDetect.SetFFTLen(aLength: integer);
  171. var
  172.    Order: integer;
  173. begin
  174.    aLength := MinMax(aLength,8,MAX_FFTLEN);
  175.    { Convert FFTLen to a power of 2 }
  176.    Order := 0;
  177.    while aLength > 1 do
  178.    begin
  179.       aLength := aLength shr 1;
  180.       inc(Order);
  181.    end;
  182.    if (Order > 0) then aLength := aLength shl Order;
  183.    {$IFDEF WIN32}
  184.    {$IFDEF TRIAL}
  185.    {$DEFINE _HACK1}
  186.    {$I MMHACK.INC}
  187.    {$ENDIF}
  188.    {$ENDIF}
  189.    if (aLength <> FFTLen) then
  190.    begin
  191.       { re-init the FFTObject with the new FFT-length }
  192.       DoneRealFFT(FpFFT);
  193.       FpFFT := InitRealFFT(Order);
  194.       FFTLen := aLength;
  195.       GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
  196.       ResetData;
  197.    end;
  198. end;
  199. {-- TMMPeakDetect ------------------------------------------------------------}
  200. procedure TMMPeakDetect.SetWindow(aValue: TMMFFTWindow);
  201. begin
  202.    if (aValue <> FWindow) then
  203.    begin
  204.       FWindow := aValue;
  205.       GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
  206.       ResetData;
  207.    end;
  208. end;
  209. {-- TMMPeakDetect ------------------------------------------------------------}
  210. Procedure TMMPeakDetect.SetChannel(aValue: TMMChannel);
  211. begin
  212.    if (aValue <> FChannel) then
  213.    begin
  214.       FChannel := aValue;
  215.       ResetData;
  216.    end;
  217. end;
  218. {-- TMMPeakDetect ------------------------------------------------------------}
  219. procedure TMMPeakDetect.SetEnabled(aValue: Boolean);
  220. begin
  221.    if (aValue <> FEnabled) then
  222.    begin
  223.       FEnabled := aValue;
  224.    end;
  225. end;
  226. {-- TMMPeakDetect ------------------------------------------------------------}
  227. procedure TMMPeakDetect.SetPWaveFormat(aValue: PWaveFormatEx);
  228. begin
  229.    if (aValue <> nil) then
  230.    begin
  231.       if not (csDesigning in ComponentState) then
  232.          if not pcmIsValidFormat(aValue) then
  233.             raise EMMPeakError.Create(LoadResStr(IDS_INVALIDFORMAT));
  234.       if (PWaveFormat <> nil) and (PWaveFormat^.wBitsPerSample = 8) then
  235.           FSilence := 128
  236.       else
  237.           FSilence := 0;
  238.       ResetData;
  239.    end;
  240.    inherited SetPWaveFormat(aValue);
  241. end;
  242. {-- TMMPeakDetect ------------------------------------------------------------}
  243. function TMMPeakDetect.GetNumPeaks: integer;
  244. begin
  245.    Result := FFTLen div 2;
  246. end;
  247. {-- TMMPeakDetect ------------------------------------------------------------}
  248. function TMMPeakDetect.GetPeaks(index: integer): Longint;
  249. begin
  250.    if index < NumPeaks then
  251.       Result := FPeaks[index]
  252.    else
  253.       Result := 0;
  254. end;
  255. {-- TMMPeakDetect ------------------------------------------------------------}
  256. function TMMPeakDetect.GetPeakIndex(Freq: Float): integer;
  257. begin
  258.    Result := Min(Trunc(Freq/Resolution),NumPeaks);
  259. end;
  260. {-- TMMPeakDetect ------------------------------------------------------------}
  261. function TMMPeakDetect.GetResolution: Float;
  262. begin
  263.    Result := 0;
  264.    if (PWaveFormat <> nil) then
  265.        Result := PWaveFormat^.nSamplesPerSec/FFTLen;
  266. end;
  267. {-- TMMPeakDetect ------------------------------------------------------------}
  268. procedure TMMPeakDetect.Open;
  269. begin
  270.    if not FOpen then
  271.    begin
  272.       if pcmIsValidFormat(PWaveFormat) then
  273.       begin
  274.          FOpen := True;
  275.       end;
  276.    end;
  277. end;
  278. {-- TMMPeakDetect ------------------------------------------------------------}
  279. procedure TMMPeakDetect.Close;
  280. begin
  281.    if FOpen then
  282.    begin
  283.       FOpen := False;
  284.    end;
  285. end;
  286. {-- TMMPeakDetect ------------------------------------------------------------}
  287. procedure TMMPeakDetect.Start;
  288. begin
  289.    if FOpen and not FStarted then
  290.    begin
  291.       ResetData;
  292.       FStarted := True;
  293.    end;
  294. end;
  295. {-- TMMPeakDetect ------------------------------------------------------------}
  296. procedure TMMPeakDetect.Stop;
  297. begin
  298.    if FStarted then
  299.    begin
  300.       FStarted := False;
  301.    end;
  302. end;
  303. {-- TMMPeakDetect ------------------------------------------------------------}
  304. function TMMPeakDetect.GetBytesPerFFT: Longint;
  305. begin
  306.    if (PWaveFormat <> nil) then
  307.        Result := PWaveformat^.nBlockAlign * FFTLen
  308.    else
  309.        Result := 0;
  310. end;
  311. {-- TMMPeakDetect ------------------------------------------------------------}
  312. procedure TMMPeakDetect.Process(Buffer: PChar; Length: integer);
  313. var
  314.    Value,nBytes,nRead,reqBytes: Longint;
  315.    i: Integer;
  316.    ReIndex: integer;
  317.    re,im,a2: Float;
  318.    fTemp: array[0..MAX_FFTLEN-1] of Float;
  319. begin
  320.    if FOpen and FEnabled then
  321.    begin
  322.       FillChar(fTemp, sizeOf(fTemp),0);
  323.       ResetData;
  324.       if FDetectPeaks then
  325.       begin
  326.          pcmFindPeak(PWaveFormat, Buffer, Length, FPeakLeft, FPeakRight);
  327.          FPeakLeft  := abs(FPeakLeft);
  328.          FPeakRight := abs(FPeakRight);
  329.       end
  330.       else
  331.       begin
  332.          FPeakLeft  := 0;
  333.          FPeakRight := 0;
  334.       end;
  335.       nRead := 0;
  336.       reqBytes := GetBytesPerFFT;
  337.       while (Length > 0) do
  338.       begin
  339.          nBytes := Min(Length,reqBytes);
  340.          GlobalMoveMem((Buffer+nRead)^,FData^,nBytes);
  341.          inc(nRead,nBytes);
  342.          dec(Length,nBytes);
  343.          if nBytes < reqBytes then
  344.             GlobalFillMem((PChar(FData)+nBytes)^,reqBytes-nBytes,FSilence);
  345.          ReIndex := Ord(FChannel)-1;
  346.          { perform windowing on sample Data }
  347.          if (PWaveFormat^.wBitsPerSample = 8) then
  348.          begin
  349.             if (PWaveFormat^.nChannels = 1) then
  350.             for i := 0 to FFTLen-1 do
  351.             begin
  352.                Value := PByteArray(FData)^[i];
  353.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  354.             end
  355.             else if (FChannel = chBoth) then
  356.             for i := 0 to FFTLen-1 do
  357.             begin
  358.                Value := (Word(PByteArray(FData)^[i+i])+PByteArray(FData)^[i+i+1])div 2;
  359.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  360.             end
  361.             else for i := 0 to FFTLen-1 do
  362.             begin
  363.                Value := PByteArray(FData)^[i+i+ReIndex];
  364.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  365.             end;
  366.          end
  367.          else
  368.          begin
  369.             if (PWaveFormat^.nChannels = 1) then
  370.             for i := 0 to FFTLen-1 do
  371.             begin
  372.                Value := PSmallArray(FData)^[i];
  373.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  374.             end
  375.             else if (FChannel = chBoth) then
  376.             for i := 0 to FFTLen-1 do
  377.             begin
  378.                Value := (Long(PSmallArray(FData)^[i+i])+PSmallArray(FData)^[i+i+1])div 2;
  379.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  380.             end
  381.             else for i := 0 to FFTLen-1 do
  382.             begin
  383.                Value := PSmallArray(FData)^[i+i+ReIndex];
  384.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  385.             end;
  386.          end;
  387.          { calc the FFT }
  388.          DoRealFFT(FpFFT,@fTemp,1);
  389.          { calc the magnitude }
  390.          for i := 0 to (FFTLen div 2)-1 do
  391.          begin
  392.             { Compute the magnitude }
  393.             re := fTemp[i+i]/(FFTLen div 2);
  394.             im := fTemp[i+i+1]/(FFTLen div 2);
  395.             a2 := re*re+im*im;
  396.             { Watch for possible overflow }
  397.             if a2 < 0 then a2 := 0;
  398.             Value := Trunc(sqrt(a2));
  399.             if assigned(FOnPeak) then FOnPeak(Self,i,Value);
  400.             if Value > FPeaks[i] then
  401.                FPeaks[i] := Value;
  402.          end;
  403.       end;
  404.    end;
  405. end;
  406. {-- TMMPeakDetect ------------------------------------------------------------}
  407. procedure TMMPeakDetect.Opened;
  408. begin
  409.    Open;
  410.    inherited Opened;
  411. end;
  412. {-- TMMPeakDetect ------------------------------------------------------------}
  413. procedure TMMPeakDetect.Closed;
  414. begin
  415.    Close;
  416.    inherited Closed;
  417. end;
  418. {-- TMMPeakDetect ------------------------------------------------------------}
  419. procedure TMMPeakDetect.Started;
  420. begin
  421.    Start;
  422.    inherited Started;
  423. end;
  424. {-- TMMPeakDetect ------------------------------------------------------------}
  425. procedure TMMPeakDetect.Stopped;
  426. begin
  427.    Stop;
  428.    inherited Stopped;
  429. end;
  430. {-- TMMPeakDetect ------------------------------------------------------------}
  431. procedure TMMPeakDetect.BufferReady(lpwh: PWaveHdr);
  432. begin
  433.    if Enabled and FOpen then
  434.    begin
  435.       Process(lpwh^.lpData, lpwh^.dwBytesRecorded);
  436.    end;
  437.    inherited BufferReady(lpwh);
  438. end;
  439. {-- TMMPeakDetect ------------------------------------------------------------}
  440. procedure TMMPeakDetect.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  441. begin
  442.    inherited BufferLoad(lpwh, MoreBuffers);
  443.    if Enabled and FOpen then
  444.    begin
  445.       Process(lpwh^.lpData, lpwh^.dwBytesRecorded);
  446.    end;
  447. end;
  448. end.