Estrarre informazioni da un file .wav

Da Gambas-it.org - Wikipedia.

Il file .wav è un sottotipo del file RIFF.

Le informazioni generali di un file WAVE sono contenute nei primi 44 byte del file medesimo.

Il file WAVE è sostanzialmente composto da un solo blocco (chunk), a sua volta composto da due sottoblocchi: il primo blocco, appunto, formato da 44 byte contiene - come già detto - le informazioni relative alle caratteristiche del file; il secondo blocco contiene i dati audio veri e propri della forma d'onda digitalizzata.


Estrazione delle informazioni con le sole funzioni Gambas

Volendo estrarre le informazioni più importanti relative ad un file WAV mediante le sole risorse interne di Gambas, andremo a leggere alcuni byte spcifici appartenenti al primo sotto-blocco. Bisogna sottolineare che i le informzioni sono espresse all'interno del primo sotto-blocco in modalità little-endian. |1|

Formato audio

Le informazioni relative al formato audio sono contenute in little-endian nel 20° e nel 21° byte.

Frequenza di campionamento

Le informazioni relative alla frequenza di campionamento del file WAV sono contenute in little-endian nel 24°, 25°, 26° e 27° byte.

Risoluzione del campionamento

Le informazioni relative alla risoluzione in bit del campionamento del file WAV sono contenute in little-endian nel 34° e 35° byte.

Numero di canali

Le informazioni relative al numero di canali del file WAV sono contenute in little-endian nel 23° e 24° byte.

La lunghezza del file

I file WAV contiene immediatamente dopo il primo sotto-blocco iniziale quattro byte che indicano la quantità di byte contenuta dal secondo sotto-blocco (quello formato dai veri e propri dati audio grezzi). Per conoscere la totale dimensione del file WAV, pertanto, basterà aggiungere a tale valore il numero 44 (che rappresentano i quarantaquattro byte che formano il primo sotto-blocco informativo del file).


Esempi pratici

Per estrarre le suddette informazioni, potremo, dunque, realizzare un codice simile quello che segue:

Public Sub Main()

 Dim fl As File
 Dim j, b, canali, risoluzione As Byte
 Dim buf As New Byte[]
 Dim frequenza As Integer
 

' Carica un file audio Wav:
  fl = Open "/percorso/del/file.wav" For Read
  
  For j = 0 To 43
    Read #fl, b
    buf.Add(b)
  Next


' Rileva il numero di canali (legge 2 byte):
  canali = buf[23] * CInt(2 ^ 8)
  canali = canali Or buf[22]
  Print "Numero canali = "; canali


' Rileva la frequenza di campionamento (legge 4 byte):
  frequenza = buf[27] * CInt(2 ^ 24)
  frequenza = frequenza Or buf[26] * CInt(2 ^ 16)
  frequenza = frequenza Or buf[25] * CInt(2 ^ 8)
  frequenza = frequenza Or buf[24]
  Print "Frequenza = hrz "; frequenza


' Rileva la risoluzione del campionamento (legge 2 byte):
  risoluzione = buf[35] * CInt(2 ^ 8)
  risoluzione = risoluzione Or buf[34]
  Print "Risoluzione = "; risoluzione; " bit"


' Rileva la quantità dei soli dati grezzi (legge 4 byte):
  dimensione = buf[43] * CInt(2 ^ 24)
  dimensione = dimensione Or buf[42] * CInt(2 ^ 16)
  dimensione = dimensione Or buf[41] * CInt(2 ^ 8)
  dimensione = dimensione Or buf[40]
  Print "Quantità dei soli dati grezzi = "; dimensione; " byte"

  
  fl.Close

End


Usando la funzione Seek

Potremo anche più semplicemente spostarci all'interno del flusso mediante la funzione Seek:

Public Sub Main()

 Dim fileWAV As String
 Dim fl As File
 Dim canali, risoluzione As Byte
 Dim d As Short
 Dim frequenza, dimensione As Integer
 

  fileWAV = "/percorso/del/file.wav"

  d = Instr(File.Load(fileWAV), "data")

' Carica un file audio Wav:
  fl = Open fileWAV For Read
  
  
' Rileva il numero di canali (legge 2 byte):
  Seek #fl, 22
  Read #fl, canali
  Print "Numero canali = "; canali


' Rileva la frequenza di campionamento (legge 4 byte):
  Seek #fl, 24
  Read #fl, frequenza
  Print "Frequenza = hrz "; frequenza


' Rileva la risoluzione del campionamento (legge 2 byte):
  Seek #fl, 34
  Read #fl, risoluzione
  Print "Risoluzione = "; risoluzione; " bit"


' Rileva la quantità dei soli dati grezzi (legge 4 byte):
  seek #fl, d + 3
  Read #fl, dimensione
  Print "Quantità dei soli dati grezzi = "; dimensione; " byte"


  fl.Close

End


Usando una variabile vettoriale di tipo Byte[]

Per estrarre le informazioni possiamo anche utilizzare un Vettore di tipo Byte[]:

Public Sub Main()

Dim percorsoFile As String
Dim fl As File
Dim bb As Byte[]


 percorsoFile = "/percorso/del/file.wav"
 
 fl = Open percorsoFile For Read

 bb = New Byte[44]
 
 bb.Read(fl, 0, 44)
 
 If bb.ToString(0, 4) <> "RIFF" Then Error.Raise("Il file caricato non è di tipo 'RIFF' !")
 
 If bb.ToString(8, 4) <> "WAVE" Then Error.Raise("Il file caricato non è di tipo 'WAVE' !")
 
 If bb.ToString(12, 4) <> "fmt " Then Error.Raise("Il file caricato non è di tipo 'fmt ' !")
 
 Print "== Caratteristiche del file: "; File.Name(percorsoFile); " ==\n"
 
 Print "Dimensioni totali del file: "; Stat(percorsoFile).Size; " byte"
 
 Print "Dimensione dei soli dati audio grezzi: "; Stat(percorsoFile).Size - 44; " byte"
 
 If bb[20] = 1 Then 
   Print "Formato audio: PCM"
 Else
   Print "Formato audio: "; bb[20]
 Endif
 
 Print "Canali di uscita audio: "; bb[22]
 
 Print "Frequenza di campionamento: Hz "; Val("&" & Hex(bb[27]) & Hex(bb[26]) & Hex(bb[25]) & Hex(bb[24]))
 
 Print "Byte rate: "; Val("&" & Hex(bb[31]) & Hex(bb[30]) & Hex(bb[29]) & Hex(bb[28])); " Bps"
 
 Print "Risoluzione di campionamento a "; bb[34]; " bit"


 fl.Close
  
End


Estrazione delle informazioni con le funzioni esterne del API di SOX

La libreria Sox contiene risorse per poter gestire ampiamente i file audio: riproduzione e registrazione, conversione di vari formati audio in altri formati, nonché applicazione di vari effetti.

Le risorse del API di Sox consentono anche di ottenere facilmente varie informazioni dai file audio, richiamando l'attuale versione della libreria: libsox.so.2.0.1

Potremo procedere con un codice simile al seguente:

Public Struct sox_signalinfo_t
  rate As Float         ' sox_rate_t:  samples per second, 0 if unknown (typedef double sox_rate_t)
  channels As Integer   ' number of sound channels, 0 if unknown
  precision As Integer  ' bits per sample, 0 if unknown
  length As Long        ' samples * chans in file, 0 if unknown, -1 if unspecified (typedef unsigned long sox_uint64_t;)
  mult As Pointer       ' Effects headroom multiplier; may be null
End Struct

Public Struct sox_format_t
  filename As Pointer
  signal As Struct Sox_signalinfo_t
End Struct

Private sfIn As New Sox_format_t


Library "libsox:2.0.1"

Private Const SOX_SUCCESS As Byte = 0

' int sox_init(void)
' Client API: Initialize effects library. SOX_SUCCESS if successful.
Private Extern sox_init() As Integer

' sox_format_t * sox_open_read(char const *path, sox_signalinfo_t const *signal, sox_encodinginfo_t const *encoding, char const *filetype)
Private Extern sox_open_read(path As String, signalP As Pointer, encoding As Pointer, filetype As String) As Sox_format_t


Public Sub Main()

 Dim err As Integer
 Dim fileWAV As String


  fileWAV = "/percorso/del/file.wav"

  err = sox_init()
  If err <> SOX_SUCCESS Then Error.Raise("Impossibile inizializzare la libreria 'libsox' !")

  sfIn = sox_open_read(fileWAV, Null, Null, Null)

 With sfIn
   Print "File audio: "; String@(.filename)
   Print "Frequenza di campionamento: hrz "; .signal.rate
   Print "Numero di canali: "; .signal.channels
   Print "Risoluzione campionamento: "; .signal.precision; " bit"
   Print "Dimensione dei soli dati grezzi del file wav: "; .signal.length * .signal.channels; " byte"  ' (tale valore è privo dei byte del blocco di intestazione del file wav = 44 byte)
 End With

End


Note

[1] Ordine dei byte


Riferimenti

Per un ulteriore e dettagliata spiegazione rinviamo ai seguenti siti: