home *** CD-ROM | disk | FTP | other *** search
- unit Unit1;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- Math, StdCtrls, Bass, ExtCtrls;
-
- type
- TForm1 = class(TForm)
- OpenDialog1: TOpenDialog;
- Timer1: TTimer;
- PB: TPaintBox;
- procedure FormCreate(Sender: TObject);
- procedure Timer1Timer(Sender: TObject);
- procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
- procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- procedure PBPaint(Sender: TObject);
- procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
- procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
- private
- function PlayFile: boolean;
- procedure ErrorPop(str: string);
- procedure SetLoopStart(position: qword);
- procedure SetLoopEnd(position: qword);
- procedure ScanPeaks2(decoder: HSTREAM);
- procedure DrawSpectrum;
- procedure DrawTime_Line(position: QWORD; x,y : integer; cl : TColor);
- public
- end;
-
- type TScanThread = class(TThread)
- private
- Fdecoder : HSTREAM;
- protected
- procedure Execute; override;
- public
- constructor Create(decoder:HSTREAM);
- end;
-
- procedure LoopSyncProc(handle: HSYNC; channel, data, user: DWORD); stdcall;
-
- var
- Form1: TForm1;
- lsync : HSYNC; // looping synchronizer handle
- chan : HSTREAM; // sample stream handle
- chan2: HSTREAM;
- loop : array[0..1] of DWORD;
- killscan : boolean;
- bpp : dword; // stream bytes per pixel
- wavebufL : array of smallint;
- wavebufR : array of smallint;
- mousedwn : integer;
- Buffer: TBitmap;
-
- implementation
-
- {$R *.dfm}
-
- //------------------------------------------------------------------------------
-
- procedure TForm1.FormCreate(Sender: TObject);
- begin
- // check that BASS 2.2 was loaded
- if not (BASS_GetVersion() = dword(MAKELONG(2,2))) then
- begin
- MessageBox(0,'BASS version 2.2 was not loaded','Incorrect BASS.DLL',0);
- Application.Terminate;
- end;
-
- //assigning layout properties
- ClientHeight := 201;
- ClientWidth := 600;
- Top := 100;
- Left := 100;
- Buffer := TBitmap.Create;
- Buffer.Width:= PB.Width;
- Buffer.Height:= PB.Height;
- PB.Parent.DoubleBuffered := true;
-
- //set array size
- setlength(wavebufL,ClientWidth);
- setlength(wavebufR,ClientWidth);
-
- //init vars
- loop[0] := 0;
- loop[1] := 0;
-
- //init BASS
- if not BASS_Init(-1,44100,0,Application.Handle,nil) then
- ErrorPop('Can''t initialize device');
-
- //init timer for updating
- Timer1.Interval := 20; //ms
- Timer1.Enabled := true;
-
- //main start play function
- if not PlayFile then
- begin
- BASS_Free();
- Application.Terminate;
- end;
- end;
-
- function TForm1.PlayFile : boolean;
- var
- filename : string;
- data : array[0..2000] of SmallInt;
- i : integer;
- begin
- result := false;
- if OpenDialog1.Execute then
- begin
- filename := OpenDialog1.Filename;
- BringWindowToTop(Form1.Handle);
- SetForegroundWindow(Form1.Handle);
-
- //creating stream
- chan := BASS_StreamCreateFile(FALSE,pchar(filename),0,0,0);
- if chan = 0 then
- begin
- chan := BASS_MusicLoad(False, pchar(filename), 0, 0, BASS_MUSIC_RAMPS or BASS_MUSIC_POSRESET or BASS_MUSIC_PRESCAN, 0);
- if (chan = 0) then
- begin
- ErrorPop('Can''t play file');
- Exit;
- end;
- end;
-
- //playing stream and setting global vars
- for i:=0 to length(data)-1 do data[0] := 0;
- bpp := BASS_ChannelGetLength(chan) div ClientWidth; // stream bytes per pixel
- if (bpp < BASS_ChannelSeconds2Bytes(chan,0.02)) then // minimum 20ms per pixel (BASS_ChannelGetLevel scans 20ms)
- bpp := BASS_ChannelSeconds2Bytes(chan,0.02);
- BASS_ChannelSetSync(chan,BASS_SYNC_END or BASS_SYNC_MIXTIME,0,LoopSyncProc,0); // set sync to loop at end
- BASS_ChannelPlay(chan,FALSE); // start playing
-
- //getting peak levels in seperate thread, stream handle as parameter
- chan2 := BASS_StreamCreateFile(FALSE,pchar(filename),0,0,BASS_STREAM_DECODE);
- if (chan2 = 0) then chan2 := BASS_MusicLoad(FALSE,pchar(filename),0,0,BASS_MUSIC_DECODE,0);
- TScanThread.Create(chan2); // start scanning peaks in a new thread
- result := true;
- end;
- end;
-
- procedure TForm1.DrawSpectrum;
- var
- i,ht : integer;
- begin
- //clear background
- Buffer.Canvas.Brush.Color := clBlack;
- Buffer.Canvas.FillRect(Rect(0,0,Buffer.Width,Buffer.Height));
-
- //draw peaks
- ht := ClientHeight div 2;
- for i:=0 to length(wavebufL)-1 do
- begin
- Buffer.Canvas.MoveTo(i,ht);
- Buffer.Canvas.Pen.Color := clLime;
- Buffer.Canvas.LineTo(i,ht-trunc((wavebufL[i]/32768)*ht));
- Buffer.Canvas.Pen.Color := clLime;
- Buffer.Canvas.MoveTo(i,ht+2);
- Buffer.Canvas.LineTo(i,ht+2+trunc((wavebufR[i]/32768)*ht));
- end;
- end;
-
- procedure TForm1.DrawTime_Line(position : QWORD; x,y : integer; cl : TColor);
- var
- sectime : integer;
- str:string;
- begin
- sectime := trunc(BASS_ChannelBytes2Seconds(chan,position));
-
- //format time
- str := '';
- if (sectime mod 60 < 10) then str := '0';
- str := str+inttostr(sectime mod 60);
- str := inttostr(sectime div 60)+':'+str;
-
- //drawline
- Buffer.Canvas.Pen.Color := cl;
- Buffer.Canvas.MoveTo(x,0);
- Buffer.Canvas.LineTo(x,ClientHeight);
-
- //drawtext
- Buffer.Canvas.Font.Color := cl;
- Buffer.Canvas.Font.Style := [fsBold];
- if x > ClientWidth-20 then
- dec(x,40);
- SetBkMode(Buffer.Canvas.Handle,TRANSPARENT);
- Buffer.Canvas.TextOut(x+2,y,str);
- end;
-
- procedure TForm1.ErrorPop(str:string);
- begin
- //show last BASS errorcode when no argument is given, else show given text.
- if str = '' then
- Showmessage('Error code: '+inttostr(BASS_ErrorGetCode()))
- else
- Showmessage(str);
- Application.Terminate;
- end;
-
- procedure TForm1.SetLoopStart(position : qword);
- begin
- loop[0] := position;
- end;
-
- procedure TForm1.SetLoopEnd(position : qword);
- begin
- loop[1] := position;
- BASS_ChannelRemoveSync(chan,lsync); // remove old sync
- lsync := BASS_ChannelSetSync(chan,BASS_SYNC_POS or BASS_SYNC_MIXTIME,loop[1],LoopSyncProc,0); // set new sync
- end;
-
- procedure LoopSyncProc(handle: HSYNC; channel, data, user: DWORD); stdcall;
- begin
- if not BASS_ChannelSetPosition(channel,loop[0]) then // try seeking to loop start
- BASS_ChannelSetPosition(channel,0); // failed, go to start of file instead
- end;
-
- procedure TForm1.ScanPeaks2(decoder : HSTREAM);
- var
- cpos,level : DWord;
- peak : array[0..1] of DWORD;
- position : DWORD;
- counter : integer;
- begin
- cpos := 0;
- peak[0] := 0;
- peak[1] := 0;
- counter := 0;
-
- while not killscan do
- begin
- level := BASS_ChannelGetLevel(decoder); // scan peaks
- if (peak[0]<LOWORD(level)) then
- peak[0]:=LOWORD(level); // set left peak
- if (peak[1]<HIWORD(level)) then
- peak[1]:=HIWORD(level); // set right peak
- if BASS_ChannelIsActive(decoder) <> BASS_ACTIVE_PLAYING then
- begin
- position := cardinal(-1); // reached the end
- end else
- position := BASS_ChannelGetPosition(decoder) div bpp;
-
- if position > cpos then
- begin
- inc(counter);
- if counter <= length(wavebufL)-1 then
- begin
- wavebufL[counter] := peak[0];
- wavebufR[counter] := peak[1];
- end;
-
- if (position >= dword(ClientWidth)) then
- break;
- cpos := position;
- end;
-
-
- peak[0] := 0;
- peak[1] := 0;
- end;
- BASS_StreamFree(decoder); // free the decoder
- end;
-
- //------------------------------------------------------------------------------
-
- { TScanThread }
-
- constructor TScanThread.Create(decoder: HSTREAM);
- begin
- inherited create(false);
- Priority := tpNormal;
- FreeOnTerminate := true;
- FDecoder := decoder;
- end;
-
- procedure TScanThread.Execute;
- begin
- inherited;
- Form1.ScanPeaks2(FDecoder);
- Terminate;
- end;
-
- //------------------------------------------------------------------------------
-
- procedure TForm1.Timer1Timer(Sender: TObject);
- begin
- if bpp = 0 then exit;
- DrawSpectrum; // draw peak waveform
- DrawTime_Line(loop[0],(loop[0] div bpp),12,TColor($FFFF00)); // loop start
- DrawTime_Line(loop[1],(loop[1] div bpp),24,TColor($00FFFF)); // loop end
- DrawTime_Line(BASS_ChannelGetPosition(chan),(BASS_ChannelGetPosition(chan) div bpp),0,TColor($FFFFFF)); // current pos
- PB.Refresh;
- end;
-
- procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X, Y: Integer);
- begin
- if Button = mbLeft then
- begin
- mousedwn := 1;
- SetLoopStart(dword(x)*bpp)
- end
- else if Button = mbRight then
- begin
- mousedwn := 2;
- SetLoopEnd(dword(x)*bpp);
- end;
- end;
-
- procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
- Y: Integer);
- begin
- if mousedwn = 0 then
- exit;
- if mousedwn = 1 then
- SetLoopStart(dword(x)*bpp)
- else if mousedwn = 2 then
- SetLoopEnd(dword(x)*bpp);
- end;
-
- procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X, Y: Integer);
- begin
- mousedwn := 0;
- end;
-
- procedure TForm1.PBPaint(Sender: TObject);
- begin
- if bpp = 0 then exit;
- PB.Canvas.Draw(0,0,Buffer);
- end;
-
- procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- begin
- if key = 27 then
- Application.Terminate;
- end;
-
- procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
- begin
- Timer1.Enabled := false;
- bpp := 0;
- killscan := true;
- Buffer.Free;
- BASS_Free();
- end;
-
- end.
-