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

Da Gambas-it.org - Wikipedia.
 
(23 versioni intermedie di uno stesso utente non sono mostrate)
Riga 2: Riga 2:
  
 
Mostriamo di seguito tre esempi.
 
Mostriamo di seguito tre esempi.
 
  
 
==Creare un'onda sinusoidale e salvare i dati in un file WAV==
 
==Creare un'onda sinusoidale e salvare i dati in un file WAV==
 +
Creiamo un'onda sinusoidale da 8000 hertz, 8-bit, 1 canale:
 
  Private Const AMPIEZZA As Integer = 127
 
  Private Const AMPIEZZA As Integer = 127
  Private Const FREQUENZA As Integer = 110
+
  Private Const FREQUENZA_ONDA As Integer = 110
  Private Const CAMPIONAMENTO As Integer = 8000
+
  Private Const CANALI As Short = 1
  Private Const DURATA As Integer = 10
+
Private Const FREQUENZA_CAMPIONAMENTO As Integer = 8000
 +
Private Const RISOLUZIONE As Short = 8  <FONT Color=gray>' ''Risoluzione del campionamento audio in bit''</font>
 +
  Private Const DURATA As Integer = 10   <FONT Color=gray>' ''Durata in secondi''</font>
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
   Dim dati As Byte[]
+
   Dim dati As New Byte[]
   
+
  <FONT Color=gray>' ''Va a generare i dati dell'onda sinusoidale:''</font>
+
  <FONT Color=gray>' ''Passa per "Indirizzo" il vettore e va a generare i dati dell'onda sinusoidale:''</font>
  dati = Onda()
+
  Onda(dati)
   
+
 
  <FONT Color=gray>' ''Va a generare il file WAV contenente l'onda sinusoidale:''</font>
 
  <FONT Color=gray>' ''Va a generare il file WAV contenente l'onda sinusoidale:''</font>
  CreaFileWav(dati.ToString(0, dati.Count))
+
  CreaFileWav(dati.ToString(0, dati.Count))
 
+
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Onda() As Short[]
+
  Private Function Onda(bb As Byte[])
 
    
 
    
 
   Dim i As Integer
 
   Dim i As Integer
   Dim s As Short
+
   Dim s As Single = 1.0
   Dim ss As New Short[]
+
 +
  If CANALI == 2 Then s = 0.5
 +
 +
  For i = 0 To (DURATA * FREQUENZA_CAMPIONAMENTO) - 1
 +
    bb.Push(<FONT Color=#B22222>AMPIEZZA * Sin(CFloat(i / FREQUENZA_CAMPIONAMENTO * FREQUENZA_ONDA * (s * Pi)))</font>)
 +
   Next
 +
 +
End
 +
 +
 +
Private Procedure CreaFileWav(dati_grezzi As String)
 
    
 
    
  For i = 0 To (DURATA * 2 * CAMPIONAMENTO) - 1
+
  Dim st As Stream
    s = 256 + AMPIEZZA * Sin(CFloat(i / CAMPIONAMENTO * FREQUENZA * (2 * Pi)))
+
  Dim header As New Byte[44]
    ss.Push(s)
+
 
  Next
+
<FONT Color=gray>' ''Per scrivere i dati del blocco d'intestazione del futuro file wav, viene usata la risorsa "Memory Stream", operando sulla Proprietà ".Data" del vettore:''</font>
   
+
  st = Memory header.Data For Write
  Return ss
 
 
    
 
    
'''End'''
+
  Write #st, "RIFF"
 
 
'''Private''' Procedure CreaFileWav(dati_grezzi As String)
 
 
    
 
    
   Dim fl As File
+
   Write #st, dati_grezzi.Len As Integer
  Dim ini As String
 
  Dim bh, bb As New Byte[]
 
  Dim canali, risoluzione, blal As Byte
 
  Dim i, i2, brps As Integer
 
 
    
 
    
<FONT Color=gray>' ''Vengono definiti gli elementi fondamentali del blocco d'intestazione del file wav:''</font>
 
  canali = 1
 
  risoluzione = 16
 
 
 
  fl = Open "/tmp/file.wav" For Create
 
 
 
  ini = "RIFF"
 
 
 
  bb = Byte[].FromString(ini)
 
 
 
  i = Len(dati_grezzi)
 
 
 
  i2 = i + 36
 
 
 
<FONT Color=gray>' ''Imposta il valore dimensionale di 4 byte a partire dal 5° byte del futuro file:''</font>
 
  bb.Add(i2 And &FF)
 
  bb.Add(Shr(i2 And &FF00&, 8))
 
  bb.Add(Shr(i2 And &FF0000&, 16))
 
  bb.Add(Shr(i2 And &FF000000&, 24))
 
 
 
 
  <FONT Color=gray>' ''Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del blocco dei dati audio:''</font>
 
  <FONT Color=gray>' ''Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del blocco dei dati audio:''</font>
  bb = bb.Insert(bh.FromString("WAVEfmt "))
+
  Write #st, "WAVEfmt "
 
   
 
   
 
  <FONT Color=gray>' ''Viene aggiunto il valore della lunghezza dei dati del formato (in questo caso il PCM):''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore della lunghezza dei dati del formato (in questo caso il PCM):''</font>
  bh = [&10, &00, &00, &00]
+
  Write #st, 16 As Integer
  bb = bb.Insert(bh)
+
 
 
 
 
  <FONT Color=gray>' ''Viene aggiunto il valore del formato audio (1 = PCM):''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore del formato audio (1 = PCM):''</font>
  bb = bb.Insert(bh.FromString(Chr(&01) & Chr(&00)))
+
  Write #st, 1 As Short
 
+
 
 
  <FONT Color=gray>' ''Viene aggiunto il numero dei canali di uscita:''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il numero dei canali di uscita:''</font>
  bb = bb.Insert(bh.FromString(Chr(canali) & Chr(&00)))
+
  Write #st, canali As Short
 
+
 
 
  <FONT Color=gray>' ''Viene aggiunto il valore della frequenza di campionamento:''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore della frequenza di campionamento:''</font>
  bb.Add(CAMPIONAMENTO And &FF)
+
  Write #st, FREQUENZA_CAMPIONAMENTO As Integer
  bb.Add(Shr(CAMPIONAMENTO And &FF00&, 8))
+
 
  bb.Add(Shr(CAMPIONAMENTO And &FF0000&, 16))
 
  bb.Add(Shr(CAMPIONAMENTO And &FF000000&, 24))
 
 
 
 
  <FONT Color=gray>' ''Viene aggiunto il valore del "Byte rate per secondo":''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore del "Byte rate per secondo":''</font>
  brps = CAMPIONAMENTO * canali * (risoluzione / 8)
+
  Write #st, FREQUENZA_CAMPIONAMENTO * CANALI * (RISOLUZIONE / 8) As Integer
  bb.Add(brps And &FF)
+
  bb.Add(Shr(brps And &FF00&, 8))
 
  bb.Add(Shr(brps And &FF0000&, 16))
 
  bb.Add(Shr(brps And &FF000000&, 24))
 
 
 
 
  <FONT Color=gray>' ''Viene aggiunto il valore del "Block Align":''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore del "Block Align":''</font>
  blal = canali * risoluzione / 8
+
  Write #st, CANALI * RISOLUZIONE / 8 As Short
  bb = bb.Insert(bh.FromString(Chr(blal) & Chr(&00)))
+
 
 
 
 
  <FONT Color=gray>' ''Viene aggiunto il valore della risoluzione di campionamento:''</font>
 
  <FONT Color=gray>' ''Viene aggiunto il valore della risoluzione di campionamento:''</font>
  bb = bb.Insert(bh.FromString(Chr(risoluzione) & Chr(&00)))
+
  Write #st, RISOLUZIONE As Short
 +
 +
<FONT Color=gray>' ''Viene aggiunto l'identificativo del Blocco dei dati audio grezzi:''</font>
 +
  Write #st, "data"
 
    
 
    
<FONT Color=gray>' ''Viene aggiunto l'identificativo del Blocco dei dati audio grezzi:''</font>
+
  <FONT Color=gray>' ''Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file e relativo alla dimensione dei dati audio grezzi:''</font>
  bb = bb.Insert(bh.FromString("data"))
+
  Write #st, dati_grezzi.Len As Integer
 
+
  <FONT Color=gray>' ''Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file
+
  st.Close
' ''e relativo alla dimensione dei dati audio grezzi:''</font>
+
  bb.Add(i And &FF)
 
  bb.Add(Shr(i And &FF00&, 8))
 
  bb.Add(Shr(i And &FF0000&, 16))
 
  bb.Add(Shr(i And &FF000000&, 24))
 
 
 
  bb = bb.Insert(Byte[].FromString(dati_grezzi))
 
 
 
 
  <FONT Color=gray>' ''Crea il nuovo file wav:''</font>
 
  <FONT Color=gray>' ''Crea il nuovo file wav:''</font>
  bb.Write(fl, 0, bb.Count)
+
  File.Save("/tmp/file.wav", header.ToString(0, header.Count) & dati_grezzi)
 
+
  fl.Close
+
  End
 
 
  '''End'''
 
 
 
  
  
Riga 147: Riga 115:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim fl As File
 
   Dim fl As File
Riga 155: Riga 123:
 
   Dim durata As Single
 
   Dim durata As Single
 
    
 
    
  filegrezzo = "/tmp/datigrezzi"   <FONT Color=gray>' ''File contenente i dati audio grezzi dell'onda''</font>
+
  filegrezzo = Temp   <FONT Color=gray>' ''File contenente i dati audio grezzi dell'onda''</font>
 
      
 
      
  campionamento = 44100  <FONT Color=gray>' ''Frequenza di campionamento dell'onda''</font>
+
  campionamento = 44100  <FONT Color=gray>' ''Frequenza di campionamento dell'onda''</font>
  canali = 2              <FONT Color=gray>' ''Numero canali del file WAV''</font>
+
  canali = 2              <FONT Color=gray>' ''Numero canali del file WAV''</font>
  frequenza = 440        <FONT Color=gray>' ''Frequenza dell'onda''</font>
+
  frequenza = 440        <FONT Color=gray>' ''Frequenza dell'onda''</font>
  durata = 3.0            <FONT Color=gray>' ''Durata in secondi''</font>
+
  durata = 3.0            <FONT Color=gray>' ''Durata in secondi''</font>
  volume = 10000          <FONT Color=gray>' ''Volume audio dell'onda''</font>
+
  volume = 10000          <FONT Color=gray>' ''Volume audio dell'onda''</font>
 
      
 
      
  fl = Open filegrezzo For Create
+
  fl = Open filegrezzo For Create
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")
+
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")
 
   
 
   
 
  <FONT Color=gray>' ''Genera 3 secondi di un'onda sinusoidale alla frequenza di Hz 440:''</font>
 
  <FONT Color=gray>' ''Genera 3 secondi di un'onda sinusoidale alla frequenza di Hz 440:''</font>
  For i = 0 To (durata * campionamento) - 1
+
  For i = 0 To (durata * campionamento) - 1
    v = (int_cos(a) * volume) \ CInt(2 ^ RISOL_BIT)
+
    v = (int_cos(a) * volume) \ CInt(2 ^ RISOL_BIT)
    For j = 0 To canali - 1
+
    For j = 0 To canali - 1
      Scrivi_File(fl, v)
+
      Scrivi_File(fl, v)
    Next
+
    Next
    a += (frequenza * FRAZIONE) / campionamento
+
    a += (frequenza * FRAZIONE) / campionamento
  Next
+
  Next
 
      
 
      
  Crea_File_WAV(fl)
+
  Crea_File_WAV(fl, filegrezzo)
 
   
 
   
  fl.Close
+
  fl.Close
 
      
 
      
  Print "Fine creazione dell'onda."
+
  Print "Fine creazione dell'onda."
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function Int_Cos(a As Integer) As Integer
+
  Private Function Int_Cos(a As Integer) As Integer
 
   
 
   
 
   Dim neg, v, f As Integer
 
   Dim neg, v, f As Integer
 
   Dim p As Integer[]
 
   Dim p As Integer[]
 
   
 
   
  a = a And (FRAZIONE - 1)
+
  a = a And (FRAZIONE - 1)
  If a >= (FRAZIONE / 2) Then a = FRAZIONE - a
+
  If a >= (FRAZIONE / 2) Then a = FRAZIONE - a
  neg = 0
+
  neg = 0
  If a > (FRAZIONE / 4) Then
+
  If a > (FRAZIONE / 4) Then
    neg = -1
+
    neg = -1
    a = (FRAZIONE / 2) - a
+
    a = (FRAZIONE / 2) - a
  Endif
+
  Endif
 
   
 
   
  p = Tabella_Valori.Copy(a \ CInt(2 ^ CSHIFT), Tabella_Valori.Count - a \ CInt(2 ^ CSHIFT))
+
  p = Tabella_Valori.Copy(a \ CInt(2 ^ CSHIFT), Tabella_Valori.Count - a \ CInt(2 ^ CSHIFT))
 
   
 
   
 
  <FONT Color=gray>' ''Interpolazione lineare:''</font>
 
  <FONT Color=gray>' ''Interpolazione lineare:''</font>
  f = a And ((1 * CInt(2 ^ CSHIFT)) - 1)
+
  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 = p[0] + (((p[1] - p[0]) * f + (1 * CInt(2 ^ (CSHIFT - 1)))) / CInt(2 ^ CSHIFT))
 
   
 
   
  v = (v Xor neg) - neg
+
  v = (v Xor neg) - neg
 
   
 
   
  v = v * CInt(2 ^ (RISOL_BIT - 15))
+
  v = v * CInt(2 ^ (RISOL_BIT - 15))
 
   
 
   
  Return v
+
  Return v
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Procedure Scrivi_File(sf As File, v As Integer)
+
  Private Procedure Scrivi_File(sf As File, v As Integer)
 
    
 
    
 
   Write #sf, CByte(v And &ff) As Byte
 
   Write #sf, CByte(v And &ff) As Byte
Riga 219: Riga 187:
 
   Write #sf, CByte((v \ CInt(2 ^ 8)) And &ff) As Byte
 
   Write #sf, CByte((v \ CInt(2 ^ 8)) And &ff) As Byte
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Procedure Crea_File_WAV(dg As File)
+
  Private Procedure Crea_File_WAV(dg As File, dati As String)
 
   
 
   
 
   Dim intes As File
 
   Dim intes As File
Riga 229: Riga 197:
 
                       &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04,
 
                       &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04,
 
                       &00, &10, &00, &64, &61, &74, &61]
 
                       &00, &10, &00, &64, &61, &74, &61]
     
+
 
  <FONT Color=gray>' ''Scrive innanzitutto il blocco di intestazione del file WAV:''</font>
 
  <FONT Color=gray>' ''Scrive innanzitutto il blocco di intestazione del file WAV:''</font>
  intes = Open "/tmp/blocco_header" For Create
+
  intes = Open "/tmp/blocco_header" For Create
  bb.Write(intes, 0, 4)
+
  bb.Write(intes, 0, 4)
  Write #intes, Lof(dg) + 36 As Integer
+
  Write #intes, Lof(dg) + 36 As Integer
  bb.Write(intes, 8, 32)
+
  bb.Write(intes, 8, 32)
  Write #intes, Lof(dg) As Integer
+
  Write #intes, Lof(dg) As Integer
  intes.Close
+
  intes.Close
   
+
  <FONT Color=gray>' ''Unisce il blocco di intestazione del file WAV ai dati audio grezzi presenti nel file "datigrezzi"''
+
  <FONT Color=gray>' ''Unisce il blocco di intestazione del file WAV ai dati audio grezzi:''</font>
' ''(in questo esempio il file WAV finale viene scritto nella cartella "/tmp"):''</font>
+
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load(dati))
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load("/tmp/datigrezzi"))
+
 
+
  End
  '''End'''
 
 
 
  
  
==Ricavare un'onda sinusoidale convertendo una nota Midi nella corrispondente frequenza sonora==
+
==Generare 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.
 
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, [[Ottenere_la_frequenza_corrispondente_ad_una_nota_Midi|calcolata la frequenza di una nota Midi]] e dai risultanti dati audio grezzi verrà creato un file wav:
+
Verrà, dunque, calcolata la frequenza di una nota Midi <SUP>&#091;[[#Note|nota 1]]&#093;</sup> e dai risultanti dati audio grezzi verrà creato un file wav:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
 
   Dim fl As File
 
   Dim fl As File
Riga 258: Riga 224:
 
   Dim dati_grezzi As Short[]
 
   Dim dati_grezzi As Short[]
 
    
 
    
  filegrezzo = "/tmp/datigrezzi"   <FONT Color=gray>' ''Percorso del file che conterrà i dati audio grezzi dell'onda''</font>
+
  filegrezzo = Temp   <FONT Color=gray>' ''Percorso del file che conterrà i dati audio grezzi dell'onda''</font>
 
        
 
        
  campionamento = 44100  <FONT Color=gray>' ''Frequenza di campionamento dell'onda''</font>
+
  campionamento = 44100  <FONT Color=gray>' ''Frequenza di campionamento dell'onda''</font>
  NotaMidi = 60          <FONT Color=gray>' ''Numero della nota Midi''</font>
+
  NotaMidi = 60          <FONT Color=gray>' ''Numero della nota Midi''</font>
  durata = 300000        <FONT Color=gray>' ''Durata''</font>
+
  durata = 300000        <FONT Color=gray>' ''Durata''</font>
  volume = 10000          <FONT Color=gray>' ''Volume audio dell'onda''</font>
+
  volume = 10000          <FONT Color=gray>' ''Volume audio dell'onda''</font>
 
    
 
    
  fl = Open filegrezzo For Create
+
  fl = Open filegrezzo For Create
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")
+
  If IsNull(fl) Then Error.Raise("Impossibile creare il file dei dati audio grezzi !")
 
    
 
    
 
  <FONT Color=gray>' ''Genera i dati audio grezzi:''</font>
 
  <FONT Color=gray>' ''Genera i dati audio grezzi:''</font>
  dati_grezzi = CreaDatiAudio(NotaMidi, durata, volume, campionamento)
+
  dati_grezzi = CreaDatiAudio(NotaMidi, durata, volume, campionamento)
 
    
 
    
  dati_grezzi.Write(fl, 0, dati_grezzi.Count)
+
  dati_grezzi.Write(fl, 0, dati_grezzi.Count)
 
    
 
    
 
  <FONT Color=gray>' ''Crea il file wav finale:''</font>
 
  <FONT Color=gray>' ''Crea il file wav finale:''</font>
  CreaFileWAV(fl)
+
  CreaFileWAV(fl, filegrezzo)
 
    
 
    
  fl.Close
+
  fl.Close
 
    
 
    
  Print "Fine creazione dell'onda e del file wav."
+
  Print "Fine creazione dell'onda e del file wav."
 
   
 
   
  '''End'''
+
  End
 
   
 
   
+
 
  '''Private''' Function CreaDatiAudio(nota As Byte, dur As Integer, ampiezza As Integer, freq_camp As Integer) As Short[]
+
  Private Function CreaDatiAudio(nota As Byte, dur As Integer, ampiezza As Integer, freq_camp As Integer) As Short[]
 
   
 
   
 
   Dim campione As Short
 
   Dim campione As Short
Riga 291: Riga 257:
 
    
 
    
 
  <FONT Color=gray>' ''Ciclo per ciascun dato campione audio:''</font>
 
  <FONT Color=gray>' ''Ciclo per ciascun dato campione audio:''</font>
  For ciclo = 1 To dur
+
  For ciclo = 1 To dur
 
  <FONT Color=gray>' ''Calcola la frequenza della nota Midi:''</font>
 
  <FONT Color=gray>' ''Calcola la frequenza della nota Midi:''</font>
    frequenza = CalcolaFrequenza(nota)
+
    frequenza = CalcolaFrequenza(nota)
 
  <FONT Color=gray>' ''Calcola il dato del campione audio:''</font>
 
  <FONT Color=gray>' ''Calcola il dato del campione audio:''</font>
    campione = ampiezza * Sin(2 * Pi * ciclo * frequenza / freq_camp)
+
    campione = ampiezza * Sin(2 * Pi * ciclo * frequenza / freq_camp)
    dati_audio.Push(campione)
+
    dati_audio.Push(campione)
  Next
+
  Next
 
    
 
    
  Return dati_audio
+
  Return dati_audio
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Function CalcolaFrequenza(numero_nota As Byte) As Float
+
  Private Function CalcolaFrequenza(numero_nota As Byte) As Float
 
    
 
    
 
  <FONT Color=gray>' ''Converte la nota Midi nella corrispondente frequenza sonora.''
 
  <FONT Color=gray>' ''Converte la nota Midi nella corrispondente frequenza sonora.''
 
  ' ''La nota di riferimento è il "Do centrale" (hz 261,63 -- nota Midi: 60).''</font>
 
  ' ''La nota di riferimento è il "Do centrale" (hz 261,63 -- nota Midi: 60).''</font>
  Return 261.63 * (2 ^ (1 / 12)) ^ (numero_nota - 60)
+
  Return 261.63 * (2 ^ (1 / 12)) ^ (numero_nota - 60)
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Procedure CreaFileWAV(wav As File)
+
  Private Procedure CreaFileWAV(wav As File, dati As String)
 
   
 
   
 
   Dim intes As File
 
   Dim intes As File
Riga 322: Riga 288:
 
      
 
      
 
  <FONT Color=gray>' ''Scrive innanzitutto il blocco di intestazione del file WAV:''</font>
 
  <FONT Color=gray>' ''Scrive innanzitutto il blocco di intestazione del file WAV:''</font>
  intes = Open "/tmp/blocco_header" For Create
+
  intes = Open "/tmp/blocco_header" For Create
  If IsNull(intes) Then Error.Raise("Impossibile scrivere il blocco d'intestazione !")
+
  If IsNull(intes) Then Error.Raise("Impossibile scrivere il blocco d'intestazione !")
 
    
 
    
  bi.Write(intes, 0, 4)
+
  bi.Write(intes, 0, 4)
  Write #intes, Lof(wav) + 36 As Integer
+
<FONT Color=gray>' ''Scrive la quantità dei dati audio grezzi + 36 byte del blocco di intestazione del futuro file WAV:''</font>
  bi.Write(intes, 8, 32)
+
  Write #intes, Lof(wav) + 36 As Integer
  Write #intes, Lof(wav) As Integer
+
  bi.Write(intes, 8, 32)
  intes.Close
+
<FONT Color=gray>' ''Scrive la sola quantità dei dati audio grezzi del futuro file WAV:''</font>
 +
  Write #intes, Lof(wav) As Integer
 +
  intes.Close
 
    
 
    
  <FONT Color=gray>' ''Unisce il blocco di intestazione del file WAV ai dati audio grezzi presenti nel file "datigrezzi"''
+
  <FONT Color=gray>' ''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"):''</font>
' ''(in questo esempio il file WAV finale viene scritto nella cartella "/tmp"):''</font>
+
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load(dati))
  File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load("/tmp/datigrezzi"))
 
 
   
 
   
  '''End'''
+
  End
 +
 
 +
 
 +
 
 +
=Note=
 +
[1] Vedere al riguardo la seguente pagina: [[Ottenere la frequenza corrispondente ad una nota Midi e viceversa]]

Versione attuale delle 18:18, 14 giu 2024

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

Mostriamo di seguito tre esempi.

Creare un'onda sinusoidale e salvare i dati in un file WAV

Creiamo un'onda sinusoidale da 8000 hertz, 8-bit, 1 canale:

Private Const AMPIEZZA As Integer = 127
Private Const FREQUENZA_ONDA As Integer = 110
Private Const CANALI As Short = 1
Private Const FREQUENZA_CAMPIONAMENTO As Integer = 8000
Private Const RISOLUZIONE As Short = 8  ' Risoluzione del campionamento audio in bit
Private Const DURATA As Integer = 10    ' Durata in secondi


Public Sub Main()
 
 Dim dati As New Byte[]

' Passa per "Indirizzo" il vettore e va a generare i dati dell'onda sinusoidale:
 Onda(dati)

' Va a generare il file WAV contenente l'onda sinusoidale:
 CreaFileWav(dati.ToString(0, dati.Count))

End


Private Function Onda(bb As Byte[])
 
 Dim i As Integer
 Dim s As Single = 1.0

 If CANALI == 2 Then s = 0.5

 For i = 0 To (DURATA * FREQUENZA_CAMPIONAMENTO) - 1
   bb.Push(AMPIEZZA * Sin(CFloat(i / FREQUENZA_CAMPIONAMENTO * FREQUENZA_ONDA * (s * Pi))))
 Next

End


Private Procedure CreaFileWav(dati_grezzi As String)
 
 Dim st As Stream
 Dim header As New Byte[44]
 
' Per scrivere i dati del blocco d'intestazione del futuro file wav, viene usata la risorsa "Memory Stream", operando sulla Proprietà ".Data" del vettore:
 st = Memory header.Data For Write
 
 Write #st, "RIFF"
 
 Write #st, dati_grezzi.Len As Integer
 
' Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del blocco dei dati audio:
 Write #st, "WAVEfmt "

' Viene aggiunto il valore della lunghezza dei dati del formato (in questo caso il PCM):
 Write #st, 16 As Integer
 
' Viene aggiunto il valore del formato audio (1 = PCM):
 Write #st, 1 As Short
 
' Viene aggiunto il numero dei canali di uscita:
 Write #st, canali As Short
 
' Viene aggiunto il valore della frequenza di campionamento:
 Write #st, FREQUENZA_CAMPIONAMENTO As Integer
 
' Viene aggiunto il valore del "Byte rate per secondo":
 Write #st, FREQUENZA_CAMPIONAMENTO * CANALI * (RISOLUZIONE / 8) As Integer

' Viene aggiunto il valore del "Block Align":
 Write #st, CANALI * RISOLUZIONE / 8 As Short
 
' Viene aggiunto il valore della risoluzione di campionamento:
 Write #st, RISOLUZIONE As Short

' Viene aggiunto l'identificativo del Blocco dei dati audio grezzi:
 Write #st, "data"
 
' Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file e relativo alla dimensione dei dati audio grezzi:
 Write #st, dati_grezzi.Len As Integer

 st.Close

' Crea il nuovo file wav:
 File.Save("/tmp/file.wav", header.ToString(0, header.Count) & dati_grezzi)

End


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 = Temp    ' 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, filegrezzo)

 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, dati As String)

 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:
 File.Save("/tmp/onda.wav", File.Load("/tmp/blocco_header") & File.Load(dati))

End


Generare 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 [nota 1] 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 = Temp   ' 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 = 300000         ' Durata
 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, filegrezzo)
  
 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, dati As String)

 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)
' Scrive la quantità dei dati audio grezzi + 36 byte del blocco di intestazione del futuro file WAV:
 Write #intes, Lof(wav) + 36 As Integer
 bi.Write(intes, 8, 32)
' Scrive la sola quantità dei dati audio grezzi del futuro file WAV:
 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(dati))

End


Note

[1] Vedere al riguardo la seguente pagina: Ottenere la frequenza corrispondente ad una nota Midi e viceversa