mirror of https://bitbucket.org/ausocean/av.git
ADPCM: small fixes, comments and style.
This commit is contained in:
parent
3f4de6d288
commit
146e993c03
|
@ -100,13 +100,13 @@ func NewDecoder(dst *bytes.Buffer) *Decoder {
|
||||||
// encodeSample takes a single 16 bit PCM sample and
|
// encodeSample takes a single 16 bit PCM sample and
|
||||||
// returns a byte of which the last 4 bits are an encoded ADPCM nibble
|
// returns a byte of which the last 4 bits are an encoded ADPCM nibble
|
||||||
func (e *Encoder) encodeSample(sample int16) byte {
|
func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
|
// find difference of actual sample from encoder's prediction
|
||||||
delta := sample - e.pred
|
delta := sample - e.pred
|
||||||
|
|
||||||
var nibble byte
|
// create and set sign bit for nibble and find absolute value of difference
|
||||||
|
var nib byte
|
||||||
// set sign bit and find absolute value of difference
|
|
||||||
if delta < 0 {
|
if delta < 0 {
|
||||||
nibble = 8
|
nib = 8
|
||||||
delta = -delta
|
delta = -delta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
if delta > step {
|
if delta > step {
|
||||||
nibble |= mask
|
nib |= mask
|
||||||
delta -= step
|
delta -= step
|
||||||
diff += step
|
diff += step
|
||||||
}
|
}
|
||||||
|
@ -125,21 +125,13 @@ func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust predicted sample based on calculated difference
|
// adjust predicted sample based on calculated difference
|
||||||
if nibble&8 != 0 {
|
if nib&8 != 0 {
|
||||||
e.pred = capAdd16(e.pred, -diff)
|
e.pred = capAdd16(e.pred, -diff)
|
||||||
} else {
|
} else {
|
||||||
e.pred = capAdd16(e.pred, diff)
|
e.pred = capAdd16(e.pred, diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for underflow and overflow
|
e.index += indexTable[nib&7]
|
||||||
if e.pred < math.MinInt16 {
|
|
||||||
e.pred = math.MinInt16
|
|
||||||
} else if e.pred > math.MaxInt16 {
|
|
||||||
e.pred = math.MaxInt16
|
|
||||||
}
|
|
||||||
|
|
||||||
e.index += indexTable[nibble&7]
|
|
||||||
|
|
||||||
// check for underflow and overflow
|
// check for underflow and overflow
|
||||||
if e.index < 0 {
|
if e.index < 0 {
|
||||||
e.index = 0
|
e.index = 0
|
||||||
|
@ -147,7 +139,7 @@ func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
e.index = int16(len(stepTable) - 1)
|
e.index = int16(len(stepTable) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nibble
|
return nib
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeSample takes a byte, the last 4 bits of which contain a single
|
// decodeSample takes a byte, the last 4 bits of which contain a single
|
||||||
|
@ -203,6 +195,8 @@ func capAdd16(a, b int16) int16 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calcHead sets the state for the encoder by running the first sample through
|
||||||
|
// the encoder, and writing the first sample
|
||||||
func (e *Encoder) calcHead(sample []byte) error {
|
func (e *Encoder) calcHead(sample []byte) error {
|
||||||
// check that we are given 1 16-bit sample (2 bytes)
|
// check that we are given 1 16-bit sample (2 bytes)
|
||||||
sampSize := 2
|
sampSize := 2
|
||||||
|
@ -221,7 +215,11 @@ func (e *Encoder) calcHead(sample []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBlock takes a slice of 1010 bytes (505 16-bit PCM samples).
|
// 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).
|
// It outputs encoded (compressed) bytes (each byte containing two ADPCM nibbles) to the encoder's dest writer.
|
||||||
|
// note: nibbles are output in little endian order, eg. n1n0 n3n2 n5n4...
|
||||||
|
// note: first 4 bytes are for initializing the decoder before decoding a block.
|
||||||
|
// - 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) error {
|
func (e *Encoder) EncodeBlock(block []byte) error {
|
||||||
bSize := 1010
|
bSize := 1010
|
||||||
if len(block) != bSize {
|
if len(block) != bSize {
|
||||||
|
@ -233,42 +231,42 @@ func (e *Encoder) EncodeBlock(block []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 2; i < len(block); i++ {
|
for i := 3; i < bSize; i += 4 {
|
||||||
if (i+1)%4 == 0 {
|
nib1 := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i-1 : i+1])))
|
||||||
sample2 := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i-1 : i+1])))
|
nib2 := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i+1 : i+3])))
|
||||||
sample := e.encodeSample(int16(binary.LittleEndian.Uint16(block[i+1 : i+3])))
|
e.dest.WriteByte(byte((nib2 << 4) | nib1))
|
||||||
e.dest.WriteByte(byte((sample << 4) | sample2))
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBlock takes a slice of 256 bytes, each byte should contain two ADPCM encoded nibbles.
|
// DecodeBlock takes a slice of 256 bytes, each byte after the first 4 should contain two ADPCM encoded nibbles.
|
||||||
// It returns a byte slice containing the resulting decoded (uncompressed) 16-bit PCM samples.
|
// It outputs the resulting decoded (decompressed) 16-bit PCM samples to the decoder's dest writer.
|
||||||
func (d *Decoder) DecodeBlock(block []byte) error {
|
func (d *Decoder) DecodeBlock(block []byte) error {
|
||||||
bSize := 256
|
bSize := 256
|
||||||
if len(block) != bSize {
|
if len(block) != bSize {
|
||||||
return fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), bSize)
|
return fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), bSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initialize decoder with first 4 bytes of the block
|
||||||
d.pred = int16(binary.LittleEndian.Uint16(block[0:2]))
|
d.pred = int16(binary.LittleEndian.Uint16(block[0:2]))
|
||||||
d.index = int16(block[2])
|
d.index = int16(block[2])
|
||||||
d.step = stepTable[d.index]
|
d.step = stepTable[d.index]
|
||||||
d.dest.Write(block[0:2])
|
d.dest.Write(block[0:2])
|
||||||
|
|
||||||
for i := 4; i < len(block); i++ {
|
// for each byte, seperate it into two nibbles (each nibble is a compressed sample),
|
||||||
originalSample := block[i]
|
// then decode each nibble and output the resulting 16-bit samples
|
||||||
secondSample := byte(originalSample >> 4)
|
for i := 4; i < bSize; i++ {
|
||||||
firstSample := byte((secondSample << 4) ^ originalSample)
|
twoNibs := block[i]
|
||||||
|
nib2 := byte(twoNibs >> 4)
|
||||||
|
nib1 := byte((nib2 << 4) ^ twoNibs)
|
||||||
|
|
||||||
firstBytes := make([]byte, 2)
|
firstBytes := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(firstBytes, uint16(d.decodeSample(firstSample)))
|
binary.LittleEndian.PutUint16(firstBytes, uint16(d.decodeSample(nib1)))
|
||||||
d.dest.Write(firstBytes)
|
d.dest.Write(firstBytes)
|
||||||
|
|
||||||
secondBytes := make([]byte, 2)
|
secondBytes := make([]byte, 2)
|
||||||
binary.LittleEndian.PutUint16(secondBytes, uint16(d.decodeSample(secondSample)))
|
binary.LittleEndian.PutUint16(secondBytes, uint16(d.decodeSample(nib2)))
|
||||||
d.dest.Write(secondBytes)
|
d.dest.Write(secondBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue