package mic import ( "encoding/binary" "errors" ) const ( SampleRate = 16000 Channels = 1 BitsPerSample = 16 BytesPerSample = BitsPerSample / 8 * Channels ) var wavHeaderSize = 44 // EncodeWAV wraps 16-bit mono PCM in a complete WAV file. func EncodeWAV(pcm []byte) []byte { if len(pcm) == 0 { return nil } if len(pcm)%BytesPerSample != 0 { pcm = pcm[:len(pcm)-len(pcm)%BytesPerSample] } out := make([]byte, wavHeaderSize+len(pcm)) writeWAVHeader(out, len(pcm)) copy(out[wavHeaderSize:], pcm) return out } func writeWAVHeader(buf []byte, dataLen int) { if len(buf) < wavHeaderSize { return } copy(buf[0:4], "RIFF") binary.LittleEndian.PutUint32(buf[4:8], uint32(36+dataLen)) copy(buf[8:12], "WAVE") copy(buf[12:16], "fmt ") binary.LittleEndian.PutUint32(buf[16:20], 16) binary.LittleEndian.PutUint16(buf[20:22], 1) // PCM binary.LittleEndian.PutUint16(buf[22:24], Channels) binary.LittleEndian.PutUint32(buf[24:28], SampleRate) byteRate := SampleRate * Channels * BytesPerSample binary.LittleEndian.PutUint32(buf[28:32], uint32(byteRate)) binary.LittleEndian.PutUint16(buf[32:34], uint16(Channels*BytesPerSample)) binary.LittleEndian.PutUint16(buf[34:36], BitsPerSample) copy(buf[36:40], "data") binary.LittleEndian.PutUint32(buf[40:44], uint32(dataLen)) } // PCMBytesFromWAV returns PCM payload length implied by a WAV header. func PCMBytesFromWAV(hdr []byte) (int, error) { if len(hdr) < wavHeaderSize { return 0, errors.New("wav header too short") } if string(hdr[0:4]) != "RIFF" || string(hdr[8:12]) != "WAVE" { return 0, errors.New("not a wav file") } dataLen := int(binary.LittleEndian.Uint32(hdr[40:44])) return dataLen, nil }