Calculate audio length from OGG file

Just starting out? Need help? Post your questions and find answers here.
User avatar
kenmo
Addict
Addict
Posts: 2039
Joined: Tue Dec 23, 2003 3:54 am

Calculate audio length from OGG file

Post by kenmo »

Is anyone familiar with the OGG/Vorbis audio file format? Does anyone know how to find the length inside the file? (I need it in seconds, but obviously I can calculate that from samples * sample rate.)

I'm looking through the Vorbis specification (here) but it seems a bit more complex than WAV or ID3 which I've parsed before.

I am playing OGG music in my program, but I need to detect when the song ends and/or starts over (if I specify the Loop flag). Until PureBasic has either a SoundLength() or SoundPlaying() function, I have to manually detect this based on elapsed time...
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Calculate audio length from OGG file

Post by IdeasVacuum »

Good description here: http://en.wikipedia.org/wiki/Ogg#File_format

...but it seems as though length is not a recorded value?
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4951
Joined: Sun Apr 12, 2009 6:27 am

Re: Calculate audio length from OGG file

Post by RASHAD »

Code: Select all

Procedure AF_Load(Nb,file.s)
  i=mciSendString_("OPEN "+Chr(34)+file+Chr(34)+" Type MPEGVIDEO ALIAS "+Str(Nb),0,0,0) 
  If i=0 
    ProcedureReturn #True 
  Else 
    ProcedureReturn #False 
  EndIf 
EndProcedure

Procedure AF_GetLength(Nb) 
  a$=Space(#MAX_PATH) 
  i=mciSendString_("Status "+Str(Nb)+" length",@a$,#MAX_PATH,0) 
  ProcedureReturn Val(a$) 
EndProcedure

Procedure.s AF_TimeString(Time) 
  Time/1000 
  sec=Time%60:Time/60 
  min=Time%60:Time/60 
  ProcedureReturn RSet(Str(Time),2,"0")+":"+RSet(Str(min),2,"0")+":"+RSet(Str(sec),2,"0") 
EndProcedure

File$=OpenFileRequester("","","ALL|*.*;*.mid|Wave|*.wav|mp3|*.mp3|OGG|*.OGG|MID|*.MID",0) 
AF_Load(1,File$) 
Debug AF_TimeString(AF_GetLength(1))

Egypt my love
User avatar
kenmo
Addict
Addict
Posts: 2039
Joined: Tue Dec 23, 2003 3:54 am

Re: Calculate audio length from OGG file

Post by kenmo »

Rashad, that seems to work fine with MP3 files, but it returns 0:00 for all the OGG files I tested! (Exported as OGG from Audacity, if that matters.)

Also I should have mentioned that I need a Mac-compatible solution, so reading the file directly is probably the best way.

I will look into the format more later...
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4951
Joined: Sun Apr 12, 2009 6:27 am

Re: Calculate audio length from OGG file

Post by RASHAD »

I tested it with an OGG file I have :mrgreen:
Now can you give me a link to any of your files just for testing
I looked at the OGG format header and it seem that we can get the bitrate so with the file data
may be we can get the total playing time
I will try
See you soon
Egypt my love
User avatar
kenmo
Addict
Addict
Posts: 2039
Joined: Tue Dec 23, 2003 3:54 am

Re: Calculate audio length from OGG file

Post by kenmo »

Here is a 6-second OGG I generated and exported from Audacity: deleted...

It shows up as 0:00 using your code (Win XP if that matters). Thanks for helping.
Last edited by kenmo on Sun Oct 07, 2012 5:58 pm, edited 1 time in total.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4951
Joined: Sun Apr 12, 2009 6:27 am

Re: Calculate audio length from OGG file

Post by RASHAD »

PB 4.61 x86 Win 7 x64
Worked as expected Time 00:00:06
It seems that it is a matter of the proper CODEC
Is that file is playable on your system kenmo?
Egypt my love
User avatar
kenmo
Addict
Addict
Posts: 2039
Joined: Tue Dec 23, 2003 3:54 am

Re: Calculate audio length from OGG file

Post by kenmo »

Yes, it plays in PureBasic, Winamp, VLC, etc...... but it does NOT play in Windows Media Player, that might be a problem.

Either way, mciSendString_() is Windows only, so I shouldn't spend too much time trying to get it to read OGG.

I've downloaded their open source "libvorbis" and I will look through that.
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Calculate audio length from OGG file

Post by MachineCode »

This VB media player supports OGG, so maybe look at its source:
http://www.planet-source-code.com/vb/sc ... 2&lngWId=1
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
kenmo
Addict
Addict
Posts: 2039
Joined: Tue Dec 23, 2003 3:54 am

Re: Calculate audio length from OGG file

Post by kenmo »

Well I hacked together an ugly procedure to calculate Ogg Vorbis length. It finds the sample rate (from the beginning of the file) and the number of samples (from the end) so the length in (milli)seconds can be calculated.

In case anybody else ever needs this, I'll post it here. It's NOT guaranteed to work with every Vorbis file!!!

I only used the bare minimum of the Vorbis specification that I needed... basically the 'OggS' and 'vorbis' headers.

2019-08-13 - Updated the code slightly to work with PB 5.70 / Unicode mode

Code: Select all

; Cross-platform procedure for determining length (in milliseconds)
;  of an Ogg Vorbis audio file. It can easily be adapted to return
;  seconds, or samples, or sample rate, etc.

; Absolutely NOT GUARANTEED to work with every .ogg file,
;  but it seems to work with all the ones I'm using...

; 2019-08-13 : Updated to PureBasic 5.70 (Unicode fixed)

Procedure.i GetOggLength(File.s)
  Protected BufferSize.i = 8192
  Protected FN.i, *Buffer, FilePos.i, *P.LONG
  Protected Result.i, Samples.q
  Protected SampleRate.d
 
  If (File)
    FN = ReadFile(#PB_Any, File)
    If (FN)
      *Buffer = AllocateMemory(BufferSize)
      If (*Buffer)
     
        ; Find sample rate (search forward from start)
        FilePos = 0
        Repeat
          FileSeek(FN, FilePos)
          If (ReadData(FN, *Buffer, BufferSize))
            *P = *Buffer + 1
            While (*P < *Buffer + BufferSize - 15)
              If (*P\l = $62726F76) ; 'brov'
                If ((PeekU(*P + 4) = $7369) And (PeekA(*P - 1) = 1)) ; 'si'
                  SampleRate = PeekL(*P + 11)
                  Break 2
                EndIf
              EndIf
              *P + 1
            Wend
          Else
            Break
          EndIf
          FilePos + BufferSize/2
        Until (FilePos >= Lof(FN))
        If (SampleRate > 0)
         
          ; Find number of samples (search backwards from end)
          FilePos = Lof(FN) - BufferSize
          If (FilePos < 0)
            FilePos = 0
          EndIf
          Repeat
            FileSeek(FN, FilePos)
            If (ReadData(FN, *Buffer, BufferSize))
              *P = *Buffer + BufferSize - 4
              While (*P >= *Buffer)
                If (*P\l = $5367674F) ; 'SggO'
                  Samples = PeekQ(*P + 6)
                  If (Samples > 0)
                 
                    ; Calculate audio length (milliseconds)
                    Result = Int(1000.0 * Samples / SampleRate)
                    Break 2
                  EndIf
                EndIf
                *P - 1
              Wend
            Else
              Break
            EndIf
            If (FilePos > 0)
              FilePos - BufferSize/2
            Else
              FilePos = -1
            EndIf
          Until (FilePos < 0)
        EndIf
        FreeMemory(*Buffer)
      EndIf
      CloseFile(FN)
    EndIf
  EndIf
 
  ProcedureReturn (Result)
EndProcedure



; Test:
File.s = OpenFileRequester("OGG", "", "Ogg Vorbis|*.ogg", 0, #PB_Requester_MultiSelection)
While (File)
  Length.i = GetOggLength(File)/1000
  Debug Str(Length/60) + ":" + RSet(Str(Length % 60), 2, "0") + "  " + GetFilePart(File)
  File = NextSelectedFileName()
Wend
Post Reply