Skip to content

Instantly share code, notes, and snippets.

@nicklanng
Created February 20, 2018 21:58
Show Gist options
  • Save nicklanng/77a4fcebf83ccf303a069ab83283fbdd to your computer and use it in GitHub Desktop.
Save nicklanng/77a4fcebf83ccf303a069ab83283fbdd to your computer and use it in GitHub Desktop.
adpcm
package main
// useful links
// http://wavefilegem.com/how_wave_files_work.html
// https://wiki.multimedia.cx/index.php/Microsoft_ADPCM
// https://github.com/bovarysme/adpcm/blob/master/status.go
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
)
type riffChunk struct {
FileSize uint32
FormatCode [4]byte
}
func (c riffChunk) String() string {
msg := `RIFF CHUNK
FileSize: %d
FormatCode: %s
`
return fmt.Sprintf(
msg,
c.FileSize,
c.FormatCode,
)
}
type fmtChunk struct {
FormatType uint16
NumChans uint16
SampleRate uint32
ByteRate uint32
BlockAlign uint16
BitsPerSample uint16
ExtraDataSize uint16
}
func (h fmtChunk) String() string {
msg := `FMT CHUNK
FormatType: %d
NumChans: %d
SampleRate: %d
ByteRate: %d
BlockAlign: %d
BitsPerSample: %d
ExtraDataSize: %d
`
return fmt.Sprintf(
msg,
h.FormatType,
h.NumChans,
h.SampleRate,
h.ByteRate,
h.BlockAlign,
h.BitsPerSample,
h.ExtraDataSize,
)
}
type factChunk struct {
NumberOfSampleFrames uint32
}
func (c factChunk) String() string {
msg := `FACT CHUNK
NumberOfSampleFrames: %d
`
return fmt.Sprintf(
msg,
c.NumberOfSampleFrames,
)
}
type blockPreamble struct {
Predictor uint8
InitialDelta int16
Sample1 int16
Sample2 int16
}
func main() {
var err error
f, err := os.Open("ima44m.wav")
if err != nil {
panic(fmt.Sprintf("couldn't open audio file - %v", err))
}
var riff riffChunk
var fmtt fmtChunk
var fact factChunk
var data []byte
for {
// read chunk name
chunkName := make([]byte, 4)
_, err = f.Read(chunkName)
if err == io.EOF {
break
}
switch string(chunkName) {
case "RIFF":
riff = loadRiff(f)
case "fmt ":
fmtt = loadFmt(f)
case "fact":
fact = loadFact(f)
case "data":
data = loadData(f)
}
}
//read data
bData := bytes.NewReader(data)
for {
block := make([]byte, fmtt.BlockAlign)
if _, err := bData.Read(block); err != nil {
if err == io.EOF {
break
}
}
blockReader := bytes.NewReader(block)
var preamble blockPreamble
if err := binary.Read(blockReader, binary.LittleEndian, &preamble); err != nil {
panic(err)
}
fmt.Println(preamble)
var b byte
for {
if b, err = blockReader.ReadByte(); err != nil {
if err == io.EOF {
break
}
}
high := b >> 4
low := b & 0x0F
fmt.Print(high)
fmt.Print(" ")
fmt.Print(low)
fmt.Print(" ")
// perform maths on nibbles to decompress
}
fmt.Println()
}
fmt.Println(riff)
fmt.Println(fmtt)
fmt.Println(fact)
}
func loadRiff(r io.Reader) riffChunk {
// get data
bData := make([]byte, 8)
if _, err := r.Read(bData); err != nil {
panic(err)
}
// read chunk in little endian
var chunk riffChunk
if err := binary.Read(bytes.NewReader(bData), binary.LittleEndian, &chunk); err != nil {
panic(err)
}
return chunk
}
func loadFmt(r io.Reader) fmtChunk {
// get chunk size
var chunkSize int32
if err := binary.Read(r, binary.LittleEndian, &chunkSize); err != nil {
panic(err)
}
// copy chunk from file to new buffer
bChunk := make([]byte, chunkSize)
if _, err := r.Read(bChunk); err != nil {
panic(err)
}
// read chunk in little endian
var chunk fmtChunk
if err := binary.Read(bytes.NewReader(bChunk), binary.LittleEndian, &chunk); err != nil {
panic(err)
}
return chunk
}
func loadFact(r io.Reader) factChunk {
// get chunk size
var chunkSize int32
if err := binary.Read(r, binary.LittleEndian, &chunkSize); err != nil {
panic(err)
}
// copy chunk from file to new buffer
bChunk := make([]byte, chunkSize)
if _, err := r.Read(bChunk); err != nil {
panic(err)
}
// read chunk in little endian
var chunk factChunk
if err := binary.Read(bytes.NewReader(bChunk), binary.LittleEndian, &chunk); err != nil {
panic(err)
}
return chunk
}
func loadData(r io.Reader) []byte {
// get chunk size
var chunkSize int32
if err := binary.Read(r, binary.LittleEndian, &chunkSize); err != nil {
panic(err)
}
// copy chunk from file to new buffer
bChunk := make([]byte, chunkSize)
if _, err := r.Read(bChunk); err != nil {
panic(err)
}
return bChunk
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment