Generare un'onda sinusoidale con le funzioni esterne della libreria PortAudio
La libreria PortAudio è una libreria per la gestione in tempo reale dei dati audio in entrata ed in uscita. Essa fa parte di un assortimento di API e librerie create per la musica e per altri media.
E' possibile con alcune funzioni esterne della libreria PortAudio generare un'onda sinusoidale. Sarà necessario avere installata nel proprio sistema la libreria condivisa: "libportaudio.so.2.0.0 ".
Mostriamo di seguito un possibile codice (per variare la frequenza dell'onda sinusoidale bisognerà modificare i valori della Costante TABLE_SIZE e delle variabili inc_sin ed inc_des):
Private Const TABLE_SIZE As Short = 440
Private Const SAMPLE_RATE As Integer = 44100
Private Const FRAMES_PER_BUFFER As Integer = 1024
Library "libportaudio:2.0.0"
Public Struct PaStreamParameters
device As Integer
channelCount As Integer
sampleFormat As Long
suggestedLatency As Float
hostApiSpecificStreamInfo As Pointer
End Struct
Private Const paNoError As Integer = 0
Private Const paNoDevice As Integer = -1
Private Const paFloat32 As Integer = 1
Private Const paClipOff As Integer = 1
' PaError Pa_Initialize(void)
' Library initialization function - call this before using PortAudio.
' This function initializes internal data structures and prepares underlying host APIs for use.
Private Extern Pa_Initialize() As Integer
' PaDeviceIndex Pa_GetDefaultOutputDevice( void )
' Retrieve the index of the default output device.
Private Extern Pa_GetDefaultOutputDevice() As Integer
' PaError Pa_OpenStream( PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
' double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData )
' Opens a stream for either input, output or both.
Private Extern Pa_OpenStream(PaStr As Pointer, inPa As PaStreamParameters, outPa As PaStreamParameters, sampleRate As Float, fraPBuf As Long, Flags As Long, Callb As Pointer, Data As Pointer) As Integer
' PaError Pa_StartStream( PaStream *stream )
' Commences audio processing.
Private Extern Pa_StartStream(PaStr As Pointer) As Integer
' PaError Pa_WriteStream( PaStream* stream, const void *buffer, unsigned long frames )
' Write samples to an output stream.
Private Extern Pa_WriteStream(PaStr As Pointer, buff As Single[], frames As Long) As Integer
' PaError Pa_CloseStream( PaStream *stream )
' Closes an audio stream.
Private Extern Pa_CloseStream(PaStr As Pointer) As Integer
' PaError Pa_Terminate( void )
' Library termination function.
Private Extern Pa_Terminate() As Integer
' const char *Pa_GetErrorText(PaError errnum)
' Translates the supplied PortAudio error number into a human readable message.
Private Extern Pa_GetErrorText(errnum As Integer) As String
Public Sub Main()
Dim outputParameters As New PaStreamParameters
Dim PaStream As Pointer
Dim err, fase_sin, fase_des, i, j, k, somma As Integer
Dim buffer As New Single[1024, 2] ' Buffer per Uscita stereo
Dim sinus As New Single[TABLE_SIZE] ' Dati dell'onda sinusoidale
Dim inc_sin As Byte = 4
Dim inc_des As Byte = 4
For i = 0 To TABLE_SIZE - 1
sinus[i] = CSingle(Sin((CFloat(i) / CFloat(TABLE_SIZE)) * Pi * 2.0))
Next
err = Pa_Initialize()
If err < paNoError Then Error.Raise("Impossibile inizializzare la libreria 'PortAudio': " & Pa_GetErrorText(err))
outputParameters.device = Pa_GetDefaultOutputDevice() ' Dispositivo audio prestabilito
If outputParameters.device = paNoDevice Then Error.Raise("Nessun dispositvo audio presente nel sistema !")
outputParameters.channelCount = 2 ' Uscita stereo
outputParameters.sampleFormat = paFloat32
outputParameters.suggestedLatency = 0.050
outputParameters.hostApiSpecificStreamInfo = Null
err = Pa_OpenStream(VarPtr(PaStream), Null, outputParameters, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, 0, 0)
If err < paNoError Then Error.Raise("Impossibile aprire un flusso audio: " & Pa_GetErrorText(err))
err = Pa_StartStream(PaStream)
If err < paNoError Then Error.Raise("Impossibile avviare il processo audio: " & Pa_GetErrorText(err))
For k = 0 To ((10 * SAMPLE_RATE) / FRAMES_PER_BUFFER) - 1
For j = 0 To FRAMES_PER_BUFFER - 1
buffer[j, 1] = sinus[fase_sin] ' Canale sinistro
buffer[j, 0] = sinus[fase_des] ' Canale destro
fase_sin += inc_sin
If fase_sin >= TABLE_SIZE Then fase_sin -= TABLE_SIZE
fase_des += inc_des
If fase_des >= TABLE_SIZE Then fase_des -= TABLE_SIZE
Next
err = Pa_WriteStream(PaStream, buffer, FRAMES_PER_BUFFER)
If err < paNoError Then Error.Raise("Impossibile avviare il processo audio: " & Pa_GetErrorText(err))
' Mostra il tempo trascorso dall'inizio dell'esecuzione dell'onda sonora:
somma += FRAMES_PER_BUFFER
Write "\rTempo trascorso: " & Str(Time(0, 0, 0, (somma / SAMPLE_RATE) * 1000))
Next
' Va in chiusura:
err = Pa_CloseStream(PaStream)
If err < paNoError Then Error.Raise("Impossibile chiudere il flusso audio: " & Pa_GetErrorText(err))
Pa_Terminate()
End
ed una sua leggera variante (anche in questo codice per variare la frequenza prestabilita dell'onda sinusoidale bisognerà modificare i valori della Costante TABLE_SIZE e delle variabili inc_sin ed inc_des):
Private Const TABLE_SIZE As Short = 440
Private Const SAMPLE_RATE As Integer = 44100
Private Const FRAMES_PER_BUFFER As Integer = 1024
Library "libportaudio:2.0.0"
Public Struct PaStreamParameters
device As Integer
channelCount As Integer
sampleFormat As Long
suggestedLatency As Float
hostApiSpecificStreamInfo As Pointer
End Struct
Public Struct PaDeviceInfo
structVersion As Integer
name As Pointer
hostApi As Integer
maxInputChannels As Integer
maxOutputChannels As Integer
defaultLowInputLatency As Float
defaultLowOutputLatency As Float
defaultHighInputLatency As Float
defaultHighOutputLatency As Float
defaultSampleRate As Float
End Struct
Private Const paNoError As Integer = 0
Private Const paNoDevice As Integer = -1
Private Const paFloat32 As Integer = 1
Private Const paClipOff As Integer = 1
' PaError Pa_Initialize(void)
' Library initialization function - call this before using PortAudio.
' This function initializes internal data structures and prepares underlying host APIs for use.
Private Extern Pa_Initialize() As Integer
' PaDeviceIndex Pa_GetDefaultOutputDevice( void )
' Retrieve the index of the default output device.
Private Extern Pa_GetDefaultOutputDevice() As Integer
' const PaDeviceInfo * Pa_GetDeviceInfo(PaDeviceIndex device)
' Retrieve a pointer to a PaDeviceInfo structure containing information about the specified device.
Private Extern Pa_GetDeviceInfo(device As Integer) As PaDeviceInfo
' PaError Pa_OpenStream( PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
' double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData )
' Opens a stream for either input, output or both.
Private Extern Pa_OpenStream(PaStr As Pointer, inPa As PaStreamParameters, outPa As PaStreamParameters, sampleRate As Float, fraPBuf As Long, Flags As Long, Callb As Pointer, Data As Pointer) As Integer
' PaError Pa_StartStream( PaStream *stream )
' Commences audio processing.
Private Extern Pa_StartStream(PaStr As Pointer) As Integer
' PaError Pa_WriteStream( PaStream* stream, const void *buffer, unsigned long frames )
' Write samples to an output stream.
Private Extern Pa_WriteStream(PaStr As Pointer, buff As Single[], frames As Long) As Integer
' PaError Pa_CloseStream( PaStream *stream )
' Closes an audio stream.
Private Extern Pa_CloseStream(PaStr As Pointer) As Integer
' PaError Pa_Terminate( void )
' Library termination function.
Private Extern Pa_Terminate() As Integer
' const char *Pa_GetErrorText(PaError errnum)
' Translates the supplied PortAudio error number into a human readable message.
Private Extern Pa_GetErrorText(errnum As Integer) As String
Public Sub Main()
Dim outputParameters As New PaStreamParameters
Dim pdi As New PaDeviceInfo
Dim PaStream As Pointer
Dim err, fase_sin, fase_des, i, j, k, somma As Integer
Dim buffer As New Single[FRAMES_PER_BUFFER]
Dim sinus As New Single[TABLE_SIZE]
Dim inc_sin As Byte = 4
Dim inc_des As Byte = 4
For i = 0 To TABLE_SIZE - 1
sinus[i] = CSingle(Sin((CFloat(i) / CFloat(TABLE_SIZE)) * Pi * 2.0))
Next
err = Pa_Initialize()
If err < paNoError Then Error.Raise("Impossibile inizializzare la libreria 'PortAudio': " & Pa_GetErrorText(err))
outputParameters.device = Pa_GetDefaultOutputDevice() ' Dispositivo audio prestabilito
If outputParameters.device = paNoDevice Then Error.Raise("Nessun dispositvo audio presente nel sistema !")
outputParameters.channelCount = 2 ' Uscita stereo
outputParameters.sampleFormat = paFloat32
pdi = Pa_GetDeviceInfo(outputParameters.device)
outputParameters.suggestedLatency = pdi.defaultLowOutputLatency
outputParameters.hostApiSpecificStreamInfo = Null
err = Pa_OpenStream(VarPtr(PaStream), Null, outputParameters, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, 0, 0)
If err < paNoError Then Error.Raise("Impossibile aprire un flusso audio: " & Pa_GetErrorText(err))
err = Pa_StartStream(PaStream)
If err < paNoError Then Error.Raise("Impossibile avviare il processo audio: " & Pa_GetErrorText(err))
For k = 0 To ((10 * SAMPLE_RATE) / FRAMES_PER_BUFFER) - 1
For j = 0 To FRAMES_PER_BUFFER - 1 Step 2
buffer[j] = sinus[fase_sin] ' Canale sinistro
buffer[j + 1] = sinus[fase_des] ' Canale destro
fase_sin += inc_sin
If fase_sin >= TABLE_SIZE Then fase_sin -= TABLE_SIZE
fase_des += inc_des
If fase_des >= TABLE_SIZE Then fase_des -= TABLE_SIZE
Next
err = Pa_WriteStream(PaStream, buffer, FRAMES_PER_BUFFER \ 2)
If err < paNoError Then Error.Raise("Impossibile avviare il processo audio: " & Pa_GetErrorText(err))
' Mostra il tempo trascorso dall'inizio dell'esecuzione dell'onda sonora:
somma += (FRAMES_PER_BUFFER \ 2)
Write "\rTempo trascorso: " & Str(Time(0, 0, 0, (somma / SAMPLE_RATE) * 1000))
Next
' Va in chiusura:
err = Pa_CloseStream(PaStream)
If err < paNoError Then Error.Raise("Impossibile chiudere il flusso audio: " & Pa_GetErrorText(err))
Pa_Terminate()
End