Differenze tra le versioni di "Generare un'onda sinusoidale con le sole funzioni di Gambas"

Da Gambas-it.org - Wikipedia.
Riga 162: Riga 162:
 
   Print "Fine creazione dell'onda e del file wav."
 
   Print "Fine creazione dell'onda e del file wav."
 
   
 
   
'''End'''
+
'''End'''
 
   
 
   
 
   
 
   

Versione delle 05:18, 21 ago 2015

E' possibile generare un'onda sinusoidale con le sole risorse di Gambas.

Mostriamo di seguito due modalità.


Ricavare un'onda sinusoidale da un insieme di dati audio grezzi predefiniti in un vettore

Mostriamo un esempio (tratto da analogo codice scritto in C da Fabrice Bellard e convertito qui in Gambas con modifiche ed integrazioni), al termine del quale verrà creato un file di tipo WAV contenente i dati audio e che consentirà di eseguire l'onda sinusoidale campionata:

Private Const RISOL_BIT As Integer = 16
Private Const COST_TAB_VAL As Integer = 7
Private FRAZIONE As Integer = 1 * CInt(2 ^ RISOL_BIT)
Private CSHIFT As Integer = RISOL_BIT - COST_TAB_VAL - 2
Private Tabella_Valori As Integer[] = [&8000&, &7ffe, &7ff6, &7fea, &7fd9, &7fc2, &7fa7, &7f87,
                                       &7f62, &7f38, &7f0a, &7ed6, &7e9d, &7e60, &7e1e, &7dd6,
                                       &7d8a, &7d3a, &7ce4, &7c89, &7c2a, &7bc6, &7b5d, &7aef,
                                       &7a7d, &7a06, &798a, &790a, &7885, &77fb, &776c, &76d9,
                                       &7642, &75a6, &7505, &7460, &73b6, &7308, &7255, &719e,
                                       &70e3, &7023, &6f5f, &6e97, &6dca, &6cf9, &6c24, &6b4b,
                                       &6a6e, &698c, &68a7, &67bd, &66d0, &65de, &64e9, &63ef,
                                       &62f2, &61f1, &60ec, &5fe4, &5ed7, &5dc8, &5cb4, &5b9d,
                                       &5a82, &5964, &5843, &571e, &55f6, &54ca, &539b, &5269,
                                       &5134, &4ffb, &4ec0, &4d81, &4c40, &4afb, &49b4, &486a,
                                       &471d, &45cd, &447b, &4326, &41ce, &4074, &3f17, &3db8,
                                       &3c57, &3af3, &398d, &3825, &36ba, &354e, &33df, &326e,
                                       &30fc, &2f87, &2e11, &2c99, &2b1f, &29a4, &2827, &26a8,
                                       &2528, &23a7, &2224, &209f, &1f1a, &1d93, &1c0c, &1a83,
                                       &18f9, &176e, &15e2, &1455, &12c8, &113a, &0fab, &0e1c,
                                       &0c8c, &0afb, &096b, &07d9, &0648, &04b6, &0324, &0192,
                                       &0000, &0000]


Public Sub Main()

 Dim fl As File
 Dim filegrezzo As String
 Dim i, a, v, j As Integer
 Dim campionamento, canali, frequenza, volume As Integer
 Dim durata As Single
 
  filegrezzo = "/tmp/datigrezzi"    ' File contenente i dati audio grezzi dell'onda
   
  campionamento = 44100   ' Frequenza di campionamento dell'onda
  canali = 2              ' Numero canali del file WAV
  frequenza = 440         ' Frequenza dell'onda
  durata = 3.0            ' Durata in secondi
  volume = 10000          ' Volume audio dell'onda
   
  fl = Open filegrezzo For Create
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")

' Genera 3 secondi di un'onda sinusoidale alla frequenza di Hz 440:
  For i = 0 To (durata * campionamento) - 1
    v = (int_cos(a) * volume) \ CInt(2 ^ RISOL_BIT)
    For j = 0 To canali - 1
      Scrivi_File(fl, v)
    Next
    a += (frequenza * FRAZIONE) / campionamento
  Next
   
  Crea_File_WAV(fl)

  fl.Close
   
  Print "Fine creazione dell'onda."

End


Private Function Int_Cos(a As Integer) As Integer

 Dim neg, v, f As Integer
 Dim p As Integer[]

  a = a And (FRAZIONE - 1)
  If a >= (FRAZIONE / 2) Then a = FRAZIONE - a
  neg = 0
  If a > (FRAZIONE / 4) Then
    neg = -1
    a = (FRAZIONE / 2) - a
  Endif

  p = Tabella_Valori.Copy(a \ CInt(2 ^ CSHIFT), Tabella_Valori.Count - a \ CInt(2 ^ CSHIFT))

' Interpolazione lineare:
  f = a And ((1 * CInt(2 ^ CSHIFT)) - 1)

  v = p[0] + (((p[1] - p[0]) * f + (1 * CInt(2 ^ (CSHIFT - 1)))) / CInt(2 ^ CSHIFT))

  v = (v Xor neg) - neg

  v = v * CInt(2 ^ (RISOL_BIT - 15))

  Return v

End


Private Procedure Scrivi_File(sf As File, v As Integer)
 
 Write #sf, CByte(v And &ff) As Byte
 
 Write #sf, CByte((v \ CInt(2 ^ 8)) And &ff) As Byte

End


Private Procedure Crea_File_WAV(dg As File)

 Dim intes As File
 Dim bb As Byte[] = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56,
                     &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00,
                     &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04,
                     &00, &10, &00, &64, &61, &74, &61]
     
' Scrive innanzitutto il blocco di intestazione del file WAV:
  intes = Open "/tmp/blocco_header" For Create
  bb.Write(intes, 0, 4)
  Write #intes, Lof(dg) + 36 As Integer
  bb.Write(intes, 8, 32)
  Write #intes, Lof(dg) As Integer
  intes.Close
   
' Unisce il blocco di intestazione del file WAV ai dati audio grezzi presenti nel file "datigrezzi"
' (in questo esempio il file WAV finale viene scritto nella cartella "/tmp"):
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load("/tmp/datigrezzi"))
 
End


Ricavare un'onda sinusoidale convertendo una nota Midi nella corrispondente frequenza sonora

Quest'altra modalità prevede il calcolo della frequenza sonora da una nota Midi. Come si sa, il sistema Midi numera le note da 0 a 127.

Verrà, dunque, calcolata la frequenza di una nota Midi e dai risultanti dati audio grezzi verrà creato un file wav:

Public Sub Main()
 
 Dim fl As File
 Dim filegrezzo As String
 Dim campionamento, durata, volume As Integer
 Dim NotaMidi As Byte
 Dim dati_grezzi As Short[]
 
  filegrezzo = "/tmp/datigrezzi"   ' Percorso del file che conterrà i dati audio grezzi dell'onda
  
  campionamento = 44100   ' Frequenza di campionamento dell'onda
  NotaMidi = 60           ' Numero della nota Midi
  durata = 3 * 100000     ' Durata in secondi
  volume = 10000          ' Volume audio dell'onda
  
  fl = Open filegrezzo For Create
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")
 
' Genera i dati audio grezzi:
  dati_grezzi = CreaDatiAudio(NotaMidi, durata, volume, campionamento)
 
  dati_grezzi.Write(fl, 0, dati_grezzi.Count)
  
' Crea il file wav finale:
  CreaFileWAV(fl)
  
  fl.Close
  
  Print "Fine creazione dell'onda e del file wav."

End


Private Function CreaDatiAudio(nota As Byte, dur As Integer, ampiezza As Integer, freq_camp As Integer) As Short[]

 Dim campione As Short
 Dim frequenza As Float
 Dim ciclo As Integer
 Dim dati_audio As New Short[]
  
' Ciclo per ciascun dato campione audio:
  For ciclo = 1 To dur
' Calcola la frequenza della nota Midi:
    frequenza = CalcolaFrequenza(nota)
' Calcola il dato del campione audio:
    campione = ampiezza * Sin(2 * Pi * ciclo * frequenza / freq_camp)
    dati_audio.Push(campione)
  Next
  
  Return dati_audio
  
End


Private Function CalcolaFrequenza(numero_nota As Byte) As Float
 
' Converte la nota Midi nella corrispondente frequenza sonora.
' La nota di riferimento è il "Do centrale" (hz 261,63 -- nota Midi: 60).
  Return 261.63 * (2 ^ (1 / 12)) ^ (numero_nota - 60)
  
End


Private Procedure CreaFileWAV(wav As File)

 Dim intes As File
 Dim bi As Byte[] = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56,
                     &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00,
                     &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04,
                     &00, &10, &00, &64, &61, &74, &61]
    
' Scrive innanzitutto il blocco di intestazione del file WAV:
  intes = Open "/tmp/blocco_header" For Create
  If IsNull(intes) Then Error.Raise("Impossibile scrivere il blocco d'intestazione !")
  
  bi.Write(intes, 0, 4)
  Write #intes, Lof(wav) + 36 As Integer
  bi.Write(intes, 8, 32)
  Write #intes, Lof(wav) As Integer
  intes.Close
  
' Unisce il blocco di intestazione del file WAV ai dati audio grezzi presenti nel file "datigrezzi"
' (in questo esempio il file WAV finale viene scritto nella cartella "/tmp"):
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load("/tmp/datigrezzi"))

End