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()
}
|