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 condivisa: "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:

Library "libvorbisidec:1.0.3"

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

' 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 = Temp
  
 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(SizeOf(gb.Byte), 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)
 If IsNull(vi) Then Error.Raise("Errore !")

 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

 Write "\e[5mAttendere...\e[0m"
 Flush

' 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:
 Write "\rConversione terminata !"
 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