Created
February 20, 2018 21:58
-
-
Save nicklanng/77a4fcebf83ccf303a069ab83283fbdd to your computer and use it in GitHub Desktop.
adpcm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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