mirror of https://bitbucket.org/ausocean/av.git
ADPCM: unexported encoder and decoder structs, documented Write funcs.
This commit is contained in:
parent
fdc4d880ac
commit
d4e0c87635
|
@ -38,31 +38,31 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Encoder is used to encode to ADPCM from PCM data.
|
// encoder is used to encode to ADPCM from PCM data.
|
||||||
// pred and index hold state that persists between calls to encodeSample and calcHead.
|
// pred and index hold state that persists between calls to encodeSample and calcHead.
|
||||||
// dest is the output buffer that implements io.writer and io.bytewriter, ie. where the encoded ADPCM data is written to.
|
// dest is the output buffer that implements io.writer and io.bytewriter, ie. where the encoded ADPCM data is written to.
|
||||||
type Encoder struct {
|
type encoder struct {
|
||||||
dest *bytes.Buffer
|
dest *bytes.Buffer
|
||||||
pred int16
|
pred int16
|
||||||
index int16
|
index int16
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoder is used to decode from ADPCM to PCM data.
|
// decoder is used to decode from ADPCM to PCM data.
|
||||||
// pred, index, and step hold state that persists between calls to decodeSample.
|
// pred, index, and step hold state that persists between calls to decodeSample.
|
||||||
// dest is the output buffer that implements io.writer and io.bytewriter, ie. where the decoded PCM data is written to.
|
// dest is the output buffer that implements io.writer and io.bytewriter, ie. where the decoded PCM data is written to.
|
||||||
type Decoder struct {
|
type decoder struct {
|
||||||
dest *bytes.Buffer
|
dest *bytes.Buffer
|
||||||
pred int16
|
pred int16
|
||||||
index int16
|
index int16
|
||||||
step int16
|
step int16
|
||||||
}
|
}
|
||||||
|
|
||||||
// PcmBS is the size of the blocks that an Encoder uses.
|
// PcmBS is the size of the blocks that an encoder uses.
|
||||||
// 'EncodeBlock' will encode PcmBS bytes at a time and the output will be AdpcmBS bytes long.
|
// 'encodeBlock' will encode PcmBS bytes at a time and the output will be AdpcmBS bytes long.
|
||||||
const PcmBS = 1010
|
const PcmBS = 1010
|
||||||
|
|
||||||
// AdpcmBS is the size of the blocks that a Decoder uses.
|
// AdpcmBS is the size of the blocks that a decoder uses.
|
||||||
// 'DecodeBlock' will decode AdpcmBS bytes at a time and the output will be PcmBS bytes long.
|
// 'decodeBlock' will decode AdpcmBS bytes at a time and the output will be PcmBS bytes long.
|
||||||
const AdpcmBS = 256
|
const AdpcmBS = 256
|
||||||
|
|
||||||
// Table of index changes (see spec).
|
// Table of index changes (see spec).
|
||||||
|
@ -88,16 +88,16 @@ var stepTable = []int16{
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder retuns a new ADPCM encoder.
|
// NewEncoder retuns a new ADPCM encoder.
|
||||||
func NewEncoder(dst *bytes.Buffer) *Encoder {
|
func NewEncoder(dst *bytes.Buffer) *encoder {
|
||||||
e := Encoder{
|
e := encoder{
|
||||||
dest: dst,
|
dest: dst,
|
||||||
}
|
}
|
||||||
return &e
|
return &e
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDecoder retuns a new ADPCM decoder.
|
// NewDecoder retuns a new ADPCM decoder.
|
||||||
func NewDecoder(dst *bytes.Buffer) *Decoder {
|
func NewDecoder(dst *bytes.Buffer) *decoder {
|
||||||
d := Decoder{
|
d := decoder{
|
||||||
step: stepTable[0],
|
step: stepTable[0],
|
||||||
dest: dst,
|
dest: dst,
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ 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.
|
// Find difference of actual sample from encoder's prediction.
|
||||||
delta := sample - e.pred
|
delta := sample - e.pred
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
e.index += indexTable[nib&7]
|
e.index += indexTable[nib&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
|
||||||
|
@ -151,7 +152,7 @@ func (e *Encoder) encodeSample(sample int16) byte {
|
||||||
|
|
||||||
// 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
|
||||||
// 4 bit ADPCM nibble, and returns a 16 bit decoded PCM sample.
|
// 4 bit ADPCM nibble, and returns a 16 bit decoded PCM sample.
|
||||||
func (d *Decoder) decodeSample(nibble byte) int16 {
|
func (d *decoder) decodeSample(nibble byte) int16 {
|
||||||
// Calculate difference.
|
// Calculate difference.
|
||||||
var diff int16
|
var diff int16
|
||||||
if nibble&4 != 0 {
|
if nibble&4 != 0 {
|
||||||
|
@ -191,7 +192,7 @@ func (d *Decoder) decodeSample(nibble byte) int16 {
|
||||||
|
|
||||||
// calcHead sets the state for the encoder by running the first sample through
|
// calcHead sets the state for the encoder by running the first sample through
|
||||||
// the encoder, and writing the first sample.
|
// the encoder, and writing the first sample.
|
||||||
func (e *Encoder) calcHead(sample []byte) (int, error) {
|
func (e *encoder) calcHead(sample []byte) (int, error) {
|
||||||
// Check that we are given 1 16-bit sample (2 bytes).
|
// Check that we are given 1 16-bit sample (2 bytes).
|
||||||
const sampSize = 2
|
const sampSize = 2
|
||||||
if len(sample) != sampSize {
|
if len(sample) != sampSize {
|
||||||
|
@ -220,13 +221,13 @@ func (e *Encoder) calcHead(sample []byte) (int, error) {
|
||||||
return writ, nil
|
return writ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 outputs encoded (compressed) bytes (each byte containing two ADPCM nibbles) to the encoder's dest writer.
|
// 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: nibbles are output in little endian order, eg. n1n0 n3n2 n5n4...
|
||||||
// Note: first 4 bytes are for initializing the decoder before decoding a block.
|
// Note: first 4 bytes are for initializing the decoder before decoding a block.
|
||||||
// - First two bytes contain the first 16-bit sample uncompressed.
|
// - 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.
|
// - 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) {
|
func (e *encoder) encodeBlock(block []byte) (int, error) {
|
||||||
writ := 0
|
writ := 0
|
||||||
if len(block) != PcmBS {
|
if len(block) != PcmBS {
|
||||||
return writ, 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)
|
||||||
|
@ -250,9 +251,9 @@ func (e *Encoder) EncodeBlock(block []byte) (int, error) {
|
||||||
return writ, nil
|
return writ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBlock takes a slice of 256 bytes, each byte after the first 4 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 outputs the resulting decoded (decompressed) 16-bit PCM samples to the decoder's dest writer.
|
// It outputs the resulting decoded (decompressed) 16-bit PCM samples to the decoder's dest writer.
|
||||||
func (d *Decoder) DecodeBlock(block []byte) (int, error) {
|
func (d *decoder) decodeBlock(block []byte) (int, error) {
|
||||||
writ := 0
|
writ := 0
|
||||||
if len(block) != AdpcmBS {
|
if len(block) != AdpcmBS {
|
||||||
return writ, fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), AdpcmBS)
|
return writ, fmt.Errorf("unsupported block size. Given: %v, expected: %v", len(block), AdpcmBS)
|
||||||
|
@ -294,12 +295,15 @@ func (d *Decoder) DecodeBlock(block []byte) (int, error) {
|
||||||
return writ, nil
|
return writ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) Write(inPcm []byte) (int, error) {
|
// Write takes a slice of bytes of arbitrary length representing pcm and encodes in into adpcm.
|
||||||
|
// It writes its output to the encoder's dest.
|
||||||
|
// The number of bytes written out is returned along with any error that occured.
|
||||||
|
func (e *encoder) Write(inPcm []byte) (int, error) {
|
||||||
numBlocks := len(inPcm) / PcmBS
|
numBlocks := len(inPcm) / PcmBS
|
||||||
writ := 0
|
writ := 0
|
||||||
for i := 0; i < numBlocks; i++ {
|
for i := 0; i < numBlocks; i++ {
|
||||||
block := inPcm[PcmBS*i : PcmBS*(i+1)]
|
block := inPcm[PcmBS*i : PcmBS*(i+1)]
|
||||||
writB, err := e.EncodeBlock(block)
|
writB, err := e.encodeBlock(block)
|
||||||
writ += writB
|
writ += writB
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return writ, err
|
return writ, err
|
||||||
|
@ -309,12 +313,15 @@ func (e *Encoder) Write(inPcm []byte) (int, error) {
|
||||||
return writ, nil
|
return writ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decoder) Write(inAdpcm []byte) (int, error) {
|
// Write takes a slice of bytes of arbitrary length representing adpcm and decodes in into pcm.
|
||||||
|
// It writes its output to the decoder's dest.
|
||||||
|
// The number of bytes written out is returned along with any error that occured.
|
||||||
|
func (d *decoder) Write(inAdpcm []byte) (int, error) {
|
||||||
numBlocks := len(inAdpcm) / AdpcmBS
|
numBlocks := len(inAdpcm) / AdpcmBS
|
||||||
writ := 0
|
writ := 0
|
||||||
for i := 0; i < numBlocks; i++ {
|
for i := 0; i < numBlocks; i++ {
|
||||||
block := inAdpcm[AdpcmBS*i : AdpcmBS*(i+1)]
|
block := inAdpcm[AdpcmBS*i : AdpcmBS*(i+1)]
|
||||||
writB, err := d.DecodeBlock(block)
|
writB, err := d.decodeBlock(block)
|
||||||
writ += writB
|
writ += writB
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return writ, err
|
return writ, err
|
||||||
|
|
Loading…
Reference in New Issue