mirror of https://bitbucket.org/ausocean/av.git
ADPCM: encoder now using byte writer instead of returning byte slices
This commit is contained in:
parent
d1c37569c4
commit
3ebf928ffe
|
@ -43,7 +43,7 @@ import (
|
|||
// pred and index hold state that persists between calls to encodeSample and calcHead.
|
||||
// dest is the output, ie. where the encoded ADPCM data is written to.
|
||||
type Encoder struct {
|
||||
dest io.Writer
|
||||
dest io.ByteWriter
|
||||
pred int16
|
||||
index int16
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ type Encoder struct {
|
|||
// pred, index, and step hold state that persists between calls to decodeSample.
|
||||
// dest is the output, ie. where the decoded PCM data is written to.
|
||||
type Decoder struct {
|
||||
dest io.Writer
|
||||
dest io.ByteWriter
|
||||
pred int16
|
||||
index int16
|
||||
step int16
|
||||
|
@ -81,7 +81,7 @@ var stepTable = []int16{
|
|||
}
|
||||
|
||||
// NewEncoder retuns a new ADPCM encoder.
|
||||
func NewEncoder(dst io.Writer) *Encoder {
|
||||
func NewEncoder(dst io.ByteWriter) *Encoder {
|
||||
e := Encoder{
|
||||
dest: dst,
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func NewEncoder(dst io.Writer) *Encoder {
|
|||
}
|
||||
|
||||
// NewDecoder retuns a new ADPCM decoder.
|
||||
func NewDecoder(dst io.Writer) *Decoder {
|
||||
func NewDecoder(dst io.ByteWriter) *Decoder {
|
||||
d := Decoder{
|
||||
step: stepTable[0],
|
||||
dest: dst,
|
||||
|
@ -203,48 +203,47 @@ func capAdd16(a, b int16) int16 {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) calcHead(sample []byte) ([]byte, error) {
|
||||
func (e *Encoder) calcHead(sample []byte) error {
|
||||
// check that we are given 1 16-bit sample (2 bytes)
|
||||
sampSize := 2
|
||||
if len(sample) != sampSize {
|
||||
return nil, fmt.Errorf("length of given byte array is: %v, expected: %v", len(sample), sampSize)
|
||||
return fmt.Errorf("length of given byte array is: %v, expected: %v", len(sample), sampSize)
|
||||
}
|
||||
|
||||
intSample := int16(binary.LittleEndian.Uint16(sample))
|
||||
e.encodeSample(intSample)
|
||||
|
||||
head := make([]byte, 2, 4)
|
||||
head[0] = sample[0]
|
||||
head[1] = sample[1]
|
||||
e.dest.WriteByte(sample[0])
|
||||
e.dest.WriteByte(sample[1])
|
||||
|
||||
head = append(head, byte(uint16(e.index)))
|
||||
head = append(head, byte(0x00))
|
||||
return head, nil
|
||||
e.dest.WriteByte(byte(uint16(e.index)))
|
||||
e.dest.WriteByte(byte(0x00))
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeBlock takes a slice of 1010 bytes (505 16-bit PCM samples).
|
||||
// It returns a byte slice containing encoded (compressed) ADPCM nibbles (each byte contains two nibbles).
|
||||
func (e *Encoder) EncodeBlock(block []byte) ([]byte, error) {
|
||||
func (e *Encoder) EncodeBlock(block []byte) error {
|
||||
bSize := 1010
|
||||
if len(block) != bSize {
|
||||
return nil, fmt.Errorf("unsupported block size. Given: %v, expected: %v, ie. 505 16-bit PCM samples", len(block), bSize)
|
||||
return fmt.Errorf("unsupported block size. Given: %v, expected: %v, ie. 505 16-bit PCM samples", len(block), bSize)
|
||||
}
|
||||
|
||||
result, err := e.calcHead(block[0:2])
|
||||
err := e.calcHead(block[0:2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 2; i < len(block); i++ {
|
||||
if (i+1)%4 == 0 {
|
||||
sample2 := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i-1 : i+1])))
|
||||
sample := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i+1 : i+3])))
|
||||
result = append(result, byte((sample<<4)|sample2))
|
||||
e.dest.WriteByte(byte((sample << 4) | sample2))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeBlock takes a slice of 256 bytes, each byte should contain two ADPCM encoded nibbles.
|
||||
|
|
|
@ -47,15 +47,14 @@ func TestEncodeBlock(t *testing.T) {
|
|||
inBSize := 1010
|
||||
numBlocks := len(pcm) / inBSize
|
||||
outBSize := int(float64(inBSize)/4 + 3.5) // compression is 4:1 and 3.5 bytes of info are added to each block
|
||||
comp := make([]byte, 0, outBSize*numBlocks)
|
||||
enc := NewEncoder(nil)
|
||||
comp := bytes.NewBuffer(make([]byte, 0, outBSize*numBlocks))
|
||||
enc := NewEncoder(comp)
|
||||
for i := 0; i < numBlocks; i++ {
|
||||
block := pcm[inBSize*i : inBSize*(i+1)]
|
||||
encBlock, err := enc.EncodeBlock(block)
|
||||
err := enc.EncodeBlock(block)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
comp = append(comp, encBlock...)
|
||||
}
|
||||
|
||||
//read expected adpcm file
|
||||
|
@ -64,7 +63,7 @@ func TestEncodeBlock(t *testing.T) {
|
|||
t.Errorf("Unable to read expected ADPCM file: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(comp, exp) {
|
||||
if !bytes.Equal(comp.Bytes(), exp) {
|
||||
t.Error("ADPCM generated does not match expected ADPCM")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue