It is currently Tue Sep 24, 2019 10:19 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 60 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Jul 30, 2019 3:18 pm 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Hi Wilbert I can try

The first vorbis header is probably easiest.

It is allways 30bytes in length.

In the ogg it is like this.

4F 67 67 53 00 02 00 00 00 00 00 00 00 00 EC 0A 00 00 00 00 00 00 96 78 16 9D 01 1E 01 76 6F 72 62 69 73 00 00 00 00 02 44 AC 00 00 00 00 00 00 00 EE 02 00 00 00 00 00 B8

The bytes I have highlighted are tthe number of segments and the length 1E (30). The actual vorbis header is:

01 76 6F 72 62 69 73 00 00 00 00 02 44 AC 00 00 00 00 00 00 00 EE 02 00 00 00 00 00 B8 01

The first byte highlighted is the packet type (1) is the identity header. You can see this from your programme I think.

Code:
Structure VorbisIdentification
  PacketType.a
  Identifier.a[6]
  VorbisVersion.l
  AudioChannnels.a
  AudioSampleRate.l
  BitrateMaximum.l
  BitrateNominal.l
  BitrateMinimum.l
  BlockSize01.a
  FramingFlag.a
EndStructure


The second header is the comments header it begins :-

03 76 6F 72 62 69 73

The first byte being the header type 03 means comments header. In the file I posted this first ogg page has all the segments set to $FF so the comments header is quite long and spans two ogg pages. I think your programme actually does retrieve this over the two pages, being an amateur I am not sure.

The third vorbis header begins:-

05 76 6F 72 62 69 73

05 being the header type which I think is the instructions for the codec?

So if these three could be read into their own buffers is what I am looking for.

The fourth section of a vorbis stream is the audio data this starts on the ogg page after the end of the third vorbis header. It seems to be split into lots of sections and reading a little about packing a vorbis stream into ogg each of the sections is a vorbis packet for use by the vorbis codec about which I do not have a clue.

Just those first three sections I need. Would be nice if the file offset for the first audio page could be kept as well.

I can see that writing vorbis comments, especially if someone wants to insert an image (not using the COVERART tag anymore) can force the comments header to cover more than one ogg page which I will have to deal with, this will mean reading in every ogg page after the comments header rewriting the page sequence number tand checksum and writing it back to a file.

The audio data, if we can extract it, could be one step towards solving the PlaySound() Bug https://www.purebasic.fr/english/viewtopic.php?f=4&t=73243

So three buffers each holding one vorbis header and then offset to first ogg page with audio would mean christmas has come early.

kind Regards

CD

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Jul 30, 2019 5:07 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
collectordave wrote:
The first byte being the header type 03 means comments header. In the file I posted this first ogg page has all the segments set to $FF so the comments header is quite long and spans two ogg pages. I think your programme actually does retrieve this over the two pages, being an amateur I am not sure.

The code I posted retrieves all comment pages; also if there are more than two.

collectordave wrote:
05 being the header type which I think is the instructions for the codec?

So if these three could be read into their own buffers is what I am looking for.

While it would be possible to read this header, I doubt if the information it contains is very useful. That's why I skipped it.

collectordave wrote:
The audio data, if we can extract it, could be one step towards solving the PlaySound() Bug https://www.purebasic.fr/english/viewtopic.php?f=4&t=73243

I wasn't aware of that.
I updated the code I posted before to display the duration in seconds.
viewtopic.php?p=539791#p539791
Can you check if the file that gave you problems reports the correct amount of seconds ?

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Jul 30, 2019 8:17 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Apr 21, 2005 2:38 pm
Posts: 1649
Location: Germany
In 2012 kenmo already demonstrated in this example how to determine the length of an ogg file. I tested it with this ogg file with a length of 6:40 minutes (using MacOS 10.6.8 Snow Leopard with PB 5.46 x86 in ASCII mode, Unicode mode didn't work!) and kenmo's example displayed the length correctly. So kenmo's code doesn't have the problem described in collectordave's linked PlaySound() bug.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 6:23 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Tried both examples here is the outputs

Test File
Arlo Guthrie - Alice's Restaurant.ogg Length 18mins 38secs

kenmo post
0:00 Arlo Guthrie - Alice's Restaurant.ogg

wilbert code
Vorbis stream: 26493
Channels: 2
Sample rate: 44100
Duration: 1116 (18.6mins)
Vendor: AO; aoTuV [20110424] (based on Xiph.Org's libVorbis)
Comments:
TITLE=Alice's Restaurant
ARTIST=Arlo Guthrie
COMMENT=fre:ac - free audio converter <https://www.freac.org/>

wilbert gets very close. However the Playsound() bug is not just the length being reported incorrectly but also Playsound() gives up after 6mins 3sec and stops playing!

I imagine the sound decode follows this route

unpack .ogg file to a vorbis stream which is then passed to the vorbis codec which outputs raw sound data

So the problem with PlaySound() may actually be a problem with LoadSound()

I am not qualified nor do I have anywhere near the knowledge to comment further on the bug except to say that the bigg problem is playback length an 18min song should playback for 18min.

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 6:27 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
collectordave wrote:
So the problem with PlaySound() may actually be a problem with LoadSound()

Did you try LoadSound with #PB_Sound_Streaming ?
It might be that there's a limit to loading the entire song in memory (which is what you do without the #PB_Sound_Streaming flag).

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 6:38 am 
Offline
Addict
Addict
User avatar

Joined: Thu Apr 21, 2005 2:38 pm
Posts: 1649
Location: Germany
Shardik wrote:
PB 5.46 x86 in ASCII mode, Unicode mode didn't work!
collectordave wrote:
kenmo post
0:00 Arlo Guthrie - Alice's Restaurant.ogg

Did you test kenmo's example with PB 5.46 x86 in ASCII mode? The result "0:00" is typical when using Unicode mode!


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 6:40 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Hi All

Thanks for the replies.

Tested with PB 5.70 with unicode so fair comment missed that.

This post refers to soundstreaming flag https://www.purebasic.fr/english/viewtopic.php?f=13&t=59824 but as mentioned there Soundpos() is not available.

However thinking as I type I could start the song with the sttreaming flag so it all plays and set up a timer at the same time then using the wilbert code to get the length I can update the progress bar correctly. I will have to try that after I get my head round writing vorbis comments.

Note:-
Maybe these few posts should be moved to the PlaySound() bug topic.

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 7:14 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Tested sound streaming and all plays ok.

Cannot pause or resume though so not much use for a media player.

It must be a restriction on the length in loadSound().

Can this be removed?

CD

PS Tried same song as a .wav file all played ok? The retriction seems to be for .ogg and .flac diles only?

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 10:25 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
collectordave wrote:
Can this be removed?

You can ask Fred :)

I finally got my code to display the images inside your ogg file :)
Code:
EnableExplicit

UsePNGImageDecoder()
UseJPEGImageDecoder()

; >> Structures <<

Structure OGGPage
  CapturePattern.l
  Version.a
  HeaderType.a
  GranulePosition.q
  BitstreamSerialNumber.l
  PageSequenceNumber.l
  Checksum.l
  PageSegments.a
  SegmentTable.a[255]
EndStructure 

Structure VorbisIdentification
  PacketType.a
  Identifier.a[6]
  VorbisVersion.l
  AudioChannnels.a
  AudioSampleRate.l
  BitrateMaximum.l
  BitrateNominal.l
  BitrateMinimum.l
  BlockSize01.a
  FramingFlag.a
EndStructure

Structure VorbisPictureInfo
  Type.l
  MIMEType.s
  Description.s
EndStructure

Structure VorbisComment
  FieldName.s
  Value.s
EndStructure

Structure VorbisStream
  BitstreamSerialNumber.l
  AudioChannels.l
  AudioSampleRate.l
  BitrateMaximum.l
  BitrateNominal.l
  BitrateMinimum.l 
  Duration.l
  Vendor.s
  List Comment.VorbisComment()
EndStructure


; >> ParseOGG procedure <<

Procedure ParseOGG(Filename.s, List VorbisStreams.VorbisStream())
 
  Protected OGGFile.i, NextPageLoc.q, Page.OGGPage, Id.VorbisIdentification
  Protected *Mem.Long, *MemEnd, *a.Ascii, *CommentPacket, BitstreamSerialNumber.l
  Protected.i i, NextPage, LastSegment, BytesToRead, PacketSize, Length
 
  OGGFile = ReadFile(#PB_Any, Filename)
  If OGGFile
    ClearList(VorbisStreams())
   
    ; >> Process pages <<
    While ReadData(OGGFile, @Page, 27) = 27 And
          Page\CapturePattern = $5367674F And
          ReadData(OGGFile, @Page + 27, Page\PageSegments) = Page\PageSegments
     
      ; >> Calculate file position of next page <<
      LastSegment = Page\PageSegments - 1
      NextPageLoc = Loc(OGGFile)
      For i = 0 To LastSegment
        NextPageLoc + Page\SegmentTable[i]
      Next
     
      ; >> Check for new vorbis stream <<
      If Page\HeaderType & 2 And Page\SegmentTable[0] = 30
        If ReadData(OGGFile, @Id, 30) = 30 And PeekS(@Id\Identifier, 6, #PB_Ascii) = "vorbis"
          ; Beginning of vorbis stream
          BitstreamSerialNumber = Page\BitstreamSerialNumber
          PacketSize = 0
          NextPage = 1
          ; Add new vorbis stream to list
          AddElement(VorbisStreams())
          VorbisStreams()\BitstreamSerialNumber = BitstreamSerialNumber
          VorbisStreams()\AudioChannels = Id\AudioChannnels
          CopyMemory(@Id\AudioSampleRate, @VorbisStreams()\AudioSampleRate, 16)
        EndIf
      EndIf
     
      If BitstreamSerialNumber = Page\BitstreamSerialNumber
       
        ; Set duration when end of stream is reached
        If Page\HeaderType & 4
          VorbisStreams()\Duration = Page\GranulePosition / Id\AudioSampleRate
        EndIf
       
        ; Process a comment page
        If Page\PageSequenceNumber = NextPage
          ; Calculate how many bytes to read
          BytesToRead = 0
          For i = 0 To LastSegment
            If Page\SegmentTable[i] = 255
              BytesToRead + 255
            Else
              BytesToRead + Page\SegmentTable[i]
              NextPage = 0; No more comment pages
              Break
            EndIf
          Next
          ; Reallocate memory for comment packet
          *Mem = ReAllocateMemory(*CommentPacket, PacketSize + BytesToRead, #PB_Memory_NoClear)
          If *Mem
            *CommentPacket = *Mem
            ; Read bytes
            If ReadData(OGGFile, *CommentPacket + PacketSize, BytesToRead) = BytesToRead
              PacketSize + BytesToRead
              If NextPage
                NextPage + 1
              Else             
                ; Done reading comment packet
                *Mem + 7
                Length = *Mem\l : *Mem + 4
                ; Set vendor
                VorbisStreams()\Vendor = PeekS(*Mem, Length, #PB_UTF8) : *Mem + Length
                ; Clear the comments list
                ClearList(VorbisStreams()\Comment())
                i = *Mem\l : *Mem + 4
                ; Loop through comments and add to list
                While i
                  AddElement(VorbisStreams()\Comment())
                  Length = *Mem\l : *Mem + 4
                  ; Find '='
                  *a = *Mem : *MemEnd = *Mem + Length
                  While *a < *MemEnd And *a\a <> $3D
                    *a + 1
                  Wend
                  VorbisStreams()\Comment()\FieldName = PeekS(*Mem, *a - *Mem, #PB_UTF8 | #PB_ByteLength)
                  If *a < *MemEnd
                    VorbisStreams()\Comment()\Value = PeekS(*a + 1, *MemEnd - *a - 1, #PB_UTF8 | #PB_ByteLength)
                  EndIf
                  *Mem + Length
                  i - 1
                Wend
              EndIf
            EndIf
          EndIf
        EndIf
       
      EndIf
     
      ; Set the file pointer to the next page
      FileSeek(OGGFile, NextPageLoc)
     
    Wend
    If *CommentPacket
      ; Free allocated memory
      FreeMemory(*CommentPacket)
    EndIf
    CloseFile(OGGFile)
    ProcedureReturn ListSize(VorbisStreams())
  Else
    ProcedureReturn #False
  EndIf
 
EndProcedure

; >> DecodeVorbisPicture procedure <<

Procedure.i DecodeVorbisPicture(Base64String.s, *Info.VorbisPictureInfo = #Null)
 
  Protected.i i, n = Len(Base64String)
  Protected Dim InputBuffer.a((n >> 6) * 66 + n & 63)
  Protected Dim P.a((3 * n) >> 2)
  Protected *c.Character = @Base64String
  Protected *a.Ascii = @InputBuffer()
 
  ; Decode Base64
  i = 0
  While *c\c
    *a\a = *c\c : i + 1
    *a + 1 : *c + SizeOf(Character)
    If i = 64
      *a\a = #CR : *a + 1
      *a\a = #LF : *a + 1
      i = 0 
    EndIf   
  Wend
  Base64DecoderBuffer(@InputBuffer(), ArraySize(InputBuffer()), @P(), ArraySize(P()))
 
  ; Type
  n = P(0)<<24 | P(1)<<16 | P(2)<<8 | P(3) : i = 4
  If *Info : *Info\Type = n : EndIf
 
  ; MIMEType
  n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3) : i + 4
  If *Info : *Info\MIMEType = PeekS(@P(i), n, #PB_Ascii) : EndIf
  i + n
 
  ; Description 
  n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3) : i + 4
  If *Info : *Info\Description = PeekS(@P(i), n, #PB_UTF8 | #PB_ByteLength) : EndIf
  i + n + 16
 
  ; Return image
  n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3) : i + 4
  If n
    ProcedureReturn CatchImage(#PB_Any, @P(i), n)
  Else
    ProcedureReturn #Null
  EndIf
 
EndProcedure



; Test the code

NewList VorbisStreams.VorbisStream()
Define.i w, h, i, p, Info.VorbisPictureInfo

OpenWindow(0, 0, 0, 420, 320, "OGG Vorbis", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
EditorGadget(0, 10, 10, 400, 300, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)

ParseOGG("Queen - Action This Day.ogg", VorbisStreams())

ForEach VorbisStreams()
  AddGadgetItem(0, -1, "Vorbis stream: " + Str(VorbisStreams()\BitstreamSerialNumber))
  AddGadgetItem(0, -1, "Channels: " + Str(VorbisStreams()\AudioChannels))
  AddGadgetItem(0, -1, "Sample rate: " + Str(VorbisStreams()\AudioSampleRate))
  AddGadgetItem(0, -1, "Duration: " + Str(VorbisStreams()\Duration) + " seconds")
  AddGadgetItem(0, -1, "Vendor: " + VorbisStreams()\Vendor)
  ForEach VorbisStreams()\Comment()
    If VorbisStreams()\Comment()\FieldName = "METADATA_BLOCK_PICTURE"
      p = DecodeVorbisPicture(VorbisStreams()\Comment()\Value, @Info)
      If p
        i + 1
        w = ImageWidth(p)
        h = ImageHeight(p)
        OpenWindow(i, 0, 0, w, h, "OGG Vorbis " + Info\MIMEType, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        ImageGadget(i, 0, 0, w, h, ImageID(p))
      EndIf
    Else
      AddGadgetItem(0, -1, VorbisStreams()\Comment()\FieldName + " => " + VorbisStreams()\Comment()\Value)
    EndIf
  Next
Next

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 10:52 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Hi wilbert

Brilliant.

I will get used to you being 5 steps ahead of what I am thinking!

CD

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Wed Jul 31, 2019 5:30 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
In case you are also interested in flac files, I read the comments of a flac file are also stored using VORBIS_COMMENT. :)

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Sat Aug 03, 2019 5:05 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Finally understanding a little.

Put together the vorbis comment reader into a module. A good mix of code from wilbert and others.

Thinking ahaead to writing the edited comments back to a file as well. The parseoggfile() procedure provides segment addresses for the three vorbis headers and also the audio start page needed to write comments. Working on that now.

I will add this to the simple ogg player in another thread. I intend vorbiscomment to be an include file.

Here is the code with a quick example of use:-

Code:
EnableExplicit

DeclareModule VorbisComment
 
  ;Only jpeg and png Supported In Comments
  UseJPEGImageDecoder()
  UsePNGImageDecoder()

  ;The SongTags() List Is Available After Using getComments()
  Structure tag
    Length.i
    Title.s
    Value.s
    ImageID.i
  EndStructure
  Global NewList SongTags.tag()
 
  Structure VorbisPictureInfo
    Type.l
    MIMEType.s
    Description.s
  EndStructure
 
  ;Header Information Shared With Module User
  Global Version.i,AudioChannels.i,SampleRate.i
 
  ;The Length of the song and the number of images in comments are not in header
  Global Length.s,ImagesFound.i

  ;Procedures Available
  ;GetComments() Fetches The Comments
  Declare GetComments(FileName.s)
 
  ;If A Picture Is found The Module User Can Have It Decoded Output is the ImageID
  Declare.i DecodeVorbisPicture(Base64String.s, *Info.VorbisPictureInfo = #Null)

EndDeclareModule

Module VorbisComment
 
  ;Structure To Hold OGG page Header Information
  Structure OGGPage
    CapturePattern.l
    Version.a
    HeaderType.a
    GranulePosition.q
    BitstreamSerialNumber.l
    PageSequenceNumber.l
    Checksum.l
    PageSegments.a
    SegmentTable.a[255]
  EndStructure
  Global Page.OGGPage
 
  ;Structure To Hold Section Information From File
  ;Section 1 Is The vorbis Identification Header
  ;Section 2 Is The vorbis Comment Header
  ;Section 3 Is the vorbis codec Instructions
  Structure Section
    IDNumber.i
    PageNumber.i
    FileOffset.i
    BytesToRead.i
  EndStructure
  Global NewList Segments.Section()
 
  ;Structure to hold File Offsets For Each Page Used When Writing Comments To New File
  Structure FileData
    PageNumber.i
    FileOffset.l
  EndStructure
  Global NewList PageOffsets.FileData()

  ;Buffers To Hold Header And Comments
  Global *Header,*Comments
 
  ;Variables Used to Calculate The Length Of The Track
  Global AudioSampleRate.i,LastGranule.i
 
  Procedure.i DecodeVorbisPicture(Base64String.s, *Info.VorbisPictureInfo = #Null)
   
    ;Decode vorbis picture by wilbert   
   
   
    Protected.i i, n = Len(Base64String)
    Protected Dim InputBuffer.a((n >> 6) * 66 + n & 63)
    Protected Dim P.a((3 * n) >> 2)
    Protected *c.Character = @Base64String
    Protected *a.Ascii = @InputBuffer()
 
    ; Decode Base64
    i = 0
    While *c\c
      *a\a = *c\c : i + 1
      *a + 1 : *c + SizeOf(Character)
      If i = 64
        *a\a = #CR : *a + 1
        *a\a = #LF : *a + 1
        i = 0
      EndIf   
    Wend
    Base64DecoderBuffer(@InputBuffer(), ArraySize(InputBuffer()), @P(), ArraySize(P()))
 
    ; Type
    n = P(0)<<24 | P(1)<<16 | P(2)<<8 | P(3) : i = 4
    If *Info : *Info\Type = n : EndIf
 
    ; MIMEType
    n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3) : i + 4
    If *Info
      *Info\MIMEType = PeekS(@P(i), n, #PB_Ascii)
    EndIf
    i + n
 
    ; Description
    n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3)
    i + 4
    If *Info
      *Info\Description = PeekS(@P(i), n, #PB_UTF8 | #PB_ByteLength)
    EndIf
    i + n + 16
 
    ; Return image
    n = P(i)<<24 | P(i+1)<<16 | P(i+2)<<8 | P(i+3)
    i + 4
    If n
      ProcedureReturn CatchImage(#PB_Any, @P(i), n)
    Else
      ProcedureReturn #Null
    EndIf
 
EndProcedure

  Procedure ProcessComments()
   
    Define VendorLength.i,NumberOfComments.i,CommentLength.i,Picture.i,PictureWidth.i,PictureHeight.i,imgWin.i
    Define ThisComment.s
    Define Info.VorbisPictureInfo
    Protected CurrentPosition.i
   
    ;Get Ready For list
    ClearList(SongTags())
    AddElement(SongTags())
    CurrentPosition = 7
   
    ;Length Of Vendor String
    VendorLength =   PeekL(*Comments + CurrentPosition)
   
    CurrentPosition + 4
   
    SongTags()\Title = "VENDOR" ;Never Set In file
    SongTags()\Value = PeekS(*Comments + CurrentPosition,VendorLength,#PB_UTF8)

    ;Add Vendor string length
    CurrentPosition + VendorLength

    ;Get Number Of Comments
    NumberOfComments = PeekL(*Comments + CurrentPosition)
    CurrentPosition + 4

    ;Fetch Each comment
    For iLoop = 1 To NumberOfComments

      CommentLength = PeekL(*Comments + CurrentPosition)

      CurrentPosition + 4
      ThisComment = PeekS(*Comments + CurrentPosition,CommentLength,#PB_UTF8)
      CurrentPosition + CommentLength
     
      ;Break Up Comment Into Title and Value
      AddElement(SongTags())
      SongTags()\Title = StringField(ThisComment,1,"=")
      SongTags()\Value = StringField(ThisComment,2,"=")   

    Next

  EndProcedure
 
  Procedure ProcessHeader()

    AudioChannels = PeekA(*Header + 11)
   
    SampleRate = PeekL(*Header + 12)
    Duration = LastGranule / SampleRate
   
    Length = Str(Duration / 60) + " Minutes"
   
    Length = Length +  " " + Str(Duration % 60) + " Seconds"

  EndProcedure

  Procedure ParseOGGFile(FileName.s)
   
    Define OGGFile.i,ThisPacket.i
    Define *Mem
   
    ClearList(Segments())
   
    OGGFile = ReadFile(#PB_Any, FileName)

    If OGGFile

      SectionNumber = 1
      PageNumber = 0
     
              ;New Page Add Element To PageOffsets()
        AddElement(PageOffsets())
        PageOffsets()\PageNumber = PageNumber
        PageOffsets()\FileOffset = 0
     
     
     
      ;Process pages
      While ReadData(OGGFile, @Page, 27) = 27 And
        Page\CapturePattern = $5367674F And
        ReadData(OGGFile, @Page + 27, Page\PageSegments) = Page\PageSegments

        ;Get last Granule Position from end of stream
        If Page\HeaderType & 4 ;Last Page
          LastGranule = Page\GranulePosition
        EndIf

        ;New Page So New Element Foe A Segment (Section)
        PageNumber + 1
        AddElement(Segments())
        Segments()\IDNumber = SectionNumber
        Segments()\PageNumber = PageNumber
        Segments()\FileOffset = Loc(OGGFile)
     
        ;Audio Section Start?
        If SectionNumber = 4
          AudioStartPage = PageNumber
        EndIf   

        ;Calculate file position of next page
        LastSegment = Page\PageSegments - 1
        NextPageLoc = Loc(OGGFile)
        For i = 0 To LastSegment
          NextPageLoc + Page\SegmentTable[i]
        Next     
       
        ;Another OGG Page Needed
        AddElement(PageOffsets())
        PageOffsets()\PageNumber = PageNumber
        PageOffsets()\FileOffset = NextPageLoc     

        ;Calculate how many bytes to read
        BytesToRead = 0
        For i = 0 To LastSegment
          If Page\SegmentTable[i] = 255
            BytesToRead + 255
          Else
         
            ;End Of A section
            BytesToRead + Page\SegmentTable[i]
         
            Segments()\BytesToRead = BytesToRead
         
            *Segment = ReAllocateMemory(*Segment,BytesToRead)
         
            ReadData(OGGFile,*Segment,BytesToRead)

            ;New Section New entry If Not end of segments
            SectionNumber + 1
            If i < LastSegment
              AddElement(Segments())
              Segments()\IDNumber = SectionNumber
              Segments()\PageNumber = PageNumber
              Segments()\FileOffset = Loc(OGGFile)
            EndIf
         
            BytesToRead = 0
         
          EndIf
     
        Next
     
        If BytesToRead > 0
          Segments()\BytesToRead = BytesToRead
        EndIf

        ;Goto Next Page
        FileSeek(OGGFile,NextPageLoc)
 
      Wend
   
    EndIf
 
 
    ;Put Header Buffer Together
    ThisPacket = 0
 
    ForEach Segments()
   
      If Segments()\IDNumber = 1
     
        FileSeek(OGGFile,Segments()\FileOffset)
     
        *mem = ReAllocateMemory(*Header,ThisPacket + Segments()\BytesToRead,#PB_Memory_NoClear)
     
        *Header = *mem
     
        ReadData(OGGFile,*Header + ThisPacket,Segments()\BytesToRead)
     
        ThisPacket + Segments()\BytesToRead
     
      EndIf
   
    Next
 
    ThisPacket = 0
 
    *Mem = #Null
 
    ForEach Segments()
   
      If Segments()\IDNumber = 2
     
        FileSeek(OGGFile,Segments()\FileOffset)

        *Mem = ReAllocateMemory(*Comments,ThisPacket + Segments()\BytesToRead,#PB_Memory_NoClear)
     
        *Comments = *Mem
     
        ReadData(OGGFile,*Comments + ThisPacket,Segments()\BytesToRead)
     
        ThisPacket + Segments()\BytesToRead
     
      EndIf
   
    Next
   
    CloseFile(OGGFile)
 
 
  EndProcedure

  Procedure GetComments(FileName.s)

    ;Set Everything Back To Start
    *Comments = #Null
    *Header = #Null
    *Mem = #Null
    ClearList(Segments())
    ClearList(SongTags())
   
    ;Now Fill Them For This Song
    ParseOGGFile(FileName)
    ProcessComments()
    ProcessHeader()

  EndProcedure

EndModule

;Start Of Demo Code


;Array To Hold ImageID's
Global Dim vorbisImage.l(0)


Global NewList SongTags.VorbisComment::tag()

Global Info.VorbisComment::VorbisPictureInfo

Global dlgvorbisComment.i,Quit.i, FileName.s

Global edtSongStats, txtFileSpec, txtAvailableComments, txtSelectComments, cmbComments, edtComment, txtImages, cnvPicture, txtImageStatus, btnPrevious, btnNext, btnDone, btnSelectFile,btnSaveComments

Global ImageIndex.i, ImagesFound.i

Define Event.i

Enumeration FormFont
  #Font_Window_0_0
EndEnumeration

LoadFont(#Font_Window_0_0,"Consolas", 10)

Procedure ShowComments(FileName.s)
 
  Protected Picture.i,iLoop.i
 
 
  ;Clear The Gadgets
  StartDrawing(CanvasOutput(cnvPicture))
    Box(0,0,220,220, RGB(255,255,255))
  StopDrawing()
  ClearGadgetItems(edtComment)
  ClearGadgetItems(edtSongStats)   
             
  ;Clear Image Array
  ReDim vorbisImage(0)
  vorbisImage(0) = 0
             
  ;Get The Comments
  VorbisComment::GetComments(FileName)

  ;Show Header Information
  AddGadgetItem(edtSongStats,0,"") 
  AddGadgetItem(edtSongStats,1,"Audio Channels")
  AddGadgetItem(edtSongStats,2,Str(VorbisComment::AudioChannels))
  AddGadgetItem(edtSongStats,3,"")
  AddGadgetItem(edtSongStats,4,"Sample Rate")
  AddGadgetItem(edtSongStats,5,Str(VorbisComment::SampleRate) + "Hz") 
  AddGadgetItem(edtSongStats,6,"")
  AddGadgetItem(edtSongStats,7,"Duration")             
  AddGadgetItem(edtSongStats,8, VorbisComment::Length)
 
  ImagesFound = 0
           
  ForEach VorbisComment::SongTags()

    If VorbisComment::SongTags()\Title = "METADATA_BLOCK_PICTURE"
       
      Picture = VorbisComment::DecodeVorbisPicture(VorbisComment::SongTags()\Value, @Info)
      If Picture
        VorbisComment::SongTags()\ImageID = Picture
        vorbisImage(ImagesFound) = Picture
        ImagesFound + 1
        ReDim vorbisImage(ImagesFound)
      EndIf
    EndIf
           
  Next
   
  ResetList(VorbisComment::SongTags())

  ClearGadgetItems(cmbComments)
   
  ForEach VorbisComment::SongTags()
 
    If VorbisComment::SongTags()\Title <> "METADATA_BLOCK_PICTURE"
      AddGadgetItem(cmbComments,-1,VorbisComment::SongTags()\Title)
    EndIf
  Next

  If vorbisImage(iLoop) > 0
    ;Show First Image
    ImageIndex = 0
    StartDrawing(CanvasOutput(cnvPicture))
      DrawImage(ImageID(vorbisImage(0)),0,0,220,220)
      StopDrawing()
      SetGadgetText(txtImageStatus,"Image 1 of " + Str(ImagesFound) + " Images")   
    Else
      SetGadgetText(txtImageStatus,"Image 0 of " + Str(ImagesFound) + " Images")
    EndIf
  DisableGadget(btnPrevious,#True)
 
  If ImagesFound > 1
    DisableGadget(btnNext,#False) 
  EndIf
   
EndProcedure

dlgvorbisComment = OpenWindow(#PB_Any, 0, 0, 810, 380, "OGG vorbis Comments", #PB_Window_SystemMenu)
edtSongStats = EditorGadget(#PB_Any, 10, 40, 200, 280, #PB_Editor_ReadOnly)
txtFileSpec = TextGadget(#PB_Any, 10, 10, 200, 20, "File Specification")
txtAvailableComments = TextGadget(#PB_Any, 230, 10, 200, 20, "Available Comments")
txtSelectComments = TextGadget(#PB_Any, 230, 40, 200, 20, "Select Comment")
cmbComments = ComboBoxGadget(#PB_Any, 230, 70, 200, 20)
edtComment = EditorGadget(#PB_Any, 230, 100, 340, 220,#PB_Editor_WordWrap)
txtImages = TextGadget(#PB_Any, 580, 10, 200, 20, "Images")
cnvPicture = CanvasGadget(#PB_Any, 580, 40, 220, 220, #PB_Canvas_Border)
txtImageStatus = TextGadget(#PB_Any, 580, 270, 220, 20, "Image 0 of 0 Images")
btnPrevious = ButtonGadget(#PB_Any, 580, 300, 60, 20, "Previous")
DisableGadget(btnPrevious,#True)
btnNext = ButtonGadget(#PB_Any, 740, 300, 60, 20, "Next")
DisableGadget(btnNext,#True)
btnDone = ButtonGadget(#PB_Any, 670, 340, 130, 25, "Done")
btnSaveComments = ButtonGadget(#PB_Any, 510, 340, 130, 25, "Save Comments")
btnSelectFile = ButtonGadget(#PB_Any, 110, 340, 130, 25, "Select File")

SetGadgetFont(edtSongStats, FontID(#Font_Window_0_0))
SetGadgetFont(edtComment, FontID(#Font_Window_0_0))

Quit = #False 
 
  Repeat
   
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Quit = #True
        CloseWindow(dlgvorbisComment)

      Case #PB_Event_Menu
        Select EventMenu()
        EndSelect

      Case #PB_Event_Gadget
        Select EventGadget()
             
          Case btnSelectFile
     
            Filename = OpenFileRequester("Select OGG File", "", "Songs (*.ogg)|*.ogg", 0) 
            If FileName
              ShowComments(FileName)
            EndIf
 
          Case btnNext
   
            If ImageIndex + 1 < ImagesFound
              ImageIndex + 1
             
              StartDrawing(CanvasOutput(cnvPicture))
                DrawImage(ImageID(vorbisImage(ImageIndex)),0,0,220,220)
              StopDrawing()
           
              SetGadgetText(txtImageStatus,"Image " + Str(ImageIndex + 1) +" of " + Str(ImagesFound) + " Images")
              If ImageIndex > 0
                DisableGadget(btnPrevious,#False)
              EndIf
               If ImageIndex = ArraySize(vorbisImage()) - 1
                DisableGadget(btnNext,#True)
              EndIf           
           
            EndIf
           
          Case btnPrevious
           
            ImageIndex - 1
           
            If ImageIndex > -1
              StartDrawing(CanvasOutput(cnvPicture))
                DrawImage(ImageID(vorbisImage(ImageIndex)),0,0,220,220)
              StopDrawing()
            EndIf
            SetGadgetText(txtImageStatus,"Image " + Str(ImageIndex + 1) +" of " + Str(ImagesFound) + " Images")
            If ImageIndex = 0
              DisableGadget(btnPrevious,#True)
            EndIf
            If ImageIndex < ArraySize(vorbisImage()) - 1
              DisableGadget(btnNext,#False)
            EndIf           
   
          Case btnDone
            Quit = #True
            CloseWindow(dlgvorbisComment)
             
          Case cmbComments
             
            ClearGadgetItems(edtComment)

            ForEach VorbisComment::SongTags()
               
              If VorbisComment::SongTags()\Title = GetGadgetText(cmbComments)
                 
                ClearGadgetItems(edtComment)
                AddGadgetItem(edtComment,-1,VorbisComment::SongTags()\Value)
                Break
               
              EndIf
               
            Next
   
        EndSelect
      EndSelect
 
    Until Quit = #True


Think I am getting there just in information overload at the moment.

Kind Regards

CD

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Aug 13, 2019 10:53 am 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Hi All

Reading comments seems to be working great thanks to wilbert and others.

Moving on to writing comments.

The first thing is to ensure we are reading the page sequence and checksums correctly.

I have modyfird infratecs checksum routine to calculate a checksum from a buffer and written a smal program to check an og vorbis files integrity as a start:-

Code:
EnableExplicit

; >> Structures <<

Structure OGGPage
  CapturePattern.l
  Version.a
  HeaderType.a
  GranulePosition.q
  BitstreamSerialNumber.l
  PageSequenceNumber.l
  Checksum.l
  PageSegments.a
  SegmentTable.a[255]
EndStructure

Structure Page
  PageNumber.i
  Start.i
  Finish.i
EndStructure

Structure Error
  PageNumber.i
  Error.s
EndStructure

Global NewList Errors.Error()

Global PageCount.i,OriginalCheckSum.s, CalculatedChecksum.s

Global NewList PageOffsets.Page()

Global *Buffer

Procedure.i checksumbuffer(*Buffer,BufferLength.i)
 
  Define iLoop.i
 
  Protected crc_reg.l, b.a
 
  For iLoop = 0 To BufferLength - 1
   
    b = PeekA(*Buffer + iLoop)

    crc_reg = (crc_reg << 8) ! PeekL(?crc_lookup + (((crc_reg >> 24) & $ff) ! b) * 4)
   
    Next iLoop
 
  ProcedureReturn crc_reg
 
EndProcedure

Procedure CheckPage(FileHandle.i,Start.i,Finish.i)
 
  Protected Result.i
 
  Define BufferSize.i
  Define BufferStart.i,BufferEnd.i
 

  If IsFile(FileHandle)

    BufferSize =  Finish - Start
     
    FileSeek(FileHandle,Start)
   
    If Finish > start
       
      If *buffer
        FreeMemory(*Buffer)
      EndIf
       
      *Buffer = AllocateMemory(BufferSize)
     
      ReadData(FileHandle,*Buffer,BufferSize)

      OriginalCheckSum = Hex(PeekL(*Buffer + 22),#PB_Long)

      ;Zero Checksum Bytes
      PokeL(*buffer + 22,0)
 
      ;Get Checksum Of Buffer
      result = checksumbuffer(*Buffer,BufferSize)
   
      CalculatedCheckSum =  Hex(result,#PB_Long)

      If CalculatedCheckSum <> OriginalCheckSum
     
        AddElement(Errors())
        Errors()\PageNumber = PageOffsets()\PageNumber
        Errors()\Error = "Bad Checksum"
     
      EndIf
   
   
    EndIf
   
  EndIf
 
EndProcedure

Procedure ParseOGG(Filename.s)
 
  Protected OGGFile.i, NextPageLoc.q, Page.OGGPage
  Protected *Mem.Long, *CommentPacket, BitstreamSerialNumber.l
  Protected.i i, NextPage, LastSegment, BytesToRead, PacketSize, Length
 
  OGGFile = ReadFile(#PB_Any, Filename)
  If OGGFile
    ClearList(PageOffsets())
   
    PageCount = 0
    AddElement(PageOffsets())
    PageOffsets()\PageNumber = PageCount
    PageOffsets()\Start = 0

    ; >> Process pages <<
    While ReadData(OGGFile, @Page, 27) = 27 And
      Page\CapturePattern = $5367674F And
      ReadData(OGGFile, @Page + 27, Page\PageSegments) = Page\PageSegments
     
      ; >> Calculate file position of next page <<
      LastSegment = Page\PageSegments - 1
      NextPageLoc = Loc(OGGFile)
      For i = 0 To LastSegment
        NextPageLoc + Page\SegmentTable[i]
      Next
     
      PageOffsets()\Finish = NextPageLoc
   
      If PageCount <> Page\PageSequenceNumber
       
        AddElement(Errors())
        Errors()\PageNumber = Page\PageSequenceNumber
        Errors()\Error = "Page sequence Error"
       
      EndIf
     
      PageCount + 1
     
      AddElement(PageOffsets())
      PageOffsets()\PageNumber = PageCount
      PageOffsets()\Start = NextPageLoc
     
      ; Set the file pointer to the next page
      FileSeek(OGGFile, NextPageLoc)
     
    Wend
    CloseFile(OGGFile)
   
  EndIf

EndProcedure

Define FileHandle.i,FileToSearch.s

FileToSearch = OpenFileRequester("Please choose ogg file", "", "Song Files (*.ogg)|*.ogg", 0)

If FileToSearch
 
  ParseOGG(FileToSearch)

  FileHandle = ReadFile(#PB_Any,FileToSearch)
 
  If IsFile(FileHandle)

    ForEach PageOffsets()
 
      CheckPage(FileHandle,PageOffsets()\Start,PageOffsets()\Finish) 
   
    Next

  EndIf

  If ListSize(Errors()) > 0

    ForEach Errors()
 
      Debug Errors()\PageNumber
      Debug Errors()\Error
    Next

  Else
 
    Debug "No Errors Found"

  EndIf
 
EndIf

End

DataSection
  crc_lookup:
  Data.l $00000000,$04c11db7,$09823b6e,$0d4326d9
  Data.l $130476dc,$17c56b6b,$1a864db2,$1e475005
  Data.l $2608edb8,$22c9f00f,$2f8ad6d6,$2b4bcb61
  Data.l $350c9b64,$31cd86d3,$3c8ea00a,$384fbdbd
  Data.l $4c11db70,$48d0c6c7,$4593e01e,$4152fda9
  Data.l $5f15adac,$5bd4b01b,$569796c2,$52568b75
  Data.l $6a1936c8,$6ed82b7f,$639b0da6,$675a1011
  Data.l $791d4014,$7ddc5da3,$709f7b7a,$745e66cd
  Data.l $9823b6e0,$9ce2ab57,$91a18d8e,$95609039
  Data.l $8b27c03c,$8fe6dd8b,$82a5fb52,$8664e6e5
  Data.l $be2b5b58,$baea46ef,$b7a96036,$b3687d81
  Data.l $ad2f2d84,$a9ee3033,$a4ad16ea,$a06c0b5d
  Data.l $d4326d90,$d0f37027,$ddb056fe,$d9714b49
  Data.l $c7361b4c,$c3f706fb,$ceb42022,$ca753d95
  Data.l $f23a8028,$f6fb9d9f,$fbb8bb46,$ff79a6f1
  Data.l $e13ef6f4,$e5ffeb43,$e8bccd9a,$ec7dd02d
  Data.l $34867077,$30476dc0,$3d044b19,$39c556ae
  Data.l $278206ab,$23431b1c,$2e003dc5,$2ac12072
  Data.l $128e9dcf,$164f8078,$1b0ca6a1,$1fcdbb16
  Data.l $018aeb13,$054bf6a4,$0808d07d,$0cc9cdca
  Data.l $7897ab07,$7c56b6b0,$71159069,$75d48dde
  Data.l $6b93dddb,$6f52c06c,$6211e6b5,$66d0fb02
  Data.l $5e9f46bf,$5a5e5b08,$571d7dd1,$53dc6066
  Data.l $4d9b3063,$495a2dd4,$44190b0d,$40d816ba
  Data.l $aca5c697,$a864db20,$a527fdf9,$a1e6e04e
  Data.l $bfa1b04b,$bb60adfc,$b6238b25,$b2e29692
  Data.l $8aad2b2f,$8e6c3698,$832f1041,$87ee0df6
  Data.l $99a95df3,$9d684044,$902b669d,$94ea7b2a
  Data.l $e0b41de7,$e4750050,$e9362689,$edf73b3e
  Data.l $f3b06b3b,$f771768c,$fa325055,$fef34de2
  Data.l $c6bcf05f,$c27dede8,$cf3ecb31,$cbffd686
  Data.l $d5b88683,$d1799b34,$dc3abded,$d8fba05a
  Data.l $690ce0ee,$6dcdfd59,$608edb80,$644fc637
  Data.l $7a089632,$7ec98b85,$738aad5c,$774bb0eb
  Data.l $4f040d56,$4bc510e1,$46863638,$42472b8f
  Data.l $5c007b8a,$58c1663d,$558240e4,$51435d53
  Data.l $251d3b9e,$21dc2629,$2c9f00f0,$285e1d47
  Data.l $36194d42,$32d850f5,$3f9b762c,$3b5a6b9b
  Data.l $0315d626,$07d4cb91,$0a97ed48,$0e56f0ff
  Data.l $1011a0fa,$14d0bd4d,$19939b94,$1d528623
  Data.l $f12f560e,$f5ee4bb9,$f8ad6d60,$fc6c70d7
  Data.l $e22b20d2,$e6ea3d65,$eba91bbc,$ef68060b
  Data.l $d727bbb6,$d3e6a601,$dea580d8,$da649d6f
  Data.l $c423cd6a,$c0e2d0dd,$cda1f604,$c960ebb3
  Data.l $bd3e8d7e,$b9ff90c9,$b4bcb610,$b07daba7
  Data.l $ae3afba2,$aafbe615,$a7b8c0cc,$a379dd7b
  Data.l $9b3660c6,$9ff77d71,$92b45ba8,$9675461f
  Data.l $8832161a,$8cf30bad,$81b02d74,$857130c3
  Data.l $5d8a9099,$594b8d2e,$5408abf7,$50c9b640
  Data.l $4e8ee645,$4a4ffbf2,$470cdd2b,$43cdc09c
  Data.l $7b827d21,$7f436096,$7200464f,$76c15bf8
  Data.l $68860bfd,$6c47164a,$61043093,$65c52d24
  Data.l $119b4be9,$155a565e,$18197087,$1cd86d30
  Data.l $029f3d35,$065e2082,$0b1d065b,$0fdc1bec
  Data.l $3793a651,$3352bbe6,$3e119d3f,$3ad08088
  Data.l $2497d08d,$2056cd3a,$2d15ebe3,$29d4f654
  Data.l $c5a92679,$c1683bce,$cc2b1d17,$c8ea00a0
  Data.l $d6ad50a5,$d26c4d12,$df2f6bcb,$dbee767c
  Data.l $e3a1cbc1,$e760d676,$ea23f0af,$eee2ed18
  Data.l $f0a5bd1d,$f464a0aa,$f9278673,$fde69bc4
  Data.l $89b8fd09,$8d79e0be,$803ac667,$84fbdbd0
  Data.l $9abc8bd5,$9e7d9662,$933eb0bb,$97ffad0c
  Data.l $afb010b1,$ab710d06,$a6322bdf,$a2f33668
  Data.l $bcb4666d,$b8757bda,$b5365d03,$b1f740b4
EndDataSection


Run the programme and select an ogg file the file will be checked for page sequence errors and every pages checksum will be checked.

Output is any errors found or "No Errors"

Regards

CD

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Aug 13, 2019 11:32 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
collectordave wrote:
The first thing is to ensure we are reading the page sequence and checksums correctly.

I have modyfird infratecs checksum routine to calculate a checksum from a buffer and written a smal program to check an og vorbis files integrity as a start:

Seems to work fine :)

If desired, you could speed up the crc calculation by using pointers instead of Peek.
(or of course use an assembly based crc routine. :wink: )

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: ogg vorbis comment (tag)
PostPosted: Tue Aug 13, 2019 12:08 pm 
Offline
Addict
Addict

Joined: Fri Aug 28, 2015 6:10 pm
Posts: 1013
Location: Portugal
Hi Wilbert

Thanks for testing.

I am moving on to firstly attempt to split the first three vorbis headers onto an ogg page each instead of scrunching them up. So that ogg page 1 is vorbis header 1 (no problem) section 2 comments on to page or pages, can be multiple, then vorbis header 3 on the next page after comments. Only 1 vorbis section to pack in the ogg file then comments. All the audio data is after vorbis header 3 so the most I will have to do is rewrite the page sequence number calculate the CRC for each page and add to the new file.

My big worry for later is encodeing images ready to be placed in the comment pages.

Of course anything that can be done to speed this all up would be welcome.

Kind Regards

CD

_________________
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 60 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: Zimon and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye