update wave package

This commit is contained in:
Markus Tzoe 2017-08-24 10:47:56 +08:00
parent d12ddbc1b2
commit 626fbecf50
4 changed files with 59 additions and 89 deletions

View file

@ -40,7 +40,7 @@ func Decompress(infile io.ReadWriteSeeker, outfile io.WriteSeeker, passwd string
smpSize := info.nch * ((info.bps + 7) / 8) smpSize := info.nch * ((info.bps + 7) / 8)
dataSize := info.samples * smpSize dataSize := info.samples * smpSize
waveHdr := wave.NewHeader(dataSize, uint16(info.nch), info.sps, uint16(info.bps), uint16(smpSize)) waveHdr := wave.NewHeader(dataSize, uint16(info.nch), info.sps, uint16(info.bps), uint16(smpSize))
if err = waveHdr.Write(outfile); err != nil { if _, err = waveHdr.WriteTo(outfile); err != nil {
return return
} }
bufSize := pcmBufferLength * smpSize bufSize := pcmBufferLength * smpSize

View file

@ -29,10 +29,8 @@ type Encoder struct {
} }
func Compress(infile io.ReadSeeker, outfile io.ReadWriteSeeker, passwd string, cb Callback) (err error) { func Compress(infile io.ReadSeeker, outfile io.ReadWriteSeeker, passwd string, cb Callback) (err error) {
waveHdr := wave.Header{} waveHdr, dataSize, err := wave.ReadHeader(infile)
var dataSize uint32 if err != nil {
if dataSize, err = waveHdr.Read(infile); err != nil {
err = errRead
return return
} else if dataSize >= 0x7FFFFFFF { } else if dataSize >= 0x7FFFFFFF {
err = fmt.Errorf("incorrect data size info in wav file: %x", dataSize) err = fmt.Errorf("incorrect data size info in wav file: %x", dataSize)

View file

@ -1,7 +1,6 @@
package wave package wave
import ( import (
"errors"
"io" "io"
"os" "os"
"reflect" "reflect"
@ -9,18 +8,16 @@ import (
) )
const ( const (
magicRiff = 0x46464952 riff = 0x46464952 // "RIFF"
magicFormat = 0x20746D66 fmtChunkId = 0x20746D66 // "fmt "
magicChunk = 0x61746164 dataChunkId = 0x61746164 // "data"
MAGIC = 0x45564157 MAGIC = 0x45564157 // "WAVE"
formatPCM = 1 formatPCM = 1
formatExt = 0xFFFE formatExt = 0xFFFE
)
var ( szHeader = 36 // unsafe.Sizeof(Header{})
errPartialWritten = errors.New("partial written") szSubchunkHeader = 8 // unsafe.Sizeof(SubchunkHeader{})
errPartialRead = errors.New("partial read")
) )
type Header struct { type Header struct {
@ -56,10 +53,10 @@ type ExtHeader struct {
func NewHeader(dataSize uint32, nch uint16, sps uint32, bps uint16, smpSize uint16) *Header { func NewHeader(dataSize uint32, nch uint16, sps uint32, bps uint16, smpSize uint16) *Header {
return &Header{ return &Header{
ChunkId: magicRiff, ChunkId: riff,
ChunkSize: dataSize + 36, ChunkSize: dataSize + szHeader,
Format: MAGIC, Format: MAGIC,
SubchunkId: magicFormat, SubchunkId: fmtChunkId,
SubchunkSize: 16, SubchunkSize: 16,
AudioFormat: 1, AudioFormat: 1,
NumChannels: nch, NumChannels: nch,
@ -71,7 +68,7 @@ func NewHeader(dataSize uint32, nch uint16, sps uint32, bps uint16, smpSize uint
} }
func (h *Header) Validate(maxNCH, maxBPS uint16) bool { func (h *Header) Validate(maxNCH, maxBPS uint16) bool {
return (h.ChunkId == magicRiff) && return (h.ChunkId == riff) &&
(h.Format == MAGIC) && (h.Format == MAGIC) &&
(h.NumChannels != 0) && (h.NumChannels != 0) &&
(h.NumChannels <= maxNCH) && (h.NumChannels <= maxNCH) &&
@ -79,60 +76,39 @@ func (h *Header) Validate(maxNCH, maxBPS uint16) bool {
(h.BitsPerSample <= maxBPS) (h.BitsPerSample <= maxBPS)
} }
func (w *Header) Bytes() []byte { func (h *Header) Bytes() []byte {
size := int(unsafe.Sizeof(*w)) return slice(unsafe.Sizeof(*h), unsafe.Pointer(h))
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(w)),
Len: size,
Cap: size,
}))
} }
func (w *SubchunkHeader) Bytes() []byte { func (s *SubchunkHeader) Bytes() []byte {
size := int(unsafe.Sizeof(*w)) return slice(unsafe.Sizeof(*s), unsafe.Pointer(s))
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(w)),
Len: size,
Cap: size,
}))
} }
func (w *ExtHeader) Bytes() []byte { func (e *ExtHeader) Bytes() []byte {
size := int(unsafe.Sizeof(*w)) return slice(unsafe.Sizeof(*e), unsafe.Pointer(e))
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(w)),
Len: size,
Cap: size,
}))
} }
func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) { func ReadHeader(fd io.ReadSeeker) (h *Header, subchunkSize uint32, err error) {
var defaultSubchunkSize uint32 = 16 var defaultSubchunkSize uint32 = 16 // PCM
b := w.Bytes() h = &Header{}
var readLen int b := h.Bytes()
// Read WAVE header // Read WAVE header
if readLen, err = fd.Read(b); err != nil { if _, err = fd.Read(b); err != nil {
return
} else if readLen != len(b) {
err = errPartialRead
return return
} }
if w.AudioFormat == formatExt { if h.AudioFormat == formatExt {
waveHdrEx := ExtHeader{} extheader := ExtHeader{}
if readLen, err = fd.Read(waveHdrEx.Bytes()); err != nil { if _, err = fd.Read(extheader.Bytes()); err != nil {
return
} else if readLen != int(unsafe.Sizeof(waveHdrEx)) {
err = errPartialRead
return return
} }
defaultSubchunkSize += uint32(unsafe.Sizeof(waveHdrEx)) defaultSubchunkSize += uint32(unsafe.Sizeof(extheader))
w.AudioFormat = uint16(waveHdrEx.est.f1) h.AudioFormat = uint16(extheader.est.f1)
} }
// Skip extra format bytes // Skip extra format bytes
if w.SubchunkSize > defaultSubchunkSize { if h.SubchunkSize > defaultSubchunkSize {
extraLen := w.SubchunkSize - defaultSubchunkSize extraLen := h.SubchunkSize - defaultSubchunkSize
if _, err = fd.Seek(int64(extraLen), os.SEEK_SET); err != nil { if _, err = fd.Seek(int64(extraLen), os.SEEK_CUR); err != nil {
return return
} }
} }
@ -140,16 +116,13 @@ func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) {
// Skip unsupported chunks // Skip unsupported chunks
subchunkHdr := SubchunkHeader{} subchunkHdr := SubchunkHeader{}
for { for {
if readLen, err = fd.Read(subchunkHdr.Bytes()); err != nil { if _, err = fd.Read(subchunkHdr.Bytes()); err != nil {
return
} else if readLen != int(unsafe.Sizeof(subchunkHdr)) {
err = errPartialRead
return return
} }
if subchunkHdr.SubchunkId == magicChunk { if subchunkHdr.SubchunkId == dataChunkId {
break break
} }
if _, err = fd.Seek(int64(subchunkHdr.SubchunkSize), os.SEEK_SET); err != nil { if _, err = fd.Seek(int64(subchunkHdr.SubchunkSize), os.SEEK_CUR); err != nil {
return return
} }
} }
@ -157,22 +130,25 @@ func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) {
return return
} }
func (w *Header) Write(fd io.Writer) (err error) { func (h *Header) WriteTo(w io.Writer) (n int64, err error) {
var writeLen int
// Write WAVE header // Write WAVE header
if writeLen, err = fd.Write(w.Bytes()); err != nil { writeLen, err := w.Write(h.Bytes())
return n += int64(writeLen)
} else if writeLen != int(unsafe.Sizeof(*w)) { if err != nil {
err = errPartialWritten
return return
} }
// Write Subchunk header // Write Subchunk header
subchunkHdr := SubchunkHeader{magicChunk, w.ChunkSize - 36} subchunkHdr := SubchunkHeader{dataChunkId, h.ChunkSize - szHeader}
if writeLen, err = fd.Write(subchunkHdr.Bytes()); err != nil { writeLen, err = w.Write(subchunkHdr.Bytes())
return n += int64(writeLen)
} else if writeLen != int(unsafe.Sizeof(subchunkHdr)) {
err = errPartialWritten
return
}
return return
} }
func slice(sz uintptr, addr unsafe.Pointer) []byte {
size := int(sz)
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: uintptr(addr),
Len: size,
Cap: size,
}))
}

View file

@ -6,7 +6,8 @@ import (
"testing" "testing"
) )
var wavSlice = []byte{0x52, 0x49, 0x46, 0x46, 0x98, 0x03, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, var wavSlice = []byte{
0x52, 0x49, 0x46, 0x46, 0x98, 0x03, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20,
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00,
0x04, 0x00, 0x10, 0x00} 0x04, 0x00, 0x10, 0x00}
@ -17,11 +18,10 @@ func TestReadHeader(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer file.Close() defer file.Close()
wav := Header{} if wav, size, err := ReadHeader(file); err != nil {
if size, err := wav.Read(file); err != nil {
t.Error(err) t.Error(err)
} else { } else {
if bytes.Compare(wavSlice, wav.Bytes()) != 0 || size != wav.ChunkSize-36 { if bytes.Compare(wavSlice, wav.Bytes()) != 0 || size != wav.ChunkSize-szHeader {
t.Error("Header::Read fail") t.Error("Header::Read fail")
} }
} }
@ -29,16 +29,12 @@ func TestReadHeader(t *testing.T) {
func TestWriteHeader(t *testing.T) { func TestWriteHeader(t *testing.T) {
t.Parallel() t.Parallel()
filename := os.TempDir() + "/tta_tmp.wav" var buf bytes.Buffer
file, err := os.Create(filename)
if err != nil {
t.Fatal(err)
}
defer file.Close()
defer os.Remove(filename)
wav := Header{} wav := Header{}
copy(wav.Bytes(), wavSlice) copy(wav.Bytes(), wavSlice)
if err = wav.Write(file); err != nil { if n, err := wav.WriteTo(&buf); err != nil {
t.Error(err) t.Error(err)
} else if n != int64(szHeader+szSubchunkHeader) {
t.Errorf("write %d bytes, expected %d bytes", n, szHeader+szSubchunkHeader)
} }
} }