Renamed 'ljud' to 'miniaudio' to better represent what engine it is.
This commit is contained in:
157
engine/miniaudio/sound.odin
Normal file
157
engine/miniaudio/sound.odin
Normal file
@@ -0,0 +1,157 @@
|
||||
package miniaudio_wrapper
|
||||
|
||||
import "core:sys/orca"
|
||||
import "base:runtime"
|
||||
import "core:log"
|
||||
import "core:strings"
|
||||
import "core:c"
|
||||
|
||||
import ma "vendor:miniaudio"
|
||||
|
||||
Sound :: struct {
|
||||
// data_source_base: ma.data_source_base,
|
||||
|
||||
decoder: ma.decoder,
|
||||
}
|
||||
|
||||
Sound_Instance :: ma.sound
|
||||
|
||||
@(private) on_read :: proc "c" (pDataSource: ^ma.data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> ma.result {
|
||||
// Read data here. Output in the same format returned by my_data_source_get_data_format().
|
||||
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
@(private) on_seek :: proc "c" (pDataSource: ^ma.data_source, frameIndex: u64) -> ma.result {
|
||||
// Seek to a specific PCM frame here. Return MA_NOT_IMPLEMENTED if seeking is not supported.
|
||||
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
@(private) on_get_data_format :: proc "c" (pDataSource: ^ma.data_source, pFormat: ^ma.format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]ma.channel, channelMapCap: c.size_t) -> ma.result {
|
||||
// Return the format of the data here.
|
||||
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
@(private) on_get_cursor :: proc "c" (pDataSource: ^ma.data_source, pCursor: ^u64) -> ma.result {
|
||||
// Retrieve the current position of the cursor here. Return MA_NOT_IMPLEMENTED and set *pCursor to 0 if there is no notion of a cursor.
|
||||
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
@(private) on_get_length :: proc "c" (pDataSource: ^ma.data_source, pLength: ^u64) -> ma.result {
|
||||
// Retrieve the length in PCM frames here. Return MA_NOT_IMPLEMENTED and set *pLength to 0 if there is no notion of a length or if the length is unknown.
|
||||
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
@(private) on_set_looping :: proc "c" (pDataSource: ^ma.data_source, isLooping: b32) -> ma.result {
|
||||
context = runtime.default_context()
|
||||
log.infof("%v", #procedure)
|
||||
return .ERROR
|
||||
}
|
||||
|
||||
load_sound_from_data :: proc(engine: ^Engine, data: []u8, extension: string) -> (^Sound, bool) {
|
||||
assert(engine != nil)
|
||||
|
||||
sound := new(Sound)
|
||||
assert(sound != nil)
|
||||
|
||||
// Configure our decoder
|
||||
decoder_config := ma.decoder_config_init(
|
||||
outputFormat = .f32,
|
||||
outputChannels = 0,
|
||||
outputSampleRate = 0,
|
||||
)
|
||||
|
||||
// NOTE: SS - "When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type is already known. In this case you can use encodingFormat variable in the device config to specify a specific encoding format you want to decode."
|
||||
decoder_config.encodingFormat = .unknown // TODO: SS - Check 'extension'.
|
||||
|
||||
decoder_result := ma.decoder_init_memory(
|
||||
pData = raw_data(data),
|
||||
dataSize = len(data),
|
||||
pConfig = &decoder_config,
|
||||
pDecoder = &sound.decoder,
|
||||
)
|
||||
if decoder_result != .SUCCESS {
|
||||
log.errorf("Failed to initialize decoder! Result: %v.", decoder_result)
|
||||
free(sound)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return sound, true
|
||||
}
|
||||
|
||||
unload_sound :: proc(engine: ^Engine, sound: ^Sound) {
|
||||
assert(engine != nil)
|
||||
assert(sound != nil)
|
||||
// assert(sound.data_source != nil)
|
||||
|
||||
ma.data_source_uninit(sound.decoder.ds.pCurrent)
|
||||
}
|
||||
|
||||
init_sound_instance :: proc(engine: ^Engine, bus: ^Bus, sound: ^Sound, sound_instance: ^Sound_Instance) -> bool {
|
||||
result := ma.sound_init_from_data_source(
|
||||
pEngine = &engine.ma_engine,
|
||||
pDataSource = sound.decoder.ds.pCurrent,
|
||||
flags = {},
|
||||
pGroup = bus,
|
||||
pSound = sound_instance,
|
||||
)
|
||||
if result != .SUCCESS {
|
||||
log.errorf("Failed to create a sound instance! Result: %v.", result)
|
||||
return false
|
||||
}
|
||||
|
||||
ma.sound_stop(sound_instance)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
play_sound_instance :: proc(
|
||||
engine: ^Engine,
|
||||
sound_instance: ^Sound_Instance,
|
||||
spatialized: bool,
|
||||
loop: bool,
|
||||
volume: f32,
|
||||
position: [3]f32,
|
||||
min_distance, max_distance: f32,
|
||||
) -> bool {
|
||||
assert(engine != nil)
|
||||
assert(sound_instance != nil)
|
||||
|
||||
ma.sound_set_spatialization_enabled(sound_instance, b32(spatialized))
|
||||
ma.sound_set_looping(sound_instance, b32(loop))
|
||||
ma.sound_set_volume(sound_instance, volume)
|
||||
ma.sound_set_position(sound_instance, expand_values(position))
|
||||
ma.sound_set_min_distance(sound_instance, min_distance)
|
||||
ma.sound_set_max_distance(sound_instance, max_distance)
|
||||
|
||||
// TODO: SS - So many cool thingss available! Expose them.
|
||||
// 'ma.sound_set_pitch' etc.
|
||||
|
||||
seek_result := ma.sound_seek_to_pcm_frame(sound_instance, 0)
|
||||
if seek_result != .SUCCESS {
|
||||
log.warnf("Failed to play sound instance! Could not seek to start. Result: %v", seek_result)
|
||||
return false
|
||||
}
|
||||
|
||||
start_result := ma.sound_start(sound_instance)
|
||||
if start_result != .SUCCESS {
|
||||
log.warnf("Failed to play sound instance! Result: %v", start_result)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user