Files

114 lines
2.6 KiB
Go

package wav
import (
"fmt"
"os"
"valhallir-deconvolver/pkg/convolve"
"github.com/go-audio/audio"
"github.com/go-audio/wav"
)
// WAVData represents the PCM data and metadata from a WAV file
type WAVData struct {
SampleRate int
BitDepth int
Channels int
PCMData []float64
}
// toMono averages all channels to mono
func toMono(data []float64, channels int) []float64 {
if channels == 1 {
return data
}
mono := make([]float64, len(data)/channels)
for i := 0; i < len(mono); i++ {
sum := 0.0
for c := 0; c < channels; c++ {
sum += data[i*channels+c]
}
mono[i] = sum / float64(channels)
}
return mono
}
// ReadWAVFile reads a WAV file and returns its PCM data as float64 (resampled to 96kHz mono)
func ReadWAVFile(filePath string) (*WAVData, error) {
// Check if path is a directory
info, err := os.Stat(filePath)
if err != nil {
return nil, fmt.Errorf("failed to access file %s: %w", filePath, err)
}
if info.IsDir() {
return nil, fmt.Errorf("path %s is a directory, not a WAV file", filePath)
}
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("failed to open file %s: %w", filePath, err)
}
defer file.Close()
decoder := wav.NewDecoder(file)
if !decoder.IsValidFile() {
return nil, fmt.Errorf("file %s is not a valid WAV file", filePath)
}
// Read all PCM data
var pcmData []int32
buf := &audio.IntBuffer{Data: make([]int, 4096), Format: &audio.Format{SampleRate: int(decoder.SampleRate), NumChannels: int(decoder.NumChans)}}
for {
n, err := decoder.PCMBuffer(buf)
if err != nil {
break
}
if n == 0 {
break
}
// Convert int samples to float64
for i := 0; i < n; i++ {
pcmData = append(pcmData, int32(buf.Data[i]))
}
}
// Convert int32 to float64 (-1.0 to 1.0 range, scale by bit depth)
floatData := make([]float64, len(pcmData))
var norm float64
if decoder.BitDepth == 16 {
norm = float64(1 << 15)
} else if decoder.BitDepth == 24 {
norm = float64(1 << 23)
} else if decoder.BitDepth == 32 {
norm = float64(1 << 31)
} else {
norm = float64(1 << 23) // fallback
}
for i, sample := range pcmData {
floatData[i] = float64(sample) / norm
}
// Convert to mono if needed
channels := int(decoder.NumChans)
if channels > 1 {
floatData = toMono(floatData, channels)
channels = 1
}
// Resample to 96kHz if needed
inSampleRate := int(decoder.SampleRate)
if inSampleRate != 96000 {
floatData = convolve.Resample(floatData, inSampleRate, 96000)
}
return &WAVData{
SampleRate: 96000,
BitDepth: int(decoder.BitDepth), // original bit depth
Channels: 1,
PCMData: floatData,
}, nil
}