diff --git a/cmd/adpcmgo/cmd/encode/encode.go b/cmd/adpcmgo/cmd/encode/encode.go index befb0aff..73a7e38d 100644 --- a/cmd/adpcmgo/cmd/encode/encode.go +++ b/cmd/adpcmgo/cmd/encode/encode.go @@ -1,22 +1,38 @@ package main import ( + "flag" "fmt" "io/ioutil" - "github.com/bovarysme/adpcm" + "bitbucket.org/ausocean/av/cmd/adpcmgo" ) -// WIP func main() { + var inPath string + flag.StringVar(&inPath, "path", "test.pcm", "file path of input data") + flag.Parse() //read pcm pcm, err := ioutil.ReadFile(inPath) if err != nil { panic(err) } + //encode adpcm var comp []byte - adpcm.Encode(pcm, &comp) + start := 0 + for i := 0; i < len(pcm); i++ { + if i%1010 == 1009 { + block := pcm[start : i+1] + encBlock, err := adpcmgo.EncodeBlock(block) + if err != nil { + //todo: use correct logging of error + panic(err) + } + comp = append(comp, encBlock...) + start = i + 1 + } + } // save adpcm to file adpcmPath := "out.adpcm" err = ioutil.WriteFile(adpcmPath, comp, 0644) diff --git a/cmd/adpcmgo/codec.go b/cmd/adpcmgo/codec.go index 98e9196c..e79d981f 100644 --- a/cmd/adpcmgo/codec.go +++ b/cmd/adpcmgo/codec.go @@ -1,18 +1,19 @@ package adpcmgo import ( + "encoding/binary" "fmt" "math" ) // table of index changes -var indexTable = []int{ +var indexTable = []int16{ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8, } // quantize step size table -var stepTable = []int{ +var stepTable = []int16{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, @@ -28,25 +29,24 @@ var stepTable = []int{ } var ( - encPred = 0 - encIndex = 0 - encStep = 7 - decPred = 0 - decIndex = 0 - decStep = 7 + encPred int16 + encIndex int16 + decPred int16 + decIndex int16 + decStep int16 = 7 ) // EncodeSample takes a single 16 bit PCM sample and // returns a byte of which the last 4 bits are an encoded ADPCM nibble -func EncodeSample(sample int) byte { +func EncodeSample(sample int16) byte { // find difference from predicted sample delta := sample - encPred // set sign bit and find absolute value of difference - var newSample byte + var nibble byte if delta < 0 { - newSample = 8 + nibble = 8 delta = -delta } @@ -57,7 +57,7 @@ func EncodeSample(sample int) byte { // quantize delta down to four bits for i := 0; i < 3; i++ { if delta > step { - newSample |= mask + nibble |= mask delta -= step diff += step } @@ -66,72 +66,110 @@ func EncodeSample(sample int) byte { } // adjust predicted sample based on calculated difference - if newSample&8 != 0 { + if nibble&8 != 0 { encPred -= diff } else { encPred += diff } // check for underflow and overflow - fmt.Print("max, min: ", math.MaxInt16) - fmt.Println(math.MinInt16) if encPred < math.MinInt16 { encPred = math.MinInt16 } else if encPred > math.MaxInt16 { encPred = math.MaxInt16 } - encIndex += indexTable[newSample&7] + encIndex += indexTable[nibble&7] // check for underflow and overflow if encIndex < 0 { encIndex = 0 - } else if encIndex > len(stepTable)-1 { - encIndex = len(stepTable) - 1 + } else if encIndex > int16(len(stepTable)-1) { + encIndex = int16(len(stepTable) - 1) } - return newSample + return nibble } // DecodeSample takes a byte, the last 4 bits of which contain a single -// 4 bit ADPCM value/sample, and returns a 16 bit decoded PCM sample -func DecodeSample(nibble byte) int { +// 4 bit ADPCM nibble, and returns a 16 bit decoded PCM sample +func DecodeSample(nibble byte) int16 { - diff := 0 + // compute predicted sample estimate (decPred): + // calculate difference + var diff int16 if nibble&4 != 0 { diff += decStep } - if nibble&2 != 0 { diff += decStep >> 1 } - if nibble&1 != 0 { diff += decStep >> 2 } - diff += decStep >> 3 - + // account for sign bit if nibble&8 != 0 { diff = -diff } - + // adjust predicted sample based on calculated difference decPred += diff + // check for overflow and underflow if decPred > math.MaxInt16 { decPred = math.MaxInt16 } else if decPred < math.MinInt16 { decPred = math.MinInt16 } + // compute new step size: + + // adjust index into step size lookup table using nibble decIndex += indexTable[nibble] + // check for overflow and underflow if decIndex < 0 { decIndex = 0 - } else if decIndex > len(stepTable)-1 { - decIndex = len(stepTable) - 1 + } else if decIndex > int16(len(stepTable)-1) { + decIndex = int16(len(stepTable) - 1) } + // find new quantizer step size decStep = stepTable[decIndex] return decPred } + +func calcHead(sample []byte) []byte { + fmt.Println(sample[0], sample[1]) + intSample := int16(binary.LittleEndian.Uint16(sample)) + + fmt.Println("before enc", intSample) + + EncodeSample(intSample) + head := sample + + fmt.Println(encIndex) + + head = append(head, byte(uint16(encIndex))) + head = append(head, byte(0x00)) + return head +} + +func EncodeBlock(block []byte) ([]byte, error) { + if len(block) != 1010 { + return nil, fmt.Errorf("unsupported block size. Given: %v, expected: 1010, ie. 505 16-bit PCM samples", len(block)) + } + + result := calcHead(block[0:2]) + + for i := 2; i < len(block); i++ { + if (i+1)%4 == 0 { + sample2 := EncodeSample(int16(binary.LittleEndian.Uint16(block[i-1 : i+1]))) + sample := EncodeSample(int16(binary.LittleEndian.Uint16(block[i+1 : i+3]))) + result = append(result, byte((sample<<4)|sample2)) + + } + } + + return result, nil +}