Files
questshock/modding/hacked/ss1/content/audio/wav/WaveLoader.go
T

134 lines
3.0 KiB
Go

package wav
import (
"bytes"
"encoding/binary"
"io"
"github.com/inkyblackness/hacked/ss1"
)
const (
errUnsupportedFormat ss1.StringError = "unsupported WAVE format"
)
func l8FromL8(input []byte) []byte {
return input
}
func l8FromL16(input []byte) []byte {
samples := len(input) / 2
output := make([]byte, samples)
for i := 0; i < samples; i++ {
output[i] = byte(int(input[i*2+1]) + 0x80)
}
return output
}
type waveLoader struct {
dataRead bool
formatRead bool
samples []byte
sampleRate float32
reader io.Reader
err error
dataConverter func([]byte) []byte
}
func (loader *waveLoader) load(reader io.Reader) {
loader.reader = reader
loader.dataConverter = l8FromL8
loader.loadRiff()
}
func (loader *waveLoader) read(data interface{}) bool {
if loader.err == nil {
loader.err = binary.Read(loader.reader, binary.LittleEndian, data)
}
return loader.err == nil
}
func (loader *waveLoader) readBytes(size uint32) (data []byte) {
data = make([]byte, int(size))
_, loader.err = loader.reader.Read(data)
return
}
func (loader *waveLoader) loadChunk(handler func(riffChunkType, uint32)) {
var tag riffChunkTag
if loader.read(&tag) {
handler(tag.ChunkType, tag.Size)
}
}
func (loader *waveLoader) loadRiff() {
loader.loadChunk(loader.handleRiff)
}
func (loader *waveLoader) handleRiff(chunkType riffChunkType, size uint32) {
if chunkType == riffChunkTypeRiff {
var contentType riffContentType
if loader.read(&contentType) && (contentType == riffContentTypeWave) {
loader.loadWave()
} else if loader.err == nil {
loader.err = errNotASupportedWave
}
} else {
loader.err = errNotASupportedWave
}
}
func (loader *waveLoader) loadWave() {
for !loader.isDone() {
loader.loadFormatOrData()
}
loader.samples = loader.dataConverter(loader.samples)
}
func (loader *waveLoader) loadFormatOrData() {
loader.loadChunk(loader.handleFormatOrData)
}
func (loader *waveLoader) handleFormatOrData(chunkType riffChunkType, size uint32) {
if chunkType == riffChunkTypeFmt {
loader.loadFormat(size)
} else if chunkType == riffChunkTypeData {
loader.loadData(size)
}
}
func (loader *waveLoader) loadFormat(size uint32) {
headerData := loader.readBytes(size)
headerReader := bytes.NewReader(headerData)
var header formatHeader
loader.formatRead = true
loader.err = binary.Read(headerReader, binary.LittleEndian, &header.base)
loader.err = binary.Read(headerReader, binary.LittleEndian, &header.extension.BitsPerSample)
loader.sampleRate = float32(header.base.SamplesPerSec)
if header.extension.BitsPerSample == 16 {
loader.dataConverter = l8FromL16
}
if (header.base.FormatType != waveFormatTypePcm) ||
(header.base.Channels != 1) ||
((header.extension.BitsPerSample != 8) && (header.extension.BitsPerSample != 16)) {
loader.err = errUnsupportedFormat
}
}
func (loader *waveLoader) loadData(size uint32) {
loader.dataRead = true
loader.samples = loader.readBytes(size)
}
func (loader *waveLoader) isDone() bool {
return (loader.err != nil) || (loader.dataRead && loader.formatRead)
}