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

Da Gambas-it.org - Wikipedia.

La libreria Libaudiofile consente la lettura e la scrittura di file audio appartenenti ai formati wav, aiff, aifc, snd, au, voc ed altri.

Per poter fruire delle risorse della libreria Libaudiofile è necessario aver installata nel proprio sistema le librerie condivise: "libaudiofile.so.1.0.0 " e "libasound.so.2.0.0 "

Di seguito mostriamo due semplici codici per l'esecuzione di un file audio di formato WAV mediante la libreria Libaudiofile e la libreria di Alsa.

Primo esempio

Private Const BUFFERFRAMES As Short = 4096

Library "libaudiofile:1.0.0"

Private Const AF_DEFAULT_TRACK As Integer = 1001
Private Const AF_SAMPFMT_TWOSCOMP As Integer = 401      ' linear two's complement
Private Enum AF_BYTEORDER_BIGENDIAN = 501, AF_BYTEORDER_LITTLEENDIAN

' AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
' Opens a specified audio file and creates a file handle structure
Private Extern afOpenFile(filename As String, mode As String, setup As Pointer) As Pointer

' int afGetChannels (AFfilehandle, int track)
' Gets number of channels.
Private Extern afGetChannels(AFfilehandle As Pointer, track As Integer) As Integer

' void afGetSampleFormat (AFfilehandle file, int track, int *sampleFormat, int *sampleWidth)
' Get the sample format for a specified audio track.
Private Extern afGetSampleFormat(AFfilehandle As Pointer, track As Integer, sampleFP As Pointer, sampleWP As Pointer)

' double afGetRate (AFfilehandle, int track)
' Gets sampling rate.
Private Extern afGetRate(AFfilehandle As Pointer, track As Integer) As Float

' int afGetByteOrder (AFfilehandle, int track)
' Gets the byte order for a specified audio track.
Private Extern afGetByteOrder(AFfilehandle As Pointer, track As Integer) As Integer

' AFframecount afGetFrameCount (AFfilehandle file, int track)
' Gets the total sample frame count for a specified audio.
Private Extern afGetFrameCount(AFfilehandle As Pointer, track As Integer) As Long

' int afSetVirtualSampleFormat (AFfilehandle, int track, int sampleFormat, int sampleWidth)
' Set the virtual data format for a track in an audio file
Private Extern afSetVirtualSampleFormat(AFfilehandle As Pointer, track As Integer, sampleFormat As Integer, sampleWidth As Integer) As Integer

' int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount)
' reads sample frames from a given audio track in an audio file.
' Returns the number of frames successfully read from file into the array referred to by samples.
Private Extern afReadFrames(AFfilehandle As Pointer, track As Integer, buf As Pointer, frameCount As Integer) As Integer

' int afCloseFile (AFfilehandle file)
' Closes an open audio file.
Private Extern afCloseFile(AFfilehandle As Pointer) As Integer


Library "libasound:2.0.0"

Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0
Private Const SND_PCM_FORMAT_S16 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_recover (snd_pcm_t * pcm, int err, int silent)
' Recover the stream state from an error or suspend.
Private Extern snd_pcm_recover(pcm As Pointer, errorI As Integer, silent As Integer) As Integer

' 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_close (snd_pcm_t *pcm)
' Close PCM handle
Private Extern snd_pcm_close(pcm As Pointer) As Integer


Public Sub Main()

 Dim afOF, AF_NULL_FILESETUP, handle As Pointer
 Dim percorsoFile As String
 Dim canali,  sfp, swp, frequenza, err, ordo As Integer
 Dim frameLetti, frameScritti, somma_scritti As Integer
 Dim durata As Long
 Dim buffer As Short[]
 
 percorsoFile = "/percorso/del/file.wav"
 
' Parte AudioFile:
 afOF = afOpenFile(percorsoFile, "r", AF_NULL_FILESETUP)
 If afOF == 0 Then Error.Raise("Impossibile aprire il file !")
   
' Estrae alcune informazioni generali sul file audio:
 canali = afGetChannels(afOF, AF_DEFAULT_TRACK)
 afGetSampleFormat(afOF, AF_DEFAULT_TRACK, VarPtr(sfp), VarPtr(swp))
 frequenza = afGetRate(afOF, AF_DEFAULT_TRACK)
 durata = afGetFrameCount(afOf, AF_DEFAULT_TRACK)
 ordo = afGetByteOrder(afOf, AF_DEFAULT_TRACK)
 Print "File audio wav:             "; percorsoFile
 Print "Dimensione:                 "; Stat(percorsoFile).Size; " byte"
 Print "Ordine dei byte dei dati:   "; IIf(ordo = AF_BYTEORDER_BIGENDIAN, "Big-Endian", "Little-Endian")
 Print "Canali audio di uscita:     "; canali
 Print "Risoluzione audio           "; swp; " bit"
 Print "Frequenza di campionamento: "; frequenza; " hertz"
 Print "Durata:                     "; CStr(Time(0, 0, 0, (durata / frequenza) * 1000))
 Print

 afSetVirtualSampleFormat(afOF, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16)
   
' Parte Alsa:
 err = snd_pcm_open(VarPtr(handle), "default", SND_PCM_STREAM_PLAYBACK, 0)
 If err < 0 Then Error.Raise("Impossibile inizializzare la libreria Alsa !")
   
 err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, canali, frequenza, 1, 500000)
 If err < 0 Then Error.Raise("Impossibile impostare i parametri audio alla libreria Alsa !")
   
 buffer = New Short[BUFFERFRAMES * canali]

' Ciclo per eseguire il file wav:
 While True
   frameLetti = afReadFrames(afOF, AF_DEFAULT_TRACK, buffer.Data, BUFFERFRAMES)
   If frameLetti <= 0 Then Break
     
' Scrive i dati audio nel sub-sistema PCM di Alsa:
   frameScritti = snd_pcm_writei(handle, buffer.Data, BUFFERFRAMES)
   If frameScritti < 0 Then
     frameScritti = snd_pcm_recover(handle, frameScritti, 0)
     Error.Raise("Impossibile scrivere dati nel dispositivo di uscita di Alsa !")
   Endif

   somma_scritti += frameScritti
   Write "\r" & Time(0, 0, 0, (somma_scritti / frequenza) * 1000)
 Wend
     
' Va in chiusura:
 snd_pcm_drain(handle)
 snd_pcm_close(handle)
 buffer.Clear()
 afCloseFile(afOF)

End


Secondo esempio

Private Const BUFFERFRAMES As Short = 4096

Library "libaudiofile:1.0.0"

Private Const AF_DEFAULT_TRACK As Integer = 1001
 
' AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
' Opens a specified audio file and creates a file handle structure
Private Extern afOpenFile(filename As String, mode As String, setup As Pointer) As Pointer

' AFframecount afGetFrameCount (AFfilehandle file, int track)
' Get the total sample frame count.
Private Extern afGetFrameCount(AFfilehandle As Pointer, track As Integer) As Long

' float afGetFrameSize (AFfilehandle, int track, int expand3to4)
' Calculate the frame size in bytes for an audio track.
Private Extern afGetFrameSize(AFfilehandle As Pointer, track As Integer, expand3to4 As Integer) As Single

' void afGetSampleFormat (AFfilehandle file, int track, int *sampleFormat, int *sampleWidth)
' Get the sample format for a specified audio track.
Private Extern afGetSampleFormat(AFfilehandle As Pointer, track As Integer, sampleFP As Pointer, sampleWP As Pointer)

' int afGetChannels (AFfilehandle, int track)
' Gets number of channels.
Private Extern afGetChannels(AFfilehandle As Pointer, track As Integer) As Integer

' double afGetRate (AFfilehandle, int track)
' Gets sampling rate.
Private Extern afGetRate(AFfilehandle As Pointer, track As Integer) As Float
 
' int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount)
' reads sample frames from a given audio track in an audio file.
' Returns the number of frames successfully read from file into the array referred to by samples.
Private Extern afReadFrames(AFfilehandle As Pointer, track As Integer, buf As Pointer, frameCount As Integer) As Integer

' int afCloseFile (AFfilehandle file)
' Closes an open audio file.
Private Extern afCloseFile(AFfilehandle As Pointer) As Integer


Library "libasound:2.0.0"

Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0
Private Const SND_PCM_FORMAT_S16 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_recover (snd_pcm_t * pcm, int err, int silent)
' Recover the stream state from an error or suspend.
Private Extern snd_pcm_recover(pcm As Pointer, errorI As Integer, silent As Integer) As Integer

' 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_close (snd_pcm_t *pcm)
' Close PCM handle
Private Extern snd_pcm_close(pcm As Pointer) As Integer


Public Sub Main()

 Dim afOF, sFP, sWP, handle As Pointer
 Dim percorsoFile As String
 Dim frameCount As Long
 Dim canali, sampleFormat, sampleWidth, frequenza As Integer
 Dim err, frameLetti, frameScritti, somma_scritti As Integer
 Dim frameSize As Single
 Dim buffer As Short[]
 
 percorsoFile = "/percorso/del/file.wav"
 
' Parte AudioFile:
 afOF = afOpenFile(percorsoFile, "r", Null)
 If afOF == 0 Then Error.Raise("Impossibile aprire il file !")
   
' Estrae informazioni generali sul file audio:
 frameCount = afGetFrameCount(afOF, AF_DEFAULT_TRACK)
 canali = afGetChannels(afOF, AF_DEFAULT_TRACK)
 sFp = VarPtr(sampleFormat)
 sWP = VarPtr(sampleWidth)
 afGetSampleFormat(afOF, AF_DEFAULT_TRACK, sFP, sWP)
 If (Int@(sWP) <> 16) Or (canali > 2) Then Error.Raise("Il file audio deve essere di formato 16-bit monofonico o stereofonico !")
 frequenza = afGetRate(afOF, AF_DEFAULT_TRACK)
 frameSize = afGetFrameSize(afOF, AF_DEFAULT_TRACK, 1)
 Print "File audio: "; percorsoFile
 Print "Numero di frame nel file:       "; frameCount
 Print "Canali audio di uscita:         "; canali
 Print "Formato del campionamento:      "; Int@(sFP)
 Print "Risoluzione del campionamento:  "; Int@(sWP); "-bit"
 Print "Frequenza di campionamento:     "; frequenza; " hertz"
 Print "Dimensione dei soli dati audio: "; frameCount * frameSize; " byte"
 Print "Durata:                         "; CStr(Time(0, 0, 0, (frameCount / frequenza) * 1000))
 Print

 buffer = New Short[frameCount * frameSize]
   
' Parte Alsa:
 err = snd_pcm_open(VarPtr(handle), "default", SND_PCM_STREAM_PLAYBACK, 0)
 If err < 0 Then Error.Raise("Impossibile inizializzare la libreria Alsa !")
   
 err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, canali, frequenza, 1, 500000)
 If err < 0 Then Error.Raise("Impossibile impostare i parametri audio alla libreria Alsa !")

' Ciclo per eseguire il file wav:
 While True
   frameLetti = afReadFrames(afOF, AF_DEFAULT_TRACK, buffer.Data, BUFFERFRAMES)
   If frameLetti <= 0 Then Break
     
' Scrive i dati audio nel sub-sistema PCM di Alsa:
   frameScritti = snd_pcm_writei(handle, buffer.Data, BUFFERFRAMES)
   If frameScritti < 0 Then
     frameScritti = snd_pcm_recover(handle, frameScritti, 0)
     Error.Raise("Impossibile scrivere dati nel dispositivo di uscita di Alsa !")
   Endif

   somma_scritti += frameScritti
   Write "\r" & Time(0, 0, 0, (somma_scritti / frequenza) * 1000)
 Wend
   
' Va in chiusura:
 snd_pcm_drain(handle)
 snd_pcm_close(handle)
 buffer.Clear()
 afCloseFile(afOF)

End


Riferimenti