Streamed OggVorbis Player

BlitzMax Forums/BlitzMax Programming/Streamed OggVorbis Player

Vertex(Posted 2007) [#1]
I love OpenAL and the politics of OggVorbis but the modules of BRL for both not ^^
So I write my own modules and player and the result is TOggVorbis. With this class you can play streamed OggVorbis Songs. The advantage of this class is:
- no long loading times(BRL version need up to 30 seconds for one song)
- no dissipation of memory(BRL version need the same memory as the song in wav format)
- seeking

http://vertex.dreamfall.at/openal/openal102.zip
http://vertex.dreamfall.at/openal/oggvorbis.zip

The class interface:
TOggVorbis
 Method Play()
 Method SetVolume(Volume:Float)
  - from 0.0 till 1.0
 Method State:Int()
  - STATE_INITIAL
  - STATE_PLAYING
  - STATE_PAUSED
  - STATE_STOPPED
 Method Stop()
 Method Pause()
 Method Length:Long()
  - in milliseconds
 Method Seek(Milliseconds:Long)
 Method Position:Long()
  - decode position in milliseconds
 Method Decode()
 Function Load:TOggVorbis(URL:OBject)


An little example:
SuperStrict

Framework Vertex.OpenAL
Import "OggVorbis.bmx"

Global Device  : Byte Ptr, ..
       Context : Byte Ptr, ..
       Song    : TOggVorbis

Device = alcOpenDevice(Null)
Context = alcCreateContext(Device, Null)
alcMakeContextCurrent(Context)

Song = TOggVorbis.Load("The Dandy Warhols - Bohemian like you.ogg")
Song.Play()
While Song.State() = STATE_PLAYING
	Song.Decode()
	Delay(10)
Wend

alcMakeContextCurrent(Null)
alcDestroyContext(Context)
alcCloseDevice(Device)
End


Need only 1-2% CPU usage.
The OggVorbis loader is alike of the BRL version but not the same(I have try it without a wrapper.c file but this seeming not possible with BMax :( )

cu olli


degac(Posted 2007) [#2]
Thanks! I will try it asap, audio streaming IS important!!! thanks again!!!


popcade(Posted 2007) [#3]
This is pretty decent.. it seems BRL can't integrate stream into BlitzMax with current sound system?


Vertex(Posted 2007) [#4]
I have code an own audiosystem for a karaoke system with streamed ogg vorbis, wav loader and audioanalyse with noisefilter and autocorrelation. Working fine and speedfull based on OpenAL.

Yes, audio streaming is important for games and applications. And the current BRL audio system don't support audio streaming. Actually I don't include so many BRL modules cause this modules are not superstrict and the interface is not designed well. So I'am learning C# and don't want to use BMax for next programs(sorry for OT ^^).

cu olli


degac(Posted 2007) [#5]
At last I've tried the Vertex module and it works perfectly (I have some problems with the official OpenAl module, but I resolved in some way...)
I've tested with a .ogg file - I've compiled the example importing only what required (thanks Framework Assistance):
- BlitzMax standard: taskmanager reports 75.525 Kb...
- BlitzMax + Vertex Ogg Streaming: taskmanager reports 3.892Kb!!!!

Very good works!!!


anawiki(Posted 2007) [#6]
Does it work on Mac/Linux? Can't test it at the moment.

cheers
Roman


degac(Posted 2007) [#7]
I have this message
Linking:Example
ld: archive: /Applications/BlitzMax/mod/vertex.mod/openal.mod/openal32.lib has no table of contents, add one with ranlib(1) (can't load from it)
ld: archive: /Applications/BlitzMax/mod/vertex.mod/openal.mod/alut.lib has no table of contents, add one with ranlib(1) (can't load from it)
Build Error: Failed to link /Users/degac/Desktop/oggvorbis Folder/Example.app/Contents/MacOS/Example
Process complete

maybe I have made some error during the installation of OpenAl module


Steffenk(Posted 2007) [#8]
Works very well under Win2k here, great work Vertex!


kronholm(Posted 2007) [#9]
Very nice work Vertex, thank you!


popcade(Posted 2007) [#10]
Just come up a question, any possibility to play samples with this, it has conflict with built-in modules, if it can work with samples I think there's no need to use built-in audio systems.


ziggy(Posted 2007) [#11]
Does this need any additional DLL?


Vertex(Posted 2007) [#12]
Thanks for testing!

It is better to play small sounds without streamed buffers. Thats mean, only one static OpenAL buffer is allocated for the samples.

This is my modified WAV loader:
	Function LoadWAV:TSound(URL:Object)
		Const CHUNK_RIFF : Int = $46464952, ..
		      CHUNK_WAVE : Int = $45564157, ..
		      CHUNK_FMT  : Int = $20746D66, ..
		      CHUNK_DATA : Int = $61746164
	
		Type TFmt
			Field Compression   : Short
			Field Channels      : Short
			Field SamplingRate  : Int
			Field BytesPerSec   : Int
			Field BlockAlign    : Short
			Field BitsPerSample : Short
	
			Method Read(Stream:TStream)
				Self.Compression = Stream.ReadShort()
				If Self.Compression <> 1 Then Return
		
				Self.Channels      = Stream.ReadShort()
				Self.SamplingRate  = Stream.ReadInt()
				Self.BytesPerSec   = Stream.ReadInt()
				Self.BlockAlign    = Stream.ReadShort()
				Self.BitsPerSample = Stream.ReadShort()
			End Method
	
			Method GetALFormat:Int()
				If Self.Channels = 1 Then
					If Self.BitsPerSample = 8 Then
						Return AL_FORMAT_MONO8
					ElseIf Self.BitsPerSample = 16 Then
						Return AL_FORMAT_MONO16
					Else
						Return 0
					EndIf
	
				ElseIf Self.Channels = 2 Then
					If Self.BitsPerSample = 8 Then
						Return AL_FORMAT_STEREO8
					ElseIf Self.BitsPerSample = 16 Then
						Return AL_FORMAT_STEREO16
					Else
						Return 0
					EndIf
	
				Else
					Return 0
				EndIf
			End Method
		End Type
	
		Local Stream : TStream, ..
		      Chunk  : Int, ..
		      Size   : Int, ..
		      Fmt    : TFMT, ..
		      Length : Int, ..
		      Data   : Byte Ptr, ..
		      Sound  : TSound
	
		If Not TDevice.Device Then Return Null
	
		Stream = ReadStream(URL)
		If Not Stream Then Return Null
	
		Chunk = Stream.ReadInt()
		Size  = Stream.ReadInt()
		If Chunk <> CHUNK_RIFF Then Return Null
	
		Chunk = Stream.ReadInt()
		If Chunk <> CHUNK_WAVE Then Return Null
	
		Chunk = Stream.ReadInt()
		Size  = Stream.ReadInt()
		If Chunk <> CHUNK_FMT Then Return Null
	
		Fmt = New TFmt
		Fmt.Read(Stream)
		If Fmt.Compression <> 1 Then Return Null
		If Size > 16 Then Stream.SkipBytes(Size - 16)
	
		While Not Stream.Eof()
			Chunk = Stream.ReadInt()
			Size  = Stream.ReadInt()
			If Chunk <> CHUNK_DATA Then
				Stream.SkipBytes(Size)
				Continue
			Else
				Exit
			EndIf
		Wend
		If Stream.Eof() Then Return Null
	
		Length = Size/(Fmt.BitsPerSample/8)
		Data = MemAlloc(Size)
		If Stream.Read(Data, Size) <> Size Then
			MemFree(Data)
			Return Null
		EndIf
	
		Stream.Close()

		Sound = New TSound
		Sound.Format       = Fmt.GetALFormat()
		Sound.SamplingRate = Fmt.SamplingRate
		Sound.Size         = Size
		alBufferData(Sound.Buffer, Sound.Format, Data, Size, ..
		             Fmt.SamplingRate)
		MemFree(Data)

		Return Sound
	End Function


But you have to manage OpenAL sounds(in BMax ^= channels) for you're self. I have for my project 4 OpenAL sounds alloced to play 1 Ogg Vorbis song and up to 3 WAV files synchronous(for buttons sound effects and so on).

And yes, it's need the OpenAL32.dll. Ogg Vorbis library you can bind for static but OpenAL without (L??)GPL agreement only as dynamic binding.

Aporpos: needs OpenAL only OpenAL32.dll in the root directory to use it? Becouse I have installed the OpenAL SDK and it works fine.

cu olli


agent4125(Posted 2007) [#13]
Yes, this is awesome. My "before" memory was 77MB, now it's 4MB. =)

Here's what I did to set it up:

1) Download openal32.dll (link)
2) Copy dll into project folder
3) Unpack the above archives and copy to BlitzMax\mod
4) Open IDE and Ctrl-D to Build Modules


agent4125(Posted 2007) [#14]
There is a bug in SetVolume() in OggVorbis.bmx. It currently is passing an int (alSourcei) instead of a float (alSourcef).

	Method SetVolume(Volume:Float)
		alSourcei(Self.Source, AL_GAIN, Volume)
	End Method


Should be:

	Method SetVolume(Volume:Float)
		alSourcef(Self.Source, AL_GAIN, Volume)
	End Method