Eseguire un file audio mediante le funzioni esterne del API di Alsa e SndFile

Da Gambas-it.org - Wikipedia.

Con alcune risorse della libreria libsndfile saranno letti i dati audio dei file appartenenti ai seguenti formati: AIFF, FLAC, OGG e WAV, mentre con la libreria di ALSA si invieranno tali dati alla scheda audio.

E' necessario avere installate nel proprio sistema le seguenti librerie condivise: "libsndfile:1.0.37 " e "libasound:2.0.0 ".

Mostriamo un esempio combinando entrambe le predette librerie esterne:

Library "libsndfile:1.0.37"

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 SFM_READ As Integer = 16

' SNDFILE * sf_open (const char *path, int mode, SF_INFO *sfinfo)
' Apre un file per la lettura.
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)
' Legge i dati del file audio.
Private Extern sf_read_short(sndfile As Pointer, ptr As Pointer, items As Integer) As Integer

' int  sf_close  (SNDFILE *sndfile)
' Chiude il file precedentemente aperto.
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_FORMAT_U8 As Byte = 1
Private Const SND_PCM_FORMAT_S16_LE As Byte = 2
Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3

' 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(pcm 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 canali, unsigned int rate, int soft_resample, unsigned int latency)
' Set the hardware and software parameters in a simple way.
Private Extern snd_pcm_set_params(pcm As Pointer, formatB As Byte, accessB 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(pcm As Pointer, buffer 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(pcm As Pointer) As Integer

' int snd_pcm_drop (snd_pcm_t *pcm)
' Stop a PCM dropping pending frames.
Private Extern snd_pcm_drop(pcm As Pointer) As Integer

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


Public Sub Main()

 Dim file_audio As String 
 Dim sfinfo As New SF_INFO
 Dim err, bit, frames As Integer
 Dim infile, pcm As Pointer
 
 file_audio = "/percorso/del/file/audio"

' Apre il file audio:
 infile = sf_open(file_audio, SFM_READ, sfinfo)

' Si ottengono alcune informazioni del file audio:
 Print "\n== Informazioni sul file audio =="
 Print "Nome:       "; File.Name(file_audio)
 Print "Dimensione: "; Stat(file_audio).Size; " byte"
 Print "Frequenza:  "; sfinfo.samplerate
 Print "Canali:     "; sfinfo.channels
 Print "Durata:     "; Time(0, 0, 0, (sfinfo.frames / sfinfo.samplerate) * 1000)

 err = snd_pcm_open(VarPtr(pcm), "default", SND_PCM_STREAM_PLAYBACK, 0)
 If err < 0 Then Error.Raise("Errore nell'apertura del subsistema PCM: " & snd_strerror(err))

 err = snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, sfinfo.channels, sfinfo.samplerate, 1, 500000)
 If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri audio: " & snd_strerror(err))

 Dim data As New Short[1024]

' ==Inizia il ciclo per la scrittura dei dati e per l'esecuzione del file audio==
' Legge i dati del file audio e li carica nel buffer "data":
 While sf_read_short(infile, data.Data, data.Count) > 0
' Scrive i dati, presenti nel buffer "data", nella variabile "pcm":
   frames = snd_pcm_writei(pcm, data.Data, data.Count / sfinfo.channels)
   If frames < 0 Then
     snd_pcm_drop(pcm)
     Break
   Endif
   Wait 0.01
 Wend

 snd_pcm_drain(pcm)

 Print "Esecuzione terminata"

' Va in chiusura:
 snd_pcm_close(pcm)
 sf_close(infile)

End