Estrarre informazioni generali da un file audio flac

Da Gambas-it.org - Wikipedia.

Il file audio FLAC (Free Lossless Audio Codec è un formato audio simile a MP3, dunque compresso, ma senza perdita di dati, il che significa senza alcuna perdita di qualità.

Il file ha una struttura complessa formata da blocchi e sottoblocchi omogenei di dati. Nel blocco chiamato METADATA_BLOCK_STREAMINFO sono contenute alcune informazioni di carattere generale del file medesimo che possono ovviamente essere estratte. In questa pagina mostreremo come estrarre tali informazioni dei dati da quel blocco, ed in particolare la frequenza di campionamento, il numero di canali, la risoluzione in bit del campionamento e il numero totale dei campioni.

Va preliminarmente detto che tali informazioni sono contenute all'interno di 8 byte successivi e contigui a cominciare dal byte di indice 18 (quindi dal 19° byte del file flac). Ogni informazione è indicata da un certo numero di bit - all'interno di quegli otto byte - fino alla concorrenza di 64 bit totali (8 byte). Esse sono così disposte a cominciare, come s'è detto, dal primo bit del byte di indice 18:

  • i primi 20 bit per memorizzare il valore relativo alla frequenza di campionamento;
  • i successivi 3 bit per indicare il numero di canali (al valore ottenuto va sempre aggiunta un'unità);
  • i successivi 5 bit per indicare la risoluzione in bit del campionamento (al valore ottenuto va sempre aggiunta un'unità);
  • i successivi 36 bit per indicare il numero totale dei frame (campioni audio coerenti).

Quest'ultima informazione è importante per ottenere in rapporto alla frequenza di campionamento la durata, espressa in secondi, dell'audio memorizzato nel file flac, secondo la formula:

durata_in_secondi = numero_totale_frame / frequenza_campionamento

Mostriamo un esempio visivo della disposizione nei 64 bit di ciascuna delle suddette informazioni relative ad un file flac avente frequenza di campionamento a hz 44100, 2 canali, risoluzione 16-bit e numero 431078 frame:

0000101011000100010000101111000000000000010000011100011100000100


Estrarre le informazioni mediante le sole risorse di Gambas

Questa modalità prevede l'estrazione delle predette informazioni relative ai dati del file mediante le sole risorse di Gambas.

Mostriamo un esempio:

Public Sub Main()
 
 Dim fileFlac As String
 Dim fl As File
 Dim i, sposta As Integer
 Dim b, c, canali, bit As Byte
 Dim l, frame_totali, frequenza As Long
 
 fileFlac = "/percorso/del/file.flac"
 Print "File 'Flac':  "; fileFlac
 
 fl = Open fileFlac For Read
 Print "Dimensione:   "; Lof(fl); " byte"  
 
' Calcola la frequenza di campionamento:
 b = SizeOf(gb.Integer)
 Seek #fl, 18
 Repeat
   Read #fl, c
   i = (i * CInt(2 ^ 8)) Or c
   Dec b
 Until b == 0
 frequenza = Shr(i, 12)
 Print "Frequenza:    "; frequenza; " Hertz"
   
' Calcola i canali:
 sposta = Shr(i, 9)
 canali = CByte(sposta And 7) + 1
 Print "Canali:       "; canali
   
' Calcola la risoluzione in bit:
 sposta = Shr(i, 4)
 bit = CByte(sposta And 31) + 1
 Print "Risoluzione:  "; bit; "-bit"
   
' Calcola i frame totali:
 b = 8
 Seek #fl, 18
 Repeat
   Read #fl, c
   l = (l * CInt(2 ^ 8)) Or c
   Dec b
 Until b == 0
 frame_totali = l And CLong(&FFFFFFFFF)
 Print "Frame totali: "; frame_totali
       
' Calcola la durata dell'audio:
 Print "Durata:       "; CStr(Date(0, 0, 0, 0, 0, 0, (frame_totali / frequenza) * 1000))
   
 fl.Close
  
End


Estrarre le informazioni mediante le funzioni esterne di Libflac

In quest'altro caso si farà uso di alcune risorse della specifica libreria dinamica condivisa "libflac.so.8.3.0", che dovrà essere installata nel sistema ed opportunamente richiamata in Gambas.

Mostriamo un esempio pratico, sottolineando che è necessario prevedere, seppur vuote, le tre funzioni di Callback presenti in questo esempio.

Library "libFLAC:8.3.0"

Private Const FLAC__STREAM_DECODER_INIT_STATUS_OK As Integer = 0

' FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
' Create a new stream decoder instance.
Private Extern FLAC__stream_decoder_new() As Pointer

' FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(FLAC__StreamDecoder *decoder, const char *filename, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data)
' Initialize the decoder instance to decode native FLAC files.
Private Extern FLAC__stream_decoder_init_file(decoder As Pointer, filename As String, write_callback As Pointer, metadata_callback As Pointer, error_callback As Pointer, client_data As Pointer) As Integer

' FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
' Decode until the end of the stream.
Private Extern FLAC__stream_decoder_process_until_end_of_stream(decoder As Pointer) As Boolean

' unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
' Get the current sample rate in Hz of the stream being decoded.
Private Extern FLAC__stream_decoder_get_sample_rate(decoder As Pointer) As Integer

' unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
' Get the current number of channels in the stream being decoded.
Private Extern FLAC__stream_decoder_get_channels(decoder As Pointer) As Byte

' unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
' Get the current sample resolution in the stream being decoded.
Private Extern FLAC__stream_decoder_get_bits_per_sample(decoder As Pointer) As Byte

' FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
' Get the total number of samples in the stream being decoded.
Private Extern FLAC__stream_decoder_get_total_samples(decoder As Pointer) As Long

' void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
' Free a decoder instance.
Private Extern FLAC__stream_decoder_delete(decoder As Pointer)


Public Sub Main()

 Dim deco, fout As Pointer
 Dim fileFlac As String
 Dim status, frequenza As Integer
 Dim canali, bit As Byte
 Dim bo As Boolean
 Dim campioni As Long
   
 fileFlac = "/percorso/del/file.flac"
   
 deco = FLAC__stream_decoder_new()
 If deco = 0 Then Error.Raise("Impossibile inizializzare la libreria 'Flac' !")
   
 status = FLAC__stream_decoder_init_file(deco, fileFlac, write_callback, metadata_callback, error_callback, fout)
 If status <> FLAC__STREAM_DECODER_INIT_STATUS_OK Then Error.Raise("Impossibile inizializzare il decodificatore !")
   
 bo = FLAC__stream_decoder_process_until_end_of_stream(deco)
 If bo = False Then Error.Raise("Decodifica fallita !")
   
 frequenza = FLAC__stream_decoder_get_sample_rate(deco)
 Print "Frequenza:       "; frequenza; " Hertz"
 canali = FLAC__stream_decoder_get_channels(deco)
 Print "Numero canali:   "; canali
 bit = FLAC__stream_decoder_get_bits_per_sample(deco)
 Print "Risoluzione:     "; bit; "-bit"
 campioni = FLAC__stream_decoder_get_total_samples(deco)
 Print "Totale Campioni: "; campioni
   
 Print "Durata audio:    "; CStr(Date(0, 0, 0, 0, 0, 0, (campioni / frequenza) * 1000))
   
 FLAC__stream_decoder_delete(deco)
   
End


Private Function write_callback(decoder As Pointer, frame As Pointer, buffer As Pointer, client_data As Pointer)
 
End

Private Function metadata_callback(decoder As Pointer, metadata As Pointer, client_data As Pointer)

End

Private Function error_callback(decoder As Pointer, errori As Integer, client_data As Pointer)
 
End



Riferimenti