Convertire un file OggVorbis in WAV ed estrarne anche informazioni con le funzioni esterne del API di VorbisFile

Da Gambas-it.org - Wikipedia.

La libreria di VorbisFile consente di estrarre informazioni di carattere generale da un file audio OggVorbis e di convertirlo in un file audio WAV.

Per poter fruire in Gambas delle risorse del API di Ogg Vorbis si dovrà utilizzare la libreria: "libvorbisfile.so.3.3.4"


Di seguito mostreremo un semplice codice per convertire un file OggVorbis in file WAV. Poiché l'uso della libreria esterna Libvorbisfile prevede il richiamo della Struttura esterna molto complessa: OggVorbis_File, al fine di poter gestire detta Struttura esterna in modo assolutamente sicuro, riserveremo un'area di memoria di dimensione pari a quella, preliminarmente calcolata, occupata dalla Struttura esterna.

Il codice Gambas potrà essere il seguente:

Public Struct vorbis_info
  version As Integer
  channels As Integer
  rate As Long
  bitrate_upper As Long
  bitrate_nominal As Long
  bitrate_lower As Long
  bitrate_window As Long
  codec_setup As Pointer
End Struct

Public Struct vorbis_comment
  user_comments As Pointer
  comment_lengths As Pointer
  comments As Integer
  vendor As Pointer
End Struct


Library "libvorbisfile:3.3.4"

' int ov_open(FILE *f, OggVorbis_File *vf, const char *initial, long ibytes)
' Open and initialize an OggVorbis_File structure.
Private Extern ov_open(f As Pointer, vfP As Pointer, initial As String, ibytes As Long) As Integer

' vorbis_info *ov_info(OggVorbis_File *vf,int link)
' Returns the vorbis_info struct for the specified bitstream.
Private Extern ov_info(OVf As Pointer, lnk As Integer) As Vorbis_info

' double ov_time_total(OggVorbis_File *vf,int i)
' Returns the total time in seconds of the physical bitstream.
Private Extern ov_time_total(OVf As Pointer, i As Integer) As Float

' ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i)
' Returns the total pcm samples of the physical bitstream or a specified logical bitstream.
Private Extern ov_pcm_total(OVf As Pointer, i As Integer) As Long

' vorbis_comment *ov_comment(OggVorbis_File *vf, int link)
' Returns a pointer to the vorbis_comment struct for the specified bitstream.
Private Extern ov_comment(OVf As Pointer, lnk As Integer) As Pointer

' long ov_read(OggVorbis_File *vf, char *buffer, int length, int bigendianp, int word, int sgned, int *bitstream)
' Decode a Vorbis file within a loop.
Private Extern ov_read(OVf As Pointer, buffer As Byte[], length As Integer, bigendianp As Integer, word As Integer, sgned As Integer, bitstream As Pointer) As Long
 

Library "libc:6"

' FILE *fopen(const char *path, const char *mode)
' Open a file and create a new stream for it.
Private Extern fopen(path As String, mode As String) As Pointer

' int fclose(FILE *stream)
' Close STREAM.
Private Extern fclose(stmP As Pointer) As Integer
 

Public Sub Main()

 Dim vf, fin As Pointer
 Dim vi As Vorbis_info
 Dim eo, current_section, err, i As Integer
 Dim ret As Long
 Dim datiPCMgrezzi, fileOGG As String
 Dim pcmout As New Byte[](4096)
 Dim f As File
 Dim commenti As Vorbis_comment
 Dim b As Byte

  datiPCMgrezzi = "/tmp/datiPCMgrezzi"
  
  fileOGG = "/percorso/del/file.ogg"
  
  fin = fopen(fileOGG, "rb")

  f = Open datiPCMgrezzi For Create
 
' Allochiamo un'area di memoria di dimensione a quella occupata dalla Struttura "OggVorbis_File":
  vf = Alloc(944)
 
  err = ov_open(fin, vf, Null, 0)
  If err < 0 Then Error.Raise("Il file caricato potrebbe non essere del formato Ogg !")

' Estrae alcune informazioni generali del file audio Ogg caricato:
  vi = ov_info(vf, -1)
 
  Print "File audio:                              "; fileOGG
  With vi
    Print "Frequenza di campionamento:              "; .rate; " Hertz"
    Print "Canali di uscita:                        "; .channels
    Print "Bitrate:                                 "; .bitrate_nominal; " bps"
    Print "Durata del file ogg:                     "; Date(0, 0, 0, 0, 0, 0, ov_time_total(vf, -1) * 1000)
    Print "Lunghezza dei campioni decodificati:     "; ov_pcm_total(vf, -1); " byte"
  End With
  Print "Commenti presenti nel file ogg:"
  commenti = ov_comment(vf, -1)
  With commenti
    For b = 0 To .comments - 1
      i = 8 * b
      Print "   "; String@(Pointer@(.user_comments + i))
    Next
    Print "   "; String@(.vendor)
  End With
 

' Ciclo per la decodifica dei dati Ogg e per la scrittura del file contenente i dati grezzi PCM:
  While eo = 0
    ret = ov_read(vf, pcmout, pcmout.Count, 0, 2, 1, VarPtr(current_section))
    If ret = 0 Then
      eo = 1
    Else
' Scrive il file contenente i dati grezzi PCM:
      pcmout.Write(f, 0, ret)
    Endif
  Wend
 
' Va a creare il file WAV finale:
  crea_file_wav(datiPCMgrezzi)


' Va in chiusura:
  Free(vf)
  f.Close
  fclose(fin)

End


Private Procedure crea_file_wav(datiGrezzi As String)
 
 Dim fl, fwav As File
 Dim i, i2 As Integer
 Dim dati As New Byte[](Stat(datiGrezzi).Size)
 Dim bh As Byte[] = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56, &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00, &02, &00,
                    &44, &AC, &00, &00, &10, &B1, &02, &00, &04, &00, &10, &00, &64, &61, &74, &61, &00, &00, &00, &00]    ' blocco d'intestazione del file wav futuro: 2 canali, 16 bit, hz 44100
                    
  fl = Open datiGrezzi For Read
  dati.Read(fl)
     
  i = Lof(fl)
  fl.Close
  i2 = i + 36
  
' Imposta il valore dimensionale di 4 byte a partire dal 5° byte del futuro file wav:
  bh[4] = i2 And &FF
  bh[5] = Shr(i2 And &FF00&, 8)
  bh[6] = Shr(i2 And &FF0000&, 16)
  bh[7] = Shr(i2 And &FF000000&, 24)
  
' Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file wav.
' Esso è relativo alla quantità effettiva dei dati audio grezzi.
  bh[40] = i And &FF
  bh[41] = Shr(i And &FF00&, 8)
  bh[42] = Shr(i And &FF0000&, 16)
  bh[43] = Shr(i And &FF000000&, 24)
     
  bh.Insert(dati, 44)

  fwav = Open "/percorso/del/file.wav" For Create

' Inizia la scrittura del file wav:
  bh.Write(fwav, 0, bh.Count)
  
  Print "\n\nDurata del file WAV: "; Date(0, 0, 0, 0, 0, 0, ((i * 8) / (44100 * 16 * 2)) * 1000)
   
  dati.Clear
  bh.Clear
  fl.Close
  fwav.Close
 
End



Riferimenti