MMLight.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:42k
- {========================================================================}
- {= (c) 1995-98 SwiftSoft Ronald Dittrich =}
- {========================================================================}
- {= All Rights Reserved =}
- {========================================================================}
- {= D 01099 Dresden = Tel.: +0351-8012255 =}
- {= Loewenstr.7a = info@swiftsoft.de =}
- {========================================================================}
- {= Actual versions on http://www.swiftsoft.de/mmtools.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: 03.03.98 - 18:51:13 $ =}
- {========================================================================}
- Unit MMLight;
- {$I COMPILER.INC}
- interface
- uses
- {$IFDEF WIN32}
- Windows,
- {$ELSE}
- WinTypes,
- WinProcs,
- {$ENDIF}
- SysUtils,
- Messages,
- Classes,
- Graphics,
- Controls,
- Forms,
- Menus,
- MMSystem,
- MMUtils,
- MMObj,
- MMString,
- MMMath,
- MMMulDiv,
- MMFFT,
- MMRegs,
- MMPCMSup,
- MMDIBCv;
- const
- MAX_FFTLEN = 4096; { Define the maximum FFT buffer length. }
- MAXDECAYCOUNT = 32; { Maximum amount of temporal averaging allowed }
- type
- TMMLightKind = (lkCircle,lkSphere);
- TMMLightArrange = (laLine,laTriangle);
- TMMLightPeakMode= (pmRMS,pmPeak,pmAverage);
- const
- {$IFDEF CBUILDER3} {$EXTERNALSYM defRealize} {$ENDIF}
- defRealize = True;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defEnabled} {$ENDIF}
- defEnabled = True;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defHeight} {$ENDIF}
- defHeight = 90;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defWidth} {$ENDIF}
- defWidth = 194;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defMode} {$ENDIF}
- defMode = mMono;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defBitLength} {$ENDIF}
- defBitLength = b8bit;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defChannel} {$ENDIF}
- defChannel = chBoth;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defSampleRate} {$ENDIF}
- defSampleRate = 11025;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defFFTLen} {$ENDIF}
- defFFTLen = 128;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defWindow} {$ENDIF}
- defWindow = fwHamming;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defDecayMode} {$ENDIF}
- defDecayMode = dmNone;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defDecay} {$ENDIF}
- defDecay = 1;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defPeakMode} {$ENDIF}
- defPeakMode = pmPeak;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defKind} {$ENDIF}
- defKind = lkCircle;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defArrange} {$ENDIF}
- defArrange = laLine;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defTriangleDist} {$ENDIF}
- defTriangleDist = 10;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defSphereHorz} {$ENDIF}
- defSphereHorz = 1.0;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defSphereVert} {$ENDIF}
- defSphereVert = 1.0;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defZoneCount} {$ENDIF}
- defZoneCount = 60;
- {$IFDEF CBUILDER3} {$EXTERNALSYM defColor} {$ENDIF}
- defColor = clBlack;
- type
- EMMLightError = class(Exception);
- { array for uniform decay mode values }
- PDataBuf = ^TDataBuf;
- TDataBuf = array[0..MAXDECAYCOUNT-1] of PLongArray;
- { struct to hold pre-calculated values for every band }
- Values = record
- OldValue: Longint;
- CurValue: Longint;
- end;
- PValues = ^TValues;
- TValues = array[0..0] of Values;
- {-- TMMLight --------------------------------------------------------}
- TMMLight = class(TMMDIBGraphicControl)
- private
- {$IFDEF WIN32}
- FpFFT : PFFTReal; { the instance for FFT calculation }
- {$ELSE}
- FFT : TMMFFT; { the FFT object }
- {$ENDIF}
- FFFTData : PSmallArray;{ Array for FFT data }
- FWinBuf : PIntArray; { Array storing windowing function }
- FDataBuf : PDataBuf; { Memory for averaging mode }
- FDisplayVal : PLongArray; { Array storing display values }
- FValues : PValues; { array with precalculted bin values }
- FLastVal_F : PFloatArray;{ Last value buffer for exp decay mode}
- FLastVal : PLongArray; { Last value buffer for uniform avg }
- Fx1 : PIntArray; { Array of bin #'s displayed }
- Fx2 : PIntArray; { Array of terminal bin #'s }
- 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}
- FFTLen : integer; { Number of points for FFT }
- FSampleRate : Longint; { A/D sampling rate }
- FAmpScale : Float; { scaling factor for amplitude scaling}
- FGainBass : Float; { gain factor for bass frequency light}
- FGainMiddle : Float; { gain factor for middle freq. light }
- FGainTreble : Float; { gain factor for treble freq. light }
- FWindow : TMMFFTWindow;{ selected window function }
- FEnabled : Boolean; { Enable or disable Light }
- FBits : TMMBits; { b8bit or b16bit }
- FChannel : TMMChannel; { chBoth, chLeft or chRigth }
- FMode : TMMMode; { mMono, mStereo or mQuadro }
- FBytes : Longint; { calculated data bytes p. Light}
- FWidth : integer; { calculated width without border }
- FHeight : integer; { calculated height without border }
- FClientRect : TRect; { calculated beveled Rect }
- FPeakMode : TMMLightPeakMode;
- FKind : TMMLightKind;
- FArrange : TMMLightArrange;
- FTriangleDist : Integer;
- FSphereHorz : Float;
- FSphereVert : Float;
- FZoneCount : Integer;
- { Events }
- FOnPcmOverflow : TNotifyEvent;
- procedure CreateDataBuffers(Length: Cardinal);
- procedure FreeDataBuffers;
- procedure CreateArrays(Size: Cardinal);
- procedure FreeArrays;
- procedure ResetDecayBuffers;
- procedure ResetValues;
- procedure InitializeData;
- procedure SetBytesPerLight;
- procedure SetupScale;
- procedure CalcMagnitude(MagnitudeForm: Boolean);
- procedure CalcDisplayValues;
- procedure DrawLight;
- procedure AdjustCtrlSize(var W, H: Integer);
- procedure SetFFTLen(aLength: integer);
- procedure SetDecayMode(aValue: TMMDecayMode);
- procedure SetDecay(aValue: integer);
- procedure SetWindow(aValue: TMMFFTWindow);
- procedure SetAmpScale(index: integer; aValue: integer);
- function GetAmpScale(index: integer): integer;
- procedure SetEnabled(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 SetPeakMode(aValue: TMMLightPeakMode);
- procedure SetKind(aValue: TMMLightKind);
- procedure SetArrange(aValue: TMMLightArrange);
- procedure SetTriangleDist(Value: Integer);
- procedure SetSphereHorz(Value: Float);
- procedure SetSphereVert(Value: Float);
- procedure SetZoneCount(Value: Integer);
- protected
- procedure Paint; override;
- procedure Loaded; override;
- procedure PcmOverflow; dynamic;
- procedure Changed; override;
- procedure InitDIB;
- procedure DrawInitData;
- procedure DrawCurrentData;
- function GetPalette: HPALETTE; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); override;
- procedure RefreshPCMData(PCMData: Pointer);
- procedure RefreshFFTData(FFTData: Pointer);
- procedure RefreshMagnitudeData(MagData: Pointer);
- procedure ResetData;
- property BytesPerLight: Longint read FBytes;
- property PCMWaveFormat: TPCMWaveFormat read GetPCMWaveFormat write SetPCMWaveFormat;
- published
- { Events }
- property OnClick;
- property OnDblClick;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnDragDrop;
- property OnDragOver;
- property OnEndDrag;
- property OnStartDrag;
- property OnPcmOverflow: TNotifyEvent read FOnPcmOverflow write FOnPcmOverflow;
- property Align;
- property Bevel;
- property Color default defColor;
- property ParentShowHint;
- property ShowHint;
- property Visible;
- property PopupMenu;
- property PaletteRealize default defRealize;
- property PaletteMapped;
- property Enabled: Boolean read FEnabled write SetEnabled default defEnabled;
- property Height default defHeight;
- property Width default defWidth;
- property Mode: TMMMode read FMode write SetMode default defMode;
- property BitLength: TMMBits read FBits write SetBits default defBitLength;
- property Channel: TMMChannel read FChannel write SetChannel default defChannel;
- property SampleRate: Longint read FSampleRate write SetSampleRate default defSampleRate;
- property FFTLength: integer read FFTLen write SetFFTLen default defFFTLen;
- property Window: TMMFFTWindow read FWindow write SetWindow default defWindow;
- property DecayMode: TMMDecayMode read FDecayMode write SetDecayMode default defDecayMode;
- property Decay: integer read FDecay write SetDecay default defDecay;
- property AmplitudeScale: integer index 0 read GetAmpScale write SetAmpScale;
- property GainBass: integer index 1 read GetAmpScale write SetAmpScale;
- property GainMiddle: integer index 2 read GetAmpScale write SetAmpScale;
- property GainTreble: integer index 3 read GetAmpScale write SetAmpScale;
- property PeakMode: TMMLightPeakMode read FPeakMode write SetPeakMode default defPeakMode;
- property Kind: TMMLightKind read FKind write SetKind default defKind;
- property Arrange: TMMLightArrange read FArrange write SetArrange default defArrange;
- property TriangleDist: Integer read FTriangleDist write SetTriangleDist default defTriangleDist;
- property SphereHorz: Float read FSphereHorz write SetSphereHorz;
- property SphereVert: Float read FSphereVert write SetSphereVert;
- property ZoneCount: Integer read FZoneCount write SetZoneCount default defZoneCount;
- end;
- implementation
- uses
- Consts;
- const
- NumLights = 3;
- { Here we have the Center Frequencys from the different bands }
- CenterFreq: array[0..NumLights-1] of integer = (150,750,1750);
- {-- TMMLight ------------------------------------------------------------}
- constructor TMMLight.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- CreateDataBuffers(MAX_FFTLEN);
- CreateArrays(NumLights);
- PaletteRealize := defRealize;
- {$IFDEF WIN32}
- FpFFT := InitRealFFT(8);
- {$ELSE}
- FFT := TMMFFT.Create;
- {$ENDIF}
- FFTLen := 8;
- FDecay := defDecay;
- FDecayMode := defDecayMode;
- FDecayFactor := 0.0001;
- FDecayCount := 1;
- FDecayCntAct := 0;
- FDecayPtr := 0;
- FSampleRate := defSampleRate;
- FChannel := defChannel;
- FBits := defBitLength;
- FMode := defMode;
- FWindow := defWindow;
- FAmpScale := 1.0;
- FGainBass := 0.05;
- FGainMiddle := 0.05;
- FGainTreble := 0.05;
- FEnabled := defEnabled;
- FPeakMode := defPeakMode;
- FKind := defKind;
- FArrange := defArrange;
- FTriangleDist := defTriangleDist;
- FSphereHorz := defSphereHorz;
- FSphereVert := defSphereVert;
- FZoneCount := defZoneCount;
- FFTLength := defFFTLen;
- Color := defColor;
- Height := defHeight;
- Width := defWidth;
- InitDIB;
- ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
- if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
- end;
- {-- TMMLight ------------------------------------------------------------}
- Destructor TMMLight.Destroy;
- begin
- FreeDataBuffers;
- FreeArrays;
- {$IFDEF WIN32}
- DoneRealFFT(FpFFT);
- {$ELSE}
- FFT.Free;
- {$ENDIF}
- inherited Destroy;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.PcmOverflow;
- begin
- if Assigned(FOnPcmOverflow) then FOnPcmOverflow(Self);
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.CreateDataBuffers(Length: Cardinal);
- 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));
- 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;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.FreeDataBuffers;
- var
- i: integer;
- begin
- GlobalFreeMem(Pointer(FFFTData));
- GlobalFreeMem(Pointer(FWinBuf));
- GlobalFreeMem(Pointer(FDisplayVal));
- GlobalFreeMem(Pointer(FLastVal));
- GlobalFreeMem(Pointer(FLastVal_F));
- 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;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.CreateArrays(Size: Cardinal);
- begin
- if (Size > 0) then
- begin
- Fx1 := GlobalAllocMem(Size * sizeOf(Integer));
- Fx2 := GlobalAllocMem(Size * sizeOf(Integer));
- FValues := GlobalAllocMem(Size * sizeOf(TValues));
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.FreeArrays;
- begin
- GlobalFreeMem(Pointer(Fx1));
- GlobalFreeMem(Pointer(Fx2));
- GlobalFreeMem(Pointer(FValues));
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.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;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.ResetValues;
- var
- i: integer;
- begin
- for i := 0 to NumLights-1 do
- begin
- FValues^[i].OldValue := -1;
- FValues^[i].CurValue := 0;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.InitializeData;
- Var
- i: integer;
- begin
- if Enabled and (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;
- ResetValues;
- end
- else
- begin { create zero data }
- FillChar(FDisplayVal^[0], FFTLen div 2 * sizeOf(Long), 0);
- FillChar(FFFTData^[0], FFTLen * sizeOf(SmallInt), 0);
- ResetDecayBuffers;
- ResetValues;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.ResetData;
- begin
- InitializeData;
- Refresh;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.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 _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- if (aLength <> FFTLen) then
- begin
- { re-init the FFTObject 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 }
- SetupScale;
- SetBytesPerLight;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.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 _HACK2}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.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;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetWindow(aValue: TMMFFTWindow);
- begin
- if (aValue <> FWindow) then
- begin
- FWindow := aValue;
- GenWindowTableInt(FWinBuf,Ord(FWindow),Trunc(Log2(FFTLen)));
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetSampleRate(aValue: Longint);
- begin
- if (aValue <> FSampleRate) then
- begin
- FSampleRate := MinMax(aValue, 8000, 100000);
- { Re-initialize the display }
- SetupScale;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetEnabled(aValue: Boolean);
- begin
- if (aValue <> FEnabled) then
- begin
- FEnabled := aValue;
- { inherited Enabled := Value }
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetKind(aValue: TMMLightKind);
- begin
- if (aValue <> FKind) then
- begin
- FKind := aValue;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetArrange(aValue: TMMLightArrange);
- begin
- if (aValue <> FArrange) then
- begin
- FArrange := aValue;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetTriangleDist(Value: Integer);
- begin
- Value := MinMax(Value,2,MaxInt);
- if (Value <> FTriangleDist) then
- begin
- FTriangleDist := Value;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetSphereHorz(Value: Float);
- begin
- Value := MaxR(Value,0);
- if (Value <> FSphereHorz) then
- begin
- FSphereHorz := Value;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetSphereVert(Value: Float);
- begin
- Value := MaxR(Value,0);
- if (Value <> FSphereVert) then
- begin
- FSphereVert := Value;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetZoneCount(Value: Integer);
- begin
- Value := MinMax(Value,1,MaxInt);
- if (Value <> FZoneCount) then
- begin
- FZoneCount := Value;
- InitDIB;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetPeakMode(aValue: TMMLightPeakMode);
- begin
- if (aValue <> FPeakMode) then
- begin
- FPeakMode := aValue;
- Refresh;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.Loaded;
- begin
- inherited Loaded;
- SetupScale;
- InitDIB;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.AdjustCtrlSize(var W, H: Integer);
- begin
- W := Max(W,2*BevelExtend+5);
- H := Max(H,2*BevelExtend+5);
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetBounds(aLeft, aTop, aWidth, aHeight: integer);
- var
- W, H: Integer;
- begin
- W := aWidth;
- H := aHeight;
- AdjustCtrlSize (W, H);
- inherited SetBounds(aLeft, aTop, W, H);
- Changed;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.Changed;
- begin
- FClientRect := BeveledRect;
- { save the real height and width }
- FWidth := Max(FClientRect.Right - FClientRect.Left,4);
- FHeight := Max(FClientRect.Bottom - FClientRect.Top,4);
- DIBCanvas.SetBounds(0,0,FWidth,FHeight);
- InitDIB;
- inherited Changed;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetBytesPerLight;
- begin
- FBytes := (Ord(FBits)+1) * (Ord(FMode)+1) * FFTLen;
- end;
- {-- TMMLight ------------------------------------------------------------}
- Procedure TMMLight.SetPCMWaveFormat(wf: TPCMWaveFormat);
- var
- pwfx: PWaveFormatEx;
- begin
- pwfx := @wf;
- if not pcmIsValidFormat(pwfx) then
- raise EMMLightError.Create(LoadResStr(IDS_INVALIDFORMAT));
- SampleRate := pwfx^.nSamplesPerSec;
- BitLength := TMMBits(pwfx^.wBitsPerSample div 8 - 1);
- Mode := TMMMode(pwfx^.nChannels-1);
- end;
- {-- TMMLight ------------------------------------------------------------}
- function TMMLight.GetPCMWaveFormat: TPCMWaveFormat;
- var
- wfx: TWaveFormatEx;
- begin
- pcmBuildWaveHeader(@wfx, (Ord(FBits)+1)*8, Ord(FMode)+1, SampleRate);
- Result := PPCMWaveFormat(@wfx)^;
- end;
- {-- TMMLight ------------------------------------------------------------}
- Procedure TMMLight.SetBits(aValue: TMMBits);
- begin
- if (aValue <> FBits) then
- begin
- FBits := aValue;
- SetBytesPerLight;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- Procedure TMMLight.SetChannel(aValue: TMMChannel);
- begin
- if (aValue <> FChannel) then
- begin
- FChannel := aValue;
- SetBytesPerLight;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- Procedure TMMLight.SetMode(aValue: TMMMode);
- begin
- if (aValue <> FMode) then
- begin
- FMode := aValue;
- SetBytesPerLight;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetAmpScale(index: integer; aValue: integer);
- begin
- { Change the amplitude scale factor }
- aValue := MinMax(aValue, 0, 1000);
- if (aValue = GetAmpScale(index)) then exit;
- case index of
- 0: FAmpScale := 0.01*aValue;
- 1: FGainBass := 0.0005*aValue;
- 2: FGainMiddle:= 0.0005*aValue;
- 3: FGainTreble:= 0.0005*aValue;
- end;
- { Flush the buffers }
- InitializeData;
- end;
- {-- TMMLight ------------------------------------------------------------}
- function TMMLight.GetAmpScale(index: integer): integer;
- begin
- case index of
- 0: Result := Round(FAmpScale/0.01);
- 1: Result := Round(FGainBass/0.0005);
- 2: Result := Round(FGainMiddle/0.0005);
- 3: Result := Round(FGainTreble/0.0005);
- else
- Result := 0;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.SetupScale;
- var
- i,ival: Longint;
- StartFreq: array[0..NumLights-1] of Float;
- begin
- if not (csLoading in ComponentState) then
- begin
- { Do RMS averaging into a fixed set of bins }
- StartFreq[0] := 0;
- for i := 1 to NumLights-1 do
- StartFreq[i] := sqrt(Longint(CenterFreq[i])*CenterFreq[i-1]);
- i := 0;
- while i < NumLights do
- begin
- ival := MinMax(Round(StartFreq[i]/FSampleRate*FFTLen),0,FFTLen div 2);
- Fx1^[i] := ival;
- if (i > 0) then Fx2^[i-1] := ival;
- inc(i);
- end;
- Fx2^[i-1] := FFTlen div 2-1;
- { Compute the ending locations for lines holding multiple bins }
- for i := 0 to NumLights-1 do
- if (Fx2^[i] <= (Fx1^[i]+1)) then Fx2^[i] := 0;
- { if lines are repeated on the screen, flag this so that we don't
- have to recompute the y values. }
- for i := NumLights-1 downTo 1 do
- begin
- if (Fx1^[i] = Fx1^[i-1]) then
- begin
- Fx1^[i] := -1;
- Fx2^[i]:= 0;
- end;
- end;
- end;
- {$IFDEF WIN32}
- {$IFDEF TRIAL}
- {$DEFINE _HACK1}
- {$I MMHACK.INC}
- {$ENDIF}
- {$ENDIF}
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.RefreshPCMData(PCMData: Pointer);
- var
- Value: Longint;
- i: Integer;
- ReIndex: integer;
- {$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 then
- begin
- ReIndex := Ord(FChannel)-1;
- { perform windowing on sample Data from PCMData to FFFTData }
- if (FBits = b8bit) then
- begin
- 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;
- end
- else
- begin
- 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;
- { 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 }
- DrawLight;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.RefreshFFTData(FFTData: Pointer);
- begin
- Move(PByte(FFTData)^, FFFTData^, FFTLen*sizeOf(SmallInt));
- { calc the magnitude }
- CalcMagnitude(False);
- { next, put this data up on the display }
- DrawLight;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.RefreshMagnitudeData(MagData: Pointer);
- begin
- Move(PByte(MagData)^, FFFTData^, FFTLen*sizeOf(SmallInt));
- { calc display values }
- CalcMagnitude(True);
- { next, put this data up on the display }
- DrawLight;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.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 }
- 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
- a2 := 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;
- end;
- { Watch for possible overflow }
- if (a2 < 0) then a2 := 0;
- Root := Trunc(FAmpScale*sqrt(a2));
- { 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;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.CalcDisplayValues;
- var
- i, j, k, index: integer;
- dv,val: Longint;
- valf: Float;
- begin
- dv := 0;
- j := 0;
- i := 0;
- while i < NumLights 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 >= 0) then
- begin
- if i > 0 then
- begin
- FValues^[j].CurValue := dv;
- { now the next }
- inc(j);
- end;
- k := 1;
- dv := FDisplayVal^[index];
- valf := dv;
- if (Fx2^[i] > 0) then
- begin
- while (index < Fx2^[i]) do
- begin
- { We have three ways here }
- case FPeakMode of
- { build the RMS value of the set of bins }
- pmRMS:
- begin
- val := FDisplayVal^[index];
- valf := valf + (val+0.1)*val;
- end;
- { search the higest bin }
- pmPeak:
- begin
- if FDisplayVal^[index] > dv then
- dv := FDisplayVal^[index];
- end;
- { average the bins }
- pmAverage:
- begin
- dv := dv + FDisplayVal^[index];
- inc(k);
- end;
- end;
- inc(index);
- end;
- case FPeakMode of
- pmRMS : dv := Trunc(sqrt(valf/Max(index-Fx1^[i],1)));
- pmPeak :;
- pmAverage: dv := dv div k;
- end;
- end;
- end;
- inc(i);
- end;
- { store the last value }
- FValues^[j].CurValue := dv;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.InitDIB;
- begin
- if (csLoading in ComponentState) then Exit;
- if Kind = lkCircle then
- DIBCanvas.AnimatedColorCount := NumLights
- else
- DIBCanvas.AnimatedColorCount := NumLights * ZoneCount;
- DIBCanvas.DIB_InitDrawing;
- { clear background }
- DIBCanvas.DIB_SetTColor(Color);
- DIBCanvas.DIB_Clear;
- { Flush the buffers }
- InitializeData;
- DrawInitData;
- DIBCanvas.DIB_DoneDrawing;
- Invalidate;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.DrawInitData;
- var
- i : Integer;
- j : Integer;
- AWidth : Integer;
- AHeight : Integer;
- ERect : TRect;
- R : TRect;
- Delta : Integer;
- Radius : Integer;
- Vert : Boolean;
- procedure DrawCircle(X,Y,W,H: Integer; Color: Integer);
- begin
- with DIBCanvas do
- begin
- DIB_SetColor(AnimatedColorIndex[Color]);
- DIB_FillEllipse(X+W div 2,Y + H div 2,W div 2,H div 2);
- end;
- end;
- procedure DrawZone(X,Y,W,H: Integer; Zone: Integer; Color: Integer);
- var
- HDelta, VDelta: Integer;
- begin
- HDelta := Trunc(Zone * ((W/ZoneCount)/2));
- VDelta := Trunc(Zone * ((H/ZoneCount)/2));
- with DIBCanvas do
- begin
- DIB_SetColor(AnimatedColorIndex[Color]);
- DIB_FillEllipse(X+W div 2,Y+H div 2,(W-HDelta*2) div 2,(H-VDelta*2) div 2);
- end;
- end;
- function EllipseRect(i: Integer ): TRect;
- var
- X, Y: Integer;
- begin
- if Arrange = laLine then
- if Vert then
- Result := Bounds(ERect.Left + Delta, ERect.Top + i*2*Radius + (2*i+1)* Delta, 2*Radius, 2*Radius)
- else
- Result := Bounds(ERect.Left + i*2*Radius + (2*i+1)* Delta, ERect.Top + Delta, 2*Radius, 2*Radius)
- else
- begin
- case i of
- 0 : begin X := AWidth div 2 - Radius - Delta; Y := Radius + Delta; end;
- 1 : begin X := AWidth div 2; Y := AHeight - Delta - Radius; end;
- 2 : begin X := AWidth div 2 + Radius + Delta; Y := Radius + Delta; end;
- else
- Exit; {???}
- end;
- Result := Bounds(X+ERect.Left-Radius,Y+ERect.Top-Radius,2*Radius,2*Radius);
- end;
- end;
- begin
- AWidth := (FClientRect.Right-FClientRect.Left);
- AHeight := (FClientRect.Bottom-FClientRect.Top);
- Delta := TriangleDist div 2;
- if Arrange = laLine then
- begin
- Vert := False;
- if AHeight > AWidth then
- begin
- Vert := True;
- if (AHeight div NumLights) > AWidth then
- AHeight := AWidth * NumLights
- else
- AWidth := AHeight div NumLights;
- Radius := ((AHeight div NumLights)) div 2 - Delta;
- end
- else
- begin
- if (AWidth div NumLights) > AHeight then
- AWidth := AHeight * NumLights
- else
- AHeight := AWidth div NumLights;
- Radius := ((AWidth div NumLights)) div 2 - Delta;
- end;
- end
- else
- begin
- if (AWidth > AHeight) then
- AWidth := AHeight;
- Radius := (AWidth - 4 * Delta) div 4;
- AWidth := 4*(Radius+Delta);
- AHeight := Trunc((2+Sqrt(3))*(Radius+Delta));
- end;
- if Radius <= 0 then Exit;
- ERect := Bounds(((FClientRect.Right-FClientRect.Left)-AWidth) div 2,
- ((FClientRect.Bottom-FClientRect.Top)-AHeight) div 2,
- AWidth, AHeight);
- if (Kind = lkCircle) then
- begin
- for i := 0 to NumLights-1 do
- begin
- R := EllipseRect(i);
- DrawCircle(R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,i);
- end;
- end
- else
- begin
- for i := 0 to NumLights-1 do
- begin
- R := EllipseRect(i);
- for j := 0 to ZoneCount - 1 do
- DrawZone(R.Left,R.Top,R.Right-R.Left,
- R.Bottom-R.Top,j,i*ZoneCount+j);
- end;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.DrawCurrentData;
- var
- i : integer;
- j : integer;
- Value : Integer;
- function RGBColor(Index: Integer; Value: Integer): TColor;
- begin
- Result := 0;
- case i of
- 0 : Result := RGB(Value,0,0);
- 1 : Result := RGB(0,Value,0);
- 2 : Result := RGB(Value,Value,0);
- end;
- end;
- function LightColor(i: Integer; Value: Integer): TColor;
- begin
- Result:= RGBColor(i,Value);
- end;
- function ZoneColor(i: Integer; Zone: Integer; Value: Integer): TColor;
- var
- X, Y: Integer;
- ZoneUpper: Integer;
- begin
- X := (ZoneCount - Zone - 1);
- if X > ZoneCount*SphereHorz then
- X := Trunc(ZoneCount*SphereHorz);
- if (SphereHorz = 0) or (SphereVert = 0) then
- Value := 0
- else
- begin
- Y := Trunc(Sqrt(Sqr(ZoneCount)-Sqr(X/SphereHorz))*SphereVert);
- ZoneUpper:= Trunc((Y/(ZoneCount*SphereVert))*255);
- Value := Trunc((Value/255)*ZoneUpper);
- end;
- Result := RGBColor(i,Value);
- end;
- begin
- CalcDisplayValues;
- DIBCanvas.BeginAnimate;
- try
- for i := 0 to NumLights - 1 do
- begin
- case i of
- 0: Value := Trunc(FValues^[i].CurValue * (FGainBass));
- 1: Value := Trunc(FValues^[i].CurValue * (2*FGainMiddle));
- 2: Value := Trunc(FValues^[i].CurValue * (4*FGainTreble));
- else Value := 0;
- end;
- Value := MinMax(Value,0,255);
- if (Value <> FValues^[i].OldValue) then
- begin
- FValues^[i].OldValue := Value;
- with DIBCanvas do
- if Kind = lkCircle then
- AnimatedColorValue[i] := LightColor(i,Value)
- else
- for j := 0 to ZoneCount - 1 do
- AnimatedColorValue[ZoneCount*i+j] := ZoneColor(i,j,Value);
- end;
- end;
- finally
- DIBCanvas.EndAnimate;
- end;
- end;
- {-- TMMLight ------------------------------------------------------------}
- function TMMLight.GetPalette: HPALETTE;
- begin
- Result := DIBCanvas.Palette;
- end;
- {-- TMMLight ------------------------------------------------------------}
- procedure TMMLight.DrawLight;
- begin
- SelectPalette(Canvas.Handle,DIBCanvas.Palette,True);
- DrawCurrentData;
- DIBCanvas.DIB_BitBlt(Canvas.Handle, FClientRect,0,0);
- end;
- {-- TMMLight ------------------------------------------------------------}
- Procedure TMMLight.Paint;
- begin
- { draw the Bevel }
- Bevel.PaintBevel(Canvas, ClientRect,True);
- DrawLight;
- {$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;
- end.