This repository has been archived on 2019-12-11. You can view files and clone it, but cannot push or open issues/pull-requests.
jlaudio/lib/extractfreq/wip.go

144 lines
3.0 KiB
Go
Raw Permalink Normal View History

2019-12-03 20:34:29 +00:00
package extractfreq
import (
2019-12-05 20:37:16 +00:00
"fmt"
2019-12-03 20:34:29 +00:00
"log"
2019-12-07 10:18:50 +00:00
"math"
2019-12-03 20:34:29 +00:00
"math/cmplx"
"git.crumpington.com/public/jlaudio/lib/flac"
"gonum.org/v1/gonum/fourier"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
)
2019-12-07 10:18:50 +00:00
// Steps:
//
2019-12-08 19:07:15 +00:00
// * Create amplitude spectrum (abs of real FFT).
2019-12-07 10:18:50 +00:00
// * Multiply by A-weight curve
2019-12-08 19:07:15 +00:00
// * Find peaks
// * Sort peaks by amplitude
// * Use strongest peak to estimate fFundamental?
// *
2019-12-07 10:18:50 +00:00
func PlotFFT(path string, nSamples int, fFundamental float64) {
2019-12-03 20:34:29 +00:00
L, R, err := flac.Load(path)
if err != nil {
panic(err)
}
if nSamples < len(L) {
nSamples = len(L)
}
data := make([]float64, nSamples)
for i := range data {
data[i] = float64(L[i]) + float64(R[i])
}
2019-12-08 19:07:15 +00:00
// Make initial fft.
2019-12-03 20:34:29 +00:00
fft := fourier.NewFFT(nSamples)
cCoeffs := fft.Coefficients(nil, data)
amps := make([]float64, len(cCoeffs))
freqs := make([]float64, len(cCoeffs))
for i := range freqs {
freqs[i] = fft.Freq(i) * 48000
2019-12-08 19:07:15 +00:00
amps[i] = cmplx.Abs(cCoeffs[i])
2019-12-03 20:34:29 +00:00
}
2019-12-08 19:07:15 +00:00
// Trim to frequencies of interest.
deltaF := freqs[1] - freqs[0]
idx0 := int(20 / deltaF)
idx1 := int(16000 / deltaF)
freqs = freqs[idx0:idx1]
amps = amps[idx0:idx1]
2019-12-03 20:34:29 +00:00
2019-12-08 19:07:15 +00:00
// Multiply by A-weight function.
for i := range amps {
amps[i] *= AWeight(freqs[i])
}
2019-12-03 20:34:29 +00:00
2019-12-08 19:07:15 +00:00
// Find peaks.
dFreq := freqs[1] - freqs[0]
halfWinSize := int(math.Round((fFundamental / dFreq) / 3))
peakInds, peakAmps := getPeaks(halfWinSize, amps)
peakInds, peakAmps = sortPeaks(peakInds, peakAmps)
2019-12-03 20:34:29 +00:00
2019-12-07 10:18:50 +00:00
p, err := plot.New()
if err != nil {
panic(err)
}
2019-12-08 19:07:15 +00:00
fMin := float64(20)
fMax := float64(16000)
2019-12-07 10:18:50 +00:00
log.Printf("Making points...")
pts := make(plotter.XYs, 0, len(amps))
for i := range amps {
2019-12-08 19:07:15 +00:00
if freqs[i] > fMin && freqs[i] < fMax {
pts = append(pts, plotter.XY{
X: freqs[i],
Y: amps[i],
})
}
}
pts2 := make(plotter.XYs, 0, len(amps))
for i := range peakInds {
if freqs[peakInds[i]] > fMin && freqs[peakInds[i]] < fMax {
pts2 = append(pts2, plotter.XY{
X: freqs[peakInds[i]],
Y: peakAmps[i],
})
2019-12-07 10:18:50 +00:00
}
}
log.Printf("Plotting...")
2019-12-08 19:07:15 +00:00
if err = plotutil.AddScatters(p, "fft", pts, "max", pts2); err != nil {
2019-12-07 10:18:50 +00:00
panic(err)
}
2019-12-08 19:07:15 +00:00
p.Add(plotter.NewGrid())
2019-12-07 10:18:50 +00:00
log.Printf("Saving...")
if err := p.Save(16*vg.Inch, 8*vg.Inch, "fft.png"); err != nil {
panic(err)
}
2019-12-08 19:07:15 +00:00
for i, idx := range peakInds {
//amp := peakAmps[i]
2019-12-03 20:34:29 +00:00
2019-12-08 19:07:15 +00:00
// Make window.
ampsWin := amps[idx-halfWinSize : idx+halfWinSize]
freqWin := freqs[idx-halfWinSize : idx+halfWinSize]
2019-12-03 20:34:29 +00:00
2019-12-05 20:37:16 +00:00
log.Printf("Making points...")
2019-12-08 19:07:15 +00:00
pts := make(plotter.XYs, 0, 2*halfWinSize)
for i := range ampsWin {
2019-12-05 20:37:16 +00:00
pts = append(pts, plotter.XY{
2019-12-08 19:07:15 +00:00
X: freqWin[i],
Y: ampsWin[i],
2019-12-05 20:37:16 +00:00
})
}
2019-12-03 20:34:29 +00:00
2019-12-05 20:37:16 +00:00
log.Printf("Plotting...")
2019-12-08 19:07:15 +00:00
p, err := plot.New()
if err != nil {
panic(err)
}
2019-12-05 20:37:16 +00:00
if err = plotutil.AddLines(p, "fft", pts); err != nil {
panic(err)
}
//p.Y.Scale = plot.LogScale{}
//p.X.Scale = plot.LogScale{}
log.Printf("Saving...")
2019-12-08 19:07:15 +00:00
filename := fmt.Sprintf("plot-%03d.png", i)
2019-12-05 20:37:16 +00:00
if err := p.Save(8*vg.Inch, 8*vg.Inch, filename); err != nil {
panic(err)
}
2019-12-03 20:34:29 +00:00
}
}