|
|
(Una versione intermedia di uno stesso utente non è mostrata) |
Riga 1: |
Riga 1: |
− | '''PortAudio''' è una libreria ''open-source'' multipiattaforma per l'ingresso e l'uscita audio in tempo reale. La libreria fornisce funzioni che permettono al software di acquisire e di inviare flussi audio in tempo reale dalle interfacce audio hardware del computer.
| + | #redirect[[Eseguire_un_file_audio_mediante_le_funzioni_esterne_del_API_di_PortAudio_e_SndFile]] |
− | | |
− | Poiché ''PortAudio'' non è progettato per leggere i dati audio utili da un file audio, bisognerà ''appoggiarsi'', per questo, ad un'altra risorsa come, ad esempio, le funzioni della libreria ''SndFile''.
| |
− | | |
− | '''SndFile''' è una libreria, scritta in C, per leggere e scrivere file che contengono suono campionato attraverso una libreria interfaccia standard.
| |
− | | |
− | | |
− | Pertanto, bisognerà coniugare entrambe le librerie, assegnando a ''SndFile'' il compito di leggere ed estrarre i dati del file audio, ed a ''PortAudio'' quello di eseguire tali dati audio.
| |
− | | |
− | | |
− | Mostreremo di seguito un semplice codice per l'esecuzione di un file audio:
| |
− | Public Struct SF_INFO
| |
− | frames As Long
| |
− | samplerate As Integer
| |
− | channels As Integer
| |
− | formatI As Integer
| |
− | sections As Integer
| |
− | seekable As Integer
| |
− | End Struct
| |
− |
| |
− | Public Struct PaStreamParameters
| |
− | device As Integer
| |
− | channelCount As Integer
| |
− | sampleFormat As Long
| |
− | suggestedLatency As Integer
| |
− | 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 Integer
| |
− | defaultLowOutputLatency As Integer
| |
− | defaultHighInputLatency As Integer
| |
− | defaultHighOutputLatency As Integer
| |
− | defaultSampleRate As Integer
| |
− | End Struct
| |
− |
| |
− | Private Const paInt16 As Byte = 8
| |
− | Private Const paClipOff As Byte = 1
| |
− | Private Const FRAMES_PER_BUFFER As Short = 1024
| |
− | Private Const BUFFER_LEN As Short = 8192
| |
− | Private Const SFM_READ As Byte = 16
| |
− | Private Const paNoError As Byte = 0
| |
− | Private PaStream As Pointer
| |
− | Private infile As Pointer
| |
− |
| |
− |
| |
− | Library "libsndfile:1.0.25"
| |
− |
| |
− | <FONT color=gray>' ''SNDFILE * sf_open (const char *path, int mode, SF_INFO *sfinfo)''
| |
− | ' ''Apre un file per la lettura.''</font>
| |
− | Private Extern sf_open(path As String, mode As Integer, SFinf As SF_INFO) As Pointer
| |
− |
| |
− | <FONT color=gray>' ''sf_count_t sf_read_short(SNDFILE *sndfile, float *ptr, sf_count_t items)''
| |
− | ' ''Legge i dati del file audio.''</font>
| |
− | Private Extern sf_read_short(sndfile As Pointer, ptr As Pointer, items As Integer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''int sf_close (SNDFILE *sndfile)''
| |
− | ' ''Chiude il file precedentemente aperto.''</font>
| |
− | Private Extern sf_close(sndfile As Pointer) As Integer
| |
− |
| |
− |
| |
− | Library "libportaudio:2.0.0"
| |
− | <FONT color=gray>' ''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.''</font>
| |
− | Private Extern Pa_Initialize() As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaDeviceIndex Pa_GetDefaultOutputDevice( void ) --> Retrieve the index of the default output device.''</font>
| |
− | Private Extern Pa_GetDefaultOutputDevice() As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )''
| |
− | ' ''Retrieve a pointer to a PaDeviceInfo structure containing information about the specified device.''</font>
| |
− | Private Extern Pa_GetDeviceInfo(device As Integer) As PaDeviceInfo
| |
− |
| |
− | <FONT color=gray>' ''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.''</font>
| |
− | <FONT size=1>Private Extern Pa_OpenStream(Pstream As Pointer, inputParameters As PaStreamParameters, outputParameters As PaStreamParameters, FsampleRate As Float, framesPerBuffer As Long, streamFlags As Byte, streamCallback As Pointer, userData As Pointer) As Integer</font>
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_StartStream( PaStream *stream )''
| |
− | ' ''Commences audio processing.''</font>
| |
− | Private Extern Pa_StartStream(Pstream As Pointer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_WriteStream(PaStream * stream, const void * buffer, unsigned long frames)''</font>
| |
− | Private Extern Pa_WriteStream(Pstream As Pointer, buffer As Pointer, frames As Integer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_CloseStream (PaStream *stream)''
| |
− | ' ''Closes an audio stream.''</font>
| |
− | Private Extern Pa_CloseStream(Pstream As Pointer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_IsStreamStopped (PaStream * stream)''
| |
− | ' ''Returns one (1) when the stream is stopped, zero (0) when the stream is running.''</font>
| |
− | Private Extern Pa_IsStreamStopped(Pstream As Pointer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_Terminate (void)''
| |
− | ' ''Library termination function - call this when finished using PortAudio.''
| |
− | ' ''This function deallocates all resources allocated by PortAudio since it was initialized by a call to Pa_Initialize().''</font>
| |
− | Private Extern Pa_Terminate() As Integer
| |
− |
| |
− | <FONT color=gray>' ''PaError Pa_StopStream (PaStream * stream)''
| |
− | ' ''Terminates audio processing. It waits until all pending audio buffers have been played before it returns.''</font>
| |
− | Private Extern Pa_StopStream(Pstream As Pointer) As Integer
| |
− |
| |
− |
| |
− | '''Public''' Sub Button1_Click()
| |
− |
| |
− | Dim data As Pointer
| |
− | Dim file_audio As String
| |
− | Dim sfinfo As New SF_INFO
| |
− | Dim pasp As New PaStreamParameters
| |
− | Dim padi As New PaDeviceInfo
| |
− | Dim err, frequenza, conto, quantum As Integer
| |
− |
| |
− |
| |
− | <FONT color=gray>' ''Se l'applicativo sta già eseguendo un file audio, esce dalla routine:''</font>
| |
− | If Pa_IsStreamStopped(PaStream) = 0 Then Return
| |
− |
| |
− | <FONT color=darkorange><B>data</b></font> = Alloc(BUFFER_LEN * 4)
| |
− |
| |
− | <FONT color=gray>' ''Inizializza la libreria di "PortAudio":''</font>
| |
− | err = Pa_Initialize()
| |
− | If err <> paNoError Then Error.Raise("Impossibile inizializzare la libreria 'PortAudio' !")
| |
− |
| |
− | file_audio = "<FONT color=gray>''/percorso/del/file/audio''</font>"
| |
− |
| |
− | <FONT color=gray>' ''Apre il file audio:''</font>
| |
− | infile = sf_open(file_audio, SFM_READ, sfinfo)
| |
− |
| |
− | <FONT color=gray>' ''Ricava la frequenza di campionamento del file audio:''</font>
| |
− | frequenza = sfinfo.samplerate
| |
− |
| |
− | <FONT color=gray>' ''Si ricavano alcune informazioni ed impostano alcuni parametri:''</font>
| |
− | Print "\n== Informazioni sul file audio =="
| |
− | Print "Nome: "; File.Name(file_audio)
| |
− | Print "Dimensione: "; Stat(file_audio).Size; " byte"
| |
− | Print "Frequenza: "; frequenza
| |
− | Print "Canali: "; sfinfo.channels
| |
− |
| |
− | With pasp
| |
− | .device = Pa_GetDefaultOutputDevice()
| |
− | .channelCount = sfinfo.channels
| |
− | .sampleFormat = paInt16
| |
− | padi = Pa_GetDeviceInfo(.device)
| |
− | .suggestedLatency = padi.defaultLowOutputLatency
| |
− | .hostApiSpecificStreamInfo = Null
| |
− | End With
| |
− |
| |
− | Print "\n== Informazioni sul dispositivo audio =="
| |
− | With padi
| |
− | Print "Nome del dispositivo: "; String@(.name)
| |
− | Print "Numero massimo Canali in Entrata: "; .maxInputChannels
| |
− | Print "Numero massimo Canali in Uscita: "; .maxOutputChannels
| |
− | Print
| |
− | End With
| |
− |
| |
− | err = Pa_OpenStream(VarPtr(PaStream), Null, pasp, frequenza, FRAMES_PER_BUFFER, paClipOff, Null, Null)
| |
− | If err <> paNoError Then Error.Raise("Impossibile aprire il flusso di dati !")
| |
− |
| |
− | If IsNull(PaStream) = False Then
| |
− |
| |
− | err = Pa_StartStream(PaStream)
| |
− | If err <> paNoError Then Error.Raise("Impossibile avviare il flusso di dati !")
| |
− |
| |
− | conto = 1
| |
− |
| |
− | <FONT color=gray>' ''Inizia il ciclo per la scrittura dei dati e per l'esecuzione del file audio:''</font>
| |
− | While conto > 0
| |
− |
| |
− | <FONT color=gray>' ''Legge i dati del file audio e li carica nel buffer "data". La quantità unitaria di dati, caricati nella variabile "data",''
| |
− | ' ''deve essere uguale alla dimensione della predetta variabile "data" moltiplicato per il numero dei canali del file:''</font>
| |
− | conto = sf_read_short(infile, <FONT color=darkorange><B>data</b></font>, BUFFER_LEN * sfinfo.channels)
| |
− |
| |
− | <FONT color=gray>' ''Scrive i dati, presenti nel buffer "data", nella variabile "PaStream":''</font>
| |
− | err = Pa_WriteStream(PaStream, <FONT color=darkorange><B>data</b></font>, BUFFER_LEN)
| |
− | If err <> paNoError Then Exit
| |
− |
| |
− | <FONT color=gray>' ''Attende un centesimo di secondo per consentire di agire su eventuali oggetti presenti sul Form.''
| |
− | ' '''''Ovviamente nel caso di applicazione "a riga di comando" questa funzione di attesa non è necessaria.'''''</font>
| |
− | Wait 0.01
| |
− |
| |
− | <FONT color=gray>' ''Mostra il tempo trascorso dall'inizio dell'esecuzione del file audio:''</font>
| |
− | quantum += BUFFER_LEN
| |
− | Write #File.out, "\r" & CStr(Date(0, 0, 0, 0, 0, 0, (quantum / sfinfo.samplerate) * 1000))
| |
− |
| |
− | Wend
| |
− |
| |
− | Endif
| |
− |
| |
− | <FONT color=gray>' ''Va in chiusura:''</font>
| |
− | err = Pa_CloseStream(PaStream)
| |
− | If err <> paNoError Then Error.Raise("Impossibile chiudere il flusso di dati !")
| |
− |
| |
− | err = Pa_Terminate()
| |
− | If err <> paNoError Then Error.Raise("Impossibile chiudere la libreria 'libportaudio' !")
| |
− |
| |
− | sf_close(infile)
| |
− |
| |
− | Free(<FONT color=darkorange><B>data</b></font>)
| |
− |
| |
− | '''End'''
| |
− |
| |
− |
| |
− | '''Public''' Sub Button2_Click()
| |
− |
| |
− | Dim err As Integer
| |
− |
| |
− | <FONT color=gray>' ''Arresta l'esecuzione del file audio:''</font>
| |
− | err = Pa_StopStream(PaStream)
| |
− | If err <> paNoError Then Error.Raise("Impossibile arrestare l'esecuzione dei dati audio !")
| |
− |
| |
− | '''End'''
| |
− | | |
− | | |
− | | |
− | =Riferimenti=
| |
− | * [http://www.portaudio.com/ Il sito di PortAudio]
| |
− | * [http://portaudio.com/docs/v19-doxydocs/index.html Il sito del API di PortAudio].
| |
− | * [http://ispac.ing.uniroma1.it/scarpiniti/files/LabEMM/Less9.pdf Una introduzione a PortAudio]
| |
− | * [http://www.mega-nerd.com/libsndfile/api.html Il sito del API di SndFile].
| |