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);
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;
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);
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
Mem.LoadFromStream(Stream);
Mem.Seek(0,soFromBeginning);
alutLoadWAVMemory(Mem.Memory,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;
procedure InitAudio;
begin
if not InitOpenAL then
begin
LogFile_LogMessage('Error initializing OpenAL!');
end;
end;
initialization
InitAudio;
end.
The audio class loads sound files (the TxeSoundBuffer class), and stores them so only one instance of any sound is loaded...this instance is added to the actual loaded TxeSound class for playing.
Bookmarks