Eseguire un file WAV con le funzioni esterne del API di LibAo

Da Gambas-it.org - Wikipedia.

Libao è una libreria multi-piattaforma che permette ai programmi di inviare dati audio PCM ai dispositivi audio nativi su una vasta gamma di piattaforme.

E' necessario avere installata nel sistema e richiamare in Gambas la libreria condivisa: "libao.so.4.1.1 "

Possiamo utilizzare almeno due modalità per eseguire un file WAV.

1a modalità

Library "libao:4.1.1"

Public Struct ao_sample_format
  bits As Integer             ' bits per sample
  rate As Integer             ' samples per second (in a single channel)
  channels As Integer         ' number of audio channels
  byte_format As Integer      ' Byte ordering in sample, see constants below
  matrix As Pointer           ' input channel location/ordering
End Struct

Public Struct ao_info
  type As Integer
  name As Pointer
  short_name As Pointer
  author As Pointer
  comment As Pointer
  preferred_byte_format As Integer
  priority As Integer
  options As Pointer
  option_count As Integer
End Struct

Private Const AO_FMT_LITTLE As Integer = 1
Private Const AO_FMT_BIG As Integer = 2
Private Const AO_FMT_NATIVE As Integer = 4

' void ao_initialize(void)
' Library setup.
Private Extern ao_initialize()

' int ao_default_driver_id(void)
' Driver information.
Private Extern ao_default_driver_id() As Integer

' ao_info *ao_driver_info(int driver_id)
' Get information about a particular driver.
Private Extern ao_driver_info(driver_id As Integer) As Ao_info

' ao_device * ao_open_live(int driver_id, ao_sample_format *format, ao_option *option)
' Open a live playback audio device for output.
Private Extern ao_open_live(driver_id As Integer, ao_format As Ao_sample_format, option As Pointer) As Pointer

' int ao_play(ao_device *device, char *output_samples, uint_32 num_bytes)
' Play a block of audio data to an open device.
Private Extern ao_play(device As Pointer, output_samples As Pointer, num_bytes As Integer) As Integer

' void ao_shutdown(void)
' Unloads all of the plugins and deallocates any internal data structures the library has created.
Private Extern ao_shutdown()
 

Public Sub Main()

 Dim device As Pointer
 Dim ao_sf As New Ao_sample_format
 Dim info As Ao_info
 Dim default_driver, i, err, rbc As Integer
 Dim buffer As Byte[]
 Dim fileWAV, fmt As String
 Dim fl As File
 Dim b As Byte

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

 fl = Open fileWAV For Read
  
' Inizializza la libreria 'libao':
 ao_initialize()
   
' Imposta il driver audio come predefinito:
 default_driver = ao_default_driver_id()
  
' Raccoglie alcune informazioni del dipositivo audio di sistema utilizzato:
 Print "Informazioni sul dispositivo audio utilizzato:"
 info = ao_driver_info(default_driver)
 With info
   Print "Tipo:                   "; IIf(.type = 1, "Live Output", "File output")
   Print "Nome:                   "; String@(.name)
   Print "Abbreviazione:          "; String@(.short_name)
   Print "Realizzatore:           "; String@(.author)
   Print "Commento:               "; String@(.comment)
   Select Case .preferred_byte_format
     Case AO_FMT_LITTLE
       fmt = "little-endian order"
     Case AO_FMT_BIG
       fmt = "big-endian order"
     Case AO_FMT_NATIVE
       fmt = "native ordering of the computer"
   End Select
   Print "Formato byte preferito: "; fmt
   Print "Priorità:               "; .priority
   Print "Opzioni:                ";
   For b = 1 To .option_count
     Print String@(Pointer@(.options + CInt(8 * b))); ", ";
   Next
 End With
 Print "\n____________________________"

' Imposta le caratteristiche del file wav caricato, leggendole da esso:
 With ao_sf
   Seek #fl, 34
   .bits = Read #fl As Short
   Seek #fl, 22
   .channels = Read #fl As Short
   .rate = Read #fl As Integer
   .byte_format = info.preferred_byte_format
' Mostra alcune informazioni generali sul file wav caricato:
  Print "File wav:    "; fileWAV
  Print "Dimensione:  "; Lof(fl); " byte"
  Print "Risoluzione: "; .bits; " bit"
  Print "Canali:      "; .channels
  Print "Frequenza:   "; .rate; " hertz"
  rbc = .rate * .bits * .channels
  Print "Durata:      "; Time(0, 0, 0, ((Lof(fl) * 8) / rbc) * 1000)
  Print
  End With

' Apre il driver:
  device = ao_open_live(default_driver, ao_sf, 0)
  If device == 0 Then Error.Raise("Errore nell'apertura del dispositivo audio !")
   
 buffer = New Byte[Lof(fl)]
      
' Ciclo per l'elaborazione dell'audio:
 For i = 1 To (buffer.Count) / 1024
' Carica i dati audio nel vettore di tipo "Byte[]":
   buffer.Read(fl, 0, 1024)
' Esegue i dati audio:
   err = ao_play(device, buffer.Data, 1024)
   If err < 1 Then Error.Raise("Errore nell'esecuzione dei dati audio !")
   Write #File.out, "\r" & CStr(Time(0, 0, 0, ((Seek(fl) * 8) / rbc) * 1000))
 Next
 
' Va in chiusura:
 fl.Close
 ao_shutdown()

End


2a modalità

La seconda modalità fa uso sia della libreria principale "libao.so.4.1.1", sia della libreria "libalsa.so".

Library "libao:4.1.1"

Public Struct ao_sample_format
  bits As Integer             ' bits per sample
  rate As Integer             ' samples per second (in a single channel)
  channels As Integer         ' number of audio channels
  byte_format As Integer      ' Byte ordering in sample, see constants below
  matrix As Pointer           ' input channel location/ordering
End Struct

Private Const AO_FMT_LITTLE As Integer = 1

' void ao_initialize(void)
' Library setup
Private Extern ao_initialize()

' int ao_default_driver_id(void)
' Driver information
Private Extern ao_default_driver_id() As Integer

' ao_device * ao_open_live(int driver_id, ao_sample_format *format, ao_option *option)
' Driver information
Private Extern ao_open_live(driver_id As Integer, fmt As Ao_sample_format, option As Pointer) As Pointer
  
' void ao_shutdown(void)
' Library teardown
Private Extern ao_shutdown()


Library "/usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa"  ' In alcune distribuzioni Linux questa libreria potrebbe trovarsi nel percorso "/usr/lib/ao/plugins-4/libalsa.so")

' int ao_plugin_test()
' Determine if parameters are requires for this particular plugin.
Private Extern ao_plugin_test() As Integer

' int ao_plugin_device_init(ao_device *device)
' Initialize internal data structures.
Private Extern ao_plugin_device_init(ao_dev As Pointer) As Integer

' int ao_plugin_open(ao_device *device, ao_sample_format *format)
' Prepare the audio device for playback.
Private Extern ao_plugin_open(ao_dev As Pointer, fmt As Ao_sample_format) As Integer

' int ao_plugin_play(ao_device *device, const char *output_samples, uint_32 num_bytes)
' Play num_bytes of audio data.
Private Extern ao_plugin_play(ao_dev As Pointer, output_samples As Pointer, num_bytes As Integer) As Integer

' int ao_plugin_close(ao_device *device)
' Close the audio device.
Private Extern ao_plugin_close(ao_dev As Pointer) As Integer

' void ao_plugin_device_clear(ao_device *device)
' Free the internal data structures.
Private Extern ao_plugin_device_clear(ao_dev As Pointer)


Public Sub Main()

 Dim device As Pointer
 Dim ao_sf As New Ao_sample_format
 Dim default_driver, i, err, rbc As Integer
 Dim buffer As Byte[]
 Dim fileWAV As String
 Dim fl As File

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

 fl = Open fileWAV For Read
  
' Inizializza la libreria 'libao':
 ao_initialize()
   
' Imposta il driver audio come predefinito:
 default_driver = ao_default_driver_id()

' Imposta le caratteristiche del file wav caricato, leggendole da esso:
 With ao_sf
   Seek #fl, 34
   .bits = Read #fl As Short
   Seek #fl, 22
   .channels = Read #fl As Short
   .rate = Read #fl As Integer
   .byte_format = AO_FMT_LITTLE
' Mostra alcune informazioni generali sul file wav caricato:
   Print "File wav:    "; fileWAV
   Print "Dimensione:  "; Lof(fl); " byte"
   Print "Risoluzione: "; .bits; " bit"
   Print "Canali:      "; .channels
   Print "Frequenza:   "; .rate; " hertz"
   rbc = .rate * .bits * .channels
   Print "Durata:      "; Time(0, 0, 0, ((Lof(fl) * 8) / rbc) * 1000)
   Print
 End With
  
 Wait 0.1

' Apre il driver:
 device = ao_open_live(default_driver, ao_sf, 0)
 If device == 0 Then Error.Raise("Errore nell'apertura del dispositivo audio !")

 err = ao_plugin_test()
 If err == 0 Then Error.Raise("Il driver audio ha bisogno che vengano impostate alcune opzioni !")
  
 ao_plugin_device_init(device)
  
 ao_plugin_open(device, ao_sf)

 buffer = New Byte[Lof(fl)]

' Riportiamo il puntatore interno del flusso del file a zero:
 Seek #fl, 0
   
' Ciclo per l'elaborazione dell'audio:
 For i = 1 To (buffer.Count) / 1024
' Carica i dati audio nel vettore di tipo "Byte[]":
   buffer.Read(fl, 0, 1024)
' Esegue i dati audio:
   err = ao_plugin_play(device, buffer.Data, 1024)
   If err < 1 Then Error.Raise("Errore nell'esecuzione dei dati audio !")
   Write #File.out, "\r" & CStr(Time(0, 0, 0, ((Seek(fl) * 8) / rbc) * 1000))
 Next

' Va in chiusura:
 fl.Close
 ao_plugin_close(device)
 ao_plugin_device_clear(device)
 ao_shutdown()

End


Riferimenti