mirror of
https://github.com/jwetzell/bmip10-go.git
synced 2026-09-11 00:59:31 +00:00
add basic working example
This commit is contained in:
@@ -0,0 +1,120 @@
|
|||||||
|
package bmip10
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
SampleStates uint32
|
||||||
|
CodedStates uint32
|
||||||
|
LossyCodeWidth uint32
|
||||||
|
LossyRounding uint32
|
||||||
|
LosslessCodes uint32
|
||||||
|
LossyCodes uint32
|
||||||
|
CodeTables uint32
|
||||||
|
DefaultTable uint32
|
||||||
|
LowestTableThresh uint32
|
||||||
|
HighestTableThresh uint32
|
||||||
|
LossyFlag uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupBMIP10(sampleBits uint32, codedBits uint32) *Config {
|
||||||
|
config := Config{}
|
||||||
|
config.SampleStates = 1 << sampleBits
|
||||||
|
config.CodedStates = 1 << codedBits
|
||||||
|
config.LossyCodeWidth = (1 << (sampleBits - codedBits + 1)) - 1
|
||||||
|
config.LossyRounding = config.LossyCodeWidth / 2
|
||||||
|
config.LosslessCodes = config.CodedStates / 2
|
||||||
|
config.LossyCodes = config.CodedStates / 2
|
||||||
|
config.CodeTables = 1 + config.CodedStates/2
|
||||||
|
config.DefaultTable = config.CodeTables / 2
|
||||||
|
config.LowestTableThresh = config.LosslessCodes / 2
|
||||||
|
config.HighestTableThresh = config.SampleStates - (config.LosslessCodes / 2)
|
||||||
|
config.LossyFlag = (1 << codedBits) / 2
|
||||||
|
|
||||||
|
return &config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the decoded sample to select the next table to use
|
||||||
|
func NextTable(config *Config, sample int32) int32 {
|
||||||
|
if sample < int32(config.LowestTableThresh) {
|
||||||
|
return 0
|
||||||
|
} else if sample >= int32(config.HighestTableThresh) {
|
||||||
|
return int32(config.LossyCodes)
|
||||||
|
} else {
|
||||||
|
return (sample - int32(config.LowestTableThresh) + int32(config.LossyRounding)) / int32(config.LossyCodeWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a given sample and code table calculate the code word
|
||||||
|
func EncodeSample(config *Config, table int32, sample int32) int32 {
|
||||||
|
lossless_low := table * int32(config.LossyCodeWidth)
|
||||||
|
lossless_high := lossless_low + int32(config.LosslessCodes)
|
||||||
|
|
||||||
|
if sample >= lossless_low && sample < lossless_high {
|
||||||
|
return sample - lossless_low
|
||||||
|
} else if sample < lossless_low {
|
||||||
|
|
||||||
|
return int32(config.LossyFlag) | (sample / int32(config.LossyCodeWidth))
|
||||||
|
} else {
|
||||||
|
return int32(config.LossyFlag) | ((sample-lossless_high)/int32(config.LossyCodeWidth) + table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a given code word and code table decode the sample
|
||||||
|
func DecodeSample(config *Config, table int32, code_word int32) int32 {
|
||||||
|
index := code_word & ^int32(config.LossyFlag)
|
||||||
|
if (code_word & int32(config.LossyFlag)) != 0 {
|
||||||
|
if index < table {
|
||||||
|
return index*int32(config.LossyCodeWidth) + int32(config.LossyRounding)
|
||||||
|
} else {
|
||||||
|
return index*int32(config.LossyCodeWidth) + int32(config.LossyRounding) + int32(config.LosslessCodes)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return table*int32(config.LossyCodeWidth) + index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Encoder struct {
|
||||||
|
Config *Config
|
||||||
|
Table int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder(sampleBits uint32, codedBits uint32) *Encoder {
|
||||||
|
config := SetupBMIP10(sampleBits, codedBits)
|
||||||
|
return &Encoder{
|
||||||
|
Config: config,
|
||||||
|
Table: int32(config.DefaultTable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) Encode(sample int32) int32 {
|
||||||
|
code_word := EncodeSample(e.Config, e.Table, sample)
|
||||||
|
decoded := DecodeSample(e.Config, e.Table, code_word)
|
||||||
|
e.Table = NextTable(e.Config, decoded)
|
||||||
|
return code_word
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) Reset(sample int32) {
|
||||||
|
e.Table = int32(e.Config.DefaultTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Decoder struct {
|
||||||
|
Config *Config
|
||||||
|
Table int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecoder(sampleBits uint32, codedBits uint32) *Decoder {
|
||||||
|
config := SetupBMIP10(sampleBits, codedBits)
|
||||||
|
return &Decoder{
|
||||||
|
Config: config,
|
||||||
|
Table: int32(config.DefaultTable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Decode(code_word int32) int32 {
|
||||||
|
decoded := DecodeSample(d.Config, d.Table, code_word)
|
||||||
|
d.Table = NextTable(d.Config, decoded)
|
||||||
|
return decoded
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Reset(sample int32) {
|
||||||
|
d.Table = int32(d.Config.DefaultTable)
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package bmip10
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBMIP10Setup(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
description string
|
||||||
|
sampleBits uint32
|
||||||
|
codedBits uint32
|
||||||
|
expected Config
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "10bit samples 8bit code words",
|
||||||
|
sampleBits: 10,
|
||||||
|
codedBits: 8,
|
||||||
|
expected: Config{
|
||||||
|
SampleStates: 1024,
|
||||||
|
CodedStates: 256,
|
||||||
|
LossyCodeWidth: 7,
|
||||||
|
LossyRounding: 3,
|
||||||
|
LosslessCodes: 128,
|
||||||
|
LossyCodes: 128,
|
||||||
|
CodeTables: 129,
|
||||||
|
DefaultTable: 64,
|
||||||
|
LowestTableThresh: 64,
|
||||||
|
HighestTableThresh: 960,
|
||||||
|
LossyFlag: 128,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range tests {
|
||||||
|
actual := SetupBMIP10(testCase.sampleBits, testCase.codedBits)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, &testCase.expected) {
|
||||||
|
t.Errorf("Test '%s' failed to setup config properly", testCase.description)
|
||||||
|
fmt.Printf("expected: %v\n", testCase.expected)
|
||||||
|
fmt.Printf("actual: %v\n", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
bmip10 "github.com/jwetzell/bmip10-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
decoder := bmip10.NewDecoder(10, 8)
|
||||||
|
|
||||||
|
encodedData := []int32{128, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 116, 143, 163, 196, 250}
|
||||||
|
|
||||||
|
fmt.Printf("index\tenc\tdec\n")
|
||||||
|
|
||||||
|
for i := 0; i < len(encodedData); i++ {
|
||||||
|
decoded := decoder.Decode(encodedData[i])
|
||||||
|
fmt.Printf("%d\t%d\t%d\n", i, encodedData[i], decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
bmip10 "github.com/jwetzell/bmip10-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var rawData []int32 = []int32{1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987}
|
||||||
|
encoder := bmip10.NewEncoder(10, 8)
|
||||||
|
|
||||||
|
fmt.Printf("index\traw\tenc\n")
|
||||||
|
for i := 0; i < len(rawData); i++ {
|
||||||
|
encoded := encoder.Encode(rawData[i])
|
||||||
|
fmt.Printf("%d\t%d\t%d\n", i, rawData[i], encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user