Files
questshock/modding/hacked/ss1/content/audio/voc/Load.go
T

114 lines
2.3 KiB
Go

package voc
import (
"encoding/binary"
"io"
"github.com/inkyblackness/hacked/ss1"
"github.com/inkyblackness/hacked/ss1/content/audio"
)
const (
errSourceIsNil ss1.StringError = "source is nil"
errNoAudioFound ss1.StringError = "no audio found"
errInvalidVersionValidity ss1.StringError = "version validity check failed"
)
// Load reads from the provided source a Creative Voice Sound and returns the data.
func Load(source io.Reader) (data audio.L8, err error) {
if source == nil {
return data, errSourceIsNil
}
err = readAndVerifyHeader(source)
if err != nil {
return
}
return readSoundData(source)
}
func readAndVerifyHeader(source io.Reader) error {
start := make([]byte, len(FileHeader))
headerSize := uint16(0)
version := uint16(0)
versionValidity := uint16(0)
_, err := source.Read(start)
if err != nil {
return err
}
err = binary.Read(source, binary.LittleEndian, &headerSize)
if err != nil {
return err
}
err = binary.Read(source, binary.LittleEndian, &version)
if err != nil {
return err
}
err = binary.Read(source, binary.LittleEndian, &versionValidity)
if err != nil {
return err
}
calculated := ^version + versionCheckValue
if calculated != versionValidity {
return errInvalidVersionValidity
}
skip := make([]byte, headerSize-standardHeaderSize)
_, err = source.Read(skip)
return err
}
func readSoundData(source io.Reader) (data audio.L8, err error) {
sampleRate := float32(0.0)
var samples []byte
done := false
for !done {
blockStart := make([]byte, 4)
_, err = source.Read(blockStart)
if err != nil {
return
}
switch blockType(blockStart[0]) {
case soundData:
{
meta := make([]byte, 2)
_, err = source.Read(meta)
if err != nil {
return
}
sampleRate = divisorToSampleRate(meta[0])
newCount := lengthFromBlockStart(blockStart) - len(meta)
buf := make([]byte, newCount)
_, err = source.Read(buf)
if err != nil {
return
}
oldCount := len(samples)
newSamples := make([]byte, oldCount+newCount)
copy(newSamples, samples)
copy(newSamples[oldCount:], buf)
samples = newSamples
}
case terminator:
{
done = true
}
}
}
if len(samples) == 0 {
return data, errNoAudioFound
}
return audio.L8{
SampleRate: sampleRate,
Samples: samples,
}, nil
}