readded Supercharger WAV loading using go-audio/wav package

This commit is contained in:
JetSetIlly 2022-05-26 16:06:36 +01:00
parent 7e57bbe46c
commit d47bbe01c3
5 changed files with 65 additions and 19 deletions

View file

@ -204,6 +204,7 @@ The following projects are used in the `Gopher2600` project:
* https://github.com/go-gl/gl
* https://github.com/hajimehoshi/go-mp3
* https://github.com/pkg/term
* https://github.com/go-audio/wav
* FontAwesome
* https://fontawesome.com/

6
go.mod
View file

@ -11,3 +11,9 @@ require (
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
)
require (
github.com/go-audio/audio v1.0.0 // indirect
github.com/go-audio/riff v1.0.0 // indirect
github.com/go-audio/wav v1.1.0 // indirect
)

6
go.sum
View file

@ -1,4 +1,10 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4=
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA=
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
github.com/go-audio/wav v1.1.0 h1:jQgLtbqBzY7G+BM8fXF7AHUk1uHUviWS4X39d5rsL2g=
github.com/go-audio/wav v1.1.0/go.mod h1:mpe9qfwbScEbkd8uybLuIpTgHyrISw/OTuvjUW2iGtE=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/hajimehoshi/go-mp3 v0.3.3 h1:cWnfRdpye2m9ElSoVqneYRcpt/l3ijttgjMeQh+r+FE=

View file

@ -93,7 +93,11 @@ func newSoundLoad(cart *Supercharger, loader cartridgeloader.Loader) (tape, erro
// get PCM data from data loaded from file
tap.pcm, err = getPCM(loader)
if err != nil {
return nil, err
return nil, fmt.Errorf("soundload: %v", err)
}
if len(tap.pcm.data) == 0 {
return nil, fmt.Errorf("soundload: no PCM data in file")
}
// the length of time of each sample in microseconds

View file

@ -21,17 +21,15 @@ import (
"path/filepath"
"strings"
// "github.com/go-audio/audio"
// "github.com/go-audio/wav".
"github.com/go-audio/wav"
"github.com/hajimehoshi/go-mp3"
"github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/logger"
)
type pcmData struct {
totalTime float64
totalTime float64 // in seconds
sampleRate float64
// data is mono data (taken from the left channel in the case of stero
@ -46,32 +44,55 @@ func getPCM(cl cartridgeloader.Loader) (pcmData, error) {
switch strings.ToLower(filepath.Ext(cl.Filename)) {
case ".wav":
return pcmData{}, curated.Errorf("wav files not currently supported (%s)", cl.Filename)
dec := wav.NewDecoder(cl.StreamedData)
if dec == nil {
return p, fmt.Errorf("wav: error decoding")
}
if !dec.IsValidFile() {
return p, fmt.Errorf("wav: not a valid wav file")
}
logger.Log(soundloadLogTag, "loading from wav file")
// load all data at once
buf, err := dec.FullPCMBuffer()
if err != nil {
return p, fmt.Errorf("soundload: wav: %v", err)
}
floatBuf := buf.AsFloat32Buffer()
// copy first channel only of data stream
p.data = make([]float32, 0, len(floatBuf.Data)/int(dec.NumChans))
for i := 0; i < len(floatBuf.Data); i += int(dec.NumChans) {
p.data = append(p.data, floatBuf.Data[i])
}
// sample rate
p.sampleRate = float64(dec.SampleRate)
// total time of recording in seconds
dur, err := dec.Duration()
if err != nil {
return p, fmt.Errorf("wav: %v", err)
}
p.totalTime = dur.Seconds()
case ".mp3":
dec, err := mp3.NewDecoder(cl.StreamedData)
if err != nil {
return p, fmt.Errorf("soundload: mp3: %v", err)
return p, fmt.Errorf("mp3: %v", err)
}
logger.Log(soundloadLogTag, "loading from mp3 file")
// according to the go-mp3 docs:
//
// "The stream is always formatted as 16bit (little endian) 2 channels even if
// the source is single channel MP3. Thus, a sample always consists of 4
// bytes.".
p.sampleRate = float64(dec.SampleRate())
logger.Log(soundloadLogTag, "using left channel only")
err = nil
chunk := make([]byte, 4096)
for err != io.EOF {
var chunkLen int
chunkLen, err = dec.Read(chunk)
if err != nil && err != io.EOF {
return p, fmt.Errorf("soundload: mp3: %v", err)
return p, fmt.Errorf("mp3: %v", err)
}
// index increment of 4 because:
@ -92,9 +113,17 @@ func getPCM(cl cartridgeloader.Loader) (pcmData, error) {
p.data = append(p.data, float32(f))
}
}
}
p.totalTime = float64(len(p.data)) / p.sampleRate
// according to the go-mp3 docs:
//
// "The stream is always formatted as 16bit (little endian) 2 channels even if
// the source is single channel MP3. Thus, a sample always consists of 4
// bytes.".
p.sampleRate = float64(dec.SampleRate())
// total time of recording in seconds
p.totalTime = float64(len(p.data)) / p.sampleRate
}
logger.Logf(soundloadLogTag, "sample rate: %0.2fHz", p.sampleRate)
logger.Logf(soundloadLogTag, "total time: %.02fs", p.totalTime)