mirror of
https://github.com/bloeys/wavy.git
synced 2025-12-29 09:28:19 +00:00
Looping sounds+get volume+pause all+resume all
This commit is contained in:
100
wavy.go
100
wavy.go
@ -25,6 +25,7 @@ type SoundInfo struct {
|
|||||||
|
|
||||||
type Sound struct {
|
type Sound struct {
|
||||||
Player oto.Player
|
Player oto.Player
|
||||||
|
Info SoundInfo
|
||||||
|
|
||||||
//File is the file descriptor of the sound file being streamed.
|
//File is the file descriptor of the sound file being streamed.
|
||||||
//This is only set if sound is streamed, and is kept to ensure GC doesn't hit it
|
//This is only set if sound is streamed, and is kept to ensure GC doesn't hit it
|
||||||
@ -34,7 +35,7 @@ type Sound struct {
|
|||||||
//Becomes nil after close
|
//Becomes nil after close
|
||||||
Data io.ReadSeeker
|
Data io.ReadSeeker
|
||||||
|
|
||||||
Info SoundInfo
|
IsLooping bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//Those values are set after Init
|
//Those values are set after Init
|
||||||
@ -75,22 +76,89 @@ func Init(sr SampleRate, chanCount SoundChannelCount, bitDepth SoundBitDepth) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//PlayAsync plays the sound in the background and returns
|
//Wait blocks until sound finishes playing. If the sound is not playing Wait returns immediately.
|
||||||
|
//In the worst case (Wait sleeping then sound immediately paused), Wait will block ~4% of the total play time.
|
||||||
|
//In most other cases Wait should be accurate to ~1ms
|
||||||
|
func (s *Sound) Wait() {
|
||||||
|
|
||||||
|
if !s.IsPlaying() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//We wait the remaining time in 25 chunks so that if the sound was paused since wait was called we don't keep blocking
|
||||||
|
sleepTime := s.RemainingTime() / 25
|
||||||
|
for s.Player.IsPlaying() {
|
||||||
|
time.Sleep(sleepTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
//If there is anything left it should be tiny so we check frequently
|
||||||
|
for s.Player.IsPlaying() {
|
||||||
|
time.Sleep(time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//PlayAsync plays the sound in the background and returns.
|
||||||
func (s *Sound) PlayAsync() {
|
func (s *Sound) PlayAsync() {
|
||||||
s.Player.Play()
|
s.Player.Play()
|
||||||
}
|
}
|
||||||
|
|
||||||
//PlaySync plays the sound (if its not already playing) and waits for it to finish before returning.
|
//PlaySync calls PlayAsync() followed by Wait()
|
||||||
func (s *Sound) PlaySync() {
|
func (s *Sound) PlaySync() {
|
||||||
|
s.PlayAsync()
|
||||||
if !s.Player.IsPlaying() {
|
s.Wait()
|
||||||
s.Player.Play()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(s.RemainingTime())
|
//LoopAsync plays the sound 'timesToPlay' times.
|
||||||
for s.Player.IsPlaying() || s.Player.UnplayedBufferSize() > 0 {
|
//If timesToPlay<0 then it is played indefinitely until paused
|
||||||
time.Sleep(time.Millisecond)
|
//If timesToPlay==0 then the sound is not played.
|
||||||
|
//If a sound is already playing then it will be paused then resumed in a looping manner
|
||||||
|
func (s *Sound) LoopAsync(timesToPlay int) {
|
||||||
|
|
||||||
|
if timesToPlay == 0 {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.IsPlaying() {
|
||||||
|
s.Pause()
|
||||||
|
s.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.PlayAsync()
|
||||||
|
s.IsLooping = true
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
if timesToPlay < 0 {
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
s.Wait()
|
||||||
|
|
||||||
|
//Check is here because we don't want to seek back if we got paused
|
||||||
|
if !s.IsLooping {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SeekToPercent(0)
|
||||||
|
s.PlayAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for timesToPlay > 0 {
|
||||||
|
|
||||||
|
timesToPlay--
|
||||||
|
s.Wait()
|
||||||
|
|
||||||
|
//Check is here because we don't want to seek back if we got paused
|
||||||
|
if !s.IsLooping {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SeekToPercent(0)
|
||||||
|
s.PlayAsync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
//TotalTime returns the time taken to play the entire sound.
|
//TotalTime returns the time taken to play the entire sound.
|
||||||
@ -124,7 +192,13 @@ func (s *Sound) SetVolume(newVol float64) {
|
|||||||
s.Player.SetVolume(newVol)
|
s.Player.SetVolume(newVol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Volume returns the current volume
|
||||||
|
func (s *Sound) Volume() float64 {
|
||||||
|
return s.Player.Volume()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Sound) Pause() {
|
func (s *Sound) Pause() {
|
||||||
|
s.IsLooping = false
|
||||||
s.Player.Pause()
|
s.Player.Pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,6 +295,14 @@ func CopyInMemSound(s *Sound) *Sound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PauseAllSounds() {
|
||||||
|
Ctx.Suspend()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResumeAllSounds() {
|
||||||
|
Ctx.Resume()
|
||||||
|
}
|
||||||
|
|
||||||
//NewSoundStreaming plays sound by streaming from a file, so no need to load the entire file into memory.
|
//NewSoundStreaming plays sound by streaming from a file, so no need to load the entire file into memory.
|
||||||
//Good for large sound files
|
//Good for large sound files
|
||||||
func NewSoundStreaming(fpath string) (s *Sound, err error) {
|
func NewSoundStreaming(fpath string) (s *Sound, err error) {
|
||||||
|
|||||||
@ -87,8 +87,11 @@ func TestSound(t *testing.T) {
|
|||||||
s2 := wavy.CopyInMemSound(s)
|
s2 := wavy.CopyInMemSound(s)
|
||||||
s2.SetVolume(0.25)
|
s2.SetVolume(0.25)
|
||||||
|
|
||||||
s.PlaySync() //Already finished, should not play
|
//Already finished, should not play
|
||||||
s2.PlaySync() //Should play from beginning
|
s.PlaySync()
|
||||||
|
|
||||||
|
//Should play from beginning
|
||||||
|
s2.PlaySync()
|
||||||
|
|
||||||
//Test seek and play
|
//Test seek and play
|
||||||
s2.SeekToPercent(0.2)
|
s2.SeekToPercent(0.2)
|
||||||
|
|||||||
Reference in New Issue
Block a user