222 lines
6.3 KiB
C
222 lines
6.3 KiB
C
#include "sound.h"
|
|
#include "arena.h"
|
|
#include "log.h"
|
|
#include "sys.h"
|
|
#include "scratch.h"
|
|
#include "resource.h"
|
|
#include "asset_cache.h"
|
|
#include "mp3.h"
|
|
|
|
struct sound_task_params {
|
|
struct sound_task_params *next_free;
|
|
|
|
u32 flags;
|
|
struct asset *asset;
|
|
u64 path_len;
|
|
char path_cstr[1024];
|
|
};
|
|
|
|
struct sound_task_params_store {
|
|
struct sound_task_params *head_free;
|
|
struct arena arena;
|
|
struct sys_mutex mutex;
|
|
};
|
|
|
|
/* ========================== *
|
|
* Global state
|
|
* ========================== */
|
|
|
|
GLOBAL struct {
|
|
struct sound_task_params_store params;
|
|
} L = { 0 }, DEBUG_LVAR(L_sound);
|
|
|
|
/* ========================== *
|
|
* Startup
|
|
* ========================== */
|
|
|
|
void sound_startup(void)
|
|
{
|
|
L.params.arena = arena_alloc(GIGABYTE(64));
|
|
L.params.mutex = sys_mutex_alloc();
|
|
}
|
|
|
|
/* ========================== *
|
|
* Load task param store
|
|
* ========================== */
|
|
|
|
INTERNAL struct sound_task_params *sound_task_params_alloc(void)
|
|
{
|
|
struct sound_task_params *p = NULL;
|
|
{
|
|
sys_mutex_lock(&L.params.mutex);
|
|
{
|
|
if (L.params.head_free) {
|
|
p = L.params.head_free;
|
|
L.params.head_free = p->next_free;
|
|
} else {
|
|
p = arena_push_zero(&L.params.arena, struct sound_task_params);
|
|
}
|
|
}
|
|
sys_mutex_unlock(&L.params.mutex);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
INTERNAL void sound_task_params_release(struct sound_task_params *p)
|
|
{
|
|
sys_mutex_lock(&L.params.mutex);
|
|
{
|
|
p->next_free = L.params.head_free;
|
|
L.params.head_free = p;
|
|
}
|
|
sys_mutex_unlock(&L.params.mutex);
|
|
}
|
|
|
|
/* ========================== *
|
|
* Load
|
|
* ========================== */
|
|
|
|
INTERNAL void sound_load_asset_task(void *vparams)
|
|
{
|
|
__prof;
|
|
struct sound_task_params *params = (struct sound_task_params *)vparams;
|
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
struct string path = string_from_cstr_len(params->path_cstr, params->path_len);
|
|
struct asset *asset = params->asset;
|
|
u32 flags = params->flags;
|
|
|
|
logf_info("Loading sound \"%F\"", FMT_STR(path));
|
|
sys_timestamp_t start_ts = sys_timestamp();
|
|
|
|
b32 success = true;
|
|
struct string error_msg = STR("Unknown error");
|
|
|
|
ASSERT(string_ends_with(path, STR(".mp3")));
|
|
if (resource_exists(path)) {
|
|
u64 decode_flags = 0;
|
|
if (flags & SOUND_FLAG_STEREO) {
|
|
decode_flags |= MP3_DECODE_FLAG_STEREO;
|
|
}
|
|
|
|
/* Decode */
|
|
struct resource sound_rs = resource_open(path);
|
|
struct mp3_decode_result decoded = mp3_decode(scratch.arena, sound_rs.bytes, decode_flags);
|
|
resource_close(sound_rs);
|
|
|
|
if (!decoded.success) {
|
|
success = false;
|
|
error_msg = STR("Failed to decode sound file");
|
|
goto abort;
|
|
}
|
|
|
|
/* Store */
|
|
struct sound *sound = NULL;
|
|
i16 *samples = NULL;
|
|
{
|
|
struct asset_cache_store store = asset_cache_store_open();
|
|
sound = arena_push(store.arena, struct sound);
|
|
samples = arena_push_array(store.arena, i16, decoded.pcm.count);
|
|
asset_cache_store_close(&store);
|
|
}
|
|
|
|
/* Initialize */
|
|
*sound = (struct sound) {
|
|
.flags = flags,
|
|
.pcm.count = decoded.pcm.count,
|
|
.pcm.samples = samples
|
|
};
|
|
MEMCPY(sound->pcm.samples, decoded.pcm.samples, decoded.pcm.count * sizeof(*decoded.pcm.samples));
|
|
|
|
logf_info("Finished loading sound \"%F\" in %F seconds",
|
|
FMT_STR(path),
|
|
FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts)));
|
|
|
|
asset_cache_mark_ready(asset, sound);
|
|
} else {
|
|
success = false;
|
|
error_msg = STR("Resource not found");
|
|
goto abort;
|
|
}
|
|
|
|
abort:
|
|
if (!success) {
|
|
logf_error("Error loading sound \"%F\": %F", FMT_STR(path), FMT_STR(error_msg));
|
|
|
|
/* Store */
|
|
struct sound *sound = NULL;
|
|
{
|
|
struct asset_cache_store store = asset_cache_store_open();
|
|
sound = arena_push(store.arena, struct sound);
|
|
asset_cache_store_close(&store);
|
|
}
|
|
*sound = (struct sound) { 0 };
|
|
|
|
asset_cache_mark_ready(asset, sound);
|
|
}
|
|
|
|
sound_task_params_release(params);
|
|
|
|
/* Decommit decoded sound data */
|
|
scratch_end_and_decommit(scratch);
|
|
}
|
|
|
|
struct asset *sound_load_asset(struct string path, u32 flags, b32 help)
|
|
{
|
|
__prof;
|
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
|
|
/* Generate and append sound flags to path key */
|
|
struct string key = string_format(scratch.arena,
|
|
STR("%F%F_sound"),
|
|
FMT_STR(path),
|
|
FMT_UINT((u64)flags));
|
|
u64 hash = asset_cache_hash(key);
|
|
b32 is_first_touch;
|
|
struct asset *asset = asset_cache_touch(key, hash, &is_first_touch);
|
|
|
|
if (is_first_touch) {
|
|
/* Assemble task params */
|
|
struct sound_task_params *params = sound_task_params_alloc();
|
|
if (path.len > (sizeof(params->path_cstr) - 1)) {
|
|
sys_panic(string_format(scratch.arena,
|
|
STR("Sound path \"%F\" too long!"),
|
|
FMT_STR(path)));
|
|
}
|
|
string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr));
|
|
params->path_len = path.len;
|
|
params->asset = asset;
|
|
params->flags = flags;
|
|
|
|
/* Push task */
|
|
asset_cache_mark_loading(asset);
|
|
struct work_handle wh = { 0 };
|
|
if (help) {
|
|
wh = work_push_task_and_help(&sound_load_asset_task, params, WORK_PRIORITY_NORMAL);
|
|
} else {
|
|
wh = work_push_task(&sound_load_asset_task, params, WORK_PRIORITY_NORMAL);
|
|
}
|
|
asset_cache_set_work(asset, &wh);
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
return asset;
|
|
}
|
|
|
|
struct sound *sound_load_async(struct string path, u32 flags)
|
|
{
|
|
__prof;
|
|
struct asset *asset = sound_load_asset(path, flags, false);
|
|
struct sound *sound = (struct sound *)asset_cache_get_store_data(asset);
|
|
return sound;
|
|
}
|
|
|
|
|
|
struct sound *sound_load(struct string path, u32 flags)
|
|
{
|
|
__prof;
|
|
struct asset *asset = sound_load_asset(path, flags, true);
|
|
asset_cache_wait(asset);
|
|
struct sound *sound = (struct sound *)asset_cache_get_store_data(asset);
|
|
return sound;
|
|
}
|