PDA

View Full Version : Win/Linux/Mac OSX Sound API with no .DLL/.SO dependencies?



paul_nicholls
07-09-2011, 05:39 AM
Hi all,
I am writing a cross-platform game engine (Windows first, Linux later, and then maybe Mac OSX), and I am hoping to add in some sound support (.wav files first, then maybe .ogg).

I am hoping to do the sound loading/playing without using some external .DLL/.SO file, and just use some Pascal units.

This is to keep down the number of external libraries that I need to deploy with my engine .DLL/.SO file...

Does anyone here know of such a beast?

I know I could use OpenAL, BASS, FMOD, Audiere, but those need an external .DLL/.SO file, don't they?

Maybe I could use the WaveOut API on windows, but what can I use under Linux/Mac OSX?

cheers,
Paul

Andru
07-09-2011, 08:53 AM
Windows - DirectSound
Linux/MacOS X - OpenAL is de facto standard :)

If you want something like WaveOut in Windows, then you will be needed to use ALSA(as much popular than OSS) for Linux and CoreAudio for MacOS X.

paul_nicholls
07-09-2011, 09:30 AM
Thanks for the info mate :)

One question...does OpenAL come pre-installed on Linux/MacOSX...or does one need to install it themselves? I am guessing that maybe Linux needs the user to install it, but maybe not in Mac OSX.

I will look up ALSA and CorAudio...

cheers,
Paul

Andru
07-09-2011, 09:59 AM
OpenAL is pre-installed on MacOS X and iOS. What about Linux - you can always use dependencies list, but Linux system with games and without OpenAL - something far from reality, IMHO )

WILL
07-09-2011, 08:26 PM
OpenAL is pretty much the best thing you could use for cross-platform. If you are doing windows only, you can just use DirectSound if you prefer, but I woudn't try using much else unless you want headaches while trying to port your sound system over to new platforms. You'll just end up having to rewrite your games sound code for each platform. :P

Linux users shouldn't need user-friendliness, they're all super-geeks anyways. ;) Just tell them what they need. Mac users will love you for using OpenAL and putting everything into one single bundle nicely/properly. Esp. those that like the new Launchpad for Lion.

paul_nicholls
07-09-2011, 08:50 PM
linux users shouldn't need user-friendliness, they're all super-geeks anyways. ;)

bwahahahahaha!!! :D

Ok, I'm sold...I will go for OpenAL then guys, thanks all! I will just ignore the fact that I need to deploy the extra DLL then ;)

cheers,
Paul

code_glitch
08-09-2011, 09:23 PM
Just dropping a line to say two things really:
1. OpenAL
2.


linux users shouldn't need user-friendliness, they're all super-geeks anyways. ;)
That wasn't entirely true when I started out, but now I'd have to almost agree. Ever since I stopped using a mouse for most things and replaced it by Ctrl + Alt + t and Alt + F2 with the ls, top, cat and similar reflexes - windows feels ancient :D

paul_nicholls
08-09-2011, 10:22 PM
Just dropping a line to say two things really:
1. OpenAL
2.


hehe, shouldn't that have been:

1. OpenAL
2. OpenAL
3. OpenAL
...
N. OpenAL


That wasn't entirely true when I started out, but now I'd have to almost agree. Ever since I stopped using a mouse for most things and replaced it by Ctrl + Alt + t and Alt + F2 with the ls, top, cat and similar reflexes - windows feels ancient :D

:D

cheers,
Paul

paul_nicholls
08-09-2011, 11:49 PM
Ok, I have now made an OpenAL sound audio class, but i am having troubles;

I have the code below:



const
cMaxSources = 10;

type
TxeAudio = class(TxeBaseObject)
private
FSounds : TStringList;
FSourcePool : array[0..cMaxSources - 1] of TALuint;
public



constructor TxeAudio.Create;
var
ALResult: TALenum;
begin
inherited Create(False);

if not InitOpenAL then
begin
LogFile_LogMessage('Error initializing OpenAL!');
end;

alGenSources(cMaxSources,@FSourcePool[0]);

ALResult := alGetError;

if ALResult <> AL_NO_ERROR then
begin
LogFile_LogMessage('Error creating OpenAL sources!');
end;

But for some reason when I call alGenSources(), my FSourcePool array is all zeros still, and I am getting no error (or log file output).

Is this normal?

cheers,
Paul

paul_nicholls
09-09-2011, 12:11 AM
I don't know if I am having trouble as I had to modify the openal.pas file to compile under Delphi 2010?

I changed al PChar to PAnsiChar and Char to AnsiChar for example...

Does anyone here have an openal.pas file that is already updated to work under D2010/freepascal?

cheers,
Paul

paul_nicholls
09-09-2011, 12:27 AM
Here is my OpenAL audio unit to see if anyone might be able to see what is going on, and the openal unit + dll too:

615
616


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(aFi leName));
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,F Freq,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.

I have noticed that loading the sound doesn't seem to do anything either...the FBuffer is zero as well as all the sources, and so is most of the data returned from the alutLoadWAVFile() routine. All this is probably related!!

I'm not getting any crashes, it just isn't working :(

cheers,
Paul

paul_nicholls
09-09-2011, 04:51 AM
Ok, I have fixed my OpenAL issues now :D

1) I was missing this code:
alutInit(nil,[]);

2) The WAV loading routines weren't working correctly in the openal.pas for me so I replaced them from an ALut.pas file I found in the Project JEDI.

I found there was still a bug fix in the loading code so I fixed it, and added a alutLoadWAVStream routine which the other loaders now use.

I have attached my fixed code, and the altered version of openal.pas


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(aFi leName));
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,FL oop);
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.

617


cheers,
Paul

Andru
09-09-2011, 09:03 AM
ALUT is a bad idea... because this is not a standard functionalty of OpenAL. If you want to play some format(e.g. wav) you should write your own decoder.

Traveler
09-09-2011, 09:25 AM
I don't know if you have read them, but the tutorials from Noeska may offer some help: http://www.noeska.com/doal/tutorials.aspx.

paul_nicholls
09-09-2011, 11:38 AM
ALUT is a bad idea... because this is not a standard functionalty of OpenAL. If you want to play some format(e.g. wav) you should write your own decoder.

Usually I would agree with you, but the ALUT stuff I am using in the openal.pas file is software only (has it's own WAV loader code), and doesn't use a DLL at all, so it should be just fine :)

@Traveler: thanks, I have seen those, I just had forgotten to do the darn alutInit() call! This is why all my sources/buffers were all at zero.

cheers,
Paul

czar
19-09-2011, 07:22 AM
I was hoping to be able to us BASS for my project that I want to have on pc and Mac and maybe on iOS

However, the delphi header for Bass requires windows.

I need to play wav files and mp3.

Has any got a good solution for this issue?

I am using dlephi XE2 with firemonkey.

I am really stuck at the moment. :(

code_glitch
19-09-2011, 06:44 PM
wav, thats the simple side. The problem then is mp3, specifically I would guess you're having trouble finding a decoder to match your license no? I heard of libmpg123 or something like that might be good...

paul_nicholls
19-09-2011, 10:20 PM
If you convert the .mp3 to .ogg then I think more 3rd party sound libraries will be able to play the music. Also, .mp3 theoretically requires a license before you can play those :(

cheers,
Paul

czar
20-09-2011, 01:58 AM
Problem is the app needs to be able to play MP3s because the user has to be able to use their own songs etc. I was hoping to use BASS but the delphi header requires windows.

I found this which gave me hope

----
Fairly straightforward in Objective Pascal using the ObjC AVAudioPlayer class:

http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html#//apple_ref/occ/cl/AVAudioPlayer

Here's example code:

var
snd : AVAudioPlayer;
{Since sound is played asynchronously, can't release (or autorelease)
until after sound is done playing, so declare and release somewhere
outside PlaySound. Call snd.release to release.}

procedure PlaySound(sndFileName : NSString);
var
path : NSString;
url : NSURL;
err : NSError;
begin
path := NSBundle.mainBundle.resourcePath.
stringByAppendingPathComponent(sndFileName);

url := NSURL.fileURLWithPath(path);

snd := AVAudioPlayer.alloc.initWithContentsOfURL_error(ur l, @err);
if Assigned(snd) then
snd.play
else
NSLog(NSSTR('Error'));
end;
Call it like this:

PlaySound(NSSTR('Cartoon Boing.mp3'));

This file is included with iMovie. Just add your audio file(s) to your Xcode project and they'll be copied to your app bundle when you build the app.

Now, the only thing you'll need is Pascal units for the parsed Foundation and AVFoundation frameworks. Check with Embarc for that.

Thanks.

-Phil

-----

However, use of the word straightforward was not as straightforward for me. I cannot find a pas file to add to uses that gives me access to the AVAudioPlayer

czar
20-09-2011, 02:03 AM
Actually he has just replied but I am still in the dark - I will have to read his parsing text and see I get any headway

==============
You'll somehow have to parse the iOS AVFoundation framework on your Mac in order to get access to the Objective C AVAudioPlayer class that you can use in Pascal as in the example code.

Note that you don't need the entire class, just the methods you need. See this explanation for how to "parse" those methods by hand for now until an updated parser is available:

https://forums.embarcadero.com/thread.jspa?threadID=60427&tstart=375

Thanks.

-Phil
===========

I might have to put it into the too hard basket for a few weeks and come back to it

User137
20-09-2011, 10:35 AM
I had a weird idea one day, putting Delphis TMediaPlayer in a dll so it could be used with Lazarus for musics... That component never failed me with MP3's. Other than that i used to have OpenAL ogg player for Delphi but i haven't managed to get that working with Lazarus.

Ingemar
25-09-2011, 09:06 PM
I use OpenAL with FPC. No problems, except that Apple's OpenAL implementation seems less that satisfactory. I have seen reports of rather severe bugs.

paul_nicholls
25-09-2011, 10:26 PM
Thanks for the info Ingemar :)
I don't know if I will be able to port my game to Mac OS X any time soon - I don't have any Mac hardware, and haven't been able to get OS X working in a virtual machine to test either :(

That will have to wait for some future time :)

On the upside, I have gotten it to work on Windows and now Linux (Ubuntu), Yay! This is thanks to me using SDL, OpenGL, and OpenAL :)

cheers,
Paul

Ingemar
15-10-2011, 06:13 PM
Didn't I hear someone mentioning that the problems with playing sounds in SDL was fixed? Maybe wishful thinking but there was a thread about sound libraries in the Mac game programming mailing list.

I really don't want to use Core Audio. It is yet another platform dependent library, and a messy one for that matter.

Relfos
07-11-2011, 02:47 PM
For crossplatforming I certaintly would recommend OpenAL, available for every platform (as it lets you reuse the same code and it just works), combined with libogg/libmad makes it very easy to play ogg or mp3 everywhere.
I had zero problems with it in all platforms I've tested (basically all of them)
There is just a situation that I found that required a different solution. Decoding of mp3/ogg in iOS (and possibly Android) is quite slow if done in software, and there I just use the native audio library that uses the hardware decoder (ogg not supported though).

Ingemar
09-11-2011, 06:20 AM
I had zero problems with it in all platforms I've tested (basically all of them)
Were you playing in more than two channels simultaneously? With different volume in each channel?

User137
09-11-2011, 07:18 AM
Do you have any source code for the MP3 or OGG playing for OpenAL? I have been unable to play any musics with OpenAL on Lazarus be it just Win32.

But i'm pretty happy about BASS at the moment. It should work on many platforms, but best of all, it's easy to use and supports wide variety of formats. I do like the MOD/XM formats aswell and they are played as easily as WAV with BASS, on many channels, and with 3D pos if needed.

And best of all, it's free for non commercial projects like most games i make should be.