ADPCM: unexported encoder and decoder structs, documented Write funcs.

This commit is contained in:
Trek H 2019-03-15 17:22:19 +10:30
parent fdc4d880ac
commit d4e0c87635
1 changed files with 30 additions and 23 deletions

View File

@ -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