diff --git a/d2core/d2audio/doc.go b/d2core/d2audio/doc.go new file mode 100644 index 00000000..cf741a3b --- /dev/null +++ b/d2core/d2audio/doc.go @@ -0,0 +1,2 @@ +// Package d2audio provides AudioProvider implementations +package d2audio diff --git a/d2core/d2audio/ebiten/ebiten_audio_provider.go b/d2core/d2audio/ebiten/ebiten_audio_provider.go index 4c7afe70..214aef23 100644 --- a/d2core/d2audio/ebiten/ebiten_audio_provider.go +++ b/d2core/d2audio/ebiten/ebiten_audio_provider.go @@ -96,13 +96,17 @@ func (eap *AudioProvider) PlayBGM(song string) { } } -// LoadSoundEffect loads a sound affect so that it canb e played -func (eap *AudioProvider) LoadSound(sfx string, loop bool, bgm bool) (d2interface.SoundEffect, error) { +// LoadSound loads a sound affect so that it canb e played +func (eap *AudioProvider) LoadSound(sfx string, loop, bgm bool) (d2interface.SoundEffect, error) { volume := eap.sfxVolume if bgm { volume = eap.bgmVolume } - result := CreateSoundEffect(sfx, eap.audioContext, volume, loop) // TODO: Split + + result := CreateSoundEffect(sfx, eap.audioContext, loop) + + result.volumeScale = volume + result.SetVolume(volume) return result, nil } diff --git a/d2core/d2audio/ebiten/ebiten_sound_effect.go b/d2core/d2audio/ebiten/ebiten_sound_effect.go index c40d8085..837e02fd 100644 --- a/d2core/d2audio/ebiten/ebiten_sound_effect.go +++ b/d2core/d2audio/ebiten/ebiten_sound_effect.go @@ -16,7 +16,11 @@ type panStream struct { pan float64 // -1: left; 0: center; 1: right } -func NewPanStreamFromReader(src audio.ReadSeekCloser) *panStream { +const ( + bitsPerByte = 8 +) + +func newPanStreamFromReader(src audio.ReadSeekCloser) *panStream { return &panStream{ ReadSeekCloser: src, pan: 0, @@ -33,13 +37,13 @@ func (s *panStream) Read(p []byte) (n int, err error) { rs := math.Min(s.pan+1, 1) for i := 0; i < len(p); i += 4 { - lc := int16(float64(int16(p[i])|int16(p[i+1])<<8) * ls) - rc := int16(float64(int16(p[i+2])|int16(p[i+3])<<8) * rs) + lc := int16(float64(int16(p[i])|int16(p[i+1])<> 8) + p[i+1] = byte(lc >> bitsPerByte) p[i+2] = byte(rc) - p[i+3] = byte(rc >> 8) + p[i+3] = byte(rc >> bitsPerByte) } return @@ -53,7 +57,7 @@ type SoundEffect struct { } // CreateSoundEffect creates a new instance of ebiten's sound effect implementation. -func CreateSoundEffect(sfx string, context *audio.Context, volume float64, loop bool) *SoundEffect { +func CreateSoundEffect(sfx string, context *audio.Context, loop bool) *SoundEffect { result := &SoundEffect{} soundFile := "/data/global/sfx/" @@ -85,10 +89,10 @@ func CreateSoundEffect(sfx string, context *audio.Context, volume float64, loop if loop { s := audio.NewInfiniteLoop(d, d.Length()) - result.panStream = NewPanStreamFromReader(s) + result.panStream = newPanStreamFromReader(s) player, err = audio.NewPlayer(context, result.panStream) } else { - result.panStream = NewPanStreamFromReader(d) + result.panStream = newPanStreamFromReader(d) player, err = audio.NewPlayer(context, result.panStream) } @@ -96,22 +100,22 @@ func CreateSoundEffect(sfx string, context *audio.Context, volume float64, loop log.Fatal(err) } - result.volumeScale = volume - player.SetVolume(volume) - result.player = player return result } +// SetPan sets the audio pan, left is -1.0, center is 0.0, right is 1.0 func (v *SoundEffect) SetPan(pan float64) { v.panStream.pan = pan } +// SetVolume ets the volume func (v *SoundEffect) SetVolume(volume float64) { v.player.SetVolume(volume * v.volumeScale) } +// IsPlaying returns a bool for whether or not the sound is currently playing func (v *SoundEffect) IsPlaying() bool { return v.player.IsPlaying() } diff --git a/d2core/d2audio/sound_engine.go b/d2core/d2audio/sound_engine.go index c6d52931..da561820 100644 --- a/d2core/d2audio/sound_engine.go +++ b/d2core/d2audio/sound_engine.go @@ -71,7 +71,7 @@ func (s *Sound) Play() { s.volume = 0 s.state = envAttack s.vTarget = float64(s.entry.Volume) / volMax - s.vRate = (s.vTarget / (float64(s.entry.FadeIn) / originalFPS)) + s.vRate = s.vTarget / (float64(s.entry.FadeIn) / originalFPS) } else { s.volume = float64(s.entry.Volume) / volMax s.effect.SetVolume(s.volume) @@ -84,7 +84,7 @@ func (s *Sound) Stop() { if s.entry.FadeOut != 0 { s.state = envRelease s.vTarget = 0 - s.vRate = (s.volume / (float64(s.entry.FadeOut) / originalFPS)) + s.vRate = s.volume / (float64(s.entry.FadeOut) / originalFPS) } else { s.state = envStopped s.volume = 0 @@ -95,10 +95,10 @@ func (s *Sound) Stop() { // SoundEngine provides functions for playing sounds type SoundEngine struct { - provider d2interface.AudioProvider - timer float64 - accTime float64 - sounds map[*Sound]struct{} + provider d2interface.AudioProvider + timer float64 + accTime float64 + sounds map[*Sound]struct{} } // NewSoundEngine creates a new sound engine diff --git a/d2core/d2audio/sound_environment.go b/d2core/d2audio/sound_environment.go index dd6b9be8..081aa19e 100644 --- a/d2core/d2audio/sound_environment.go +++ b/d2core/d2audio/sound_environment.go @@ -6,6 +6,9 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" ) +const assumedFPS = 25 + +// SoundEnvironment represents the audio environment for map areas type SoundEnvironment struct { environment *d2datadict.SoundEnvironRecord engine *SoundEngine @@ -14,6 +17,7 @@ type SoundEnvironment struct { eventTimer float64 } +// NewSoundEnvironment creates a SoundEnvironment using the given SoundEngine func NewSoundEnvironment(soundEngine *SoundEngine) SoundEnvironment { r := SoundEnvironment{ // Start with env NONE @@ -24,9 +28,10 @@ func NewSoundEnvironment(soundEngine *SoundEngine) SoundEnvironment { return r } -func (s *SoundEnvironment) SetEnv(environment int) { - if s.environment.Index != environment { - newEnv := d2datadict.SoundEnvirons[environment] +// SetEnv sets the sound environment using the given record index +func (s *SoundEnvironment) SetEnv(environmentIdx int) { + if s.environment.Index != environmentIdx { + newEnv := d2datadict.SoundEnvirons[environmentIdx] if s.environment.Song != newEnv.Song { if s.bgm != nil { @@ -48,10 +53,11 @@ func (s *SoundEnvironment) SetEnv(environment int) { } } +// Advance advances the sound engine and plays sounds when necessary func (s *SoundEnvironment) Advance(elapsed float64) { s.eventTimer -= elapsed if s.eventTimer < 0 { - s.eventTimer = float64(s.environment.EventDelay) / 25 + s.eventTimer = float64(s.environment.EventDelay) / assumedFPS snd := s.engine.PlaySoundID(s.environment.DayEvent) if snd != nil {