sound layer refactor

This commit is contained in:
jacob 2025-07-30 21:05:23 -05:00
parent 7253e8f210
commit 35564cceef
5 changed files with 130 additions and 88 deletions

View File

@ -243,7 +243,7 @@ void P_AppStartup(String args_str)
F_StartupReceipt font_sr = F_Startup(&asset_cache_sr, &ttf_sr); F_StartupReceipt font_sr = F_Startup(&asset_cache_sr, &ttf_sr);
S_StartupReceipt sprite_sr = sprite_startup(); S_StartupReceipt sprite_sr = sprite_startup();
M_StartupReceipt mixer_sr = M_Startup(); M_StartupReceipt mixer_sr = M_Startup();
SND_StartupReceipt sound_sr = sound_startup(&asset_cache_sr); SND_StartupReceipt sound_sr = SND_Startup(&asset_cache_sr);
D_StartupReceipt draw_sr = D_Startup(&font_sr); D_StartupReceipt draw_sr = D_Startup(&font_sr);
SimStartupReceipt sim_sr = sim_startup(); SimStartupReceipt sim_sr = sim_startup();

View File

@ -40,9 +40,8 @@ Struct(F_LoadJobSigStore)
P_Mutex mutex; P_Mutex mutex;
}; };
/* ========================== * ////////////////////////////////
* Global state //~ Shared state
* ========================== */
#define F_LookupTableSize (256) #define F_LookupTableSize (256)

View File

@ -295,7 +295,7 @@ M_PcmF32 M_MixAllTracks(Arena *arena, u64 frame_count)
SND_Sound *source = mix->source; SND_Sound *source = mix->source;
M_TrackDesc desc = mix->desc; M_TrackDesc desc = mix->desc;
M_EffectData *effect_data = &mix->effect_data; M_EffectData *effect_data = &mix->effect_data;
b32 source_is_stereo = source->flags & SOUND_FLAG_STEREO; b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
f32 speed = MaxF32(0, desc.speed); f32 speed = MaxF32(0, desc.speed);
//- Determine sample range //- Determine sample range

View File

@ -1,76 +1,56 @@
#define SOUND_SAMPLE_RATE 48000 SND_SharedState SND_shared_state = ZI;
struct sound_task_params { ////////////////////////////////
struct sound_task_params *next_free; //~ Startup
u32 flags; SND_StartupReceipt SND_Startup(AC_StartupReceipt *asset_cache_sr)
AC_Asset *asset;
u64 path_len;
char path_cstr[1024];
};
struct sound_task_params_store {
struct sound_task_params *head_free;
Arena *arena;
P_Mutex mutex;
};
/* ========================== *
* Global state
* ========================== */
Global struct {
struct sound_task_params_store params;
} G = ZI, DebugAlias(G, G_sound);
/* ========================== *
* Startup
* ========================== */
SND_StartupReceipt sound_startup(AC_StartupReceipt *asset_cache_sr)
{ {
__prof; __prof;
SND_SharedState *g = &SND_shared_state;
(UNUSED)asset_cache_sr; (UNUSED)asset_cache_sr;
G.params.arena = AllocArena(Gibi(64)); g->params.arena = AllocArena(Gibi(64));
return (SND_StartupReceipt) { 0 }; return (SND_StartupReceipt) { 0 };
} }
/* ========================== * ////////////////////////////////
* Load task param store //~ Job sig store
* ========================== */
internal struct sound_task_params *sound_task_params_alloc(void) SND_LoadAssetJobSig *SND_AllocJobSig(void)
{ {
struct sound_task_params *p = 0; SND_SharedState *g = &SND_shared_state;
SND_LoadAssetJobSig *p = 0;
{ {
P_Lock lock = P_LockE(&G.params.mutex); P_Lock lock = P_LockE(&g->params.mutex);
if (G.params.head_free) { if (g->params.head_free)
p = G.params.head_free; {
G.params.head_free = p->next_free; p = g->params.head_free;
} else { g->params.head_free = p->next_free;
p = PushStruct(G.params.arena, struct sound_task_params); }
else
{
p = PushStruct(g->params.arena, SND_LoadAssetJobSig);
} }
P_Unlock(&lock); P_Unlock(&lock);
} }
return p; return p;
} }
internal void sound_task_params_release(struct sound_task_params *p) void SND_ReleaseJobSig(SND_LoadAssetJobSig *p)
{ {
P_Lock lock = P_LockE(&G.params.mutex); SND_SharedState *g = &SND_shared_state;
p->next_free = G.params.head_free; P_Lock lock = P_LockE(&g->params.mutex);
G.params.head_free = p; p->next_free = g->params.head_free;
g->params.head_free = p;
P_Unlock(&lock); P_Unlock(&lock);
} }
/* ========================== * ////////////////////////////////
* Load //~ Load job
* ========================== */
internal P_JobDef(sound_load_asset_job, job) P_JobDef(SND_LoadAssetJob, job)
{ {
__prof; __prof;
struct sound_task_params *params = job.sig; SND_LoadAssetJobSig *params = job.sig;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
String path = STRING(params->path_len, (u8 *)params->path_cstr); String path = STRING(params->path_len, (u8 *)params->path_cstr);
AC_Asset *asset = params->asset; AC_Asset *asset = params->asset;
@ -87,22 +67,28 @@ internal P_JobDef(sound_load_asset_job, job)
MP3_Result decoded = ZI; MP3_Result decoded = ZI;
{ {
R_Resource sound_rs = R_OpenResource(path); R_Resource sound_rs = R_OpenResource(path);
if (R_ResourceExists(&sound_rs)) { if (R_ResourceExists(&sound_rs))
{
u64 decode_flags = 0; u64 decode_flags = 0;
if (flags & SOUND_FLAG_STEREO) { if (flags & SND_SoundFlag_Stereo)
{
decode_flags |= MP3_DecodeFlag_Stereo; decode_flags |= MP3_DecodeFlag_Stereo;
} }
decoded = MP3_Decode(scratch.arena, R_GetResourceData(&sound_rs), SOUND_SAMPLE_RATE, decode_flags); decoded = MP3_Decode(scratch.arena, R_GetResourceData(&sound_rs), SND_SampleRate, decode_flags);
if (!decoded.success) { if (!decoded.success)
{
error_msg = Lit("Failed to decode sound file"); error_msg = Lit("Failed to decode sound file");
} }
} else { }
else
{
error_msg = Lit("Resource not found"); error_msg = Lit("Resource not found");
} }
R_CloseResource(&sound_rs); R_CloseResource(&sound_rs);
} }
if (decoded.success) { if (decoded.success)
{
/* Store */ /* Store */
SND_Sound *sound = 0; SND_Sound *sound = 0;
u64 samples_count = decoded.samples_count; u64 samples_count = decoded.samples_count;
@ -123,7 +109,9 @@ internal P_JobDef(sound_load_asset_job, job)
P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns))); P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)));
AC_MarkReady(asset, sound); AC_MarkReady(asset, sound);
} else { }
else
{
P_LogErrorF("Error loading sound \"%F\": %F", FmtString(path), FmtString(error_msg)); P_LogErrorF("Error loading sound \"%F\": %F", FmtString(path), FmtString(error_msg));
/* Store */ /* Store */
@ -137,32 +125,37 @@ internal P_JobDef(sound_load_asset_job, job)
AC_MarkReady(asset, sound); AC_MarkReady(asset, sound);
} }
sound_task_params_release(params); SND_ReleaseJobSig(params);
EndScratch(scratch); EndScratch(scratch);
} }
AC_Asset *sound_load_asset(String path, u32 flags, b32 wait) ////////////////////////////////
//~ Load sound
AC_Asset *SND_LoadAsset(String path, u32 flags, b32 wait)
{ {
__prof; __prof;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
/* Generate and append sound flags to path key */ /* Generate and append sound flags to path key */
String key = StringFormat(scratch.arena, String key = StringFormat(scratch.arena,
Lit("%F%F_sound"), Lit("%F%F_sound"),
FmtString(path), FmtString(path),
FmtUint((u64)flags)); FmtUint((u64)flags));
u64 hash = AC_HashFromKey(key); u64 hash = AC_HashFromKey(key);
b32 is_first_touch; b32 is_first_touch;
AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch); AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch);
if (is_first_touch) { if (is_first_touch)
{
/* Assemble task params */ /* Assemble task params */
struct sound_task_params *params = sound_task_params_alloc(); SND_LoadAssetJobSig *params = SND_AllocJobSig();
if (path.len > (sizeof(params->path_cstr) - 1)) { if (path.len > (sizeof(params->path_cstr) - 1))
{
P_Panic(StringFormat(scratch.arena, P_Panic(StringFormat(scratch.arena,
Lit("Sound path \"%F\" too long!"), Lit("Sound path \"%F\" too long!"),
FmtString(path))); FmtString(path)));
} }
CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path); CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path);
params->path_len = path.len; params->path_len = path.len;
@ -171,8 +164,9 @@ AC_Asset *sound_load_asset(String path, u32 flags, b32 wait)
/* PushStruct task */ /* PushStruct task */
AC_MarkLoading(asset); AC_MarkLoading(asset);
P_Run(1, sound_load_asset_job, params, P_Pool_Background, P_Priority_Low, &asset->counter); P_Run(1, SND_LoadAssetJob, params, P_Pool_Background, P_Priority_Low, &asset->counter);
if (wait) { if (wait)
{
AC_WaitOnAssetReady(asset); AC_WaitOnAssetReady(asset);
} }
} }
@ -181,19 +175,18 @@ AC_Asset *sound_load_asset(String path, u32 flags, b32 wait)
return asset; return asset;
} }
SND_Sound *sound_load_async(String path, u32 flags) SND_Sound *SND_LoadSoundAsync(String path, u32 flags)
{ {
__prof; __prof;
AC_Asset *asset = sound_load_asset(path, flags, 0); AC_Asset *asset = SND_LoadAsset(path, flags, 0);
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset); SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
return sound; return sound;
} }
SND_Sound *SND_LoadSoundWait(String path, u32 flags)
SND_Sound *sound_load(String path, u32 flags)
{ {
__prof; __prof;
AC_Asset *asset = sound_load_asset(path, flags, 1); AC_Asset *asset = SND_LoadAsset(path, flags, 1);
AC_WaitOnAssetReady(asset); AC_WaitOnAssetReady(asset);
SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset); SND_Sound *sound = (SND_Sound *)AC_DataFromStore(asset);
return sound; return sound;

View File

@ -1,17 +1,67 @@
#define SOUND_FLAG_NONE 0x0 ////////////////////////////////
#define SOUND_FLAG_STEREO 0x1 //~ Sound structs
typedef struct SND_Sound SND_Sound; #define SND_SampleRate 48000
struct SND_Sound {
typedef u32 SND_SoundFlag; enum
{
SND_SoundFlag_None = 0,
SND_SoundFlag_Stereo = (1 << 0)
};
Struct(SND_Sound)
{
u32 flags; u32 flags;
u64 samples_count; u64 samples_count;
i16 *samples; i16 *samples;
}; };
typedef struct SND_StartupReceipt SND_StartupReceipt; ////////////////////////////////
struct SND_StartupReceipt { i32 _; }; //~ Sound job types
SND_StartupReceipt sound_startup(AC_StartupReceipt *asset_cache_sr);
AC_Asset *sound_load_asset(String path, u32 flags, b32 wait); Struct(SND_LoadAssetJobSig)
SND_Sound *sound_load_async(String path, u32 flags); {
SND_Sound *sound_load(String path, u32 flags); SND_LoadAssetJobSig *next_free;
u32 flags;
AC_Asset *asset;
u64 path_len;
char path_cstr[1024];
};
Struct(SND_LoadAssetJobSigStore)
{
SND_LoadAssetJobSig *head_free;
Arena *arena;
P_Mutex mutex;
};
////////////////////////////////
//~ Shared state
Struct(SND_SharedState)
{
SND_LoadAssetJobSigStore params;
};
extern SND_SharedState SND_shared_state;
////////////////////////////////
//~ Startup
Struct(SND_StartupReceipt) { i32 _; };
SND_StartupReceipt SND_Startup(AC_StartupReceipt *asset_cache_sr);
////////////////////////////////
//~ Sound load job
SND_LoadAssetJobSig *SND_AllocJobSig(void);
void SND_ReleaseJobSig(SND_LoadAssetJobSig *p);
////////////////////////////////
//~ Sound load operations
P_JobDef(SND_LoadAssetJob, job);
AC_Asset *SND_LoadAsset(String path, u32 flags, b32 wait);
SND_Sound *SND_LoadSoundAsync(String path, u32 flags);
SND_Sound *SND_LoadSoundWait(String path, u32 flags);