Eseguire un file audio usando l'API di SndFile e di Alsa

Da Gambas-it.org - Wikipedia.

SndFile è una libreria, scritta in C, per leggere e scrivere file che contengono suono campionato (come i formati: WAV, AIFF, FLAC e OGG) attraverso una libreria interfaccia standard.

Pertanto, coniugheremo le librerie di SndFile e di Alsa, assegnando a SndFile il compito di leggere ed estrarre i dati del file audio, ed ad Alsa quello di eseguire tali dati audio.
A tal fine è necessario avere installate nel sistema e richiamare in Gambas le libreria condivise: "libsndfile.so.1.0.31 " e "libasound.so.2.0.0 ".

Mostreremo di seguito un semplice codice per l'esecuzione di un file WAV, AIFF, FLAC oppure OGG:

Library "libsndfile:1.0.31"

Public Struct SF_INFO
  frames As Long
  samplerate As Integer
  channels As Integer  
  format_ As Integer
  sections As Integer
  seekable As Integer
End Struct
 
Private Const BUFFER_LEN As Short = 1024
Private Const SFM_READ As Byte = 16
 
' SNDFILE * sf_open (const char *path, int mode, SF_INFO *sfinfo)
' Open the specified file for read, write or both.
Private Extern sf_open(path As String, mode As Integer, SFinf As SF_INFO) As Pointer

' sf_count_t  sf_read_short(SNDFILE *sndfile, float *ptr, sf_count_t items)
' Read the data chunk in terms of frames (in the native short format).
Private Extern sf_read_short(sndfile As Pointer, ptr As Pointer, items As Integer) As Integer

' int  sf_close  (SNDFILE *sndfile)
' Close the SNDFILE and clean up all memory allocations associated with this file.
Private Extern sf_close(sndfile As Pointer) As Integer
 

Library "libasound:2.0.0"

Private Const SND_PCM_STREAM_PLAYBACK As Byte = 0
Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3
Private Const SND_PCM_FORMAT_U8 As Byte = 1

' int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode)
' Opens a PCM.
Private Extern snd_pcm_open(pcmP As Pointer, nome As String, stream As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message For an Error code.
Private Extern snd_strerror(errnum As Integer) As String

' int snd_pcm_set_params (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency)
' Set the hardware And software parameters In aPrivate Const MPG123_ADD_FLAGS As Byte = 2 simple way.
Private Extern snd_pcm_set_params(pcmP As Pointer, format_ As Byte, access_ As Byte, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer

' snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
' Write interleaved frames to a PCM.
Private Extern snd_pcm_writei(pcmP As Pointer, buffP As Pointer, uframes As Long) As Integer

' int snd_pcm_drain (snd_pcm_t *pcm)
' Stop a PCM preserving pending frames.
Private Extern snd_pcm_drain(pcmP As Pointer) As Integer

' int snd_pcm_close(snd_pcm_t **pcm)
' Close PCM handle.
Private Extern snd_pcm_close(pcmP As Pointer)
 

Public Sub Main()
 
 Dim fileaudio, s As String
 Dim infile, buffer, handle As Pointer
 Dim sfinfo As New SF_INFO
 Dim err, lun, frequenza, frames, canali, somma As Integer
 Dim durata As Single

 fileaudio = "/percorso/del/file/audio"
 s = File.Load(fileaudio)
 lun = Len(s)
 
 buffer = Alloc(SizeOf(gb.Byte), BUFFER_LEN * 4)
 
' Apre il file audio:
 infile = sf_open(fileaudio, SFM_READ, sfinfo)
 If infile == 0 Then Error.Raise("Errore nell'apertura del file audio !")
   
' Ricava la frequenza di campionamento ed il numero di canali del file audio:
 With sfinfo
   frequenza = .samplerate
   canali = .channels
 End With
 
 Print "File audio:    "; fileaudio
 Print "Frequenza:     "; frequenza; " hertz"
 Print "Numero canali: "; canali
 durata = (sfinfo.frames / frequenza)
 If Mid(File.Load(fileaudio), 9, 4) = "WAVE" Then
   Print "Risoluzione:   "; Fix(((lun * 8) / (frequenza * canali)) / durata); " bit"
 Endif
 Print "Campioni:      "; sfinfo.frames
 Print "Durata: "; Time(0, 0, 0, durata * 1000)
 Print
 
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Qui inizia la parte relativa alle funzioni di Alsa:

 err = snd_pcm_open(VarPtr(handle), "default", SND_PCM_STREAM_PLAYBACK, 0)
 If err < 0 Then Error.Raise("Playback open error: " & snd_strerror(err))
 
 err = snd_pcm_set_params(handle, 2, SND_PCM_ACCESS_RW_INTERLEAVED, canali, frequenza, 1, 500000)
 If err < 0 Then Error.Raise("Playback open error: " & snd_strerror(err))
 
' Inizia il ciclo per la scrittura dei dati e per l'esecuzione del file wav:
 Repeat
  
' Legge i dati del file wav e li carica nel buffer:
   lun = sf_read_short(infile, buffer, BUFFER_LEN)
   
' I dati audio vengono inviati al sub-sistema "PCM" di Alsa, attraverso la lettura della variabile
' qui denominata "buffer". La quantità unitaria di dati scritti nell'handle del sub-sistema PCM deve essere uguale
' al valore del 3° argomento della precedente funzione "sf_read_short" diviso il numero di canali del file audio:
   frames = snd_pcm_writei(handle, buffer, BUFFER_LEN / sfinfo.channels)
   If (frames < 0) Then Error.Raise("Errore alla funzione 'snd_pcm_writei': " & snd_strerror(err))
   
   somma += frames
   Write "\r\e[31m" & Str(Time(0, 0, 0, (somma / frequenza) * 1000))
    
 Until lun = 0
   
' Impedisce che al termine l'esecuzione venga troncata inaspettatamente:
 snd_pcm_drain(handle)
  
' Va in chiusura:
 snd_pcm_close(handle)
 sf_close(infile)
 Free(buffer)
 
End


Riferimenti