Calcolare la potenza di picco e di ampiezza di un file WAV con le funzioni esterne del API di Libaudiofile

Da Gambas-it.org - Wikipedia.
Versione del 30 ott 2024 alle 07:57 di Vuott (Discussione | contributi)

(diff) ← Versione meno recente | Versione attuale (diff) | Versione più recente → (diff)

La libreria Libaudiofile consente la lettura e la scrittura di file audio in diversi formati comuni, astraendo i dettagli dei formati di file AIFC, AIFF, AU, VOC, WAV e altri.

Per poter fruire in Gambas delle risorse di questa libreria, sarà necessario installare la libreria condivisa: "libaudiofile.so.1.0.0 ".

Mostriamo di seguito un esempio per calcolare la potenza di picco e di ampiezza di un file WAV:

Public Struct smooth
  buf As Float[]
  lungh As Integer
  start As Integer
  n As Integer
End Struct


Library "libaudiofile:1.0.0"

Private Const AF_DEFAULT_TRACK As Integer = 1001
Private Const AF_SAMPFMT_DOUBLE As Integer = 404

' AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
' Opens a specified audio file and creates a file handle structure.
Private Extern afOpenFile(filename As String, mode As String, setup As Pointer) As Pointer

' int afGetChannels (AFfilehandle, int track)
' Get the number of interleaved track from an AFfilehandle structure for an audio track.
Private Extern afGetChannels(AFfile As Pointer, track As Integer) As Integer

' double afGetRate(AFfilehandle file, int track)
' Get the track sample rate for a specified audio track from an AFfilehandle structure.
Private Extern afGetRate(AFfile As Pointer, track As Integer) As Float

' AFframecount afGetFrameCount (AFfilehandle file, int track)
' Get the total sample frame count for a specified audio track from an AFfilehandle structure.
Private Extern afGetFrameCount(AFfile As Pointer, track As Integer) As Long

' int afSetVirtualSampleFormat (AFfilehandle, int track, int sampleFormat, int sampleWidth)
' Set the virtual data format for a specified audio track.
Private Extern afSetVirtualSampleFormat(AFfile As Pointer, track As Integer, sampleFormat As Integer, sampleWidth As Integer) As Integer

' int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount)
' Read sample frames from a track in an audio file.
Private Extern afReadFrames(AFfile As Pointer, track As Integer, buffer As Float[], frameCount As Integer) As Integer

' int afCloseFile (AFfilehandle file)
' Closes an open audio file, updating the file if it was opened for writing.
Private Extern afCloseFile(AFfile As Pointer) As Integer

 
Public Sub Main()

  Dim nomefile As String
  Dim fl As Pointer
  Dim canali, windowSize, frameCount As Integer
  Dim i, c, winStart, winEnd, fine As Integer
  Dim powsmooth As New Smooth[]
  Dim lastWindow As Boolean
  Dim frames, sums As Float[]
  Dim frequenza, sample, pow, maxpow, durata As Float
  Dim livello, picco, minSample, maxSample As Float
   
   
  nomefile = "/percorso/del/file.wav"
  minSample = 1
  maxSample = -1
  
  fl = afOpenFile(nomefile, "r", 0)
  If fl == 0 Then Error.Raise("Impossibile aprire il file audio !")
   
  canali = afGetChannels(fl, AF_DEFAULT_TRACK)
  
  frequenza = afGetRate(fl, AF_DEFAULT_TRACK)

  durata = afGetFrameCount(fl, AF_DEFAULT_TRACK) / afGetRate(fl, AF_DEFAULT_TRACK)

  windowSize = CInt(frequenza / 100)
   
  frameCount = CInt(afGetFrameCount(fl, AF_DEFAULT_TRACK))
   
  afSetVirtualSampleFormat(fl, AF_DEFAULT_TRACK, AF_SAMPFMT_DOUBLE, SizeOf(gb.Float))
   
  powsmooth = New Smooth[canali]

  For c = 0 To canali - 1
    With powsmooth[c] = New Smooth
      .lungh = 100
      .buf = New Float[powsmooth[c].lungh * SizeOf(gb.Float)]
      .start = 0
      .n = 0
    End With
  Next

  Repeat
     
    winEnd = winStart + windowSize
    If winEnd >= frameCount Then 
      winEnd = frameCount
      lastWindow = True
    Endif
    frames = New Float[canali * windowSize]
    afReadFrames(fl, AF_DEFAULT_TRACK, frames, windowSize)
    sums = New Float[canali]
    For c = 0 To canali - 1
      sums[c] = 0
      For i = 0 To (winEnd - winStart) - 1
        sample = frames[i * canali + c]
        sums[c] += sample * sample
        If (sample > maxSample) Then maxSample = sample
        If (sample < minSample) Then minSample = sample
      Next
    Next

' Calcola la potenza di ciascun canale:
    For c = 0 To canali - 1
      pow = sums[c] / (winEnd - winStart)
      fine = (powsmooth[c].start + powsmooth[c].n) % powsmooth[c].lungh
      powsmooth[c].buf[fine] = pow
      If powsmooth[c].n = powsmooth[c].lungh Then
        powsmooth[c].start = (powsmooth[c].start + 1) % powsmooth[c].lungh
        pow = Dati_Attenuati(powsmooth[c])
        If pow > maxpow Then maxpow = pow
      Else
        Inc powsmooth[c].n
      Endif
    Next
    winStart += windowSize
    
  Until lastWindow
   
  For c = 0 To canali - 1
    pow = Dati_Attenuati(powsmooth[c])
    If pow > maxpow Then maxpow = pow
  Next
   
  livello = Sqr(maxpow)

  afCloseFile(fl)
 
  Print "File audio: "; Null, nomefile
  Print "Frequenza: "; Null, "Hz ";frequenza
  Print "Canali: "; Null, canali
  Print "Durata: "; Null, Cstr(Date(0, 0, 0, 0, 0, 0, durata * 1000))
  Print "Livello (dB): "; Null, 20 * Log10(livello)
  Print "Picco-: "; Null, minSample
  Print "Picco+: "; Null, maxSample
   
  picco = Abs(minSample)
   
  If picco < Abs(maxSample) Then picco = Abs(maxSample)
   
  Print "Picco (dB): "; Null, 20 * Log10(picco)
 
End


Private Function Dati_Attenuati(s As Smooth) As Float
 
  Dim i As Integer
  Dim attenuato As Float

  attenuato = 0
  For i = 0 To s.n - 1
    attenuato += s.buf[i]
  Next
  attenuato = attenuato / s.n

  Return attenuato

End


Riferimenti