117 lines
2.5 KiB
Go
117 lines
2.5 KiB
Go
package riff
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"sync"
|
|
)
|
|
|
|
type Chunk struct {
|
|
ID [4]byte
|
|
Size int
|
|
Pos int
|
|
R io.Reader
|
|
okChan chan bool
|
|
Wg *sync.WaitGroup
|
|
}
|
|
|
|
func (ch *Chunk) DecodeWavHeader(p *Parser) error {
|
|
if ch == nil {
|
|
return fmt.Errorf("can't decode a nil chunk")
|
|
}
|
|
if ch.ID == FmtID {
|
|
p.wavHeaderSize = uint32(ch.Size)
|
|
if err := ch.ReadLE(&p.WavAudioFormat); err != nil {
|
|
return err
|
|
}
|
|
if err := ch.ReadLE(&p.NumChannels); err != nil {
|
|
return err
|
|
}
|
|
if err := ch.ReadLE(&p.SampleRate); err != nil {
|
|
return err
|
|
}
|
|
if err := ch.ReadLE(&p.AvgBytesPerSec); err != nil {
|
|
return err
|
|
}
|
|
if err := ch.ReadLE(&p.BlockAlign); err != nil {
|
|
return err
|
|
}
|
|
if err := ch.ReadLE(&p.BitsPerSample); err != nil {
|
|
return err
|
|
}
|
|
if ch.Size > 16 {
|
|
extra := make([]byte, ch.Size-16)
|
|
ch.ReadLE(&extra)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ch *Chunk) Done() {
|
|
if !ch.IsFullyRead() {
|
|
ch.Drain()
|
|
}
|
|
if ch.Wg != nil {
|
|
ch.Wg.Done()
|
|
}
|
|
}
|
|
|
|
func (ch *Chunk) IsFullyRead() bool {
|
|
if ch == nil || ch.R == nil {
|
|
return true
|
|
}
|
|
return ch.Size <= ch.Pos
|
|
}
|
|
|
|
func (ch *Chunk) Read(p []byte) (n int, err error) {
|
|
if ch == nil || ch.R == nil {
|
|
return 0, errors.New("nil chunk/reader pointer")
|
|
}
|
|
n, err = ch.R.Read(p)
|
|
ch.Pos += n
|
|
return n, err
|
|
}
|
|
|
|
func (ch *Chunk) ReadLE(dst interface{}) error {
|
|
if ch == nil || ch.R == nil {
|
|
return errors.New("nil chunk/reader pointer")
|
|
}
|
|
if ch.IsFullyRead() {
|
|
return io.EOF
|
|
}
|
|
ch.Pos += binary.Size(dst)
|
|
return binary.Read(ch.R, binary.LittleEndian, dst)
|
|
}
|
|
|
|
func (ch *Chunk) ReadBE(dst interface{}) error {
|
|
if ch.IsFullyRead() {
|
|
return io.EOF
|
|
}
|
|
ch.Pos += binary.Size(dst)
|
|
return binary.Read(ch.R, binary.LittleEndian, dst)
|
|
}
|
|
|
|
func (ch *Chunk) ReadByte() (byte, error) {
|
|
if ch.IsFullyRead() {
|
|
return 0, io.EOF
|
|
}
|
|
var r byte
|
|
err := ch.ReadLE(&r)
|
|
return r, err
|
|
}
|
|
|
|
func (ch *Chunk) Drain() {
|
|
bytesAhead := ch.Size - ch.Pos
|
|
for bytesAhead > 0 {
|
|
readSize := int64(bytesAhead)
|
|
|
|
if _, err := io.CopyN(ioutil.Discard, ch.R, readSize); err != nil {
|
|
return
|
|
}
|
|
bytesAhead -= int(readSize)
|
|
}
|
|
}
|