-
-Strict
-
-Rem
-bbdoc: Audio/OpenAL audio
-about:
-The OpenAL audio module provide OpenAL drivers for use with the #audio module.
-End Rem
-Module BRL.OpenALAudio
-
-ModuleInfo "Version: 1.05"
-ModuleInfo "Author: Mark Sibly"
-ModuleInfo "License: zlib/libpng"
-ModuleInfo "Copyright: Blitz Research Ltd"
-ModuleInfo "Modserver: BRL"
-
-ModuleInfo "History: 1.05 Release"
-ModuleInfo "History: Fixed default channel volume,pan,rate"
-ModuleInfo "History: Fixed behaviour of channel going out of scope"
-ModuleInfo "History: 1.04 Release"
-ModuleInfo "History: Fixed channel playing to return true if active (playing or paused)"
-ModuleInfo "History: 1.03 Release"
-ModuleInfo "History: Added (synced) alDeleteBuffers"
-ModuleInfo "History: 1.02 Release"
-ModuleInfo "History: Added EnableOpenALAudio"
-ModuleInfo "History: 1.01 Initial Release"
-
-Import BRL.Math
-Import BRL.Audio
-Import Pub.OpenAL
-
-Private
-
-Const CLOG=False
-
-'list of all non-static sources
-Global _sources:TOpenALSource
-
-Function CheckAL()
- Local err$
- Select alGetError()
- Case AL_NO_ERROR
- Return True
- Case AL_INVALID_NAME
- err="INVALID_NAME"
- Case AL_INVALID_ENUM
- err="INVALID_ENUM"
- Case AL_INVALID_VALUE
- err="INVALID_VALUE"
- Case AL_INVALID_OPERATION
- err="INVALID_OPERATION"
- Case AL_OUT_OF_MEMORY
- err="OUT_OF_MEMORY"
- Default
- err="?????"
- End Select
- If CLOG WriteStdout "OpenAL Error: "+err+"~n"
- Return False
-End Function
-
-Type TOpenALSource
-
- Field _succ:TOpenALSource,_id,_seq,_sound:TOpenALSound,_avail
-
- Method Playing()
- Local st
- alGetSourcei _id,AL_SOURCE_STATE,Varptr st
- Return st=AL_PLAYING
- End Method
-
- Method Paused()
- Local st
- alGetSourcei _id,AL_SOURCE_STATE,Varptr st
- Return st=AL_PAUSED Or st=AL_INITIAL
- End Method
-
- Method Active()
- Local st
- alGetSourcei _id,AL_SOURCE_STATE,Varptr st
- Return st=AL_PLAYING Or st=AL_PAUSED Or st=AL_INITIAL
- End Method
-
- Method LogState()
- Local st
- alGetSourcei _id,AL_SOURCE_STATE,Varptr st
- Select st
- Case AL_PAUSED WriteStdout "AL_PAUSED~n"
- Case AL_INITIAL WriteStdout "AL_INITIAL~n"
- Case AL_STOPPED WriteStdout "AL_STOPPED~n"
- Case AL_PLAYING WriteStdout "AL_PLAYING~n"
- Default WriteStdout "AL_DUNNO, st="+st+"~n"
- End Select
- End Method
-
-End Type
-
-Function EnumOpenALDevices$[]()
- Local p:Byte Ptr=alcGetString( 0,ALC_DEVICE_SPECIFIER )
- If Not p Return
- Local devs$[100],n
- While p[0] And n<100
- Local sz
- Repeat
- sz:+1
- Until Not p[sz]
- devs[n]=String.FromBytes( p,sz )
- n:+1
- p:+sz+1
- Wend
- Return devs[..n]
-End Function
-
-Public
-
-Type TOpenALSound Extends TSound
-
- Method Delete()
- alDeleteBuffers 1,Varptr _buffer
- CheckAL
- If CLOG WriteStdout "Deleted OpenAL buffer "+_buffer+"~n"
- End Method
-
- Method Play:TOpenALChannel( alloced_channel:TChannel=Null )
- Local t:TOpenALChannel=Cue( alloced_channel )
- t.SetPaused False
- Return t
- End Method
-
- Method Cue:TOpenALChannel( alloced_channel:TChannel=Null )
- Local t:TOpenALChannel=TOpenALChannel( alloced_channel )
- If t
- Assert t._static
- Else
- t=TOpenALChannel.Create( False )
- EndIf
- t.Cue Self
- Return t
- End Method
-
- Function Create:TOpenALSound( sample:TAudioSample,flags )
- Local alfmt
- Select sample.format
- Case SF_MONO8
- alfmt=AL_FORMAT_MONO8
- Case SF_MONO16LE
- alfmt=AL_FORMAT_MONO16
-?BigEndian
- sample=sample.Convert( SF_MONO16BE )
-?
- Case SF_MONO16BE
- alfmt=AL_FORMAT_MONO16
-?LittleEndian
- sample=sample.Convert( SF_MONO16LE )
-?
- Case SF_STEREO8
- alfmt=AL_FORMAT_STEREO8
- Case SF_STEREO16LE
- alfmt=AL_FORMAT_STEREO16
-?BigEndian
- sample=sample.Convert( SF_STEREO16BE )
-?
- Case SF_STEREO16BE
- alfmt=AL_FORMAT_STEREO16
-?LittleEndian
- sample=sample.Convert( SF_STEREO16LE )
-?
- End Select
-
- Local buffer=-1
- alGenBuffers 1,Varptr buffer
- CheckAL
-
- If CLOG WriteStdout "Generated OpenAL buffer "+buffer+"~n"
-
- alBufferData buffer,alfmt,sample.samples,sample.length*BytesPerSample[sample.format],sample.hertz
- CheckAL
-
- Local t:TOpenALSound=New TOpenALSound
- t._buffer=buffer
- If (flags & 1) t._loop=1
- Return t
- End Function
-
- Field _buffer,_loop
-
-End Type
-
-Type TOpenALChannel Extends TChannel
-
- Method Delete()
- If _seq<>_source._seq Return
-
- If _static 'LEAKED!
- Stop 'Just in case...
- Return
- EndIf
-
- If Not _source.Playing()
- alSourceStop _source._id
- alSourcei _source._id,AL_BUFFER,0
- _source._sound=Null
- EndIf
-
- End Method
-
- Method Stop()
- If _seq<>_source._seq Return
-
- _source._seq:+1
-
- alSourceStop _source._id
- alSourcei _source._id,AL_BUFFER,0
- _source._sound=Null
-
- If _static
- _source._avail=True
- _source._succ=_sources
- _sources=_source
- EndIf
- End Method
-
- Method SetPaused( paused )
- If _seq<>_source._seq Return
-
- If paused
- alSourcePause _source._id
- Else
- If _source.Paused() alSourcePlay _source._id
- EndIf
- End Method
-
- Method SetVolume( volume# )
- If _seq<>_source._seq Return
-
- alSourcef _source._id,AL_GAIN,volume
- End Method
-
- Method SetPan( pan# )
- If _seq<>_source._seq Return
-
- pan:*90
- alSource3f _source._id,AL_POSITION,Sin(pan),0,-Cos(pan)
- End Method
-
- Method SetDepth( depth# )
- If _seq<>_source._seq Return
- End Method
-
- Method SetRate( rate# )
- If _seq<>_source._seq Return
-
- alSourcef _source._id,AL_PITCH,rate
- End Method
-
- Method Playing()
- If _seq<>_source._seq Return
-
- Return _source.Playing()
- End Method
-
- Method Cue( sound:TOpenALSound )
- If _seq<>_source._seq Return
-
- _source._sound=sound
- alSourceRewind _source._id
- alSourcei _source._id,AL_LOOPING,sound._loop
- alSourcei _source._id,AL_BUFFER,sound._buffer
- End Method
-
- Function Create:TOpenALChannel( static )
-
- Local source:TOpenALSource=_sources,pred:TOpenALSource
- While source
- If source._avail Or Not source.Active()
- source._seq:+1
- If pred pred._succ=source._succ Else _sources=source._succ
- If CLOG WriteStdout "Recycling OpenAL source "+source._id+"~n"
- If CLOG source.LogState
- alSourceRewind source._id 'return to FA_INITIAL state
- If CLOG source.LogState
- alSourcei source._id,AL_BUFFER,0
- source._sound=Null
- Exit
- EndIf
- pred=source
- source=source._succ
- Wend
-
- If Not source
- source=New TOpenALSource
-
- alGenSources 1,Varptr source._id
- CheckAL
-
- If source._id
- If CLOG WriteStdout "Generated OpenAL source "+source._id+"~n"
- Else
- If CLOG WriteStdout "Failed to generate OpenAL source~n"
- EndIf
- EndIf
-
- Local t:TOpenALChannel=New TOpenALChannel
- t._source=source
- t._seq=source._seq
- t._static=static
- If source._id
- alSourcei source._id,AL_SOURCE_RELATIVE,True
- alSourcef source._id,AL_GAIN,1
- alSourcef source._id,AL_PITCH,1
- alSource3f source._id,AL_POSITION,0,0,1
- If Not static
- source._avail=False
- source._succ=_sources
- _sources=source
- EndIf
- Else
- t._seq:+1
- EndIf
- Return t
- End Function
-
- Field _source:TOpenALSource,_seq,_static
-
-End Type
-
-Type TOpenALAudioDriver Extends TAudioDriver
-
- Method Name$()
- Return _name
- End Method
-
- Method Startup()
- _device=0
- If _devname
- _device=alcOpenDevice( _devname )
- Else If OpenALInstalled()
- _device=alcOpenDevice( Null )
- If Not _device
- _device=alcOpenDevice( "Generic Hardware" )
- If Not _device
- _device=alcOpenDevice( "Generic Software" )
- EndIf
- EndIf
- EndIf
- If _device
- _context=alcCreateContext( _device,Null )
- If _context
- alcMakeContextCurrent _context
- alDistanceModel AL_NONE
- Return True
- EndIf
- alcCloseDevice( _device )
- EndIf
- End Method
-
- Method Shutdown()
- _sources=Null
- alcDestroyContext _context
- alcCloseDevice _device
- End Method
-
- Method CreateSound:TOpenALSound( sample:TAudioSample,flags )
- Return TOpenALSound.Create( sample,flags )
- End Method
-
- Method AllocChannel:TOpenALChannel()
- Return TOpenALChannel.Create( True )
- End Method
-
- Function Create:TOpenALAudioDriver( name$,devname$ )
- Local t:TOpenALAudioDriver=New TOpenALAudioDriver
- t._name=name
- t._devname=devname
- Return t
- End Function
-
- Field _name$,_devname$,_device,_context
-
-End Type
-
-If OpenALInstalled() TOpenALAudioDriver.Create "OpenAL",""
-
-Rem
-bbdoc: Enable OpenAL Audio
-returns: True if successful
-about:
-After successfully executing this command, OpenAL audio drivers will be added
-to the array of drivers returned by #AudioDrivers.
-End Rem
-Function EnableOpenALAudio()
- Global done,okay
- If done Return okay
- If OpenALInstalled() And alcGetString
- For Local devname$=EachIn EnumOpenALDevices()
- TOpenALAudioDriver.Create( "OpenAL "+devname,devname )
- Next
- TOpenALAudioDriver.Create "OpenAL Default",String.FromCString( alcGetString( 0,ALC_DEFAULT_DEVICE_SPECIFIER ) )
- okay=True
- EndIf
- done=True
- Return okay
-End Function
+\r
+Strict\r
+\r
+Rem\r
+bbdoc: Audio/OpenAL audio \r
+about:\r
+The OpenAL audio module provide OpenAL drivers for use with the #audio module.\r
+End Rem\r
+Module BRL.OpenALAudio\r
+\r
+ModuleInfo "Version: 1.05"\r
+ModuleInfo "Author: Mark Sibly"\r
+ModuleInfo "License: zlib/libpng"\r
+ModuleInfo "Copyright: Blitz Research Ltd"\r
+ModuleInfo "Modserver: BRL"\r
+\r
+ModuleInfo "History: 1.05 Release"\r
+ModuleInfo "History: Fixed default channel volume,pan,rate"\r
+ModuleInfo "History: Fixed behaviour of channel going out of scope"\r
+ModuleInfo "History: 1.04 Release"\r
+ModuleInfo "History: Fixed channel playing to return true if active (playing or paused)"\r
+ModuleInfo "History: 1.03 Release"\r
+ModuleInfo "History: Added (synced) alDeleteBuffers"\r
+ModuleInfo "History: 1.02 Release"\r
+ModuleInfo "History: Added EnableOpenALAudio"\r
+ModuleInfo "History: 1.01 Initial Release"\r
+\r
+Import BRL.Math\r
+Import BRL.Audio\r
+Import Pub.OpenAL\r
+\r
+Private\r
+\r
+Const CLOG=False\r
+\r
+'list of all non-static sources\r
+Global _sources:TOpenALSource\r
+\r
+Function CheckAL()\r
+ Local err$\r
+ Select alGetError()\r
+ Case AL_NO_ERROR\r
+ Return True\r
+ Case AL_INVALID_NAME\r
+ err="INVALID_NAME"\r
+ Case AL_INVALID_ENUM\r
+ err="INVALID_ENUM"\r
+ Case AL_INVALID_VALUE\r
+ err="INVALID_VALUE"\r
+ Case AL_INVALID_OPERATION\r
+ err="INVALID_OPERATION"\r
+ Case AL_OUT_OF_MEMORY\r
+ err="OUT_OF_MEMORY"\r
+ Default\r
+ err="?????"\r
+ End Select\r
+ If CLOG WriteStdout "OpenAL Error: "+err+"~n"\r
+ Return False\r
+End Function\r
+\r
+Type TOpenALSource\r
+\r
+ Field _succ:TOpenALSource,_id,_seq,_sound:TOpenALSound,_avail\r
+ \r
+ Method Playing()\r
+ Local st\r
+ alGetSourcei _id,AL_SOURCE_STATE,Varptr st\r
+ Return st=AL_PLAYING\r
+ End Method\r
+ \r
+ Method Paused()\r
+ Local st\r
+ alGetSourcei _id,AL_SOURCE_STATE,Varptr st\r
+ Return st=AL_PAUSED Or st=AL_INITIAL\r
+ End Method\r
+ \r
+ Method Active() \r
+ Local st\r
+ alGetSourcei _id,AL_SOURCE_STATE,Varptr st\r
+ Return st=AL_PLAYING Or st=AL_PAUSED Or st=AL_INITIAL\r
+ End Method\r
+ \r
+ Method LogState()\r
+ Local st\r
+ alGetSourcei _id,AL_SOURCE_STATE,Varptr st\r
+ Select st\r
+ Case AL_PAUSED WriteStdout "AL_PAUSED~n"\r
+ Case AL_INITIAL WriteStdout "AL_INITIAL~n"\r
+ Case AL_STOPPED WriteStdout "AL_STOPPED~n"\r
+ Case AL_PLAYING WriteStdout "AL_PLAYING~n"\r
+ Default WriteStdout "AL_DUNNO, st="+st+"~n"\r
+ End Select\r
+ End Method\r
+ \r
+End Type\r
+\r
+Function EnumOpenALDevices$[]()\r
+ Local p:Byte Ptr=alcGetString( 0,ALC_DEVICE_SPECIFIER )\r
+ If Not p Return\r
+ Local devs$[100],n\r
+ While p[0] And n<100\r
+ Local sz\r
+ Repeat\r
+ sz:+1\r
+ Until Not p[sz]\r
+ devs[n]=String.FromBytes( p,sz )\r
+ n:+1\r
+ p:+sz+1\r
+ Wend\r
+ Return devs[..n]\r
+End Function\r
+\r
+Public\r
+\r
+Type TOpenALSound Extends TSound\r
+\r
+ Method Delete()\r
+ alDeleteBuffers 1,Varptr _buffer\r
+ CheckAL\r
+ If CLOG WriteStdout "Deleted OpenAL buffer "+_buffer+"~n"\r
+ End Method\r
+\r
+ Method Play:TOpenALChannel( alloced_channel:TChannel=Null )\r
+ Local t:TOpenALChannel=Cue( alloced_channel )\r
+ t.SetPaused False\r
+ Return t\r
+ End Method\r
+\r
+ Method Cue:TOpenALChannel( alloced_channel:TChannel=Null )\r
+ Local t:TOpenALChannel=TOpenALChannel( alloced_channel )\r
+ If t\r
+ Assert t._static\r
+ Else\r
+ t=TOpenALChannel.Create( False )\r
+ EndIf\r
+ t.Cue Self\r
+ Return t\r
+ End Method\r
+\r
+ Function Create:TOpenALSound( sample:TAudioSample,flags )\r
+ Local alfmt\r
+ Select sample.format\r
+ Case SF_MONO8\r
+ alfmt=AL_FORMAT_MONO8\r
+ Case SF_MONO16LE\r
+ alfmt=AL_FORMAT_MONO16\r
+?BigEndian\r
+ sample=sample.Convert( SF_MONO16BE )\r
+?\r
+ Case SF_MONO16BE\r
+ alfmt=AL_FORMAT_MONO16\r
+?LittleEndian\r
+ sample=sample.Convert( SF_MONO16LE )\r
+?\r
+ Case SF_STEREO8\r
+ alfmt=AL_FORMAT_STEREO8\r
+ Case SF_STEREO16LE\r
+ alfmt=AL_FORMAT_STEREO16\r
+?BigEndian\r
+ sample=sample.Convert( SF_STEREO16BE )\r
+?\r
+ Case SF_STEREO16BE\r
+ alfmt=AL_FORMAT_STEREO16\r
+?LittleEndian\r
+ sample=sample.Convert( SF_STEREO16LE )\r
+?\r
+ End Select\r
+ \r
+ Local buffer=-1\r
+ alGenBuffers 1,Varptr buffer\r
+ CheckAL\r
+ \r
+ If CLOG WriteStdout "Generated OpenAL buffer "+buffer+"~n"\r
+ \r
+ alBufferData buffer,alfmt,sample.samples,sample.length*BytesPerSample[sample.format],sample.hertz\r
+ CheckAL\r
+ \r
+ Local t:TOpenALSound=New TOpenALSound\r
+ t._buffer=buffer\r
+ If (flags & 1) t._loop=1\r
+ Return t\r
+ End Function\r
+\r
+ Field _buffer,_loop\r
+\r
+End Type\r
+\r
+Rem\r
+bbdoc: OpenAL audio channel Type\r
+End Rem\r
+Type TOpenALChannel Extends TChannel\r
+\r
+ Method Delete()\r
+ If _seq<>_source._seq Return\r
+ \r
+ If _static 'LEAKED!\r
+ Stop 'Just in case... \r
+ Return\r
+ EndIf\r
+ \r
+ If Not _source.Playing()\r
+ alSourceStop _source._id\r
+ alSourcei _source._id,AL_BUFFER,0\r
+ _source._sound=Null\r
+ EndIf\r
+\r
+ End Method\r
+\r
+ Method Stop()\r
+ If _seq<>_source._seq Return\r
+ \r
+ _source._seq:+1\r
+\r
+ alSourceStop _source._id\r
+ alSourcei _source._id,AL_BUFFER,0\r
+ _source._sound=Null\r
+ \r
+ If _static\r
+ _source._avail=True\r
+ _source._succ=_sources\r
+ _sources=_source\r
+ EndIf\r
+ End Method\r
+ \r
+ Method SetPaused( paused )\r
+ If _seq<>_source._seq Return\r
+\r
+ If paused\r
+ alSourcePause _source._id\r
+ Else\r
+ If _source.Paused() alSourcePlay _source._id\r
+ EndIf\r
+ End Method\r
+ \r
+ Method SetVolume( volume# )\r
+ If _seq<>_source._seq Return\r
+\r
+ alSourcef _source._id,AL_GAIN,volume\r
+ End Method\r
+ \r
+ Method SetPan( pan# )\r
+ If _seq<>_source._seq Return\r
+\r
+ pan:*90\r
+ alSource3f _source._id,AL_POSITION,Sin(pan),0,-Cos(pan)\r
+ End Method\r
+ \r
+ Method SetDepth( depth# )\r
+ If _seq<>_source._seq Return\r
+ End Method\r
+ \r
+ Method SetRate( rate# )\r
+ If _seq<>_source._seq Return\r
+\r
+ alSourcef _source._id,AL_PITCH,rate\r
+ End Method\r
+ \r
+ Method Playing()\r
+ If _seq<>_source._seq Return\r
+\r
+ Return _source.Playing()\r
+ End Method\r
+\r
+ Method Cue( sound:TOpenALSound ) \r
+ If _seq<>_source._seq Return\r
+\r
+ _source._sound=sound\r
+ alSourceRewind _source._id\r
+ alSourcei _source._id,AL_LOOPING,sound._loop\r
+ alSourcei _source._id,AL_BUFFER,sound._buffer\r
+ End Method\r
+ \r
+ Rem\r
+ bbdoc: Get native openal source id\r
+ returns: The native openal source id for the channel, or 0 if the channel\r
+ has been stopped using #Stop.\r
+ End Rem\r
+ Method OpenALSourceId()\r
+ If _seq<>_source._seq Return 0\r
+ Return _source._id\r
+ End Method\r
+ \r
+ Function Create:TOpenALChannel( static )\r
+ \r
+ Local source:TOpenALSource=_sources,pred:TOpenALSource\r
+ While source\r
+ If source._avail Or Not source.Active()\r
+ source._seq:+1\r
+ If pred pred._succ=source._succ Else _sources=source._succ\r
+ If CLOG WriteStdout "Recycling OpenAL source "+source._id+"~n"\r
+ If CLOG source.LogState\r
+ alSourceRewind source._id 'return to FA_INITIAL state\r
+ If CLOG source.LogState\r
+ alSourcei source._id,AL_BUFFER,0\r
+ source._sound=Null\r
+ Exit\r
+ EndIf\r
+ pred=source\r
+ source=source._succ\r
+ Wend\r
+ \r
+ If Not source\r
+ source=New TOpenALSource\r
+\r
+ alGenSources 1,Varptr source._id\r
+ CheckAL\r
+\r
+ If source._id\r
+ If CLOG WriteStdout "Generated OpenAL source "+source._id+"~n"\r
+ Else\r
+ If CLOG WriteStdout "Failed to generate OpenAL source~n"\r
+ EndIf\r
+ EndIf\r
+ \r
+ Local t:TOpenALChannel=New TOpenALChannel\r
+ t._source=source\r
+ t._seq=source._seq\r
+ t._static=static\r
+ If source._id\r
+ alSourcei source._id,AL_SOURCE_RELATIVE,True\r
+ alSourcef source._id,AL_GAIN,1\r
+ alSourcef source._id,AL_PITCH,1\r
+ alSource3f source._id,AL_POSITION,0,0,1\r
+ If Not static\r
+ source._avail=False\r
+ source._succ=_sources\r
+ _sources=source\r
+ EndIf\r
+ Else\r
+ t._seq:+1\r
+ EndIf\r
+ Return t\r
+ End Function\r
+ \r
+ Field _source:TOpenALSource,_seq,_static\r
+ \r
+End Type\r
+\r
+Type TOpenALAudioDriver Extends TAudioDriver\r
+\r
+ Method Name$()\r
+ Return _name\r
+ End Method\r
+ \r
+ Method Startup()\r
+ _device=0\r
+ If _devname\r
+ _device=alcOpenDevice( _devname )\r
+ Else If OpenALInstalled()\r
+ _device=alcOpenDevice( Null )\r
+ If Not _device\r
+ _device=alcOpenDevice( "Generic Hardware" )\r
+ If Not _device\r
+ _device=alcOpenDevice( "Generic Software" )\r
+ EndIf\r
+ EndIf\r
+ EndIf\r
+ If _device\r
+ _context=alcCreateContext( _device,Null )\r
+ If _context\r
+ alcMakeContextCurrent _context\r
+ alDistanceModel AL_NONE\r
+ Return True\r
+ EndIf\r
+ alcCloseDevice( _device )\r
+ EndIf\r
+ End Method\r
+ \r
+ Method Shutdown()\r
+ _sources=Null\r
+ alcDestroyContext _context\r
+ alcCloseDevice _device\r
+ End Method\r
+\r
+ Method CreateSound:TOpenALSound( sample:TAudioSample,flags )\r
+ Return TOpenALSound.Create( sample,flags )\r
+ End Method\r
+ \r
+ Method AllocChannel:TOpenALChannel()\r
+ Return TOpenALChannel.Create( True )\r
+ End Method\r
+ \r
+ Function Create:TOpenALAudioDriver( name$,devname$ )\r
+ Local t:TOpenALAudioDriver=New TOpenALAudioDriver\r
+ t._name=name\r
+ t._devname=devname\r
+ Return t\r
+ End Function\r
+ \r
+ Field _name$,_devname$,_device,_context\r
+\r
+End Type\r
+\r
+If OpenALInstalled() TOpenALAudioDriver.Create "OpenAL",""\r
+\r
+Rem\r
+bbdoc: Enable OpenAL Audio\r
+returns: True if successful\r
+about:\r
+After successfully executing this command, OpenAL audio drivers will be added\r
+to the array of drivers returned by #AudioDrivers.\r
+End Rem\r
+Function EnableOpenALAudio()\r
+ Global done,okay\r
+ If done Return okay\r
+ If OpenALInstalled() And alcGetString\r
+ For Local devname$=EachIn EnumOpenALDevices()\r
+ TOpenALAudioDriver.Create( "OpenAL "+devname,devname )\r
+ Next\r
+ TOpenALAudioDriver.Create "OpenAL Default",String.FromCString( alcGetString( 0,ALC_DEFAULT_DEVICE_SPECIFIER ) )\r
+ okay=True\r
+ EndIf\r
+ done=True\r
+ Return okay\r
+End Function\r