114 lines
2.3 KiB
Go
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
|
|
}
|