Ridurre a 8-bit la risoluzione di campionamento di un file audio WAV con le funzioni esterne del API di Sox

Da Gambas-it.org - Wikipedia.

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. Sox consente di eseguire numerosissimi formati di file audio.

Per poter diminuire a 8-bit la risoluzione di campionamento di un file WAV, campionato ad esempio a 16-bit, bisognerà impostare con il valore della Costante SOX_ENCODING_UNSIGNED il membro "->encoding.encoding" della Struttura sox_format_t, relativa ai nuovi dati del nuovo file wav.

E' necessario avere installata nel proprio sistema e richiamare in Gambas la libreria condivisa: "libsox.so.3.0.0 ".

Mostriamo un esempio, nel quale un file di formato WAV a 16-bit, 44100 hertz, viene diminuita a 8-bit la risoluzione di campionamento e a 8000 hertz la frequenza di campionamento:

Library "libsox:3.0.0

Public Struct sox_signalinfo_t
  rate As Float
  channels As Integer
  precision As Integer
  length As Long
  mult As Pointer
End Struct

Public Struct sox_encodinginfo_t
  encoding As Integer
  bits_per_sample As Integer
  compression As Float
  reverse_bytes As Integer
  reverse_nibbles As Integer
  reverse_bits As Integer
  opposite_endian As Integer
End Struct

Public Struct sox_effects_globals_t
  plot As Integer
  global_info As Pointer
End Struct

Public Struct sox_effects_chain_t
  effects As Pointer
  table_size As Integer
  length As Integer
  ibufc As Pointer
  obufc As Pointer
  global_info As Struct Sox_effects_globals_t
  in_enc As Pointer
  out_enc As Pointer
End Struct

Public Struct sox_effect_handler_t
  name As Pointer
  usage As Pointer
  flags As Integer
  sox_effect_handler_getopts As Pointer
  sox_effect_handler_start As Pointer
  sox_effect_handler_flow As Pointer
  sox_effect_handler_drain As Pointer
  sox_effect_handler_stop As Pointer
  sox_effect_handler_kill As Pointer
  priv_size As Long
End Struct
 
Public Struct sox_effect_t
  global_info As Pointer
  in_signal As Struct Sox_signalinfo_t
  out_signal As Struct Sox_signalinfo_t
  in_encoding As Pointer
  out_encoding As Pointer
  handler As Struct Sox_effect_handler_t
  obuf As Pointer
  obeg As Long
  oend As Long
  imin As Long
  clips As Long
  flows As Long
  flow As Long
  priv As Pointer
End Struct
 
Private Enum SOX_EOF = -1, SOX_SUCCESS, SOX_EHDR = 2000, SOX_EFMT, SOX_ENOMEM, SOX_EPERM, SOX_ENOTSUP, SOX_EINVAL
Private Const SOX_ENCODING_UNSIGNED As Integer = 2
Private Const SOX_UNSPEC As Integer = 0
Private Const SOX_EFF_LENGTH As Integer = 8

' int sox_format_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)
' Opens a decoding session for a file. returns the handle for the new session, or null on failure.
Private Extern sox_open_read(path As String, signal As Sox_signalinfo_t, encoding As sox_encodinginfo_t, filetype As String) As Pointer
 
' sox_format_t * sox_open_write(char const *path, sox_signalinfo_t const *signal, sox_encodinginfo_t const *encoding, char const *filetype, sox_oob_t const *oob, sox_bool(*overwrite_permitted)(const char *filename)
' Opens a decoding session for a file. returns the handle for the new session, or null on failure.
Private Extern sox_open_write(path As String, signal As Sox_signalinfo_t, encoding As Sox_encodinginfo_t, filetype As String, oob As Pointer, filename As String) As Pointer

' sox_effects_chain_t * sox_create_effects_chain(sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
' Initializes an effects chain.
Private Extern sox_create_effects_chain(in_enc As Sox_encodinginfo_t, out_enc As Sox_encodinginfo_t) As Sox_effects_chain_t

' sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
' Creates an effect using the given handler.
Private Extern sox_create_effect(eh As Sox_effect_handler_t) As Sox_effect_t

' sox_effect_handler_t const * sox_find_effect(char const * name)
' Finds the effect handler with the given name.
Private Extern sox_find_effect(name As String) As Pointer

' int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
' Applies the command-line options to the effect.
Private Extern sox_effect_options(effp As Sox_effect_t, argc As Integer, argv As Pointer[]) As Integer

' int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
' Adds an effect to the effects chain, returns SOX_SUCCESS if successful. Returns SOX_SUCCESS if successful.
Private Extern sox_add_effect(chain As Sox_effects_chain_t, effp As Sox_effect_t, inS As Sox_signalinfo_t, ouS As Sox_signalinfo_t) As Integer

' int sox_flow_effects(sox_effects_chain_t * chain, sox_flow_effects_callback callback, void * client_data)
' Runs the effects chain, returns SOX_SUCCESS if successful. Returns SOX_SUCCESS if successful.
Private Extern sox_flow_effects(chain As Sox_effects_chain_t, callback As Pointer, client_data As Pointer) As Integer

' void sox_delete_effects_chain(sox_effects_chain_t *ecp)
' Closes an effects chain.
Private Extern sox_delete_effects_chain(chain As Sox_effects_chain_t)

' int sox_close(sox_format_t * ft)
' Closes an encoding or decoding session.
Private Extern sox_close(ft As Pointer) As Integer

' int sox_quit(void)
' Close effects library and unload format handler plugins. Returns SOX_SUCCESS if successful.
Private Extern sox_quit()


Public Sub Main()

 Dim fileAUDIO As String
 Dim err As Integer
 Dim sfIn, sfOut As Pointer
 Dim sigIn, sigOut As New Sox_signalinfo_t
 Dim encoIn, encoOut As New Sox_encodinginfo_t
 Dim chain As Sox_effects_chain_t
 Dim eff As New Sox_effect_t
 Dim argsP As New Pointer[10]
 Dim st As Stream
 Dim s As Short

 fileAUDIO = "/percorso/del/file/audio.wav"

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

 sfIn = sox_open_read(fileAUDIO, Null, Null, Null)
 If sfIn == 0 Then Error.Raise("Impossibile aprire il file audio !")

 sigIn = sfIn + SizeOf(gb.Pointer)
 With sigIn
   Print "File audio \e[31msorgente\e[0m:        ", String@(Pointer@(sfIn))
   Print "Frequenza di campionamento: ", .rate; " hertz"
   Print "Canali:                     ", .channels
   Print "Risoluzione:                ", .precision; " bit"
   Print "Quantità dati audio:        ", .length * .channels; " byte"
   Print "Durata:                     ", Str(Time(0, 0, 0, (((.length * .channels) * 8) / (.rate * .channels * .precision)) * 1000))
 End With

' Sostituisce la necessaria funzione "memcpy()" di C, con le seguenti 5 righe:
 sfOut = Alloc(SizeOf(gb.Byte), 728)
 st = Memory sfOut For Write
 For s = 0 To 727
   Write #st, Byte@(sfIn + CInt(s)) As Byte
 Next
 st.Close

 encoOut = sfOut + (SizeOf(gb.Pointer) * 5)
 With encoOut
   .encoding = SOX_ENCODING_UNSIGNED
   .bits_per_sample = 8
 End With

 sigOut = sfOut + SizeOf(gb.Pointer)
 With sigOut
   .rate = 8000
   .precision = 16
   .length = SOX_UNSPEC
 End With

 Free(sfOut)

' Imposta il "percorso" del nuovo file da creare:
 sfOut = sox_open_write("/percorso/del/nuovo/file/audio.wav", sigOut, encoOut, Null, 0, Null)
 If sfOut == 0 Then Error.Raise("Impossibile aprire il nuovo file audio per la scrittura !")

 encoIn = sfIn + (SizeOf(gb.Pointer) * 5)

 chain = sox_create_effects_chain(encoIn, encoOut)
 
 eff = sox_create_effect(sox_find_effect("input"))
 argsP[0] = sfIn
 err = sox_effect_options(eff, 1, argsP)
 If err <> SOX_SUCCESS Then Error.Raise("Errore nella funzione 'sox_effect_options' !")
 err = sox_add_effect(chain, eff, sigIn, sigIn)
 If err <> SOX_SUCCESS Then Error.Raise("Errore nella funzione 'sox_add_effect' !")
 
 If sigIn.rate <> sigOut.rate Then
   eff = sox_create_effect(sox_find_effect("rate"))
   err = sox_effect_options(eff, 0, Null)
   If err <> SOX_SUCCESS Then Error.Raise("Errore nella funzione 'sox_effect_options' !")  
   eff.handler.flags = eff.handler.flags Or SOX_EFF_LENGTH
   err = sox_add_effect(chain, eff, sigIn, sigOut)
   If err <> SOX_SUCCESS Then Error.Raise("Errore nella funzione 'sox_add_effect' !")
 Endif

 If sigIn.channels <> sigOut.channels Then
   eff = sox_create_effect(sox_find_effect("channels"))
   sox_effect_options(eff, 0, Null)
   sox_add_effect(chain, eff, sigIn, sigOut)
 Endif
 
 eff = sox_create_effect(sox_find_effect("output"))
 argsP[0] = sfOut
 sox_effect_options(eff, 1, argsP)
 sox_add_effect(chain, eff, sigIn, sigOut)

' Esegue i dati audio:
 sox_flow_effects(chain, Null, Null)
 
' Va in chiusura:
 Free(argsP.Data)
 sox_delete_effects_chain(chain)
 sox_close(sfOut)
 sox_close(sfIn)
 sox_quit()

End


Riferimenti