Differenze tra le versioni di "Eseguire onde sonore con Alsa"

Da Gambas-it.org - Wikipedia.
Riga 523: Riga 523:
 
   Dim err, j, k, num_campioni, frames As Integer
 
   Dim err, j, k, num_campioni, frames As Integer
 
   Dim handle As Pointer
 
   Dim handle As Pointer
  Dim hz As Short
 
 
   Dim buffer As New Single[]
 
   Dim buffer As New Single[]
   Dim metaPeriodo, proxCamp, aumento As Single
+
   Dim hz, metaPeriodo, proxCamp, aumento As Single
 
  <FONT color=gray>' ''Dim periodo As Single''</font>
 
  <FONT color=gray>' ''Dim periodo As Single''</font>
 
    
 
    
 
   
 
   
 
   
 
   
   hz = 440            <FONT color=gray>' ''frequenza dell'onda''</font>
+
   hz = 440.0           <FONT color=gray>' ''frequenza dell'onda''</font>
 
   num_campioni = NUM_SECONDI * CANALI * FREQ_CAMPION
 
   num_campioni = NUM_SECONDI * CANALI * FREQ_CAMPION
 
   metaLunghOnda = FREQ_CAMPION / (2 * hz)
 
   metaLunghOnda = FREQ_CAMPION / (2 * hz)

Versione delle 09:21, 11 feb 2014

Mostriamo di seguito alcuni esempi di codice per generare ed eseguire onde di diverso tipo.


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 Short
 Dim buffer As New Single[]


  fc = BUFFER_LEN     ' frequenza di campionamento
  hz = 440            ' 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, frames As Integer
 Dim handle As Pointer
 Dim hz As Short
 Dim buffer As New Single[]
 Dim periodo, canali As Integer


  hz = 440            ' 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 \ canali) Mod periodo) / CSingle(periodo - 1))
' oppure più similmente alla formula 2(t/a - floor(t/a + 1/2)):
    buffer.Add(2 * (k / periodo - Fix((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 hz As Short
 Dim buffer As New Single[]
 Dim canali As Integer
 Dim metaLunghOnda As Integer
 Dim proxCamp, aumento As Single
' Dim periodo As Single


  hz = 440            ' frequenza dell'onda
  canali = 1
  metaLunghOnda = FREQ_CAMPION / (2 * hz)
  proxCamp = -1
  aumento = -2.0 / (metaLunghOnda + 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(proxCamp)
    If Not (CInt(k / canali) Mod metaLunghOnda) Then aumento *= -1
    proxCamp += aumento
' oppure secondo la formula |2(t/a - [t/a + 1/2]):
    buffer.Add((Abs(2 * (k / periodo - Fix((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, metaPeriodo, proxCamp, aumento As Single
' Dim periodo As Single
 


  hz = 440.0            ' frequenza dell'onda
  num_campioni = NUM_SECONDI * CANALI * FREQ_CAMPION
  metaLunghOnda = FREQ_CAMPION / (2 * hz)
  proxCamp = -1
  aumento = -2.0 / (metaLunghOnda + 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 "quadra":
  While k <= num_campioni
    buffer.Add(proxCamp)
    If Not ((k \ CANALI) Mod Cint(metaLunghOnda)) Then proxCamp *= -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, 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 "pulsante" (pulse wave)

L'esempio che segue mostra un codice che genera un'onda pulsante (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 hz As Short
 Dim buffer As New Single[]
 Dim num_campioni As Integer
 Dim pulsus As Single
 Dim lunghezzaOnda As Integer
  

  hz = 440            ' 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 di "polso":
  While k <= num_campioni
    If ((CInt(k / CANALI) Mod 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