Differenze tra le versioni di "Eseguire onde sonore con Alsa"
Riga 547: | Riga 547: | ||
− | ===Esempio di codice per emettere un'onda "'' | + | ===Esempio di codice per emettere un'onda ad "''impulsi''" (''pulse wave'')=== |
− | L'esempio che segue mostra un codice che genera un'onda '' | + | L'esempio che segue mostra un codice che genera un'onda ad ''impulsi'' (''pulse wave'') della frequenza di 440 hz: |
Private Const FREQ_CAMPION As Integer = 44100 <FONT color=gray>' ''frequenza di campionamento''</font> | Private Const FREQ_CAMPION As Integer = 44100 <FONT color=gray>' ''frequenza di campionamento''</font> | ||
Private Const CANALI As Integer = 1 | Private Const CANALI As Integer = 1 | ||
Riga 600: | Riga 600: | ||
− | <FONT color=gray>' ''Genera i valori dell'onda | + | <FONT color=gray>' ''Genera i valori dell'onda ad "impulsi":''</font> |
While k <= num_campioni | While k <= num_campioni | ||
If (CInt(k / CANALI) Mod CInt(lunghezzaOnda)) < (lunghezzaOnda * pulsus) Then | If (CInt(k / CANALI) Mod CInt(lunghezzaOnda)) < (lunghezzaOnda * pulsus) Then |
Versione delle 15:35, 11 feb 2014
Mostriamo di seguito alcuni esempi di codice per generare ed eseguire onde di diverso tipo.
Indice
- 1 Codice base esemplificativo
- 2 Uso di codice semplificato
- 2.1 Esempio di codice per generare un bip
- 2.2 Esempio di codice per generare onde sinusoidali
- 2.3 Eseguire una scala cromatica di 10 ottave con un'onda sinusoidale
- 2.4 Esempio di codice per emettere un'onda a "dente di sega"
- 2.5 Esempio di codice per emettere un'onda "triangolare"
- 2.6 Esempio di codice per emettere un'onda "quadra"
- 2.7 Esempio di codice per emettere un'onda ad "impulsi" (pulse wave)
- 3 Note
Codice base esemplificativo
Codice che genera ed esegue un rumore bianco
Di questo codice esporremo anche la descrizione della sua struttura:
' Individuiamo innanzitutto la libreria condivisa, ' nella quale sono contenute le funzioni esterne di ALSA: Library "libasound:2" Private Const SND_PCM_STREAM_PLAYBACK As Byte = 0 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3 Private Const SND_PCM_FORMAT_S16_LE As Byte = 2 ' int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) Private Extern snd_pcm_open(pcmP As Pointer, nome As String, stream As Integer, mode As Integer) As Integer ' int snd_pcm_hw_params_malloc (snd_pcm_hw_params_t **ptr) Private Extern snd_pcm_hw_params_malloc(ptr As Pointer) As Integer ' int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) Private Extern snd_pcm_hw_params_any(pcmP As Pointer, ptrP As Pointer) As Integer ' int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access) Private Extern snd_pcm_hw_params_set_access(pcmP As Pointer, ptrP As Pointer, accesso As Integer) As Integer ' int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val) Private Extern snd_pcm_hw_params_set_format(pcmP As Pointer, ptrP As Pointer, valformat As Integer) As Integer ' int snd_pcm_hw_params_set_frequenza_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) Private Extern snd_pcm_hw_params_set_rate_near(pcmP As Pointer, ptrP As Pointer, valP As Pointer, dirP As Pointer) As Integer ' int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) Private Extern snd_pcm_hw_params_set_channels(pcmP As Pointer, ptrP As Pointer, valP As Pointer) As Integer ' int snd_pcm_hw_params_set_periodi(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) Private Extern snd_pcm_hw_params_set_periods(pcmP As Pointer, ptrP As Pointer, valP As Pointer, dirI As Integer) As Integer ' int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val) Private Extern snd_pcm_hw_params_set_buffer_size(pcmP As Pointer, ptrP As Pointer, uframes As Long) As Integer ' int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) Private Extern snd_pcm_hw_params(pcmP As Pointer, ptrP As Pointer) As Integer ' snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) Private Extern snd_pcm_writei(pcmP As Pointer, buffer As single[], uframes As Integer) As Integer ' int snd_pcm_prepare(snd_pcm_t * pcm) Private Extern snd_pcm_prepare(pcmP As Pointer) As Integer ' int snd_pcm_close(snd_pcm_t * pcm) Private Extern snd_pcm_close(pcmP As Pointer) Public Sub Main() Dim handle As Pointer Dim dimen As Integer Dim j, num_secondi as Byte Dim frequenza As Integer = 44100 ' frequenza del campione audio Dim canali As Integer = 2 ' canali di uscita del campione audio Dim periodi As Integer = 2 ' Numero di periodi Dim dimenPeriodi As Integer = 8192 Dim nomen As String = "plughw:0,0" Dim hwparams, frequenzaEsatta As Pointer Dim dati As Single[]
1 Viene innanzitutto allocata una struttura di tipo "hwparams", che consentirà di impostare la configurazione adatta per il dispositivo PCM.
snd_pcm_hw_params_malloc(VarPtr(hwparams))
2 Quindi apriamo il dispositivo PCM di ALSA:
If snd_pcm_open(VarPtr(handle), nomen, SND_PCM_STREAM_PLAYBACK, 0) < 0 then Message.Error("Errore nell'apertura del dispositivo PCM !")
3 Prima di poter scrivere dati dal PCM alla scheda audio, dobbiamo specificare il tipo di accesso, formato dei campioni, frequenza di campionamento, numero di canali, numero di periodi e dimensioni del periodo. In primo luogo, si inizializza la struttura "hwparams" con lo spazio di configurazione completa della scheda audio.
If snd_pcm_hw_params_any(handle, hwparams) < 0 Then Message.Error("Non è possibile la configurazione del dispositivo PCM !")
4 Viene quindi impostato il tipo di accesso, il quale specifica il modo in cui i dati multicanale sono memorizzati nel buffer. Per l'accesso INTERLEAVED |1|, ogni frame nel buffer contiene campioni di dati consecutivi per entrambi i canali. Per dati stereo a 16 bit il buffer contiene campioni di dati che si alternano per il canale sinistro e per quello destro. Per l'accesso NONINTERLEAVED |2|, ogni periodo prima contiene tutti i campioni di dati per il primo canale seguito dai campioni di dati per il secondo canale e così via.
If snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 Then Message.Error("Errore nell'impostazione della modalità di accesso !")
5 Viene impostato il formato dei campioni:
If snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0 Then Message.Error("Errore nell'impostazione del formato campioni audio !")
6 Imposta la frequenza di campionamento. Se la frequenza esatta non è supportata dall'hardware, è opportuno utilizzare la frequenza più prossima possibile.
frequenzaEsatta = VarPtr(frequenza) If snd_pcm_hw_params_set_rate_near(handle, hwparams, frequenzaEsatta, 0) < 0 Then Message.Error("Errore nell'impostazione della frequenza !") If frequenza <> Int@(frequenzaEsatta) Then Message.Error("La frequenza non è supportata dalla scheda audio !")
7 Imposta il numero dei canali:
If snd_pcm_hw_params_set_channels(handle, hwparams, canali) < 0 Then Message.Error("Errore nell'impostazione dei canali !")
8 Imposta i numeri dei periodi:
If snd_pcm_hw_params_set_periods(handle, hwparams, periodi, 0) < 0 Then Message.Error("Errore nell'impostazione dei periodi !")
9 L'unità della dimensione del buffer dipende dalla funzione. A volte viene fornito in byte, a volte il numero di frame deve essere specificata. Un frame |3| è il vettore dei dati di esempio per tutti i canali. Per 16 di dati bit stereo, un frame ha una lunghezza di quattro byte. Imposta in "frames" la dimensione del buffer. La latenza risultante è data da: latenza = dimenPeriodi * periodi / (frequenza * bytes_per_frame).
dimen = Shr((dimenPeriodi * periodi), 2) If snd_pcm_hw_params_set_buffer_size(handle, hwparams, dimen) < 0 Then Message.Error("Errore nell'impostazione della dimensione del buffer !")
10 Si applica, dunque, la configurazione fin qui preparata al dispositivo PCM puntato dalla variabile handle di tipo Pointer.
If snd_pcm_hw_params(handle, hwparams) < 0 Then Message.Error("Errore nell'impostazione dei parametri hardware !")
11 Dopo la configurazione del sub-sistema PCM, è possibile inviargli i dati. Con il tipo di accesso in scrittura "interleaved" si dovrà utilizzare la funzione "snd_pcm_writei", che invia i dati frames presenti nella variabile "dati" dal buffer dei dati al dispositivo PCM puntato dalla variabile handle di tipo Pointer. Bisogna assicurarsi che venga inviata al sub-sistema PCM una quantità adeguata di dati, altrimenti verrà sollevato un errore di Buffer Underrun |4|. In caso di tale errore è opportuno chiamare la funzione "snd_pcm_prepare".
num_secondi = 3 num_campioni = num_secondi * canali * frequenza dati = New Single[] While k <= num_campioni dati.Add(Rnd(0.1, 1)) k += canali Wend ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, dati, frequenza) snd_pcm_prepare(handle) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Uso di codice semplificato
L'API di ALSA consente anche di utilizzare una modalità semplificata per ottenenere onde sonore.
Esempio di codice per generare un bip
Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_U8 As Integer = 1 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Integer = 3 Private handle As Pointer Private buffer As Integer ' int snd_pcm_open (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffP As Pointer, sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, i, frames As Integer Dim sizep As Pointer err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_U8, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 22050, 1, 100000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) sizep = Alloc(130) For i = 0 To 149 frames = snd_pcm_writei(handle, sizep, 130 \ 4) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: Free(sizep) snd_pcm_close(handle) End
Esempio di codice per generare onde sinusoidali
L'esempio che segue mostra un codice che genera un'onda sinusoidale della frequenza di 440 hz:
Private Const BUFFER_LEN As Integer = 44100 Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, j, k, frames, fc As Integer Dim handle As Pointer Dim hz As Single Dim buffer As New Single[] fc = BUFFER_LEN ' frequenza di campionamento hz = 440.0 ' frequenza dell'onda err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, 1, fc, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) ' Genera i valori dell'onda sinusoidale: For k = 0 To BUFFER_LEN - 1 buffer.Add(Sin(2 * Pi * hz / fc * k)) Next ' Invia i valori dell'onda sinusoidale al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, buffer, BUFFER_LEN) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Eseguire una scala cromatica di 10 ottave con un'onda sinusoidale
L'esempio in questione eseguirà con un suono di onda sinusoidale una scala cromatica di ben 10 ottave:
Private Const FREQ_CAMPION As Integer = 44100 ' frequenza di campionamento Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, k, frames As Integer Dim handle As Pointer Dim buffer As New Single[] Dim b, m, st As Byte err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, 1, FREQ_CAMPION, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) For b = 1 To 10 ' Conta il numero di ottave For st = 0 To 11 ' Aggiunge la quantità di semitoni esistenti fra la prima nota dell'ottava e la nota da eseguire m = b - 1 ' Genera i valori dell'onda sinusoidale: For k = 0 To FREQ_CAMPION - 1 ' Calcola la frequenza della nota da eseguire: buffer.Add(Sin(2 * Pi * (Fix((2 ^ (((12 * m) + st) / 12)) * 16)) / FREQ_CAMPION * k)) |5| Next ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: frames = snd_pcm_writei(handle, buffer, FREQ_CAMPION) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") buffer.Clear Next Next ' Va in chiusura: snd_pcm_close(handle) End
Esempio di codice per emettere un'onda a "dente di sega"
L'esempio che segue mostra un codice che genera un'onda a dente di sega della frequenza di 440 hz:
Private Const FREQ_CAMPION As Integer = 44100 ' frequenza di campionamento Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, j, k, canali, frames As Integer Dim handle As Pointer Dim hz As Single Dim buffer As New Single[] Dim periodo As Single hz = 440.0 ' frequenza dell'onda canali = 1 err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, canali, FREQ_CAMPION, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) periodo = FREQ_CAMPION / hz ' Genera i valori dell'onda a "dente di sega": While k <= FREQ_CAMPION buffer.Add(2 * (k / periodo - CInt((k / periodo) + 0.5))) k += canali Wend ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, buffer, FREQ_CAMPION) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Esempio di codice per emettere un'onda "triangolare"
L'esempio che segue mostra un codice che genera un'onda a triangolare della frequenza di 440 hz:
Private Const FREQ_CAMPION As Integer = 44100 ' frequenza di campionamento Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, j, k, frames As Integer Dim handle As Pointer Dim buffer As New Single[] Dim canali As Integer Dim hz, periodo As Single hz = 440.0 ' frequenza dell'onda canali = 1 periodo = FREQ_CAMPION / hz err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, canali, FREQ_CAMPION, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) ' Genera i valori dell'onda "triangolare": While k <= FREQ_CAMPION buffer.Add(Abs(2 * (k / periodo - CInt((k / periodo) + 0.5)))) k += canali Wend ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, buffer, FREQ_CAMPION) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Esempio di codice per emettere un'onda "quadra"
L'esempio che segue mostra un codice che genera un'onda quadra della frequenza di 440 hz:
Private Const FREQ_CAMPION As Integer = 44100 ' frequenza di campionamento Private Const CANALI As Integer = 1 Private Const NUM_SECONDI As Byte = 3 Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, j, k, num_campioni, frames As Integer Dim handle As Pointer Dim buffer As New Single[] Dim hz, periodo As Single hz = 440.0 ' frequenza dell'onda num_campioni = NUM_SECONDI * CANALI * FREQ_CAMPION periodo = FREQ_CAMPION / hz err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, CANALI, FREQ_CAMPION, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) ' Genera i valori dell'onda "quadra": While k <= num_campioni buffer.Add(Sgn(Sin(2 * Pi(1) * (k / periodo)))) k += CANALI Wend ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, buffer, FREQ_CAMPION) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Esempio di codice per emettere un'onda ad "impulsi" (pulse wave)
L'esempio che segue mostra un codice che genera un'onda ad impulsi (pulse wave) della frequenza di 440 hz:
Private Const FREQ_CAMPION As Integer = 44100 ' frequenza di campionamento Private Const CANALI As Integer = 1 Private Const NUM_SECONDI As Byte = 3 Library "libasound:2" Private Const device As String = "default" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_FLOAT As Integer = 14 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) Private Extern snd_pcm_open(pcm As Pointer, name As String, stream 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) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso 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) Private Extern snd_pcm_writei(pcm As Pointer, buffSn As Single[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim err, j, k, frames As Integer Dim handle As Pointer Dim buffer As New Single[] Dim num_campioni As Integer Dim hz, pulsus, lunghezzaOnda As Single hz = 440.0 ' frequenza dell'onda num_campioni = NUM_SECONDI * CANALI * FREQ_CAMPION pulsus = 0.9 lunghezzaOnda = FREQ_CAMPION / hz err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) err = snd_pcm_set_params(handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, CANALI, FREQ_CAMPION, 1, 500000) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) ' Genera i valori dell'onda ad "impulsi": While k <= num_campioni If (CInt(k / CANALI) Mod CInt(lunghezzaOnda)) < (lunghezzaOnda * pulsus) Then buffer.Add(1) Else buffer.Add(0) Endif k += CANALI Wend ' Invia i valori dell'onda al dispositivo sonoro PCM di ALSA: For j = 0 To 4 frames = snd_pcm_writei(handle, buffer, FREQ_CAMPION) If frames < 0 Then Error.Raise("Errore alla funzione 'snd_pcm_writei' !") Next ' Va in chiusura: snd_pcm_close(handle) End
Note
[1] L'accesso INTERLEAVED prevede un'organizzazione dei dati in cui i campioni di ogni canale, che saranno eseguiti allo stesso tempo, si susseguono in sequenza: il campione di un canale segue il campione dell'altro canale.
[2] L'accesso NONINTERLEAVED prevede un'organizzazione dei dati in cui i campioni di un singolo canale si susseguono sequenzialmente; i campioni per l'altro canale si trovano o in un altro buffer o in un'altra parte di questo buffer.
[3] Un campione audio è un valore singolo che rappresenta l'ampiezza del segnale audio in un determinato attimo di tempo su un singolo canale. Con l'audio digitale spesso si parla di dati che rappresentano tutti i canali in un unico momento temporale. Questa è una raccolta di campioni, una per canale, ed è generalmente chiamata "frame".
[4] L'errore di Buffer Underrun, o errore di svuotamento del buffer, si ottiene quando il processo di scrittura dei dati nel dispositivo PCM si interrompe inaspettatamente a causa della mancanza di dati nel buffer (buffer vuoto) da inviare al predetto dispositivo.
[5] Conoscendo la frequenza di una nota, la formula per calcolare la frequenza di tutte le altre note, compresi i semitoni, è: 2^(n/12) * hz
ossia 2 elevato a n/12 e moltiplicato per la frequenza della nota di riferimento; dove n è il numero dei semitoni di distanza dalla nota di riferimento stessa.
Ad esempio: rispetto al La a 440 Hz, la frequenza del Si, distante da La due semitoni, è: 2 ^(2/12) * 440 = 1,1225 * 440 = 493,9
Un altra modalità, per calcolare la frequenza delle altre note partendo dalla frequenza conosciuta di una nota, è: hz * c ^ n
laddove hz è la frequenza conosciuta di una nota, c è il coefficiente uguale a 1.0594630943592952645 ed n è il numero di semitoni esistenti fra la nota di riferimento e la nota di cui si intende trovare la frequenza.
Ad esempio: rispetto al La a 440 Hz, la frequenza del Si, distante da La due semitoni, è: 440 * c ^ 2 = 493,8833