Differenze tra le versioni di "Modificare la frequenza di campionamento di un file audio con l'API di Libresample e Libsndfile"

Da Gambas-it.org - Wikipedia.
 
(4 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
 
La libreria '''Libresample''', creata da Dominic Mazzoni, consente di modificare la frequenza di campionamento (''Sample Rate'') di un file audio.
 
La libreria '''Libresample''', creata da Dominic Mazzoni, consente di modificare la frequenza di campionamento (''Sample Rate'') di un file audio.
  
Per poter fruire in Gambas delle risorse della libreria ''Libresample'', bisognera installare e richiamare la libreria dinamica condivisa: "''libresample.so.1.0''"
+
Per poter fruire in Gambas delle risorse della libreria ''Libresample'', bisognera installare e richiamare la libreria condivisa: "''libresample.so.1.0'' ".
  
 
+
Nell'esempio che segue si farà uso anche della libreria "''libsndfile.so.1.0.37'' ".
Nell'esempio che segue si farà uso anche della libreria ''SndFile''.
 
 
  Library "libresample:1.0"
 
  Library "libresample:1.0"
 
   
 
   
Riga 14: Riga 13:
 
   
 
   
 
   
 
   
  Library "libsndfile:1.0.25"
+
  Library "libsndfile:1.0.37"
 
   
 
   
 
  Public Struct SF_INFO
 
  Public Struct SF_INFO
Riga 20: Riga 19:
 
   samplerate As Integer
 
   samplerate As Integer
 
   channels As Integer   
 
   channels As Integer   
   formatI As Integer
+
   format_ As Integer
 
   sections As Integer
 
   sections As Integer
 
   seekable As Integer
 
   seekable As Integer
Riga 26: Riga 25:
 
   
 
   
 
  Public Struct SF_FORMAT_INFO
 
  Public Struct SF_FORMAT_INFO
   formatI As Integer
+
   format_ As Integer
 
   name As Pointer
 
   name As Pointer
 
   extension As Pointer
 
   extension As Pointer
Riga 57: Riga 56:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim srcinfo, dstinfo As New SF_INFO
 
   Dim srcinfo, dstinfo As New SF_INFO
Riga 69: Riga 68:
 
   Dim inUsed, inused2, out, out2 As Integer
 
   Dim inUsed, inused2, out, out2 As Integer
 
   Dim extension As String
 
   Dim extension As String
   Dim FileAudioIn As String = "''/percorso/del/file/audio/originario''"
+
   Dim FileAudioIn As String = "<FONT color=darkgreen>''/percorso/del/file/audio/originario''</font>"
   Dim FileAudioOut As String = "''/percorso/del/file/audio/finale/modificato''"
+
   Dim FileAudioOut As String = "<FONT color=darkgreen>''/percorso/del/file/audio/finale/modificato''</font>"
 
   
 
   
 
  <FONT color=gray>' ''Imposta la nuova frequenza di campionamento del file audio:''</font>
 
  <FONT color=gray>' ''Imposta la nuova frequenza di campionamento del file audio:''</font>
  dstrate = 22050.00
+
  dstrate = 22050.00
  If (dstrate < 10.0) Or (dstrate > 100000.0) Then Error.Raise("Valore della frequenza di campionamento non consentita !")
+
  If (dstrate < 10.0) Or (dstrate > 100000.0) Then Error.Raise("Valore della frequenza di campionamento non consentita !")
 
      
 
      
  srcfile = sf_open(FileAudioIn, SFM_READ, srcinfo)
+
  srcfile = sf_open(FileAudioIn, SFM_READ, srcinfo)
  If IsNull(srcfile) Then Error.Raise("Impossibile aprire il file audio in entrata !")
+
  If srcfile == 0 Then Error.Raise("Impossibile aprire il file audio in entrata !")
   
+
  Print "File audio in entrata:  "; FileAudioIn
+
  Print "File audio in entrata:  "; FileAudioIn
  Print "Frequenza campionamento: "; srcinfo.samplerate; " Hertz"
+
  Print "Frequenza campionamento: "; srcinfo.samplerate; " Hertz"
  Print "Canali n.                "; srcinfo.channels
+
  Print "Canali n.                "; srcinfo.channels
 
   
 
   
  srcrate = srcinfo.samplerate
+
  srcrate = srcinfo.samplerate
 
      
 
      
  If dstrate = 0.0 Then
+
  If dstrate = 0.0 Then
    dstrate = srcrate * ratio
+
    dstrate = srcrate * ratio
  Else
+
  Else
    ratio = dstrate / srcrate
+
    ratio = dstrate / srcrate
  Endif
+
  Endif
 
      
 
      
  channels = srcinfo.channels
+
  channels = srcinfo.channels
 
   
 
   
 
  <FONT color=gray>' ''Estrae il formato del file di destinazione:''</font>
 
  <FONT color=gray>' ''Estrae il formato del file di destinazione:''</font>
  extension = File.Ext(FileAudioOut)
+
  extension = File.Ext(FileAudioOut)
  If "." & extension Then
+
  If "." & extension Then
    sf_command(Null, SFC_GET_FORMAT_MAJOR_COUNT, VarPtr(numformats), SizeOf(gb.Integer))
+
    sf_command(Null, SFC_GET_FORMAT_MAJOR_COUNT, VarPtr(numformats), SizeOf(gb.Integer))
+
    Print "\nLa libreria 'libresample' supporta "; numformats; " formati audio: "
    Print "\nLa libreria 'libresample' supporta "; numformats; " formati audio: "
+
    p = Alloc(Object.SizeOf(formatinfo))
   
+
    For i = 0 To numformats - 1
    p = Alloc(Object.SizeOf(formatinfo))
+
      formatinfo.format_ = i
+
      sf_command(Null, SFC_GET_FORMAT_MAJOR, p, Object.SizeOf(formatinfo))
    For i = 0 To numformats - 1
+
      formatinfo = p
      formatinfo.formatI = i
+
      Print String@(formatinfo.extension); "  ";
      sf_command(Null, SFC_GET_FORMAT_MAJOR, p, Object.SizeOf(formatinfo))
+
      If Not Comp(String@(formatinfo.extension), extension) Then
     
+
        Print "\nSi sta usando "; String@(formatinfo.name); " come formato in uscita."
      formatinfo = p
+
        dstinfo.format_ = formatinfo.format_ Or (srcinfo.format_ And SF_FORMAT_SUBMASK)
     
+
        Break
      Print String@(formatinfo.extension); "  ";
+
      Endif             
       
+
    Next
      If Not Comp(String@(formatinfo.extension), extension) Then
+
    Free(p)
        Print "\nSi sta usando "; String@(formatinfo.name); " come formato in uscita."
+
  Endif
        dstinfo.formatI = formatinfo.formatI Or (srcinfo.formatI And SF_FORMAT_SUBMASK)
 
        Break
 
      Endif             
 
    Next
 
   
 
    Free(p)
 
   
 
  Endif
 
 
   
 
   
  If Not dstinfo.formatI Then
+
  If Not dstinfo.format_ Then
    If (extension) Then Error.Raise("Attenzione: il formato in uscita " & extension & " non è riconosciuto. Usare lo stesso formato del file originario !")
+
    If (extension) Then Error.Raise("Attenzione: il formato in uscita " & extension & " non è riconosciuto. Usare lo stesso formato del file originario !")
    dstinfo.formatI = srcinfo.formatI
+
    dstinfo.format_ = srcinfo.format_
  Endif
+
  Endif
 
      
 
      
  dstinfo.samplerate = CInt(dstrate + 0.5)
+
  dstinfo.samplerate = CInt(dstrate + 0.5)
  dstinfo.channels = channels
+
  dstinfo.channels = channels
 
      
 
      
  dstfile = sf_open(FileAudioOut, SFM_WRITE, dstinfo)
+
  dstfile = sf_open(FileAudioOut, SFM_WRITE, dstinfo)
  If IsNull(dstfile) Then Error.Raise("Impossibile aprire il file audio in uscita !")
+
  If dstfile == 0 Then Error.Raise("Impossibile aprire il file audio in uscita !")
 
      
 
      
  Print "\n\nFile sorgente:    "; FileAudioIn; " ("; srcinfo.frames; " frames, ", srcrate; " Hz)"
+
  Print "\n\nFile sorgente:    "; FileAudioIn; " ("; srcinfo.frames; " frames, ", srcrate; " Hz)"
  Print "File destinazione: "; FileAudioOut; " ("; dstrate; " Hz, ratio = "; ratio
+
  Print "File destinazione: "; FileAudioOut; " ("; dstrate; " Hz, ratio = "; ratio
 
    
 
    
  srclen = 4096
+
  srclen = 4096
  dstlen = (srclen * ratio + 1000)
+
  dstlen = (srclen * ratio + 1000)
 
  srci = New Single[](srclen * channels * SizeOf(gb.Single))
 
  dsti = New Single[](dstlen * channels * SizeOf(gb.Single))
 
  src = New Single[](srclen * SizeOf(gb.Single))
 
  dst = New Single[](dstlen * SizeOf(gb.Single))
 
  handle = New Pointer[](channels * SizeOf(gb.Pointer))
 
 
   
 
   
  For c = 0 To channels - 1
+
  srci = New Single[](srclen * channels * SizeOf(gb.Single))
    handle[c] = resample_open(1, ratio, ratio)
+
  dsti = New Single[](dstlen * channels * SizeOf(gb.Single))
  Next
+
  src = New Single[](srclen * SizeOf(gb.Single))
 +
  dst = New Single[](dstlen * SizeOf(gb.Single))
 +
  handle = New Pointer[](channels * SizeOf(gb.Pointer))
 
   
 
   
  While pos < srcinfo.frames
+
  For c = 0 To channels - 1
     
+
    handle[c] = resample_open(1, ratio, ratio)
    block = Min(srclen - bufferpos, srcinfo.frames - pos)
+
  Next
    lastFlag = (pos + block == srcinfo.frames)
 
   
 
    sf_readf_float(srcfile, srci, block)
 
    block += bufferpos
 
     
 
    For c = 0 To channels - 1
 
      For i = 0 To block - 1
 
        src[i] = srci[i * channels + c]
 
      Next
 
      inUsed = 0
 
      out = resample_process(handle[c], ratio, src, block, lastFlag, VarPtr(inUsed), dst, dstlen)
 
      If c = 0
 
        inUsed2 = inUsed
 
        out2 = out
 
      Else
 
        If (inUsed2 <> inUsed) Or (out2 <> out) Then Error.Raise("Grave errore: canali fuori sincronizzazione !")
 
      Endif
 
 
      For i = 0 To out - 1
 
        If dst[i] <= -1 Then
 
          dsti[i * channels + c] = -1
 
        Else If dst[i] >= 1
 
          dsti[i * channels + c] = 1
 
        Else
 
          dsti[i * channels + c] = dst[i]
 
        Endif
 
      Next
 
         
 
    Next
 
 
    sf_writef_float(dstfile, dsti, out)
 
 
    bufferpos = block - inUsed
 
     
 
    For i = 0 To i < (bufferpos * channels) - 1
 
      srci[i] = srci[i + (inUsed * channels)]
 
      pos += inUsed
 
      outcount += out
 
    Next
 
     
 
  Wend
 
 
   
 
   
 +
  While pos < srcinfo.frames
 +
    block = Min(srclen - bufferpos, srcinfo.frames - pos)
 +
    lastFlag = (pos + block == srcinfo.frames)
 +
    sf_readf_float(srcfile, srci, block)
 +
    block += bufferpos
 +
    For c = 0 To channels - 1
 +
      For i = 0 To block - 1
 +
        src[i] = srci[i * channels + c]
 +
      Next
 +
      inUsed = 0
 +
      out = resample_process(handle[c], ratio, src, block, lastFlag, VarPtr(inUsed), dst, dstlen)
 +
      If c = 0
 +
        inUsed2 = inUsed
 +
        out2 = out
 +
      Else
 +
        If (inUsed2 <> inUsed) Or (out2 <> out) Then Error.Raise("Grave errore: canali fuori sincronizzazione !")
 +
      Endif
 +
      For i = 0 To out - 1
 +
        If dst[i] <= -1 Then
 +
          dsti[i * channels + c] = -1
 +
        Else If dst[i] >= 1
 +
          dsti[i * channels + c] = 1
 +
        Else
 +
          dsti[i * channels + c] = dst[i]
 +
        Endif
 +
      Next
 +
    Next
 +
    sf_writef_float(dstfile, dsti, out)
 +
    bufferpos = block - inUsed
 +
    For i = 0 To i < (bufferpos * channels) - 1
 +
      srci[i] = srci[i + (inUsed * channels)]
 +
      pos += inUsed
 +
      outcount += out
 +
    Next
 +
  Wend
 
   
 
   
 
  <FONT color=gray>' ''Va in chiusura:''</font>
 
  <FONT color=gray>' ''Va in chiusura:''</font>
  sf_close(srcfile)
+
  sf_close(srcfile)
  sf_close(dstfile)
+
  sf_close(dstfile)
 
   
 
   
  '''End'''
+
  End
 
 
  
  

Versione attuale delle 17:33, 13 gen 2024

La libreria Libresample, creata da Dominic Mazzoni, consente di modificare la frequenza di campionamento (Sample Rate) di un file audio.

Per poter fruire in Gambas delle risorse della libreria Libresample, bisognera installare e richiamare la libreria condivisa: "libresample.so.1.0 ".

Nell'esempio che segue si farà uso anche della libreria "libsndfile.so.1.0.37 ".

Library "libresample:1.0"

' void *resample_open(int highQuality, double minFactor, double maxFactor)
Private Extern resample_open(highQuality As Integer, minFactor As Float, maxFactor As Float) As Pointer

' int resample_process(void *handle, double factor, float *inBuffer, int inBufferLen, int lastFlag, int *inBufferUsed, float *outBuffer, int outBufferLen)
Private Extern resample_process(handleP As Pointer, factor As Float, inBUffer As Single[], inBufferLen As Integer, lastFlag As Integer, inBufferUsed As Pointer, outBuffer As Single[], outBufferLen As Integer) As Integer


Library "libsndfile:1.0.37"

Public Struct SF_INFO
  frames As Long
  samplerate As Integer
  channels As Integer  
  format_ As Integer
  sections As Integer
  seekable As Integer
End Struct

Public Struct SF_FORMAT_INFO
  format_ As Integer
  name As Pointer
  extension As Pointer
End Struct

Private Const SFM_READ As Integer = &10
Private Const SFM_WRITE As Integer = &20
Private Enum SFC_GET_FORMAT_MAJOR_COUNT = &1030, SFC_GET_FORMAT_MAJOR
Private Const SF_FORMAT_SUBMASK As Integer = &0000FFFF

' SNDFILE * sf_open (const char *path, int mode, SF_INFO *sfinfo)
' Open the specified file for read, write or both.
Private Extern sf_open(path As String, mode As Integer, SFinf As SF_INFO) As Pointer

' int sf_command (SNDFILE *sndfile, int command, void *data, int datasize)
' Return TRUE if fields of the SF_INFO struct are a valid combination of values.
Private Extern sf_command(snd As Pointer, command As Integer, data As Pointer, datasize As Integer)

' sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames)
' Reads the data chunk in terms of frames. Passes data in the native float format.
Private Extern sf_readf_float(snd As Pointer, ptr As Single[], frames As Long) As Long

' sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames)
' Writes the data chunk in terms of frames. Passes data in the native float format.
Private Extern sf_writef_float(snd As Pointer, ptr As Single[], frames As Long) As Long

' int sf_close (SNDFILE *sndfile)
' Close the SNDFILE and clean up all memory allocations associated with this file.
Private Extern sf_close(snd As Pointer) As Integer


Public Sub Main()

 Dim srcinfo, dstinfo As New SF_INFO
 Dim formatinfo As New SF_FORMAT_INFO
 Dim srcfile, dstfile, p As Pointer
 Dim dsti, src, dst, srci As Single[]
 Dim handle As Pointer[]
 Dim dstrate, srcrate, ratio As Float
 Dim channels, numformats, i, c, srclen, dstlen As Integer
 Dim pos, bufferpos, outcount, block, lastFlag As Integer
 Dim inUsed, inused2, out, out2 As Integer
 Dim extension As String
 Dim FileAudioIn As String = "/percorso/del/file/audio/originario"
 Dim FileAudioOut As String = "/percorso/del/file/audio/finale/modificato"

' Imposta la nuova frequenza di campionamento del file audio:
 dstrate = 22050.00
 If (dstrate < 10.0) Or (dstrate > 100000.0) Then Error.Raise("Valore della frequenza di campionamento non consentita !")
   
 srcfile = sf_open(FileAudioIn, SFM_READ, srcinfo)
 If srcfile == 0 Then Error.Raise("Impossibile aprire il file audio in entrata !")

 Print "File audio in entrata:   "; FileAudioIn
 Print "Frequenza campionamento: "; srcinfo.samplerate; " Hertz"
 Print "Canali n.                "; srcinfo.channels

 srcrate = srcinfo.samplerate
   
 If dstrate = 0.0 Then
   dstrate = srcrate * ratio
 Else
   ratio = dstrate / srcrate
 Endif
   
 channels = srcinfo.channels

' Estrae il formato del file di destinazione:
 extension = File.Ext(FileAudioOut)
 If "." & extension Then
   sf_command(Null, SFC_GET_FORMAT_MAJOR_COUNT, VarPtr(numformats), SizeOf(gb.Integer))
   Print "\nLa libreria 'libresample' supporta "; numformats; " formati audio: "
   p = Alloc(Object.SizeOf(formatinfo))
   For i = 0 To numformats - 1
     formatinfo.format_ = i
     sf_command(Null, SFC_GET_FORMAT_MAJOR, p, Object.SizeOf(formatinfo))
     formatinfo = p
     Print String@(formatinfo.extension); "  ";
     If Not Comp(String@(formatinfo.extension), extension) Then
       Print "\nSi sta usando "; String@(formatinfo.name); " come formato in uscita."
       dstinfo.format_ = formatinfo.format_ Or (srcinfo.format_ And SF_FORMAT_SUBMASK)
       Break
     Endif            
   Next
   Free(p)
 Endif

 If Not dstinfo.format_ Then
   If (extension) Then Error.Raise("Attenzione: il formato in uscita " & extension & " non è riconosciuto. Usare lo stesso formato del file originario !")
   dstinfo.format_ = srcinfo.format_
 Endif
   
 dstinfo.samplerate = CInt(dstrate + 0.5)
 dstinfo.channels = channels
   
 dstfile = sf_open(FileAudioOut, SFM_WRITE, dstinfo)
 If dstfile == 0 Then Error.Raise("Impossibile aprire il file audio in uscita !")
   
 Print "\n\nFile sorgente:     "; FileAudioIn; " ("; srcinfo.frames; " frames, ", srcrate; " Hz)"
 Print "File destinazione: "; FileAudioOut; " ("; dstrate; " Hz, ratio = "; ratio
  
 srclen = 4096
 dstlen = (srclen * ratio + 1000)

 srci = New Single[](srclen * channels * SizeOf(gb.Single))
 dsti = New Single[](dstlen * channels * SizeOf(gb.Single))
 src = New Single[](srclen * SizeOf(gb.Single))
 dst = New Single[](dstlen * SizeOf(gb.Single))
 handle = New Pointer[](channels * SizeOf(gb.Pointer))

 For c = 0 To channels - 1
   handle[c] = resample_open(1, ratio, ratio)
 Next

 While pos < srcinfo.frames
   block = Min(srclen - bufferpos, srcinfo.frames - pos)
   lastFlag = (pos + block == srcinfo.frames)
   sf_readf_float(srcfile, srci, block)
   block += bufferpos
   For c = 0 To channels - 1
     For i = 0 To block - 1
       src[i] = srci[i * channels + c]
     Next
     inUsed = 0
     out = resample_process(handle[c], ratio, src, block, lastFlag, VarPtr(inUsed), dst, dstlen)
     If c = 0
       inUsed2 = inUsed
       out2 = out
     Else
       If (inUsed2 <> inUsed) Or (out2 <> out) Then Error.Raise("Grave errore: canali fuori sincronizzazione !")
     Endif
     For i = 0 To out - 1
       If dst[i] <= -1 Then
         dsti[i * channels + c] = -1
       Else If dst[i] >= 1
         dsti[i * channels + c] = 1
       Else
         dsti[i * channels + c] = dst[i]
       Endif
     Next
   Next
   sf_writef_float(dstfile, dsti, out)
   bufferpos = block - inUsed
   For i = 0 To i < (bufferpos * channels) - 1
     srci[i] = srci[i + (inUsed * channels)]
     pos += inUsed
     outcount += out
   Next
 Wend

' Va in chiusura:
 sf_close(srcfile)
 sf_close(dstfile)

End


Riferimenti