Eseguire un'onda sinusoidale mediante le funzioni esterne del API di PulseAudio

Da Gambas-it.org - Wikipedia.

Con le risorse esterne di PulseAudio è possibile eseguire un'onda sinusoidale.

E' necessario avere installata nel sistema e richiamare in Gambas la libreria condivisa: "libpulse-simple.so.0.1.1".

Private Const FREQUENZA_ONDA As Integer = 440
Private Const CANALI As Byte = 1
Private Const FREQUENZA_CAMPIONAMENTO As Integer = 8000
Private bo As Boolean


Library "libpulse-simple:0.1.1"

Public Struct pa_sample_spec
  format_ As Integer
  rate As Integer
  channels As Byte
End Struct
 
Private Const PA_STREAM_PLAYBACK As Byte = 1
Private Const PA_SAMPLE_FLOAT32LE As Byte = 5  ' 32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0

' pa_simple* pa_simple_new (const char *server, const char *name, pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_buffer_attr *attr, int *error)
' Crea una connessione col server sonoro.
Private Extern pa_simple_new(server$ As String, name As String, direct As Byte, dev As String, stream_name As String, ss As Pa_sample_spec, map As Pointer, attr As Pointer, err As Pointer) As Pointer

' int pa_simple_write (pa_simple *s, const void *data, size_t bytes, int *error)
' Scrive una certa quantità di dati nel server sonoro.
Private Extern pa_simple_write(sP As Pointer, data As Pointer, bytes As Integer, err As Pointer) As Integer

' int pa_simple_drain (pa_simple *s, int *error)
' Attende sino a quando tutti i dati scritti nel server sonoro vengono eseguiti.
Private Extern pa_simple_drain(sP As Pointer, err As Pointer) As Integer

' void pa_simple_free (pa_simple *s)
' Chiude e libera la connessione con il server sonoro. 
Private Extern pa_simple_free(sP As Pointer)


Public Sub Main()

 Dim pss As New Pa_sample_spec
 Dim p As Pointer
 Dim buf As New Single[]
 Dim tmp As Date

' Vengono assegnati ai rispettivi membri della "Struttura" i necessari valori per l'esecuzione dei dati audio:
 With pss
   .format_= PA_SAMPLE_FLOAT32LE
   .rate = FREQUENZA_CAMPIONAMENTO
   .channels = CANALI
 End With
 
' Viene quindi creata una connessione con il server sonoro per il flusso di dati audio da eseguire.
' Riguardo ai parametri impostati nella seguente funzione si precisa che:
' - NUll: viene usato il server sonoro di default;
' - "nome qualsiasi": il nome dell'applicazione;
' - PA_STREAM_PLAYBACK: stabilisce che il flusso sarà in uscita, ossia in esecuzione;
' - Null: viene usato il dispositivo sonoro di default;
' - "testo qualsiasi": una testo descrittivo del flusso dati audio dell'onda sinusoidale;
' - pss: le caratteristiche dei campioni audio del flusso di dati;
' - Null: viene usata la mappatura dei canali di default;
' - Null: vengono usati attributi di bufferizzazione di default;
' - Null: vengono ignorati i codici di errore sollevati.
 p = pa_simple_new(Null, "nome qualsiasi", PA_STREAM_PLAYBACK, Null, "testo qualsiasi", pss, 0, 0, 0)
 If p == 0 Then Error.Raise("Impossible inizializzare la libreria 'Pulseaudio' !")
 
 For i As Integer = 0 To FREQUENZA_CAMPIONAMENTO - 1
   buf.Push(Sin(2 * Pi * FREQUENZA_ONDA / FREQUENZA_CAMPIONAMENTO * i))
   If pss.channels == 2 Then buf.Push(buf[buf.max])
 Next

 tmp = Time

' Viene eseguito un ciclo per la lettura dei dati audio, e per la successiva scrittura nel server sonoro:
 Repeat
' La funzione "pa_simple_write" prevede un Puntatore al buffer contenente i dati da scrivere:
   pa_simple_write(p, buf.Data, buf.Count, 0)
' Mostra il tempo trascorso dall'inizio dell'esecuzione dell'audio:
   Write "\r" & Str(Time(0, 0, 0, DateDiff(tmp, Time, gb.Millisecond)))
   Flush
   Wait 0.1
 Until bo   ' Si esce dal ciclo, quando si sarà premuto il tasto "Invio" della tastiera

 pa_simple_drain(p, 0)
 
' Va in Chiusura:
 Print "\nEsecuzione terminata !"
 pa_simple_free(p)
 Quit

End


Public Sub Application_Read() ' Questo Evento viene sollevato, quando si preme il tasto "Invio" della tastiera

 bo = True

End