Eseguire un file WAV mediante le funzioni esterne del API di libaudio e di Alsa

Da Gambas-it.org - Wikipedia.

E' possibile eseguire un file formato WAV utilizzando le risorse delle librerie Libaudio ed ALSA. Con le funzioni della libreria Libaudio si provvederà ad aprire e leggere i dati del file audio WAV, mentre con le funzioni della libreria di ALSA si provvederà ad inviare i dati audio letti al sub-sistema PCM.

Per fruire di tali risorse in Gambas bisognerà installare e richiamare le librerie dinamiche e condivise: "libaudio.so.2.4 " e "libasound.so.2.0.0 "

Mostriamo un esempio pratico:

Private Const BUFFER As Integer = 32


Library "libaudio:2.4"

Public Struct WaveInfo
  fp As Pointer
  comment As Pointer
  channels As Short
  bitsPerSample As Short
  sampleRate As Integer
  dataOffset As Integer
  numSamples As Integer
  fileSize As Integer
  dataSize As Integer
  sizeOffset As Integer
  writing As Integer
  formatSh As Short
End Struct

' WaveInfo * WaveOpenFileForReading(const char *name)
' Open an wave file for reading.
Private Extern WaveOpenFileForReading(name As String) As WaveInfo

' int WaveSeekFile(int n, WaveInfo *wi)
' Seek to a position in an wave file.
Private Extern WaveSeekFile(n As Integer, wi As WaveInfo) As Integer

' int WaveReadFile(char *p, int n, WaveInfo *wi)
' Read wave data from an audio file.
Private Extern WaveReadFile(p As Pointer, n As Integer, wi As WaveInfo) As Integer

' int WaveCloseFile(WaveInfo *wi)
' Close an wave file description.
Private Extern WaveCloseFile(wi As WaveInfo) As Integer


Library "libasound:2.0.0"

Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0
Private Const SND_PCM_FORMAT_U8 As Integer = 1
Private Const SND_PCM_FORMAT_S16_LE As Integer = 2
Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Integer = 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, name As String, streamI As Integer, mode As Integer) As Integer

' 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 a simple way.
Private Extern snd_pcm_set_params(pcm As Pointer, formatI As Integer, accessI As Integer, 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, buf As Pointer, size As Integer) 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(pcm As Pointer) As Integer


Public Sub Main()

 Dim buf, handle As Pointer
 Dim fileWav As String
 Dim err, bit, msec, obr, frames, i, n As Integer
 Dim info As New WaveInfo

  fileWav = "/percorso/del/file.wav"

  info = WaveOpenFileForReading(fileWav)
  If IsNull(info) Then Error.Raise("Errore nella lettura del file wav !")
 
  buf = Alloc(SizeOf(gb.Byte), BUFFER)
  If buf = 0 Then Error.Raise("Impossibile allocare memoria !")
  
  Print "File audio:      "; fileWav
  Print "Numero canali:   "; info.channels
  Print "Risoluzione bit: "; info.bitsPerSample; " bit"
  Print "Frequenza camp.: "; info.sampleRate; " Hertz"
  obr = info.channels * info.bitsPerSample * info.sampleRate
  Print "Overall BitRate: "; obr; " bps"
  msec = Fix(((info.dataSize * 8) / obr) * 1000)
  Print "Durata:          "; CStr(Time(0, 0, 0, msec))
  Print

  err = snd_pcm_open(VarPtr(handle), "default", SND_PCM_STREAM_PLAYBACK, 0)
  If err < 0 Then Error.Raise("Impossibile inizializzare la libreria Alsa !")
   
  Select Case info.bitsPerSample
    Case 16
      bit = SND_PCM_FORMAT_S16_LE
    Case 8
      bit = SND_PCM_FORMAT_U8
  End Select
  
  err = snd_pcm_set_params(handle, bit, SND_PCM_ACCESS_RW_INTERLEAVED, info.channels, info.sampleRate, 1, 500000)
  If err < 0 Then Error.Raise("Impossibile impostare i parametri audio alla libreria Alsa !")
   
  i = info.bitsPerSample / (8 / info.channels)
   
  While n < info.dataSize
    
    err = WaveSeekFile(n, info)
    If err Then Error.Raise("Impossibile posizionarsi nel file wav !")
    
    WaveReadFile(buf, BUFFER, info)
    
    frames = snd_pcm_writei(handle, buf, BUFFER / i)
    If frames < 0 Then Error.Raise("Errore nella funzione 'snd_pcm_writei()' !")
    
    n += BUFFER
    
    Write "\rTempo trascorso: " & Time(0, 0, 0, ((n * 8) / obr) * 1000)
       
  Wend

' Impedisce che al termine l'esecuzione venga troncata inaspettatamente:
  snd_pcm_drain(handle)
  
  
' Va in chiusura:
  snd_pcm_close(handle)
  Free(buf)
  WaveCloseFile(info)
  
End



Riferimenti