ov:Lib v0.27 - Stream OggVorbis in PureBasic (3.94 / 4.00)

Developed or developing a new product in PureBasic? Tell the world about it.
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

ov:Lib v0.27 - Stream OggVorbis in PureBasic (3.94 / 4.00)

Post by traumatic »

While PureBasic already has a certain support for OggVorbis files,
it still lacks streaming-capabilities, thus making it impossible to use
any sounds longer than about a minute - like background music.

With [ov:Lib], this gap has been closed. Now it's possible to play
OggVorbis music with a length of five minutes and more. (No one
stops you from using half an hour scores in your next game...)

The sounddata can be loaded from disk or from memory - the choice
is yours...


Just streaming - nothing more?

Starting with version 0.25, [ov:Lib] provides some basic FFT functions,
making it easy to do simple visualizations, beat-detection, etc.


What ov:Lib is not

[ov:Lib] is by no means supposed to be a replacement for PureBasic's
Sound-Library. Its one and only purpose is to stream OggVorbis files
with ease, packed into a single small library.

(ov:Lib only adds about 50kb to your upx-compressed exe!)


System Requirements

[ov:Lib] utilizes DirectSound for sound-output, so a working version
of DirectX (5.0 or higher) is required (WINMM-support may follow).

[ov:Lib] has been tested on Windows 98, 2000 and XP.

If you happen to find bugs in this version, please feel free to report them
here. Also please keep in mind that this is only a very early version which
will most likely still contain bugs. Reporting of these bugs is highly appreciated.

In case someone with a better english than me can help me out with the
helpfile - please let me know!! :)


Well, enough said... you can get the library here:
http://files.connection-refused.org/ovL ... b-0.26.zip

Maintenance release for PureBasic 4.0 (library only!):
http://files.connection-refused.org/ovL ... ibOnly.zip
Last edited by traumatic on Tue Oct 10, 2006 4:20 pm, edited 4 times in total.
Good programmers don't comment their code. It was hard to write, should be hard to read.
WolfgangS
Enthusiast
Enthusiast
Posts: 174
Joined: Fri Apr 25, 2003 3:30 pm

Post by WolfgangS »

Excellent work !
Image
(that's NOT me ...)

EDIT:Did I listen right ?? A PUREBASIC song .. :mrgreen:
WolfgangS' projects http://www.schliess.net
Quotation of the month:
<p3hicy>oder ich hol mir so eine geile aus asien
<p3hicy>die ständig poppen will
<p3hicy>'n brötchen pro tag reicht doch
<p3hicy>die essen eh' nich so viel
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Post by LuCiFeR[SD] »

traumatic: nice job... but occasionally, it doesn't play the tune when played from memory.

hell, you could play it 50 times and it'll play 49 times out of 50... but I like the lib and the tune. Awesome ;)
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

LuCiFeR[SD] wrote:but occasionally, it doesn't play the tune when played from memory.

hell, you could play it 50 times and it'll play 49 times out of 50...
Thanks for your reply! Hey, 49/50 isn't that bad ;)

Is this reproducable in some way? Does it crash?
Good programmers don't comment their code. It was hard to write, should be hard to read.
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Post by LuCiFeR[SD] »

I've not had a crash yet...(apart from when I made a mistake in my routine for checking if the song was still playing and trying to restart it... but that was my fault, not yours) but I'll see if I can reproduce the error for you.
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Post by LuCiFeR[SD] »

Right, excuse my sloppy code here... but this was rushed to death... it doesn't seem to reproduce the error I was on about mind you, perhaps the reboot i did this morning did something good :)

Code: Select all

;- Window Constants
;
Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Frame3D_0
  #Button_0
  #Text_0
EndEnumeration

;- Requester strings
RequesterTitle$="Woah there neddy!"
RequesterBodyText$="For some reason, we failed to access the music file in memory!"
;- globals
Global RequesterTitle$,RequesterBodyText$

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 478, 444, 221, 65,  #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_WindowCentered , "Ogg memory player")
    If CreateGadgetList(WindowID())
      Frame3DGadget(#Frame3D_0, 5, 0, 210, 60, "")
      ButtonGadget(#Button_0, 75, 30, 65, 25, "OK")
      TextGadget(#Text_0, 10, 10, 205, 20, "Simple ogg vorbis player... click ok to quit")
      
    EndIf
  EndIf
EndProcedure

Procedure PlayOgg()
If ovOpenMem(?oggStart, ?oggEnd-?oggStart)
    ; success!
    ovPlay()
Else
MessageRequester(RequesterTitle$,RequesterBodyText$)     
EndIf
EndProcedure

;-main code
PlayOgg()
Open_Window_0()
Repeat
  If ovIsPlaying()
      ;do other stuff in here
      Event = WaitWindowEvent()
  
      If Event = #PB_EventGadget
          ;Debug "WindowID: " + Str(EventWindowID())
          GadgetID = EventGadgetID()
         
      If GadgetID = #Button_0
          Debug "GadgetID: #Button_0" 
      EndIf     
      EndIf

  Else
      ;attempt to restart the ogg... doesn't seem to work though... perhaps I got it wrong? or perhaps a bug?
      ;hell, I may even just need to check the position and just reset it to zero... I'll try that :)
      ovStop()
      ovClose()
      PlayOgg()
  EndIf
  
Until GadgetID = #Button_0

For k.l=100 To 0 Step -1
      Delay(20)
      ovSetVolume(k.l)
Next
ovStop()
ovClose()
End

 
;-Data secton
;this is how we tell the compiler to store the music file in the executable.
  DataSection
    oggStart:
      IncludeBinary "PurePower.ogg"
    oggEnd:
  EndDataSection
but, I am having problems getting the ogg to restart playing, but I suspect it is some stupid oversight on my part (see my coments in the source lol)... I'll play around a bit more... but that doesn't detract from this being an excellent lib :)
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

LuCiFeR[SD] wrote: but, I am having problems getting the ogg to restart playing, but I suspect it is some stupid oversight on my part (see my coments in the source lol)... I'll play around a bit more... but that doesn't detract from this being an excellent lib :)
Thank you! Your efforts are deeply appreciated!

Simply do a ovSetPosition(0) - that should do the trick.
If the Ogg isn't playing anymore, you'll have to call ovPlay() again.


I'll see if I can make you a working version tonight if you want to.

Thanks again! :)


BTW: Maybe I should add a #PLAYLOOPED flag...
Good programmers don't comment their code. It was hard to write, should be hard to read.
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Post by LuCiFeR[SD] »

Right, successfully got it looping :)... that issue is now dealt with. setting the position did the trick ;). Next, I'll implement all the other features into something a little nicer, just to show it off a bit... especially now I have a little free time to play some more. I knew it was just a stupid oversight :) hehe.

Again, thanks for the lib traumatic :)
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

LuCiFeR[SD] wrote:Right, successfully got it looping :)... that issue is now
dealt with. setting the position did the trick ;)
Anyway, I promised you an example so here it is ;)

Code: Select all

OpenWindow(0, 0, 0, 320, 240, #PB_Window_SystemMenu, "loooooooooop")

; try to open stream
If ovOpen("test.ogg") = 0
  MessageRequester("", "Couldn't open file")
  End
EndIf

; play stream
ovPlay()

Repeat
  If ovIsPlaying()
    ;
    ; do something else here
    ;
    Delay(10)
  Else
    ovSetPosition(0)  ; rewind to the beginning...
    ovPlay()          ; ...and play it again
  EndIf
Until WaitWindowEvent() = #PB_Event_CloseWindow

; cleanup
ovClose()
End
BTW: Opening the Window _before_ you load the ogg is always
a good idea because on initialization, the library sets the cooperative
level of directsound to the openend window.
If no window is opened, a little trick is used instead ;)
However, using OpenWindow() prior to ovOpen() may yield in
a slightly better performance.

I will add this to the helpfile...
Next, I'll implement all the other features into something a little nicer, just to show it off a bit... especially now I have a little free time to play some more.
I'm looking forward to see this :)
Again, thanks for the lib traumatic :)
I'm glad you like it. Thanks!
Good programmers don't comment their code. It was hard to write, should be hard to read.
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

EDIT: obsolete
Last edited by traumatic on Wed Jan 12, 2005 11:13 pm, edited 1 time in total.
Good programmers don't comment their code. It was hard to write, should be hard to read.
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Post by LuCiFeR[SD] »

Right, a little update/cleaned up code by me... adding little bits as I go :). all future updates to the code will go here :).

If you want to use this as an example truamatic, feel free, although my coding skills are a little rusty :)

Code: Select all

;- Credits
;Thanks to traumatic for such a cool lib. A link can be found at http://jconserv.net/purebasic/viewtopic.php?t=13637
;this has revived my interest in programming a little :) music is one of my favourite things, And now I can play 
;with something which is easy to use and supports streaming.

;this little example was knocked up by LuC!FeR[SD], hope somebody finds it usefull :)
 
;- Window Constants
;
Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Frame3D_0
  #Button_0
  #Text_0
  #Text_1
  #Text_2
  #Text_3
  #Text_4
  #Text_5

EndEnumeration

;- globals
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 478, 444, 280, 165,  #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_WindowCentered , "Ogg memory player")
    If CreateGadgetList(WindowID())
      Frame3DGadget(#Frame3D_0, 5, 0, 270, 160, "")
      ButtonGadget(#Button_0, 110, 130, 64, 25, "OK")
      TextGadget(#Text_0, 10, 10, 260, 20, "Simple ogg vorbis player... click ok to quit",#PB_Text_Center)
      TextGadget(#Text_1, 10, 30, 260, 20, "",#PB_Text_Center )
      TextGadget(#Text_2, 10, 50, 260, 20, "",#PB_Text_Center )
      TextGadget(#Text_3, 10, 70, 260, 20, "",#PB_Text_Center )
      TextGadget(#Text_4, 10, 90, 260, 20, "",#PB_Text_Center )
      TextGadget(#Text_5, 10, 110, 260, 20, "",#PB_Text_Center )

    EndIf
  EndIf
EndProcedure

Procedure PlayOgg()
    If ovOpenMem(?oggStart, ?oggEnd-?oggStart)
        ; success!
        ovPlay()
    Else
    ;- Requester strings
    RequesterTitle$="Woah there neddy!"
    RequesterBodyText$="For some reason, we failed to access the music file in memory!"
    MessageRequester(RequesterTitle$,RequesterBodyText$)     
    EndIf
EndProcedure

Procedure GetSongInfo()
;implemented a crude song info thing... we just update text gadgets 1 to 5 with the relevent info.
    SetGadgetText(#Text_1,"VendorInfo:  "+ovGetVendorInfo())
    SetGadgetText(#Text_2,"Comments:  "+ovGetComments(num.l))
    SetGadgetText(#Text_3,"Available channels:  "+Str(ovGetNumChannels()))
    SetGadgetText(#Text_4,"Sample Rate:  "+Str(ovGetSamplingRate()))
    SetGadgetText(#Text_5,"Bit Rate:  "+Str(ovGetBitrate()))
EndProcedure

;-main code
;as per advice of traumatic, we open the window BEFORE playing the damn music :)
Open_Window_0()
;now we play the song... hopefully, if all goes well :)
PlayOgg()
;now we pull the song info from the tune in memory.
GetSongInfo()
;get total length of the music file in memory.
TotalLength.l = ovGetTotalLength()
Repeat
    Select ovIsPlaying()
        Case #TRUE 
        ;the next routine checks the songs current position.. if TotalLength and Position = the same..
        ;the songs position is reset to the begining.  No need to call ovPlay() again.
            Position.l=ovGetPosition()   
            If Position=TotalLength
                Result.l = ovSetPosition(0)
            EndIf

            ;here we are tracking window and gadget events.  WaitWindowEvent() seems to fudge the player for some reason
            ;especially with my routine to loop the song so we are just using WindowEvent() and 
            ;a delay to keep things running nicely :)
            Select WindowEvent() 
                Case #PB_EventGadget
                Select EventGadgetID()
                ;not actually needed right now, but here to handle more gadgets as added.
                ;next step, to add play, stop buttons.. trackbar gadgets etc.   
                EndSelect     
            EndSelect
        Delay(10)
    EndSelect
;checks to see if the user has hit the window X button or the ok button      
Until EventGadgetID() = #Button_0 Or WindowEvent() = #PB_EventCloseWindow

;fade out the music.
For k.l=100 To 0 Step -1
      Delay(20)
      ovSetVolume(k.l)
Next
;try to do a clean exit :)
ovStop()
ovClose()
End

 
;-Data secton
;this is how we tell the compiler to store the music file in the executable.
  DataSection
    oggStart:
      IncludeBinary "PurePower.ogg"
    oggEnd:
  EndDataSection
Last edited by LuCiFeR[SD] on Mon Jan 10, 2005 11:37 pm, edited 1 time in total.
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

I like the fade-out!

Keep in mind that both ovGetPosition() and ovGetTotalLength() return integer values.

Alas, happy coding! :)
Good programmers don't comment their code. It was hard to write, should be hard to read.
traumatic
PureBasic Expert
PureBasic Expert
Posts: 1661
Joined: Sun Apr 27, 2003 4:41 pm
Location: Germany
Contact:

Post by traumatic »

Update: Changes in v0.23:

- added additional error handling

- changed behaviour of ovGetPosition(), now it returns the correct stream
position even if playback has been temporarily stopped (could be useful
for trackbars etc.)

- fixed occasional crashes in ovSetPosition()

- improved overall performance

- revised help file


Get it using the link in the threads first post or here:
EDIT: link removed


Please let me know if anyone's interested in further updates.
Last edited by traumatic on Fri Feb 11, 2005 11:20 pm, edited 2 times in total.
Good programmers don't comment their code. It was hard to write, should be hard to read.
Blade
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Aug 06, 2003 2:49 pm
Location: Venice - Italy, Japan when possible.
Contact:

Post by Blade »

Further updates are welcome! :)

This lib is very useful, I just wonder if we should consider this just a bugfix of the official Purebasic OGG library, that should implement streaming...
Beach
Enthusiast
Enthusiast
Posts: 677
Joined: Mon Feb 02, 2004 3:16 am
Location: Beyond the sun...

Post by Beach »

Please let me know if anyone's interested in further updates.
Very nice! I would like to integrate ogg capability for a couple of projects coming up so this will be nice. Keep up the good work!
-Beach
Post Reply