463 lines
11 KiB
ObjectPascal
463 lines
11 KiB
ObjectPascal
unit DTMain;
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
StdCtrls, ExtCtrls, BASS, Math, ComCtrls;
|
|
|
|
const
|
|
|
|
XDIST = 70;
|
|
YDIST = 65;
|
|
XCENTER = 268;
|
|
YCENTER = 92;
|
|
DIAM = 10;
|
|
TIMERPERIOD = 50; // timer period (ms)
|
|
MAXDIST = 50; // maximum distance of the channels (m)
|
|
SPEED = 12;
|
|
|
|
type
|
|
PSource = ^TSource;
|
|
TSource = record
|
|
next: PSource;
|
|
Channel: DWORD;
|
|
pos, vel: BASS_3DVECTOR;
|
|
end;
|
|
|
|
TForm1 = class(TForm)
|
|
GroupBox1: TGroupBox;
|
|
ListBox1: TListBox;
|
|
Button1: TButton;
|
|
Button2: TButton;
|
|
Button3: TButton;
|
|
Button4: TButton;
|
|
Bevel1: TBevel;
|
|
StaticText1: TStaticText;
|
|
GroupBox2: TGroupBox;
|
|
ComboBox1: TComboBox;
|
|
GroupBox3: TGroupBox;
|
|
GroupBox4: TGroupBox;
|
|
Timer1: TTimer;
|
|
OpenDialog1: TOpenDialog;
|
|
ScrollBar_Rolloff: TTrackBar;
|
|
ScrollBar_Doppler: TTrackBar;
|
|
ed_X: TEdit;
|
|
ed_Z: TEdit;
|
|
Label1: TLabel;
|
|
Label2: TLabel;
|
|
btnReset: TButton;
|
|
Bevel2: TBevel;
|
|
Bevel3: TBevel;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure Timer1Timer(Sender: TObject);
|
|
procedure Button1Click(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure ListBox1Click(Sender: TObject);
|
|
procedure Button2Click(Sender: TObject);
|
|
procedure ListBox1KeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure Button3Click(Sender: TObject);
|
|
procedure Button4Click(Sender: TObject);
|
|
procedure ComboBox1Change(Sender: TObject);
|
|
procedure ScrollBar_DopplerChange(Sender: TObject);
|
|
procedure ScrollBar_RollofChange(Sender: TObject);
|
|
procedure btnResetClick(Sender: TObject);
|
|
procedure ed_XKeyPress(Sender: TObject; var Key: Char);
|
|
procedure ed_XChange(Sender: TObject);
|
|
procedure FormPaint(Sender: TObject);
|
|
private
|
|
{ Private-Deklarationen }
|
|
sources: PSource;
|
|
procedure Error(msg: string);
|
|
procedure AddSource(name: string);
|
|
procedure RemSource(num: Integer);
|
|
function GetSource(num: Integer): PSource;
|
|
procedure DrawSources;
|
|
procedure FreeSources;
|
|
procedure ActualizeSources(forceupdate: Boolean);
|
|
procedure ActualizeButtons;
|
|
|
|
public
|
|
{ Public-Deklarationen }
|
|
end;
|
|
|
|
var
|
|
Form1: TForm1;
|
|
|
|
implementation
|
|
|
|
{$R *.DFM}
|
|
|
|
procedure TForm1.Error(msg: string);
|
|
var
|
|
s: string;
|
|
begin
|
|
s := msg + #13#10 + '(error code: ' + IntToStr(BASS_ErrorGetCode) + ')';
|
|
MessageBox(handle, PChar(s), nil, 0);
|
|
end;
|
|
|
|
procedure TForm1.FormCreate(Sender: TObject);
|
|
begin
|
|
sources := nil;
|
|
end;
|
|
|
|
procedure TForm1.AddSource(name: string);
|
|
var
|
|
NewCHan: DWORD;
|
|
p, last: PSource;
|
|
begin
|
|
|
|
// Load a music from "file" with 3D enabled, and make it loop & use ramping
|
|
newchan := BASS_MusicLoad(FALSE, PChar(name), 0, 0, BASS_MUSIC_RAMP or BASS_MUSIC_LOOP or
|
|
BASS_SAMPLE_3D {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF}, 1);
|
|
if (newchan = 0) then
|
|
begin
|
|
// Load a sample from "file" with 3D enabled, and make it loop
|
|
newchan := BASS_SampleLoad(FALSE, PChar(name), 0, 0, 1, BASS_SAMPLE_LOOP or BASS_SAMPLE_3D or
|
|
BASS_SAMPLE_MONO {$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
|
|
end;
|
|
if (newchan = 0) then
|
|
begin
|
|
Error('Can''t load file (note samples must be mono)');
|
|
Exit;
|
|
end;
|
|
|
|
New(p);
|
|
FillChar(p^, SizeOf(P^), 0);
|
|
p.Channel := newchan;
|
|
BASS_SampleGetChannel(newchan, False); // initialize sample channel
|
|
last := sources;
|
|
if last <> nil then
|
|
while (last.next <> nil) do
|
|
last := last.next;
|
|
if last = nil then
|
|
sources := p
|
|
else
|
|
last.next := p;
|
|
ListBox1.Items.Add(name);
|
|
ActualizeButtons;
|
|
end;
|
|
|
|
procedure TForm1.RemSource(num: Integer);
|
|
var
|
|
p, prev: PSource;
|
|
i: Integer;
|
|
begin
|
|
prev := nil;
|
|
p := sources;
|
|
i := 0;
|
|
while (p <> nil) and (i < num) do
|
|
begin
|
|
Inc(i);
|
|
prev := p;
|
|
p := p.next;
|
|
end;
|
|
if (p <> nil) then
|
|
begin
|
|
if (prev <> nil) then
|
|
prev.next := p.next
|
|
else
|
|
sources := p.next;
|
|
BASS_SampleFree(p.channel);
|
|
BASS_MusicFree(p.channel);
|
|
Dispose(p);
|
|
end;
|
|
ListBox1.Items.Delete(num);
|
|
ActualizeButtons;
|
|
end;
|
|
|
|
function TForm1.GetSource(num: Integer): PSource;
|
|
var
|
|
p: PSource;
|
|
i: Integer;
|
|
begin
|
|
if num < 0 then
|
|
begin
|
|
Result := nil;
|
|
Exit;
|
|
end;
|
|
p := sources;
|
|
i := 0;
|
|
while (p <> nil) and (i < num) do
|
|
begin
|
|
Inc(i);
|
|
p := p.next;
|
|
end;
|
|
Result := p;
|
|
end;
|
|
|
|
procedure TForm1.DrawSources;
|
|
var
|
|
p: PSource;
|
|
i, j: Integer;
|
|
begin
|
|
p := sources;
|
|
with Canvas do
|
|
begin
|
|
Brush.Color := Form1.Color;
|
|
Pen.Color := Form1.Color;
|
|
Rectangle(XCENTER - XDIST - DIAM,
|
|
YCENTER - YDIST - DIAM,
|
|
XCENTER + XDIST + DIAM,
|
|
YCENTER + YDIST + DIAM);
|
|
Brush.Color := clGray;
|
|
Pen.Color := clBlack;
|
|
Ellipse(XCENTER - DIAM div 2,
|
|
YCENTER - DIAM div 2,
|
|
XCENTER + DIAM div 2,
|
|
YCENTER + DIAM div 2);
|
|
Pen.Color := Form1.Color;
|
|
i := 0;
|
|
j := ListBox1.ItemIndex;
|
|
while (p <> nil) do
|
|
begin
|
|
if (i = j) then
|
|
Brush.Color := clRed
|
|
else
|
|
Brush.Color := clBlack;
|
|
|
|
Ellipse(XCENTER + Trunc(p.pos.x)+ DIAM div 2,
|
|
YCENTER - Trunc(p.pos.z) + DIAM div 2,
|
|
XCENTER + Trunc(p.pos.x)- DIAM div 2,
|
|
YCENTER - Trunc(p.pos.z)- DIAM div 2);
|
|
p := p.next;
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.ActualizeSources(forceupdate: Boolean);
|
|
var
|
|
p: PSource;
|
|
chng, fchng: Boolean;
|
|
tmp: BASS_3DVECTOR;
|
|
begin
|
|
fchng := forceupdate;
|
|
p := sources;
|
|
while (p <> nil) do
|
|
begin
|
|
chng := forceupdate;
|
|
if (BASS_ChannelIsActive(p.channel) = BASS_ACTIVE_PLAYING) then
|
|
begin
|
|
|
|
if (P.pos.z >= MAXDIST) or (P.pos.z <= -MAXDIST) then
|
|
P.vel.z := -P.vel.z;
|
|
if (p.pos.X >= MAXDIST) or (p.pos.X <= -MAXDIST) then
|
|
P.vel.X := -P.vel.X;
|
|
|
|
// Update channel position
|
|
P.pos.z := P.pos.z + P.vel.z * TIMERPERIOD / 1000;
|
|
P.pos.X := P.pos.X + P.vel.X * TIMERPERIOD / 1000;
|
|
ZeroMemory(@tmp, sizeof(tmp));
|
|
BASS_ChannelSet3DPosition(P.channel, P.pos, tmp, P.vel);
|
|
chng := true;
|
|
end;
|
|
p := p.next;
|
|
if chng then
|
|
fchng := TRUE;
|
|
end;
|
|
if fchng then
|
|
begin
|
|
DrawSources;
|
|
BASS_Apply3D;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.FreeSources;
|
|
var
|
|
p, v: PSource;
|
|
begin
|
|
p := sources;
|
|
while (p <> nil) do
|
|
begin
|
|
v := p.next;
|
|
Dispose(v);
|
|
p := v;
|
|
end;
|
|
sources := nil;
|
|
end;
|
|
|
|
procedure TForm1.Timer1Timer(Sender: TObject);
|
|
begin
|
|
ActualizeSources(false);
|
|
|
|
end;
|
|
|
|
procedure TForm1.Button1Click(Sender: TObject);
|
|
begin
|
|
if OpenDialog1.Execute then
|
|
begin
|
|
AddSource(OpenDialog1.FileName);
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.FormDestroy(Sender: TObject);
|
|
begin
|
|
FreeSources;
|
|
BASS_Stop;
|
|
BASS_Free;
|
|
end;
|
|
|
|
procedure TForm1.ActualizeButtons;
|
|
var
|
|
en: Boolean;
|
|
begin
|
|
en := (ListBox1.ItemIndex >= 0);
|
|
Button2.Enabled := en;
|
|
Button3.Enabled := en;
|
|
Button4.Enabled := en;
|
|
ed_x.Enabled := en;
|
|
ed_z.Enabled := en;
|
|
btnReset.Enabled := en;
|
|
if en then
|
|
DrawSources;
|
|
end;
|
|
|
|
procedure TForm1.ListBox1Click(Sender: TObject);
|
|
begin
|
|
ActualizeButtons;
|
|
end;
|
|
|
|
procedure TForm1.Button2Click(Sender: TObject);
|
|
begin
|
|
if ListBox1.ItemIndex >= 0 then
|
|
RemSource(ListBox1.ItemIndex);
|
|
end;
|
|
|
|
procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
ActualizeButtons;
|
|
end;
|
|
|
|
procedure TForm1.Button3Click(Sender: TObject);
|
|
var
|
|
p: PSource;
|
|
begin
|
|
if ListBox1.ItemIndex < 0 then
|
|
Exit;
|
|
p := GetSource(ListBox1.itemIndex);
|
|
if p <> nil then
|
|
BASS_ChannelPlay(p.channel, False);
|
|
end;
|
|
|
|
procedure TForm1.Button4Click(Sender: TObject);
|
|
var
|
|
p: PSource;
|
|
begin
|
|
if ListBox1.ItemIndex < 0 then
|
|
Exit;
|
|
p := GetSource(ListBox1.ItemIndex);
|
|
if p = nil then
|
|
Exit;
|
|
BASS_ChannelPause(p.channel);
|
|
end;
|
|
|
|
procedure TForm1.ComboBox1Change(Sender: TObject);
|
|
begin
|
|
case (ComboBox1.ItemIndex) of
|
|
0: BASS_SetEAXParameters (-1, 0, -1, -1);
|
|
1: BASS_SetEAXPreset(EAX_ENVIRONMENT_GENERIC);
|
|
2: BASS_SetEAXPreset(EAX_ENVIRONMENT_PADDEDCELL);
|
|
3: BASS_SetEAXPreset(EAX_ENVIRONMENT_ROOM);
|
|
4: BASS_SetEAXPreset(EAX_ENVIRONMENT_BATHROOM);
|
|
5: BASS_SetEAXPreset(EAX_ENVIRONMENT_LIVINGROOM);
|
|
6: BASS_SetEAXPreset(EAX_ENVIRONMENT_STONEROOM);
|
|
7: BASS_SetEAXPreset(EAX_ENVIRONMENT_AUDITORIUM);
|
|
8: BASS_SetEAXPreset(EAX_ENVIRONMENT_CONCERTHALL);
|
|
9: BASS_SetEAXPreset(EAX_ENVIRONMENT_CAVE);
|
|
10: BASS_SetEAXPreset(EAX_ENVIRONMENT_ARENA);
|
|
11: BASS_SetEAXPreset(EAX_ENVIRONMENT_HANGAR);
|
|
12: BASS_SetEAXPreset(EAX_ENVIRONMENT_CARPETEDHALLWAY);
|
|
13: BASS_SetEAXPreset(EAX_ENVIRONMENT_HALLWAY);
|
|
14: BASS_SetEAXPreset(EAX_ENVIRONMENT_STONECORRIDOR);
|
|
15: BASS_SetEAXPreset(EAX_ENVIRONMENT_ALLEY);
|
|
16: BASS_SetEAXPreset(EAX_ENVIRONMENT_FOREST);
|
|
17: BASS_SetEAXPreset(EAX_ENVIRONMENT_CITY);
|
|
18: BASS_SetEAXPreset(EAX_ENVIRONMENT_MOUNTAINS);
|
|
19: BASS_SetEAXPreset(EAX_ENVIRONMENT_QUARRY);
|
|
20: BASS_SetEAXPreset(EAX_ENVIRONMENT_PLAIN);
|
|
21: BASS_SetEAXPreset(EAX_ENVIRONMENT_PARKINGLOT);
|
|
22: BASS_SetEAXPreset(EAX_ENVIRONMENT_SEWERPIPE);
|
|
23: BASS_SetEAXPreset(EAX_ENVIRONMENT_UNDERWATER);
|
|
24: BASS_SetEAXPreset(EAX_ENVIRONMENT_DRUGGED);
|
|
25: BASS_SetEAXPreset(EAX_ENVIRONMENT_DIZZY);
|
|
26: BASS_SetEAXPreset(EAX_ENVIRONMENT_PSYCHOTIC);
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.ScrollBar_DopplerChange(Sender: TObject);
|
|
var
|
|
a: integer;
|
|
begin
|
|
a := ScrollBar_Doppler.Position;
|
|
BASS_Set3DFactors(-1, -1, Power(2, a - 10 / 5.0));
|
|
end;
|
|
|
|
procedure TForm1.ScrollBar_RollofChange(Sender: TObject);
|
|
var
|
|
a: integer;
|
|
begin
|
|
a:= ScrollBar_Rolloff.Position;
|
|
BASS_Set3DFactors(-1, Power(2, (a - 10) / 5.0), -1);
|
|
end;
|
|
|
|
procedure TForm1.btnResetClick(Sender: TObject);
|
|
var
|
|
p: PSource;
|
|
tmp : BASS_3DVECTOR;
|
|
begin
|
|
ed_x.Text := '0';
|
|
ed_z.Text := '0';
|
|
if ListBox1.ItemIndex < 0 then
|
|
Exit;
|
|
p := GetSource(ListBox1.ItemIndex);
|
|
if p <> nil then
|
|
begin
|
|
ZeroMemory(@tmp, sizeof(tmp));
|
|
p.pos := tmp;
|
|
p.vel := tmp;
|
|
ActualizeSources(TRUE);
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.ed_XKeyPress(Sender: TObject; var Key: Char);
|
|
begin
|
|
if Key in [Char(VK_BACK)] then
|
|
Key := '0'
|
|
else if not (Key in ['0'..'9']) then
|
|
Key := #0;
|
|
//Only Numbers and Back key allowed
|
|
end;
|
|
|
|
procedure TForm1.ed_XChange(Sender: TObject);
|
|
var
|
|
p: PSource;
|
|
v_x, v_z: integer;
|
|
begin
|
|
if ListBox1.ItemIndex < 0 then
|
|
Exit;
|
|
p := GetSource(ListBox1.ItemIndex);
|
|
if p <> nil then
|
|
begin
|
|
v_x := strtointdef(ed_x.Text, 0);
|
|
v_z := strtointdef(ed_z.Text, 0);
|
|
// X velocity
|
|
|
|
if abs(round(P.vel.x))<> v_x then
|
|
P.vel.x := v_x;
|
|
// Z velocity
|
|
if abs(round(P.vel.z)) <> v_z then
|
|
P.vel.z := v_z;
|
|
ActualizeSources(TRUE);
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.FormPaint(Sender: TObject);
|
|
begin
|
|
DrawSources;
|
|
end;
|
|
|
|
end.
|
|
|