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 }