Convertire un file OggVorbis in WAV con le funzioni esterne del API di Libvorbisidec

Da Gambas-it.org - Wikipedia.

La libreria Libvorbisidec (Tremor) intende essere il più possibile simile alla libreria Vorbisfile distribuita gratuitamente da Xiph.org . Essa fornisce una libreria di soli valori con numeri interi destinati alla decodifica di tutti i formati di file Vorbis attuali e futuri.


Per poter fruire delle risorse del API di Libvorbisidec si dovrà utilizzare la libreria (nella sua attuale versione): "libvorbisidec.so.1.0.3"


Di seguito mostreremo un semplice codice per convertire un file OggVorbis in file WAV. Poiché l'uso della libreria esterna Libvorbisidec 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


Library "libvorbisidec:1.0.3"

' 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

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

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

' 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(vfP As Pointer, i As Integer) As Long


Library "libc:6"

' FILE *fopen(const char *path, const char *mode)
' Apre il file path associandolo ad uno stream.
Private Extern fopen(path As String, mode As String) As Pointer

' int fclose(FILE *stream)
' Chiude il file associato a 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 As Integer
 Dim ret As Long
 Dim datiPCMgrezzi As String
 Dim pcmout As New Byte[](4096)
 Dim f As File

  datiPCMgrezzi = "/tmp/datiPCMgrezzi"
  
  fin = fopen("/percorso/del/file.ogg", "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)
 
  With vi
    Print "Frequenza di campionamento: Hz "; .rate
    Print "Canali di uscita: "; .channels
    Print "Bitrate: "; .bitrate_nominal; " bps"
    Print "Lunghezza dei campioni decodificati: "; ov_pcm_total(vf, -1); " byte"
  End With
 

' Ciclo per la decodifica dei dati Ogg e per la scrittura del file contenente i dati grezzi PCM:
  While Not eo
    ret = ov_read(vf, pcmout, pcmout.Count, 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)
   
  dati.Clear
  bh.Clear
  fl.Close
  fwav.Close
 
End


Riferimenti

[1] L'API di Libvorbisidec

[2] L'API di Tremor-Libvorbisidec