File: writer.go

package info (click to toggle)
golang-github-cryptix-wav 0.0~git20180415.8bdace6-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 164 kB
  • sloc: makefile: 5
file content (151 lines) | stat: -rw-r--r-- 2,992 bytes parent folder | download | duplicates (2)
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()
}