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

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: 05.10.98 - 15:53:33 $                                        =}
  24. {========================================================================}
  25. Unit MMSpGram;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     Messages,
  37.     Classes,
  38.     Graphics,
  39.     Controls,
  40.     Forms,
  41.     Menus,
  42.     MMSystem,
  43.     MMUtils,
  44.     MMObj,
  45.     MMString,
  46.     MMMath,
  47.     MMMulDiv,
  48.     MMFFT,
  49.     MMRegs,
  50.     MMPCMSup,
  51.     MMDIBCv;
  52. const
  53.     {$IFDEF CBUILDER3} {$EXTERNALSYM SCALEWIDTH} {$ENDIF}
  54.     SCALEWIDTH      = 32;
  55.     {$IFDEF CBUILDER3} {$EXTERNALSYM SCALEFONT} {$ENDIF}
  56.     SCALEFONT       = 'ARIAL';
  57.     SCALEFONTSIZE   : integer = 10;
  58.     INFOCOLOR       : TCOLOR = clWhite;
  59.     {$IFDEF CBUILDER3} {$EXTERNALSYM MIN_COLOR} {$ENDIF}
  60.     MIN_COLOR       : Word = 10;
  61.     {$IFDEF CBUILDER3} {$EXTERNALSYM NUM_COLORS} {$ENDIF}
  62.     NUM_COLORS      : Word = 236;
  63.     {$IFDEF CBUILDER3} {$EXTERNALSYM MAX_FFTLEN} {$ENDIF}
  64.     MAX_FFTLEN      = 4096; { Define the maximum FFT buffer length.        }
  65. type
  66.     EMMSpectrogramError  = class(Exception);
  67.     TMMSpectrogramGain   = (sgrNone,sgr6db,sgr12db);
  68.     TMMSpectrogramPalette= (spHSV,spThreshold,spBlackWhite,spWhiteBlack,spBone,spCopper,spCool,spHot);
  69.     TMMSpectrogramSelect = procedure(Sender: TObject; Min, Max: Longint) of object;
  70.     PMMSaveBuffer        = ^TMMSaveBuffer;
  71.     TMMSaveBuffer        = array[0..0,0..0] of integer;
  72.     {-- TMMSpectrogram --------------------------------------------------}
  73.     TMMSpectrogram = class(TMMDIBGraphicControl)
  74.     private
  75.       {$IFDEF WIN32}
  76.       FpFFT           : PFFTReal;   { the instance for the FFT calculation}
  77.       {$ELSE}
  78.       FFT             : TMMFFT;     { the object that performs the FFT    }
  79.       {$ENDIF}
  80.       FFFTData        : PSmallArray;{ Array for FFT data                  }
  81.       FOldData        : PSmallArray;{ Storage for embossed mode           }
  82.       FWinBuf         : PIntArray;  { Array storing windowing function    }
  83.       FDisplayVal     : PLongArray; { Array storing display values        }
  84.       FColorValues    : PByteArray; { Array holding color values          }
  85.       Fy1             : PIntArray;  { Array of bin #'s displayed          }
  86.       Fy2             : PIntArray;  { Array of terminal bin #'s           }
  87.       FFTLen          : integer;    { Number of points for FFT            }
  88.       FSampleRate     : Longint;    { A/D sampling rate                   }
  89.       FFreqScaleFactor: Float;      { Scalefactor for the horiz. scale    }
  90.       FFreqBase       : Float;      { Base frequency for the display      }
  91.       FAmpScale       : Float;      { scaling factor for amplitude scaling}
  92.       FLogAmp         : Boolean;    { true for log-based amplitude scale  }
  93.       FSensitivy      : integer;    { here starts the display (db) scaling}
  94.       FWindow         : TMMFFTWindow;{ selected window function           }
  95.       FEmbossed       : Boolean;    { enable/disable embossed palette mode}
  96.       FEnabled        : Boolean;    { Enable or disable Spectrogram       }
  97.       FScaleTextColor : TColor;     { the text color for the scale        }
  98.       FScaleLineColor : TColor;     { the line color for the scale        }
  99.       FScaleBackColor : TColor;     { background color for the scale      }
  100.       FSelectColor    : TColor;     { color for selected range            }
  101.       FSelectDotColor : TColor;     { border color for selected range     }
  102.       FLocatorColor   : TColor;     { locator color                       }
  103.       FPalMode        : TMMSpectrogramPalette;
  104.       FBits           : TMMBits;    { b8bit or b16bit                     }
  105.       FChannel        : TMMChannel; { chBoth, chLeft or chRigth           }
  106.       FMode           : TMMMode;    { mMono, mStereo or mQuadro           }
  107.       FBytes          : Longint;    { calculated data bytes p. spectrogram}
  108.       FGain           : TMMSpectrogramGain;{ Amount of db/octave gain     }
  109.       FOldShowHint    : Boolean;    { save ShowHint propertie             }
  110.       FShowInfo       : Boolean;    { show the freq info or not           }
  111.       FShowInfoHint   : Boolean;    { mouse is down, show the info hint   }
  112.       FDrawScale      : Boolean;    { draw the scale or not               }
  113.       FWidth          : integer;    { calculated width without border     }
  114.       FHeight         : integer;    { calculated height without border    }
  115.       FClientRect     : TRect;      { calculated beveled Rect             }
  116.       Fx1             : integer;    { horiz. position counter for display }
  117.       Fx2             : integer;    { horizontal position counter for bar }
  118.       FNumScaleSteps  : integer;    { pre-calculated number of scale steps}
  119.       FBarWidth       : integer;    { width for the moving bar            }
  120.       FBarColor       : TColor;     { the color for the moving bar        }
  121.       FBarTickColor   : TColor;     { the color for the ticks on the bar  }
  122.       FNeedReset      : Boolean;    { the spectrum needs a reset          }
  123.       FAccelerate     : Boolean;    { accelerate the display refresh      }
  124.       FScroll         : Boolean;    { scroll the display or not           }
  125.       FSaveData       : Boolean;    { save the actual spectrum data       }
  126.       FSaveBuffer     : PMMSaveBuffer;
  127.       FSelectStart    : Longint;    { start pos for selected region       }
  128.       FSelectEnd      : Longint;    { end pos for selected region         }
  129.       FLocator        : Longint;    { current locator position            }
  130.       FDrawing        : Boolean;
  131.       FOldCursor      : TCursor;
  132.       FOrigin         : TRect;
  133.       FMoveRect       : TRect;
  134.       FLocked         : Boolean;
  135.       FUseSelection   : Boolean;
  136.       { Events }
  137.       FOnPcmOverflow  : TNotifyEvent;
  138.       FOnSelecting    : TMMSpectrogramSelect;
  139.       FOnSelectEnd    : TMMSpectrogramSelect;
  140.       procedure CreateDataBuffers(Length: Cardinal);
  141.       procedure FreeDataBuffers;
  142.       procedure CreateArrays(Size: Cardinal);
  143.       procedure FreeArrays;
  144.       procedure SetBytesPerSpectrogram;
  145.       procedure SetupYScale;
  146.       procedure CalcScaleSteps;
  147.       procedure CalcMagnitude(MagnitudeForm: Boolean);
  148.       procedure DrawInfo(Pos: TPoint);
  149.       procedure DrawFrequencyScale;
  150.       procedure DrawData(pDispData: PLongArray);
  151.       procedure DrawBar;
  152.       procedure DrawSelection(aCanvas: TMMDIBCanvas; sStart, sEnd: Longint;
  153.                               sColor: TColor; Solid: Boolean);
  154.       procedure DrawLocator(aCanvas: TMMDIBCanvas; aPos: Longint; aColor: TColor);
  155.       procedure DrawSpectrogram(ClearBackGround: Boolean);
  156.       procedure AdjustSize(var W, H: Integer);
  157.       procedure AdjustBounds;
  158.       procedure SetFFTLen(aLength: integer);
  159.       procedure SetWindow(aValue: TMMFFTWindow);
  160.       procedure SetPalMode(aValue: TMMSpectrogramPalette);
  161.       procedure SetEmbossed(aValue: Boolean);
  162.       procedure SetLogAmp(aValue: Boolean);
  163.       procedure SetFreqScale(aValue: integer);
  164.       function  GetFreqScale: integer;
  165.       procedure SetFreqBase(aValue: integer);
  166.       function  GetFreqBase: integer;
  167.       procedure SetAmplitudeScale(aValue: integer);
  168.       function  GetAmplitudeScale: integer;
  169.       procedure SetAccelerate(aValue: Boolean);
  170.       procedure SetDrawScale(aValue: Boolean);
  171.       procedure SetEnabled(aValue: Boolean);
  172.       procedure SetColors(Index: Integer; Value: TColor);
  173.       procedure SetBarWidth(aValue: integer);
  174.       procedure SetPCMWaveFormat(wf: TPCMWaveFormat);
  175.       function  GetPCMWaveFormat: TPCMWaveFormat;
  176.       procedure SetBits(aValue: TMMBits);
  177.       procedure SetChannel(aValue: TMMChannel);
  178.       procedure SetMode(aValue: TMMMode);
  179.       procedure SetSampleRate(aValue: Longint);
  180.       procedure SetGain(aValue: TMMSpectrogramGain);
  181.       procedure SetSensitivy(aValue: integer);
  182.       procedure SetScroll(aValue: Boolean);
  183.       function  GetScaleBackColor: TColor;
  184.       procedure SetLocator(aValue: Longint);
  185.       procedure SetSaveData(aValue: Boolean);
  186.       
  187.     protected
  188.       procedure ChangeDesigning(aValue: Boolean); override;
  189.       procedure Paint; override;
  190.       procedure Loaded; override;
  191.       procedure PcmOverflow; dynamic;
  192.       procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); override;
  193.       procedure Changed; override;
  194.       procedure Selecting(Min, Max: Longint); dynamic;
  195.       procedure SelectEnd(Min, Max: Longint); dynamic;
  196.       procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  197.       procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  198.       procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  199.     public
  200.       constructor Create(AOwner: TComponent); override;
  201.       destructor  Destroy; override;
  202.       function    GetFrequency(Pos: TPoint): Float;
  203.       procedure   SetPalette(LogPal: PLogPalette);
  204.       procedure   RefreshPCMData(PCMData: Pointer);
  205.       procedure   RefreshFFTData(FFTData: Pointer);
  206.       procedure   RefreshMagnitudeData(MagData: Pointer);
  207.       procedure   ResetData;
  208.       property    ColorValues: PByteArray read FColorValues;
  209.       property    BytesPerSpectrogram: Longint read FBytes;
  210.       property    PCMWaveFormat: TPCMWaveFormat read GetPCMWaveFormat write SetPCMWaveFormat;
  211.       property    FFTData: PSmallArray read FFFTData;
  212.       procedure   Select(sStart, sEnd: Longint; Redraw: Boolean);
  213.       property    SelectionStart: Longint read FSelectStart;
  214.       property    SelectionEnd: Longint read FSelectEnd;
  215.       property    Locator: Longint read Flocator write SetLocator default -1;
  216.       function    IsLocator(X: integer): Boolean;
  217.       function    IsSelectStart(X: integer): Boolean;
  218.       function    IsSelectEnd(X: integer): Boolean;
  219.       function    IsInSelection(X: integer): Boolean;
  220.       property    SaveData: Boolean read FSaveData write SetSaveData default False;
  221.     published
  222.       { Events }
  223.       property OnClick;
  224.       property OnDblClick;
  225.       property OnMouseDown;
  226.       property OnMouseMove;
  227.       property OnMouseUp;
  228.       property OnDragDrop;
  229.       property OnDragOver;
  230.       property OnEndDrag;
  231.       property OnStartDrag;
  232.       property OnPcmOverflow: TNotifyEvent read FOnPcmOverflow write FOnPcmOverflow;
  233.       property OnSelecting: TMMSpectrogramSelect read FOnSelecting write FOnSelecting;
  234.       property OnSelectEnd: TMMSpectrogramSelect read FOnSelectEnd write FOnSelectEnd;
  235.       property Align;
  236.       property Bevel;
  237.       property PopupMenu;
  238.       property ParentShowHint;
  239.       property ShowHint;
  240.       property Visible;
  241.       property Cursor default crCross;
  242.       property PaletteRealize default True;
  243.       property PaletteMapped;
  244.       property ShowInfo: Boolean read FShowInfo write FShowInfo default True;
  245.       property Enabled: Boolean read FEnabled write SetEnabled default True;
  246.       property DrawScale: Boolean read FDrawScale write SetDrawScale default False;
  247.       property Height default 90;
  248.       property Width default 194;
  249.       property Accelerate: Boolean read FAccelerate write SetAccelerate default True;
  250.       property Scroll: Boolean read FScroll write SetScroll default False;
  251.       property ScaleTextColor: TColor index 0 read FScaleTextColor write SetColors default clBlack;
  252.       property ScaleLineColor: TColor index 1 read FScaleLineColor write SetColors default clBlack;
  253.       property BarColor: TColor index 2 read FBarColor write SetColors default clGray;
  254.       property BarTickColor: TColor index 3 read FBarTickColor write SetColors default clWhite;
  255.       {$IFDEF BUILD_ACTIVEX}
  256.       property ScaleBackColor: TColor index 4 read FScaleBackColor write SetColors default clBtnface;
  257.       {$ENDIF}
  258.       property SelectionColor: TColor index 5 read FSelectColor write SetColors default clRed;
  259.       property SelectionDotColor: TColor index 6 read FSelectDotColor write SetColors default clRed;
  260.       property LocatorColor: TColor index 7 read FLocatorColor write SetColors default clYellow;
  261.       property BarWidth: integer read FBarWidth write SetBarWidth default 5;
  262.       property Mode: TMMMode read FMode write SetMode default mMono;
  263.       property BitLength: TMMBits read FBits write SetBits default b8bit;
  264.       property Channel: TMMChannel read FChannel write SetChannel default chBoth;
  265.       property SampleRate: Longint read FSampleRate write SetSampleRate default 11025;
  266.       property Gain: TMMSpectrogramGain read FGain write SetGain default sgrNone;
  267.       property FFTLength: integer read FFTLen write SetFFTLen default 128;
  268.       property Window: TMMFFTWindow read FWindow write SetWindow default fwHamming;
  269.       property LogAmp: Boolean read FLogAmp write SetLogAmp default False;
  270.       property Embossed: Boolean read FEmbossed write SetEmbossed default False;
  271.       property AmplitudeScale: integer read GetAmplitudeScale write SetAmplitudeScale default 100;
  272.       property FrequencyBase: integer read GetFreqBase write SetFreqBase default 0;
  273.       property FrequencyScale: integer read GetFreqScale write SetFreqScale default 1;
  274.       property Sensitivy: integer read FSensitivy write SetSensitivy default -90;
  275.       property PaletteTyp: TMMSpectrogramPalette read FPalMode write SetPalMode default spThreshold;
  276.       property Locked: Boolean read FLocked write FLocked default False;
  277.       property UseSelection: Boolean read FUseSelection write FUseSelection default False;
  278.     end;
  279. implementation
  280. uses consts;
  281. const
  282.    CreateCount: Longint = 0;
  283.    ControlList: TList   = nil;
  284.    SaveDC     : HDC     = 0;
  285.    SaveBitmap : HBitmap = 0;
  286.    SaveWidth  : integer = 0;
  287.    SaveHeight : integer = 0;
  288.    SaveInfoPos: TPoint  = (X:0;Y:0);
  289.    OldBitmap  : HBitmap = 0;
  290.    OldPalette : HPalette= 0;
  291. {------------------------------------------------------------------------}
  292. procedure AddSpectrogram(Spectrogram: TMMSpectrogram);
  293. begin
  294.    inc(CreateCount);
  295.    if (CreateCount = 1) then
  296.    begin
  297.       ControlList := TList.Create;
  298.    end;
  299.    if ControlList.IndexOf(Spectrogram) = -1 then
  300.       ControlList.Add(Spectrogram);
  301. end;
  302. {------------------------------------------------------------------------}
  303. procedure RemoveSpectrogram(Spectrogram: TMMSpectrogram);
  304. begin
  305.    ControlList.Remove(Spectrogram);
  306.    ControlList.Pack;
  307.    dec(CreateCount);
  308.    if (CreateCount = 0) then
  309.    begin
  310.       ControlList.Free;
  311.       ControlList := nil;
  312.    end;
  313. end;
  314. {------------------------------------------------------------------------}
  315. procedure ResetSpectrograms(Spectrogram: TMMSpectrogram);
  316. var
  317.    i: integer;
  318. begin
  319.    if (ControlList <> nil) and (ControlList.Count > 0) then
  320.    begin
  321.       for i := 0 to ControlList.Count-1 do
  322.           if (ControlList.Items[i] <> Spectrogram) then
  323.              TMMSpectrogram(ControlList.Items[i]).FNeedReset := True;
  324.    end;
  325. end;
  326. {-- TMMSpectrogram ------------------------------------------------------}
  327. constructor TMMSpectrogram.Create(AOwner: TComponent);
  328. begin
  329.    inherited Create(AOwner);
  330.    CreateDataBuffers(MAX_FFTLEN);
  331.    PaletteRealize := True;
  332.    {$IFDEF WIN32}
  333.    FpFFT := InitRealFFT(8);
  334.    {$ELSE}
  335.    FFT := TMMFFT.Create;
  336.    {$ENDIF}
  337.    FFTLen := 8;
  338.    FAccelerate := True;
  339.    FSampleRate := 11025;
  340.    FChannel := chBoth;
  341.    FBits := b8bit;
  342.    FMode := mMono;
  343.    FGain := sgrNone;
  344.    FEmbossed := False;
  345.    FWindow := fwHamming;
  346.    FFreqScaleFactor := 1.0;
  347.    FFreqBase := 0;
  348.    FAmpScale := 1.0;
  349.    FLogAmp := False;
  350.    FSensitivy := -90;
  351.    FEnabled := True;
  352.    FPalMode := spThreshold;
  353.    Color := clBlack;
  354.    FScaleTextColor := clBlack;
  355.    FScaleLineColor:= clBlack;
  356.    FScaleBackColor := clBtnFace;
  357.    FBarWidth := 5;
  358.    FBarColor := clGray;
  359.    FBarTickColor := clWhite;
  360.    FDrawScale := False;
  361.    Fx1 := -FBarWidth;
  362.    Fx2 := 0;
  363.    FNeedReset := False;
  364.    FScroll := False;
  365.    FShowInfoHint := False;
  366.    FShowInfo := True;
  367.    FSaveData := False;
  368.    FSelectStart := -1;
  369.    FSelectEnd := -1;
  370.    FLocator := -1;
  371.    FSelectColor := clRed;
  372.    FSelectDotColor := clRed;
  373.    FLocatorColor := clYellow;
  374.    FDrawing := False;
  375.    FLocked := False;
  376.    FUseSelection := False;
  377.    FSaveBuffer := nil;
  378.    Height := 90;
  379.    Width := 194;
  380.    Cursor := crCross;
  381.    FFTLength := 128;
  382.    if not (csDesigning in ComponentState) then
  383.    begin
  384.       { update the spectrogram list }
  385.       AddSpectrogram(Self);
  386.    end;
  387.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  388.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  389. end;
  390. {-- TMMSpectrogram ------------------------------------------------------}
  391. Destructor TMMSpectrogram.Destroy;
  392. begin
  393.    if not (csDesigning in ComponentState) then
  394.    begin
  395.       { update the spectrogram list }
  396.       RemoveSpectrogram(Self);
  397.    end;
  398.    FreeDataBuffers;
  399.    FreeArrays;
  400.    {$IFDEF WIN32}
  401.    DoneRealFFT(FpFFT);
  402.    {$ELSE}
  403.    FFT.Free;
  404.    {$ENDIF}
  405.    inherited Destroy;
  406. end;
  407. {-- TMMSpectrogram ------------------------------------------------------}
  408. procedure TMMSpectrogram.ChangeDesigning(aValue: Boolean);
  409. begin
  410.    inherited ChangeDesigning(aValue);
  411.    if not (csDesigning in ComponentState) then
  412.    begin
  413.       { update the spectrogram list }
  414.       AddSpectrogram(Self);
  415.    end;
  416. end;
  417. {-- TMMSpectrogram ------------------------------------------------------}
  418. procedure TMMSpectrogram.PcmOverflow;
  419. begin
  420.    if Assigned(FOnPcmOverflow) then FOnPcmOverflow(Self);
  421. end;
  422. {-- TMMSpectrogram ------------------------------------------------------}
  423. procedure TMMSpectrogram.CreateDataBuffers(Length: Cardinal);
  424. begin
  425.    if (Length > 0) then
  426.    begin
  427.       FFFTData   := GlobalAllocMem(Length * sizeOf(SmallInt));
  428.       FWinBuf    := GlobalAllocMem(Length * sizeOf(Integer));
  429.       FOldData   := GlobalAllocMem((Length div 2) * sizeOf(SmallInt));
  430.       FDisplayVal:= GlobalAllocMem((Length div 2) * sizeOf(Long));
  431.    end;
  432. end;
  433. {-- TMMSpectrogram ------------------------------------------------------}
  434. procedure TMMSpectrogram.FreeDataBuffers;
  435. begin
  436.    GlobalFreeMem(Pointer(FFFTData));
  437.    GlobalFreeMem(Pointer(FWinBuf));
  438.    GlobalFreeMem(Pointer(FOldData));
  439.    GlobalFreeMem(Pointer(FDisplayVal));
  440.    GlobalFreeMem(Pointer(FSaveBuffer));
  441. end;
  442. {-- TMMSpectrogram ------------------------------------------------------}
  443. procedure TMMSpectrogram.CreateArrays(Size: Cardinal);
  444. begin
  445.    if (Size > 0) then
  446.    begin
  447.       Fy1          := GlobalAllocMem(Size * sizeOf(Integer));
  448.       Fy2          := GlobalAllocMem(Size * sizeOf(Integer));
  449.       FColorValues := GlobalAllocMem(Size * sizeOf(Byte));
  450.    end;
  451. end;
  452. {-- TMMSpectrogram ------------------------------------------------------}
  453. procedure TMMSpectrogram.FreeArrays;
  454. begin
  455.    GlobalFreeMem(Pointer(Fy1));
  456.    GlobalFreeMem(Pointer(Fy2));
  457.    GlobalFreeMem(Pointer(FColorValues));
  458. end;
  459. {-- TMMSpectrogram ------------------------------------------------------}
  460. procedure TMMSpectrogram.ResetData;
  461. var
  462.    P: TPoint;
  463. begin
  464.    if FShowInfoHint then
  465.    begin
  466.       GetCursorPos(P);
  467.       P := ScreenToClient(P);
  468.       Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
  469.    end;
  470.    FNeedReset   := True;
  471.    FSelectStart := -1;
  472.    FSelectEnd   := -1;
  473.    FLocator     := -1;
  474.    Fx1 := -BarWidth;//Max(-FBarWidth,0);
  475.    Fx2 := 0;
  476.    if (FSaveBuffer <> nil) then
  477.        FillChar(FSaveBuffer^,(MAX_FFTLEN div 2) * sizeOf(Long)*FWidth,0);
  478.    Refresh;
  479. end;
  480. {-- TMMSpectrogram ------------------------------------------------------}
  481. procedure TMMSpectrogram.SetFFTLen(aLength: integer);
  482. var
  483.    Order: integer;
  484. begin
  485.    aLength := MinMax(aLength,8,MAX_FFTLEN);
  486.    { Convert FFTLen to a power of 2 }
  487.    Order := 0;
  488.    while aLength > 1 do
  489.    begin
  490.       aLength := aLength shr 1;
  491.       inc(Order);
  492.    end;
  493.    if (Order > 0) then aLength := aLength shl Order;
  494.    {$IFDEF WIN32}
  495.    {$IFDEF TRIAL}
  496.    {$DEFINE _HACK1}
  497.    {$I MMHACK.INC}
  498.    {$ENDIF}
  499.    {$ENDIF}
  500.    if (aLength <> FFTLen) then
  501.    begin
  502.       { re-init the FFTObject with the new FFT-length }
  503.       {$IFDEF WIN32}
  504.       DoneRealFFT(FpFFT);
  505.       FpFFT := InitRealFFT(Order);
  506.       FFTLen := aLength;
  507.       GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
  508.       {$ELSE}
  509.       FFT.FFTLength := aLength;
  510.       FFTLen := aLength;
  511.       GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
  512.       {$ENDIF}
  513.       { Re-initialize the display }
  514.       SetupYScale;
  515.       SetBytesPerSpectrogram;
  516.       Invalidate;
  517.    end;
  518. end;
  519. {-- TMMSpectrogram ------------------------------------------------------}
  520. procedure TMMSpectrogram.SetWindow(aValue: TMMFFTWindow);
  521. begin
  522.    if (aValue <> FWindow) then
  523.    begin
  524.       FWindow := aValue;
  525.       GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
  526.    end;
  527. end;
  528. {-- TMMSpectrogram ------------------------------------------------------}
  529. procedure TMMSpectrogram.SetSampleRate(aValue: Longint);
  530. begin
  531.    if (aValue <> FSampleRate) then
  532.    begin
  533.       FSampleRate := MinMax(aValue, 8000, 100000);
  534.       { Re-initialize the display }
  535.       SetupYScale;
  536.       { calc the number of scale steps }
  537.       CalcScaleSteps;
  538.       Invalidate;
  539.    end;
  540. end;
  541. {-- TMMSpectrogram ------------------------------------------------------}
  542. procedure TMMSpectrogram.SetLogAmp(aValue: Boolean);
  543. begin
  544.    { Toggle linear/logarithmic amplitude axis }
  545.    if (aValue <> FLogAmp) then
  546.    begin
  547.       FLogAmp := aValue;
  548.    end;
  549. end;
  550. {-- TMMSpectrogram ------------------------------------------------------}
  551. procedure TMMSpectrogram.SetEnabled(aValue: Boolean);
  552. begin
  553.    if (aValue <> FEnabled) then
  554.    begin
  555.       FEnabled := aValue;
  556.       { inherited Enabled := Value }
  557.       Invalidate;
  558.    end;
  559. end;
  560. {-- TMMSpectrogram ------------------------------------------------------}
  561. procedure TMMSpectrogram.SetBarWidth(aValue: integer);
  562. begin
  563.    if (aValue <> FBarWidth) then
  564.    begin
  565.       FBarWidth := Max(aValue,0);
  566.       Invalidate;
  567.    end;
  568.    {$IFDEF WIN32}
  569.    {$IFDEF TRIAL}
  570.    {$DEFINE _HACK2}
  571.    {$I MMHACK.INC}
  572.    {$ENDIF}
  573.    {$ENDIF}
  574. end;
  575. {-- TMMSpectrogram ------------------------------------------------------}
  576. procedure TMMSpectrogram.SetSaveData(aValue: Boolean);
  577. begin
  578.    if (aValue <> FSaveData) then
  579.    begin
  580.       if (FSaveBuffer <> nil) then
  581.           GlobalFreeMem(Pointer(FSaveBuffer));
  582.       FSaveData := aValue;
  583.       if FSaveData then
  584.          FSaveBuffer := GlobalAllocMem((MAX_FFTLEN div 2) * sizeOf(Long)*FWidth);
  585.    end;
  586. end;
  587. {-- TMMSpectrogram ------------------------------------------------------}
  588. procedure TMMSpectrogram.Loaded;
  589. begin
  590.    inherited Loaded;
  591.    SetupYScale;
  592.    SetPalMode(FPalMode);
  593.    FastDraw(DrawSpectrogram,True);
  594. end;
  595. {-- TMMSpectrogram ------------------------------------------------------}
  596. procedure TMMSpectrogram.AdjustSize(var W, H: Integer);
  597. begin
  598.    if FDrawScale then
  599.       W := Max(W,2*SCALEWIDTH+2*BevelExtend+5)
  600.    else
  601.       W := Max(W,2*BevelExtend+5);
  602.    H := Max(H,2*BevelExtend+5);
  603. end;
  604. {-- TMMSpectrogram ------------------------------------------------------}
  605. procedure TMMSpectrogram.AdjustBounds;
  606. var
  607.   W, H: Integer;
  608. begin
  609.    W := Width;
  610.    H := Height;
  611.    AdjustSize(W, H);
  612.    if (W <> Width) or (H <> Height) then SetBounds(Left, Top, W, H)
  613.    else Changed;
  614. end;
  615. {-- TMMSpectrogram ------------------------------------------------------}
  616. procedure TMMSpectrogram.SetBounds(aLeft, aTop, aWidth, aHeight: integer);
  617. var
  618.   W, H: Integer;
  619. begin
  620.    W := aWidth;
  621.    H := aHeight;
  622.    AdjustSize (W, H);
  623.    inherited SetBounds(aLeft, aTop, W, H);
  624.    Changed;
  625. end;
  626. {-- TMMSpectrogram ------------------------------------------------------}
  627. procedure TMMSpectrogram.Changed;
  628. begin
  629.    FClientRect := Rect(0,0,Width,Height);
  630.    if FDrawScale then
  631.    begin
  632.       { make place for the scale }
  633.       InflateRect(FClientRect, -SCALEWIDTH,0);
  634.    end;
  635.    { and now for the bevel }
  636.    InflateRect(FClientRect, -Bevel.BevelExtend, -Bevel.BevelExtend);
  637.    { save the real height and width }
  638.    FWidth  := Max(FClientRect.Right - FClientRect.Left,4);
  639.    FHeight := Max(FClientRect.Bottom - FClientRect.Top,4);
  640.    FreeArrays;                               { adjust the dyn.array size }
  641.    CreateArrays(FHeight);
  642.    DIBCanvas.SetBounds(0,0,FWidth,FHeight);
  643.    if (FSaveBuffer <> nil) then
  644.    begin
  645.       GlobalFreeMem(Pointer(FSaveBuffer));
  646.       FSaveBuffer := GlobalAllocMem((MAX_FFTLEN div 2) * sizeOf(Long)*FWidth);
  647.    end;
  648.    SetBytesPerSpectrogram;        { calc the new bytes per Scope }
  649.    SetupYScale;                   { recalc the scalings }
  650.    CalcScaleSteps;
  651.    ResetData;
  652.    inherited Changed;
  653. end;
  654. {-- TMMSpectrogram ------------------------------------------------------}
  655. procedure TMMSpectrogram.SetBytesPerSpectrogram;
  656. begin
  657.    FBytes := (Ord(FBits)+1) * (Ord(FMode)+1) * FFTLen;
  658. end;
  659. {-- TMMSpectrogram ------------------------------------------------------}
  660. Procedure TMMSpectrogram.SetPCMWaveFormat(wf: TPCMWaveFormat);
  661. var
  662.    pwfx: PWaveFormatEx;
  663. begin
  664.    pwfx := @wf;
  665.    if not pcmIsValidFormat(pwfx) then
  666.       raise EMMSpectrogramError.Create(LoadResStr(IDS_INVALIDFORMAT));
  667.    SampleRate := pwfx^.nSamplesPerSec;
  668.    BitLength := TMMBits(pwfx^.wBitsPerSample div 8 - 1);
  669.    Mode := TMMMode(pwfx^.nChannels-1);
  670. end;
  671. {-- TMMSpectrogram ------------------------------------------------------}
  672. function TMMSpectrogram.GetPCMWaveFormat: TPCMWaveFormat;
  673. var
  674.    wfx: TWaveFormatEx;
  675. begin
  676.    pcmBuildWaveHeader(@wfx, (Ord(FBits)+1)*8, Ord(FMode)+1, SampleRate);
  677.    Result := PPCMWaveFormat(@wfx)^;
  678. end;
  679. {-- TMMSpectrogram ------------------------------------------------------}
  680. Procedure TMMSpectrogram.SetBits(aValue: TMMBits);
  681. begin
  682.    if (aValue <> FBits) then
  683.    begin
  684.       FBits := aValue;
  685.       SetBytesPerSpectrogram;
  686.       Invalidate;
  687.    end;
  688.    {$IFDEF WIN32}
  689.    {$IFDEF TRIAL}
  690.    {$DEFINE _HACK3}
  691.    {$I MMHACK.INC}
  692.    {$ENDIF}
  693.    {$ENDIF}
  694. end;
  695. {-- TMMSpectrogram ------------------------------------------------------}
  696. Procedure TMMSpectrogram.SetChannel(aValue: TMMChannel);
  697. begin
  698.    if (aValue <> FChannel) then
  699.    begin
  700.       FChannel := aValue;
  701.       SetBytesPerSpectrogram;
  702.       Invalidate;
  703.    end;
  704. end;
  705. {-- TMMSpectrogram ------------------------------------------------------}
  706. Procedure TMMSpectrogram.SetMode(aValue: TMMMode);
  707. begin
  708.    if (aValue <> FMode) then
  709.    begin
  710.       FMode := aValue;
  711.       SetBytesPerSpectrogram;
  712.       Invalidate;
  713.    end;
  714. end;
  715. {-- TMMSpectrogram ------------------------------------------------------}
  716. procedure TMMSpectrogram.SetGain(aValue: TMMSpectrogramGain);
  717. begin
  718.    if (aValue <> FGain) then
  719.    begin
  720.       FGain := aValue;
  721.    end;
  722. end;
  723. {-- TMMSpectrogram ------------------------------------------------------}
  724. procedure TMMSpectrogram.Select(sStart, sEnd: Longint; Redraw: Boolean);
  725. var
  726.    oldStart,oldEnd: Longint;
  727. begin
  728.    oldStart:= FSelectStart;
  729.    oldEnd := FSElectEnd;
  730.    if (sStart <> FSelectStart) then
  731.    begin
  732.       if (sStart < 0) then sStart := -1;
  733.       if (sStart > FWidth) then sStart := FWidth;
  734.       FSelectStart := sStart;
  735.    end;
  736.    if (sEnd <> FSelectEnd) then
  737.    begin
  738.       if (sEnd < 0) then sEnd := -1;
  739.       if (sEnd > FWidth) then sEnd := FWidth;
  740.       FSelectEnd := sEnd;
  741.    end;
  742.    if (FSelectStart > FSelectEnd) then
  743.    begin
  744.       SwapLong(FSelectStart,FSelectEnd);
  745.    end;
  746.    if (FSelectEnd - FSelectStart <= 0) then
  747.    begin
  748.       FSelectStart := -1;
  749.       FSelectEnd := -1;
  750.    end;
  751.    if Redraw and ((oldStart <> FSelectStart) or (oldEnd <> FSelectEnd)) then
  752.       Refresh;
  753. end;
  754. {-- TMMSpectrogram ------------------------------------------------------}
  755. procedure TMMSpectrogram.SetLocator(aValue: Longint);
  756. var
  757.    oldLoc: Longint;
  758. begin
  759.    oldLoc := FLocator;
  760.    if (aValue <> FLocator) then
  761.    begin
  762.       if (aValue < 0) then aValue := -1;
  763.       if (aValue > FWidth) then aValue := FWidth;
  764.       FLocator := aValue;
  765.    end;
  766.    if (oldLoc <> FLocator) then
  767.       Refresh;
  768. end;
  769. {-- TMMSpectrogram ------------------------------------------------------}
  770. procedure TMMSpectrogram.SetAmplitudeScale;
  771. begin
  772.    { Change the amplitude scale factor }
  773.    aValue := MinMax(aValue, 0, 1000);
  774.    if (aValue <> GetAmplitudeScale) then
  775.    begin
  776.       FAmpScale := 0.01*aValue;
  777.    end;
  778. end;
  779. {-- TMMSpectrogram ------------------------------------------------------}
  780. function TMMSpectrogram.GetAmplitudeScale: integer;
  781. begin
  782.    Result := Round(FAmpScale/0.01);
  783. end;
  784. {-- TMMSpectrogram ------------------------------------------------------}
  785. procedure TMMSpectrogram.SetFreqScale(aValue: integer);
  786. begin
  787.    aValue := MinMax(aValue,1,16);
  788.    if (aValue <> Trunc(FFreqScaleFactor)) then
  789.    begin
  790.       FFreqScaleFactor := aValue;
  791.       { Re-initialize the display }
  792.       SetupYScale;
  793.       { calc the number of scale steps }
  794.       CalcScaleSteps;
  795.       Invalidate;
  796.    end;
  797. end;
  798. {-- TMMSpectrogram ------------------------------------------------------}
  799. function TMMSpectrogram.GetFreqScale: integer;
  800. begin
  801.    Result := Trunc(FFreqScaleFactor);
  802. end;
  803. {-- TMMSpectrogram ------------------------------------------------------}
  804. procedure TMMSpectrogram.SetFreqBase(aValue: integer);
  805. begin
  806.    aValue := Max(aValue,0);
  807.    if (aValue <> Trunc(FFreqBase)) then
  808.    begin
  809.       FFreqBase := aValue;
  810.       { Re-initialize the display }
  811.       SetupYScale;
  812.       { calc the number of scale steps }
  813.       CalcScaleSteps;
  814.       Invalidate;
  815.    end;
  816. end;
  817. {-- TMMSpectrogram ------------------------------------------------------}
  818. function TMMSpectrogram.GetFreqBase: integer;
  819. begin
  820.    Result := Trunc(FFreqBase);
  821. end;
  822. {-- TMMSpectrogram ------------------------------------------------------}
  823. procedure TMMSpectrogram.SetSensitivy(aValue: integer);
  824. begin
  825.    aValue := MinMax(aValue, -90, -9);
  826.    if (aValue <> FSensitivy) then
  827.    begin
  828.       FSensitivy := aValue;
  829.    end;
  830. end;
  831. {-- TMMSpectrogram ------------------------------------------------------}
  832. procedure TMMSpectrogram.SetDrawScale(aValue: Boolean);
  833. begin
  834.    if (aValue <> FDrawScale) then
  835.    begin
  836.       FDrawScale := aValue;
  837.       AdjustBounds;
  838.       Invalidate;
  839.    end;
  840.    {$IFDEF WIN32}
  841.    {$IFDEF TRIAL}
  842.    {$DEFINE _HACK2}
  843.    {$I MMHACK.INC}
  844.    {$ENDIF}
  845.    {$ENDIF}
  846. end;
  847. {-- TMMSpectrogram ------------------------------------------------------}
  848. procedure TMMSpectrogram.SetAccelerate(aValue: Boolean);
  849. begin
  850.    if (aValue <> FAccelerate) then
  851.    begin
  852.       FAccelerate := aValue;
  853.       if not FAccelerate and FScroll then Invalidate;
  854.    end;
  855. end;
  856. {-- TMMSpectrogram ------------------------------------------------------}
  857. procedure TMMSpectrogram.SetEmbossed(aValue: Boolean);
  858. begin
  859.    if (aValue <> FEmbossed) then
  860.    begin
  861.       FEmbossed := aValue;
  862.       Invalidate;
  863.    end;
  864. end;
  865. {-- TMMSpectrogram ------------------------------------------------------}
  866. Procedure TMMSpectrogram.SetScroll(aValue: Boolean);
  867. begin
  868.    if (aValue <> FScroll) then
  869.    begin
  870.       FScroll := aValue;
  871.       Invalidate;
  872.    end;
  873. end;
  874. {-- TMMSpectrogram ------------------------------------------------------}
  875. Procedure TMMSpectrogram.SetColors(Index: Integer; Value: TColor);
  876. begin
  877.    case Index of
  878.         0: if FScaleTextColor = Value then exit else FScaleTextColor := Value;
  879.         1: if FScaleLineColor = Value then exit else FScaleLineColor := Value;
  880.         2: if FBarColor = Value then exit else FBarColor := Value;
  881.         3: if FBarTickColor = Value then exit else FBarTickColor := Value;
  882.         4: if FScaleBackColor = Value then exit else FScaleBackColor := Value;
  883.         5: if FSelectColor = Value then exit else FSelectColor := Value;
  884.         6: if FSelectDotColor = Value then exit else FSelectDotColor := Value;
  885.         7: if FLocatorColor = Value then exit else FLocatorColor := Value;
  886.    end;
  887.    Invalidate;
  888.    {$IFDEF WIN32}
  889.    {$IFDEF TRIAL}
  890.    {$DEFINE _HACK1}
  891.    {$I MMHACK.INC}
  892.    {$ENDIF}
  893.    {$ENDIF}
  894. end;
  895. {-- TMMSpectrogram ------------------------------------------------------}
  896. procedure TMMSpectrogram.SetPalette(LogPal: PLogPalette);
  897. begin
  898.    Refresh;
  899.    DIBCanvas.SetLogPalette(LogPal);
  900.    Invalidate;
  901. end;
  902. {-- TMMSpectrogram ------------------------------------------------------}
  903. procedure TMMSpectrogram.SetPalMode(aValue: TMMSpectrogramPalette);
  904. type
  905.    { Logical Palette }
  906.    TLogPal = packed record
  907.     palVersion: Word;
  908.     palNumEntries: Word;
  909.     palEntry: array[0..255] of TPaletteEntry;
  910.   end;
  911. var
  912.    i,clr: Longint;
  913.    LogPal: TLogPal;
  914. begin
  915.    FPalMode := aValue;
  916.    if not (csLoading in ComponentState) and
  917.       not (csReading in ComponentState) then
  918.    begin
  919.       FillChar(LogPal, sizeOf(LogPal),0);
  920.       with LogPal do
  921.       begin
  922.          palVersion := $300;
  923.          palNumEntries := 256;
  924.          for i := MIN_COLOR to MIN_COLOR+NUM_COLORS-1 do
  925.          begin
  926.             clr := (i-MIN_COLOR)*256 div NUM_COLORS;
  927.             case FPalMode of
  928.               spHSV:
  929.               begin
  930.                  if (clr < 64) then
  931.                  begin
  932.                     palEntry[i].peRed := 0;
  933.                     palEntry[i].peGreen := clr*4;
  934.                     palEntry[i].peBlue := 255;
  935.                  end
  936.                  else if (clr < 128) then
  937.                  begin
  938.                     palEntry[i].peRed := 0;
  939.                     palEntry[i].peGreen := 255;
  940.                     palEntry[i].peBlue := 510-clr*4;
  941.                  end
  942.                  else if (clr < 192) then
  943.                  begin
  944.                     palEntry[i].peRed := clr*4-510;
  945.                     palEntry[i].peGreen := 255;
  946.                     palEntry[i].peBlue := 0;
  947.                  end
  948.                  else
  949.                  begin
  950.                     palEntry[i].peRed := 255;
  951.                     palEntry[i].peGreen := 1020-clr*4;
  952.                     palEntry[i].peBlue := 0;
  953.                  end;
  954.               end;
  955.               spThreshold:
  956.               begin
  957.                  if (clr < 16) then
  958.                  begin
  959.                     palEntry[i].peRed := 0;
  960.                     palEntry[i].peGreen := 0;
  961.                     palEntry[i].peBlue := 0;
  962.                  end
  963.                  else if (clr < 64) then
  964.                  begin
  965.                     palEntry[i].peRed := 0;
  966.                     palEntry[i].peGreen := clr*4;
  967.                     palEntry[i].peBlue := 255;
  968.                  end
  969.                  else if (clr < 128) then
  970.                  begin
  971.                     palEntry[i].peRed := 0;
  972.                     palEntry[i].peGreen := 255;
  973.                     palEntry[i].peBlue := 510-clr*4;
  974.                  end
  975.                  else if (clr < 192) then
  976.                  begin
  977.                     palEntry[i].peRed := clr*4-510;
  978.                     palEntry[i].peGreen := 255;
  979.                     palEntry[i].peBlue := 0;
  980.                  end
  981.                  else
  982.                  begin
  983.                     palEntry[i].peRed := 255;
  984.                     palEntry[i].peGreen := 1020-clr*4;
  985.                     palEntry[i].peBlue := 0;
  986.                  end;
  987.               end;
  988.               spCool:
  989.               begin
  990.                  palEntry[i].peRed := clr;
  991.                  palEntry[i].peGreen := 255-clr;
  992.                  palEntry[i].peBlue := 255;
  993.               end;
  994.               spHot:
  995.               begin
  996.                  if (clr < 96) then
  997.                  begin
  998.                     palEntry[i].peRed := Trunc(clr*2.66667+0.5);
  999.                     palEntry[i].peGreen := 0;
  1000.                     palEntry[i].peBlue := 0;
  1001.                  end
  1002.                  else if (clr < 192) then
  1003.                  begin
  1004.                     palEntry[i].peRed := 255;
  1005.                     palEntry[i].peGreen := Trunc(clr*2.66667-254);
  1006.                     palEntry[i].peBlue := 0;
  1007.                  end
  1008.                  else
  1009.                  begin
  1010.                     palEntry[i].peRed := 255;
  1011.                     palEntry[i].peGreen := 255;
  1012.                     palEntry[i].peBlue := Trunc(clr*4.0-766.0);
  1013.                  end;
  1014.               end;
  1015.               spBone:
  1016.               begin
  1017.                  if (clr < 96) then
  1018.                  begin
  1019.                     palEntry[i].peRed := Trunc(clr*0.88889);
  1020.                     palEntry[i].peGreen := Trunc(clr*0.88889);
  1021.                     palEntry[i].peBlue := Trunc(clr*1.20000);
  1022.                  end
  1023.                  else if (clr < 192) then
  1024.                  begin
  1025.                     palEntry[i].peRed := Trunc(clr*0.88889);
  1026.                     palEntry[i].peGreen := Trunc(clr*1.20000-29);
  1027.                     palEntry[i].peBlue := Trunc(clr*0.88889+29);
  1028.                  end
  1029.                  else
  1030.                  begin
  1031.                     palEntry[i].peRed := Trunc(clr*1.20000-60);
  1032.                     palEntry[i].peGreen := Trunc(clr*0.88889+29);
  1033.                     palEntry[i].peBlue := Trunc(clr*0.88889+29);
  1034.                  end;
  1035.               end;
  1036.               spCopper:
  1037.               begin
  1038.                  if (clr < 208) then
  1039.                  begin
  1040.                     palEntry[i].peRed := Trunc(clr*1.23);
  1041.                     palEntry[i].peGreen := Trunc(clr*0.78);
  1042.                     palEntry[i].peBlue := Trunc(clr*0.5);
  1043.                  end
  1044.                  else
  1045.                  begin
  1046.                     palEntry[i].peRed := 255;
  1047.                     palEntry[i].peGreen := Trunc(clr*0.78);
  1048.                     palEntry[i].peBlue := Trunc(clr*0.5);
  1049.                  end;
  1050.               end;
  1051.               spBlackWhite:
  1052.               begin
  1053.                  palEntry[i].peRed := clr;
  1054.                  palEntry[i].peGreen := clr;
  1055.                  palEntry[i].peBlue := clr;
  1056.               end;
  1057.               spWhiteBlack:
  1058.               begin
  1059.                  palEntry[i].peRed := 255-clr;
  1060.                  palEntry[i].peGreen := 255-clr;
  1061.                  palEntry[i].peBlue := 255-clr;
  1062.               end;
  1063.             end;
  1064.          end;
  1065.       end;
  1066.       SetPalette(@LogPal);
  1067.    end;
  1068. end;
  1069. {-- TMMSpectrogram ------------------------------------------------------}
  1070. procedure TMMSpectrogram.SetupYScale;
  1071. var
  1072.    i,ival: Long;
  1073.    FFTBase: Float;
  1074. begin
  1075.    { Setup Y axis }
  1076.    if not(csLoading in ComponentState) then
  1077.    begin
  1078.       { Do some range checking on the base and scale factors }
  1079.       FFreqBase := MinMaxR(FFreqBase,0,FSampleRate/2-1000);
  1080.       if FFreqBase+(FSampleRate/2-FFreqScaleFactor*FFreqBase)/FFreqScaleFactor > FSampleRate/2 then
  1081.  FFreqBase := FSampleRate/2-(FSampleRate/2-FFreqScaleFactor*FFreqBase)/FFreqScaleFactor-1000;
  1082.       FFTBase := FFreqBase/FSampleRate*FFTLen;
  1083.       { Initialize graph y scale (linear or logarithmic).
  1084.         This array points to the bin to be plotted on a given row.}
  1085.       for i := 0 to FHeight-1 do
  1086.       begin
  1087.          ival := Floor(0.01+FFTBase+(i/FHeight*
  1088.                         (FFTLen/2-FFreqScaleFactor*FFTBase))/FFreqScaleFactor);
  1089.          ival := MinMax(ival,0,FFTLen div 2-1);
  1090.          Fy1^[i] := ival;
  1091.          if (i > 0) then Fy2^[i-1] := ival;
  1092.       end;
  1093.       { Compute the ending locations for lines holding multiple bins }
  1094.       for i := 0 to FHeight-1 do
  1095.           if (Fy2^[i] <= (Fy1^[i]+1)) then Fy2^[i] := 0;
  1096.       { if lines are repeated on the screen, flag this so that we don't
  1097.         have to recompute the y values. }
  1098.       for i := FHeight-1 downTo 1 do
  1099.       begin
  1100.          if (Fy1^[i] = Fy1^[i-1]) then
  1101.          begin
  1102.            Fy1^[i] := -1;
  1103.     Fy2^[i]:= 0;
  1104.          end;
  1105.       end;
  1106.    end;
  1107. end;
  1108. {-- TMMSpectrogram ------------------------------------------------------}
  1109. procedure TMMSpectrogram.RefreshPCMData(PCMData: Pointer);
  1110. var
  1111.    Value: Longint;
  1112.    i: Integer;
  1113.    ReIndex: integer;
  1114.    Back1, Back2: Long;                       { Variables for differencing }
  1115.    {$IFDEF WIN32}
  1116.    fTemp: array[0..MAX_FFTLEN] of Float;
  1117.    {$ELSE}
  1118.    fTemp: array[0..MAX_FFTLEN] of Smallint;
  1119.    {$ENDIF}
  1120. begin
  1121.    if FEnabled and Visible and not FShowInfoHint then
  1122.    begin
  1123.       ReIndex := Ord(FChannel)-1;
  1124.       if (FGain = sgrNone) then
  1125.       begin
  1126.          { perform windowing on sample Data from PCMData to FFFTData }
  1127.          if (FBits = b8bit) then
  1128.             if (FMode = mMono) then
  1129.             for i := 0 to FFTLen-1 do
  1130.             begin
  1131.                Value := PByteArray(PCMData)^[i];
  1132.                if Value >= 255 then PcmOverflow;
  1133.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  1134.             end
  1135.             else if (FChannel = chBoth) then
  1136.             for i := 0 to FFTLen-1 do
  1137.             begin
  1138.                Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
  1139.                if Value >= 255 then PcmOverflow;
  1140.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  1141.             end
  1142.             else
  1143.             for i := 0 to FFTLen-1 do
  1144.             begin
  1145.                Value := PByteArray(PCMData)^[i+i+ReIndex];
  1146.                if Value >= 255 then PcmOverflow;
  1147.                fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
  1148.             end
  1149.          else
  1150.             if (FMode = mMono) then
  1151.             for i := 0 to FFTLen-1 do
  1152.             begin
  1153.                Value := PSmallArray(PCMData)^[i];
  1154.                if Value >= 32767 then PcmOverflow;
  1155.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  1156.             end
  1157.             else if (FChannel = chBoth) then
  1158.             for i := 0 to FFTLen-1 do
  1159.             begin
  1160.                Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
  1161.                if Value >= 32766 then PcmOverflow;
  1162.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  1163.             end
  1164.             else
  1165.             for i := 0 to FFTLen-1 do
  1166.             begin
  1167.                Value := PSmallArray(PCMData)^[i+i+ReIndex];
  1168.                if Value >= 32767 then PcmOverflow;
  1169.                fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
  1170.             end;
  1171.       end
  1172.       else if (FGain = sgr6db) then
  1173.       begin
  1174.          { perform windowing on sample Data from PCMData to FFFTData }
  1175.          if (FBits = b8bit) then
  1176.          begin
  1177.             if (FMode = mMono) then
  1178.             begin
  1179.                Back1 := PByteArray(PCMData)^[0];
  1180.                for i := 0 to FFTLen-1 do
  1181.                begin
  1182.                   Value := PByteArray(PCMData)^[i];
  1183.                   if Value >= 255 then PcmOverflow;
  1184.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
  1185.                   Back1 := Value;
  1186.                end;
  1187.             end
  1188.             else if (FChannel = chBoth) then
  1189.             begin
  1190.                Back1 := PByteArray(PCMData)^[0];
  1191.                for i := 0 to FFTLen-1 do
  1192.                begin
  1193.                   Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
  1194.                   if Value >= 255 then PcmOverflow;
  1195.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
  1196.                   Back1 := Value;
  1197.                end;
  1198.             end
  1199.             else
  1200.             begin
  1201.                Back1 := PByteArray(PCMData)^[ReIndex];
  1202.                for i := 0 to FFTLen-1 do
  1203.                begin
  1204.                   Value := PByteArray(PCMData)^[i+i+ReIndex];
  1205.                   if Value >= 255 then PcmOverflow;
  1206.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
  1207.                   Back1 := Value;
  1208.                end;
  1209.             end;
  1210.          end
  1211.          else
  1212.          begin
  1213.             if (FMode = mMono) then
  1214.             begin
  1215.                Back1 := PSmallArray(PCMData)^[0];
  1216.                for i := 0 to FFTLen-1 do
  1217.                begin
  1218.                   Value := PSmallArray(PCMData)^[i];
  1219.                   if Value >= 32767 then PcmOverflow;
  1220.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
  1221.                   Back1 := Value;
  1222.                end;
  1223.             end
  1224.             else if (FChannel = chBoth) then
  1225.             begin
  1226.                Back1 := PSmallArray(PCMData)^[0];
  1227.                for i := 0 to FFTLen-1 do
  1228.                begin
  1229.                   Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
  1230.                   if Value >= 32766 then PcmOverflow;
  1231.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
  1232.                   Back1 := Value;
  1233.                end;
  1234.             end
  1235.             else
  1236.             begin
  1237.                Back1 := PSmallArray(PCMData)^[ReIndex];
  1238.                for i := 0 to FFTLen-1 do
  1239.                begin
  1240.                   Value := PSmallArray(PCMData)^[i+i+ReIndex];
  1241.                   if Value >= 32767 then PcmOverflow;
  1242.                   fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
  1243.                   Back1 := Value;
  1244.                end;
  1245.             end;
  1246.          end;
  1247.       end
  1248.       else { Deriv = 2 }
  1249.       begin
  1250.          { perform windowing on sample Data from PCMData to FFFTData }
  1251.          if (FBits = b8bit) then
  1252.          begin
  1253.             if (FMode = mMono) then
  1254.             begin
  1255.                Back1 := PByteArray(PCMData)^[0];
  1256.                Back2 := Back1;
  1257.                for i := 0 to FFTLen-1 do
  1258.                begin
  1259.                   Value := PByteArray(PCMData)^[i];
  1260.                   if Value >= 255 then PcmOverflow;
  1261.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
  1262.                   Back2 := Back1;
  1263.                   Back1 := Value;
  1264.                end;
  1265.             end
  1266.             else if (FChannel = chBoth) then
  1267.             begin
  1268.                Back1 := PByteArray(PCMData)^[0];
  1269.                Back2 := Back1;
  1270.                for i := 0 to FFTLen-1 do
  1271.                begin
  1272.                   Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
  1273.                   if Value >= 255 then PcmOverflow;
  1274.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
  1275.                   Back2 := Back1;
  1276.                   Back1 := Value;
  1277.                end;
  1278.             end
  1279.             else
  1280.             begin
  1281.                Back1 := PByteArray(PCMData)^[ReIndex];
  1282.                Back2 := Back1;
  1283.                for i := 0 to FFTLen-1 do
  1284.                begin
  1285.                   Value := PByteArray(PCMData)^[i+i+ReIndex];
  1286.                   if Value >= 255 then PcmOverflow;
  1287.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
  1288.                   Back2 := Back1;
  1289.                   Back1 := Value;
  1290.                end;
  1291.             end;
  1292.          end
  1293.          else
  1294.          begin
  1295.             if (FMode = mMono) then
  1296.             begin
  1297.                Back1 := PSmallArray(PCMData)^[0];
  1298.                Back2 := Back1;
  1299.                for i := 0 to FFTLen-1 do
  1300.                begin
  1301.                   Value := PSmallArray(PCMData)^[i];
  1302.                   if Value >= 32767 then PcmOverflow;
  1303.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
  1304.                   Back2 := Back1;
  1305.                   Back1 := Value;
  1306.                end;
  1307.             end
  1308.             else if (FChannel = chBoth) then
  1309.             begin
  1310.                Back1 := PSmallArray(PCMData)^[0];
  1311.                Back2 := Back1;
  1312.                for i := 0 to FFTLen-1 do
  1313.                begin
  1314.                   Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
  1315.                   if Value >= 32767 then PcmOverflow;
  1316.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
  1317.                   Back2 := Back1;
  1318.                   Back1 := Value;
  1319.                end;
  1320.             end
  1321.             else
  1322.             begin
  1323.                Back1 := PSmallArray(PCMData)^[ReIndex];
  1324.                Back2 := Back1;
  1325.                for i := 0 to FFTLen-1 do
  1326.                begin
  1327.                   Value := PSmallArray(PCMData)^[i+i+ReIndex];
  1328.                   if Value >= 32767 then PcmOverflow;
  1329.                   fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
  1330.                   Back2 := Back1;
  1331.                   Back1 := Value;
  1332.                end;
  1333.             end;
  1334.          end;
  1335.       end;
  1336.       fTemp[FFTLen] := 0;
  1337.       { calc the FFT }
  1338.       {$IFDEF WIN32}
  1339.       DoRealFFT(FpFFT,@fTemp,1);
  1340.       for i := 0 to FFTLen do FFFTData^[i] := Trunc(fTemp[i]/(FFTLen div 2));
  1341.       {$ELSE}
  1342.       for i := 0 to FFTLen do FFFTData^[i] := fTemp[i];
  1343.       FFT.CalcFFT(Pointer(FFFTData));
  1344.       {$ENDIF}
  1345.       { calc the magnitude }
  1346.       CalcMagnitude(False);
  1347.       { next, put this data up on the display }
  1348.       FastDraw(DrawSpectrogram,False);
  1349.    end;
  1350. end;
  1351. {-- TMMSpectrogram ------------------------------------------------------}
  1352. procedure TMMSpectrogram.RefreshFFTData(FFTData: Pointer);
  1353. begin
  1354.    Move(PByte(FFTData)^, FFFTData^, FFTLen*sizeOf(SmallInt));
  1355.    { calc the magnitude }
  1356.    CalcMagnitude(False);
  1357.    { next, put this data up on the display }
  1358.    FastDraw(DrawSpectrogram,False);
  1359. end;
  1360. {-- TMMSpectrogram ------------------------------------------------------}
  1361. procedure TMMSpectrogram.RefreshMagnitudeData(MagData: Pointer);
  1362. begin
  1363.    Move(PByte(MagData)^, FFFTData^, FFTLen*sizeOf(SmallInt));
  1364.    { calc display values }
  1365.    CalcMagnitude(True);
  1366.    { next, put this data up on the display }
  1367.    FastDraw(DrawSpectrogram,False);
  1368. end;
  1369. {-- TMMSpectrogram ------------------------------------------------------}
  1370. procedure TMMSpectrogram.CalcMagnitude(MagnitudeForm: Boolean);
  1371. var
  1372.    i: integer;
  1373.    re,im: Long;
  1374.    a2: Longint;
  1375.    pSave: PLongArray;
  1376. begin
  1377.    { go through the data set and convert it to magnitude form }
  1378.    if FSaveData then
  1379.       pSave := Pointer(PChar(FSaveBuffer) + Fx2*(FFTLen div 2)*sizeof(Long))
  1380.    else
  1381.       pSave := nil;
  1382.    if not FLogAmp then
  1383.    begin
  1384.       { Use sqrt(a2) in linear-amplitude mode }
  1385.       for i := 0 to (FFTLen div 2)-1 do
  1386.       begin
  1387.          if MagnitudeForm then
  1388.          begin
  1389.             a2 := PLongArray(FFFTData)^[i];
  1390.          end
  1391.          else
  1392.          begin
  1393.             { Compute the magnitude }
  1394.             {$IFDEF WIN32}
  1395.             re := FFFTData^[i+i];
  1396.             im := FFFTData^[i+i+1];
  1397.             {$ELSE}
  1398.             re := FFFTData^[FFT.BitReversed^[i]];
  1399.             im := FFFTData^[FFT.BitReversed^[i]+1];
  1400.             {$ENDIF}
  1401.             a2 := re*re+im*im;
  1402.          end;
  1403.          { Watch for possible overflow }
  1404.          if a2 < 0 then a2 := 0;
  1405.          FDisplayVal^[i] := Trunc((FAmpScale*sqrt(a2))+(-90-FSensitivy))+MIN_COLOR;
  1406.          if (pSave <> nil) then
  1407.              pSave[i] := FDisplayVal^[i];
  1408.       end;
  1409.    end
  1410.    else
  1411.    begin { log-amplitude mode }
  1412.       for i := 0 to (FFTLen div 2)-1 do
  1413.       begin
  1414.          if MagnitudeForm then
  1415.          begin
  1416.             a2 := PLongArray(FFFTData)^[i];
  1417.          end
  1418.          else
  1419.          begin
  1420.             { Compute the magnitude }
  1421.             {$IFDEF WIN32}
  1422.             re := FFFTData^[i+i];
  1423.             im := FFFTData^[i+i+1];
  1424.             {$ELSE}
  1425.             re := FFFTData^[FFT.BitReversed^[i]];
  1426.             im := FFFTData^[FFT.BitReversed^[i]+1];
  1427.             {$ENDIF}
  1428.             a2 := re*re+im*im;
  1429.          end;
  1430.          { Watch for possible overflow }
  1431.          if a2 < 1 then a2 := 1;
  1432.          FDisplayVal^[i] := Trunc((20*FAmpScale*Log(a2))+2*(-90-FSensitivy))+MIN_COLOR;
  1433.          if (pSave <> nil) then
  1434.              pSave[i] := FDisplayVal^[i];
  1435.       end;
  1436.    end;
  1437. end;
  1438. {.$DEFINE COLORTEST}
  1439. {-- TMMSpectrogram ------------------------------------------------------}
  1440. procedure TMMSpectrogram.DrawData(pDispData: PLongArray);
  1441. var
  1442.    i, j, y, index, repcount: integer;
  1443.    val,val2: Long;
  1444.    oldData: PSmallInt;
  1445.    LastVal: integer;
  1446.    {$IFDEF COLRTEST}
  1447.    clr: integer;
  1448.    {$ENDIF}
  1449. begin
  1450.    val := 0;
  1451.    i := 0;
  1452.    y := FHeight-1;
  1453.    oldData := Pointer(FOldData);
  1454.    LastVal := MIN_COLOR;
  1455.    repcount := 0;
  1456.    {$IFDEF COLORTEST}
  1457.    clr := MIN_COLOR+NUM_COLORS;
  1458.    {$ENDIF}
  1459.    while i < FHeight do
  1460.    begin
  1461.       { If this line is the same as the previous one, just use the previous
  1462.         Y value. Else go ahead and compute the value. }
  1463.       index := Fy1^[i];
  1464.       if (index <> -1) or (i = FHeight-1) then
  1465.       begin
  1466.          if i > 0 then
  1467.          begin
  1468.             if (FEmbossed) then
  1469.             begin
  1470.                { Get difference with offset }
  1471.                val2 := OldData^ - val + (NUM_COLORS div 2);
  1472.                Olddata^ := LastVal;
  1473.                inc(OldData);
  1474.                LastVal := val;
  1475.                val := val2;
  1476.             end;
  1477.             val := MinMax(val,MIN_COLOR,MIN_COLOR+NUM_COLORS-1);
  1478.             for j := 0 to repcount-1 do
  1479.             begin
  1480.                if y >= 0 then FColorValues^[y] := val;
  1481.                dec(y);
  1482.             end;
  1483.             if (i = FHeight-1) then
  1484.             begin
  1485.                while y > -1 do
  1486.                begin
  1487.                   FColorValues^[y] := val;
  1488.                   dec(y);
  1489.                end;
  1490.                break;
  1491.             end;
  1492.          end;
  1493.          repcount := 0;
  1494.          {$IFDEF COLORTEST}
  1495.          dec(Clr);
  1496.          val:= Clr;
  1497.          {$ELSE}
  1498.          val := pDispData^[index];
  1499.  if (Fy2^[i] > 0) then { Take the maximum of a set of bins }
  1500.  begin
  1501.     while (index < Fy2^[i]) do
  1502.             begin
  1503.        if (pDispData^[index] > val) then
  1504.                    val := pDispData^[index];
  1505.                inc(index);
  1506.             end;
  1507.          end;
  1508.          {$ENDIF}
  1509.       end;
  1510.       inc(repcount);
  1511.       inc(i);
  1512.    end;
  1513.    DIBCanvas.DIB_VLineMultiColor(Fx1, 0, PByte(FColorValues), FHeight);
  1514.   { for i := 0 to FHeight-1 do DIBCanvas.DIB_SetPixel(Fx1,i,FColorValues^[i]);}
  1515. end;
  1516. {-- TMMSpectrogram ------------------------------------------------------}
  1517. function TMMSpectrogram.GetFrequency(Pos: TPoint): Float;
  1518. begin
  1519.    Result := 0;
  1520.    if PtInRect(FClientRect,Pos) then
  1521.    begin
  1522.       dec(Pos.Y,FClientRect.Top);
  1523.       Result := FFreqBase+(FSampleRate/2-FFreqScaleFactor*FFReqBase)*(FHeight-Pos.Y-1)/(FHeight-1)/FFreqScaleFactor;
  1524.    end;
  1525. end;
  1526. {-- TMMSpectrogram ------------------------------------------------------}
  1527. procedure TMMSpectrogram.CalcScaleSteps;
  1528. begin
  1529.    { calc the number of steps required }
  1530.    FNumScaleSteps := Trunc(FSampleRate/2/1000*FFreqScaleFactor);
  1531.    while (FHeight div FNumScaleSteps < SCALEFONTSIZE) do
  1532.    begin
  1533.       FNumScaleSteps := FNumScaleSteps div 2;
  1534.       if FNumScaleSteps <= 1 then break;
  1535.    end;
  1536. end;
  1537. {-- TMMSpectrogram ------------------------------------------------------}
  1538. function TMMSpectrogram.GetScaleBackColor: TColor;
  1539. begin
  1540.    {$IFNDEF BUILD_ACTIVEX}
  1541.    Result := TForm(Parent).Color;
  1542.    {$ELSE}
  1543.    Result := FScaleBackColor;
  1544.    {$ENDIF}
  1545. end;
  1546. {-- TMMSpectrogram ------------------------------------------------------}
  1547. procedure TMMSpectrogram.DrawFrequencyScale;
  1548. var
  1549.    aBitmap: TBitmap;
  1550.    i, X, Y: integer;
  1551.    Text: String;
  1552.    Step: Float;
  1553. begin
  1554.    { put up the frequency scale }
  1555.    if FDrawScale then
  1556.    begin
  1557.       aBitmap := TBitmap.Create;
  1558.       try
  1559.          aBitmap.Width := SCALEWIDTH;
  1560.          aBitmap.Height := Height;
  1561.          aBitmap.Canvas.Font.Color := FScaleTextColor;
  1562.          aBitmap.Canvas.Pen.Color := FScaleLineColor;
  1563.          aBitmap.Canvas.Brush.Color := GetScaleBackColor;
  1564.          with aBitmap.Canvas do
  1565.          begin
  1566.             { Put up the frequency scale. }
  1567.             Step := (FSampleRate/2-FFreqScaleFactor*FFReqBase)/FNumScaleSteps/FFreqScaleFactor/1000;
  1568.             { draw the left side }
  1569.             FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
  1570.             X := SCALEWIDTH-1;
  1571.             MoveTo(X, Height-BevelExtend-1);
  1572.             for i := 0 to FNumScaleSteps do
  1573.             begin
  1574.                Y := Height - BevelExtend - Trunc(i * (FHeight-1)/FNumScaleSteps)-1;
  1575.                LineTo(X, Y);
  1576.                LineTo(X-3, Y);
  1577.                MoveTo(X, Y);
  1578.                if (FFreqBase > 0) or (FFreqScaleFactor > 1) then
  1579.                   Text := Format('%4.2f',[FFreqBase/1000+i*step])
  1580.                else
  1581.           Text := IntToStr(Round(FFreqBase/1000+i*step-0.05));
  1582.                TextOutAligned(aBitmap.Canvas, X-5, Y, Text,SCALEFONT,SCALEFONTSIZE,1);{ right text }
  1583.             end;
  1584.             { write right scale text }
  1585.             if (FFreqBase = 0) and (FFreqScaleFactor = 1) then
  1586.                TextOutAligned(aBitmap.Canvas, 2, Height-5,
  1587.                              'KHz', SCALEFONT,SCALEFONTSIZE,0);
  1588.             { copy to screen }
  1589.             Canvas.Draw(-3, 0, aBitmap);
  1590.             { draw the right side }
  1591.             FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
  1592.             X := 0;
  1593.             MoveTo(X, Height-BevelExtend-1);
  1594.             for i := 0 to FNumScaleSteps do
  1595.             begin
  1596.                Y := Height - BevelExtend - Trunc(i * (FHeight-1)/FNumScaleSteps)-1;
  1597.                LineTo(X, Y);
  1598.                LineTo(X+3, Y);
  1599.                MoveTo(X, Y);
  1600.                if (FFreqBase > 0) or (FFreqScaleFactor > 1) then
  1601.                   Text := Format('%4.2f',[FFreqBase/1000+i*step])
  1602.                else
  1603.           Text := IntToStr(Round(FFreqBase/1000+i*step-0.05));
  1604.                TextOutAligned(aBitmap.Canvas, X+6, Y, Text, SCALEFONT,SCALEFONTSIZE,0);{ left text }
  1605.             end;
  1606.             { write right scale text }
  1607.             if (FFreqBase = 0) and (FFreqScaleFactor = 1) then
  1608.                TextOutAligned(aBitmap.Canvas, SCALEWIDTH-19, Height-5,
  1609.                               'KHz', SCALEFONT,SCALEFONTSIZE,0);
  1610.             { copy to screen }
  1611.             Canvas.Draw((Width - SCALEWIDTH)+3, 0, aBitmap);
  1612.          end;
  1613.       finally
  1614.          aBitmap.Free;
  1615.       end;
  1616.    end;
  1617. end;
  1618. {-- TMMSpectrogram ------------------------------------------------------}
  1619. procedure TMMSpectrogram.DrawBar;
  1620. var
  1621.    i,Y: integer;
  1622.    aRect: TRect;
  1623. begin
  1624.    if (FBarWidth > 0) then
  1625.    begin
  1626.       if FAccelerate then
  1627.       with Canvas do
  1628.       begin
  1629.          Pen.Mode := pmCopy;
  1630.          Pen.Color := FBarColor;
  1631.          Pen.Width := 1;
  1632.          aRect := Rect(FClientRect.Left+Fx2,FClientRect.Top,
  1633.                        FClientRect.Left+Fx2,FClientRect.Bottom);
  1634.          MoveTo(aRect.Left, aRect.Top);
  1635.          LineTo(aRect.Left, aRect.Bottom);
  1636.          for i := 0 to FNumScaleSteps do
  1637.          begin
  1638.             Y := (BevelExtend+FHeight)-Trunc(i * (FHeight-1)/FNumScaleSteps)-1;
  1639.             SetPixel(Handle,aRect.Left, Y, FBarTickColor);
  1640.          end;
  1641.       end
  1642.       else
  1643.       with DIBCanvas do
  1644.       begin
  1645.          Pen.Mode := pmCopy;
  1646.          Brush.Color := FBarColor;
  1647.          if Fx2 > Fx1 then
  1648.          begin
  1649.             aRect := Rect(Fx1+1,0,Fx2+1,FHeight);
  1650.             FillRect(aRect);
  1651.          end
  1652.          else
  1653.          begin
  1654.             aRect := Rect(0,0,Fx2+1,FHeight);
  1655.             FillRect(aRect);
  1656.          end;
  1657.          Pen.Color := FBarTickColor;
  1658.          for i := 0 to FNumScaleSteps do
  1659.          begin
  1660.             Y := FHeight - Trunc(i * (FHeight-1)/FNumScaleSteps)-1;
  1661.             MoveTo(aRect.Left,Y);
  1662.             LineTo(aRect.Right,Y);
  1663.          end;
  1664.       end;
  1665.    end;
  1666. end;
  1667. {-- TMMSpectrogram ------------------------------------------------------}
  1668. procedure TMMSpectrogram.DrawSelection(aCanvas: TMMDIBCanvas; sStart, sEnd: Longint;
  1669.                                   sColor: TColor; Solid: Boolean);
  1670. var
  1671.    rColor: Longint;
  1672. begin
  1673.    if (sStart >= 0) and (sEnd >= 0) then
  1674.    begin
  1675.       with aCanvas do
  1676.       begin
  1677.          DIB_SetTColor(sColor);
  1678.          if Solid then
  1679.          begin
  1680.             DIB_FillRectXor(Rect(sStart,0,sEnd+1,Height));
  1681.          end
  1682.          else
  1683.          begin
  1684.             DIB_SetTColor(sColor);
  1685.             DIB_HLineDashed(sStart,sEnd+1,0);
  1686.             DIB_HLineDashed(sStart,sEnd+1,Height-1);
  1687.             DIB_VLineDashed(sStart,0,Height-1);
  1688.             DIB_VLineDashed(sEnd,0,Height-1);
  1689.          end;
  1690.       end;
  1691.    end;
  1692. end;
  1693. {-- TMMSpectrogram ------------------------------------------------------}
  1694. procedure TMMSpectrogram.DrawLocator(aCanvas: TMMDIBCanvas; aPos: Longint; aColor: TColor);
  1695. begin
  1696.    with aCanvas do
  1697.    begin
  1698.       DIB_SetTColor(aColor);
  1699.       DIB_MoveTo(aPos,0);
  1700.       DIB_LineTo(aPos,FHeight);
  1701.    end;
  1702. end;
  1703. {$IFDEF WIN32}
  1704. {-- TMMSpectrogram ------------------------------------------------------}
  1705. procedure TMMSpectrogram.DrawInfo(Pos: TPoint);
  1706. var
  1707.    Text: String;
  1708.    aRect: TRect;
  1709.    Buf: array[0..255] of Char;
  1710.    DC: HDC;
  1711.    WindowHandle: HWND;
  1712. begin
  1713.    if FShowInfoHint then
  1714.    with DIBCanvas do
  1715.    begin
  1716.       if PtInRect(FClientRect,Pos) then
  1717.       begin
  1718.          Text := Format('%2.3f KHz', [GetFrequency(Pos)/1000]);
  1719.          Font.Name := 'MS Sans Serif';
  1720.          Font.Size := 8;
  1721.          Font.Style := [];
  1722.          {$IFDEF WIN32}
  1723.          Font.Color := clInfoText;
  1724.          {$ELSE}
  1725.          Font.Color := clBlack;
  1726.          {$ENDIF}
  1727.          aRect.Left := Pos.X-BevelExtend;
  1728.          if FDrawScale then dec(aRect.Left, SCALEWIDTH);
  1729.          aRect.Top := Pos.Y-BevelExtend+15;
  1730.          aRect.Right := aRect.Left + TextWidth(Text)+4;
  1731.          aRect.Bottom := aRect.Top + TextHeight(Text)+2;
  1732.          if (aRect.Bottom > FHeight) then OffsetRect(aRect,0,-40);
  1733.          if (aRect.Right > FWidth) then OffsetRect(aRect,FWidth-aRect.Right,0);
  1734.          if (aRect.Top < 0) then
  1735.          begin
  1736.             aRect.Top := 0;
  1737.             aRect.Bottom := TextHeight(Text)+2;
  1738.          end;
  1739.          {$IFDEF TRIAL}
  1740.          {$DEFINE _HACK3}
  1741.          {$I MMHACK.INC}
  1742.          {$ENDIF}
  1743.          if (SaveDC = 0) then
  1744.          begin
  1745.             { create memory DC for save bitmap }
  1746.             SaveDC := CreateCompatibleDC(DIBCanvas.Handle);
  1747.             { create bitmap to store background }
  1748.             SaveWidth := 10*TextWidth('W')+4;
  1749.             SaveHeight := TextHeight('W')+2;
  1750.             SaveBitmap := CreateCompatibleBitmap(DIBCanvas.Handle,SaveWidth,SaveHeight);
  1751.             OldBitmap := SelectObject(SaveDC, SaveBitmap);
  1752.             OldPalette := SelectPalette(SaveDC, DIBCanvas.Palette, False);
  1753.          end
  1754.          else
  1755.             { restore background }
  1756.             BitBlt(DIBCanvas.Handle,SaveInfoPos.X,
  1757.                    SaveInfoPos.Y,SaveWidth,SaveHeight,
  1758.                    SaveDC, 0,0,SRCCOPY);
  1759.          { save background }
  1760.          BitBlt(SaveDC,0,0,SaveWidth,SaveHeight,
  1761.                 DIBCanvas.Handle,aRect.Left,aRect.Top,SRCCOPY);
  1762.          SaveInfoPos := aRect.TopLeft;
  1763.          Brush.Color := INFOCOLOR;
  1764.          Brush.Style := bsSolid;
  1765.          Pen.Color := clBlack;
  1766.          Rectangle(aRect.Left,aRect.Top,aRect.Right,aRect.Bottom);
  1767.          Brush.Style := bsClear;
  1768.          DrawText(Handle, StrPCopy(Buf, Text), -1, aRect,
  1769.                   DT_SINGLELINE  or DT_VCENTER or DT_CENTER or DT_NOPREFIX);
  1770.          Brush.Style := bsSolid;
  1771.       end
  1772.       else if (SaveDC <> 0) then
  1773.       begin
  1774.          { restore background }
  1775.          BitBlt(DIBCanvas.Handle,SaveInfoPos.X,
  1776.                    SaveInfoPos.Y,SaveWidth,SaveHeight,
  1777.                    SaveDC,0,0,SRCCOPY);
  1778.       end;
  1779.       DIB_InitDrawing;                                  { copy to screen }
  1780.       DC := GetDeviceContext(WindowHandle);
  1781.       DIBCanvas.DIB_BitBlt(DC, FClientRect,0,0);
  1782.       ReleaseDC(WindowHandle, DC);
  1783.       DIB_DoneDrawing;
  1784.    end;
  1785. end;
  1786. {$ELSE}
  1787. {-- TMMSpectrogram ------------------------------------------------------}
  1788. procedure TMMSpectrogram.DrawInfo(Pos: TPoint);
  1789. var
  1790.    Text: String;
  1791.    aRect: TRect;
  1792.    Buf: array[0..255] of Char;
  1793.    Border: integer;
  1794. begin
  1795.    if FShowInfoHint then
  1796.    with Canvas do
  1797.    begin
  1798.       if PtInRect(FClientRect,Pos) then
  1799.       begin
  1800.          Text := Format('%2.3f KHz', [GetFrequency(Pos)/1000]);
  1801.          Font.Name := 'MS Sans Serif';
  1802.          Font.Size := 8;
  1803.          Font.Style := [];
  1804.          {$IFDEF WIN32}
  1805.          Font.Color := clInfoText;
  1806.          {$ELSE}
  1807.          Font.Color := clBlack;
  1808.          {$ENDIF}
  1809.          aRect.Left := Pos.X;
  1810.          aRect.Top := Pos.Y+15;
  1811.          aRect.Right := aRect.Left + TextWidth(Text)+4;
  1812.          aRect.Bottom := aRect.Top + TextHeight(Text)+2;
  1813.          if (aRect.Bottom > Height-BevelExtend) then OffsetRect(aRect,0,-40);
  1814.          Border := BevelExtend;
  1815.          if FDrawScale then inc(Border,SCALEWIDTH);
  1816.          if (aRect.Right > Width-Border) then
  1817.              OffsetRect(aRect,Width-Border-aRect.Right,0);
  1818.          if (aRect.Top < 0) then
  1819.          begin
  1820.             aRect.Top := 0;
  1821.             aRect.Bottom := TextHeight(Text)+2;
  1822.          end;
  1823.          if (SaveDC = 0) then
  1824.          begin
  1825.             { create memory DC for save bitmap }
  1826.             SaveDC := CreateCompatibleDC(Canvas.Handle);
  1827.             { create bitmap to store background }
  1828.             SaveWidth := 10*TextWidth('W')+4;
  1829.             SaveHeight := TextHeight('W')+2;
  1830.             SaveBitmap := CreateCompatibleBitmap(Canvas.Handle,SaveWidth,SaveHeight);
  1831.             OldBitmap := SelectObject(SaveDC, SaveBitmap);
  1832.             OldPalette := SelectPalette(SaveDC, DIBCanvas.Palette, False);
  1833.          end
  1834.          else
  1835.             { restore background }
  1836.             BitBlt(Canvas.Handle,SaveInfoPos.X,
  1837.                    SaveInfoPos.Y,SaveWidth,SaveHeight,
  1838.                    SaveDC,0,0,SRCCOPY);
  1839.          { save background }
  1840.          BitBlt(SaveDC,0,0,SaveWidth,SaveHeight,
  1841.                 Canvas.Handle,aRect.Left,aRect.Top,SRCCOPY);
  1842.          SaveInfoPos := aRect.TopLeft;
  1843.          Brush.Color := INFOCOLOR;
  1844.          Brush.Style := bsSolid;
  1845.          Pen.Color := clBlack;
  1846.          Rectangle(aRect.Left,aRect.Top,aRect.Right,aRect.Bottom);
  1847.          Brush.Style := bsClear;
  1848.          DrawText(Handle, StrPCopy(Buf, Text), -1, aRect,
  1849.                   DT_SINGLELINE  or DT_VCENTER or DT_CENTER or DT_NOPREFIX);
  1850.          Brush.Style := bsSolid;
  1851.       end
  1852.       else if (SaveDC <> 0) then
  1853.       begin
  1854.          { restore background }
  1855.          BitBlt(Canvas.Handle,SaveInfoPos.X,
  1856.                    SaveInfoPos.Y,SaveWidth,SaveHeight,
  1857.                    SaveDC,0,0,SRCCOPY);
  1858.       end;
  1859.    end;
  1860. end;
  1861. {$ENDIF}
  1862. {-- TMMSpectrogram ------------------------------------------------------}
  1863. procedure TMMSpectrogram.DrawSpectrogram(ClearBackGround: Boolean);
  1864. var
  1865.    i: integer;
  1866.    aRect: TRect;
  1867. begin
  1868. //   ClearBackGround := False;
  1869. //   FNeedReset := False;
  1870.    DIBCanvas.DIB_InitDrawing;
  1871.                                                    { clear background }
  1872.    if ClearBackGround or FNeedReset then
  1873.    begin
  1874.       if FEmbossed then
  1875.          DIBCanvas.DIB_SetColor((MIN_COLOR+NUM_COLORS) div 2)
  1876.       else
  1877.          DIBCanvas.DIB_SetColor(MIN_COLOR);
  1878.       DIBCanvas.DIB_Clear;
  1879.       Fx1 := -FBarWidth;//Max(-FBarWidth,0);
  1880.       Fx2 := 0;
  1881.       if ClearBackGround and FSaveData then
  1882.       begin
  1883.          //DB_WriteStrLn(0,'Restoring Data...');
  1884.          for i := 0 to FWidth-1 do
  1885.          begin
  1886.             DrawData(Pointer(PChar(FSaveBuffer) + Fx2*(FFTLen div 2)*sizeof(Long)));
  1887.             inc(Fx1);
  1888.             if (Fx1 = FWidth) then Fx1 := 0;
  1889.             inc(Fx2);
  1890.             if (Fx2 = FWidth) then Fx2 := 0;
  1891.          end;
  1892.       end;
  1893.       if not FNeedReset and not FSaveData then
  1894.          ResetSpectrograms(Self);
  1895.    end
  1896.    else
  1897.    begin
  1898.       { now plot the data }
  1899.       DrawData(FDisplayVal);
  1900.    end;
  1901.    { copy to screen }
  1902.    if ClearBackGround or FNeedReset {or FSaveData} or not FAccelerate then
  1903.    begin
  1904.       if not FScroll or (Fx2 < FWidth) then DrawBar;
  1905.       { draw solid Selection }
  1906.       DrawSelection(DIBCanvas,FSelectStart,FSelectEnd,FSelectColor,True);
  1907.       { draw doted Selection }
  1908.       DrawSelection(DIBCanvas,FSelectStart,FSelectEnd,FSelectDotColor,False);
  1909.       { draw the locator }
  1910.       DrawLocator(DIBCanvas,FLocator,FLocatorColor);
  1911.       DIBCanvas.DIB_BitBlt(Canvas.Handle, FClientRect,0,0);
  1912.       FNeedReset := False;
  1913.    end
  1914.    else
  1915.    begin
  1916.       aRect := FClientRect;
  1917.       aRect.Left := FClientRect.Left + Fx1;
  1918.       aRect.Right := 1;
  1919.       DIBCanvas.DIB_BitBlt(Canvas.Handle,aRect,Fx1,0);
  1920.    end;
  1921.    { move the bar }
  1922.    if FScroll then
  1923.    begin
  1924.       if (Fx2 < FWidth) then
  1925.       begin
  1926.          if Accelerate then DrawBar;
  1927.          inc(Fx1);
  1928.          inc(Fx2);
  1929.       end
  1930.       else
  1931.       begin
  1932.          if Accelerate then
  1933.          begin
  1934.             {$IFNDEF BUILD_ACTIVEX}
  1935.             aRect:= BoundsRect;
  1936.             {$ELSE}
  1937.             aRect:= ClientRect;
  1938.             {$ENDIf}
  1939.             InflateRect(aRect, -BevelExtend, -BevelExtend);
  1940.             if FDrawScale then InflateRect(aRect, -SCALEWIDTH, 0);
  1941.             dec(aRect.Right,Max(FBarWidth-1,0));
  1942.             {$IFNDEF BUILD_ACTIVEX}
  1943.             ScrollWindowEx(Parent.Handle,-1,0,@aRect,@aRect,0,nil,0);
  1944.             {$ELSE}
  1945.             ScrollWindowEx(Handle,-1,0,@aRect,@aRect,0,nil,0);
  1946.             {$ENDIF}
  1947.          end
  1948.          else DIBCanvas.DIB_CopyDIBBits(biSurface,0,0,FWidth-1,FHeight,1,0);
  1949.       end;
  1950.    end
  1951.    else if not FSaveData or not ClearBackGround then
  1952.    begin
  1953.       if FAccelerate then DrawBar;
  1954.       inc(Fx1);
  1955.       if (Fx1 = FWidth) then Fx1 := 0;
  1956.       inc(Fx2);
  1957.       if (Fx2 = FWidth) then Fx2 := 0;
  1958.    end;
  1959.    DIBCanvas.DIB_DoneDrawing;
  1960. end;
  1961. {-- TMMSpectrogram ------------------------------------------------------}
  1962. Procedure TMMSpectrogram.Paint;
  1963. var
  1964.    aRect: TRect;
  1965. begin
  1966.    with Canvas do
  1967.    begin
  1968.       if FDrawScale then
  1969.       begin
  1970.          { clear the space between the scales only, to eliminate flicker }
  1971.          Brush.Color := GetScaleBackColor;
  1972.          Brush.Style := bsSolid;
  1973.          aRect := Rect(0,0,SCALEWIDTH,Height);
  1974.          aRect := Rect(SCALEWIDTH-3,0,SCALEWIDTH,Height);
  1975.          FillRect(aRect);
  1976.          aRect:= Rect(Width-SCALEWIDTH,0,Width-SCALEWIDTH+3,Height);
  1977.          FillRect(aRect);
  1978.          { make place for the scale }
  1979.          aRect := GetClientRect;
  1980.          InflateRect(aRect,-SCALEWIDTH,0);
  1981.       end
  1982.       else aRect := GetClientRect;
  1983.       { draw the Bevel }
  1984.       aRect := Bevel.PaintBevel(Canvas, aRect, True);
  1985.    end;
  1986.    { now draw the scales and the spectrogram }
  1987.    DrawFrequencyScale;
  1988.    if (csDesigning in ComponentState) {$IFDEF WIN32}or (csPaintCopy in ControlState){$ENDIF} then
  1989.        DrawSpectrogram(True)
  1990.    else
  1991.        FastDraw(DrawSpectrogram,True);
  1992.    {$IFDEF BUILD_ACTIVEX}
  1993.    if Selected then
  1994.    begin
  1995.       Canvas.Brush.Style := bsClear;
  1996.       Canvas.Pen.Color   := clRed;
  1997.       Canvas.Rectangle(0,0,Width,Height);
  1998.       Canvas.Brush.Style := bsSolid;
  1999.    end;
  2000.    {$ENDIF}
  2001. end;
  2002. {-- TMMSpectrogram ------------------------------------------------------}
  2003. procedure TMMSpectrogram.Selecting(Min, Max: Longint);
  2004. begin
  2005.    Select(Min,Max,True);
  2006.    if assigned(FOnSelecting) then FOnSelecting(Self,Min,Max);
  2007. end;
  2008. {-- TMMSpectrogram ------------------------------------------------------}
  2009. procedure TMMSpectrogram.SelectEnd(Min, Max: Longint);
  2010. begin
  2011.    Select(Min,Max,False);
  2012.    if assigned(FOnSelectEnd)then FOnSelectEnd(Self,Min,Max);
  2013. end;
  2014. {-- TMMSpectrogram ------------------------------------------------------}
  2015. function TMMSpectrogram.IsLocator(X: integer): Boolean;
  2016. begin
  2017.    Result := (FLocator >= 0) and
  2018.              (X >= (FLocator+BevelExtend)-3) and
  2019.              (X <= (FLocator+BevelExtend)+3) and
  2020.              (X >= 0) and (X <= Width);
  2021. end;
  2022. {-- TMMSpectrogram ------------------------------------------------------}
  2023. function TMMSpectrogram.IsSelectStart(X: integer): Boolean;
  2024. begin
  2025.    Result := (FSelectStart >= 0) and
  2026.              (X >= (FSelectStart+BevelExtend)-3) and
  2027.              (X <= (FSelectStart+BevelExtend)+2) and
  2028.              (X >= 0) and (X <= Width);
  2029. end;
  2030. {-- TMMSpectrogram ------------------------------------------------------}
  2031. function TMMSpectrogram.IsSelectEnd(X: integer): Boolean;
  2032. begin
  2033.    Result := (FSelectEnd >= 0) and
  2034.              (X >= (FSelectEnd+BevelExtend)-2) and
  2035.              (X <= (FSelectEnd+BevelExtend)+3) and
  2036.              (X >= 0) and (X <= Width);
  2037. end;
  2038. {-- TMMSpectrogram ------------------------------------------------------}
  2039. function TMMSpectrogram.IsInSelection(X: integer): Boolean;
  2040. begin
  2041.    Result := (FSelectStart >= 0) and (FSelectEnd >= 0) and
  2042.              (X >= (FSelectStart+BevelExtend)) and
  2043.              (X <= (FSelectEnd+BevelExtend)) and
  2044.              (X >= 0) and (X <= Width);
  2045. end;
  2046. var
  2047.    StartOrigin,Origin,
  2048.    MinShift,
  2049.    MaxShift: Longint;
  2050.    Moving  : Boolean;
  2051. {-- TMMSpectrogram ------------------------------------------------------}
  2052. procedure TMMSpectrogram.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  2053. var
  2054.    aRect: TRect;
  2055. begin
  2056.    if not (csDesigning in ComponentState) and Enabled then
  2057.    begin
  2058.       if (Button = mbLeft) and FShowInfo then
  2059.       begin
  2060.          aRect.TopLeft := ClientToScreen(FClientRect.TopLeft);
  2061.          aRect.BottomRight := ClientToScreen(FClientRect.BottomRight);
  2062.          ClipCursor(@aRect);
  2063.          FShowInfoHint := True;
  2064.          { maybe there is a hint, hide it }
  2065.          if ShowHint then
  2066.          begin
  2067.             FOldShowHint := ShowHint;
  2068.             ShowHint := False;
  2069.             Application.CancelHint;
  2070.             Update;
  2071.          end
  2072.          else FOldShowHint := False;
  2073.          {$IFDEF WIN32}
  2074.          { we must save the screen in our bitmap }
  2075.          DIBCanvas.CopyRect(Rect(0,0,FWidth,FHeight),Canvas,FClientRect);
  2076.          {$ENDIF}
  2077.          DrawInfo(Point(X,Y));
  2078.       end
  2079.       else if (Button = mbRight) and FUseSelection and not FLocked and not FDrawing then
  2080.       begin
  2081.          aRect := BeveledRect;
  2082.          if PtInRect(aRect,Point(X,Y)) then
  2083.          begin
  2084.             FDrawing := True;
  2085.             Moving := False;
  2086.             MouseCapture := True;
  2087.             if IsSelectStart(X) then
  2088.             begin
  2089.                Origin := FSelectEnd;
  2090.             end
  2091.             else if IsSelectEnd(X) then
  2092.             begin
  2093.                Origin := FSelectStart;
  2094.             end
  2095.             else if IsInSelection(X) then
  2096.             begin
  2097.                Windows.SetCursor(Screen.Cursors[crsHand4]);
  2098.                Moving := True;
  2099.                Origin := X-BevelExtend;
  2100.                MinShift := -(FSelectStart);
  2101.                MaxShift := (FWidth-1)-FSelectEnd;
  2102.             end
  2103.             else
  2104.             begin
  2105.                Windows.SetCursor(Screen.Cursors[crSizeWE]);
  2106.                Origin := X-BevelExtend;
  2107.                { clear old selection }
  2108.                Selecting(-1,-1);
  2109.                Selecting(Origin,Origin+1);
  2110.             end;
  2111.             StartOrigin := Origin;
  2112.          end;
  2113.       end;
  2114.    end;
  2115.    inherited MouseDown(Button, Shift, X, Y);
  2116. end;
  2117. {-- TMMSpectrogram ------------------------------------------------------}
  2118. procedure TMMSpectrogram.MouseMove(Shift: TShiftState; X, Y: Integer);
  2119. var
  2120.    NewPos,Diff: Longint;
  2121. begin
  2122.    if FShowInfo and FShowInfoHint then
  2123.    begin
  2124.       inherited MouseMove(Shift, X, Y);
  2125.       DrawInfo(Point(X,Y));
  2126.    end
  2127.       else if FUseSelection and not FLocked and FDrawing then
  2128.    begin
  2129.       X := Limit(X,BevelExtend,(Width-BevelExtend)-1);
  2130.       if Moving then
  2131.       begin
  2132.          Diff := Limit((X-BevelExtend)-Origin,MinShift,MaxShift);
  2133.          Selecting(FSelectStart+Diff,FSelectEnd+Diff);
  2134.          Origin := Origin + Diff;
  2135.          MinShift := MinShift - Diff;
  2136.          MaxShift := MaxShift - Diff;
  2137.       end
  2138.       else
  2139.       begin
  2140.          NewPos := Limit(X-BevelExtend,0,Width-2*BevelExtend);
  2141.          Selecting(Origin,NewPos);
  2142.       end;
  2143.       inherited MouseMove(Shift, X, Y);
  2144.    end
  2145.    else if FUseSelection and not FLocked then
  2146.    begin
  2147.       inherited MouseMove(Shift, X, Y);
  2148.       if IsSelectStart(X) or IsSelectEnd(X) then
  2149.          Cursor := crSizeWE
  2150.       else if IsInSelection(X) then
  2151.          Cursor := crsHand3
  2152.       else if (Cursor=crSizeWE)or(Cursor=crsHand3)or(Cursor=crsZoom1) then
  2153.          Cursor := crDefault;
  2154.    end
  2155.    else
  2156.    begin
  2157.       inherited MouseMove(Shift, X, Y);
  2158.       if (Cursor <> crCross) and (Cursor <> crHourGlass) then
  2159.           Cursor := crDefault;
  2160.    end;
  2161. end;
  2162. {-- TMMSpectrogram ------------------------------------------------------}
  2163. procedure TMMSpectrogram.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  2164. var
  2165.    P: TPoint;
  2166. begin
  2167.    if (Button = mbLeft) and FShowInfoHint then
  2168.    begin
  2169.       { restore background }
  2170.       if FEnabled then DrawInfo(Point(-1,-1));
  2171.       if (SaveDC <> 0) then
  2172.       begin
  2173.          SelectObject(SaveDC, OldBitmap);
  2174.          DeleteObject(SaveBitmap);
  2175.          SelectObject(SaveDC, OldPalette);
  2176.          SaveBitmap := 0;
  2177.          DeleteDC(SaveDC);
  2178.          SaveDC := 0;
  2179.       end;
  2180.       FShowInfoHint := False;
  2181.       ClipCursor(nil);
  2182.       ShowHint := FOldShowHint;
  2183.    end
  2184.    else if (Button = mbRight) and FDrawing then
  2185.    begin
  2186.       FDrawing := False;
  2187.       MouseCapture := False;
  2188.       if (FSelectEnd = FSelectStart+1) or (FSelectEnd = FSelectStart-1) then
  2189.       begin
  2190.          Selecting(-1,-1);
  2191.       end;
  2192.       SelectEnd(FSelectStart,FSelectEnd);
  2193.    end;
  2194.    inherited MouseUp(Button, Shift, X, Y);
  2195. end;
  2196. end.