1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-18 10:26:02 -05:00
OpenDiablo2/d2core/d2audio/ebiten/ebiten_audio_provider.go
2021-01-10 02:44:42 -05:00

183 lines
4.0 KiB
Go

// Package ebiten contains ebiten's implementation of the audio interface
package ebiten
import (
"io"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/hajimehoshi/ebiten/v2/audio"
"github.com/hajimehoshi/ebiten/v2/audio/wav"
)
const sampleRate = 44100
const logPrefix = "Ebiten Audio Provider"
var _ d2interface.AudioProvider = &AudioProvider{} // Static check to confirm struct conforms to interface
// CreateAudio creates an instance of ebiten's audio provider
func CreateAudio(l d2util.LogLevel, am *d2asset.AssetManager) *AudioProvider {
result := &AudioProvider{
asset: am,
}
result.Logger = d2util.NewLogger()
result.Logger.SetLevel(l)
result.Logger.SetPrefix(logPrefix)
result.audioContext = audio.NewContext(sampleRate)
return result
}
// AudioProvider represents a provider capable of playing audio
type AudioProvider struct {
asset *d2asset.AssetManager
audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player
bgmStream *wav.Stream
lastBgm string
sfxVolume float64
bgmVolume float64
*d2util.Logger
}
// PlayBGM loads an audio stream and plays it in the background
func (eap *AudioProvider) PlayBGM(song string) {
if eap.lastBgm == song {
return
}
eap.lastBgm = song
if song == "" && eap.bgmAudio != nil && eap.bgmAudio.IsPlaying() {
eap.bgmAudio.Pause()
return
}
if eap.bgmAudio != nil {
err := eap.bgmAudio.Close()
if err != nil {
eap.Fatal(err.Error())
}
}
audioStream, err := eap.asset.LoadFileStream(song)
if err != nil {
panic(err)
}
if _, err = audioStream.Seek(0, io.SeekStart); err != nil {
eap.Fatal(err.Error())
}
eap.bgmStream, err = wav.Decode(eap.audioContext, audioStream)
if err != nil {
eap.Fatal(err.Error())
}
s := audio.NewInfiniteLoop(eap.bgmStream, eap.bgmStream.Length())
eap.bgmAudio, err = audio.NewPlayer(eap.audioContext, s)
if err != nil {
eap.Fatal(err.Error())
}
eap.bgmAudio.SetVolume(eap.bgmVolume)
// Play the infinite-length stream. This never ends.
err = eap.bgmAudio.Rewind()
if err != nil {
panic(err)
}
eap.bgmAudio.Play()
}
// 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 := eap.createSoundEffect(sfx, eap.audioContext, loop)
result.volumeScale = volume
result.SetVolume(volume)
return result, nil
}
// SetVolumes sets the volumes of the audio provider
func (eap *AudioProvider) SetVolumes(bgmVolume, sfxVolume float64) {
eap.sfxVolume = sfxVolume
eap.bgmVolume = bgmVolume
}
// createSoundEffect creates a new instance of ebiten's sound effect implementation.
func (eap *AudioProvider) createSoundEffect(sfx string, context *audio.Context,
loop bool) *SoundEffect {
result := &SoundEffect{}
soundFile := "data/global/sfx/"
if _, exists := eap.asset.Records.Sound.Details[sfx]; exists {
soundEntry := eap.asset.Records.Sound.Details[sfx]
soundFile += soundEntry.FileName
} else {
soundFile += sfx
}
if fileExists, _ := eap.asset.FileExists(soundFile); !fileExists {
soundFile = "data/global/music/" + sfx
}
audioData, err := eap.asset.LoadFileStream(soundFile)
if err != nil {
audioData, err = eap.asset.LoadFileStream("data/global/music/" + sfx)
}
if err != nil {
panic(err)
}
d, err := wav.Decode(context, audioData)
if err != nil {
eap.Fatal(err.Error())
}
if d == nil {
eap.Fatal("Decoded data is nil")
}
var player *audio.Player
if loop {
s := audio.NewInfiniteLoop(d, d.Length())
result.panStream = newPanStreamFromReader(s)
player, err = audio.NewPlayer(context, result.panStream)
} else {
result.panStream = newPanStreamFromReader(d)
player, err = audio.NewPlayer(context, result.panStream)
}
if err != nil {
eap.Fatal(err.Error())
}
result.player = player
return result
}