Code:
unit xeEngine_audio_openal;
interface
{$I xeEngine_include.inc}
uses
Classes,
xeEngine_base,
xeEngine_types,
openal;
const
cMaxSources = 10;
type
TxeAudio = class;
//
// TxeSoundBuffer
//
TxeSoundBuffer = class(TxeBaseObject)
private
FFormat : TALenum;
FData : TALvoid;
FSize : TALsizei;
FFreq : TALsizei;
FLoop : TALint;
FBuffer : TALuint;
public
constructor Create;
destructor Destroy; override;
function LoadWavFromStream(Stream: TStream): Boolean;
function LoadWavFromFile(FileName: PWideChar): Boolean;
property Format : TALenum read FFormat;
property Data : TALvoid read FData;
property Size : TALsizei read FSize;
property Freq : TALsizei read FFreq;
property Loop : TALint read FLoop;
property Buffer : TALuint read FBuffer;
end;
//
// TxeSound
//
TxeSound = class(TxeBaseObject)
private
FParent : TxeAudio;
FVolume : Single;
FSource : TALuint;
FBuffer : TxeSoundBuffer;
public
constructor Create(aParent: TxeAudio; aSoundBuffer: TxeSoundBuffer);
destructor Destroy; override;
procedure Play(aVolume,aPan: Single);
end;
//
// TxeAudio
//
TxeAudio = class(TxeBaseObject)
private
FSounds : TStringList;
FSourcePool : array[0..cMaxSources - 1] of TALuint;
// function get a free source for playing purposes
function AcquireSource: TALuint;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function LoadSoundFromFile(aFileName: PWideChar): TxeSound;
end;
// DLL interface routines
function Audio_LoadSoundFromFile(AudioInst: LongWord; aFileName: PWideChar): LongWord; cdecl;
procedure Sound_Play (SoundInst: LongWord; aVolume: Single); cdecl;
implementation
uses
SysUtils,
xeEngine_logfile,
unit_wavbuffer,
WaveFileParser;
// DLL interface routines
function Audio_LoadSoundFromFile(AudioInst: LongWord; aFileName: PWideChar): LongWord;
begin
Result := LongWord(TxeAudio(AudioInst).LoadSoundFromFile(aFileName));
end;
procedure Sound_Play(SoundInst: LongWord; aVolume: Single);
begin
TxeSound(SoundInst).Play(aVolume,1);
end;
const
listenerPos: array[1..3] of TALfloat =(0.0,0.0,0.0);
listenerVel: array[1..3] of TALfloat =(0.0,0.0,0.0);
listenerOri: array[1..6] of TAlfloat =(0.0,0.0,1.0, 0.0,1.0,0.0);
source0Pos : array[1..3] of TALfloat =( 0.0, 0.0, 0.0);
source0Vel : array[1..3] of TALfloat =( 0.0, 0.0, 0.0);
//
// TxeAudio
//
constructor TxeAudio.Create;
var
ALResult: TALenum;
begin
inherited Create(False);
if not InitOpenAL then
begin
LogFile_LogMessage('Error initializing OpenAL!');
end;
alutInit(nil,[]);
alGenSources(cMaxSources,@FSourcePool[0]);
ALResult := alGetError;
if ALResult <> AL_NO_ERROR then
begin
LogFile_LogMessage('Error creating OpenAL sources!');
end;
alListenerfv(AL_POSITION ,@listenerPos);
alListenerfv(AL_VELOCITY ,@listenerVel);
alListenerfv(AL_ORIENTATION,@listenerOri);
FSounds := TStringList.Create;
FSounds.Sorted := True;
FSounds.Duplicates := dupIgnore;
end;
destructor TxeAudio.Destroy;
var
i: Integer;
begin
Clear;
alDeleteSources(cMaxSources,@FSourcePool);
FSounds.Free;
alutExit;
inherited Destroy;
end;
procedure TxeAudio.Clear;
var
i: Integer;
begin
for i := 0 to cMaxSources - 1 do
alSourceStop(FSourcePool[i]);
for i := FSounds.Count - 1 downto 0 do
TxeSoundBuffer(FSounds.Objects[i]).Free;
FSounds.Clear;
end;
function TxeAudio.LoadSoundFromFile(aFileName: PWideChar): TxeSound;
var
FileName: WideString;
Name : WideString;
Index : Integer;
Buffer : TxeSoundBuffer;
Ext : WideString;
begin
Result := nil;
if not FileExists(aFileName) then Exit;
FileName := ExtractFileName(WideString(aFileName));
Ext := LowerCase(ExtractFileExt(FileName));
if Ext <> '.wav' then Exit;
Name := ChangeFileExt(FileName,'');
if FSounds.Find(Name,Index) then
Buffer := TxeSoundBuffer(FSounds.Objects[Index])
else
begin
Buffer := TxeSoundBuffer.Create;
Buffer.LoadWavFromFile(aFileName);
FSounds.AddObject(Name,Buffer);
end;
Result := TxeSound.Create(Self,Buffer);
end;
function TxeAudio.AcquireSource: TALuint;
var
i : Integer;
State: PALint;
begin
Result := 0;
for i := 0 to cMaxSources - 1 do
begin
alGetSourcei(FSourcePool[i],AL_SOURCE_STATE,@State);
if State <> PALint(AL_PLAYING) then
// this source is free so return it
begin
Result := FSourcePool[i];
Exit;
end;
end;
end;
//
// TxeSoundBuffer
//
constructor TxeSoundBuffer.Create;
begin
inherited Create(True);
FFormat := 0;
FData := nil;
FSize := 0;
FFreq := 0;
FBuffer := 0;
end;
destructor TxeSoundBuffer.Destroy;
begin
if FBuffer <> 0 then
alDeleteBuffers(1,@FBuffer);
inherited Destroy;
end;
function TxeSoundBuffer.LoadWavFromStream(Stream: TStream): Boolean;
var
Mem: TMemoryStream;
begin
Mem := TMemoryStream.Create;
try
Stream.Seek(0,soFromBeginning);
Mem.LoadFromStream(Stream);
Mem.Seek(0,soFromBeginning);
alutLoadWAVStream(Mem,FFormat,FData,FSize,FFreq,FLoop);
alGenBuffers(1,@FBuffer);
alBufferData(FBuffer,FFormat,FData,FSize,FFreq);
alutUnloadWAV(FFormat,FData,FSize,FFreq);
finally
Mem.Free;
end;
Result := True;
end;
function TxeSoundBuffer.LoadWavFromFile(FileName: PWideChar): Boolean;
var
WAVFile: TFileStream;
begin
Result := False;
if not FileExists(String(FileName)) then Exit;
WAVFile := TFileStream.Create(String(FileName),fmOpenRead or fmShareDenyWrite);
try
Result := LoadWavFromStream(WAVFile);
finally
WAVFile.Free;
end;
end;
//
// TxeSound
//
constructor TxeSound.Create(aParent: TxeAudio; aSoundBuffer: TxeSoundBuffer);
begin
inherited Create(True);
FSource := 0;
FVolume := 1.0;
FBuffer := aSoundBuffer;
FParent := aParent;
end;
destructor TxeSound.Destroy;
begin
inherited Destroy;
end;
procedure TxeSound.Play(aVolume,aPan: Single);
begin
FSource := FParent.AcquireSource;
if FSource = 0 then Exit;
FVolume := aVolume;
alSourcef (FSource, AL_PITCH , 1.0);
alSourcef (FSource, AL_GAIN , FVolume);
alSourcefv(FSource, AL_POSITION , @source0Pos);
alSourcefv(FSource, AL_VELOCITY , @source0Vel);
alSourcei (FSource, AL_BUFFER , FBuffer.Buffer);
alSourcei (FSource, AL_LOOPING , AL_FALSE);
alSourcePlay(FSource);
end;
end.
Bookmarks