134 lines
3.0 KiB
Go
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)
|
|
}
|