148 lines
4.4 KiB
Odin
148 lines
4.4 KiB
Odin
package game
|
|
|
|
import rl "vendor:raylib"
|
|
|
|
Fade_State :: enum {
|
|
None,
|
|
In,
|
|
Out,
|
|
}
|
|
|
|
// setup sound IDs so gameplay code never
|
|
// touches raw Raylib sound handles
|
|
Sound_ID :: enum {
|
|
Ball_Collision,
|
|
Score_Goal,
|
|
UI_Select,
|
|
UI_Confirm,
|
|
}
|
|
|
|
Audio_Manager :: struct {
|
|
sounds: map[Sound_ID]rl.Sound,
|
|
music: rl.Music,
|
|
music_loaded: bool,
|
|
|
|
sfx_vol: f32, // User SFX volume setting
|
|
user_music_vol: f32, // User Music volume setting
|
|
current_music_vol: f32, // Live interpolated output volume
|
|
|
|
// Runtime Fade State
|
|
fade_state: Fade_State,
|
|
fade_elapsed_sec: f32,
|
|
fade_duration_sec: f32,
|
|
}
|
|
// ------------------------------------------------------------------------------
|
|
// Lifecycle procs
|
|
// ------------------------------------------------------------------------------
|
|
audio_init :: proc(audio: ^Audio_Manager) {
|
|
rl.InitAudioDevice()
|
|
audio.sounds = make(map[Sound_ID]rl.Sound)
|
|
|
|
// Load SFX
|
|
audio.sfx_vol = 0.5
|
|
audio.sounds[.UI_Select] = rl.LoadSound("assets/audio/ui/select.ogg")
|
|
audio.sounds[.Ball_Collision] = rl.LoadSound("assets/audio/gameplay/ballhit.ogg")
|
|
|
|
// Load Music Stream
|
|
audio.user_music_vol = 0.1
|
|
audio.current_music_vol = 0.0
|
|
audio.fade_state = .None
|
|
audio.music = rl.LoadMusicStream("assets/audio/gameplay/music/track_1.wav")
|
|
audio.music_loaded = true
|
|
rl.SetMusicVolume(audio.music, audio.current_music_vol)
|
|
}
|
|
|
|
audio_update :: proc(audio: ^Audio_Manager, dt: f32) {
|
|
if !audio.music_loaded do return
|
|
|
|
// Process Fade if the audio state machine requires
|
|
if audio.fade_state != .None {
|
|
audio.fade_elapsed_sec += dt
|
|
// convert elapsed seconds over target seconds into a 0.0 -> 1.0 percentage
|
|
progress_pct := clamp(audio.fade_elapsed_sec / audio.fade_duration_sec, 0.0, 1.0)
|
|
|
|
#partial switch audio.fade_state {
|
|
case .In:
|
|
audio.current_music_vol = rl.Lerp(0.0, audio.user_music_vol, progress_pct)
|
|
// progress is 100% or more stop fading in music
|
|
if progress_pct >= 1.0 do audio.fade_state = .None
|
|
|
|
case .Out:
|
|
audio.current_music_vol = rl.Lerp(audio.user_music_vol, 0.0, progress_pct)
|
|
// progress is 100% or more stop fading out music and stop the stream
|
|
if progress_pct >= 1.0 {
|
|
audio.fade_state = .None
|
|
rl.StopMusicStream(audio.music)
|
|
}
|
|
}
|
|
} else {
|
|
// not fading, output matches the user setting directly
|
|
audio.current_music_vol = audio.user_music_vol
|
|
}
|
|
|
|
rl.SetMusicVolume(audio.music, audio.current_music_vol)
|
|
|
|
// keep audio stream buffer fed
|
|
if rl.IsMusicStreamPlaying(audio.music) {
|
|
rl.UpdateMusicStream(audio.music)
|
|
}
|
|
}
|
|
|
|
audio_manager_quit :: proc(audio: ^Audio_Manager) {
|
|
for _, sound in audio.sounds {
|
|
rl.UnloadSound(sound)
|
|
}
|
|
delete(audio.sounds)
|
|
rl.UnloadMusicStream(audio.music)
|
|
rl.CloseAudioDevice()
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Utilities
|
|
// ------------------------------------------------------------------------------
|
|
audio_play_music :: proc(audio: ^Audio_Manager) {
|
|
if audio.music_loaded {
|
|
// Only trigger start if it isn't playing already
|
|
if !rl.IsMusicStreamPlaying(audio.music) {
|
|
rl.PlayMusicStream(audio.music)
|
|
}
|
|
}
|
|
}
|
|
|
|
audio_stop_music :: proc(audio: ^Audio_Manager) {
|
|
if audio.music_loaded && rl.IsMusicStreamPlaying(audio.music) {
|
|
rl.StopMusicStream(audio.music)
|
|
}
|
|
}
|
|
|
|
audio_play_sfx :: proc(audio: ^Audio_Manager, id: Sound_ID) {
|
|
if sound, ok := audio.sounds[id]; ok {
|
|
rl.SetSoundVolume(sound, audio.sfx_vol)
|
|
rl.PlaySound(sound)
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Audio Fading
|
|
// ------------------------------------------------------------------------------
|
|
audio_fade_in :: proc(audio: ^Audio_Manager, duration: f32 = 1.0) {
|
|
if !audio.music_loaded do return
|
|
|
|
if !rl.IsMusicStreamPlaying(audio.music) {
|
|
rl.PlayMusicStream(audio.music)
|
|
}
|
|
|
|
audio.fade_state = .In
|
|
audio.fade_duration_sec = max(0.001, duration)
|
|
audio.fade_elapsed_sec = 0.0
|
|
audio.current_music_vol = 0.0
|
|
rl.SetMusicVolume(audio.music, 0.0)
|
|
}
|
|
|
|
audio_fade_out :: proc(audio: ^Audio_Manager, duration: f32 = 1.0) {
|
|
if !audio.music_loaded || !rl.IsMusicStreamPlaying(audio.music) do return
|
|
|
|
audio.fade_state = .Out
|
|
audio.fade_duration_sec = max(0.001, duration)
|
|
audio.fade_elapsed_sec = 0.0
|
|
} |