-
Notifications
You must be signed in to change notification settings - Fork 42
/
writer.go
151 lines (123 loc) · 2.92 KB
/
writer.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package wav
import (
"bufio"
"encoding/binary"
"fmt"
"io"
"os"
)
type output interface {
io.Writer
io.Seeker
io.Closer
}
// Writer encapsulates a io.WriteSeeker and supplies Functions for writing samples
type Writer struct {
output
options File
sampleBuf *bufio.Writer
bytesWritten int
}
// NewWriter creates a new WaveWriter and writes the header to it
func (file File) NewWriter(out output) (wr *Writer, err error) {
if file.Channels != 1 {
err = fmt.Errorf("sorry, only mono currently")
return
}
wr = &Writer{}
wr.output = out
wr.sampleBuf = bufio.NewWriter(out)
wr.options = file
// write header when close to get correct number of samples
_, err = wr.Seek(12, os.SEEK_SET)
if err != nil {
return
}
// fmt.Fprintf(wr, "%s", tokenChunkFmt)
n, err := wr.output.Write(tokenChunkFmt[:])
if err != nil {
return
}
wr.bytesWritten += n
chunkFmt := riffChunkFmt{
LengthOfHeader: 16,
AudioFormat: 1,
NumChannels: file.Channels,
SampleRate: file.SampleRate,
BytesPerSec: uint32(file.Channels) * file.SampleRate * uint32(file.SignificantBits) / 8,
BytesPerBloc: file.SignificantBits / 8 * file.Channels,
BitsPerSample: file.SignificantBits,
}
err = binary.Write(wr.output, binary.LittleEndian, chunkFmt)
if err != nil {
return
}
wr.bytesWritten += 20 //sizeof riffChunkFmt
n, err = wr.output.Write(tokenData[:])
if err != nil {
return
}
wr.bytesWritten += n
// leave space for the data size
_, err = wr.Seek(4, os.SEEK_CUR)
if err != nil {
return
}
return
}
// WriteInt32 writes the sample to the file using the binary package
func (w *Writer) WriteInt32(sample int32) error {
err := binary.Write(w.sampleBuf, binary.LittleEndian, sample)
if err != nil {
return err
}
w.bytesWritten += 4
return err
}
// WriteSample writes a []byte array to file without conversion
func (w *Writer) WriteSample(sample []byte) error {
if len(sample)*8 != int(w.options.SignificantBits) {
return fmt.Errorf("incorrect Sample Length %d", len(sample))
}
n, err := w.sampleBuf.Write(sample)
if err != nil {
return err
}
w.bytesWritten += n
return nil
}
func (w *Writer) Write(data []byte) (int, error) {
n, err := w.output.Write(data)
w.bytesWritten += n
return n, err
}
// Close corrects the filesize information in the header
func (w *Writer) Close() error {
if err := w.sampleBuf.Flush(); err != nil {
return err
}
_, err := w.Seek(0, os.SEEK_SET)
if err != nil {
return err
}
header := riffHeader{
ChunkSize: uint32(w.bytesWritten + 8),
}
copy(header.Ftype[:], tokenRiff[:])
copy(header.ChunkFormat[:], tokenWaveFormat[:])
err = binary.Write(w.output, binary.LittleEndian, header)
if err != nil {
return err
}
// write data chunk size
_, err = w.Seek(0x28, os.SEEK_SET)
if err != nil {
return err
}
// write chunk size
err = binary.Write(w.output, binary.LittleEndian, int32(w.bytesWritten))
if err != nil {
return err
}
return w.output.Close()
}