📄 vismain.pas
字号:
unit VisMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, Mask, ToolEdit, Registry,
WinampVisBase, ImgList, Spin, RXShell;
type
TVisPlugInBuf = record
DLLName : string;
DLLHandle : THandle;
Header : PwinampVisHeader;
Count : integer;
Modules : array of PwinampVisModule;
Enables : array of Boolean;
end;
TVisPlugInList=array of TVisPlugInBuf;
TMainForm = class(TForm)
TreeView1: TTreeView;
Panel1: TPanel;
Label1: TLabel;
DirectoryEdit1: TDirectoryEdit;
CheckBox1: TCheckBox;
Button1: TButton;
ImageList: TImageList;
Label2: TLabel;
SpinEdit1: TSpinEdit;
RxTrayIcon1: TRxTrayIcon;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure TreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView;
Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;
var PaintImages, DefaultDraw: Boolean);
procedure TreeView1CustomDrawItem(Sender: TCustomTreeView;
Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
procedure TreeView1DblClick(Sender: TObject);
procedure DirectoryEdit1Change(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure RxTrayIcon1Click(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SpinEdit1Change(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
private
{ Private declarations }
FReg : TRegistry;
FRenderThread : TThread;
procedure SearchPlugIn;
function IndexofVisPlugInList(DLLName: string): integer;
function AddVisPlugInList(DLLName: string): integer;
function IsPlugInFile(Name: string): Boolean;
procedure TestVisParent(Node: TTreeNode; index: integer);
procedure EnabledVisPlugIn(DLLName: string; Index: integer; Flag: Boolean);
procedure ShowPlugInError;
procedure SetupVisPlugIn(DLLName: string; Index: integer);
procedure FreeVisPlugIn;
procedure SaveVisPlugIn(sName: string);
procedure LoadVisPlugIn(sName: string);
public
{ Public declarations }
procedure AddSoundData(samples : PByte;numsamples,bps,nch,srate : integer);
end;
TRenderThread = class(TThread)
private
{ Private declarations }
FOldClock : DWORD;
FAudioBuffer : array of Byte;
FSampleRate : integer;
FSampleMul : integer;
FSampleLen : integer;
FSampleCh : integer;
FSampleBps : integer;
frequency : array[0..1,0..1024-1] of Byte;
waveform : array[0..1,0..1024-1] of Byte;
FReal,FImag : array[0..1024-1] of Double;
procedure UpdateSoundData(pSample: pByte; len, bps, nch, srate: integer);
procedure AnalySampleData(samples: pByte; numsamples, bps, nch: integer);
procedure GetSpectrum(var wave, freq: array of Byte);
protected
procedure Execute; override;
end;
var
MainForm: TMainForm;
FFrameRate : integer;
FVisPlugInList : TVisPlugInList;
FUsePlugIn : Boolean;
FIsTrayIcon : Boolean;
const
sRegistryKey = '\Software\ChangwonUniv\KMP\Visualization';
sPluginPath = 'PluginPath';
sVisPlugKey = 'VisPlugInKey';
sBaseVisPreset = 'BaseVisPreset';
sUsePlugIn = 'UsePlugIn';
sFrameRate = 'FrameRate';
sIsTrayIcon = 'IsTrayIcon';
cDataLen = 1024;
implementation
{$R *.dfm}
{ TRenderThread }
procedure TRenderThread.AnalySampleData(samples: pByte; numsamples, bps, nch : integer);
var
pw : pSmallInt;
pb : pByte;
i,num : integer;
begin
if numsamples>cDataLen then num:=cDataLen
else num:=numsamples;
if bps=8 then begin
pb:=pByte(samples);
if nch=1 then begin
for i:=0 to num-1 do begin
waveform[0][i]:=pb^;
inc(pb);
end;
end
else if nch=2 then begin
for i:=0 to num-1 do begin
waveform[0][i]:=pb^;
inc(pb);
waveform[1][i]:=pb^;
inc(pb);
end;;
end;
end
else if bps=16 then begin
pw:=pSmallInt(samples);
if nch=1 then begin
for i:=0 to num-1 do begin
waveform[0][i]:=((pw^) div 256)+128;
inc(pw);
end;
end
else if nch=2 then begin
for i:=0 to num-1 do begin
waveform[0][i]:=((pw^) div 256)+128;
inc(pw);
waveform[1][i]:=((pw^) div 256)+128;
inc(pw);
end;
end;
end;
end;
procedure TRenderThread.GetSpectrum(var wave,freq : array of Byte);
var
i,j,m,mmax,istep,aa,bb : integer;
c,s,treal,timag : double;
theta : double;
begin
for i:=0 to cDataLen-1 do begin
FReal[i]:=wave[i];
FImag[i]:=0.0;
end;
j:=1;
for i:=1 to cDataLen do begin
if(i<j) then begin
aa:=j-1;
bb:=i-1;
treal:=FReal[aa];
FReal[aa]:=FReal[bb];
FReal[bb]:=treal;
end;
m:=cDataLen div 2;
while(j>m) do begin
j:=j-m;
m:=(m+1) div 2;
end;
j:=j+m;
end;
mmax:=1;
while(cDataLen>mmax) do begin
istep:=2*mmax;
for m:=1 to mmax do begin
theta:=PI*(m-1)/mmax;
c:=cos(theta);
s:=sin(theta);
i:=m;
while i<=cDataLen do begin
j:=i+mmax;
aa:=j-1;
bb:=i-1;
treal:=FReal[aa]*c-FImag[aa]*s;
timag:=FImag[aa]*c+FReal[aa]*s;
FReal[aa]:=FReal[bb]-treal;
FImag[aa]:=FImag[bb]-timag;
FReal[bb]:=FReal[bb]+treal;
FImag[bb]:=FImag[bb]+timag;
i:=i+istep;
end;
end;
mmax:=istep;
end;
for i:=0 to cDataLen-1 do begin
freq[i]:=Trunc(sqrt(FReal[i]*FReal[i]+FImag[i]*FImag[i])) shr 3;
end;
end;
procedure TRenderThread.Execute;
var
pp,i,j : integer;
np : DWORD;
begin
FreeOnTerminate:=False;
FOldClock:=0;
while not(Terminated) do begin
np:=GetTickCount;
if FAudioBuffer<>nil then begin
if FOldClock=0 then pp:=0
else pp:=(np-FOldClock);
pp:=pp*FSampleRate*FSampleMul div 1000;
if pp>FSampleLen*2 then pp:=FSampleLen*2;
if (pp and $03)<>0 then pp:=(pp shr 2) shl 2;
AnalySampleData(@FAudioBuffer[pp],FSampleLen,FSampleBps,FSampleCh);
GetSpectrum(waveform[0],frequency[0]);
if FSampleCh=2 then GetSpectrum(waveform[1],frequency[1]);
for i:=0 to Length(FVisPlugInList)-1 do begin
for j:=0 to FVisPlugInList[i].Count-1 do begin
if FVisPlugInList[i].Enables[j] then begin
Move(waveform[0],FVisPlugInList[i].Modules[j]^.waveformData[0],576);
if FSampleCh=2 then Move(waveform[1],FVisPlugInList[i].Modules[j]^.waveformData[1],576);
FVisPlugInList[i].Modules[j]^.sRate:=FSampleRate;
FVisPlugInList[i].Modules[j]^.nCh:=FSampleCh;
FVisPlugInList[i].Modules[j]^.spectrumNch:=FSampleCh;
FVisPlugInList[i].Modules[j]^.waveformNch:=FSampleCh;
FVisPlugInList[i].Modules[j]^.Render(FVisPlugInList[i].Modules[j]);
end;
end;
end;
end;
Sleep(FFrameRate);
end;
end;
procedure TRenderThread.UpdateSoundData(pSample: pByte; len, bps, nch, srate: integer);
begin
FSampleRate:=srate;
FSampleMul:=(nch*bps div 8);
FSampleLen:=len;
FSampleCh:=nch;
FSampleBps:=bps;
if Length(FAudioBuffer)<len*4 then SetLength(FAudioBuffer,len*4);
Move(FAudioBuffer[len],FAudioBuffer[len shl 1],len);
Move(FAudioBuffer[0],FAudioBuffer[len],len);
Move(pSample^,FAudioBuffer[0],len);
FOldClock:=GetTickCount;
end;
{ TMainForm }
procedure TMainForm.AddSoundData(samples: PByte; numsamples, bps, nch, srate: integer);
begin
if FRenderThread<>nil then TRenderThread(FRenderThread).UpdateSoundData(samples,numsamples,bps,nch,srate);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FReg:=TRegistry.Create;
FReg.RootKey:=HKEY_CURRENT_USER;
if FReg.OpenKey(sRegistryKey,True) then begin
if FReg.ValueExists(sPluginPath) then DirectoryEdit1.Text:=FReg.ReadString(sPluginPath);
if DirectoryEdit1.Text='' then DirectoryEdit1.Text:=ExtractFilePath(Application.ExeName)+'PlugIns';
if FReg.ValueExists(sUsePlugIn) then FUsePlugIn:=FReg.ReadBool(sUsePlugIn)
else FUsePlugIn:=True;
if FReg.ValueExists(sIsTrayIcon) then FIsTrayIcon:=FReg.ReadBool(sIsTrayIcon)
else FIsTrayIcon:=True;
if FReg.ValueExists(sFrameRate) then FFrameRate:=FReg.ReadInteger(sFrameRate)
else FFrameRate:=15;
CheckBox1.Checked:=FUsePlugIn;
SpinEdit1.Value:=FFrameRate;
if FIsTrayIcon then RxTrayIcon1.Active:=True
else Show;
FReg.CloseKey;
end;
FRenderThread:=TRenderThread.Create(False);
LoadVisPlugIn(sBaseVisPreset);
SearchPlugIn;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
if FReg.OpenKey(sRegistryKey,True) then begin
FReg.WriteString(sPluginPath,DirectoryEdit1.Text);
FReg.WriteBool(sUsePlugIn,FUsePlugIn);
FReg.WriteBool(sIsTrayIcon,RxTrayIcon1.Active);
FReg.WriteInteger(sFrameRate,FFrameRate);
FReg.CloseKey;
end;
FRenderThread.Terminate;
FRenderThread.WaitFor;
FRenderThread.Free;
SaveVisPlugIn(sBaseVisPreset);
FreeVisPlugIn;
FReg.Free;
end;
function TMainForm.IndexofVisPlugInList(DLLName: string): integer;
var
i : integer;
begin
Result:=-1;
for i:=0 to Length(FVisPlugInList)-1 do begin
if UpperCase(FVisPlugInList[i].DLLName)=UpperCase(DLLName) then begin
result:=i;
break;
end;
end;
end;
function TMainForm.AddVisPlugInList(DLLName: string): integer;
var
i,jj : integer;
Func : function : PwinampVisHeader; cdecl;
DSPMod : PwinampVisModule;
begin
Result:=IndexofVisPlugInList(DLLName);
if Result>=0 then exit;
SetLength(FVisPlugInList,Length(FVisPlugInList)+1);
jj:=Length(FVisPlugInList)-1;
FVisPlugInList[jj].DLLName:=DLLName;
FVisPlugInList[jj].DLLHandle:=SafeLoadLibrary(pchar(DLLName));
Func:=GetProcAddress(FVisPlugInList[Length(FVisPlugInList)-1].DLLHandle,'winampVisGetHeader');
if Assigned(Func) then begin
FVisPlugInList[jj].Header:=Func;
FVisPlugInList[jj].Count:=0;
FVisPlugInList[jj].Modules:=nil;
FVisPlugInList[jj].Enables:=nil;
i:=0;
while True do begin
DSPMod:=Func^.getModule(i);
if DSPMod=nil then break;
DSPMod^.hwndParent:=Handle;
DSPMod^.hDllInstance:=FVisPlugInList[jj].DLLHandle;
SetLength(FVisPlugInList[jj].Modules,Length(FVisPlugInList[jj].Modules)+1);
SetLength(FVisPlugInList[jj].Enables,Length(FVisPlugInList[jj].Enables)+1);
FVisPlugInList[jj].Modules[Length(FVisPlugInList[jj].Modules)-1]:=DSPMod;
FVisPlugInList[jj].Enables[Length(FVisPlugInList[jj].Enables)-1]:=False;
FVisPlugInList[jj].Count:=Length(FVisPlugInList[jj].Enables);
inc(i);
end;
end;
Result:=jj;
end;
function TMainForm.IsPlugInFile(Name: string): Boolean;
var
DLLHandle : THandle;
p : Pointer;
begin
DLLHandle:=LoadLibrary(pchar(Name));
p:=GetProcAddress(DLLHandle,'winampVisGetHeader');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -