A minimal application to print out the incoming pitch from the microphone
Over the weekend I got excited about the idea of building a singing practice app where folks can sing along to music they own and the app will allow them to sing along and score them on pitch accuracy.
This feels ambitious, so I want to celebrate every small win.
I used ChatGPT to outline and build what I needed.
The audio streaming element that captures incoming data from the microphone .
1package main
23import(4"github.com/gordonklaus/portaudio"5)67// initAudio initializes an audio stream to capture audio from the microphone.8funcinitAudio()(*portaudio.Stream,error){9 err := portaudio.Initialize()10if err !=nil{11returnnil, err
12}1314// Open the default audio device with a buffer of size 204815 stream, err := portaudio.OpenDefaultStream(1,0,44100,len(buffer),&buffer)16if err !=nil{17returnnil, err
18}19return stream,nil20}
go
the element that processes the audio using fft to read in the stream from the microphone and determine its dominant frequency.
1package main
23import(4"math/cmplx"5"gonum.org/v1/gonum/dsp/fourier"6)78funcprocessAudio(in []float32)float64{9// Convert float32 to float64 for FFT10 data :=make([]float64,len(in))11for i, v :=range in {12 data[i]=float64(v)13}1415// Create an FFT plan16 fft := fourier.NewFFT(len(data))17// This performs the FFT and returns complex coefficients18 coeff := fft.Coefficients(nil, data)1920// Find dominant frequency21returnfindDominantFrequency(coeff)22}2324funcfindDominantFrequency(coeff []complex128)float64{25 maxVal :=0.026var maxIdx int27for i, v :=range coeff {28if abs := cmplx.Abs(v); abs > maxVal {29 maxVal = abs
30 maxIdx = i
31}32}33 sampleRate :=44100// Define as per your setup34// Calculate frequency35returnfloat64(maxIdx)*float64(sampleRate)/float64(len(coeff))36}37