Files
audio/engine/sound.odin
2026-02-08 03:23:18 +01:00

161 lines
4.0 KiB
Odin

package engine
import os "core:os/os2"
import "core:container/queue"
import "core:log"
import "ljud"
Sound :: struct {
path: string, // Where I was loaded from.
data: []u8,
backend: ^Sound_Backend, // Backend-representation.
}
Sound_Instance :: struct {
parent: ^Sound, // What I'm an instance of.
backend: Sound_Instance_Backend, // Backend-representation.
spatialized: bool,
volume: f32, // 0..1
position: [3]f32,
min_distance, max_distance: f32,
// ..
}
Sound_Instance_ID :: distinct u32
load_sound_from_path :: proc(engine: ^Engine, path: string) -> (Sound, bool) {
assert(engine != nil)
if len(path) == 0 {
return {}, false
}
base, ext := os.split_filename(path)
log.info("Loading sound '%v' with extension '%v'.", base, ext)
// TODO: SS - Check extension.
data, err := os.read_entire_file(path, context.allocator)
if err != nil {
log.errorf("Failed to load sound! Could not read entire file. Error: %v", err)
return {}, false
}
if len(data) == 0 {
log.errorf("Failed to load sound! No data.")
return {}, false
}
when AUDIO_ENGINE_LJUD {
backend, ok := ljud.load_sound_from_data(&engine.backend, data, ext)
if !ok {
return {}, false
}
assert(backend != nil)
log.info("Loaded sound, returning")
return Sound {
path = path,
data = data,
backend = backend,
}, true
}
else when AUDIO_ENGINE_FMOD {
}
else when AUDIO_ENGINE_WWISE {
}
log.info("No engine defined")
return {}, false
}
unload_sound :: proc(engine: ^Engine, sound: ^Sound) {
assert(engine != nil)
assert(sound != nil)
assert(sound.data != nil)
when AUDIO_ENGINE_LJUD {
ljud.unload_sound(&engine.backend, sound.backend)
}
else when AUDIO_ENGINE_FMOD {
}
else when AUDIO_ENGINE_WWISE {
}
delete(sound.data)
sound.data = nil
free(sound.backend)
sound.backend = nil
}
create_sound_instance :: proc(engine: ^Engine, sound: ^Sound, bus: ^Bus) -> (^Sound_Instance, bool) {
assert(engine != nil)
assert(sound != nil)
// TODO: SS - Get an available instance from a pre-allocated buffer.
sound_instance_id, pop_ok := queue.pop_front_safe(&engine.sound_instance_ids)
if !pop_ok {
log.warnf("No free sound-instance available.")
return {}, false
}
sound_instance := &engine.sound_instances[sound_instance_id]
assert(sound_instance != nil)
sound_instance.parent = sound
sound_instance.backend = {}
instance_ok: bool
when AUDIO_ENGINE_LJUD {
instance_ok = ljud.init_sound_instance(&engine.backend, bus != nil ? bus.backend : nil, sound.backend, &sound_instance.backend)
}
else when AUDIO_ENGINE_FMOD {
}
else when AUDIO_ENGINE_WWISE {
}
if !instance_ok {
log.errorf("Failed to create a Sound-Instance for sound '%v'.", sound.path)
return nil, false
}
return sound_instance, true
}
play_sound_instance :: proc(engine: ^Engine, sound_instance: ^Sound_Instance) -> bool {
assert(engine != nil)
assert(sound_instance != nil)
when AUDIO_ENGINE_LJUD {
spec := ljud.Play_Sound_Instance_Spec {
spatialized = sound_instance.spatialized,
volume = sound_instance.volume,
position = sound_instance.position,
distance = {
min = sound_instance.min_distance,
max = sound_instance.max_distance,
},
}
return ljud.play_sound_instance(&engine.backend, &sound_instance.backend, spec)
}
else when AUDIO_ENGINE_FMOD {
}
else when AUDIO_ENGINE_WWISE {
}
return false
}