From 7f91f83a38a13772c2cc1003d7f6649ebe988e99 Mon Sep 17 00:00:00 2001 From: Mark Sibly Date: Thu, 15 Oct 2015 16:38:00 +1300 Subject: [PATCH] Added OpenALSourceId() method to TOpenALAudioChannel --- mod/brl.mod/openalaudio.mod/openalaudio.bmx | 817 ++++++++++---------- 1 file changed, 415 insertions(+), 402 deletions(-) diff --git a/mod/brl.mod/openalaudio.mod/openalaudio.bmx b/mod/brl.mod/openalaudio.mod/openalaudio.bmx index 7da3300..430a826 100644 --- a/mod/brl.mod/openalaudio.mod/openalaudio.bmx +++ b/mod/brl.mod/openalaudio.mod/openalaudio.bmx @@ -1,402 +1,415 @@ - -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 + +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 + +Rem +bbdoc: OpenAL audio channel Type +End Rem +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 + + Rem + bbdoc: Get native openal source id + returns: The native openal source id for the channel, or 0 if the channel + has been stopped using #Stop. + End Rem + Method OpenALSourceId() + If _seq<>_source._seq Return 0 + Return _source._id + 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 -- 2.30.2