mirror of
https://github.com/cgzirim/seek-tune.git
synced 2025-12-17 08:54:19 +00:00
refactor: improve comments and variable names for clarity.
This commit is contained in:
parent
1e5e42e1dc
commit
5411913a98
4 changed files with 12 additions and 17 deletions
|
|
@ -4,20 +4,20 @@ import (
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fft performs the Fast Fourier Transform on the input signal.
|
// FFT computes the Fast Fourier Transform (FFT) of the input data,
|
||||||
|
// converting the signal from the time domain to the frequency domain.
|
||||||
|
// For better understanding, refer to this video: https://www.youtube.com/watch?v=spUNpyF58BY
|
||||||
func FFT(input []float64) []complex128 {
|
func FFT(input []float64) []complex128 {
|
||||||
// Convert input to complex128
|
|
||||||
complexArray := make([]complex128, len(input))
|
complexArray := make([]complex128, len(input))
|
||||||
for i, v := range input {
|
for i, v := range input {
|
||||||
complexArray[i] = complex(v, 0)
|
complexArray[i] = complex(v, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fftResult := make([]complex128, len(complexArray))
|
fftResult := make([]complex128, len(complexArray))
|
||||||
copy(fftResult, complexArray) // Copy input to result buffer
|
copy(fftResult, complexArray)
|
||||||
return recursiveFFT(fftResult)
|
return recursiveFFT(fftResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursiveFFT performs the recursive FFT algorithm.
|
|
||||||
func recursiveFFT(complexArray []complex128) []complex128 {
|
func recursiveFFT(complexArray []complex128) []complex128 {
|
||||||
N := len(complexArray)
|
N := len(complexArray)
|
||||||
if N <= 1 {
|
if N <= 1 {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fingerprint generates fingerprints from a list of peaks and stores them in an array.
|
// Fingerprint generates fingerprints from a list of peaks and stores them in an array.
|
||||||
// The fingerprints are encoded using a 32-bit integer format and stored in an array.
|
|
||||||
// Each fingerprint consists of an address and a couple.
|
// Each fingerprint consists of an address and a couple.
|
||||||
// The address is a hash. The couple contains the anchor time and the song ID.
|
// The address is a hash. The couple contains the anchor time and the song ID.
|
||||||
func Fingerprint(peaks []Peak, songID uint32) map[uint32]models.Couple {
|
func Fingerprint(peaks []Peak, songID uint32) map[uint32]models.Couple {
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,9 @@ import (
|
||||||
|
|
||||||
// ConvertSpectrogramToImage converts a spectrogram to a heat map image
|
// ConvertSpectrogramToImage converts a spectrogram to a heat map image
|
||||||
func SpectrogramToImage(spectrogram [][]complex128, outputPath string) error {
|
func SpectrogramToImage(spectrogram [][]complex128, outputPath string) error {
|
||||||
// Determine dimensions of the spectrogram
|
|
||||||
numWindows := len(spectrogram)
|
numWindows := len(spectrogram)
|
||||||
numFreqBins := len(spectrogram[0])
|
numFreqBins := len(spectrogram[0])
|
||||||
|
|
||||||
// Create a new grayscale image
|
|
||||||
img := image.NewGray(image.Rect(0, 0, numFreqBins, numWindows))
|
img := image.NewGray(image.Rect(0, 0, numFreqBins, numWindows))
|
||||||
|
|
||||||
// Scale the values in the spectrogram to the range [0, 255]
|
// Scale the values in the spectrogram to the range [0, 255]
|
||||||
|
|
@ -38,7 +36,6 @@ func SpectrogramToImage(spectrogram [][]complex128, outputPath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the image to a PNG file
|
|
||||||
file, err := os.Create(outputPath)
|
file, err := os.Create(outputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,18 @@ const (
|
||||||
hopSize = freqBinSize / 32
|
hopSize = freqBinSize / 32
|
||||||
)
|
)
|
||||||
|
|
||||||
func Spectrogram(samples []float64, sampleRate int) ([][]complex128, error) {
|
func Spectrogram(sample []float64, sampleRate int) ([][]complex128, error) {
|
||||||
lpf := NewLowPassFilter(maxFreq, float64(sampleRate))
|
lpf := NewLowPassFilter(maxFreq, float64(sampleRate))
|
||||||
filteredSamples := lpf.Filter(samples)
|
filteredSample := lpf.Filter(sample)
|
||||||
|
|
||||||
downsampledSamples, err := Downsample(filteredSamples, sampleRate, sampleRate/dspRatio)
|
downsampledSample, err := Downsample(filteredSample, sampleRate, sampleRate/dspRatio)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't downsample audio samples: %v", err)
|
return nil, fmt.Errorf("couldn't downsample audio sample: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
numOfWindows := len(downsampledSamples) / (freqBinSize - hopSize)
|
numOfWindows := len(downsampledSample) / (freqBinSize - hopSize)
|
||||||
spectrogram := make([][]complex128, numOfWindows)
|
spectrogram := make([][]complex128, numOfWindows)
|
||||||
|
|
||||||
// Apply Hamming window function
|
|
||||||
window := make([]float64, freqBinSize)
|
window := make([]float64, freqBinSize)
|
||||||
for i := range window {
|
for i := range window {
|
||||||
window[i] = 0.54 - 0.46*math.Cos(2*math.Pi*float64(i)/(float64(freqBinSize)-1))
|
window[i] = 0.54 - 0.46*math.Cos(2*math.Pi*float64(i)/(float64(freqBinSize)-1))
|
||||||
|
|
@ -36,12 +35,12 @@ func Spectrogram(samples []float64, sampleRate int) ([][]complex128, error) {
|
||||||
for i := 0; i < numOfWindows; i++ {
|
for i := 0; i < numOfWindows; i++ {
|
||||||
start := i * hopSize
|
start := i * hopSize
|
||||||
end := start + freqBinSize
|
end := start + freqBinSize
|
||||||
if end > len(downsampledSamples) {
|
if end > len(downsampledSample) {
|
||||||
end = len(downsampledSamples)
|
end = len(downsampledSample)
|
||||||
}
|
}
|
||||||
|
|
||||||
bin := make([]float64, freqBinSize)
|
bin := make([]float64, freqBinSize)
|
||||||
copy(bin, downsampledSamples[start:end])
|
copy(bin, downsampledSample[start:end])
|
||||||
|
|
||||||
// Apply Hamming window
|
// Apply Hamming window
|
||||||
for j := range window {
|
for j := range window {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue