mirror of
https://github.com/jwetzell/bmip10-go.git
synced 2026-09-13 10:09:32 +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