From ca4db3a12b66689bcdda5675f4f1cc8c85d4efb5 Mon Sep 17 00:00:00 2001 From: bloeys Date: Sat, 25 Jun 2022 20:44:03 +0400 Subject: [PATCH] Many sounds from one data buffer+volume control --- sound_buffer.go | 6 +++--- wavy.go | 43 +++++++++++++++++++++++++++++++++++++------ wavy_test.go | 9 +++++---- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/sound_buffer.go b/sound_buffer.go index a0c743f..099c387 100755 --- a/sound_buffer.go +++ b/sound_buffer.go @@ -58,12 +58,12 @@ func (sb *SoundBuffer) Seek(offset int64, whence int) (int64, error) { return sb.Pos, nil } -//Clone returns a new SoundBuffer that uses the same `Data` but with an independent ReadSeeker. +//Copy returns a new SoundBuffer that uses the same `Data` but with an independent ReadSeeker. //This allows you to have many readers all reading from different positions of the same buffer. // //The new buffer will have its starting position set to io.SeekStart (`Pos=0`) -func (sb *SoundBuffer) Clone() SoundBuffer { - return SoundBuffer{ +func (sb *SoundBuffer) Copy() *SoundBuffer { + return &SoundBuffer{ Data: sb.Data, Pos: 0, } diff --git a/wavy.go b/wavy.go index ce38bd1..8d9d094 100644 --- a/wavy.go +++ b/wavy.go @@ -26,9 +26,9 @@ type SoundInfo struct { type Sound struct { Player oto.Player - //FileDesc 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 - FileDesc *os.File + File *os.File //Data is an io.ReadSeeker over an open file or over a buffer containing the uncompressed sound file. //Becomes nil after close @@ -110,6 +110,17 @@ func (s *Sound) RemainingTime() time.Duration { return time.Duration(lenInMS) * time.Millisecond } +//SetVolume must be between 0 and 1 (both inclusive). Other values will panic. +//The default volume is 1. +func (s *Sound) SetVolume(newVol float64) { + + if newVol < 0 || newVol > 1 { + panic("sound volume can not be less than zero or bigger than one") + } + + s.Player.SetVolume(newVol) +} + func (s *Sound) IsClosed() bool { return s.Data == nil } @@ -123,8 +134,8 @@ func (s *Sound) Close() error { } var fdErr error = nil - if s.FileDesc != nil { - fdErr = s.FileDesc.Close() + if s.File != nil { + fdErr = s.File.Close() } s.Data = nil @@ -145,7 +156,27 @@ func (s *Sound) Close() error { return fdErr } +//CopyInMemSound returns a new sound object that has identitcal info but uses the same underlying data. +//Since the sound data is not copied this function is very fast. +// +//The returned sound can be used independently of the original one (e.g. use it to play the same gunshot sound many times). +func CopyInMemSound(s *Sound) *Sound { + + if s.Info.Mode == SoundMode_Streaming { + panic("streaming sounds can not be copied. Please use NewSoundStreaming instead") + } + + d := s.Data.(*SoundBuffer).Copy() + return &Sound{ + Player: Ctx.NewPlayer(d), + File: nil, + Data: d, + Info: s.Info, + } +} + //NewSoundStreaming plays sound by streaming from a file, so no need to load the entire file into memory. +//Good for large sound files func NewSoundStreaming(fpath string) (s *Sound, err error) { //Error checking filetype @@ -165,7 +196,7 @@ func NewSoundStreaming(fpath string) (s *Sound, err error) { } s = &Sound{ - FileDesc: file, + File: file, Info: SoundInfo{ Type: soundType, Mode: SoundMode_Streaming, @@ -188,7 +219,7 @@ func NewSoundStreaming(fpath string) (s *Sound, err error) { return s, nil } -//NewSoundMem loads the entire sound file into memory and plays from that +//NewSoundMem loads the entire sound file into memory func NewSoundMem(fpath string) (s *Sound, err error) { //Error checking filetype diff --git a/wavy_test.go b/wavy_test.go index 9c4524c..400e05d 100755 --- a/wavy_test.go +++ b/wavy_test.go @@ -1,7 +1,6 @@ package wavy_test import ( - "io" "testing" "time" @@ -85,7 +84,9 @@ func TestSound(t *testing.T) { s.PlaySync() //Test repeat playing - s.Player.Reset() - s.Data.Seek(0, io.SeekStart) - s.PlaySync() + s2 := wavy.CopyInMemSound(s) + s2.SetVolume(0.25) + + s.PlaySync() //Already finished, should not play + s2.PlaySync() //Should play from beginning }