ADPCM: added a Write function to decoder so that it implements io.Writer,

and also so that it can decode adpcm of arbitrary length.
Updated test and decode command to use Write.
This commit is contained in:
Trek H 2019-03-15 17:07:22 +10:30
parent c7c7ef75f5
commit fdc4d880ac
3 changed files with 63 additions and 41 deletions

View File

@ -227,8 +227,9 @@ func (e *Encoder) calcHead(sample []byte) (int, error) {
// - First two bytes contain the first 16-bit sample uncompressed.
// - Third byte is the decoder's starting index for the block, the fourth is padding and ignored.
func (e *Encoder) EncodeBlock(block []byte) (int, error) {
writ := 0
if len(block) != PcmBS {
return 0, fmt.Errorf("unsupported block size. Given: %v, expected: %v, ie. 505 16-bit PCM samples", len(block), PcmBS)
return writ, fmt.Errorf("unsupported block size. Given: %v, expected: %v, ie. 505 16-bit PCM samples", len(block), PcmBS)
}
writ, err := e.calcHead(block[0:2])
@ -249,6 +250,50 @@ func (e *Encoder) EncodeBlock(block []byte) (int, error) {
return writ, nil
}
// DecodeBlock takes a slice of 256 bytes, each byte after the first 4 should contain two ADPCM encoded nibbles.
// It outputs the resulting decoded (decompressed) 16-bit PCM samples to the decoder's dest writer.
func (d *Decoder) DecodeBlock(block []byte) (int, error) {
writ := 0
if len(block) != AdpcmBS {
return writ, fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), AdpcmBS)
}
// Initialize decoder with first 4 bytes of the block.
d.pred = int16(binary.LittleEndian.Uint16(block[0:2]))
d.index = int16(block[2])
d.step = stepTable[d.index]
writ, err := d.dest.Write(block[0:2])
if err != nil {
return writ, err
}
// For each byte, seperate it into two nibbles (each nibble is a compressed sample),
// then decode each nibble and output the resulting 16-bit samples.
for i := 4; i < AdpcmBS; i++ {
twoNibs := block[i]
nib2 := byte(twoNibs >> 4)
nib1 := byte((nib2 << 4) ^ twoNibs)
firstBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(firstBytes, uint16(d.decodeSample(nib1)))
writS, err := d.dest.Write(firstBytes)
writ += writS
if err != nil {
return writ, err
}
secondBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(secondBytes, uint16(d.decodeSample(nib2)))
writS, err = d.dest.Write(secondBytes)
writ += writS
if err != nil {
return writ, err
}
}
return writ, nil
}
func (e *Encoder) Write(inPcm []byte) (int, error) {
numBlocks := len(inPcm) / PcmBS
writ := 0
@ -264,34 +309,17 @@ func (e *Encoder) Write(inPcm []byte) (int, error) {
return writ, nil
}
// DecodeBlock takes a slice of 256 bytes, each byte after the first 4 should contain two ADPCM encoded nibbles.
// It outputs the resulting decoded (decompressed) 16-bit PCM samples to the decoder's dest writer.
func (d *Decoder) DecodeBlock(block []byte) error {
if len(block) != AdpcmBS {
return fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), AdpcmBS)
func (d *Decoder) Write(inAdpcm []byte) (int, error) {
numBlocks := len(inAdpcm) / AdpcmBS
writ := 0
for i := 0; i < numBlocks; i++ {
block := inAdpcm[AdpcmBS*i : AdpcmBS*(i+1)]
writB, err := d.DecodeBlock(block)
writ += writB
if err != nil {
return writ, err
}
}
// Initialize decoder with first 4 bytes of the block.
d.pred = int16(binary.LittleEndian.Uint16(block[0:2]))
d.index = int16(block[2])
d.step = stepTable[d.index]
d.dest.Write(block[0:2])
// For each byte, seperate it into two nibbles (each nibble is a compressed sample),
// then decode each nibble and output the resulting 16-bit samples.
for i := 4; i < AdpcmBS; i++ {
twoNibs := block[i]
nib2 := byte(twoNibs >> 4)
nib1 := byte((nib2 << 4) ^ twoNibs)
firstBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(firstBytes, uint16(d.decodeSample(nib1)))
d.dest.Write(firstBytes)
secondBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(secondBytes, uint16(d.decodeSample(nib2)))
d.dest.Write(secondBytes)
}
return nil
return writ, nil
}

View File

@ -75,12 +75,9 @@ func TestDecodeBlock(t *testing.T) {
numBlocks := len(comp) / AdpcmBS
decoded := bytes.NewBuffer(make([]byte, 0, PcmBS*numBlocks))
dec := NewDecoder(decoded)
for i := 0; i < numBlocks; i++ {
block := comp[AdpcmBS*i : AdpcmBS*(i+1)]
err := dec.DecodeBlock(block)
if err != nil {
t.Errorf("Unable to write to decoder: %v", err)
}
_, err = dec.Write(comp)
if err != nil {
t.Errorf("Unable to write to decoder: %v", err)
}
// Read expected pcm file.

View File

@ -57,12 +57,9 @@ func main() {
numBlocks := len(comp) / adpcm.AdpcmBS
decoded := bytes.NewBuffer(make([]byte, 0, adpcm.PcmBS*numBlocks))
dec := adpcm.NewDecoder(decoded)
for i := 0; i < numBlocks; i++ {
block := comp[adpcm.AdpcmBS*i : adpcm.AdpcmBS*(i+1)]
err := dec.DecodeBlock(block)
if err != nil {
log.Fatal(err)
}
_, err = dec.Write(comp)
if err != nil {
log.Fatal(err)
}
// Save pcm to file.