OpenAL

BlitzMax Forums/BlitzMax Programming/OpenAL

I was wondering if OpenAL let you skip around in a song by clicking on various spots on a time line or something?

Thanks.

If you mean the BlitzMax driver then no. If you mean OpenAL generally, then I'm not sure, although I also suspect that the answer is again no, as it, like DirectSound, is simply an API to access sound hardware.

In order to do what you want, you're probably looking for a sound engine similar to FMod and suchlike.

Yes openal can do this (as can directsound), use AL_SAMPLE_OFFSET with the alsourcei function.

@REDi:
Can you show me an example? I don't think I understand.

Hi Ked

Do you have MaxGUI? if so I'll knock you up an example using that.

Dont worry I've done a little 2D example for ya.
'Import MaxMod.ModPlayer

EnableOpenALAudio()
SetAudioDriver "openal"

Graphics 800,32,0

' TSoundBuffer is like TSound in blitzmax
Local Sound:TSoundBuffer = TSoundBuffer.Load(RequestFile(""))
If Not Sound RuntimeError "unable to open buffer"

' TSoundSource is like TChannel
Local Source:TSoundSource = TSoundSource.Create(Sound,True)
If Not Source RuntimeError "unable to create source"
Source.Play()

Local Length:Int = Sound.GetLength()
Local XD:Double = 800!/Length
Local Pos:Double
Repeat
	Cls
	If MouseHit(1) Source.SetPlayPosition((Length/800!)*MouseX())
	Pos = XD*Source.GetPlayPosition()
	DrawLine(pos,0,pos,32)
	Flip
Until KeyDown(KEY_ESCAPE) Or AppTerminate()

' _________________________________________________________________________

Type TSoundBuffer

	Field AS:TAudioSample
	Field Buffer:Int

	Function Load:TSoundBuffer(Url:Object)

		Local AS:TAudioSample = LoadAudioSample(url)
		If Not AS Return Null
		
		Local This:TSoundBuffer = New TSoundBuffer
		This.AS = AS
		alGenBuffers(1, Varptr(This.buffer) )

		Local format:Int = AL_FORMAT_STEREO16
		Select AS.Format
			Case SF_MONO8		; format = AL_FORMAT_MONO8
			Case SF_STEREO8		; format = AL_FORMAT_STEREO8
			Case SF_MONO16LE	; format = AL_FORMAT_MONO16
			Case SF_STEREO16LE	; format = AL_FORMAT_STEREO16
		EndSelect
		Local size:Int = AS.Length*bytespersample[as.format]
		alBufferData(This.Buffer, format, AS.Samples, size, AS.Hertz)
		
		Return This

	EndFunction
	' _____________________________________________________________________

	Method Delete()
		alDeleteBuffers(1,Varptr(Buffer))
		AS = Null
		GCCollect()
	EndMethod
	' _____________________________________________________________________

	Method GetLength:Int()
		Local value:Int
		alGetBufferi(Buffer,AL_SIZE,Varptr(value))
		Return value/bytespersample[as.format]
	EndMethod
	' _____________________________________________________________________

	Method GetFrequency:Int()
		Local value:Int
		alGetBufferi(Buffer,AL_FREQUENCY,Varptr(value))
		Return value
	EndMethod
	' _____________________________________________________________________

	Method GetBits:Int()
		Local value:Int
		alGetBufferi(Buffer,AL_BITS,Varptr(value))
		Return value
	EndMethod
	' _____________________________________________________________________

	Method GetChannels:Int()
		Local value:Int
		alGetBufferi(Buffer,AL_Channels,Varptr(value))
		Return value
	EndMethod
	
EndType

' _________________________________________________________________________

Type TSoundSource

	Field Buf:TSoundBuffer
	Field Source:Int

	Function Create:TSoundSource(SoundBuffer:TSoundBuffer,Loop:Int=False)
		If Not SoundBuffer Return Null
		Local This:TSoundSource = New TSoundSource
		This.Buf = SoundBuffer
		alGenSources(1, Varptr(This.Source) )
	    	alSourcei(This.Source, AL_BUFFER, SoundBuffer.Buffer)
	    	This.SetLoop(Loop)
		Return This
	EndFunction
	' _____________________________________________________________________

	Method Delete()
		alDeleteSources(1,Varptr(Source))
		Buf = Null
		GCCollect()
	EndMethod
	' _____________________________________________________________________

	Method Play()
		alSourcePlay(Source)
	EndMethod
	
	Method Stop()
		alSourceStop(Source)
	EndMethod
	
	Method Pause()
		alSourcePause(Source)
	EndMethod
	
	Method Rewind()
		alSourceRewind(Source)
	EndMethod

	Method GetState:Int()
		Local value:Int
		alGetSourcei(Source,AL_SOURCE_STATE,Varptr(value))
		Return value
	EndMethod
	' _____________________________________________________________________
	
	Method SetPlayPosition(pos:Int)
		alSourcei(Source,AL_SAMPLE_OFFSET,pos)
	EndMethod
	
	Method GetPlayPosition:Int()
		Local pos:Int
		alGetSourcei(Source,AL_SAMPLE_OFFSET,Varptr(pos))
		Return pos
	EndMethod
	' _____________________________________________________________________

	Method SetGain(value:Float=1.0)
		alSourcef(Source, AL_GAIN, 1.0)
	EndMethod
	
	Method GetGain:Float()
		Local value:Float
		alGetSourcef(Source, AL_GAIN, Varptr(value))
		Return value
	EndMethod
	' _____________________________________________________________________

	Method SetPitch(value:Float=1.0)
		alSourcef(Source, AL_PITCH, 1.0)
	EndMethod
	
	Method GetPitch:Float()
		Local value:Float
		alGetSourcef(Source, AL_PITCH, Varptr(value))
		Return value
	EndMethod
	' _____________________________________________________________________

	Field Looping:Int	

	Method SetLoop(bool:Int=True)
		Looping=bool
	    	alSourcei(Source, AL_LOOPING, bool)		
	EndMethod
	
	Method GetLoop:Int()
		Return Looping
	EndMethod

EndType


I know you asked specifically about OpenAL but, just for fun, I went all native...
Strict

Graphics 800,32,0

Local sample:TAudioSample = LoadAudioSample(RequestFile(""))'getenv_("BMXPATH") + "\samples\digesteroids\sounds\menu.ogg")

Local Length:Int = GetSampleLength(sample) ; Print Length
Local XD:Double = 800! / Length
Local pos:Double
Local startPos!
Local startTime = MilliSecs()
Local musicChan:TChannel = PlaySection(sample)

Repeat
	Cls
	
	If MouseHit(1)
		startPos! = (Length / 800!) * MouseX() ; Print startPos 
		StopChannel(musicChan)
		musicChan = PlaySection(sample, startPos!)
		startTime = MilliSecs()
	EndIf
	
	pos = XD * ((MilliSecs() - startTime) + startPos!)
	DrawLine pos, 0, pos, 32
	
	Flip
Until KeyDown(KEY_ESCAPE) Or AppTerminate()

End


Function GetSampleLength(sample:TAudioSample)
	Return (sample.length / Double(sample.hertz)) * 1000
End Function

Function PlaySection:TChannel(sample:TAudioSample, start!=0, stop!=Null)
	Local offSet
	
	start! = (start! / 1000!) * sample.hertz
	If start! > sample.length Then Return Null
	
	Select sample.format
		Case SF_MONO16LE, SF_MONO16BE, SF_STEREO8
			offset = Int(start!) * 2
		
		Case SF_STEREO16LE, SF_STEREO16BE 
 			offset = Int(start!) * 4
		
		Default
			offset = start!
	End Select
	
	stop! = (stop! / 1000!) * sample.hertz
	If (stop! = Null) Or (stop! > sample.length) Then stop! = sample.length
	
	Local newSample:TAudioSample = CreateStaticAudioSample(sample.samples + offset, (stop! - start!), sample.hertz, sample.format)
	Local soundSection:TSound = LoadSound(newSample)
	
	Return PlaySound(soundSection)
End Function

...Obviously a bit 'brute force' and inelegant but seems to work reasonably well.

REDi,
Sorry about not getting back to you sooner. I wasn't able to get on yesterday.

I compiled your example and it gave me an "unable to open buffer" error.

Interesting, what OS are you on?

really this should only happen if LoadAudioSample is returning null, could you try somthing like...
EnableOpenALAudio()
SetAudioDriver "openal"

Local AS:TAudioSample = LoadAudioSample(RequestFile(""))
If Not AS RunTimeError("unable to open buffer")
Print "Okay."

Just to see what happens.

I am on Windows XP. I tried that example you posted and it returned "unable to open buffer."

Yan's example works when I use the path to the OGG. I've been selecting MP3's. Do they not work with LoadAudioSample?

MP3 are license fee bound when you use them in your program (ie have code for load and playback). BM does not support mp3 due to that

MP3 are license fee bound when you use them in your program (ie have code for load and playback). BM does not support mp3 due to that

But why can I play MP3's using LoadSound if BlitzMax doesn't support it?

You can?

Yes.

I was going to make a music player, so I wasn't going to include MP3's. Would that still need a license?

you don't need to play for including MP3. You need to pay to use the technology to decompress them and playbeck them!
And music players are actually expensive (compared to games with their around 3000 USD fixed fee per title)

I'm looking at getting 3D audio going, as in position/listener, so I was looking for some code to get me started with understanding the OpenAL library and come across the example posted here by REDi. It's not working though. I keep getting "Unhandled exception : Attempt to call uninitialized function pointer" on the following line:

alGenBuffers(1, Varptr(This.Buffer) )


I'm using windoze bmax 1.30. I think something has changed in bmax which broke this example. Any help getting this working would be much appreciated.

Oh yeah, Happy New Year!

Edit - Ok fixed. Helps if I have OpenAL installed. Doh.