Page 1 of 4

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

Posted: Sun Jan 09, 2005 8:04 pm
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

Posted: Sun Jan 09, 2005 8:22 pm
by WolfgangS
Excellent work !
Image
(that's NOT me ...)

EDIT:Did I listen right ?? A PUREBASIC song .. :mrgreen:

Posted: Sun Jan 09, 2005 9:46 pm
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 ;)

Posted: Mon Jan 10, 2005 9:01 am
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?

Posted: Mon Jan 10, 2005 2:08 pm
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.

Posted: Mon Jan 10, 2005 3:15 pm
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 :)

Posted: Mon Jan 10, 2005 3:33 pm
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...

Posted: Mon Jan 10, 2005 6:19 pm
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 :)

Posted: Mon Jan 10, 2005 6:58 pm
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!

Posted: Mon Jan 10, 2005 7:16 pm
by traumatic
EDIT: obsolete

Posted: Mon Jan 10, 2005 10:48 pm
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

Posted: Mon Jan 10, 2005 11:31 pm
by traumatic
I like the fade-out!

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

Alas, happy coding! :)

Posted: Wed Jan 12, 2005 11:21 pm
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.

Posted: Thu Jan 13, 2005 12:00 am
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...

Posted: Thu Jan 13, 2005 4:09 am
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!