mirror of
https://github.com/bloeys/wavy.git
synced 2025-12-29 09:28:19 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2af3583f6f | |||
| daf46e5d41 | |||
| 8f19e800f1 | |||
| aa751bbedd | |||
| 989547c14e | |||
| 2d0f00175a |
16
README.md
16
README.md
@ -29,8 +29,9 @@ If you are using iOS or Linux please check [this](https://github.com/hajimehoshi
|
||||
|
||||
## Supported audio formats
|
||||
|
||||
- MP3
|
||||
- Wav/Wave
|
||||
- MP3 (`.mp3`)
|
||||
- Wav (`.wav`/`.wave`)
|
||||
- OGG (`.ogg`)
|
||||
|
||||
## Usage
|
||||
|
||||
@ -49,8 +50,9 @@ import (
|
||||
|
||||
func main() {
|
||||
|
||||
//At the start if your program you should init wavy and tell it the sampling rate of your sounds (usually 44100),
|
||||
//the number of channels (usually 2) and the number of bytes per channel (usually 2).
|
||||
//At the start if your program you should init wavy and tell it the
|
||||
//sampling rate of your sounds (usually 44100), the number of
|
||||
//channels (usually 2) and the number of bytes per channel (usually 2).
|
||||
//
|
||||
//These settings will be used for all sounds regardless of their actual settings
|
||||
err := wavy.Init(wavy.SampleRate_44100, wavy.SoundChannelCount_2, wavy.SoundBitDepth_2)
|
||||
@ -70,7 +72,8 @@ func main() {
|
||||
mySound.PlaySync()
|
||||
|
||||
//Since the sound finished playing, lets reset to start
|
||||
//by seeking to 0% then play again. Seeking to 0.5 then playing will start from the middle the sound.
|
||||
//by seeking to 0% then play again. Seeking to 0.5 then playing
|
||||
//will start from the middle the sound.
|
||||
mySound.SeekToPercent(0)
|
||||
mySound.PlayAsync()
|
||||
|
||||
@ -131,7 +134,8 @@ mySound.PlaySync()
|
||||
//Set volume to 25%
|
||||
mySound.SetVolume(0.25)
|
||||
|
||||
//Play the sound three times and wait for all 3 plays to finish. Negative numbers will play infinitely till paused
|
||||
//Play the sound three times and wait for all 3 plays to finish.
|
||||
//Negative numbers will play infinitely till paused
|
||||
mySound.LoopAsync(3)
|
||||
mySound.WaitLoop()
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@ -6,10 +6,12 @@ require (
|
||||
github.com/go-audio/wav v1.1.0
|
||||
github.com/hajimehoshi/go-mp3 v0.3.3
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0
|
||||
github.com/jfreymuth/oggvorbis v1.0.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-audio/audio v1.0.0 // indirect
|
||||
github.com/go-audio/riff v1.0.0 // indirect
|
||||
github.com/jfreymuth/vorbis v1.0.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@ -9,6 +9,10 @@ github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0Ubt
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0 h1:/h+UkbKzhD7xBHOQlWgKUplBPZ+J4DK3P2Y7g2UF1X4=
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0/go.mod h1:9i0oYbpJ8BhVGkXDKdXKfFthX1JUNfXjeTp944W8TGM=
|
||||
github.com/jfreymuth/oggvorbis v1.0.3 h1:MLNGGyhOMiVcvea9Dp5+gbs2SAwqwQbtrWnonYa0M0Y=
|
||||
github.com/jfreymuth/oggvorbis v1.0.3/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
|
||||
75
ogg_streamer.go
Executable file
75
ogg_streamer.go
Executable file
@ -0,0 +1,75 @@
|
||||
package wavy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/jfreymuth/oggvorbis"
|
||||
)
|
||||
|
||||
var _ io.ReadSeeker = &OggStreamer{}
|
||||
|
||||
type OggStreamer struct {
|
||||
F *os.File
|
||||
Dec *oggvorbis.Reader
|
||||
|
||||
//TODO: This is currently needed because of https://github.com/hajimehoshi/oto/issues/171
|
||||
//We should be able to delete once its resolved
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (ws *OggStreamer) Read(outBuf []byte) (floatsRead int, err error) {
|
||||
|
||||
ws.mutex.Lock()
|
||||
|
||||
readerBuf := make([]float32, len(outBuf)/2)
|
||||
floatsRead, err = ws.Dec.Read(readerBuf)
|
||||
F32ToUnsignedPCM16(readerBuf[:floatsRead], outBuf)
|
||||
|
||||
ws.mutex.Unlock()
|
||||
|
||||
return floatsRead * 2, err
|
||||
}
|
||||
|
||||
func (ws *OggStreamer) Seek(offset int64, whence int) (int64, error) {
|
||||
|
||||
ws.mutex.Lock()
|
||||
defer ws.mutex.Unlock()
|
||||
|
||||
//This is because ogg expects position in samples not bytes
|
||||
offset /= BytesPerSample
|
||||
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
if err := ws.Dec.SetPosition(offset); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
case io.SeekCurrent:
|
||||
|
||||
if err := ws.Dec.SetPosition(ws.Dec.Position() + offset); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
case io.SeekEnd:
|
||||
if err := ws.Dec.SetPosition(ws.Dec.Length() + offset); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return ws.Dec.Position() * BytesPerSample, nil
|
||||
}
|
||||
|
||||
//Size returns number of bytes
|
||||
func (ws *OggStreamer) Size() int64 {
|
||||
return ws.Dec.Length() * BytesPerSample
|
||||
}
|
||||
|
||||
func NewOggStreamer(f *os.File, dec *oggvorbis.Reader) *OggStreamer {
|
||||
return &OggStreamer{
|
||||
F: f,
|
||||
Dec: dec,
|
||||
mutex: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ const (
|
||||
SoundType_Unknown SoundType = iota
|
||||
SoundType_MP3
|
||||
SoundType_WAV
|
||||
SoundType_OGG
|
||||
)
|
||||
|
||||
type SampleRate int
|
||||
|
||||
BIN
test_audio_files/camera.mp3
Executable file
BIN
test_audio_files/camera.mp3
Executable file
Binary file not shown.
BIN
test_audio_files/camera.ogg
Executable file
BIN
test_audio_files/camera.ogg
Executable file
Binary file not shown.
94
wav_streamer.go
Executable file
94
wav_streamer.go
Executable file
@ -0,0 +1,94 @@
|
||||
package wavy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/go-audio/wav"
|
||||
)
|
||||
|
||||
var _ io.ReadSeeker = &WavStreamer{}
|
||||
|
||||
type WavStreamer struct {
|
||||
F *os.File
|
||||
Dec *wav.Decoder
|
||||
Pos int64
|
||||
PCMStart int64
|
||||
|
||||
//TODO: This is currently needed because of https://github.com/hajimehoshi/oto/issues/171
|
||||
//We should be able to delete once its resolved
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (ws *WavStreamer) Read(outBuf []byte) (bytesRead int, err error) {
|
||||
|
||||
ws.mutex.Lock()
|
||||
bytesRead, err = ws.Dec.PCMChunk.Read(outBuf)
|
||||
ws.Pos += int64(bytesRead)
|
||||
ws.mutex.Unlock()
|
||||
|
||||
return bytesRead, err
|
||||
}
|
||||
|
||||
func (ws *WavStreamer) Seek(offset int64, whence int) (int64, error) {
|
||||
|
||||
ws.mutex.Lock()
|
||||
defer ws.mutex.Unlock()
|
||||
|
||||
//This will only seek the underlying file but not the actual decoder because it can't seek
|
||||
n, err := ws.Dec.Seek(offset, whence)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
//Since underlying decoder can't seek back, if the requested movement is back we have to rewind the decoder
|
||||
//then seek forward to the requested position.
|
||||
if n < ws.Pos {
|
||||
|
||||
err = ws.Dec.Rewind()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
//Anything before PCMStart is not valid sound, so the minimum seek back we allow is PCMStart
|
||||
if n < ws.PCMStart {
|
||||
n = ws.PCMStart
|
||||
} else {
|
||||
n, err = ws.Dec.Seek(offset, whence)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ws.Pos = n
|
||||
return n, err
|
||||
}
|
||||
|
||||
//Size returns number of bytes
|
||||
func (ws *WavStreamer) Size() int64 {
|
||||
return ws.Dec.PCMLen()
|
||||
}
|
||||
|
||||
func NewWavStreamer(f *os.File, wavDec *wav.Decoder) (*WavStreamer, error) {
|
||||
|
||||
err := wavDec.FwdToPCM()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//The actual data starts somewhat within the file, not at 0
|
||||
currPos, err := wavDec.Seek(0, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &WavStreamer{
|
||||
F: f,
|
||||
Dec: wavDec,
|
||||
Pos: currPos,
|
||||
PCMStart: currPos,
|
||||
mutex: sync.Mutex{},
|
||||
}, nil
|
||||
}
|
||||
121
wavy.go
121
wavy.go
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
@ -12,6 +13,7 @@ import (
|
||||
"github.com/go-audio/wav"
|
||||
"github.com/hajimehoshi/go-mp3"
|
||||
"github.com/hajimehoshi/oto/v2"
|
||||
"github.com/jfreymuth/oggvorbis"
|
||||
)
|
||||
|
||||
//SoundInfo contains static info about a loaded sound file
|
||||
@ -19,7 +21,6 @@ type SoundInfo struct {
|
||||
Type SoundType
|
||||
Mode SoundMode
|
||||
|
||||
//Size is the sound's size in bytes
|
||||
Size int64
|
||||
}
|
||||
|
||||
@ -232,12 +233,14 @@ func (s *Sound) IsPlaying() bool {
|
||||
//percent is clamped [0,1], so passing <0 is the same as zero, and >1 is the same as 1
|
||||
func (s *Sound) SeekToPercent(percent float64) {
|
||||
|
||||
percent = clamp01F64(percent)
|
||||
s.Data.Seek(int64(float64(s.Info.Size)*percent), io.SeekStart)
|
||||
|
||||
//NOTE: Due to https://github.com/hajimehoshi/oto/issues/171, it is safer to seek before reset so we don't seek while a read is happening.
|
||||
//This can still happen though if for example sound was paused midway then seeked, as read would be getting called
|
||||
if !s.IsPlaying() {
|
||||
s.Player.Reset()
|
||||
}
|
||||
|
||||
percent = clamp01F64(percent)
|
||||
s.Data.Seek(int64(float64(s.Info.Size)*percent), io.SeekStart)
|
||||
}
|
||||
|
||||
//SeekToTime moves the current position of the sound to the given duration.
|
||||
@ -248,10 +251,6 @@ func (s *Sound) SeekToPercent(percent float64) {
|
||||
//t is clamped between [0, totalTime]
|
||||
func (s *Sound) SeekToTime(t time.Duration) {
|
||||
|
||||
if !s.IsPlaying() {
|
||||
s.Player.Reset()
|
||||
}
|
||||
|
||||
byteCount := ByteCountFromPlayTime(t)
|
||||
if byteCount < 0 {
|
||||
byteCount = 0
|
||||
@ -260,6 +259,10 @@ func (s *Sound) SeekToTime(t time.Duration) {
|
||||
}
|
||||
|
||||
s.Data.Seek(byteCount, io.SeekStart)
|
||||
|
||||
if !s.IsPlaying() {
|
||||
s.Player.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Sound) IsClosed() bool {
|
||||
@ -379,7 +382,7 @@ func NewSoundStreaming(fpath string) (s *Sound, err error) {
|
||||
},
|
||||
}
|
||||
|
||||
err = soundFromReaderSeeker(file, s)
|
||||
err = soundFromFile(file, s)
|
||||
if err != nil {
|
||||
return nil, getLoadingErr(fpath, err)
|
||||
}
|
||||
@ -387,6 +390,49 @@ func NewSoundStreaming(fpath string) (s *Sound, err error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func soundFromFile(f *os.File, s *Sound) error {
|
||||
|
||||
if s.Info.Type == SoundType_MP3 {
|
||||
|
||||
dec, err := mp3.NewDecoder(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Data = dec
|
||||
s.Player = Ctx.NewPlayer(dec)
|
||||
s.Info.Size = dec.Length()
|
||||
} else if s.Info.Type == SoundType_WAV {
|
||||
|
||||
ws, err := NewWavStreamer(f, wav.NewDecoder(f))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Data = ws
|
||||
s.Player = Ctx.NewPlayer(ws)
|
||||
s.Info.Size = ws.Size()
|
||||
} else if s.Info.Type == SoundType_OGG {
|
||||
|
||||
oggReader, err := oggvorbis.NewReader(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oggStreamer := NewOggStreamer(f, oggReader)
|
||||
|
||||
s.Data = oggStreamer
|
||||
s.Player = Ctx.NewPlayer(oggStreamer)
|
||||
s.Info.Size = oggStreamer.Size()
|
||||
}
|
||||
|
||||
if s.Data == nil {
|
||||
panic("invalid sound type. This is probably a bug!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//NewSoundMem loads the entire sound file into memory
|
||||
func NewSoundMem(fpath string) (s *Sound, err error) {
|
||||
|
||||
@ -408,7 +454,7 @@ func NewSoundMem(fpath string) (s *Sound, err error) {
|
||||
},
|
||||
}
|
||||
|
||||
err = soundFromReaderSeeker(bytesReader, s)
|
||||
err = decodeSoundFromReaderSeeker(bytesReader, s)
|
||||
if err != nil {
|
||||
return nil, getLoadingErr(fpath, err)
|
||||
}
|
||||
@ -420,7 +466,9 @@ func getLoadingErr(fpath string, err error) error {
|
||||
return fmt.Errorf("failed to load '%s' with err '%s'", fpath, err.Error())
|
||||
}
|
||||
|
||||
func soundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
||||
//decodeSoundFromReaderSeeker reads and decodes till EOF, and places the final
|
||||
//PCM16 data in a buffer, thus producing an in-memory sound
|
||||
func decodeSoundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
||||
|
||||
if s.Info.Type == SoundType_MP3 {
|
||||
|
||||
@ -438,8 +486,6 @@ func soundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
||||
s.Data = sb
|
||||
s.Player = Ctx.NewPlayer(sb)
|
||||
s.Info.Size = int64(len(sb.Data))
|
||||
return nil
|
||||
|
||||
} else if s.Info.Type == SoundType_WAV {
|
||||
|
||||
wavDec := wav.NewDecoder(r)
|
||||
@ -457,10 +503,24 @@ func soundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
||||
s.Data = sb
|
||||
s.Player = Ctx.NewPlayer(sb)
|
||||
s.Info.Size = int64(len(sb.Data))
|
||||
return nil
|
||||
} else if s.Info.Type == SoundType_OGG {
|
||||
|
||||
soundData, _, err := oggvorbis.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
panic("invalid sound type")
|
||||
sb := &SoundBuffer{Data: F32ToUnsignedPCM16(soundData, nil)}
|
||||
s.Data = sb
|
||||
s.Player = Ctx.NewPlayer(sb)
|
||||
s.Info.Size = int64(len(sb.Data))
|
||||
}
|
||||
|
||||
if s.Data == nil {
|
||||
panic("invalid sound type. This is probably a bug!")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetSoundFileType(fpath string) SoundType {
|
||||
@ -471,6 +531,8 @@ func GetSoundFileType(fpath string) SoundType {
|
||||
return SoundType_MP3
|
||||
case ".wav", ".wave":
|
||||
return SoundType_WAV
|
||||
case ".ogg":
|
||||
return SoundType_OGG
|
||||
default:
|
||||
return SoundType_Unknown
|
||||
}
|
||||
@ -534,3 +596,32 @@ func clamp01F64(x float64) float64 {
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
//F32ToUnsignedPCM16 takes PCM data stored as float32 between [-1, 1]
|
||||
//and returns a byte array of uint16, where each two subsequent bytes represent one uint16.
|
||||
func F32ToUnsignedPCM16(fs []float32, outBuf []byte) []byte {
|
||||
|
||||
if outBuf == nil {
|
||||
outBuf = make([]byte, len(fs)*2)
|
||||
}
|
||||
|
||||
for i := 0; i < len(fs); i++ {
|
||||
|
||||
//Remap [-1,1]->[-32768, 32767], then re-interprets the int16 as a uint16.
|
||||
//With this, the negative values are mapped into the higher half of the uint16 range,
|
||||
//while positive values remain unchanged
|
||||
x := fs[i]
|
||||
var u16 uint16
|
||||
if x < 0 {
|
||||
u16 = uint16(x * -math.MinInt16)
|
||||
} else {
|
||||
u16 = uint16(x * math.MaxInt16)
|
||||
}
|
||||
|
||||
baseIndex := i * 2
|
||||
outBuf[baseIndex] = byte(u16 >> 0)
|
||||
outBuf[baseIndex+1] = byte(u16 >> 8)
|
||||
}
|
||||
|
||||
return outBuf
|
||||
}
|
||||
|
||||
56
wavy_test.go
56
wavy_test.go
@ -7,19 +7,29 @@ import (
|
||||
"github.com/bloeys/wavy"
|
||||
)
|
||||
|
||||
func TestSound(t *testing.T) {
|
||||
func TestWavy(t *testing.T) {
|
||||
t.Run("Init", TestInit)
|
||||
t.Run("MP3", MP3Subtest)
|
||||
t.Run("Wav", WavSubtest)
|
||||
t.Run("Ogg", OggSubtest)
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
|
||||
err := wavy.Init(wavy.SampleRate_44100, wavy.SoundChannelCount_2, wavy.SoundBitDepth_2)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to init wavy. Err: %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func MP3Subtest(t *testing.T) {
|
||||
|
||||
const fatihaFilepath = "./test_audio_files/Fatiha.mp3"
|
||||
const tadaFilepath = "./test_audio_files/tada.mp3"
|
||||
const fatihaLenMS = 55484
|
||||
|
||||
//Streaming
|
||||
//Mp3 streaming
|
||||
s, err := wavy.NewSoundStreaming(fatihaFilepath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load streaming sound with path '%s'. Err: %s\n", fatihaFilepath, err)
|
||||
@ -47,7 +57,7 @@ func TestSound(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
//In-Memory
|
||||
//Mp3 in-memory
|
||||
s, err = wavy.NewSoundMem(fatihaFilepath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load memory sound with path '%s'. Err: %s\n", fatihaFilepath, err)
|
||||
@ -75,7 +85,7 @@ func TestSound(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
//Memory 'tada.mp3'
|
||||
//'tada.mp3' memory
|
||||
s, err = wavy.NewSoundMem(tadaFilepath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load memory sound with path '%s'. Err: %s\n", tadaFilepath, err)
|
||||
@ -103,15 +113,49 @@ func TestSound(t *testing.T) {
|
||||
s3 := wavy.ClipInMemSoundPercent(s2, 0, 0.25)
|
||||
s3.LoopAsync(3)
|
||||
s3.WaitLoop()
|
||||
}
|
||||
|
||||
func WavSubtest(t *testing.T) {
|
||||
|
||||
//Wav
|
||||
const wavFPath = "./test_audio_files/camera.wav"
|
||||
s, err = wavy.NewSoundMem(wavFPath)
|
||||
|
||||
s, err := wavy.NewSoundMem(wavFPath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load memory sound with path '%s'. Err: %s\n", wavFPath, err)
|
||||
return
|
||||
}
|
||||
s.PlaySync()
|
||||
|
||||
//Wav streaming
|
||||
s, err = wavy.NewSoundStreaming(wavFPath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load streaming sound with path '%s'. Err: %s\n", wavFPath, err)
|
||||
return
|
||||
}
|
||||
s.PlaySync()
|
||||
s.SeekToPercent(0.5)
|
||||
s.PlaySync()
|
||||
}
|
||||
|
||||
func OggSubtest(t *testing.T) {
|
||||
|
||||
const oggFPath = "./test_audio_files/camera.ogg"
|
||||
s, err := wavy.NewSoundMem(oggFPath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load memory sound with path '%s'. Err: %s\n", oggFPath, err)
|
||||
return
|
||||
}
|
||||
s.PlaySync()
|
||||
|
||||
//Ogg streaming
|
||||
s, err = wavy.NewSoundStreaming(oggFPath)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to load streaming sound with path '%s'. Err: %s\n", oggFPath, err)
|
||||
return
|
||||
}
|
||||
s.PlaySync()
|
||||
s.SeekToPercent(.5)
|
||||
s.PlaySync()
|
||||
}
|
||||
|
||||
func TestByteCountFromPlayTime(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user