Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 27

Thread: Win/Linux/Mac OSX Sound API with no .DLL/.SO dependencies?

  1. #11
    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:

    openal.zip
    OpenAL32.zip

    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.

    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
    Last edited by paul_nicholls; 09-09-2011 at 12:37 AM.

  2. #12
    Ok, I have fixed my OpenAL issues now

    1) I was missing this code:
    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

    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.
    openal.zip


    cheers,
    Paul

  3. #13
    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.

  4. #14
    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.

  5. #15
    Quote Originally Posted by Andru View Post
    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

  6. #16
    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.
    The views expressed on this programme are bloody good ones. - Fred Dagg

  7. #17
    PGD Staff code_glitch's Avatar
    Join Date
    Oct 2009
    Location
    UK (England, the bigger bit)
    Posts
    933
    Blog Entries
    45
    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...
    I once tried to change the world. But they wouldn't give me the source code. Damned evil cunning.

  8. #18
    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

  9. #19
    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/i.../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
    The views expressed on this programme are bloody good ones. - Fred Dagg

  10. #20
    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/threa...427&tstart=375

    Thanks.

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

    I might have to put it into the too hard basket for a few weeks and come back to it
    The views expressed on this programme are bloody good ones. - Fred Dagg

Page 2 of 3 FirstFirst 123 LastLast

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •