Files
tia-love/internal/audio/wav.go
T

52 lines
1.5 KiB
Go

package audio
import (
"encoding/binary"
"errors"
"fmt"
)
// ParsePCM memvalidasi file WAV (RIFF) dan mengembalikan isi chunk "data" (PCM).
// Standar aset tia (PRD Appendix C): 44.1 kHz, mono, 16-bit — selain itu ditolak
// agar kesalahan aset ketahuan saat dev, bukan saat runtime.
func ParsePCM(b []byte) ([]byte, error) {
if len(b) < 44 || string(b[0:4]) != "RIFF" || string(b[8:12]) != "WAVE" {
return nil, errors.New("bukan file RIFF/WAVE")
}
var (
format, channels, bits, rate int
data []byte
)
for off := 12; off+8 <= len(b); {
id := string(b[off : off+4])
size := int(binary.LittleEndian.Uint32(b[off+4 : off+8]))
off += 8
if size < 0 || off+size > len(b) {
return nil, fmt.Errorf("chunk %q terpotong", id)
}
switch id {
case "fmt ":
if size < 16 {
return nil, errors.New("chunk fmt terlalu pendek")
}
format = int(binary.LittleEndian.Uint16(b[off : off+2]))
channels = int(binary.LittleEndian.Uint16(b[off+2 : off+4]))
rate = int(binary.LittleEndian.Uint32(b[off+4 : off+8]))
bits = int(binary.LittleEndian.Uint16(b[off+14 : off+16]))
case "data":
data = b[off : off+size]
}
off += size + size%2 // chunk berukuran ganjil dipad 1 byte
}
if format != 1 {
return nil, fmt.Errorf("format %d bukan PCM", format)
}
if channels != 1 || bits != 16 || rate != 44100 {
return nil, fmt.Errorf("hanya mono/16-bit/44100Hz didukung (dapat %dch/%dbit/%dHz)", channels, bits, rate)
}
if len(data) == 0 {
return nil, errors.New("chunk data kosong")
}
return data, nil
}