MMSpectr.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:114k
- {========================================================================}
- {= (c) 1995-98 SwiftSoft Ronald Dittrich =}
- {========================================================================}
- {= All Rights Reserved =}
- {========================================================================}
- {= D 01099 Dresden = Fax.: +49(0)351-8037944 =}
- {= Loewenstr.7a = info@swiftsoft.de =}
- {========================================================================}
- {= Actual versions on http://www.swiftsoft.de/index.html =}
- {========================================================================}
- {= This code is for reference purposes only and may not be copied or =}
- {= distributed in any format electronic or otherwise except one copy =}
- {= for backup purposes. =}
- {= =}
- {= No Delphi Component Kit or Component individually or in a collection=}
- {= subclassed or otherwise from the code in this unit, or associated =}
- {= .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed =}
- {= without express permission from SwiftSoft. =}
- {= =}
- {= For more licence informations please refer to the associated =}
- {= HelpFile. =}
- {========================================================================}
- {= $Date: 19.11.98 - 22:31:13 $ =}
- {========================================================================}
- Unit MMSpectr;
- {$C FIXED PRELOAD PERMANENT}
- {$I COMPILER.INC}
- interface
- uses
- {$IFDEF WIN32}
- Windows,
- {$ELSE}
- WinTypes,
- WinProcs,
- {$ENDIF}
- SysUtils,
- Messages,
- Classes,
- Graphics,
- Controls,
- Forms,
- Menus,
- MMSystem,
- MMUtils,
- MMObj,
- MMTimer,
- MMString,
- MMMath,
- MMMulDiv,
- MMFFT,
- MMRegs,
- MMPCMSup,
- MMDIBCv;
- const
- {$IFDEF CBUILDER3} {$EXTERNALSYM SCALEHEIGHT} {$ENDIF}
- SCALEHEIGHT = 40;
- {$IFDEF CBUILDER3} {$EXTERNALSYM SCALEWIDTH} {$ENDIF}
- SCALEWIDTH = 32;
- {$IFDEF CBUILDER3} {$EXTERNALSYM SCALEFONT} {$ENDIF}
- SCALEFONT = 'ARIAL';
- SCALEFONTSIZE : integer = 10;
- SCROLLDISTANCE : integer = 2;
- INFOCOLOR : TCOLOR = clWhite;
- {$IFDEF CBUILDER3} {$EXTERNALSYM MAX_FFTLEN} {$ENDIF}
- MAX_FFTLEN = 4096; { Define the maximum FFT buffer length. }
- {$IFDEF CBUILDER3} {$EXTERNALSYM MAXDECAYCOUNT} {$ENDIF}
- MAXDECAYCOUNT = 32; { Maximum amount of temporal averaging allowed }
- type
- EMMSpectrumError = class(Exception);
- TMMSpectrumKind = (skDots, skLines, skVLines, skBars, skPeaks, skScroll);
- TMMSpectrumGain = (sgNone,sg3db,sg6db,sg9db,sg12db);
- TMMSpectrumDrawBar = procedure(Sender: TObject; DIB: TMMDIBCanvas; Rect: TRect; nSpots,Peak: integer) of object;
- TMMSpectrumClear = procedure(Sender: TObject; DIB: TMMDIBCanvas; Rect: TRect) of object;
- TMMSpectrumGetXScale = procedure(Sender: TObject; pX1,pX2: PIntArray) of object;
- { array for uniform decay mode values }
- PDataBuf = ^TDataBuf;
- TDataBuf = array[0..MAXDECAYCOUNT-1] of PLongArray;
- TPeak = record { record for peak values }
- Freq : Float;
- Amp : Float;
- db : Float;
- { !! internal for peak display, do not use !! }
- Amplitude: Long; { peak amplitude found }
- Index : integer; { bin number of the peak amplitude }
- X : integer; { the X value for the Peak }
- end;
- TDrawVal = record { record for display values to draw }
- Left : integer; { left X1 for this set of bin's }
- Right : integer; { right X2 for this set of bin's }
- Value : Longint; { the (Y) value for this set of bin's }
- Peak : integer; { the peak value for this set of bin's }
- PeakCnt : integer; { internal peak counter for timing }
- end;
- PDrawArray = ^TDrawArray;
- TDrawArray = array[0..DebugCount] of TDrawVal;
- {-- TMMSpectrum -----------------------------------------------------}
- TMMSpectrum = class(TMMDIBGraphicControl)
- private
- FTimerID : Longint; { timer for peak handling }
- FBarDIB : TMMDIBCanvas;{ bitmap for inactive bars }
- {$IFDEF WIN32}
- FpFFT : PFFTReal; { the instance for the FFT }
- {$ELSE}
- FFT : TMMFFT; { the object that performs the FFT }
- {$ENDIF}
- FFFTData : PSmallArray;{ Array for FFT data }
- FWinBuf : PIntArray; { Array storing windowing function }
- FDataBuf : PDataBuf; { Memory for averaging mode }
- FYBase : PLongArray; { Scaling offset for log calculations }
- FLastVal_F : PFloatArray;{ Last value buffer for exp decay mode }
- FLastVal : PLongArray; { Last value buffer for uniform averaging}
- FDisplayVal : PLongArray; { Array storing display values }
- Fx1 : PIntArray; { Array of bin #'s displayed }
- Fx2 : PIntArray; { Array of terminal bin #'s }
- FYScale : PIntArray; { scaling factors }
- FDrawVal : PDrawArray; { array with the rect's / points to draw }
- FFTLen : integer; { Number of points for FFT }
- FSampleRate : Longint; { A/D sampling rate }
- FLogFreq : Boolean; { true for log-based frequency scale }
- FLogAmp : Boolean; { true for log-based amplitude scale }
- Fys : Float; { set for max of y-axis }
- FLogBase : integer; { base of log scale (default=6 = -60db) }
- FLogs : integer; { for max of log scale (default=0 = 0db) }
- FGain3db : integer; { indicating 3db/octave scale factor gain}
- FDeriv : integer; { doing differencing for 6db/octave gain }
- FRefFreq : integer; { ref. frequency for n db/octave gains }
- FPeak : TPeak; { the current peak value over all frequ. }
- FWindow : TMMFFTWindow;{ selected window function }
- FDecay : integer; { the current Decay value }
- FDecayMode : TMMDecayMode;{ indicating decay mode on/off }
- FDecayFactor : Float; { Geometric decay factor }
- FDecayCount : integer; { Temporal averaging parameter }
- FDecayCntAct : integer; { Total number of bins averaged so far }
- FMaxDecayCount: integer; { Maximum value for the decay count }
- FDecayPtr : integer; { index for cur. averag. buffer location }
- FShift : integer;{ Number of bits for gain shift }
- FLogScaleFactor : Float; { Scaling factor for log values }
- FDispScaleFactor : Float; { Display scalefactor for log values }
- FFreqScaleFactor : Float; { Scalefactor for inc. the horiz. scale }
- FFreqBase : Float; { Base frequency for the display }
- FKind : TMMSpectrumKind;{ draw as dots,bars,lines,vlines }
- FEnabled : Boolean; { Enable or disable Spectrum }
- FBar1Color : TColor; { Farbe f黵 die Punkte im 1. Abschnitt }
- FBar2Color : TColor; { Farbe f黵 die Punkte im 2. Abschnitt }
- FBar3Color : TColor; { Farbe f黵 die Punkte im 3. Abschnitt }
- FInact1Color : TColor; { foreColor for inactive spots 1 }
- FInact2Color : TColor; { foreColor for inactive spots 2 }
- FInact3Color : TColor; { foreColor for inactive spots 3 }
- FScaleTextColor: TColor; { the text color for the scale }
- FScaleLineColor: TColor; { the line color for the scale }
- FGridColor : TColor; { the grid color }
- FScaleBackColor: TColor; { background color for the scale }
- FInactiveDoted : Boolean; { draw the inactive spots doted }
- FActiveDoted : Boolean; { draw the active spots doted }
- FPoint1 : integer; { Schwelle von 1. zu 2. Abschnitt % }
- FPoint2 : integer; { Schwelle von 2. zu 3. Abschnitt % }
- FPoint1Spot : integer; { on which spot begins next color }
- FPoint2Spot : integer; { on which spot begins next color }
- FSpotSpace : integer; { vertical space between spots }
- FSpotHeight : integer; { the spot height in pixel }
- FSpace : integer; { horizontal between the bars }
- FFirstSpace : integer; { the space before the first spot }
- FNumSpots : integer; { number of Spots }
- FNumPeaks : integer; { number of spots displayed as peak }
- FPeakDelay : integer; { the delay for the peak spots }
- FPeakSpeed : integer; { the decrease speed for the peak spots }
- FDisplayPeak : Boolean; { show the highest frequency or not }
- FDrawInactive : Boolean; { draw the inactive spots or not }
- FBits : TMMBits; { bit8 or bit16 }
- FChannel : TMMChannel;{ chBoth, chLeft or chRigth }
- FMode : TMMMode; { mMono, mStereo or mQuadro }
- FBytes : Longint; { calculated data bytes per spectrum }
- FGain : TMMSpectrumGain;{ Amount of db/octave gain }
- FOldShowHint : Boolean; { saved ShowHint propertie }
- FShowInfo : Boolean; { show the freq/amp info or not }
- FShowInfoHint : Boolean; { mouse is down, show the info }
- FDrawFreqScale : Boolean; { draw the horiz scale or not }
- FDrawAmpScale : Boolean; { draw the vert scale or not }
- FDrawGrid : Boolean; { draw the grid or not }
- FWidth : integer; { calculated width without border }
- FHeight : integer; { calculated height without border }
- FClientRect : TRect; { calculated beveled Rect }
- { Events }
- FOnNeedData : TNotifyEvent;
- FOnGainOverflow : TNotifyEvent;
- FOnPcmOverflow : TNotifyEvent;
- FOnDrawBar : TMMSpectrumDrawBar;
- FOnClearBackground: TMMSpectrumClear;
- FOnGetXScale : TMMSpectrumGetXScale;
- procedure CreateDataBuffers(Length: integer);
- procedure FreeDataBuffers;
- procedure CreateArrays(Size: integer);
- procedure FreeArrays;
- procedure ResetDecayBuffers;
- procedure ResetPeakValues;
- procedure XRangeCheck;
- procedure SetupXScale;
- procedure SetupLogScales;
- procedure SetupLinScales;
- procedure CalcNumSpots;
- procedure CalcMagnitude(MagnitudeForm: Boolean);
- procedure CalcDisplayValues;
- procedure SetBytesPerSpectrum;
- procedure InitializeData;
- procedure NeedData;
- procedure DrawFrequencyScale(Dummy: Boolean);
- procedure DrawAmplitudeScale;
- procedure SetLocalVariables(DIB: TMMDIBCanvas);
- procedure InitLocalVariables;
- procedure DrawPeakValue;
- {$IFDEF USEASM}
- procedure DrawBar(X1,X2,nSpots,Peak: integer);{$IFDEF WIN32}pascal;{$ENDIF}
- procedure DrawBarPeak(X1,X2,nSpots,Peak: integer);{$IFDEF WIN32}pascal;{$ENDIF}
- procedure PointedLineTo(X,Y: integer; Pointed: Boolean);{$IFDEF WIN32}pascal;{$ENDIF}
- {$ENDIF}
- procedure DrawBar_Native(X1,X2,nSpots,Peak: integer);
- procedure DrawBarPeak_Native(X1,X2,nSpots,Peak: integer);
- procedure DrawGrids;
- procedure DrawInfo(Pos: TPoint);
- procedure DrawAsDots;
- procedure DrawAsLines;
- procedure DrawAsVLines;
- procedure DrawAsBars;
- procedure DrawInactiveSpots;
- procedure DrawSpectrum(Clear: Boolean);
- procedure SetOnDrawBar(aValue: TMMSpectrumDrawBar);
- procedure AdjustSize(var W, H: Integer);
- procedure AdjustBounds;
- procedure SetFFTLen(aLength: integer);
- procedure SetWindow(aValue: TMMFFTWindow);
- procedure SetLogFreq(aValue: Boolean);
- procedure SetLogAmp(aValue: Boolean);
- procedure SetKind(aValue: TMMSpectrumKind);
- procedure SetDecayMode(aValue: TMMDecayMode);
- procedure SetDecay(aValue: integer);
- procedure SetVertScale(aValue: integer);
- function GetVertScale: integer;
- procedure SetFreqScale(aValue: integer);
- function GetFreqScale: integer;
- procedure SetDrawFreqScale(aValue: Boolean);
- procedure SetDrawAmpScale(aValue: Boolean);
- procedure SetDrawGrid(aValue: Boolean);
- procedure SetEnabled(aValue: Boolean);
- procedure SetColors(Index: Integer; Value: TColor);
- procedure SetPoints(Index, aValue: integer);
- procedure SetSpotSpace(aValue: integer);
- procedure SetSpotHeight(aValue: integer);
- procedure SetSpace(aValue: integer);
- procedure SetNumPeaks(aValue: integer);
- procedure SetPeakDelay(aValue: integer);
- procedure SetPeakSpeed(aValue: integer);
- procedure SetDisplayPeak(aValue: Boolean);
- procedure SetPCMWaveFormat(wf: TPCMWaveFormat);
- function GetPCMWaveFormat: TPCMWaveFormat;
- procedure SetBits(aValue: TMMBits);
- procedure SetChannel(aValue: TMMChannel);
- procedure SetMode(aValue: TMMMode);
- procedure SetSampleRate(aValue: Longint);
- procedure SetRefFreq(aValue: integer);
- procedure SetGain(aValue: TMMSpectrumGain);
- procedure SetDrawInactive(aValue: Boolean);
- procedure SetInactiveDoted(aValue: Boolean);
- procedure SetActiveDoted(aValue: Boolean);
- function GetScaleBackColor: TColor;
- function GetPeak: TPeak;
- procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
- protected
- procedure ChangeDesigning(aValue: Boolean); override;
- procedure SetBPP(aValue: integer); override;
- procedure Paint; override;
- procedure Loaded; override;
- procedure GainOverflow; dynamic;
- procedure PcmOverflow; dynamic;
- procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); override;
- procedure Changed; override;
- procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
- procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
- procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function GetOptimalWidth(aWidth: integer): integer;
- procedure ForceRescale;
- function GetFrequencyAtPos(Pos: TPoint): Float;
- function GetAmplitudeAtPos(Pos: TPoint): Float;
- procedure RefreshPCMData(PCMData: Pointer);
- procedure RefreshFFTData(FFTData: Pointer);
- procedure RefreshMagnitudeData(MagData: Pointer);
- procedure ResetData;
- property Peak: TPeak read GetPeak;
- property BytesPerSpectrum: Longint read FBytes;
- property PCMWaveFormat: TPCMWaveFormat read GetPCMWaveFormat write SetPCMWaveFormat;
- property FFTData: PSmallArray read FFFTData;
- published
- { Events }
- property OnClick;
- property OnDblClick;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnDragDrop;
- property OnDragOver;
- property OnEndDrag;
- property OnStartDrag;
- property OnGetXScale: TMMSpectrumGetXScale read FOnGetXScale write FOnGetXScale;
- property OnNeedData: TNotifyEvent read FOnNeedData write FOnNeedData;
- property OnDrawBar: TMMSpectrumDrawBar read FOnDrawBar write SetOnDrawBar;
- property OnClearBackground: TMMSpectrumClear read FOnClearBackground write FOnClearBackground;
- property OnGainOverflow: TNotifyEvent read FOnGainOverflow write FOnGainOverflow;
- property OnPcmOverflow: TNotifyEvent read FOnPcmOverflow write FOnPcmOverflow;
- property Align;
- property Bevel;
- property BackGroundDIB;
- property UseBackGroundDIB;
- property PaletteRealize;
- property Color default clBlack;
- property Cursor default crCross;
- property ParentShowHint;
- property ParentColor default False;
- property PopupMenu;
- property Visible;
- property ShowHint;
- property ShowInfo: Boolean read FShowInfo write FShowInfo default True;
- property Enabled: Boolean read FEnabled write SetEnabled default True;
- property DrawFreqScale: Boolean read FDrawFreqScale write SetDrawFreqScale default False;
- property DrawAmpScale: Boolean read FDrawAmpScale write SetDrawAmpScale default False;
- property DrawGrid: Boolean read FDrawGrid write SetDrawGrid default False;
- property Height default 89;
- property Width default 194;
- property Space: integer read FSpace write SetSpace default 1;
- property SpotSpace: integer read FSpotSpace write SetSpotSpace default 1;
- property SpotHeight: integer read FSpotHeight write SetSpotHeight default 1;
- property Bar1Color: TColor index 0 read FBar1Color write SetColors default clAqua;
- property Bar2Color: TColor index 1 read FBar2Color write SetColors default clAqua;
- property Bar3Color: TColor index 2 read FBar3Color write SetColors default clRed;
- property Inactive1Color: TColor index 3 read FInact1Color write SetColors default clTeal;
- property Inactive2Color: TColor index 4 read FInact2Color write SetColors default clTeal;
- property Inactive3Color: TColor index 5 read FInact3Color write SetColors default clMaroon;
- property ScaleTextColor: TColor index 6 read FScaleTextColor write SetColors default clBlack;
- property ScaleLineColor: TColor index 7 read FScaleLineColor write SetColors default clBlack;
- property GridColor: TColor index 8 read FGridColor write SetColors default clGray;
- {$IFDEF BUILD_ACTIVEX}
- property ScaleBackColor: TColor index 9 read FScaleBackColor write SetColors default clBtnFace;
- {$ENDIF}
- property Point1: integer index 0 read FPoint1 write SetPoints default 50;
- property Point2: integer index 1 read FPoint2 write SetPoints default 85;
- property DrawInactive: Boolean read FDrawInactive write SetDrawInactive default True;
- property InactiveDoted: Boolean read FInactiveDoted write SetInactiveDoted default False;
- property ActiveDoted: Boolean read FActiveDoted write SetActiveDoted default False;
- property Mode: TMMMode read FMode write SetMode default mMono;
- property BitLength: TMMBits read FBits write SetBits default b8bit;
- property Channel: TMMChannel read FChannel write SetChannel default chBoth;
- property SampleRate: Longint read FSampleRate write SetSampleRate default 11025;
- property RefFreq: integer read FRefFreq write SetRefFreq default 1000;
- property Gain: TMMSpectrumGain read FGain write SetGain default sgNone;
- property FFTLength: integer read FFTLen write SetFFTLen default 128;
- property LogFreq: Boolean read FLogFreq write SetLogFreq default False;
- property LogAmp: Boolean read FLogAmp write SetLogAmp default False;
- property Kind: TMMSpectrumKind read FKind write SetKind default skBars;
- property Window: TMMFFTWindow read FWindow write SetWindow default fwHamming;
- property DecayMode: TMMDecayMode read FDecayMode write SetDecayMode default dmNone;
- property Decay: integer read FDecay write SetDecay default 1;
- property VerticalScale: integer read GetVertScale write SetVertScale default 100;
- property FrequencyScale: integer read GetFreqScale write SetFreqScale default 1;
- property NumPeaks: integer read FNumPeaks write SetNumPeaks default 1;
- property PeakDelay: integer read FPeakDelay write SetPeakDelay default 20;
- property PeakSpeed: integer read FPeakSpeed write SetPeakSpeed default 0;
- property DisplayPeak: Boolean read FDisplayPeak write SetDisplayPeak default False;
- end;
- implementation
- uses Consts;
- {.$DEFINE USE_INTEGER_CODE}
- {$IFDEF USE_INTEGER_CODE}
- const
- { Table for approximating the logarithm.
- { These values are round(log2(index/16)*8192) for index=0:31 }
- _ln: array[0..31] of Long = (-131072,-32768,-24576,-19784,-16384,
- -13747,-11592,-9770,-8192,-6800,-5555,
- -4428,-3400,-2454,-1578,-763,0,716,1392,
- 2031,2637,3214,3764,4289,4792,5274,5738,
- 6184,6614,7029,7429,7817);
- {$ENDIF}
- var
- { local variables for fast asm drawing }
- _DIB : TMMDIBCanvas;
- _DIB_ORIENT : integer;
- _biBits : Longint;
- _biBPP : Longint;
- _biWidth : Longint;
- _biHeight : Longint;
- _biScanWidth : Longint;
- _biLineDiff : Longint;
- _biColor : Longint;
- _biSurface : Pointer;
- _biPenPos : TPoint;
- _biClipRect : TRect;
- _Bar1Color : Cardinal;
- _Bar2Color : Cardinal;
- _Bar3Color : Cardinal;
- _Inact1Color : Cardinal;
- _Inact2Color : Cardinal;
- _Inact3Color : Cardinal;
- _NumSpots : integer;
- _NumPeaks : integer;
- _SpotHeight : Longint;
- _SpotSpace : Longint;
- _FirstSpace : Longint;
- _Space : Longint;
- _Point1Spot : integer;
- _Point2Spot : integer;
- _ActiveDoted : Boolean;
- _InactiveDoted: Boolean;
- _DrawInactive : Boolean;
- _Offset : integer;
- const
- SaveDC : HDC = 0;
- SaveBitmap : HBitmap = 0;
- SaveWidth : integer = 0;
- SaveHeight : integer = 0;
- SaveInfoPos : TPoint = (X:0;Y:0);
- OldBitmap : HBitmap = 0;
- {------------------------------------------------------------------------}
- procedure TimeCallBack(uTimerID, dwUser: Longint);export;
- var
- j: integer;
- begin
- if (dwUser <> 0) then
- with TMMSpectrum(dwUser) do
- begin
- if (FNumPeaks < 1) or (FDrawVal = nil) or FShowInfoHint then exit;
- j := 0;
- while (FDrawVal^[j].Left <> -1) and (j < FWidth) do
- with FDrawVal^[j] do
- begin
- if (Peak > 0) then
- begin
- dec(PeakCnt);
- if PeakCnt <= 0 then
- begin
- if (FPeakSpeed = 0) then
- begin
- Peak := 0; { clear the peak hold spot }
- PeakCnt := 0;
- end
- else
- begin
- dec(Peak); { dec the peak spot }
- PeakCnt := FPeakSpeed;
- end;
- end;
- end;
- inc(j);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- constructor TMMSpectrum.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ControlState := ControlState + [csCreating];
- FTimerID := 0;
- CreateDataBuffers(MAX_FFTLEN);
- FBarDIB := TMMDIBCanvas.Create(Self);
- {$IFDEF WIN32}
- FpFFT := InitRealFFT(8);
- {$ELSE}
- FFT := TMMFFT.Create;
- {$ENDIF}
- FFTLen := 8;
- FWindow := fwHamming;
- FSampleRate := 11025;
- FLogFreq := False;
- FLogAmp := False;
- FFreqScaleFactor := 1.0;
- FFreqBase := 1.0;
- Fys := 1.0;
- FLogBase := 6;
- FLogs := 0;
- FGain3db := 0;
- FDeriv := 0;
- FRefFreq := 1000;
- FDecay := 1;
- FDecayMode := dmNone;
- FDecayFactor := 0.0001;
- FDecayCount := 1;
- FDecayCntAct := 0;
- FDecayPtr := 0;
- FNumPeaks := 1;
- FPeakDelay := 20;
- FPeakSpeed := 0;
- FDisplayPeak := False;
- FKind := skBars;
- FEnabled := True;
- FBar1Color := clAqua;
- FBar2Color := clAqua;
- FBar3Color := clRed;
- FInact1Color := clTeal;
- FInact2Color := clTeal;
- FInact3Color := clMaroon;
- FScaleTextColor := clBlack;
- FScaleLineColor:= clBlack;
- FScaleBackColor:= clBtnFace;
- FGridColor := clGray;
- FPoint1 := 50;
- FPoint2 := 85;
- FInactiveDoted := False;
- FActiveDoted := False;
- FSpace := 1;
- FSpotSpace := 1;
- FSpotHeight := 1;
- FChannel := chBoth;
- FBits := b8bit;
- FMode := mMono;
- FGain := sgNone;
- FDrawInactive := True;
- FDrawFreqScale := False;
- FDrawAmpScale := False;
- FDrawGrid := False;
- FDrawVal := nil;
- FShowInfoHint := False;
- FShowInfo := True;
- Color := clBlack;
- SetBounds(0,0,194,89);
- Cursor := crCross;
- ControlState := ControlState - [csCreating];
- FFTLength := 128;
- if not (csDesigning in ComponentState) then
- begin
- { create the peak timer }
- FTimerID := MMTimeSetEvent(25,False,TimeCallBack,Longint(Self));
- end;
- ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
- if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Destructor TMMSpectrum.Destroy;
- begin
- if (FTimerID <> 0) then
- begin
- { destroy the peak timer }
- MMTimeKillEvent(FTimerID);
- end;
- FreeDataBuffers;
- FreeArrays;
- {$IFDEF WIN32}
- DoneRealFFT(FpFFT);
- {$ELSE}
- FFT.Free;
- {$ENDIF}
- FBarDIB.Free;
- inherited Destroy;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.ChangeDesigning(aValue: Boolean);
- begin
- inherited ChangeDesigning(aValue);
- if not (csDesigning in ComponentState) then
- begin
- { create the peak timer }
- if (FTimerID = 0) then
- FTimerID := MMTimeSetEvent(25,False,TimeCallBack,Longint(Self));
- InitializeData;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetBPP(aValue: integer);
- begin
- if (aValue <> BitsPerPixel) then
- begin
- if (aValue <> 8) and (aValue <> 24) then
- raise EMMDIBError.Create('Bitlength not supported yet');
- FBarDIB.BitsPerPixel := aValue;
- DIBCanvas.BitsPerPixel := aValue;
- DrawInactiveSpots;
- Invalidate;
- end;
- // inherited SetBPP(aValue);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.GainOverflow;
- begin
- if Assigned(FOnGainOverflow) then FOnGainOverflow(Self);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.PcmOverflow;
- begin
- if Assigned(FOnPcmOverflow) then FOnPcmOverflow(Self);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.ResetDecayBuffers;
- var
- i, j: integer;
- begin
- FDecayPtr := 0;
- FDecayCntAct := 0; { Restart the count of number of samples taken }
- FillChar(FLastVal^, (FFTLen div 2)*sizeOf(Long),0);
- FillChar(FLastVal_F^, (FFTLen div 2)*sizeOf(Float),0);
- for i := 0 to FMaxDecayCount-1 do
- for j := 0 to (FFTLen div 2)-1 do FDataBuf^[i]^[j] := 0;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.ResetPeakValues;
- begin
- FillChar(FDrawVal^[0], FWidth * sizeOf(TDrawVal), 0);
- FillChar(FPeak, sizeOf(TPeak),0);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CreateDataBuffers(Length: integer);
- begin
- if (Length > 0) then
- begin
- FFFTData := GlobalAllocMem(Length * sizeOf(SmallInt));
- FWinBuf := GlobalAllocMem(Length * sizeOf(Integer));
- FDisplayVal:= GlobalAllocMem((Length div 2) * sizeOf(Long));
- FLastVal := GlobalAllocMem((Length div 2) * sizeOf(Long));
- FLastVal_F := GlobalAllocMem((Length div 2) * sizeOf(Float));
- FYBase := GlobalAllocMem((Length div 2) * sizeOf(Long));
- FDataBuf := GlobalAllocMem(MAXDECAYCOUNT * sizeOf(PLongArray));
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- FMaxDecayCount := 0;
- while FMaxDecayCount < MAXDECAYCOUNT do
- begin
- FDataBuf^[FMaxDecayCount] := GlobalAllocMem((Length div 2) * sizeOf(Long));
- if FDataBuf^[FMaxDecayCount] = nil then break;
- inc(FMaxDecayCount);
- end;
- if (FMaxDecayCount < 1) then OutOfMemoryError;
- FDecayCount := Min(FDecayCount, FMaxDecayCount);
- { Clear out the memory buffers }
- ResetDecayBuffers;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.FreeDataBuffers;
- var
- i: integer;
- begin
- GlobalFreeMem(Pointer(FFFTData));
- GlobalFreeMem(Pointer(FWinBuf));
- GlobalFreeMem(Pointer(FDisplayVal));
- GlobalFreeMem(Pointer(FLastVal));
- GlobalFreeMem(Pointer(FLastVal_F));
- GlobalFreeMem(Pointer(FYBase));
- if FDataBuf <> nil then
- begin
- for i := 0 to FMaxDecayCount-1 do
- if FDataBuf^[i] <> nil then GlobalFreeMem(Pointer(FDataBuf^[i]));
- GlobalFreeMem(Pointer(FDataBuf));
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CreateArrays(Size: integer);
- begin
- if (Size > 0) then
- begin
- MMTimeSuspendEvent(FTimerID);
- Fx1 := GlobalAllocMem((Size+10) * sizeOf(Integer));
- Fx2 := GlobalAllocMem((Size+10) * sizeOf(Integer));
- FYScale := GlobalAllocMem(Size * sizeOf(Integer));
- FDrawVal:= GlobalAllocMem((Size+1) * sizeOf(TDrawVal));
- FDrawVal^[Size].Left := -1; { mark the end }
- MMTimeResumeEvent(FTimerID);
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.FreeArrays;
- begin
- MMTimeSuspendEvent(FTimerID);
- GlobalFreeMem(Pointer(Fx1));
- GlobalFreeMem(Pointer(Fx2));
- GlobalFreeMem(Pointer(FYScale));
- GlobalFreeMem(Pointer(FDrawVal));
- MMTimeResumeEvent(FTimerID);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.InitializeData;
- Var
- i: integer;
- begin
- FillChar(FDisplayVal^[0], FFTLen div 2 * sizeOf(Long), 0);
- FillChar(FFFTData^[0], FFTLen * sizeOf(SmallInt), 0);
- ResetPeakValues;
- ResetDecayBuffers;
- if Enabled then
- begin
- if assigned(FOnNeedData) then FOnNeedData(Self)
- else if (csDesigning in ComponentState) then
- begin
- Randomize;
- for i := 0 to FFTLen div 2-1 do
- begin { create random data }
- FDisplayVal^[i] := Long(Random(32767));
- end;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.ResetData;
- var
- P: TPoint;
- begin
- if FShowInfoHint then
- begin
- GetCursorPos(P);
- P := ScreenToClient(P);
- Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
- end;
- InitializeData;
- Refresh;
- end;
- const
- inHandler: Longint = 0;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.NeedData;
- begin
- inc(inHandler);
- try
- if (inHandler = 1)
- {$IFDEF BUILD_ACTIVEX}
- and not Selected
- {$ENDIF} then
- begin
- if (csLoading in ComponentState) or
- (csReading in ComponentState) then exit;
- InitializeData;
- end;
- finally
- dec(inHandler);
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.ForceRescale;
- begin
- SetupXScale;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetFFTLen(aLength: integer);
- var
- Order: integer;
- begin
- aLength := MinMax(aLength,8,MAX_FFTLEN);
- { Convert FFTLen to a power of 2 }
- Order := 0;
- while aLength > 1 do
- begin
- aLength := aLength shr 1;
- inc(Order);
- end;
- if (Order > 0) then aLength := aLength shl Order;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- if (aLength <> FFTLen) then
- begin
- { re-init the FFT instance with the new FFT-length }
- {$IFDEF WIN32}
- DoneRealFFT(FpFFT);
- FpFFT := InitRealFFT(Order);
- FFTLen := aLength;
- GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
- {$ELSE}
- FFT.FFTLength := aLength;
- FFTLen := aLength;
- GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
- {$ENDIF}
- { Re-initialize the display }
- SetupXScale;
- SetBytesPerSpectrum;
- { Flush the buffers }
- NeedData;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetWindow(aValue: TMMFFTWindow);
- begin
- if (aValue <> FWindow) then
- begin
- FWindow := aValue;
- GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetSampleRate(aValue: Longint);
- begin
- if (aValue <> FSampleRate) then
- begin
- FSampleRate := MinMax(aValue, 8000,100000);
- { Re-initialize the display }
- SetupXScale;
- NeedData;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetLogFreq(aValue: Boolean);
- begin
- { Toggle between linear and logarithmic frequency scale }
- if (aValue <> FLogFreq) then
- begin
- FLogFreq := aValue;
- SetupXScale;
- NeedData;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetLogAmp(aValue: Boolean);
- begin
- { Toggle linear/logarithmic amplitude axis }
- if (aValue <> FLogAmp) then
- begin
- FLogAmp := aValue;
- if FLogAmp then SetupLogScales
- else SetupLinScales;
- NeedData;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDecayMode(aValue: TMMDecayMode);
- begin
- { Select averaging mode }
- if (aValue <> FDecayMode) then
- begin
- FDecayMode := aValue;
- { Re-initialize the buffers }
- ResetDecayBuffers;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDecay(aValue: integer);
- var
- i: integer;
- begin
- aValue := MinMax(aValue,1,16);
- if (aValue <> FDecay) then
- begin
- FDecay := aValue;
- { factor for stepUp and exponential averaging }
- FDecayFactor := 0.0001;
- for i := 0 to FDecay-1 do
- FDecayFactor := sqrt(FDecayFactor);
- { counter for uniform averaging }
- FDecayCount := MinMax(2*(aValue-1),1,MaxDecayCount);
- { Re-initialize the buffers for uniform averaging }
- if (FDecayMode = dmUniform) then ResetDecayBuffers;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetKind(aValue: TMMSpectrumKind);
- begin
- if (aValue <> FKind) then
- begin
- FKind := aValue;
- CalcNumSpots;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetEnabled(aValue: Boolean);
- begin
- if (aValue <> FEnabled) then
- begin
- FEnabled := aValue;
- { inherited Enabled := Value }
- if (not FEnabled) then
- begin
- ResetData;
- MMTimeSuspendEvent(FTimerID);
- end
- else
- begin
- NeedData; { init Data when in designing }
- MMTimeResumeEvent(FTimerID);
- end;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.Loaded;
- begin
- inherited Loaded;
- SetupXScale;
- NeedData;
- Invalidate;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CalcNumSpots;
- begin
- FSpotHeight := Max(FSpotHeight, 1);
- FNumSpots := (FHeight+FSpotSpace) div (FSpotHeight+FSpotSpace);
- if (FNumSpots = 0) then inc(FNumSpots); { fix divisio by zerro !!! }
- FFirstSpace := (FHeight-(FNumSpots*(FSpotHeight+FSpotSpace)-FSpotSpace)) div 2;
- case FKind of
- skBars,
- skPeaks:
- begin
- { calc the spot on which the next color starts }
- FPoint1Spot := Round((FPoint1 * FNumSpots) / 100);
- FPoint2Spot := Round((FPoint2 * FNumSpots) / 100);
- end;
- skLines,
- skVLines:
- begin
- { calc the point on which the next color starts }
- FPoint1Spot := Round((FPoint1 * FHeight) / 100);
- FPoint2Spot := Round((FPoint2 * FHeight) / 100);
- end;
- skScroll:
- begin
- { calc the point on which the next color starts }
- FPoint1Spot := Round((FPoint1 * FHeight/3) / 100);
- FPoint2Spot := Round((FPoint2 * FHeight/3) / 100);
- end;
- else
- begin
- { calc the point on which the next color starts }
- FPoint1Spot := Round(FHeight-((FPoint1 * FHeight) / 100));
- FPoint2Spot := Round(FHeight-((FPoint2 * FHeight) / 100));
- end;
- end;
- { prepare the second DIB with the inactive spots }
- DrawInactiveSpots;
- { we will see anything in designer or clear out the buffers at runtime }
- NeedData;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.AdjustSize(var W, H: Integer);
- begin
- W := Max(W,2*BevelExtend+5);
- H := Max(H,2*BevelExtend+5);
- if FDrawAmpScale then
- W := Max(W,2*SCALEWIDTH+2*BevelExtend+5);
- if FDrawFreqScale then
- H := Max(H,SCALEHEIGHT+2*BevelExtend+5);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.AdjustBounds;
- var
- W, H: Integer;
- begin
- W := Width;
- H := Height;
- AdjustSize(W, H);
- if (W <> Width) or (H <> Height) then SetBounds(Left, Top, W, H)
- else Changed;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetBounds(aLeft, aTop, aWidth, aHeight: integer);
- var
- W, H: Integer;
- begin
- W := aWidth;
- H := aHeight;
- AdjustSize (W, H);
- inherited SetBounds(aLeft, aTop, W, H);
- Changed;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.Changed;
- begin
- FClientRect := Rect(0,0,Width,Height);
- { make place for the amp scale }
- if FDrawAmpScale then
- InflateRect(FClientRect, -SCALEWIDTH,0);
- { make place for the freq scale }
- if FDrawFreqScale then
- dec(FClientRect.Bottom, SCALEHEIGHT);
- { and now for the bevel }
- InflateRect(FClientRect, -Bevel.BevelExtend, -Bevel.BevelExtend);
- { save the real height and width }
- FWidth := Max(FClientRect.Right - FClientRect.Left,4);
- FHeight := Max(FClientRect.Bottom - FClientRect.Top,4);
- { adjust the dyn.array size }
- FreeArrays;
- CreateArrays(FWidth);
- { set the DIB sizes }
- DIBCanvas.SetBounds(0,0,FWidth,FHeight);
- FBarDIB.SetBounds(0,0,FWidth,FHeight);
- { recalculate the number of spots }
- CalcNumSpots;
- { calc the new bytes per Scope }
- SetBytesPerSpectrum;
- { recalc the scalings }
- SetupXScale;
- { init the data buffers }
- NeedData;
- inherited Changed;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetBytesPerSpectrum;
- begin
- FBytes := (Ord(FBits)+1) * (Ord(FMode)+1) * FFTLen;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetPCMWaveFormat(wf: TPCMWaveFormat);
- var
- pwfx: PWaveFormatEx;
- begin
- pwfx := @wf;
- if not pcmIsValidFormat(pwfx) then
- raise EMMSpectrumError.Create(LoadResStr(IDS_INVALIDFORMAT));
- SampleRate := pwfx^.nSamplesPerSec;
- BitLength := TMMBits(pwfx^.wBitsPerSample div 8 - 1);
- Mode := TMMMode(pwfx^.nChannels-1);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetPCMWaveFormat: TPCMWaveFormat;
- var
- wfx: TWaveFormatEx;
- begin
- pcmBuildWaveHeader(@wfx, (Ord(FBits)+1)*8, Ord(FMode)+1, SampleRate);
- Result := PPCMWaveFormat(@wfx)^;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetBits(aValue: TMMBits);
- begin
- if (aValue <> FBits) then
- begin
- FBits := aValue;
- SetBytesPerSpectrum;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetChannel(aValue: TMMChannel);
- begin
- if (aValue <> FChannel) then
- begin
- FChannel := aValue;
- SetBytesPerSpectrum;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetMode(aValue: TMMMode);
- begin
- if (aValue <> FMode) then
- begin
- FMode := aValue;
- SetBytesPerSpectrum;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetRefFreq(aValue: integer);
- begin
- aValue := MinMax(aValue,1,44100);
- if (aValue <> FRefFreq) then
- begin
- FRefFreq := aValue;
- if LogAmp then SetupLogScales
- else SetupLinScales;
- { Re-initialize the buffers }
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetGain(aValue: TMMSpectrumGain);
- begin
- if (aValue <> FGain) then
- begin
- FGain := aValue;
- FDeriv := Ord(FGain) div 2;
- FGain3db := Ord(FGain) - FDeriv * 2;
- if LogAmp then SetupLogScales
- else SetupLinScales;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetVertScale;
- begin
- { Change the vertical scale factor }
- aValue := MinMax(aValue, 1, 500);
- if (aValue <> GetVertScale) then
- begin
- Fys := 0.01 * aValue;
- if LogAmp then SetupLogScales
- else SetupLinScales;
- {TODO: !!!}
- (* VK_UP: Increase the vertical scale factor }
- if LogAmp then
- begin
- if (Log_Base < 10) then
- begin
- inc(Logs, 1);
- inc(Log_Base, 1);
- if (Log_Base > 10) then
- begin
- Logs := Logs - (Log_Base-10);
- Log_Base := 10;
- end;
- Setup_LogScales;
- end;
- end;
- VK_DOWN: { Decrease the vertical scale factor }
- if LogAmp then
- begin
- if (Logs > 0) then
- begin
- dec(Logs, 1);
- dec(Log_Base, 1);
- if (Logs < 0) then
- begin
- dec(Log_Base, Logs);
- Logs := 0;
- end;
- Setup_LogScales;
- end;
- end*)
- ResetPeakValues;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetVertScale: integer;
- begin
- Result := Round(Fys / 0.01);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetFreqScale(aValue: integer);
- var
- i: integer;
- begin
- aValue := MinMax(aValue,1,16);
- { Convert scale to a power of 2 }
- i := 0;
- while aValue > 1 do
- begin
- aValue := aValue shr 1;
- inc(i);
- end;
- if (i > 0) then aValue := aValue shl i;
- if (aValue <> Trunc(FFreqScaleFactor)) then
- begin
- FFreqScaleFactor := aValue;
- { Re-initialize the display }
- SetupXScale;
- NeedData;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetFreqScale: integer;
- begin
- Result := Trunc(FFreqScaleFactor);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDrawFreqScale(aValue: Boolean);
- begin
- if (aValue <> FDrawFreqScale) then
- begin
- FDrawFreqScale := aValue;
- AdjustBounds;
- Refresh;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDrawAmpScale(aValue: Boolean);
- begin
- if (aValue <> FDrawAmpScale) then
- begin
- FDrawAmpScale := aValue;
- AdjustBounds;
- Refresh;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDrawGrid(aValue: Boolean);
- begin
- if (aValue <> FDrawGrid) then
- begin
- FDrawGrid := aValue;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CMColorChanged(var Message: TMessage);
- begin
- DrawInactiveSpots;
- inherited;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetColors(Index: Integer; Value: TColor);
- begin
- case Index of
- 0: if FBar1Color = Value then exit else FBar1Color := Value;
- 1: if FBar2Color = Value then exit else FBar2Color := Value;
- 2: if FBar3Color = Value then exit else FBar3Color := Value;
- 3: if FInact1Color = Value then exit else FInact1Color := Value;
- 4: if FInact2Color = Value then exit else FInact2Color := Value;
- 5: if FInact3Color = Value then exit else FInact3Color := Value;
- 6: if FScaleTextColor = Value then exit else FScaleTextColor := Value;
- 7: if FScaleLineColor = Value then exit else FScaleLineColor := Value;
- 8: if FGridColor = Value then exit else FGridColor := Value;
- 9: if FScaleBackColor = Value then exit else FScaleBackColor := Value;
- end;
- DrawInactiveSpots;
- Invalidate;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetPoints(Index, aValue: integer);
- begin
- if (aValue>=1) and (aValue<=100) then
- begin
- case Index of
- 0: if FPoint1 = aValue then exit else FPoint1 := aValue;
- 1: if FPoint2 = aValue then exit else FPoint2 := aValue;
- end;
- CalcNumSpots;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetSpace(aValue: integer);
- begin
- if (aValue <> FSpace) AND (aValue >= 0) AND (aValue <= 5) then
- begin
- FSpace := aValue;
- ResetPeakValues;
- DrawInactiveSpots;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetSpotSpace(aValue: integer);
- begin
- if (aValue <> FSpotSpace) AND (aValue >= 0) AND (aValue <= 10) then
- begin
- FSpotSpace := aValue;
- CalcNumSpots;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.SetSpotHeight(aValue: integer);
- begin
- if (aValue <> FSpotHeight) and (aValue > 0) and (aValue <= FHeight div 3) then
- begin
- FSpotHeight := aValue;
- CalcNumSpots;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDrawInactive(aValue: Boolean);
- begin
- if (aValue <> FDrawInactive) then
- begin
- FDrawInactive := aValue;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetInactiveDoted(aValue: Boolean);
- begin
- if (aValue <> FInactiveDoted) then
- begin
- FInactiveDoted := aValue;
- DrawInactiveSpots;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetActiveDoted(aValue: Boolean);
- begin
- if (aValue <> FActiveDoted) then
- begin
- FActiveDoted := aValue;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetPeakDelay(aValue: integer);
- begin
- if (aValue <> FPeakDelay) AND (aValue >= 0) AND (aValue <= 50) then
- begin
- FPeakDelay := aValue;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK3}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetPeakSpeed(aValue: integer);
- begin
- if (aValue <> FPeakSpeed) AND (aValue >= 0) AND (aValue <= 50) then
- begin
- FPeakSpeed := aValue;
- ResetPeakValues;
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetNumPeaks(aValue: integer);
- begin
- if (aValue <> FNumPeaks) AND (aValue >= 0) AND (aValue <= 5) then
- begin
- FNumPeaks := aValue;
- ResetPeakValues;
- if (FNumPeaks = 0) then
- MMTimeSuspendEvent(FTimerID)
- else if FEnabled then
- MMTimeResumeEvent(FTimerID);
- Invalidate;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetDisplayPeak(aValue: Boolean);
- begin
- if (aValue <> FDisplayPeak) then
- begin
- FDisplayPeak := aValue;
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetPeak: TPeak;
- var
- re,im: Float;
- begin
- with FPeak do
- begin
- if (FDecayMode <> dmNone) then
- begin
- re := FDisplayVal^[index]/16.0;
- im := 0;
- end
- else
- begin
- {$IFDEF WIN32}
- re := FFFTData^[2*index];
- im := FFFTData^[2*index+1];
- {$ELSE}
- re := FFFTData^[FFT.BitReversed^[index]];
- im := FFFTData^[FFT.BitReversed^[index]+1];
- {$ENDIF}
- end;
- amp := sqrt(re*re+im*im)/32768.0;
- if (FGain3db > 0) then
- amp := amp * sqrt((index+1)*FSampleRate/FFTLen/FRefFreq);
- if (FDeriv = 1) then
- amp := amp * FSampleRate/(2*M_PI*FRefFreq);
- if (FDeriv = 2) then
- amp := amp * FSampleRate/(2*M_PI*FRefFreq)
- * FSampleRate/(2*M_PI*FRefFreq);
- if (amp <> 0) and (FPeak.Amplitude > 0) then
- begin
- db := 20*log10(amp);
- if FLogFreq then
- begin
- if index <= 1 then Freq := (index+0.25) * FSampleRate/FFTLen
- else Freq := index * FSampleRate/FFTLen;
- end
- else Freq := (index+0.5) * FSampleRate/FFTLen;
- end
- else
- begin
- amp := 0;
- db := -100;
- Freq := 0;
- end;
- end;
- Result := FPeak;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- { Set up logarithmic amplitude (Y) scale factors and offsets. }
- procedure TMMSpectrum.SetupLogScales;
- var
- i: integer;
- Scale,Base,Convert,Offset: Float;
- begin
- if not(csLoading in ComponentState) then
- begin
- { Compute the (logarithmic) y scale factor and offset.
- This may include a 3dB/octave gain.
- Conversion factor from db/10 to dPhils (the computed "unit")
- where a factor of 2 yields 16384 dPhils (6.02dB)
- Scaling factor is such that 32768 -> 0.00 dB -> 245760 dPhils
- and 2 -> -84.29 dB -> 16384 dPhils
- and 1 -> -90.31 dB -> 0 dPhils
- i.e. dPhils=16384.0/log(2) * log(value)
- and changes of 6.02 dB = 16384 dPhils }
- Convert := 819.2*log(10)/log(2); { Scale for dB to dPhils conversion }
- Offset := log10(32768)*20; { Offset for db to dPhils conversion }
- { This value is used in the main program group to convert squared values
- amplitudes to dPhils using dPhils = log(value^2)*Log_ScaleFactor }
- FLogScaleFactor := 8192.0/log(2);
- Scale := FHeight/(10*(FLogBase-FLogs)*Convert);
- if (FDeriv = 0) then
- Base := (Offset-FLogBase*10)*Convert
- else if(FDeriv = 1) then
- Base := (Offset-log10(FSampleRate/(2*M_PI*FRefFreq))*20-FLogBase*10)*Convert
- else
- Base := (Offset-log10(FSampleRate/(2*M_PI*FRefFreq))*40-FLogBase*10)*Convert;
- FDispScaleFactor := Scale; { Save the unshifted version for avg. display mode }
- FShift := 0;
- { Make maximum use of available bits
- (use only 12 bits--other 4 used for higher resolution in the data) }
- while (Scale < 4096) do
- begin
- Scale := Scale*2;
- inc(FShift);
- end;
- for i := 0 to FWidth-1 do
- FYScale^[i] := Floor(Scale+0.5);
- if (FGain3db > 0) then
- begin
- for i := 0 to (FFTLen div 2)-1 do
- FYBase^[i] := Floor(0.5+Base-log10((i+1)*FSampleRate/FFTLen/FRefFreq)*Convert*10);
- end
- else
- begin
- for i := 0 to (FFTLen div 2)-1 do
- FYBase^[i] := Floor(0.5+Base);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- { Set up linear amplitude (Y) scale factors }
- procedure TMMSpectrum.SetupLinScales;
- var
- i: integer;
- Scale: Float;
- begin
- if not(csLoading in ComponentState) then
- begin
- { Compute the (linear) y scale factor.
- This may include a 3dB/octave gain. }
- Scale := FHeight/(Fys*32768.0*sqrt(FRefFreq));
- FShift := 4; { Display data has an extra factor of 16 for better resolution }
- if (FDeriv = 1) then
- begin
- Scale := Scale*FSampleRate/(2*M_PI*FRefFreq);
- end
- else if (FDeriv = 2) then
- begin
- Scale := Scale*FSampleRate*FSampleRate/(4*M_PI*M_PI*FRefFreq*FRefFreq);
- end;
- { Make maximum use of available bits }
- if (FGain3db > 0) then
- begin
- { Make maximum use of available bits
- (use only 12 bits--other 4 used for higher resolution in the data) }
- while Scale*sqrt(FSampleRate/2) < 4096 do
- begin
- Scale := Scale*2;
- inc(FShift);
- end;
- for i := 0 to FWidth-1 do
- begin
- if (Fx1^[i] = -1) then FYScale^[i] := 0
- else FYScale^[i] := Round(Scale*sqrt((Fx1^[i]+1)*FSampleRate/FFTLen)+0.5);
- end;
- end
- else
- begin
- { Make maximum use of available bits
- (use only 12 bits--other 4 used for higher resolution in the data) }
- Scale := Scale*sqrt(FRefFreq);
- while (Scale < 4096) do
- begin
- Scale := Scale*2;
- inc(FShift);
- end;
- for i := 0 to FWidth-1 do
- begin
- if (Fx1^[i] = -1) then FYScale^[i] := 0
- else FYScale^[i] := Floor(Scale+0.5);
- end;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.XRangeCheck;
- var
- MaxBase: Float;
- begin
- FFreqScaleFactor := MinMaxR(FFreqScaleFactor, 1.0, 16.0);
- if FLogFreq then
- begin
- MaxBase := FSampleRate/2/exp(log(FFTLen/2)/FFreqScaleFactor);
- FFreqBase := MinMaxR(FFreqBase, FSampleRate/FFTLen, MaxBase);
- end
- else
- begin
- FFreqBase := MaxR(FFreqBase, 0);
- if ((FFreqBase+FSampleRate/(2*FFreqScaleFactor))>FSampleRate/2) then
- FFreqBase := FSampleRate/2-FSampleRate/(2*FFreqScaleFactor);
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- { Set up X axis scales }
- procedure TMMSpectrum.SetupXScale;
- var
- i,ival: Long;
- begin
- if not(csLoading in ComponentState) then
- begin
- { Do some range checking on the base and scale factors }
- XRangeCheck;
- if assigned(FOnGetXScale) then FOnGetXScale(Self,Fx1,Fx2)
- else
- begin
- { Initialize graph x scale (linear or logarithmic).
- This array points to the bin to be plotted on a given line.}
- for i := 0 to FWidth-1 do
- begin
- if FLogFreq then
- ival := Floor(FFTLen*FFreqBase/FSampleRate*exp((i-0.45)/
- FWidth*Log((FFTLen+1)/2)/FFreqScaleFactor)+0.51)-1
- else
- ival := Floor((i/FWidth*FFTLen/2.0/FFreqScaleFactor)+
- (FFreqBase/FSampleRate*FFTLen)+0.01);
- ival := MinMax(ival,0,(FFTLen div 2)-1);
- Fx1^[i] := ival;
- if (i > 0) then Fx2^[i-1] := ival;
- end;
- { Compute the ending locations for lines holding multiple bins }
- for i := 0 to FWidth-1 do
- if (Fx2^[i] <= (Fx1^[i]+1)) then Fx2^[i] := 0;
- end;
- { If lines are repeated on the screen, flag this so that we don't
- have to recompute the y values. }
- for i := FWidth-1 downTo 1 do
- begin
- if (Fx1^[i] = Fx1^[i-1]) then
- begin
- Fx1^[i] := -1;
- Fx2^[i]:= 0;
- end;
- end;
- if FLogAmp then SetupLogScales
- else SetupLinScales;
- DrawInactiveSpots;
- if not (csDesigning in ComponentState) then
- FastDraw(DrawFrequencyScale,True)
- else
- Invalidate;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetFrequencyAtPos(Pos: TPoint): Float;
- var
- Step: Float;
- begin
- Result := 0;
- if PtInRect(FClientRect,Pos) then
- begin
- dec(Pos.X,FClientRect.Left);
- if (FLogFreq) then
- begin
- Step := log(FFTLen/2)/((FWidth-1)*FFreqScaleFactor);
- Result := MaxR(FFreqBase*exp(Pos.X*Step),0);
- end
- else
- begin
- Step := (FSampleRate/2-FFreqBase)/(FWidth-1)/FFreqScaleFactor;
- Result := MaxR(FFreqBase+Pos.X*Step,0);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetAmplitudeAtPos(Pos: TPoint): Float;
- begin
- Result := 0;
- if PtInRect(FClientRect,Pos) then
- begin
- dec(Pos.Y,FClientRect.Top);
- if FLogAmp then
- Result := (Pos.Y*((FLogBase-FLogs)/(FHeight-1))+FLogs)*-10
- else
- Result := (FHeight-Pos.Y-1)*(10/(FHeight-1))*Fys*0.1;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- function TMMSpectrum.GetScaleBackColor: TColor;
- begin
- {$IFNDEF BUILD_ACTIVEX}
- Result := TForm(Parent).Color;
- {$ELSE}
- Result := FScaleBackColor;
- {$ENDIF}
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawFrequencyScale(Dummy: Boolean);
- var
- aBitmap: TBitmap;
- i, X: integer;
- Step, Freq: Float;
- Text: String;
- NumSteps: integer;
- begin
- if FDrawFreqScale then
- begin
- aBitmap := TBitmap.Create;
- try
- aBitmap.Width := FWidth + 2*BevelExtend;
- aBitmap.Height := SCALEHEIGHT;
- aBitmap.Canvas.Font.Color := FScaleTextColor;
- aBitmap.Canvas.Pen.Color := FScaleLineColor;
- aBitmap.Canvas.Brush.Color := GetScaleBackColor;
- with aBitmap.Canvas do
- begin
- FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
- { calc the number of steps required }
- NumSteps := 32;
- while (FWidth div NumSteps < SCALEFONTSIZE) do
- begin
- NumSteps := NumSteps div 2;
- if NumSteps = 1 then break;
- end;
- { Put up the frequency scale. }
- if (FLogFreq) then
- Step := log(FFTLen/2)/(NumSteps*FFreqScaleFactor)
- else
- Step := (FSampleRate/2-FFreqBase)/NumSteps/FFreqScaleFactor;
- MoveTo(BevelExtend,0);
- for i := 0 to NumSteps do
- begin
- X := BevelExtend + Round(i * (FWidth-1)/NumSteps);
- LineTo(X, 0);
- LineTo(X, 3);
- MoveTo(X, 0);
- if (FLogFreq) then
- Freq := MaxR(FFreqBase*exp(Step*i),0)
- else
- Freq := MaxR(FFreqBase+i*step,0);
- Text := Format('%.0f',[Freq]);
- TextOutAligned(aBitmap.Canvas,X,6,Text,SCALEFONT,SCALEFONTSIZE,2);{ vertical text }
- end;
- end;
- Canvas.Draw(FClientRect.Left-BevelExtend,
- FClientRect.Bottom+BevelExtend+3, aBitmap);
- finally
- aBitmap.Free;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawAmplitudeScale;
- var
- aBitmap: TBitmap;
- i, X, Y, H: integer;
- Text: String;
- Scale: Float;
- NumSteps: integer;
- begin
- { Put up the amplitude scale }
- if FDrawAmpScale then
- begin
- aBitmap := TBitmap.Create;
- try
- if FdrawFreqScale then
- H := Height-ScaleHeight
- else
- H := Height;
- aBitmap.Width := SCALEWIDTH;
- aBitmap.Height := H;
- aBitmap.Canvas.Font.Color := FScaleTextColor;
- aBitmap.Canvas.Pen.Color := FScaleLineColor;
- aBitmap.Canvas.Brush.Color := GetScaleBackColor;
- with aBitmap.Canvas do
- begin
- if (LogAmp) then
- begin
- { calc the number of steps required }
- NumSteps := (FLogBase-FLogs);
- while (FHeight div NumSteps < SCALEFONTSIZE) do
- begin
- dec(NumSteps);
- if NumSteps <= 1 then break;
- end;
- { draw the left side }
- FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
- X := SCALEWIDTH-1;
- MoveTo(X, BevelExtend);
- for i := 0 to NumSteps do
- begin
- Y := BevelExtend + Trunc(i*(FHeight-1)/NumSteps);
- LineTo(X, Y);
- LineTo(X-3, Y);
- MoveTo(X, Y);
- Text := Format('%d',[Round((i*((FLogBase-FLogs)/NumSteps)+FLogs)*-10)]);
- TextOutAligned(aBitmap.Canvas, X-4, Y, Text, SCALEFONT,SCALEFONTSIZE, 1);{ right text }
- end;
- Canvas.Draw(-3, 0, aBitmap);
- { draw the right side }
- FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
- X := 0;
- MoveTo(X, BevelExtend);
- for i := 0 to NumSteps do
- begin
- Y := BevelExtend + Trunc(i*(FHeight-1)/NumSteps);
- LineTo(X, Y);
- LineTo(X+3, Y);
- MoveTo(X, Y);
- Text := Format('%2.d',[Round((i*((FLogBase-FLogs)/NumSteps)+FLogs)*-10)]);
- TextOutAligned(aBitmap.Canvas, X+6, Y, Text, SCALEFONT,SCALEFONTSIZE,0);
- end;
- Canvas.Draw((Width - SCALEWIDTH)+3, 0, aBitmap);
- end
- else
- begin
- { calc the number of steps required }
- NumSteps := 10;
- while (FHeight div NumSteps < SCALEFONTSIZE) do
- begin
- dec(NumSteps);
- if NumSteps <= 1 then break;
- end;
- { calc the scaling steps }
- Scale := (Fys*32768.0)/FHeight;
- { draw the left side }
- FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
- X := SCALEWIDTH-1;
- MoveTo(X, H-BevelExtend-1);
- for i := 0 to NumSteps do
- begin
- if (Fys > 0.095) then Text := Format('%4.2f',[i*(10/NumSteps)*Fys*0.1])
- else Text := Format('%5.3f',[i*(10/NumSteps)*Fys*0.1]);
- Y := H-BevelExtend-Trunc(i*Fys*32760.0/NumSteps/Scale)-1;
- LineTo(X, Y);
- LineTo(X-3, Y);
- MoveTo(X, Y);
- TextOutAligned(aBitmap.Canvas, X-5, Y, Text,SCALEFONT,SCALEFONTSIZE,1);{ right text }
- end;
- Canvas.Draw(-3, 0, aBitmap);
- { draw the right side }
- FillRect(Rect(0,0,aBitmap.Width,aBitmap.Height));
- X := 0;
- MoveTo(X, H-BevelExtend-1);
- for i := 0 to NumSteps do
- begin
- if (Fys > 0.095) then Text := Format('%4.2f',[i*(10/NumSteps)*Fys*0.1])
- else Text := Format('%5.3f',[i*(10/NumSteps)*Fys*0.1]);
- Y := H-BevelExtend-Trunc(i*Fys*32760.0/NumSteps/Scale)-1;
- LineTo(X, Y);
- LineTo(X+3, Y);
- MoveTo(X, Y);
- TextOutAligned(aBitmap.Canvas, X+6, Y, Text, SCALEFONT,SCALEFONTSIZE,0);{ left text }
- end;
- Canvas.Draw((Width - SCALEWIDTH)+3, 0, aBitmap);
- end;
- end;
- finally
- aBitmap.Free;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawGrids;
- var
- i,X,Y,NumSteps: integer;
- Scale: Float;
- begin
- if FDrawGrid then
- with DIBCanvas do
- begin
- DIB_SetTColor(FGridColor);
- { the horizontal lines }
- if (LogAmp) then
- begin
- { calc the number of steps required }
- NumSteps := (FLogBase-FLogs);
- while (FHeight div NumSteps < SCALEFONTSIZE) do
- begin
- dec(NumSteps);
- if NumSteps <= 1 then break;
- end;
- for i := 0 to NumSteps do
- begin
- Y := Trunc(i*(FHeight-1)/NumSteps);
- DIB_HLineDoted(0, FWidth, Y, 1);
- end;
- end
- else
- begin
- { calc the number of steps required }
- NumSteps := 10;
- while (FHeight div NumSteps < SCALEFONTSIZE) do
- begin
- dec(NumSteps);
- if NumSteps <= 1 then break;
- end;
- { calc the scale steps required }
- Scale := (Fys*32768.0)/FHeight;
- for i := 0 to NumSteps do
- begin
- Y := FHeight-Trunc(i*Fys*32760.0/NumSteps/Scale)-1;
- DIB_HLineDoted(0, FWidth, Y, 1);
- end;
- end;
- { the vertical lines }
- { calc the number of steps required }
- NumSteps := 32;
- while (FWidth div NumSteps < SCALEFONTSIZE) do
- begin
- NumSteps := NumSteps div 2;
- if NumSteps = 1 then break;
- end;
- for i := 0 to NumSteps do
- begin
- X := i * (FWidth-1) div NumSteps;
- DIB_VLineDoted(X, 0, FHeight, 1);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.RefreshPCMData(PCMData: Pointer);
- var
- Value: Longint;
- i: Integer;
- ReIndex: integer;
- Back1, Back2: Long; { Variables for differencing }
- {$IFDEF WIN32}
- fTemp : array[0..MAX_FFTLen-1] of Float;
- {$ELSE}
- fTemp : array[0..MAX_FFTLen-1] of Smallint;
- {$ENDIF}
- begin
- if FEnabled and Visible and not FShowInfoHint then
- begin
- ReIndex := Ord(FChannel)-1;
- if (FDeriv = 0) then
- begin
- { perform windowing on sample Data from PCMData to FFFTData }
- if (FBits = b8bit) then
- if (FMode = mMono) then
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i];
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
- end
- else if (FChannel = chBoth) then
- for i := 0 to FFTLen-1 do
- begin
- Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
- end
- else
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i+i+ReIndex];
- if Value >= 255 then PcmOverflow;
- ftemp[i] := MulDiv32(Value-128,FWinBuf^[i],128);
- end
- else
- if (FMode = mMono) then
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
- end
- else if (FChannel = chBoth) then
- for i := 0 to FFTLen-1 do
- begin
- Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
- if Value >= 32766 then PcmOverflow;
- fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
- end
- else
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i+i+ReIndex];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value,FWinBuf^[i],32768);
- end;
- end
- else if (FDeriv = 1) then
- begin
- { perform windowing on sample Data from PCMData to FFFTData }
- if (FBits = b8bit) then
- begin
- if (FMode = mMono) then
- begin
- Back1 := PByteArray(PCMData)^[0];
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i];
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
- Back1 := Value;
- end;
- end
- else if (FChannel = chBoth) then
- begin
- Back1 := PByteArray(PCMData)^[0];
- for i := 0 to FFTLen-1 do
- begin
- Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
- Back1 := Value;
- end;
- end
- else
- begin
- Back1 := PByteArray(PCMData)^[ReIndex];
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i+i+ReIndex];
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],128);
- Back1 := Value;
- end;
- end;
- end
- else
- begin
- if (FMode = mMono) then
- begin
- Back1 := PSmallArray(PCMData)^[0];
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
- Back1 := Value;
- end;
- end
- else if (FChannel = chBoth) then
- begin
- Back1 := PSmallArray(PCMData)^[0];
- for i := 0 to FFTLen-1 do
- begin
- Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
- if Value >= 32766 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
- Back1 := Value;
- end;
- end
- else
- begin
- Back1 := PSmallArray(PCMData)^[ReIndex];
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i+i+ReIndex];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-Back1,FWinBuf^[i],32768);
- Back1 := Value;
- end;
- end;
- end;
- end
- else { Deriv = 2 }
- begin
- { perform windowing on sample Data from PCMData to FFFTData }
- if (FBits = b8bit) then
- begin
- if (FMode = mMono) then
- begin
- Back1 := PByteArray(PCMData)^[0];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i];
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
- Back2 := Back1;
- Back1 := Value;
- end;
- end
- else if (FChannel = chBoth) then
- begin
- Back1 := PByteArray(PCMData)^[0];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := (Word(PByteArray(PCMData)^[i+i])+PByteArray(PCMData)^[i+i+1])div 2;
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
- Back2 := Back1;
- Back1 := Value;
- end;
- end
- else
- begin
- Back1 := PByteArray(PCMData)^[ReIndex];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := PByteArray(PCMData)^[i+i+ReIndex];
- if Value >= 255 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],128);
- Back2 := Back1;
- Back1 := Value;
- end;
- end;
- end
- else
- begin
- if (FMode = mMono) then
- begin
- Back1 := PSmallArray(PCMData)^[0];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
- Back2 := Back1;
- Back1 := Value;
- end;
- end
- else if (FChannel = chBoth) then
- begin
- Back1 := PSmallArray(PCMData)^[0];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := (Long(PSmallArray(PCMData)^[i+i])+PSmallArray(PCMData)^[i+i+1])div 2;
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
- Back2 := Back1;
- Back1 := Value;
- end;
- end
- else
- begin
- Back1 := PSmallArray(PCMData)^[ReIndex];
- Back2 := Back1;
- for i := 0 to FFTLen-1 do
- begin
- Value := PSmallArray(PCMData)^[i+i+ReIndex];
- if Value >= 32767 then PcmOverflow;
- fTemp[i] := MulDiv32(Value-2*Back1+Back2,FWinBuf^[i],32768);
- Back2 := Back1;
- Back1 := Value;
- end;
- end;
- end;
- end;
- { calc the FFT }
- {$IFDEF WIN32}
- DoRealFFT(FpFFT,@fTemp, 1);
- for i := 0 to FFTLen-1 do FFFTData^[i] := Trunc(fTemp[i]/(FFTLen div 2));
- {$ELSE}
- for i := 0 to FFTLen-1 do FFFTData^[i] := fTemp[i];
- FFT.CalcFFT(Pointer(FFFTData));
- {$ENDIF}
- { calc the magnitude }
- CalcMagnitude(False);
- { next, put this data up on the display }
- FastDraw(DrawSpectrum,False);
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.RefreshFFTData(FFTData: Pointer);
- begin
- Move(PByte(FFTData)^, FFFTData^, FFTLen*sizeOf(SmallInt));
- { calc the magnitude }
- CalcMagnitude(False);
- { next, put this data up on the display }
- FastDraw(DrawSpectrum,False);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.RefreshMagnitudeData(MagData: Pointer);
- begin
- Move(PChar(MagData)^, FFFTData^, (FFTLen div 2)*sizeOf(Longint));
- { calc display values }
- CalcMagnitude(True);
- { next, put this data up on the display }
- FastDraw(DrawSpectrum,False);
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CalcMagnitude(MagnitudeForm: Boolean);
- var
- i: integer;
- re,im: Long;
- a2,Root: Long;{ Variables for computing Sqrt/Log of Amplitude^2 }
- begin
- { go through the data set and convert it to magnitude form }
- if (FDecayMode <> dmNone) or (not FLogAmp) then
- begin
- { Use sqrt(a2) in averaging mode and linear-amplitude mode }
- inc(FDecayPtr);
- inc(FDecayCntAct);
- if (FDecayPtr >= FDecayCount) then FDecayPtr := 0;
- if (FDecayCntAct > FDecayCount) then FDecayCntAct := FDecayCount;
- for i := 0 to (FFTLen div 2)-1 do
- begin
- if MagnitudeForm then
- begin
- Root := PLongArray(FFFTData)^[i];
- end
- else
- begin
- { Compute the magnitude }
- {$IFDEF WIN32}
- re := FFFTData^[i+i];
- im := FFFTData^[i+i+1];
- {$ELSE}
- re := FFFTData^[FFT.BitReversed^[i]];
- im := FFFTData^[FFT.BitReversed^[i]+1];
- {$ENDIF}
- a2 := re*re+im*im;
- { Watch for possible overflow }
- if (a2 < 0) then a2 := 0;
- { Use higher resolution only for small values }
- {$IFDEF USE_INTEGER_CODE}
- if (a2 > 4194304) then
- begin
- Root := 32;
- repeat
- Mask :=a2 div Root;
- Root := (Root+Mask) shr 1;
- until not (abs(Root-Mask) > 1);
- Root := Root*16;
- end
- else
- begin
- Root := 512;
- a2 := a2*256;
- repeat
- Mask := a2 div Root;
- Root := (Root+Mask) shr 1;
- until not (abs(root-mask) > 1);
- end;
- {$ELSE}
- Root := Trunc(sqrt(a2)*16);
- {$ENDIF}
- end;
- { In decay mode, need to average this value }
- case Ord(FDecayMode) of
- 1: begin
- FLastVal_F^[i] := FLastVal_F^[i]*FDecayFactor;
- if (Root >= FLastVal_F^[i]) then FLastVal_F^[i] := Root
- else Root := Trunc(FLastVal_F^[i]);
- end;
- 2: begin
- FLastVal_F^[i] := FLastVal_F^[i]*FDecayFactor+(1-FDecayFactor)*Root;
- Root := Floor(FLastVal_F^[i]);
- end;
- 3: begin
- FLastVal^[i] := FLastVal^[i] + (Root-FDataBuf^[FDecayPtr]^[i]);
- FDataBuf^[FDecayPtr]^[i] := Root;
- Root := FLastVal^[i] div FDecayCntAct;
- end;
- end;
- FDisplayVal^[i] := Root;
- end;
- end
- else { No averaging, log-amplitude mode }
- begin
- for i := 0 to (FFTLen div 2)-1 do
- begin
- if MagnitudeForm then
- begin
- Root := PLongArray(FFFTData)^[i];
- end
- else
- begin
- { Compute the magnitude }
- {$IFDEF WIN32}
- re := FFFTData^[i+i];
- im := FFFTData^[i+i+1];
- {$ELSE}
- re := FFFTData^[FFT.BitReversed^[i]];
- im := FFFTData^[FFT.BitReversed^[i]+1];
- {$ENDIF}
- a2 := re*re+im*im;
- { Watch for possible overflow }
- if (a2 < 0) then a2 := 0;
- {$IFDEF USE_INTEGER_CODE}
- Root := 32768;
- while (a2 >= 32) do
- begin
- Root := Root + 8192;
- a2 := a2 shr 1;
- end;
- Root := Root + _ln[a2]-FYBase^[i];
- {$ELSE}
- if (a2 > 0) then Root := Trunc(log(a2)*FLogScaleFactor-FYBase^[i])
- else Root := 0;
- {$ENDIF}
- end;
- if (Root < 0) then
- FDisplayVal^[i] := 0
- else
- FDisplayVal^[i] := Root;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.CalcDisplayValues;
- var
- i, j, index, xval: integer;
- dv: Long;
- begin
- dv := 0;
- j := 0;
- { In log-amp decay mode, need to do some special things }
- if (FDecayMode <> dmNone) and FLogAmp then
- begin
- i := 0;
- while i < FWidth do
- begin
- { If this line is the same as the previous one, just use the
- previous Y value. Else go ahead and compute the value. }
- index := Fx1^[i];
- if (index <> -1) then
- begin
- if i > 0 then
- begin
- { save the display rect for this set of bins }
- FDrawVal^[j].Right := i;
- FDrawVal^[j].Value := dv;
- inc(j);
- end;
- FDrawVal^[j].Left := i;
- { Convert the amplitude values to log scale }
- dv := FDisplayVal^[index];
- if (Fx2^[i] > 0) then { Take the max of a set of bins }
- begin
- xval := index;
- while xval < Fx2^[i] do
- begin
- if (FDisplayVal^[xval] > dv) then
- begin
- dv := FDisplayVal^[xval];
- index := xval;
- end;
- inc(xval);
- end;
- end;
- if (dv > 0) then
- dv := Trunc((log(dv/16.0)*2*FLogScaleFactor-FYBase^[index])
- * FDispScaleFactor)
- else dv := 0;
- { new peak found ? }
- if (dv > FPeak.Amplitude) then
- begin
- FPeak.Amplitude := dv;
- FPeak.Index := Fx1^[i];
- FPeak.X := i;
- end;
- if dv >= FHeight then GainOverflow;
- end;
- inc(i);
- end;
- end
- else
- begin
- { For linear amplitude mode and log amp without decay }
- i := 0;
- while i < FWidth do
- begin
- { If this line is the same as the previous one, just use the previous
- Y value. Else go ahead and compute the value. }
- index := Fx1^[i];
- if (index <> -1) then
- begin
- if i > 0 then
- begin
- { save the display rect for this set of bins }
- FDrawVal^[j].Right := i;
- FDrawVal^[j].Value := dv;
- { now the next rect }
- inc(j);
- end;
- FDrawVal^[j].Left := i;
- dv := FDisplayVal^[index];
- if (Fx2^[i] > 0) then { Take the maximum of a set of bins }
- begin
- while (index < Fx2^[i]) do
- begin
- if (FDisplayVal^[index] > dv) then dv := FDisplayVal^[index];
- inc(index);
- end;
- end;
- if (dv > 0) then dv := (dv * FYScale^[i]) shr FShift
- else dv := 0;
- { new peak found ? }
- if (dv > FPeak.Amplitude) then
- begin
- FPeak.Amplitude := dv;
- FPeak.Index := Fx1^[i];
- FPeak.X := i;
- end;
- if dv >= FHeight then GainOverflow;
- end;
- inc(i);
- end;
- end;
- { save the last value }
- FDrawVal^[j].Right := i;
- FDrawVal^[j].Value := dv;
- { and mark the end }
- FDrawVal^[j+1].Left := -1;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetOnDrawBar(aValue: TMMSpectrumDrawBar);
- begin
- FOnDrawBar := aValue;
- if not assigned(FOnDrawBar) then DrawInactiveSpots;
- Invalidate;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.SetLocalVariables(DIB: TMMDIBCanvas);
- begin
- with DIB do
- begin
- _DIB := DIB;
- _Bar1Color := DIB_ColorToIndex(FBar1Color);
- _Bar2Color := DIB_ColorToIndex(FBar2Color);
- _Bar3Color := DIB_ColorToIndex(FBar3Color);
- _Inact1Color := DIB_ColorToIndex(FInact1Color);
- _Inact2Color := DIB_ColorToIndex(FInact2Color);
- _Inact3Color := DIB_ColorToIndex(FInact3Color);
- _NumSpots := FNumSpots;
- _NumPeaks := FNumPeaks;
- _SpotHeight := FSpotHeight;
- _SpotSpace := FSpotSpace;
- _FirstSpace := FFirstSpace;
- _Space := FSpace;
- _Point1Spot := FPoint1Spot;
- _Point2Spot := FPoint2Spot;
- _ActiveDoted := FActiveDoted;
- _InactiveDoted:= FInactiveDoted;
- _DrawInactive := FDrawInactive;
- _Offset := 1;
- if (FKind = skScroll) then _Offset := FHeight-FHeight div 3;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.InitLocalVariables;
- begin
- { copy some variables from the DIBCanvas unit to this scope to fix a bug in CBuilder 3.0 }
- _DIB_ORIENT := DIB_ORIENT;
- _biBits := biBits;
- _biBPP := biBPP;
- _biWidth := biWidth;
- _biHeight := biHeight;
- _biScanWidth := biScanWidth;
- _biLineDiff := biLineDiff;
- _biColor := biColor;
- _biSurface := biSurface;
- _biPenPos := biPenPos;
- _biClipRect := biClipRect;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawAsDots;
- var
- i, Y: integer;
- begin
- SetLocalVariables(DIBCanvas);
- with DIBCanvas do
- begin
- i := 0;
- while (FDrawVal^[i].Left <> -1) and (i < FWidth) do
- with FDrawVal^[i] do
- begin
- Y := MinMax(FHeight-Value-1,0,FHeight-1);
- if not FEnabled then DIB_SetTColor(_Inact1Color)
- else if Y <= _Point2Spot then DIB_SetColor(_Bar3Color)
- else if Y <= _Point1Spot then DIB_SetColor(_Bar2Color)
- else DIB_SetColor(_Bar1Color);
- DIB_HLine(Left, Right, Y);
- inc(i);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawAsLines;
- var
- i,y: integer;
- begin
- SetLocalVariables(DIBCanvas);
- with DIBCanvas do
- begin
- if FEnabled then DIB_SetTColor(FBar1Color)
- else DIB_SetTColor(FInact1Color);
- DIB_MoveTo(0,MinMax(FHeight-FDrawVal^[0].Value-_Offset,0,FHeight-1));
- {$IFDEF USEASM}
- _biPenPos := biPenPos;
- {$ENDIF}
- i := 0;
- y := 0;
- while (FDrawVal^[i].Left <> -1) and (i < FWidth) do
- with FDrawVal^[i] do
- begin
- y := MinMax(FHeight-Value-_Offset,0,FHeight-1);
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- PointedLineTo(Left+(Right-Left) div 2, y,(FKind = skScroll))
- else
- DIB_LineTo(Left+(Right-Left) div 2, y);
- {$ELSE}
- DIB_LineTo(Left+(Right-Left) div 2, y);
- {$ENDIF}
- inc(i);
- end;
- {$IFDEF USEASM}
- biPenPos := _biPenPos;
- {$ENDIF}
- if (BitsPerPixel <> 24) then DIB_LineTo(FWidth,y);
- if (FKind <> skScroll) and (FNumPeaks > 0) then
- begin
- i := 0;
- while (FDrawVal^[i].Left <> -1) and (i < FWidth) do
- with FDrawVal^[i] do
- begin
- if (Value >= Peak) and (Value > 0) then
- begin
- Peak := Value;
- PeakCnt := (FPeakDelay*2)+1;
- end;
- y := MinMax(FHeight-Peak-_Offset,0,FHeight-1);
- if (i = 0) then
- begin
- DIB_MoveTo(0,y);
- {$IFDEF USEASM}
- _biPenPos := biPenPos;
- {$ENDIF}
- end;
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- PointedLineTo(Left+(Right-Left) div 2, y,(FKind = skScroll))
- else
- DIB_LineTo(Left+(Right-Left) div 2, y);
- {$ELSE}
- DIB_LineTo(Left+(Right-Left) div 2, y);
- {$ENDIF}
- inc(i);
- end;
- {$IFDEF USEASM}
- biPenPos := _biPenPos;
- {$ENDIF}
- DIB_LineTo(FWidth,y);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawAsVLines;
- var
- aRect: TRect;
- i, Y: integer;
- begin
- SetLocalVariables(DIBCanvas);
- with DIBCanvas do
- begin
- i := 0;
- while (FDrawVal^[i].Left <> -1) and (i < FWidth) do
- with FDrawVal^[i] do
- begin
- Value := MinMax(Value,0,FHeight-1);
- Y := (FHeight + Value) div 2;
- aRect.Top := FHeight-Y-1;
- aRect.Bottom := Y+1;
- aRect.Left := Left;
- aRect.Right := Right;
- with aRect do
- begin
- if Right - Left <= 0 then Right := Left + 1;{ we don't accept <= 0 }
- if Right - Left > _Space then { can we work with space ? }
- begin
- Left := Left + _Space div 2;
- Right := (Right + _Space div 2) - _Space;
- end;
- if FEnabled then
- begin
- if Value > _Point2Spot then
- begin
- DIB_SetColor(_Bar3Color);
- DIB_FillRect(aRect);
- InflateRect(aRect,0,-(Value-_Point2Spot)div 2);
- dec(Value,Value-_Point2Spot);
- end;
- if Value > _Point1Spot then
- begin
- DIB_SetColor(_Bar2Color);
- DIB_FillRect(aRect);
- InflateRect(aRect,0,-(Value-_Point1Spot)div 2);
- end;
- DIB_SetColor(_Bar1Color);
- DIB_FillRect(aRect);
- end
- else
- begin
- DIB_SetColor(_Inact1Color);
- DIB_FillRect(aRect);
- end;
- end;
- inc(i);
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawAsBars;
- var
- i: integer;
- nSpots,iMax: integer;
- begin
- SetLocalVariables(DIBCanvas);
- if assigned(FOnDrawBar) then
- iMax := FHeight
- else
- iMax := FNumSpots;
- i := 0;
- while (FDrawVal^[i].Left <> -1) and (i < FWidth) do
- with FDrawVal^[i] do
- begin
- nSpots := MinMax(Round(Value/(FHeight/iMax)+0.5),0,iMax);
- if (nSpots >= Peak) and (nSpots > 0) and (FNumPeaks > 0) then
- begin
- Peak := nSpots;
- PeakCnt := (FPeakDelay*2)+1;
- end;
- if assigned(FOnDrawBar) then
- FOnDrawBar(Self,_DIB,Rect(Left,0,Right,FHeight),nSpots,Peak)
- else if (FKind = skBars) then
- begin
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- DrawBar(Left,Right,nSpots,Peak)
- else
- DrawBar_Native(Left,Right,nSpots,Peak);
- {$ELSE}
- DrawBar_Native(Left,Right,nSpots,Peak);
- {$ENDIF}
- end
- else
- begin
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- DrawBarPeak(Left,Right,nSpots,Peak)
- else
- DrawBarPeak_Native(Left,Right,nSpots,Peak);
- {$ELSE}
- DrawBarPeak_Native(Left,Right,nSpots,Peak);
- {$ENDIF}
- end;
- inc(i);
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawInactiveSpots;
- var
- i, L: integer;
- begin
- if not (csLoading in ComponentState) and not (csCreating in ControlState) and
- not assigned(FOnDrawBar) and ((FKind = skBars) or (FKind = skPeaks)) then
- begin
- SetLocalVariables(FBarDIB);
- _Bar1Color := _Inact1Color;
- _Bar2Color := _Inact2Color;
- _Bar3Color := _Inact3Color;
- _ActiveDoted := _InactiveDoted;
- with _DIB do
- begin
- DIB_InitDrawing;
- InitLocalVariables;
- DIB_SetTColor(Color);
- DIB_Clear;
- L := 0;
- for i := 0 to FWidth-1 do
- begin
- { If this line is the same as the previous one, just use the
- previous Y value. Else go ahead and compute the value. }
- if (Fx1^[i] <> -1) then
- begin
- { draw this bar }
- if i > 0 then
- begin
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- DrawBar(L,i,FNumSpots,0)
- else
- DrawBar_Native(L,i,FNumSpots,0);
- {$ELSE}
- DrawBar_Native(L,i,FNumSpots,0);
- {$ENDIF}
- end;
- L := i;
- end;
- end;
- {$IFDEF USEASM}
- if (BitsPerPixel <> 24) then
- DrawBar(L,FWidth,FNumSpots,0)
- else
- DrawBar_Native(L,FWidth,FNumSpots,0);
- {$ELSE}
- DrawBar_Native(L,FWidth,FNumSpots,0);
- {$ENDIF}
- DIB_DoneDrawing;
- end;
- end;
- end;
- {$IFDEF USEASM}
- {$IFDEF WIN32}{$L MMSPEC32.OBJ}{$ELSE}{$L MMSPEC16.OBJ}{$ENDIF}
- {$F+}
- procedure TMMSpectrum.DrawBar(X1,X2,nSpots, Peak: integer); external;
- procedure TMMSpectrum.DrawBarPeak(X1,X2, nSpots, Peak: integer); external;
- procedure TMMSpectrum.PointedLineTo(X,Y: integer; Pointed: Boolean); external;
- {$F-}
- {$ENDIF}
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawBar_Native(X1, X2, nSpots, Peak: integer);
- Var
- SpotRect: TRect; { Spot draw rectangle }
- i,SpotInc: integer;
- begin
- SpotInc := FSpotHeight + FSpotSpace;
- if X2 - X1 <= 0 then X2 := X1 + 1; { we don't accept <= 0 }
- if X2 - X1 > FSpace then { can we work with space ? }
- begin
- X1 := X1 + FSpace div 2;
- X2 := (X2 + FSpace div 2) - FSpace;
- end;
- SpotRect.Left := X1;
- SpotRect.Right := X2;
- SpotRect.Bottom := FHeight - _FirstSpace;
- SpotRect.Top := SpotRect.Bottom - _SpotHeight;
- with _DIB do
- begin
- DIB_SetColor(_Bar1Color);
- for i := 1 to nSpots do { draw the highlited spots }
- begin
- if i > _Point2Spot then DIB_SetColor(_Bar3Color)
- else if i > _Point1Spot then DIB_SetColor(_Bar2Color);
- DIB_FillRectDoted(SpotRect,_ActiveDoted);
- OffsetRect(SpotRect, 0, -SpotInc);
- end;
- if (_NumPeaks > 0) and (Peak > nSpots) then
- begin
- OffsetRect(SpotRect, 0, -((Peak-1)-nSpots)*SpotInc);
- for i := 0 to _NumPeaks-1 do { draw the peak spots }
- begin
- if Peak-i > _Point2Spot then DIB_SetColor(_Bar3Color)
- else if Peak-i > _Point1Spot then DIB_SetColor(_Bar2Color)
- else DIB_SetColor(_Bar1Color);
- DIB_FillRectDoted(SpotRect,_ActiveDoted);
- OffsetRect(SpotRect, 0, SpotInc);
- end;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawBarPeak_Native(X1, X2, nSpots, Peak: integer);
- Var
- SpotRect: TRect; { Spot draw rectangle }
- i,SpotInc: integer;
- begin
- if X2 - X1 <= 0 then X2 := X1 + 1; { we don't accept <= 0 }
- if X2 - X1 > FSpace then { can we work with space ? }
- begin
- X1 := X1 + FSpace div 2;
- X2 := (X2 + FSpace div 2) - FSpace;
- end;
- SpotInc := FSpotHeight + FSpotSpace;
- SpotRect.Left := X1;
- SpotRect.Right := X2;
- with DIBCanvas do
- begin
- if (nSpots > 0) then
- begin
- SpotRect.Bottom := FHeight - _FirstSpace - ((nSpots-1)*SpotInc);
- SpotRect.Top := SpotRect.Bottom - _SpotHeight;
- if nSpots > _Point2Spot then DIB_SetColor(_Bar3Color)
- else if nSpots > _Point1Spot then DIB_SetColor(_Bar2Color)
- else DIB_SetColor(_Bar1Color);
- DIB_FillRectDoted(SpotRect,_ActiveDoted);
- end;
- if (_NumPeaks > 0) and (Peak > nSpots) then
- begin
- SpotRect.Bottom := FHeight - _FirstSpace - (Peak-1)*SpotInc;
- SpotRect.Top := SpotRect.Bottom - _SpotHeight;
- for i := 0 to _NumPeaks-1 do { draw the peak spots }
- begin
- if Peak-i > FPoint2Spot then DIB_SetColor(_Bar3Color)
- else if Peak-i > FPoint1Spot then DIB_SetColor(_Bar2Color)
- else DIB_SetColor(_Bar1Color);
- DIB_FillRectDoted(SpotRect,_ActiveDoted);
- OffsetRect(SpotRect, 0, SpotInc);
- end;
- end;
- end;
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawPeakValue;
- var
- Border,Y: integer;
- Text: String;
- begin
- if not (csDesigning in ComponentState) then
- begin
- if FDisplayPeak and (FPeak.Amplitude > 5) then
- with Canvas, FPeak do
- begin
- Font.Name := 'MS Sans Serif';
- Font.Style := [fsBold];
- Font.Size := 8;
- Font.Color := clWhite;
- Brush.Style := bsClear;
- if FLogFreq then
- begin
- if index <= 1 then Freq := (index+0.25) * FSampleRate/FFTLen
- else Freq := index * FSampleRate/FFTLen;
- end
- else Freq := (index+0.5) * FSampleRate/FFTLen;
- Text := TrimLeft(Format('%7.1f Hz',[Freq]));
- if X + TextWidth(Text) >= FWidth then X := FWidth-TextWidth(Text)-1;
- Y := Max((FHeight-Amplitude-_Offset)-TextHeight(Text),0);
- Border := BevelExtend;
- if FDrawAmpScale then inc(Border, SCALEWIDTH);
- TextOut(Border+X,BevelExtend+Y,Text);
- Font.Style := [];
- Brush.Style := bsSolid;
- end;
- end;
- end;
- {$IFDEF WIN32}
- {-- TMMSpectrum --------------------------------------------------------}
- procedure TMMSpectrum.DrawInfo(Pos: TPoint);
- var
- Freq, Amp, Text: String;
- aRect: TRect;
- Buf: array[0..255] of char;
- DC: HDC;
- WindowHandle: HWND;
- begin
- if FShowInfoHint then
- with DIBCanvas do
- begin
- if PtInRect(FClientRect,Pos) then
- begin
- Freq := Format('%2.3f KHz', [GetFrequencyAtPos(Pos)/1000]);
- if (FKind <> skScroll) then
- begin
- if FLogAmp then
- Amp := Format(' %2.1f dB',[GetAmplitudeAtPos(Pos)])
- else
- begin
- if (VerticalScale > 9) then
- Amp := Format(' %4.2f V',[GetAmplitudeAtPos(Pos)])
- else
- Amp := Format(' %5.3f V',[GetAmplitudeAtPos(Pos)]);
- end;
- end
- else Amp := '';
- Font.Name := 'MS Sans Serif';
- Font.Style := [];
- Font.Size := 8;
- {$IFDEF WIN32}
- Font.Color := clInfoText;
- {$ELSE}
- Font.Color := clBlack;
- {$ENDIF}
- Text := Freq+Amp;
- aRect.Left := Pos.X-BevelExtend;
- if FDrawAmpScale then dec(aRect.Left, SCALEWIDTH);
- aRect.Top := Pos.Y-BevelExtend+15;
- aRect.Right := aRect.Left + TextWidth(Text)+4;
- aRect.Bottom := aRect.Top + TextHeight(Text)+2;
- if (aRect.Bottom > FHeight) then OffsetRect(aRect,0,-40);
- if (aRect.Right > FWidth) then OffsetRect(aRect,FWidth-aRect.Right,0);
- if (aRect.Top < 0) then
- begin
- aRect.Top := 0;
- aRect.Bottom := TextHeight(Text)+2;
- end;
- if (SaveDC = 0) then
- begin
- { create memory DC for save bitmap }
- SaveDC := CreateCompatibleDC(DIBCanvas.Handle);
- { create bitmap to store background }
- SaveWidth := 10*TextWidth('W')+4;
- SaveHeight := TextHeight('W')+2;
- SaveBitmap := CreateCompatibleBitmap(DIBCanvas.Handle,SaveWidth,SaveHeight);
- OldBitmap := SelectObject(SaveDC, SaveBitmap);
- end
- else
- { restore background }
- BitBlt(DIBCanvas.Handle,SaveInfoPos.X,
- SaveInfoPos.Y,SaveWidth,SaveHeight,
- SaveDC,0,0,SRCCOPY);
- { save background }
- BitBlt(SaveDC,0,0,SaveWidth,SaveHeight,
- DIBCanvas.Handle,aRect.Left,aRect.Top,SRCCOPY);
- SaveInfoPos := aRect.TopLeft;
- Brush.Color := INFOCOLOR;
- Brush.Style := bsSolid;
- Pen.Color := clBlack;
- Rectangle(aRect.Left,aRect.Top,aRect.Right,aRect.Bottom);
- Brush.Style := bsClear;
- DrawText(Handle, StrPCopy(Buf, Text), -1, aRect,
- DT_SINGLELINE or DT_VCENTER or DT_CENTER or DT_NOPREFIX);
- Brush.Style := bsSolid;
- end
- else if (SaveBitmap <> 0) then
- begin
- { restore background }
- BitBlt(DIBCanvas.Handle,SaveInfoPos.X,
- SaveInfoPos.Y,SaveWidth,SaveHeight,
- SaveDC,0,0,SRCCOPY);
- end;
- DIB_InitDrawing; { copy to screen }
- DC := GetDeviceContext(WindowHandle);
- DIBCanvas.DIB_BitBlt(DC, FClientRect,0,0);
- ReleaseDC(WindowHandle, DC);
- DIB_DoneDrawing;
- DrawPeakValue;
- end;
- end;
- {$ELSE}
- {-- TMMSpectrum --------------------------------------------------------}
- procedure TMMSpectrum.DrawInfo(Pos: TPoint);
- var
- Freq, Amp, Text: String;
- aRect: TRect;
- Buf: array[0..255] of char;
- Border: integer;
- begin
- if FShowInfoHint then
- with Canvas do
- begin
- if PtInRect(FClientRect,Pos) then
- begin
- Freq := Format('%2.3f KHz', [GetFrequency(Pos)/1000]);
- if (FKind <> skScroll) then
- begin
- if FLogAmp then
- Amp := Format(' %2.1f dB',[GetAmplitude(Pos)])
- else
- begin
- if (VerticalScale > 9) then
- Amp := Format(' %4.2f V',[GetAmplitude(Pos)])
- else
- Amp := Format(' %5.3f V',[GetAmplitude(Pos)]);
- end;
- end
- else Amp := '';
- Font.Name := 'MS Sans Serif';
- Font.Size := 8;
- {$IFDEF WIN32}
- Font.Color := clInfoText;
- {$ELSE}
- Font.Color := clBlack;
- {$ENDIF}
- Text := Freq+Amp;
- aRect.Left := Pos.X;
- aRect.Top := Pos.Y+15;
- aRect.Right := aRect.Left + TextWidth(Text)+4;
- aRect.Bottom := aRect.Top + TextHeight(Text)+2;
- Border := BevelExtend;
- if FDrawFreqScale then inc(Border,SCALEWIDTH);
- if (aRect.Bottom > Height-Border) then OffsetRect(aRect,0,-40);
- Border := BevelExtend;
- if FDrawAmpScale then inc(Border,SCALEWIDTH);
- if (aRect.Right > Width-Border) then OffsetRect(aRect,Width-Border-aRect.Right,0);
- if (aRect.Top < 0) then
- begin
- aRect.Top := 0;
- aRect.Bottom := TextHeight(Text)+2;
- end;
- if (SaveDC = 0) then
- begin
- { create memory DC for save bitmap }
- SaveDC := CreateCompatibleDC(Canvas.Handle);
- { create bitmap to store background }
- SaveWidth := 10*TextWidth('W')+4;
- SaveHeight := TextHeight('W')+2;
- SaveBitmap := CreateCompatibleBitmap(Canvas.Handle,SaveWidth,SaveHeight);
- OldBitmap := SelectObject(SaveDC, SaveBitmap);
- end
- else
- { restore background }
- BitBlt(Canvas.Handle,SaveInfoPos.X,
- SaveInfoPos.Y,SaveWidth,SaveHeight,
- SaveDC,0,0,SRCCOPY);
- { save background }
- BitBlt(SaveDC,0,0,SaveWidth,SaveHeight,
- Canvas.Handle,aRect.Left,aRect.Top,SRCCOPY);
- SaveInfoPos := aRect.TopLeft;
- Brush.Color := INFOCOLOR;
- Brush.Style := bsSolid;
- Pen.Color := clBlack;
- Rectangle(aRect.Left,aRect.Top,aRect.Right,aRect.Bottom);
- Brush.Style := bsClear;
- DrawText(Handle, StrPCopy(Buf, Text), -1, aRect,
- DT_SINGLELINE or DT_VCENTER or DT_CENTER or DT_NOPREFIX);
- Brush.Style := bsSolid;
- end
- else if (SaveDC <> 0) then
- begin
- { restore background }
- BitBlt(Canvas.Handle,SaveInfoPos.X,
- SaveInfoPos.Y,SaveWidth,SaveHeight,
- SaveDC,0,0,SRCCOPY);
- end;
- end;
- end;
- {$ENDIF}
- {-- TMMSpectrum ---------------------------------------------------------}
- procedure TMMSpectrum.DrawSpectrum(Clear: Boolean);
- Label Calc;
- begin { reset the peak index }
- FPeak.Amplitude := 0;
- FPeak.Index := 0;
- DIBCanvas.DIB_InitDrawing;
- InitLocalVariables;
- { Clear background or draw DIB }
- if (FKind <> skScroll) or Clear then
- begin
- if not assigned(FOnDrawBar) then
- begin
- if ((FKind = skBars) or (FKind = skPeaks)) and FDrawInactive then
- begin
- DIBCanvas.DIB_CopyDIBBits(FBarDIB.Surface,0,0,FWidth,FHeight,0,0);
- goto Calc;
- end
- else if (FKind <> skScroll) then
- begin
- if assigned(FOnClearBackground) then
- FOnClearBackground(Self, DIBCanvas, Rect(0,0,FWidth,FHeight))
- else
- DrawBackGround;
- goto Calc;
- end;
- end;
- if assigned(FOnClearBackground) then
- begin
- FOnClearBackground(Self, DIBCanvas, Rect(0,0,FWidth,FHeight));
- end
- else
- begin
- DIBCanvas.DIB_SetTColor(Color);
- DIBCanvas.DIB_Clear;
- end;
- end
- else if (FKind = skScroll) and not (csDesigning in ComponentState) then
- begin { scroll down }
- DIBCanvas.DIB_CopyDIBBits(biSurface,0,SCROLLDISTANCE,FWidth,FHeight-SCROLLDISTANCE,0,0);
- DIBCanvas.DIB_SetTColor(Color);
- DIBCanvas.DIB_FillRect(Rect(0,0,FWidth,SCROLLDISTANCE));
- end;
- Calc:
- CalcDisplayValues; { calculate the amplitude values }
- if (FKind <> skScroll) then DrawGrids; { draw the grid }
- case FKind of { draw the spectrum to bitmap }
- skDots : DrawAsDots;
- skLines,
- skScroll: DrawAsLines;
- skVLines: DrawAsVLines;
- skBars,
- skPeaks: DrawAsBars;
- end;
- { copy to screen }
- DIBCanvas.DIB_BitBlt(Canvas.Handle, FClientRect,0,0);
- DIBCanvas.DIB_DoneDrawing;
- DrawPeakValue; { Draw the Peak value }
- end;
- {-- TMMSpectrum ---------------------------------------------------------}
- Procedure TMMSpectrum.Paint;
- var
- H,L: integer;
- Text: String;
- aRect: TRect;
- begin
- with Canvas do
- begin
- if FDrawFreqScale or FDrawAmpScale then
- begin
- { clear the space between the scales only, to eliminate flicker }
- Brush.Color := GetScaleBackColor;
- Brush.Style := bsSolid;
- if FDrawAmpScale then
- begin
- H := Height;
- if FDrawFreqScale then H := Height-SCALEHEIGHT;
- aRect := Rect(SCALEWIDTH-3,0,SCALEWIDTH,H);
- FillRect(aRect);
- aRect:= Rect(Width-SCALEWIDTH,0,Width-SCALEWIDTH+3,H);
- FillRect(aRect);
- end;
- if FDrawFreqScale then
- begin
- aRect:= Rect(0,Height-SCALEHEIGHT,Width,Height-SCALEHEIGHT+3);
- FillRect(aRect);
- if FdrawAmpScale then
- begin
- aRect:= Rect(0,Height-SCALEHEIGHT,SCALEWIDTH,Height);
- FillRect(aRect);
- aRect:= Rect(WIDTH-SCALEWIDTH,Height-SCALEHEIGHT,Width,Height);
- FillRect(aRect);
- end;
- end;
- { write scale text }
- Canvas.Font.Color := FScaleTextColor;
- if FDrawAmpScale and FDrawFreqScale then
- begin
- if LogAmp then
- begin
- Text := 'db';
- L := SCALEWIDTH-9;
- end
- else
- begin
- Text := 'V';
- L := SCALEWIDTH-16;
- end;
- TextOutAligned(Canvas, L, Height-SCALEWIDTH,
- Text, SCALEFONT,SCALEFONTSIZE, 1);
- TextOutAligned(Canvas, Width-SCALEWIDTH+12, Height-SCALEWIDTH,
- Text, SCALEFONT,SCALEFONTSIZE,0);
- TextOutAligned(Canvas, Width-SCALEWIDTH+2, Height-SCALEHEIGHT+20,
- 'Hz', SCALEFONT,SCALEFONTSIZE,0);
- end;
-
- { make place for the scale }
- aRect := GetClientRect;
- if FDrawAmpScale then InflateRect(aRect,-SCALEWIDTH,0);
- if FDrawFreqScale then dec(aRect.Bottom, SCALEHEIGHT);
- end
- else aRect := GetClientRect;
- { draw the Bevel and fill the real area }
- aRect := Bevel.PaintBevel(Canvas, aRect,True);
- end;
- { now draw scales and the the spectrum }
- DrawAmplitudeScale;
- DrawFrequencyScale(True);
- DrawSpectrum(True);
- {$IFDEF BUILD_ACTIVEX}
- if Selected then
- begin
- Canvas.Brush.Style := bsClear;
- Canvas.Pen.Color := clRed;
- Canvas.Rectangle(0,0,Width,Height);
- Canvas.Brush.Style := bsSolid;
- end;
- {$ENDIF}
- end;
- {-- TMMSpectrum --------------------------------------------------------}
- procedure TMMSpectrum.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- var
- aRect: TRect;
- begin
- if not (csDesigning in ComponentState) and Enabled and (Button = mbLeft) and FShowInfo then
- begin
- aRect.TopLeft := ClientToScreen(FClientRect.TopLeft);
- aRect.BottomRight := ClientToScreen(FClientRect.BottomRight);
- ClipCursor(@aRect);
- FShowInfoHint := True;
- { maybe there is a hint, hide it }
- if ShowHint then
- begin
- FOldShowHint := ShowHint;
- ShowHint := False;
- Application.CancelHint;
- Update;
- end
- else FOldShowHint := False;
- DrawInfo(Point(X,Y));
- end;
- inherited MouseDown(Button, Shift, X, Y);
- end;
- {-- TMMSpectrum --------------------------------------------------------}
- procedure TMMSpectrum.MouseMove(Shift: TShiftState; X, Y: Integer);
- begin
- inherited MouseMove(Shift, X, Y);
- if FShowInfoHint then DrawInfo(Point(X,Y));
- end;
- {-- TMMSpectrum --------------------------------------------------------}
- procedure TMMSpectrum.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- begin
- if (Button = mbLeft) and FShowInfoHint then
- begin
- { restore background }
- if FEnabled then DrawInfo(Point(-1,-1));
- if (SaveDC <> 0) then
- begin
- SelectObject(SaveDC, OldBitmap);
- DeleteObject(SaveBitmap);
- SaveBitmap := 0;
- DeleteDC(SaveDC);
- SaveDC := 0;
- end;
- FShowInfoHint := False;
- ClipCursor(nil);
- ShowHint := FOldShowHint;
- end;
- inherited MouseUp(Button, Shift, X, Y);
- end;
- {-- TMMSpectrum --------------------------------------------------------}
- function TMMSpectrum.GetOptimalWidth(aWidth: integer): integer;
- var
- NumBars, SpotWidth: integer;
- begin
- Result := aWidth;
- if (Kind = skBars) or (Kind = skPeaks) or (Kind = skVLines) then
- begin
- NumBars := (FFTLen div 2)div FrequencyScale;
- if FDrawAmpScale then
- begin
- SpotWidth := (((aWidth-2*SCALEWIDTH)-2*BevelExtend) div NumBars);
- if SpotWidth > 0 then
- Result := 2*SCALEWIDTH + SpotWidth*NumBars + 2*BevelExtend;
- end
- else
- begin
- SpotWidth := ((aWidth-2*BevelExtend) div NumBars);
- if SpotWidth > 0 then
- Result := SpotWidth*NumBars + 2*BevelExtend;
- end;
- end;
- end;
- end.