⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frmfft.pas

📁 Delphi FFT Spectrum Analyzer
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  GainLabel.Caption := format('Correction gain: %1.2f',[CoherentGain[WindowFunction]]);
end;


{ **************************************************************************** }
{ Params   : ....                                                              }
{ Return   : -                                                                 }
{                                                                              }
{ Descript : Callback function for Wave Input. This is the 'workhorse' part of }
{            of the application because this is called for every filled buffer.}
{ Notes    : See TFNDrvCallBack for definition.                                }
{ **************************************************************************** }
procedure Callback(hdrvr: HDRVR; uMsg: UINT; dwUser: DWORD;
                   dw1, dw2: DWORD) stdcall;
var
  TheBuffer   : smallint;
  i           : smallint;
  Temp        : single;
  TempH       : single;
  Max         : single;
  MaxHz       : single;
  MaxDbV      : single;
  Peak        : longint;
  PeakY       : longint;
  HzStr       : string;
  DbStr       : string;
  PeakLow     : single;
  PeakHigh    : single;
  LowHighIndex: integer;
begin
  case uMsg of
    MM_WIM_DATA  :
      begin
        { First determine which waverecording-buffer is full (we assume it is full...) }
        TheBuffer := PWaveHdr(dw1).dwUser;
        { Next release buffer for waverecording }
        WaveInUnPrepareHeader(WaveInhandle, @header[TheBuffer], sizeof(TWaveHdr));
        { Next give waverecording new buffer }
        header[FreeBuffer].lpData := pbuf[FreeBuffer];
        header[FreeBuffer].dwBufferLength := BufferLength;
        header[FreeBuffer].dwUser  := FreeBuffer;
        header[FreeBuffer].dwFlags := 0;
        header[FreeBuffer].dwLoops := 0;
        header[FreeBuffer].Reserved:= 0;
        WaveInPrepareHeader(WaveInhandle, @header[FreeBuffer], sizeof(TWaveHdr));
        WaveInAddBuffer(WaveInhandle, @header[FreeBuffer], sizeof(TWaveHdr));
        FreeBuffer := TheBuffer;                { Released buffer is now free }
        { Display wave-buffer }
        for i:=0 to FFTSize-1 do
        begin
          Lines[i].x := i;
          Temp := PFFTArray2(pbuf[TheBuffer])[i] * SourceScale;
          Lines[i].y := SourceHalfHeight - trunc(Temp);
        end;
        frmMain.WavePaintBox.Canvas.FillRect(frmMain.WavePaintBox.ClientRect);
        frmMain.WavePaintBox.Canvas.PolyLine(Slice(Lines, FFTSize));

        { Do FFT on wave-buffer, use integer input }
        Spectrum2(WindowFunction, FFTSize, pbuf[TheBuffer], OutRealFFT);
        { Determine min/max FFT for additional display and filter }
        Max      := 0;
        Peak     := 0;
        PeakY    := 0;
        PeakLow  := 0;
        PeakHigh := 0;
        LowHighIndex := trunc(FilterFreq/FreqMult);        { Low/high pass border }
        for i := 3 to MaxIndex do
        begin
          if i <= LowHighIndex then
          begin
            if OutRealFFT^[i] > PeakLow then PeakLow := OutRealFFT^[i];
          end
          else
          begin
            if OutRealFFT^[i] > PeakHigh then PeakHigh := OutRealFFT^[i];
          end;
          if OutRealFFT^[i]>Max then
          begin
            Max  := OutRealFFT^[i];
            Peak := i;
          end;
        end;
        { Display FFT as either spectrogram or frequency }
        if frmMain.SpectrogramBox.Checked then
        begin
          { If FFT to display as spectrogram }
          for i := 3 to MaxIndex do
          begin
            Temp := log10(OutRealFFT^[i]/MaxOutput) * SpectroCScale; {To color }
            if Temp>MaxColor then Temp := MaxColor;
            TempH := SpectroHScale * i;
            TempH := frmMain.FFTPaintBox.Height - TempH;
            { Capture out of bounds exceptions }
            try
              frmMain.FFTPaintBox.Canvas.Pixels[SpectrogramIndex, trunc(TempH)]:= ColorArray[trunc(Temp)];
            except
            end;
          end;
          inc(SpectrogramIndex);
          if SpectrogramIndex > frmMain.FFTPaintBox.Width then
            SpectrogramIndex := 0;
        end
        else
        begin
          { If FFT to display as frequency }
          for i := 0 to 2 do        { First 3 point are invalid (always some signal) }
          begin
            LinesFFT[i].x := i;
            LinesFFT[i].y := frmMain.FFTPaintBox.Height;
          end;
          for i := 3 to MaxIndex do
          begin
            LinesFFT[i].x := i;
            Temp := log10(OutRealFFT^[i]/MaxOutput) * FFTScale;
            LinesFFT[i].y := trunc(Temp);
            if i = Peak then PeakY := LinesFFT[i].y;
          end;
          frmMain.FFTPaintBox.Canvas.FillRect(frmMain.FFTPaintBox.ClientRect);
          frmMain.FFTPaintBox.Canvas.PolyLine(Slice(LinesFFT, MaxIndex));
        end;
        { Display low/high pass filter }
        if PeakLow=0 then PeakLow := 1;
        Temp := log10(PeakLow/MaxOutput) * FilterScale;

        frmMain.LowPassPaintBox.Canvas.Brush.Color := clYellow;
        frmMain.LowPassPaintBox.Canvas.Rectangle(0, trunc(Temp),
          frmMain.LowPassPaintBox.Width, frmMain.LowPassPaintBox.Height);
        frmMain.LowPassPaintBox.Canvas.Brush.Color := clBlack;
        frmMain.LowPassPaintBox.Canvas.Rectangle(0, 0,
          frmMain.LowPassPaintBox.Width, trunc(Temp));

        if PeakHigh=0 then PeakHigh := 1;
        Temp := log10(PeakHigh/MaxOutput) * FilterScale;
        frmMain.HighPassPaintBox.Canvas.Brush.Color := clYellow;
        frmMain.HighPassPaintBox.Canvas.Rectangle(0, trunc(Temp),
          frmMain.HighPassPaintBox.Width, frmMain.HighPassPaintBox.Height);
        frmMain.HighPassPaintBox.Canvas.Brush.Color := clBlack;
        frmMain.HighPassPaintBox.Canvas.Rectangle(0, 0, frmMain.HighPassPaintBox.Width, trunc(Temp));

        { Display max values }
        MaxHz := Peak * FreqMult;
        MaxDbV := 20 * log10(Max/MaxOutput);
        Peak := trunc(MaxHz);
        if (Peak<>0) and (abs(MaxDbV)<MaxDb) then
        begin
          Str(Peak, HzStr);
          Peak := trunc(MaxDbV);
          Str(Peak, DbStr);
        end
        else
        begin
          HzStr := '___';
          DbStr := '___';
        end;
        frmMain.HzLabel.Caption := HzStr;
        frmMain.dBLabel.Caption := dBStr;
        { Display max line for FFT as frequency }
        if not(frmMain.SpectrogramBox.Checked) then
        begin
          frmMain.FFTPaintBox.Canvas.Pen.Style := psDot;
          frmMain.FFTPaintBox.Canvas.MoveTo(0, PeakY);
          frmMain.FFTPaintBox.Canvas.LineTo(frmMain.FFTPaintBox.Width, PeakY);
          frmMain.FFTPaintBox.Canvas.Pen.Style := psSolid;
        end;
      end;
  end;
end;


{ **************************************************************************** }
{ Params   : -                                                                 }
{ Return   : -                                                                 }
{                                                                              }
{ Descript : Start recording.                                                  }
{ Notes    :                                                                   }
{ **************************************************************************** }
procedure TfrmMain.StartRecording;
const
  TheFunction : TFNDrvCallBack = Callback;
var
  OpenResult: MMRESULT;
  Loop      : integer;
  ErrorText : string;
begin
  if OutRealFFT<>nil then FreeMem(OutRealFFT);

  val(CBoxFFTSize.Text, FFTSize, Loop);
{  if Loop<>0 then FFTSize := 1024;}
  if Loop<>0 then FFTSize := 512; {2005.3.7. kys}
  cbBuf := FFTSize;
  BufferLength := cbBuf * Channels * (BitsPerSample div 8);
  MaxOutput    := (MaxInput * cbBuf) div 2;

  CalcWindowFunctions(FFTSize);
  { Make sure combo box shows correct }
  CBoxWindChange(nil);
  GainLabel.Caption := format('Correction gain: %1.2f',[CoherentGain[WindowFunction]]);

  GetMem(OutRealFFT, FFTSize * sizeof(single));
  val(CBoxSamplerate.Text, Samplerate, Loop);
{  if Loop<>0 then Samplerate := 8000;  }
  if Loop<>0 then Samplerate := 441000;  {2005.3.7. kys}
  FreqMult   := SampleRate/cbBuf;
  MaxIndex   := trunc((SampleRate div 2)/FreqMult);
  frmMain.Caption := format('Realtime FFT (%d points), %d Hz sampling',[cbBuf, SampleRate]);
  FreqScrollBar.Max := SampleRate div 2;
  FilterFreq :=FreqScrollBar.Max-FreqScrollBar.Position;
  FreqFilterLabel.Caption := format('%d Hz',[FilterFreq]);

  FFTPaintBox.Canvas.Pen.Color := clYellow;
  WavePaintBox.Canvas.Pen.Color := clWhite;
  SpectrogramIndex := 0;


  { Setup scales for displaying properly }
  SourceHalfHeight := WavePaintBox.Height div 2;
  SourceScale := SourceHalfHeight / MaxInput;
  FFTHeight := FFTPaintBox.Height;
  FFTScale  := (FFTPaintBox.Height / -MaxDb) * 20;         { 20*log in/out = actual value and dB is actually negative}

  SpectroCScale  := ((6*6*6) / -MaxDb) * 20;               { Intensity to color }
  SpectroHScale  := FFTPaintBox.Height / MaxIndex;         { Frequency to height }

  FilterScale := (LowPassPaintBox.Height / -MaxDb) * 20;   { 20*log in/out = actual value and dB is actually negative}
  { Setup waverecording parameters }
  with WaveFormat do
  begin
    wFormatTag      := WAVE_FORMAT_PCM;
    nChannels       := Channels;
    nSamplesPerSec  := SampleRate;
    nAvgBytesPerSec := SampleRate * Channels * (BitsPerSample div 8);
    nBlockAlign     := Channels * (BitsPerSample div 8);
    wBitsPerSample  := BitsPerSample;
    cbSize          := 0;
  end;
  OpenResult := WaveInOpen (@WaveInHandle, WAVE_MAPPER, @WaveFormat,
                            DWORD(@TheFunction), 0, CALLBACK_FUNCTION);
  if OpenResult=MMSYSERR_NOERROR then
  begin
    { Set width of displays to half the recording frequency }
    FFTPaintBox.Width  := MaxIndex;
    WavePaintBox.Width := FFTPaintBox.Width + LogBarPaintBox.Width;
    FreeBuffer := num_buf;                                 { Last buffer initially free }
    { Make all but one buffers available for waverecording }
    for Loop := 1 to num_buf do
      begin
        GetMem(pbuf[Loop], BufferLength);
        header[Loop].lpData         := pbuf[Loop];
        header[Loop].dwBufferLength := BufferLength;
        header[Loop].dwUser         := Loop;
        header[Loop].dwFlags        := 0;
        header[Loop].dwLoops        := 0;
        header[Loop].dwLoops        := 0;
        if Loop<FreeBuffer then                            { Don't use last buffer yet }
        begin
          OpenResult := WaveInPrepareHeader(WaveInhandle, @header[Loop], sizeof(TWaveHdr));
          if OpenResult=MMSYSERR_NOERROR
            then WaveInAddBuffer(WaveInhandle, @header[Loop], sizeof(TWaveHdr))
            else
            begin
              case OpenResult of
                MMSYSERR_INVALHANDLE  : ErrorText := 'device handle is invalid';
                MMSYSERR_NODRIVER     : ErrorText := 'no device driver present';
                MMSYSERR_NOMEM        : ErrorText := 'memory allocation error, could be incorrect samplerate';
                else                    ErrorText := 'unknown error';
              end;
              MessageDlg(format('Error adding buffer %d device (%s)',[Loop, ErrorText]), mtError, [mbOk], 0);
            end;
        end;
      end;
    WaveInStart(WaveInHandle);                             { Start recording }
  end
  else
  begin
    case OpenResult of
      MMSYSERR_ERROR        : ErrorText := 'unspecified error';
      MMSYSERR_BADDEVICEID  : ErrorText := 'device ID out of range';
      MMSYSERR_NOTENABLED   : ErrorText := 'driver failed enable';
      MMSYSERR_ALLOCATED    : ErrorText := 'device already allocated';
      MMSYSERR_INVALHANDLE  : ErrorText := 'device handle is invalid';
      MMSYSERR_NODRIVER     : ErrorText := 'no device driver present';
      MMSYSERR_NOMEM        : ErrorText := 'memory allocation error, could be incorrect samplerate';
      MMSYSERR_NOTSUPPORTED : ErrorText := 'function isn''t supported';
      MMSYSERR_BADERRNUM    : ErrorText := 'error value out of range';
      MMSYSERR_INVALFLAG    : ErrorText := 'invalid flag passed';
      MMSYSERR_INVALPARAM   : ErrorText := 'invalid parameter passed';
      MMSYSERR_HANDLEBUSY   : ErrorText := 'handle being used simultaneously on another thread (eg callback)';
      MMSYSERR_INVALIDALIAS : ErrorText := 'specified alias not found';
      MMSYSERR_BADDB        : ErrorText := 'bad registry database';
      MMSYSERR_KEYNOTFOUND  : ErrorText := 'registry key not found';
      MMSYSERR_READERROR    : ErrorText := 'registry read error';
      MMSYSERR_WRITEERROR   : ErrorText := 'registry write error';
      MMSYSERR_DELETEERROR  : ErrorText := 'registry delete error';
      MMSYSERR_VALNOTFOUND  : ErrorText := 'registry value not found';
      MMSYSERR_NODRIVERCB   : ErrorText := 'driver does not call DriverCallback';
      else                    ErrorText := 'unknown error';
    end;
    MessageDlg(format('Error opening wave input device (%s)',[ErrorText]), mtError, [mbOk], 0);
    Application.Terminate;
  end;
  LogBarPaintBox.Repaint;                                  { Make sure other paintboxes adjusted }
  FreqBarPaintBox.Repaint;
end;


{ **************************************************************************** }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -