161 lines
3.9 KiB
Odin
161 lines
3.9 KiB
Odin
package engine
|
|
|
|
import os "core:os/os2"
|
|
import "core:container/queue"
|
|
import "core:log"
|
|
|
|
import "miniaudio"
|
|
|
|
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,
|
|
loop: 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_MINIAUDIO {
|
|
backend, ok := miniaudio.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_MINIAUDIO {
|
|
miniaudio.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_MINIAUDIO {
|
|
instance_ok = miniaudio.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_MINIAUDIO {
|
|
return miniaudio.play_sound_instance(
|
|
&engine.backend,
|
|
&sound_instance.backend,
|
|
sound_instance.spatialized,
|
|
sound_instance.loop,
|
|
sound_instance.volume,
|
|
sound_instance.position,
|
|
sound_instance.min_distance,
|
|
sound_instance.max_distance,
|
|
)
|
|
}
|
|
else when AUDIO_ENGINE_FMOD {
|
|
}
|
|
else when AUDIO_ENGINE_WWISE {
|
|
|
|
}
|
|
|
|
return false
|
|
} |