Differenze tra le versioni di "Estrarre da un file sf2 i dati audio di ciascun suono campionato e creare un file wav"

Da Gambas-it.org - Wikipedia.
 
Riga 3: Riga 3:
 
Il file contiene, dunque, dati audio di suoni campionati che possono essere successivamente manipolati dal calcolatore per generare le restanti frequenze sonore appartenenti a quel timbro originario.
 
Il file contiene, dunque, dati audio di suoni campionati che possono essere successivamente manipolati dal calcolatore per generare le restanti frequenze sonore appartenenti a quel timbro originario.
  
Il file .sf2 è costituito, fra l'altro, da diversi blocchi comprendenti specifiche informazioni di carattere generale sul file stesso. In particolare il sub-blocco denominato "''shdr''" contiene i nomi di ciascun suono campionato e la posizione iniziale e finale dei suoi dati audio grezzi all'interno del sub-blocco "''sdtasmpl''". Quest'ultimo contiene i dati audio grezzi, dunque, di tutti i suoni campionati contenuti nel file sf2.
+
Il file .sf2 è costituito, fra l'altro, da diversi blocchi comprendenti specifiche informazioni di carattere generale sul file stesso. In particolare il sub-blocco denominato "''shdr'' " contiene i nomi di ciascun suono campionato e la posizione iniziale e finale dei suoi dati audio grezzi all'interno del sub-blocco "''sdtasmpl'' ". Quest'ultimo contiene i dati audio grezzi, dunque, di tutti i suoni campionati contenuti nel file sf2.
 
 
  
 
Mostriamo un possibile codice per estrarre da un file sf2 i dati audio grezzi di ciascun suono campionato, presenti nel file, con i quali si generarà per ciascun suono un distinto file audio wav:
 
Mostriamo un possibile codice per estrarre da un file sf2 i dati audio grezzi di ciascun suono campionato, presenti nel file, con i quali si generarà per ciascun suono un distinto file audio wav:
Riga 30: Riga 29:
 
   Dim ssff As SfSample[]
 
   Dim ssff As SfSample[]
 
   
 
   
  sf2 = "<FONT Color=gray>''/percorso/del/file.sf2''</font>"
+
  sf2 = "<FONT Color=gray>''/percorso/del/file.sf2''</font>"
 
    
 
    
  fl = Open sf2 For Read
+
  fl = Open sf2 For Read
  If IsNull(fl) Then Error.Raise("Impossibile caricare il file '" & sf2 & " ' !")
+
 
 
+
  With bb = New Byte[Lof(fl)]
  With bb = New Byte[Lof(fl)]
+
    .Read(fl, 0, Lof(fl))
    .Read(fl, 0, Lof(fl))
+
    s = .ToString(0, bb.Count)
    s = .ToString(0, bb.Count)
+
    If IsNull(s) Then Error.Raise("Il file caricato non contiene dati !")
    If IsNull(s) Then Error.Raise("Il file caricato non contiene dati !")
+
  End With
  End With
+
  bb.Clear
  bb.Clear
 
 
      
 
      
 
  <FONT Color=gray>' ''Individua la posizione del sub-Blocco 'shdr':''</font>
 
  <FONT Color=gray>' ''Individua la posizione del sub-Blocco 'shdr':''</font>
  i = InStr(s, "shdr")
+
  i = InStr(s, "shdr")
  If i = 0 Then Error.Raise("Impossibile trovare il sub-blocco 'shdr' !")
+
  If i == 0 Then Error.Raise("Impossibile trovare il sub-blocco 'shdr' !")
 
   
 
   
 
  <FONT Color=gray>' ''Individua la posizione del sub-blocco "sdtasmpl":''</font>
 
  <FONT Color=gray>' ''Individua la posizione del sub-blocco "sdtasmpl":''</font>
  i2 = InStr(s, "sdtasmpl")
+
  i2 = InStr(s, "sdtasmpl")
  If i2 = 0 Then Error.Raise("Impossibile trovare il sub-blocco 'sdtasmpl' !")
+
  If i2 == 0 Then Error.Raise("Impossibile trovare il sub-blocco 'sdtasmpl' !")
 
    
 
    
 
  <FONT Color=gray>' ''Individua la quantità di byte che compongono l'intero blocco 'shdr':''</font>
 
  <FONT Color=gray>' ''Individua la quantità di byte che compongono l'intero blocco 'shdr':''</font>
  Seek #fl, i + 3
+
  Seek #fl, i + 3
  j = Read #fl As Integer
+
  j = Read #fl As Integer
 
    
 
    
 
  <FONT Color=gray>' ''Raccoglie ad ogni ciclo 46 byte contenenti i vari elementi del suono campionato, rappresentati dai membri della "Struttura".''
 
  <FONT Color=gray>' ''Raccoglie ad ogni ciclo 46 byte contenenti i vari elementi del suono campionato, rappresentati dai membri della "Struttura".''
  ' ''In particolare serviranno in seguito i seguenti 4 membri: nome del suono campionato, byte iniziale del suono campionato dall'inizio dei dati audio del sotto-blocco "sdtasmpl",''
+
  ' ''In particolare serviranno in seguito i seguenti 4 membri: nome del suono campionato, byte iniziale del suono campionato dall'inizio dei dati audio del sotto-blocco "sdtasmpl", byte finale del suono campionato e frequenza di campionamento dei dati del campione. Va precisato che la dimensione del suono campionato, data dalla sottrazione dei membri della Struttura ".dWEnd" e ".dwStart" è espressa in dati di campionamento, i quali hanno sempre una risoluzione a 16 bit.''</font>
' ''byte finale del suono campionato e frequenza di campionamento dei dati del campione. Va precisato che la dimensione del suono campionato, data dalla sottrazione''
+
  ssff = New SfSample[]
' ''dei membri della Struttura ".dWEnd" e ".dwStart" è espressa in dati di campionamento, i quali hanno sempre una risoluzione a 16 bit:''</font>
 
  ssff = New SfSample[]
 
 
   
 
   
  While Seek(fl) < j + i
+
  While Seek(fl) < j + i
 
+
    sfS = New SfSample
    sfS = New SfSample
+
    With sfS
 
+
      .achSampleName.Read(fl, 0, 20)
    With sfS
+
      .dwStart = Read #fl As Integer
      .achSampleName.Read(fl, 0, 20)
+
      .dwEnd = Read #fl As Integer
      .dwStart = Read #fl As Integer
+
      .dwStartLoop = Read #fl As Integer
      .dwEnd = Read #fl As Integer
+
      .dwEndLoop = Read #fl As Integer
      .dwStartLoop = Read #fl As Integer
+
      .dwSampleRate = Read #fl As Integer
      .dwEndLoop = Read #fl As Integer
+
      .byOriginalPitch = Read #fl As Byte
      .dwSampleRate = Read #fl As Integer
+
      .chPitchCorrection = Read #fl As Byte
      .byOriginalPitch = Read #fl As Byte
+
      .wSampleLink = Read #fl As Short
      .chPitchCorrection = Read #fl As Byte
+
      .sfSampleType = Read #fl As Short
      .wSampleLink = Read #fl As Short
+
    End With
      .sfSampleType = Read #fl As Short
+
    ssff.Add(sfS)
    End With
+
  Wend
   
 
    ssff.Add(sfS)
 
   
 
  Wend
 
 
    
 
    
 
  <FONT Color=gray>' ''Elimina l'ultima variabile di tipo "Struttura", poiché contenente i dati terminale del blocco 'shdr' che sono non significativi:''</font>
 
  <FONT Color=gray>' ''Elimina l'ultima variabile di tipo "Struttura", poiché contenente i dati terminale del blocco 'shdr' che sono non significativi:''</font>
  ssff.Remove(ssff.Max)
+
  ssff.Remove(ssff.Max)
 
    
 
    
 
  <FONT Color=gray>' ''Mostra i nomi ad alcune caratteristiche dei suoni campionati presenti nel file sf2:''</font>
 
  <FONT Color=gray>' ''Mostra i nomi ad alcune caratteristiche dei suoni campionati presenti nel file sf2:''</font>
  Print "Suoni campionati presenti nel file: "; File.Name(sf2)
+
  Print "Suoni campionati presenti nel file: "; File.Name(sf2)
 
    
 
    
  For j = 0 To ssff.Max
+
  For j = 0 To ssff.Max
    Print "\nSuono campionato n. "; j; ":"
+
    Print "\nSuono campionato n. "; j; ":"
    With ssff[j]
+
    With ssff[j]
      Print "  - nome assegnato: "; .achSampleName.ToString()
+
      Print "  - nome assegnato: "; .achSampleName.ToString()
      Print "  - frequenza campionamento: "; .dwSampleRate;; "hertz"
+
      Print "  - frequenza campionamento: "; .dwSampleRate;; "hertz"
      Print "  - dimensione: "; (.dwEnd - .dwStart) * 2;; "byte"
+
      Print "  - dimensione: "; (.dwEnd - .dwStart) * 2;; "byte"
    End With
+
    End With
      
+
     CreaFileWAV(fl, ssff[j])
    CreaFileWAV(fl, ssff[j])
+
  Next
   
 
  Next
 
 
    
 
    
  fl.Close   
+
  fl.Close   
 
    
 
    
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Private''' Procedure CreaFileWAV(camp As File, sf As SfSample)
 
  '''Private''' Procedure CreaFileWAV(camp As File, sf As SfSample)
Riga 110: Riga 99:
 
   Dim dmn As Integer
 
   Dim dmn As Integer
 
    
 
    
  wav = Open "/tmp" &/ sf.achSampleName.ToString() & ".wav" For Create
+
  wav = Open "/tmp" &/ sf.achSampleName.ToString() & ".wav" For Create
 
    
 
    
  dmn = (sf.dwEnd - sf.dwStart) * SizeOf(gb.Short)
+
  dmn = (sf.dwEnd - sf.dwStart) * SizeOf(gb.Short)
 
    
 
    
  Seek #camp, sf.dwStart * SizeOf(gb.Short)
+
  Seek #camp, sf.dwStart * SizeOf(gb.Short)
 
   
 
   
 
  <FONT Color=gray>' ''Comincia a scrivere il blocco d'intestazione del futuro file wav:''</font>
 
  <FONT Color=gray>' ''Comincia a scrivere il blocco d'intestazione del futuro file wav:''</font>
  Write #wav, "RIFF"
+
  Write #wav, "RIFF"
   
+
 
 
  <FONT Color=gray>' ''Continua ad aggiungere altri elementi costituenti il blocco d'intestazione del futuro file wav:''</font>
 
  <FONT Color=gray>' ''Continua ad aggiungere altri elementi costituenti il blocco d'intestazione del futuro file wav:''</font>
  Write #wav, (dmn) + 36 As Integer
+
  Write #wav, dmn + 36 As Integer
  bb = New Byte[]
+
  bb = New Byte[]
  bb = [&57, &41, &56, &45, &66, &6D, &74, &20, 16, 0, 0, 0, 1, 0, 1, 0]
+
  bb = [&57, &41, &56, &45, &66, &6D, &74, &20, 16, 0, 0, 0, 1, 0, 1, 0]
  bb.Write(wav, 0, bb.Count)
+
  bb.Write(wav, 0, bb.Count)
  bb.Clear
+
  bb.Clear
 
    
 
    
  Write #wav, sf.dwSampleRate As Integer
+
  Write #wav, sf.dwSampleRate As Integer
  Write #wav, sf.dwSampleRate * 2 As Integer
+
  Write #wav, sf.dwSampleRate * 2 As Integer
 
    
 
    
  bb = [2, 0, 16, 0, &64, &61, &74, &61]
+
  bb = [2, 0, 16, 0, &64, &61, &74, &61]
  bb.Write(wav, 0, bb.Count)
+
  bb.Write(wav, 0, bb.Count)
  bb.Clear
+
  bb.Clear
 
    
 
    
  Write #wav, dmn As Integer
+
  Write #wav, dmn As Integer
 
    
 
    
  bb = New Byte[dmn * 2]
+
  bb = New Byte[dmn * 2]
+
  bb.Read(camp, 0, dmn)
  bb.Read(camp, 0, dmn)
+
  bb.Write(wav, 0, bb.Count)
  bb.Write(wav, 0, bb.Count)
 
 
    
 
    
  <FONT Color=gray>' ''Al termine dei dati audio di ciascun suono campionato facciamo avanzare il puntatore interno del file di 92 byte (46 * 16 bit),''
+
  <FONT Color=gray>' ''Al termine dei dati audio di ciascun suono campionato facciamo avanzare il puntatore interno del file di 92 byte (46 * 16 bit), poiché il valore espresso dal membro ".dwEnd" della Struttura rappresenta il primo di 46 byte di valore zero, posti dopo i dati audio del suono campionato.''
' ''poiché il valore espresso dal membro ".dwEnd" della Struttura rappresenta il primo di 46 byte di valore zero, posti dopo i dati audio del suono campionato.''
 
 
  ' ''Come già detto in precedenza tali valori, indicanti quantità di byte all'interno del sotto-blocco "sdtasmpl", vanno moltiplicati per i bit (16 bit)della risoluzione di ogni campione audio.</font>
 
  ' ''Come già detto in precedenza tali valori, indicanti quantità di byte all'interno del sotto-blocco "sdtasmpl", vanno moltiplicati per i bit (16 bit)della risoluzione di ogni campione audio.</font>
  Seek #camp, Seek(camp) + 92
+
  Seek #camp, Seek(camp) + 92
 
   
 
   
 
  '''End'''
 
  '''End'''
 
  
  

Versione attuale delle 08:06, 4 ott 2022

Un file banco di suoni di formato sf2 è semplicemente una libreria di suoni per la riproduzione di dati Midi che si basa su tabelle di suoni campionati (wavetable).

Il file contiene, dunque, dati audio di suoni campionati che possono essere successivamente manipolati dal calcolatore per generare le restanti frequenze sonore appartenenti a quel timbro originario.

Il file .sf2 è costituito, fra l'altro, da diversi blocchi comprendenti specifiche informazioni di carattere generale sul file stesso. In particolare il sub-blocco denominato "shdr " contiene i nomi di ciascun suono campionato e la posizione iniziale e finale dei suoi dati audio grezzi all'interno del sub-blocco "sdtasmpl ". Quest'ultimo contiene i dati audio grezzi, dunque, di tutti i suoni campionati contenuti nel file sf2.

Mostriamo un possibile codice per estrarre da un file sf2 i dati audio grezzi di ciascun suono campionato, presenti nel file, con i quali si generarà per ciascun suono un distinto file audio wav:

Public Struct sfSample
  achSampleName[20] As Byte
  dwStart As Integer
  dwEnd As Integer
  dwStartLoop As Integer
  dwEndLoop As Integer
  dwSampleRate As Integer
  byOriginalPitch As Byte
  chPitchCorrection As Byte
  wSampleLink As Short
  sfSampleType As Short
End Struct


Public Sub Main()
   
 Dim fl As File
 Dim sf2, s As String
 Dim bb As Byte[]
 Dim i, j, i2 As Integer
 Dim sfS As SfSample
 Dim ssff As SfSample[]

 sf2 = "/percorso/del/file.sf2"
  
 fl = Open sf2 For Read
 
 With bb = New Byte[Lof(fl)]
   .Read(fl, 0, Lof(fl))
   s = .ToString(0, bb.Count)
   If IsNull(s) Then Error.Raise("Il file caricato non contiene dati !")
 End With
 bb.Clear
    
' Individua la posizione del sub-Blocco 'shdr':
 i = InStr(s, "shdr")
 If i == 0 Then Error.Raise("Impossibile trovare il sub-blocco 'shdr' !")

' Individua la posizione del sub-blocco "sdtasmpl":
 i2 = InStr(s, "sdtasmpl")
 If i2 == 0 Then Error.Raise("Impossibile trovare il sub-blocco 'sdtasmpl' !")
 
' Individua la quantità di byte che compongono l'intero blocco 'shdr':
 Seek #fl, i + 3
 j = Read #fl As Integer
 
' Raccoglie ad ogni ciclo 46 byte contenenti i vari elementi del suono campionato, rappresentati dai membri della "Struttura".
' In particolare serviranno in seguito i seguenti 4 membri: nome del suono campionato, byte iniziale del suono campionato dall'inizio dei dati audio del sotto-blocco "sdtasmpl", byte finale del suono campionato e frequenza di campionamento dei dati del campione. Va precisato che la dimensione del suono campionato, data dalla sottrazione dei membri della Struttura ".dWEnd" e ".dwStart" è espressa in dati di campionamento, i quali hanno sempre una risoluzione a 16 bit.
 ssff = New SfSample[]

 While Seek(fl) < j + i
   sfS = New SfSample
   With sfS
     .achSampleName.Read(fl, 0, 20)
     .dwStart = Read #fl As Integer
     .dwEnd = Read #fl As Integer
     .dwStartLoop = Read #fl As Integer
     .dwEndLoop = Read #fl As Integer
     .dwSampleRate = Read #fl As Integer
     .byOriginalPitch = Read #fl As Byte
     .chPitchCorrection = Read #fl As Byte
     .wSampleLink = Read #fl As Short
     .sfSampleType = Read #fl As Short
   End With
   ssff.Add(sfS)
 Wend
  
' Elimina l'ultima variabile di tipo "Struttura", poiché contenente i dati terminale del blocco 'shdr' che sono non significativi:
 ssff.Remove(ssff.Max)
 
' Mostra i nomi ad alcune caratteristiche dei suoni campionati presenti nel file sf2:
 Print "Suoni campionati presenti nel file: "; File.Name(sf2)
  
 For j = 0 To ssff.Max
   Print "\nSuono campionato n. "; j; ":"
   With ssff[j]
     Print "  - nome assegnato: "; .achSampleName.ToString()
     Print "  - frequenza campionamento: "; .dwSampleRate;; "hertz"
     Print "  - dimensione: "; (.dwEnd - .dwStart) * 2;; "byte"
   End With
   CreaFileWAV(fl, ssff[j])
 Next
  
 fl.Close  
 
End

Private Procedure CreaFileWAV(camp As File, sf As SfSample)

 Dim wav As File
 Dim bb As Byte[]
 Dim dmn As Integer
 
 wav = Open "/tmp" &/ sf.achSampleName.ToString() & ".wav" For Create
  
 dmn = (sf.dwEnd - sf.dwStart) * SizeOf(gb.Short)
  
 Seek #camp, sf.dwStart * SizeOf(gb.Short)

' Comincia a scrivere il blocco d'intestazione del futuro file wav:
 Write #wav, "RIFF"
  
' Continua ad aggiungere altri elementi costituenti il blocco d'intestazione del futuro file wav:
 Write #wav, dmn + 36 As Integer
 bb = New Byte[]
 bb = [&57, &41, &56, &45, &66, &6D, &74, &20, 16, 0, 0, 0, 1, 0, 1, 0]
 bb.Write(wav, 0, bb.Count)
 bb.Clear
 
 Write #wav, sf.dwSampleRate As Integer
 Write #wav, sf.dwSampleRate * 2 As Integer
 
 bb = [2, 0, 16, 0, &64, &61, &74, &61]
 bb.Write(wav, 0, bb.Count)
 bb.Clear
  
 Write #wav, dmn As Integer
  
 bb = New Byte[dmn * 2]
 bb.Read(camp, 0, dmn)
 bb.Write(wav, 0, bb.Count)
  
' Al termine dei dati audio di ciascun suono campionato facciamo avanzare il puntatore interno del file di 92 byte (46 * 16 bit), poiché il valore espresso dal membro ".dwEnd" della Struttura rappresenta il primo di 46 byte di valore zero, posti dopo i dati audio del suono campionato.
' Come già detto in precedenza tali valori, indicanti quantità di byte all'interno del sotto-blocco "sdtasmpl", vanno moltiplicati per i bit (16 bit)della risoluzione di ogni campione audio.
 Seek #camp, Seek(camp) + 92

End


Riferimenti