Calculate audio length from OGG file

Just starting out? Need help? Post your questions and find answers here.
User avatar
kenmo
Addict
Addict
Posts: 1967
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