mirror of https://bitbucket.org/ausocean/av.git
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:
parent
c7c7ef75f5
commit
fdc4d880ac
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue