Visualizzare la forma d'onda di un file WAV
Vai alla navigazione
Vai alla ricerca
E' possibile visualizzare con le sole funzioni native di Gambas la forma d'onda di un file audio WAV.
Public Sub Form_Open()
Dim audioPath As String = "/percorso/del/file.wav"
Dim samplesL As New Float[]
Dim samplesR As New Float[]
Dim sampleRate, channels As Integer
With Me
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
.Arrangement = Arrange.Fill
End With
LoadWav(audioPath, samplesL, samplesR, ByRef sampleRate, ByRef channels)
' Caratteristiche del file wav caricato:
Print "Canali: "; channels
Print "Frequenza: "; sampleRate
If samplesL.Count > 0 Then
Print "Campione L[0]: "; samplesL[0]
Else
Print "Campione L[0]: Vuoto"
Endif
If samplesR.Count > 0 Then
Print "Campione R[0]: "; samplesR[0]
Else
Print "Campione R[0]: Vuoto"
Endif
' Analisi:
CalcolaAnalisi("Sinistro", samplesL)
If channels = 2 Then CalcolaAnalisi("Destro", samplesR)
' Parametri grafici:
Dim width As Integer = Min(2000, samplesL.Count)
Dim height As Integer = 300
Dim centerYL As Integer = height \ 4
Dim centerYR As Integer = (3 * height) \ 4
Dim ampMax As Integer = (height \ 4) - 10
Dim img As Image = New Image(width, height, Color.White)
' 🔴 Canale sinistro - peak rendering:
Paint.Begin(img)
Paint.LineWidth = 1
Paint.Brush = Paint.Color(Color.Red)
DisegnaCanalePeak(samplesL, width, centerYL, ampMax)
Paint.Stroke
Paint.End
' 🔵 Canale destro (se stereo):
If channels = 2 Then
Paint.Begin(img)
Paint.LineWidth = 1
Paint.Brush = Paint.Color(Color.Blue)
DisegnaCanalePeak(samplesR, width, centerYR, ampMax, True)
Paint.Stroke
Paint.End
Endif
ImageView1.Image = img
End
' ---------------------------------------------------------------------
' Disegna una forma d'onda con min-max rendering verticale
' ---------------------------------------------------------------------
Private Sub DisegnaCanalePeak(dati As Float[], width As Integer, centerY As Integer, ampMax As Integer, Optional invert As Boolean)
Dim x, i, iStart, iEnd As Integer
Dim val As Float, minVal As Float, maxVal As Float
For x = 0 To width - 1
iStart = CInt((CLong(x) * dati.Count) \ width)
iEnd = CInt((CLong(x + 1) * dati.Count) \ width) - 1
If iEnd >= dati.Count Then iEnd = dati.Count - 1
minVal = 1
maxVal = -1
For i = iStart To iEnd
val = dati[i]
If val < minVal Then minVal = val
If val > maxVal Then maxVal = val
Next
If invert Then
Paint.MoveTo(x, centerY + Int(minVal * ampMax))
Paint.LineTo(x, centerY + Int(maxVal * ampMax))
Else
Paint.MoveTo(x, centerY - Int(maxVal * ampMax))
Paint.LineTo(x, centerY - Int(minVal * ampMax))
Endif
Next
End
' ---------------------------------------------------------------------
' Calcola RMS, picco, range dinamico in dB
' ---------------------------------------------------------------------
Private Sub CalcolaAnalisi(nome As String, dati As Float[])
If dati.Count = 0 Then
Print "Canale "; nome; ": vuoto"
Return
Endif
Dim sumSq As Float = 0
Dim minVal As Float = dati[0]
Dim maxVal As Float = dati[0]
Dim i As Integer
For i = 0 To dati.Count - 1
Dim val As Float = dati[i]
sumSq += val ^ 2
If val < minVal Then minVal = val
If val > maxVal Then maxVal = val
Next
Dim rms As Float = Sqr(sumSq / dati.Count)
Dim peak As Float = Max(Abs(minVal), Abs(maxVal))
Dim rangeDB As Float = 0
If minVal <> 0 And maxVal <> 0 Then
rangeDB = 20 * Log10(Abs(maxVal / minVal))
Endif
Print "📊 Canale "; nome
Print " - RMS: "; Format$(rms, "0.000")
Print " - Picco: "; Format$(peak, "0.000")
Print " - Range dinamico: "; Format$(rangeDB, "0.0"); " dB"
End
' ---------------------------------------------------------------------
' WAV parser robusto con lettura fmt e data
' ---------------------------------------------------------------------
Private Sub LoadWav(audioPath As String, samplesL As Float[], samplesR As Float[], ByRef sampleRate As Integer, ByRef channels As Integer)
Dim f As File
Dim header As Byte[]
Dim i, fmtOffset, dataOffset As Integer
Dim fmtSize, sampleStart As Integer
Dim audioFormat, bitsPerSample, dataSize As Integer
Dim bytesPerSample, numSamples As Integer
f = Open audioPath For Read
header = New Byte[Lof(f)]
header.Read(f, 0, header.Count)
Close #f
If header.ToString(0, 4) <> "RIFF" Then Error.Raise("Non è un file WAV RIFF.")
If header.ToString(8, 4) <> "WAVE" Then Error.Raise("Formato WAV non riconosciuto.")
i = 12
While i < header.Count - 8
If header.ToString(i, 4) = "fmt " Then
fmtSize = ReadLE32(header, i + 4)
fmtOffset = i + 8
Exit
Endif
Inc i
Wend
If fmtOffset = 0 Or fmtSize < 16 Then Error.Raise("Blocco 'fmt ' non valido.")
audioFormat = ReadLE16(header, fmtOffset)
channels = ReadLE16(header, fmtOffset + 2)
sampleRate = ReadLE32(header, fmtOffset + 4)
bitsPerSample = ReadLE16(header, fmtOffset + 14)
If audioFormat <> 1 Then Error.Raise("Solo WAV PCM supportati.")
If bitsPerSample <> 16 Then Error.Raise("Solo WAV a 16 bit supportati.")
bytesPerSample = bitsPerSample \ 8
i = fmtOffset + fmtSize
While i < header.Count - 8
If header.ToString(i, 4) = "data" Then
dataSize = ReadLE32(header, i + 4)
dataOffset = i + 8
Exit
Endif
Inc i
Wend
If dataOffset = 0 Then Error.Raise("Blocco 'data' non trovato.")
sampleStart = dataOffset
numSamples = dataSize \ (bytesPerSample * channels)
For i = 0 To numSamples - 1
Dim offset As Integer = sampleStart + (i * channels * bytesPerSample)
Dim sampleL As Integer = ReadLE16(header, offset)
If sampleL > 32767 Then sampleL -= 65536
samplesL.Push(sampleL / 32768.0)
If channels = 2 Then
Dim sampleR As Integer = ReadLE16(header, offset + 2)
If sampleR > 32767 Then sampleR -= 65536
samplesR.Push(sampleR / 32768.0)
Endif
Next
End
Private Function ReadLE16(b As Byte[], index As Integer) As Integer
Return CInt(b[index]) Or Shl(CInt(b[index + 1]), 8)
End
Private Function ReadLE32(b As Byte[], index As Integer) As Integer
Return CInt(b[index]) Or Shl(CInt(b[index + 1]), 8) Or Shl(CInt(b[index + 2]), 16) Or Shl(CInt(b[index + 3]), 24)
End