Differenze tra le versioni di "Estrarre informazioni da un file .wav"

Da Gambas-it.org - Wikipedia.
 
(20 versioni intermedie di uno stesso utente non sono mostrate)
Riga 4: Riga 4:
  
 
Il file ''[http://it.wikipedia.org/wiki/WAV 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.
 
Il file ''[http://it.wikipedia.org/wiki/WAV 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.
 +
 +
[[File:Wav.png]]
  
  
Riga 10: Riga 12:
  
 
===Formato audio===
 
===Formato audio===
Le informazioni relative al formato audio sono contenute in ''little-endian'' nel 21° e nel 22° byte.
+
Le informazioni relative al formato audio sono contenute in ''little-endian'' nel 21° e nel 22° byte (indice offset: 20, 21).
  
 
===Numero di canali===
 
===Numero di canali===
Le informazioni relative al numero di canali del file WAV sono contenute in ''little-endian'' nel 23° e 24° byte (indice offset: 22 - 23).
+
Le informazioni relative al numero di canali del file WAV sono contenute in ''little-endian'' nel 23° e 24° byte (indice offset: 22, 23).
  
 
===Frequenza di campionamento===
 
===Frequenza di campionamento===
Le informazioni relative alla frequenza di campionamento del file WAV sono contenute in ''little-endian'' nel 25°, 26° 27° e 28° byte (indice offset: 24 - 25 - 26 - 27).
+
Le informazioni relative alla frequenza di campionamento del file WAV sono contenute in ''little-endian'' nel 25°, 26° 27° e 28° byte (indice offset: 24, 25, 26 e 27).
  
 +
===ByteRate===
 +
Le informazioni relative al ''ByteRate'' sono contenute in ''Little-Endian'' nel 29°, 30, 31° e 32° byte (indice offset: 28, 29, 30 e 31).
 +
 +
===block align===
 +
Il ''Block Align'' rappresenta la quantità di byte che costituisce un campione audio significativo.
 +
<BR>Esso è un valore di tipo ''Short'' in ''Little-Endian'', posto al byte d'indice offset n. 32, ed è dato anche dalla seguente formula:
 +
Block_Align = (Risoluzione_del_campionamento_in_bit / 8-bit) * Canali
 
===Risoluzione del campionamento===
 
===Risoluzione del campionamento===
La risoluzione del campionamento audio rappresenta la gamma di valori che un campione audio può assumere. Una gamma più ampia conferisce ovviamente un campionamento più dinamico e ricco.
+
La risoluzione del campionamento audio è espresso in bit per un campione audio e rappresenta la gamma di valori che detto campione audio può assumere. Una gamma più ampia conferisce ovviamente un campionamento più dinamico e ricco.
  
 
Le informazioni relative alla risoluzione in bit del campionamento del file WAV sono contenute in ''little-endian'' nel 35° e 36° byte (indice offset: 34 - 35).
 
Le informazioni relative alla risoluzione in bit del campionamento del file WAV sono contenute in ''little-endian'' nel 35° e 36° byte (indice offset: 34 - 35).
  
 +
Un'altra modalità, per ottenere il valore della risoluzione in bit, è - conoscendo la durata dell'esecuzione audio del file - effettuare il seguente calcolo:
 +
bit = ((quantità_dati_audio_del_file * 8) / durata_in_secondi) / (frequenza_di_campionamento * numero_canali_audio)
 
===La lunghezza del file===
 
===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).
+
Il 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 di byte costituenti il blocco d'intestazione del file wav, solitamente 44 byte, che formano il primo sotto-blocco informativo del file.
  
 
===Numero dei campioni (''samples'')===
 
===Numero dei campioni (''samples'')===
Riga 35: Riga 46:
  
 
===Ottenere la durata del file wav===
 
===Ottenere la durata del file wav===
Per ottenere la durata dei dati audio wav, si possono adottare due modalità di calcolo:
+
Per ottenere la durata dei dati audio wav <SUP>&#091;[[#Note|Nota 2]]&#093;</sup>, si possono adottare due modalità di calcolo:
  
 
La prima modalità prevede la seguente formula:
 
La prima modalità prevede la seguente formula:
Riga 48: Riga 59:
  
 
====Assegnando i dati letti dall'<I>Header</i> del file wav ai membri di un'apposita ''Struttura''====
 
====Assegnando i dati letti dall'<I>Header</i> del file wav ai membri di un'apposita ''Struttura''====
 +
In questo esempio assegneremo i dati letti dall'<I>Header</i> del file wav ai membri di un'apposita "Struttura":
 
  Public Struct Header_Wav
 
  Public Struct Header_Wav
 
   riff As String          <FONT color=gray>' ''tipo file "RIFF"''</font>
 
   riff As String          <FONT color=gray>' ''tipo file "RIFF"''</font>
Riga 65: Riga 77:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim fileWAV As String
+
  Dim fileWAV As String
  Dim wav As File
+
  Dim wav As File
  Dim hw As New Header_Wav
+
  Dim hw As New Header_Wav
 
    
 
    
   fileWAV = "<FONT color=gray>''/percorso/del/file.wav''</font>"
+
   fileWAV = "<FONT color=darkgreen>''/percorso/del/file.wav''</font>"
 
    
 
    
 
   wav = Open fileWAV For Read
 
   wav = Open fileWAV For Read
Riga 94: Riga 106:
 
   wav.Close
 
   wav.Close
 
          
 
          
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function legge_stringa(fl As File) As String
+
  Private Function legge_stringa(fl As File) As String
 
   
 
   
  Dim s As String
+
  Dim s As String
 
    
 
    
 
   Read #fl, s, 4
 
   Read #fl, s, 4
Riga 105: Riga 117:
 
   Return s
 
   Return s
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function legge_intero(fl As File) As Integer
+
  Private Function legge_intero(fl As File) As Integer
 
   
 
   
  Dim i As Integer
+
  Dim i As Integer
 
    
 
    
 
   Read #fl, i
 
   Read #fl, i
Riga 116: Riga 128:
 
   Return i
 
   Return i
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function legge_corto(fl As File) As Short
+
  Private Function legge_corto(fl As File) As Short
 
   
 
   
  Dim sh As Short
+
  Dim sh As Short
 
    
 
    
 
   Read #fl, sh
 
   Read #fl, sh
Riga 127: Riga 139:
 
   Return sh
 
   Return sh
 
   
 
   
  '''End'''
+
  End
  
  
 
====Leggendo e gestendo il file WAV come ''stringa''====
 
====Leggendo e gestendo il file WAV come ''stringa''====
 
In questo caso leggeremo e gestiremo l'intero file WAV come una ''stringa''.
 
In questo caso leggeremo e gestiremo l'intero file WAV come una ''stringa''.
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
  Dim per, s, dati_grezzi As String
+
  Dim per, s, dati_grezzi As String
  Dim d, i, campionamento, formato, durata As Integer
+
  Dim d, i, campionamento, formato, durata As Integer
  Dim canali, bit As Short
+
  Dim canali, bit As Short
 
    
 
    
 
  <FONT Color=gray>' '''''Estrae alcune informazioni sul file:'''''</font>
 
  <FONT Color=gray>' '''''Estrae alcune informazioni sul file:'''''</font>
 
+
   per = "<FONT Color=gray>''/percorso/del/file.wav''</font>"
+
   per = "<FONT Color=darkgreen>''/percorso/del/file.wav''</font>"
 
   Print "Percorso del file audio:    "; per
 
   Print "Percorso del file audio:    "; per
 
    
 
    
Riga 148: Riga 160:
 
    
 
    
 
   d = InStr(s, "data", 0, gb.Binary)
 
   d = InStr(s, "data", 0, gb.Binary)
   i = Int@(VarPtr(s) + d + 3)
+
   i = Int@(s[d + 3])
 
   Print "Totale dei soli byte audio: "; i; " byte"
 
   Print "Totale dei soli byte audio: "; i; " byte"
 
    
 
    
 
   d = InStr(s, "fmt ", 0, gb.Binary)
 
   d = InStr(s, "fmt ", 0, gb.Binary)
   canali = Short@(VarPtr(s) + d + 9)
+
   canali = Short@(s[d + 9])
 
   Print "Numero canali audio:        "; canali
 
   Print "Numero canali audio:        "; canali
 
    
 
    
   campionamento = Int@(VarPtr(s) + d + 11)
+
   campionamento = Int@(s[d + 11])
 
   Print "Frequenza di campionamento: "; campionamento; " hertz"
 
   Print "Frequenza di campionamento: "; campionamento; " hertz"
 
    
 
    
   bit = Short@(VarPtr(s) + d + 21)
+
   bit = Short@(s[d + 21])
 
   Print "Profondità campionamento:  "; bit; " bit"
 
   Print "Profondità campionamento:  "; bit; " bit"
 
    
 
    
 
   durata = (i * 8) / (campionamento * bit * canali)
 
   durata = (i * 8) / (campionamento * bit * canali)
   Print "Durata del brano audio:    "; CStr(Date(0, 0, 0, 0, 0, 0, durata * 1000))
+
   Print "Durata del brano audio:    "; CStr(Time(0, 0, 0, durata * 1000))
 
    
 
    
 
  <FONT Color=gray>' ''Raccoglie i soli byte dei dati audio grezzi:''</font>
 
  <FONT Color=gray>' ''Raccoglie i soli byte dei dati audio grezzi:''</font>
 
   dati_grezzi = Right(s, i)
 
   dati_grezzi = Right(s, i)
 
    
 
    
  '''End'''
+
  End
  
  
 
====Usando una variabile vettoriale di tipo ''Byte[]'' - 1====
 
====Usando una variabile vettoriale di tipo ''Byte[]'' - 1====
 
Potremo utilizzare un vettore di tipo ''Byte[]'' per contenere i dati del file wav:
 
Potremo utilizzare un vettore di tipo ''Byte[]'' per contenere i dati del file wav:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim percorsoFile As String
+
  Dim percorsoFile As String
  Dim fl As File
+
  Dim fl As File
  Dim j, b, formato, canali, risoluzione As Byte
+
  Dim j, b, formato, canali, risoluzione As Byte
  Dim buf As New Byte[]
+
  Dim buf As New Byte[]
  Dim frequenza, dimensione As Integer
+
  Dim frequenza, dimensione As Integer
 
    
 
    
+
   percorsoFile = "<FONT Color=darkgreen>''/percorso/del/file.wav''</font>"
   percorsoFile = "''/percorso/del/file.wav''"
 
 
   
 
   
 
  <FONT color=gray>' ''Carica un file audio Wav:''</font>
 
  <FONT color=gray>' ''Carica un file audio Wav:''</font>
Riga 207: Riga 218:
 
   canali = canali Or buf[22]
 
   canali = canali Or buf[22]
 
   Print "Numero canali = "; canali
 
   Print "Numero canali = "; canali
 
 
   
 
   
 
  <FONT color=gray>' ''Rileva la frequenza di campionamento (legge 4 byte):''</font>
 
  <FONT color=gray>' ''Rileva la frequenza di campionamento (legge 4 byte):''</font>
Riga 215: Riga 225:
 
   frequenza = frequenza Or buf[24]
 
   frequenza = frequenza Or buf[24]
 
   Print "Frequenza = hrz "; frequenza
 
   Print "Frequenza = hrz "; frequenza
 
 
   
 
   
 
  <FONT color=gray>' ''Rileva la risoluzione del campionamento (legge 2 byte):''</font>
 
  <FONT color=gray>' ''Rileva la risoluzione del campionamento (legge 2 byte):''</font>
Riga 221: Riga 230:
 
   risoluzione = risoluzione Or buf[34]
 
   risoluzione = risoluzione Or buf[34]
 
   Print "Risoluzione = "; risoluzione; " bit"
 
   Print "Risoluzione = "; risoluzione; " bit"
 
 
   
 
   
 
  <FONT color=gray>' ''Rileva la quantità dei soli dati grezzi (legge 4 byte):''</font>
 
  <FONT color=gray>' ''Rileva la quantità dei soli dati grezzi (legge 4 byte):''</font>
Riga 231: Riga 239:
 
   
 
   
 
  <FONT color=gray>' ''Calcola la durata del brano audio:''</font>
 
  <FONT color=gray>' ''Calcola la durata del brano audio:''</font>
   Print "Durata del brano: "; Date(0, 0, 0, 0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)
+
   Print "Durata del brano: "; Time(0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)
 
   
 
   
 
 
 
   fl.Close
 
   fl.Close
 
   
 
   
  '''End'''
+
  End
  
  
 
====Usando una variabile vettoriale di tipo ''Byte[]'' - 2====
 
====Usando una variabile vettoriale di tipo ''Byte[]'' - 2====
 
Per estrarre le informazioni possiamo anche utilizzare un Vettore di tipo ''Byte[]'':
 
Per estrarre le informazioni possiamo anche utilizzare un Vettore di tipo ''Byte[]'':
  '''Public''' Sub Main()
+
  Public Sub Main()
 
Dim percorsoFile As String
 
Dim fl As File
 
Dim bb As Byte[]
 
Dim solo_dati, frequenza As Integer
 
 
   
 
   
 +
  Dim percorsoFile As String
 +
  Dim fl As File
 +
  Dim bb As Byte[]
 +
  Dim solo_dati, frequenza As Integer
 
   
 
   
   percorsoFile = "''/percorso/del/file.wav''"
+
   percorsoFile = "<FONT color=darkgreen>''/percorso/del/file.wav''</font>"
 
    
 
    
 
   fl = Open percorsoFile For Read
 
   fl = Open percorsoFile For Read
Riga 285: Riga 291:
 
   Print "Risoluzione di campionamento a "; bb[34]; " bit"
 
   Print "Risoluzione di campionamento a "; bb[34]; " bit"
 
   
 
   
   Print "Durata del brano: "; Date(0, 0, 0, 0, 0, 0, Fix((solo_dati * 8) / (frequenza * bb[34] * bb[22])) * 1000)
+
   Print "Durata del brano: "; Time(0, 0, 0, Fix((solo_dati * 8) / (frequenza * bb[34] * bb[22])) * 1000)
 
   
 
   
 
   
 
   
 
   fl.Close
 
   fl.Close
 
    
 
    
  '''End'''
+
  End
  
  
====Usando una variabile vettoriale di tipo ''Byte[]'' - 3====
+
====Usando una variabile vettoriale di tipo Byte[] - 3====
 
In questo esempio vengono caricati in un'apposita ''Struttura'' alcuni dati del file Wav: numero canali, frequenza di campionamento, risoluzione, block align (quest'ultimo sarà utile per ottenere la durata del brano audio). Tali dati verranno poi mostrati in console ed utilizzati alcuni per calcolare la durata di esecuzione del file Wav:
 
In questo esempio vengono caricati in un'apposita ''Struttura'' alcuni dati del file Wav: numero canali, frequenza di campionamento, risoluzione, block align (quest'ultimo sarà utile per ottenere la durata del brano audio). Tali dati verranno poi mostrati in console ed utilizzati alcuni per calcolare la durata di esecuzione del file Wav:
 
  Public Struct INFOWAV
 
  Public Struct INFOWAV
Riga 305: Riga 311:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim fileWav As String
+
  Dim fileWav As String
  Dim datiwav As New INFOWAV
+
  Dim datiwav As New INFOWAV
 
    
 
    
   datiwav.fileWav = "''/percorso/del/file.wav''"
+
   datiwav.fileWav = "<FONT color=darkgreen>''/percorso/del/file.wav''</font>"
 
    
 
    
 
   EstraeDatiAudio(datiwav)
 
   EstraeDatiAudio(datiwav)
 
    
 
    
  <FONT Color=gray>' ''Mostra in console le informazioni ottenute:</font>
+
  <FONT Color=gray>' ''Mostra in console le informazioni ottenute:''</font>
 
   With datiwav
 
   With datiwav
     Print "File wav caricato:";; .fileWAV
+
     Print "File wav caricato:           "; .fileWAV
     Print "Numero canali:";; .canali
+
     Print "Numero canali:               "; .canali
     Print "Frequenza di campionamento: hz";; .frequenza
+
     Print "Frequenza di campionamento: hz"; .frequenza
     Print "Risoluzione:";; .bit;; "bit"
+
     Print "Risoluzione:                 "; .bit; " bit"
     Print "Durata esecuzione:";; CStr(Date(0, 0, 0, 0, 0, 0, .durata * 1000))
+
     Print "Durata esecuzione:           "; CStr(Time(0, 0, 0, .durata * 1000))
 
   End With
 
   End With
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function EstraeDatiAudio(iw As INFOWAV)
+
  Private Function EstraeDatiAudio(iw As INFOWAV)
 
   
 
   
 
   Dim fl As File
 
   Dim fl As File
 
    
 
    
 
  <FONT Color=gray>' ''Carica il file audio Wav:</font>
 
  <FONT Color=gray>' ''Carica il file audio Wav:</font>
  fl = Open iw.fileWAV For Read
+
  fl = Open iw.fileWAV For Read
 
   
 
   
 
  <FONT Color=gray>' ''Legge il numero dei canali al byte d'indice (offset) 22:''</font>
 
  <FONT Color=gray>' ''Legge il numero dei canali al byte d'indice (offset) 22:''</font>
  Seek #fl, 22
+
  Seek #fl, 22
  iw.canali = Read #fl As Short
+
  iw.canali = Read #fl As Short
 
   
 
   
 
  <FONT Color=gray>' ''Legge la frequenza di campionamento dei dati audio al byte d'indice (offset) 24:''</font>
 
  <FONT Color=gray>' ''Legge la frequenza di campionamento dei dati audio al byte d'indice (offset) 24:''</font>
  Seek #fl, 24
+
  Seek #fl, 24
  iw.frequenza = Read #fl As Integer
+
  iw.frequenza = Read #fl As Integer
 
   
 
   
 
  <FONT Color=gray>' ''Legge il valore del "block align" al byte d'indice (offset) 32:''</font>
 
  <FONT Color=gray>' ''Legge il valore del "block align" al byte d'indice (offset) 32:''</font>
  Seek #fl, 32  
+
  Seek #fl, 32  
  iw.block_align = Read #fl As Short
+
  iw.block_align = Read #fl As Short
 
   
 
   
 
  <FONT Color=gray>' ''Legge la risoluzione bit del campionamento al byte d'indice (offset) 34:''</font>
 
  <FONT Color=gray>' ''Legge la risoluzione bit del campionamento al byte d'indice (offset) 34:''</font>
  Seek #fl, 34  
+
  Seek #fl, 34  
  iw.bit = Read #fl As Short
+
  iw.bit = Read #fl As Short
 
   
 
   
 
  <FONT Color=gray>' ''Calcola la durata dell'esecuzione del file wav:''</font>
 
  <FONT Color=gray>' ''Calcola la durata dell'esecuzione del file wav:''</font>
  iw.durata = (iw.sonora.Count / iw.block_align) / iw.frequenza
+
  iw.durata = (Lof(fl) / iw.block_align) / iw.frequenza
 
   
 
   
  fl.Close
+
  fl.Close
 
   
 
   
  '''End'''
+
  End
  
  
 
====Usando la funzione ''Seek''====
 
====Usando la funzione ''Seek''====
 
Potremo anche più semplicemente spostarci all'interno del flusso mediante la funzione ''Seek'':
 
Potremo anche più semplicemente spostarci all'interno del flusso mediante la funzione ''Seek'':
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim fileWAV As String
+
  Dim fileWAV As String
  Dim fl As File
+
  Dim fl As File
  Dim formato, canali, risoluzione As Byte
+
  Dim formato, canali, risoluzione As Byte
  Dim d As Short
+
  Dim d As Short
  Dim frequenza, dimensione As Integer
+
  Dim frequenza, dimensione As Integer
 
 
 
   
 
   
   fileWAV = "''/percorso/del/file.wav''"
+
   fileWAV = "<FONT color=darkgreen>''/percorso/del/file.wav''</font>"
 
   
 
   
 
   d = Instr(File.Load(fileWAV), "data")
 
   d = Instr(File.Load(fileWAV), "data")
Riga 391: Riga 396:
 
   Read #fl, canali
 
   Read #fl, canali
 
   Print "Numero canali = "; canali
 
   Print "Numero canali = "; canali
 
 
   
 
   
 
  <FONT color=gray>' ''Rileva la frequenza di campionamento (legge 4 byte):''</font>
 
  <FONT color=gray>' ''Rileva la frequenza di campionamento (legge 4 byte):''</font>
Riga 397: Riga 401:
 
   Read #fl, frequenza
 
   Read #fl, frequenza
 
   Print "Frequenza = hrz "; frequenza
 
   Print "Frequenza = hrz "; frequenza
+
 
 
 
  <FONT color=gray>' ''Rileva la risoluzione del campionamento (legge 2 byte):''</font>
 
  <FONT color=gray>' ''Rileva la risoluzione del campionamento (legge 2 byte):''</font>
 
   Seek #fl, 34
 
   Seek #fl, 34
 
   Read #fl, risoluzione
 
   Read #fl, risoluzione
 
   Print "Risoluzione = "; risoluzione; " bit"
 
   Print "Risoluzione = "; risoluzione; " bit"
+
 
 
 
  <FONT color=gray>' ''Rileva la quantità dei soli dati grezzi (legge 4 byte):''</font>
 
  <FONT color=gray>' ''Rileva la quantità dei soli dati grezzi (legge 4 byte):''</font>
 
   seek #fl, d + 3
 
   seek #fl, d + 3
 
   Read #fl, dimensione
 
   Read #fl, dimensione
 
   Print "Quantità dei soli dati grezzi = "; dimensione; " byte"
 
   Print "Quantità dei soli dati grezzi = "; dimensione; " byte"
+
 
 
 
  <FONT color=gray>' ''Calcola la durata del brano audio:''</font>
 
  <FONT color=gray>' ''Calcola la durata del brano audio:''</font>
   Print "Durata del brano: "; Date(0, 0, 0, 0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)
+
   Print "Durata del brano: "; Time(0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)
+
 
 
 
   fl.Close
 
   fl.Close
 
   
 
   
  '''End'''
+
  End
  
  
 
==Estrazione delle informazioni da un file wav contenente testo nel proprio header==
 
==Estrazione delle informazioni da un file wav contenente testo nel proprio header==
Talvolta, seppur raramente, i file wav possono contenere delle informazioni aggiuntive in formato testuale poste all'interno del proprio header.
+
Talvolta, seppur raramente, i file wav possono contenere delle informazioni aggiuntive in formato testuale poste all'interno del proprio header, il quale pertanto risulterà complessivamente essere formato da una quantità di byte superiore a quella ordinaria di 44 byte.
 
<BR>Ciò determina che i riferimenti e, dunque, calcoli esposti nei paragrafi precedenti risultino non più utili.
 
<BR>Ciò determina che i riferimenti e, dunque, calcoli esposti nei paragrafi precedenti risultino non più utili.
<BR>Per individuare i nuovi riferimenti di indice, va considerato che le suddette eventuali informazioni testuali sono poste appena prima del tag "data". Pertanto si potrà fare riferimento di partenza dalla stringa "fmt ", individuata nel file wav dai seguenti valori: 66 6D 74 20.
+
<BR>Per individuare i nuovi riferimenti di indice, va considerato che le suddette eventuali informazioni testuali sono poste tra l'ultimo valore a 16 bit del file wav, che fornisce l'informazione del "''bit per campione''" (risoluzione del campionamento) e che è posto all'indice di offset 34, e il tag "data".
 +
<BR>Pertanto, tale eventuale presenza testuale non pregiudica la consueta e agevole estrazione dei dati attinenti alle caratteristiche del file wav in esame.  
  
Mostriamo un esempio commentato:
 
 
   
 
   
 
 
=Estrazione delle informazioni con le funzioni esterne del API di SOX=
 
=Estrazione delle informazioni con le funzioni esterne del API di SOX=
 
La libreria '''''[http://sox.sourceforge.net/ 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.
 
La libreria '''''[http://sox.sourceforge.net/ 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.
Riga 447: Riga 446:
 
  End Struct
 
  End Struct
 
   
 
   
  Public''' Struct sox_format_t
+
  Public Struct sox_format_t
 
   filename As Pointer
 
   filename As Pointer
 
   signal As Struct Sox_signalinfo_t
 
   signal As Struct Sox_signalinfo_t
Riga 462: Riga 461:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim err As Integer
 
   Dim err As Integer
 
   Dim fileWAV As String
 
   Dim fileWAV As String
 
+
   fileWAV = "<FONT color=gray>''/percorso/del/file.wav''</font>"
+
   fileWAV = "<FONT color=darkgreen>''/percorso/del/file.wav''</font>"
 
   
 
   
 
   err = sox_init()
 
   err = sox_init()
Riga 482: Riga 481:
 
   End With
 
   End With
 
   
 
   
  '''End'''
+
  End
  
  
Riga 488: Riga 487:
 
=Note=
 
=Note=
 
[1] [http://it.wikipedia.org/wiki/Ordine_dei_byte Ordine dei byte]
 
[1] [http://it.wikipedia.org/wiki/Ordine_dei_byte Ordine dei byte]
 +
 +
[2] Vedi anche la seguente pagina: [[Calcolare la durata di un file audio WAV]]
  
  
Riga 500: Riga 501:
 
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd757712(v=vs.85).aspx
 
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd757712(v=vs.85).aspx
 
* https://blogs.msdn.microsoft.com/dawate/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format/
 
* https://blogs.msdn.microsoft.com/dawate/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format/
* http:&#047;/i.stack.imgur.com/ITplE.gif
 
 
* http://www.digitalpreservation.gov/formats/fdd/fdd000001.shtml
 
* http://www.digitalpreservation.gov/formats/fdd/fdd000001.shtml
 
* http://unusedino.de/ec64/technical/formats/wav.html
 
* http://unusedino.de/ec64/technical/formats/wav.html
* http://www-mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html
+
* http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
 
* http://sharkysoft.com/archive/lava/docs/javadocs/lava/riff/wave/doc-files/riffwave-frameset.htm
 
* http://sharkysoft.com/archive/lava/docs/javadocs/lava/riff/wave/doc-files/riffwave-frameset.htm
 
* http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html
 
* http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html
 
* http://www.lightlink.com/tjweber/StripWav/Canon.html
 
* http://www.lightlink.com/tjweber/StripWav/Canon.html
 
* http://paulbourke.net/dataformats/audio/
 
* http://paulbourke.net/dataformats/audio/
* http://www.neurophys.wisc.edu/auditory/riff-format.txt
 
 
* https://tecnologiamusicale.wordpress.com/2012/08/19/il-formato-wave-dei-file-audio/
 
* https://tecnologiamusicale.wordpress.com/2012/08/19/il-formato-wave-dei-file-audio/
 +
* [http://i.stack.imgur.com/ITplE.gif Formato WAV]

Versione attuale delle 13:50, 18 giu 2024

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.

Wav.png


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. [Nota 1]

Formato audio

Le informazioni relative al formato audio sono contenute in little-endian nel 21° e nel 22° byte (indice offset: 20, 21).

Numero di canali

Le informazioni relative al numero di canali del file WAV sono contenute in little-endian nel 23° e 24° byte (indice offset: 22, 23).

Frequenza di campionamento

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

ByteRate

Le informazioni relative al ByteRate sono contenute in Little-Endian nel 29°, 30, 31° e 32° byte (indice offset: 28, 29, 30 e 31).

block align

Il Block Align rappresenta la quantità di byte che costituisce un campione audio significativo.
Esso è un valore di tipo Short in Little-Endian, posto al byte d'indice offset n. 32, ed è dato anche dalla seguente formula:

Block_Align = (Risoluzione_del_campionamento_in_bit / 8-bit) * Canali

Risoluzione del campionamento

La risoluzione del campionamento audio è espresso in bit per un campione audio e rappresenta la gamma di valori che detto campione audio può assumere. Una gamma più ampia conferisce ovviamente un campionamento più dinamico e ricco.

Le informazioni relative alla risoluzione in bit del campionamento del file WAV sono contenute in little-endian nel 35° e 36° byte (indice offset: 34 - 35).

Un'altra modalità, per ottenere il valore della risoluzione in bit, è - conoscendo la durata dell'esecuzione audio del file - effettuare il seguente calcolo:

bit = ((quantità_dati_audio_del_file * 8) / durata_in_secondi) / (frequenza_di_campionamento * numero_canali_audio)

La lunghezza del file

Il 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 di byte costituenti il blocco d'intestazione del file wav, solitamente 44 byte, che formano il primo sotto-blocco informativo del file.

Numero dei campioni (samples)

Il numero di campioni si ottiene con la seguente formula:

campioni = dimensione_dei_dati_grezzi_in_byte / block_align

Overall BitRate

Per ottenere il valore del Overall BitRate, bisogna moltiplicare la frequenza di campionamento per la risoluzione in bit per il numero dei canali:

Overall BitRate = frequenza * ris_bit * canali

Ottenere la durata del file wav

Per ottenere la durata dei dati audio wav [Nota 2], si possono adottare due modalità di calcolo:

La prima modalità prevede la seguente formula:

durata = (dimensione_dei_dati_grezzi_in_byte * 8) / (frequenza * ris_bit * canali)

La seconda modalità prevede la seguente formula:

durata = (dimensione_dei_dati_grezzi_in_byte / block_align) / frequenza


Esempi pratici

Per estrarre le suddette informazioni, potremo, dunque, realizzare alcuni codici come quelli che seguono.

Assegnando i dati letti dall'Header del file wav ai membri di un'apposita Struttura

In questo esempio assegneremo i dati letti dall'Header del file wav ai membri di un'apposita "Struttura":

Public Struct Header_Wav
  riff As String          ' tipo file "RIFF"
  lung_rest As Integer    ' lunghezza del resto del file = dimensione restante dell'header (36 byte) + lunghezza dei dati audio grezzi
  wave As String          ' sottotipo file "wav"
  fmt As String           ' inizio blocco "fmt " del file
  lungh_fmt As Integer    ' lunghezza del blocco "fmt"
  pcm As Short            ' formato MS PCM
  canali As Short         ' canali audio di ucita (mono = 1, stereo = 2)
  frequenza As Integer    ' frequenza di campionamento per secondo
  byte_rate As Integer    ' byte per secondo = frequenza * byte_campione
  byte_campione As Short  ' block align (byte per campione) = canali * bit_per_campione / 8
  bit_campione As Short   ' bit per campione (risoluzione del campionamento) = 8, 16 o 24
  data As String          ' "data"
  lungh_dati As Integer   ' lunghezza dei dati audio grezzi
End Struct


Public Sub Main()

  Dim fileWAV As String
  Dim wav As File
  Dim hw As New Header_Wav
 
  fileWAV = "/percorso/del/file.wav"
 
  wav = Open fileWAV For Read
   
' Leggiamo ed assegnamo alla Struttura tutte le informazioni presenti nell'Header del file wav:
  With hw
    .riff = legge_stringa(wav)
    .lung_rest = legge_intero(wav)
    .wave = legge_stringa(wav)
    .fmt = legge_stringa(wav)
    .lungh_fmt = legge_intero(wav)
    .pcm = legge_corto(wav)
    .canali = legge_corto(wav)
    .frequenza = legge_intero(wav)
    .byte_rate = legge_intero(wav)
    .byte_campione = legge_corto(wav)
    .bit_campione = legge_corto(wav)
    .data = legge_stringa(wav)
    .lungh_dati = legge_intero(wav)
  End With

  wav.Close
        
End


Private Function legge_stringa(fl As File) As String

  Dim s As String
 
  Read #fl, s, 4

  Return s

End


Private Function legge_intero(fl As File) As Integer

  Dim i As Integer
 
  Read #fl, i

  Return i

End


Private Function legge_corto(fl As File) As Short

  Dim sh As Short
 
  Read #fl, sh

  Return sh

End


Leggendo e gestendo il file WAV come stringa

In questo caso leggeremo e gestiremo l'intero file WAV come una stringa.

Public Sub Main()
 
  Dim per, s, dati_grezzi As String
  Dim d, i, campionamento, formato, durata As Integer
  Dim canali, bit As Short
  
' Estrae alcune informazioni sul file:

  per = "/percorso/del/file.wav"
  Print "Percorso del file audio:    "; per
  
' Legge e carica nella variabile di tipo Stringa "s" tutti i byte del file audio WAV:
  s = File.Load(per)
  Print "Dimensione del file:        "; Len(s); " byte"
  
  d = InStr(s, "data", 0, gb.Binary)
  i = Int@(s[d + 3])
  Print "Totale dei soli byte audio: "; i; " byte"
  
  d = InStr(s, "fmt ", 0, gb.Binary)
  canali = Short@(s[d + 9])
  Print "Numero canali audio:        "; canali
  
  campionamento = Int@(s[d + 11])
  Print "Frequenza di campionamento: "; campionamento; " hertz"
  
  bit = Short@(s[d + 21])
  Print "Profondità campionamento:   "; bit; " bit"
  
  durata = (i * 8) / (campionamento * bit * canali)
  Print "Durata del brano audio:     "; CStr(Time(0, 0, 0, durata * 1000))
  
' Raccoglie i soli byte dei dati audio grezzi:
  dati_grezzi = Right(s, i)
  
End


Usando una variabile vettoriale di tipo Byte[] - 1

Potremo utilizzare un vettore di tipo Byte[] per contenere i dati del file wav:

Public Sub Main()

  Dim percorsoFile As String
  Dim fl As File
  Dim j, b, formato, canali, risoluzione As Byte
  Dim buf As New Byte[]
  Dim frequenza, dimensione As Integer
 
  percorsoFile = "/percorso/del/file.wav"

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

  Print "== Caratteristiche del file: "; File.Name(percorsoFile); " ==\n"

' Rileva il formato audio (legge 2 byte):
  formato = buf[21] * CInt(2 ^ 8)
  formato = formato Or buf[20]
  If formato = 1 Then
    Print "Formato audio = PCM"
  Else
    Print "Formato audio = "; formato
  Endif


' 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"

' Calcola la durata del brano audio:
  Print "Durata del brano: "; Time(0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)

  fl.Close

End


Usando una variabile vettoriale di tipo Byte[] - 2

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[]
 Dim solo_dati, frequenza As Integer

 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"
 
 solo_dati = Stat(percorsoFile).Size - 44
 Print "Dimensione dei soli dati audio grezzi: "; solo_dati; " byte"
 
 If bb[20] = 1 Then 
   Print "Formato audio: PCM"
 Else
   Print "Formato audio: "; bb[20]
 Endif
 
 Print "Canali di uscita audio: "; bb[22]
 
 frequenza = Val("&" & Hex(bb[27]) & Hex(bb[26]) & Hex(bb[25]) & Hex(bb[24]))
 Print "Frequenza di campionamento: Hz "; frequenza
 
 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"

 Print "Durata del brano: "; Time(0, 0, 0, Fix((solo_dati * 8) / (frequenza * bb[34] * bb[22])) * 1000)


 fl.Close
  
End


Usando una variabile vettoriale di tipo Byte[] - 3

In questo esempio vengono caricati in un'apposita Struttura alcuni dati del file Wav: numero canali, frequenza di campionamento, risoluzione, block align (quest'ultimo sarà utile per ottenere la durata del brano audio). Tali dati verranno poi mostrati in console ed utilizzati alcuni per calcolare la durata di esecuzione del file Wav:

Public Struct INFOWAV
  fileWAV As String      ' Percorso del file wav
  canali As Short        ' Numero dei canali
  frequenza As Integer   ' Frequenza di campionamento
  bit As Short           ' Risoluzione di campionamento in bit
  block_align As Short   ' Block Align
  durata As Float        ' Durata di esecuzione del file wav
End Struct


Public Sub Main()

  Dim fileWav As String
  Dim datiwav As New INFOWAV
  
  datiwav.fileWav = "/percorso/del/file.wav"
  
  EstraeDatiAudio(datiwav)
  
' Mostra in console le informazioni ottenute:
  With datiwav
    Print "File wav caricato:            "; .fileWAV
    Print "Numero canali:                "; .canali
    Print "Frequenza di campionamento: hz"; .frequenza
    Print "Risoluzione:                  "; .bit; " bit"
    Print "Durata esecuzione:            "; CStr(Time(0, 0, 0, .durata * 1000))
  End With

End


Private Function EstraeDatiAudio(iw As INFOWAV)

 Dim fl As File
 
' Carica il file audio Wav:
 fl = Open iw.fileWAV For Read

' Legge il numero dei canali al byte d'indice (offset) 22:
 Seek #fl, 22
 iw.canali = Read #fl As Short

' Legge la frequenza di campionamento dei dati audio al byte d'indice (offset) 24:
 Seek #fl, 24
 iw.frequenza = Read #fl As Integer

' Legge il valore del "block align" al byte d'indice (offset) 32:
 Seek #fl, 32 
 iw.block_align = Read #fl As Short

' Legge la risoluzione bit del campionamento al byte d'indice (offset) 34:
 Seek #fl, 34 
 iw.bit = Read #fl As Short

' Calcola la durata dell'esecuzione del file wav:
 iw.durata = (Lof(fl) / iw.block_align) / iw.frequenza

 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 formato, 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


  Print "== Caratteristiche del file: "; File.Name(fileWAV); " ==\n"

' Rileva il formato audio (legge 2 byte):
  Seek #fl, 20
  Read #fl, formato
  If formato = 1 Then
    Print "Formato audio = PCM"
  Else
    Print "Formato audio = "; formato
  Endif 
  
' 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"
 
' Calcola la durata del brano audio:
  Print "Durata del brano: "; Time(0, 0, 0, Fix((dimensione * 8) / (frequenza * risoluzione * canali)) * 1000)
 
  fl.Close

End


Estrazione delle informazioni da un file wav contenente testo nel proprio header

Talvolta, seppur raramente, i file wav possono contenere delle informazioni aggiuntive in formato testuale poste all'interno del proprio header, il quale pertanto risulterà complessivamente essere formato da una quantità di byte superiore a quella ordinaria di 44 byte.
Ciò determina che i riferimenti e, dunque, calcoli esposti nei paragrafi precedenti risultino non più utili.
Per individuare i nuovi riferimenti di indice, va considerato che le suddette eventuali informazioni testuali sono poste tra l'ultimo valore a 16 bit del file wav, che fornisce l'informazione del "bit per campione" (risoluzione del campionamento) e che è posto all'indice di offset 34, e il tag "data".
Pertanto, tale eventuale presenza testuale non pregiudica la consueta e agevole estrazione dei dati attinenti alle caratteristiche del file wav in esame.


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:

Private sfIn As New Sox_format_t


Library "libsox:2.0.1"

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 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

[2] Vedi anche la seguente pagina: Calcolare la durata di un file audio WAV


Riferimenti

Per un ulteriore e dettagliata spiegazione rinviamo ai seguenti siti: