Estrarre informazioni generali da un file audio flac
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 sotto-blocchi 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 431078 byte frame audio in questo caso la rappresentazione in bit sarà: 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: "; Time(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.12.1.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:12.1.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" Print "File 'Flac': "; fileFlac 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(Time(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