PDA

View Full Version : Simple OpenAL Library



cairnswm
26-10-2004, 06:58 AM
Just realised I never published my OpenAL library :)

It is for simple sounds - there is no fading, moving, stereo etc. This is designed for straight forward puzzle games. This library was created after reading through the OpanAL site.

The Library contains two objects. The main Object is the SoundEngine that controls and manages the various sound items.

Make sure that the file OpenAL.dll is avaialble on the destination PC (I include it in my install program).

unit ALSound;

interface

// ------------------------------------------
//
// ALSound
//
// (C) CairnsGames S.A. 2004
//
// Version 1.0 2004/07/12
//
//-------------------------------------------

uses
Classes, al, altypes, alut;

Type
TOpenALSoundItem = Class
Private
buffer : TALuint;
source : TALuint;
Volume : Integer;
FName: String;
procedure SetName(const Value: String);
Public
Property Name : String read FName write SetName;
Constructor Create; Overload;
Constructor Create(FileName : String); Overload;
Destructor Destroy; Override;
Procedure Play(NewVolume : Integer); Overload;
Procedure Play; Overload;
Procedure Stop;
Procedure Pause;
End;
TOpenALSoundEngine = Class(TComponent)
Private
FItems: TList;
procedure SetItems(const Value: TList);
Public
Property Items : TList read FItems write SetItems;
Constructor Create(AnOwner : TComponent); Override;
Destructor Destroy; Override;
Procedure Load(Name, FileName : String);
Procedure Play(Index : Integer; Volume : Integer = 100);
Procedure Stop(Index : Integer);
Procedure Pause(Index : Integer);
Function Find(SoundName : String) : TOpenALSoundItem;
End;

implementation

{ TOpenALSoundEngine }

const
sourcepos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 );
sourcevel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 );
listenerpos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0);
listenervel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0);
listenerori: array [0..5] of TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);


constructor TOpenALSoundEngine.Create(AnOwner: TComponent);
var
argv: array of PChar;
Item : TOpenALSoundItem;
begin
Items := TList.Create;
AlutInit(nil,argv);

Item := TOpenALSoundItem.Create;
Items.Add(Item);
end;

destructor TOpenALSoundEngine.Destroy;
begin
AlutExit();

end;

function TOpenALSoundEngine.Find(SoundName: String): TOpenALSoundItem;
Var
I : Integer;
SoundItem : TOpenALSoundItem;
begin
For I := 0 to Items.Count - 1 do
Begin
SoundItem := TOpenALSoundItem(Items[I]);
If SoundItem.Name = SoundName then
Begin
Result := SoundItem;
Exit;
End;
End;
Result := Nil;
end;

procedure TOpenALSoundEngine.Load(Name, FileName: String);
var
Item : TOpenALSoundItem;
begin
Item := TOpenALSoundItem.Create(FileName);
Item.Name := Name;
Items.Add(Item);
end;

procedure TOpenALSoundEngine.Pause(Index: Integer);
begin
TOpenALSoundItem(Items[Index]).Pause;


end;

procedure TOpenALSoundEngine.Play(Index: Integer; Volume : Integer);
begin
TOpenALSoundItem(Items[Index]).Play(Volume);
end;

procedure TOpenALSoundEngine.SetItems(const Value: TList);
begin
FItems := Value;
end;

procedure TOpenALSoundEngine.Stop(Index: Integer);
begin
TOpenALSoundItem(Items[Index]).Stop;

end;

{ TOpenALSoundItem }

constructor TOpenALSoundItem.Create;
var
format: TALEnum;
size: TALSizei;
freq: TALSizei;
loop: TALInt;
data: TALVoid;
begin
AlGenBuffers(1, @buffer);
// AlutLoadWavFile('..\sound\dog1.wav', format, data, size, freq, loop);
AlBufferData(buffer, format, data, size, freq);
AlutUnloadWav(format, data, size, freq);

AlGenSources(1, @source);
AlSourcei ( source, AL_BUFFER, buffer);
AlSourcef ( source, AL_PITCH, 1.0 );
AlSourcef ( source, AL_GAIN, 1.0 );
AlSourcefv ( source, AL_POSITION, @sourcepos);
AlSourcefv ( source, AL_VELOCITY, @sourcevel);
AlSourcei ( source, AL_LOOPING, loop);

AlListenerfv ( AL_POSITION, @listenerpos);
AlListenerfv ( AL_VELOCITY, @listenervel);
AlListenerfv ( AL_ORIENTATION, @listenerori);

Volume := 100;
end;

constructor TOpenALSoundItem.Create(FileName: String);
var
format: TALEnum;
size: TALSizei;
freq: TALSizei;
loop: TALInt;
data: TALVoid;
begin
AlGenBuffers(1, @buffer);
AlutLoadWavFile(FileName, format, data, size, freq, loop);
AlBufferData(buffer, format, data, size, freq);
AlutUnloadWav(format, data, size, freq);

AlGenSources(1, @source);
AlSourcei ( source, AL_BUFFER, buffer);
AlSourcef ( source, AL_PITCH, 1.0 );
AlSourcef ( source, AL_GAIN, 1.0 );
AlSourcefv ( source, AL_POSITION, @sourcepos);
AlSourcefv ( source, AL_VELOCITY, @sourcevel);
AlSourcei ( source, AL_LOOPING, loop);

AlListenerfv ( AL_POSITION, @listenerpos);
AlListenerfv ( AL_VELOCITY, @listenervel);
AlListenerfv ( AL_ORIENTATION, @listenerori);

Volume := 100;
end;

destructor TOpenALSoundItem.Destroy;
begin
AlDeleteBuffers(1, @buffer);
AlDeleteSources(1, @source);
end;

procedure TOpenALSoundItem.Pause;
begin
AlSourcePause(source);
end;

procedure TOpenALSoundItem.Play(NewVolume : Integer);
begin
Volume := NewVolume;
AlSourcef (source, AL_GAIN, Volume / 100);
AlSourcePlay(source);
end;

procedure TOpenALSoundItem.Play;
begin
AlSourcef ( source, AL_GAIN, Volume / 100);
AlSourcePlay(source);
end;

procedure TOpenALSoundItem.SetName(const Value: String);
begin
FName := Value;
end;

procedure TOpenALSoundItem.Stop;
begin
AlSourceStop(source);
end;

end.

To Use the Library you first need to create the engine, load a sound and play it.

To create the engine and load some sounds:
procedure TMainForm.LoadSounds;
begin
SoundEngine := TOpenALSoundEngine.Create(Self);
SoundEngine.Load('Click1','Sound\Click1.wav');
SoundEngine.Load('Click2','Sound\Click2.wav');
end;


To Play a sound you just find the sound and call play:
SoundEngine.Find('Click1').Play;



Actually quite simple.

Traveler
26-10-2004, 07:27 AM
Very nice!

Thanks for sharing this!

cairnswm
26-10-2004, 07:41 AM
Thanks

Its a pleasure :)

(I've just notices that the sound engine doesn't release all the sound items - oops)

Robert Kosek
26-10-2004, 03:02 PM
:shock: WHoa! Wish I was more OOP oriented, I can't write it but I can use it fairly well.

Forgot to free everything properly? No prob:
destructor TOpenALSoundEngine.Destroy;
var
I: Integer;
begin
for I := low[items] to high[items] do begin
Stop(I); // If it's playing avoid errors
items[I].Free;
end;
AlutExit();
end;

Is that it? Thought I'd post my "fix"...
EDIT: Put in "Item[i].destroy" instead of "free"

cairnswm
27-10-2004, 05:05 AM
Pretty close to the way I'd do it:

Destructor TOpenALSoundEngine.Destroy;
var
I: Integer;
begin
For I := Items.count -1 downto 0 do
Begin
Stop(I); // If it's playing avoid errors
Items[I].Free;
Items.delete(I);
End;
AlutExit();
End;

:) - I havn't tested it - just typed it in so if you use it test it first.

Robert Kosek
27-10-2004, 02:50 PM
:lol: I haven't use a TList object before so it was a "lucky" guess to be so close. Forgot it was like a stringlist, heh.

Robert Kosek
31-10-2004, 01:42 PM
I downloaded the OpenAL library and noticed it was all in C headers. Does FreePascal support C/C++ headers? Or will I have to change them? :?:

cairnswm
31-10-2004, 05:17 PM
Go to noeska's site and download the Delphi Headers

My library does not work with FreePascal :(

Robert Kosek
31-10-2004, 07:00 PM
In that case what would the best FPC solution be? I am semi-experienced with the BASS library in Delphi, but what would the best choice be?

I am working on a hangman-esque game using the VGFX you found, and I'm doing all the art. A friend is doing some music, but I don't know an adaquate FPC compatible library... I will likely release it as an Open Source game.

WILL
01-11-2004, 12:48 AM
Robert, for OpenAL try noeska's site.

http://www.noeska.com/doal/

For a mod playback engine(if thats what your friend is using try SoundLib 2:
http://www.crossfire-designs.de/index.php?lang=en&what=sourcecode&name=sl2.htm

sardaukar
26-08-2005, 01:16 AM
thanks for sharing, this is really nice to get started with.

Is there anyone that can give a snippet on two sources sharing buffers? and positioning them differently?

JSoftware
26-08-2005, 03:56 PM
you forget to inherit create and destroy procedures