|
|
|
@@ -2,6 +2,7 @@ package recorder |
|
|
|
|
|
|
|
import ( |
|
|
|
"encoding/binary" |
|
|
|
"io" |
|
|
|
"os" |
|
|
|
) |
|
|
|
|
|
|
|
@@ -11,59 +12,62 @@ func writeWAV(path string, samples []float32, sampleRate int, channels int) erro |
|
|
|
return err |
|
|
|
} |
|
|
|
defer f.Close() |
|
|
|
return writeWAVTo(f, samples, sampleRate, channels) |
|
|
|
} |
|
|
|
|
|
|
|
func writeWAVTo(w io.Writer, samples []float32, sampleRate int, channels int) error { |
|
|
|
if channels <= 0 { |
|
|
|
channels = 1 |
|
|
|
} |
|
|
|
// 16-bit PCM |
|
|
|
dataSize := uint32(len(samples) * 2) |
|
|
|
// RIFF header |
|
|
|
if _, err := f.Write([]byte("RIFF")); err != nil { |
|
|
|
if _, err := w.Write([]byte("RIFF")); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint32(36)+dataSize); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint32(36)+dataSize); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if _, err := f.Write([]byte("WAVE")); err != nil { |
|
|
|
if _, err := w.Write([]byte("WAVE")); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
// fmt chunk |
|
|
|
if _, err := f.Write([]byte("fmt ")); err != nil { |
|
|
|
if _, err := w.Write([]byte("fmt ")); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint32(16)); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint32(16)); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint16(1)); err != nil { // PCM |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint16(1)); err != nil { // PCM |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint16(channels)); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint16(channels)); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint32(sampleRate)); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint32(sampleRate)); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
byteRate := uint32(sampleRate * channels * 2) |
|
|
|
if err := binary.Write(f, binary.LittleEndian, byteRate); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, byteRate); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint16(channels*2)); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint16(channels*2)); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, uint16(16)); err != nil { // bits |
|
|
|
if err := binary.Write(w, binary.LittleEndian, uint16(16)); err != nil { // bits |
|
|
|
return err |
|
|
|
} |
|
|
|
// data chunk |
|
|
|
if _, err := f.Write([]byte("data")); err != nil { |
|
|
|
if _, err := w.Write([]byte("data")); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
if err := binary.Write(f, binary.LittleEndian, dataSize); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, dataSize); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
// samples |
|
|
|
for _, s := range samples { |
|
|
|
v := int16(clip(s * 32767)) |
|
|
|
if err := binary.Write(f, binary.LittleEndian, v); err != nil { |
|
|
|
if err := binary.Write(w, binary.LittleEndian, v); err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
|