-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimplewav.go
68 lines (61 loc) · 1.65 KB
/
simplewav.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package simplewav
import (
"encoding/binary"
"io"
"math"
"os"
)
const (
bitsPerSample = 16
numChannels = 1
)
// writeHeader writes a minimal WAV header to an io.Writer.
func writeHeader(w io.Writer, numSamples, sampleRate int) error {
// Ensure all calculations use fixed-size types for binary writing.
fileSize := uint32(44 + numSamples*numChannels*bitsPerSample/8)
audioFormat := int16(1) // PCM = 1
byteRate := uint32(sampleRate) * uint32(numChannels) * uint32(bitsPerSample) / 8
blockAlign := uint16(numChannels * bitsPerSample / 8)
subChunk2Size := uint32(numSamples) * uint32(numChannels) * uint32(bitsPerSample) / 8
// Directly write the byte slices and fixed-size data to the writer
parts := []struct {
data interface{}
}{
{[]byte("RIFF")},
{fileSize - 8},
{[]byte("WAVE")},
{[]byte("fmt ")},
{uint32(16)}, // Subchunk1Size for PCM
{audioFormat},
{int16(numChannels)},
{uint32(sampleRate)},
{byteRate},
{blockAlign},
{int16(bitsPerSample)},
{[]byte("data")},
{subChunk2Size},
}
for _, part := range parts {
if err := binary.Write(w, binary.LittleEndian, part.data); err != nil {
return err
}
}
return nil
}
// Write creates a WAV file from a slice of float64 audio samples
func Write(wave []float64, filename string, sampleRate int) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
if err := writeHeader(file, len(wave), sampleRate); err != nil {
return err
}
buffer := make([]int16, len(wave))
const maxInt16 = float64(math.MaxInt16)
for i, sample := range wave {
buffer[i] = int16(sample * maxInt16)
}
return binary.Write(file, binary.LittleEndian, buffer)
}