From 626fbecf5008b035653a75db8945aea062c600eb Mon Sep 17 00:00:00 2001 From: Markus Tzoe Date: Thu, 24 Aug 2017 10:47:56 +0800 Subject: [PATCH] update wave package --- decoder.go | 2 +- encoder.go | 6 +-- wave/wav.go | 120 +++++++++++++++++++---------------------------- wave/wav_test.go | 20 ++++---- 4 files changed, 59 insertions(+), 89 deletions(-) diff --git a/decoder.go b/decoder.go index 2d13eb8..2b23abf 100644 --- a/decoder.go +++ b/decoder.go @@ -40,7 +40,7 @@ func Decompress(infile io.ReadWriteSeeker, outfile io.WriteSeeker, passwd string smpSize := info.nch * ((info.bps + 7) / 8) dataSize := info.samples * 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 } bufSize := pcmBufferLength * smpSize diff --git a/encoder.go b/encoder.go index 6f5b283..a031de9 100644 --- a/encoder.go +++ b/encoder.go @@ -29,10 +29,8 @@ type Encoder struct { } func Compress(infile io.ReadSeeker, outfile io.ReadWriteSeeker, passwd string, cb Callback) (err error) { - waveHdr := wave.Header{} - var dataSize uint32 - if dataSize, err = waveHdr.Read(infile); err != nil { - err = errRead + waveHdr, dataSize, err := wave.ReadHeader(infile) + if err != nil { return } else if dataSize >= 0x7FFFFFFF { err = fmt.Errorf("incorrect data size info in wav file: %x", dataSize) diff --git a/wave/wav.go b/wave/wav.go index 5fdc5ef..812a454 100644 --- a/wave/wav.go +++ b/wave/wav.go @@ -1,7 +1,6 @@ package wave import ( - "errors" "io" "os" "reflect" @@ -9,18 +8,16 @@ import ( ) const ( - magicRiff = 0x46464952 - magicFormat = 0x20746D66 - magicChunk = 0x61746164 - MAGIC = 0x45564157 + riff = 0x46464952 // "RIFF" + fmtChunkId = 0x20746D66 // "fmt " + dataChunkId = 0x61746164 // "data" + MAGIC = 0x45564157 // "WAVE" formatPCM = 1 formatExt = 0xFFFE -) -var ( - errPartialWritten = errors.New("partial written") - errPartialRead = errors.New("partial read") + szHeader = 36 // unsafe.Sizeof(Header{}) + szSubchunkHeader = 8 // unsafe.Sizeof(SubchunkHeader{}) ) type Header struct { @@ -56,10 +53,10 @@ type ExtHeader struct { func NewHeader(dataSize uint32, nch uint16, sps uint32, bps uint16, smpSize uint16) *Header { return &Header{ - ChunkId: magicRiff, - ChunkSize: dataSize + 36, + ChunkId: riff, + ChunkSize: dataSize + szHeader, Format: MAGIC, - SubchunkId: magicFormat, + SubchunkId: fmtChunkId, SubchunkSize: 16, AudioFormat: 1, 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 { - return (h.ChunkId == magicRiff) && + return (h.ChunkId == riff) && (h.Format == MAGIC) && (h.NumChannels != 0) && (h.NumChannels <= maxNCH) && @@ -79,60 +76,39 @@ func (h *Header) Validate(maxNCH, maxBPS uint16) bool { (h.BitsPerSample <= maxBPS) } -func (w *Header) Bytes() []byte { - size := int(unsafe.Sizeof(*w)) - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(w)), - Len: size, - Cap: size, - })) +func (h *Header) Bytes() []byte { + return slice(unsafe.Sizeof(*h), unsafe.Pointer(h)) } -func (w *SubchunkHeader) Bytes() []byte { - size := int(unsafe.Sizeof(*w)) - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(w)), - Len: size, - Cap: size, - })) +func (s *SubchunkHeader) Bytes() []byte { + return slice(unsafe.Sizeof(*s), unsafe.Pointer(s)) } -func (w *ExtHeader) Bytes() []byte { - size := int(unsafe.Sizeof(*w)) - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer(w)), - Len: size, - Cap: size, - })) +func (e *ExtHeader) Bytes() []byte { + return slice(unsafe.Sizeof(*e), unsafe.Pointer(e)) } -func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) { - var defaultSubchunkSize uint32 = 16 - b := w.Bytes() - var readLen int +func ReadHeader(fd io.ReadSeeker) (h *Header, subchunkSize uint32, err error) { + var defaultSubchunkSize uint32 = 16 // PCM + h = &Header{} + b := h.Bytes() // Read WAVE header - if readLen, err = fd.Read(b); err != nil { - return - } else if readLen != len(b) { - err = errPartialRead + if _, err = fd.Read(b); err != nil { return } - if w.AudioFormat == formatExt { - waveHdrEx := ExtHeader{} - if readLen, err = fd.Read(waveHdrEx.Bytes()); err != nil { - return - } else if readLen != int(unsafe.Sizeof(waveHdrEx)) { - err = errPartialRead + if h.AudioFormat == formatExt { + extheader := ExtHeader{} + if _, err = fd.Read(extheader.Bytes()); err != nil { return } - defaultSubchunkSize += uint32(unsafe.Sizeof(waveHdrEx)) - w.AudioFormat = uint16(waveHdrEx.est.f1) + defaultSubchunkSize += uint32(unsafe.Sizeof(extheader)) + h.AudioFormat = uint16(extheader.est.f1) } // Skip extra format bytes - if w.SubchunkSize > defaultSubchunkSize { - extraLen := w.SubchunkSize - defaultSubchunkSize - if _, err = fd.Seek(int64(extraLen), os.SEEK_SET); err != nil { + if h.SubchunkSize > defaultSubchunkSize { + extraLen := h.SubchunkSize - defaultSubchunkSize + if _, err = fd.Seek(int64(extraLen), os.SEEK_CUR); err != nil { return } } @@ -140,16 +116,13 @@ func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) { // Skip unsupported chunks subchunkHdr := SubchunkHeader{} for { - if readLen, err = fd.Read(subchunkHdr.Bytes()); err != nil { - return - } else if readLen != int(unsafe.Sizeof(subchunkHdr)) { - err = errPartialRead + if _, err = fd.Read(subchunkHdr.Bytes()); err != nil { return } - if subchunkHdr.SubchunkId == magicChunk { + if subchunkHdr.SubchunkId == dataChunkId { 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 } } @@ -157,22 +130,25 @@ func (w *Header) Read(fd io.ReadSeeker) (subchunkSize uint32, err error) { return } -func (w *Header) Write(fd io.Writer) (err error) { - var writeLen int +func (h *Header) WriteTo(w io.Writer) (n int64, err error) { // Write WAVE header - if writeLen, err = fd.Write(w.Bytes()); err != nil { - return - } else if writeLen != int(unsafe.Sizeof(*w)) { - err = errPartialWritten + writeLen, err := w.Write(h.Bytes()) + n += int64(writeLen) + if err != nil { return } // Write Subchunk header - subchunkHdr := SubchunkHeader{magicChunk, w.ChunkSize - 36} - if writeLen, err = fd.Write(subchunkHdr.Bytes()); err != nil { - return - } else if writeLen != int(unsafe.Sizeof(subchunkHdr)) { - err = errPartialWritten - return - } + subchunkHdr := SubchunkHeader{dataChunkId, h.ChunkSize - szHeader} + writeLen, err = w.Write(subchunkHdr.Bytes()) + n += int64(writeLen) 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, + })) +} diff --git a/wave/wav_test.go b/wave/wav_test.go index a1c0f43..ac5cbf3 100644 --- a/wave/wav_test.go +++ b/wave/wav_test.go @@ -6,7 +6,8 @@ import ( "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, 0x04, 0x00, 0x10, 0x00} @@ -17,11 +18,10 @@ func TestReadHeader(t *testing.T) { t.Fatal(err) } defer file.Close() - wav := Header{} - if size, err := wav.Read(file); err != nil { + if wav, size, err := ReadHeader(file); err != nil { t.Error(err) } 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") } } @@ -29,16 +29,12 @@ func TestReadHeader(t *testing.T) { func TestWriteHeader(t *testing.T) { t.Parallel() - filename := os.TempDir() + "/tta_tmp.wav" - file, err := os.Create(filename) - if err != nil { - t.Fatal(err) - } - defer file.Close() - defer os.Remove(filename) + var buf bytes.Buffer wav := Header{} copy(wav.Bytes(), wavSlice) - if err = wav.Write(file); err != nil { + if n, err := wav.WriteTo(&buf); err != nil { t.Error(err) + } else if n != int64(szHeader+szSubchunkHeader) { + t.Errorf("write %d bytes, expected %d bytes", n, szHeader+szSubchunkHeader) } }