From: hgn Date: Mon, 25 Oct 2021 21:40:36 +0000 (+0100) Subject: much cleaner audio handling & extra controls X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=d94e286c52dcfd5faf7cbd12690268f9d68957ef much cleaner audio handling & extra controls --- diff --git a/fishladder.c b/fishladder.c index ac1efcf..e6d2ef7 100644 --- a/fishladder.c +++ b/fishladder.c @@ -611,6 +611,8 @@ void vg_update(void) world.io[i].recv_count = 0; vg_info( "Stopping simulation!\n" ); + + sfx_system_fadeout( &audio_system_balls_rolling, 44100 ); } else { diff --git a/fishladder_resources.h b/fishladder_resources.h index dcb24c7..cd73f52 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -19,7 +19,6 @@ sfx_system audio_system_sfx = .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx, - .fadeout_length = FADEOUT_LENGTH, .name = "sfx" }; @@ -59,21 +58,21 @@ sfx_system audio_system_balls_rolling = sfx_system audio_system_balls_switching = { .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx, - .name = "Balls Switching", .fadeout_length = FADEOUT_LENGTH + .name = "Balls Switching" }; // Gameplay critical sounds eg. splitter sound rocking sfx_system audio_system_balls_important = { .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx, - .name = "Balls Gameplay", .fadeout_length = FADEOUT_LENGTH + .name = "Balls Gameplay" }; // Suplemental sounds sfx_system audio_system_balls_extra = { .vol = 1.f, .ch = 1, .vol_src = &audio_volume_sfx, - .name = "Balls Extra", .fadeout_length = FADEOUT_LENGTH + .name = "Balls Extra" }; static void resource_load_main(void) diff --git a/vg/vg_audio.h b/vg/vg_audio.h index 457ac13..2191385 100644 --- a/vg/vg_audio.h +++ b/vg/vg_audio.h @@ -6,10 +6,11 @@ #define STB_VORBIS_MAX_CHANNELS 2 #include "stb/stb_vorbis.h" -#define SFX_MAX_SYSTEMS 16 +#define SFX_MAX_SYSTEMS 32 #define SFX_FLAG_ONESHOT 0x1 #define SFX_FLAG_STEREO 0x2 #define SFX_FLAG_REPEAT 0x4 +#define SFX_FLAG_GHOST 0x8 #define FADEOUT_LENGTH 441 #define FADEOUT_DIVISOR (1.f/(float)FADEOUT_LENGTH) @@ -32,11 +33,11 @@ struct sfx_system float vol; // Info - int ch, end, cur; + int ch, end, cur, cur_lagged; u32 flags; // Effects - u32 fadeout, fadeout_length, fadeout_cursor; + u32 fadeout, fadeout_current; sfx_system *thread_clone; // Memory of this structure is copied into thread 2 @@ -348,8 +349,6 @@ static sfx_system *sfx_alloc(void) { if( sfx_sys_len >= SFX_MAX_SYSTEMS ) { - vg_error( "Warning: No free space in sound system\n" ); - return NULL; } @@ -384,14 +383,38 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput while( sfx_q_len --> 0 ) { sfx_system *src = sfx_q[sfx_q_len]; + sfx_system *clone; // This is a 'new' sound if thread_clone not set. if( !src->thread_clone || src->flags & SFX_FLAG_ONESHOT ) { src->thread_clone = sfx_alloc(); + if( !src->thread_clone ) + break; + } + else + { + // Modifying an active system spawns a small fadeout ghost system + sfx_system *ghost_system = sfx_alloc(); + + if( !ghost_system ) + break; + + ghost_system->source = src->source; + ghost_system->ch = src->ch; + ghost_system->end = src->end; + ghost_system->cur = src->cur_lagged; + ghost_system->flags = SFX_FLAG_GHOST; + ghost_system->fadeout = FADEOUT_LENGTH; + ghost_system->fadeout_current = FADEOUT_LENGTH; + ghost_system->vol_src = src->vol_src; + ghost_system->name = src->name; + ghost_system->thread_clone = src; } - // run replacement routine if one is waiting + clone = src->thread_clone; + + // run replacement routine if one is waiting (todo: what is this?) if( src->replacement ) { free( src->source ); @@ -399,21 +422,20 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput src->source = src->replacement; src->replacement = NULL; } - - src->thread_clone->source = src->source; // Localize data to thread 1's memory pool - src->thread_clone->ch = src->ch; - src->thread_clone->end = src->end; - src->thread_clone->cur = src->cur; - src->thread_clone->flags = src->flags; - src->thread_clone->fadeout = src->fadeout; - src->thread_clone->fadeout_length = src->fadeout_length; - src->thread_clone->vol_src = src->vol_src; - src->thread_clone->name = src->name; + clone->source = src->source; + clone->ch = src->ch; + clone->end = src->end; + clone->cur = src->cur; + clone->flags = src->flags; + clone->vol_src = src->vol_src; + clone->name = src->name; + clone->fadeout = src->fadeout; + clone->fadeout_current = src->fadeout_current; // loopback pointer, mainly used for persistent sound handles - src->thread_clone->thread_clone = src; + clone->thread_clone = src; } sfx_q_len = 0; @@ -441,57 +463,56 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput { sfx_system *sys = sfx_sys + i; - u32 cursor = sys->cur; - u32 bpos = 0; + u32 cursor = sys->cur, buffer_pos = 0; float avgvol = 0.f; float pcf[2] = { 0.f, 0.0f }; - if( sys->fadeout_cursor != sys->cur ) - sys->fadeout = sys->fadeout_length; - u32 frames_write = frameCount; + float fadeout_divisor = 1.0f / (float)sys->fadeout; while( frames_write ) { u32 samples_this_run = vg_min( frames_write, sys->end - cursor ); + if( sys->fadeout ) + { + // Force this system to be removed + if( sys->fadeout_current == 0 ) + { + sys->flags = SFX_FLAG_GHOST; + sys->cur = sys->end; + break; + } + + samples_this_run = vg_min( samples_this_run, sys->fadeout_current ); + } + for( u32 j = 0; j < samples_this_run; j ++ ) { audio_mixer_getsamples( pcf, sys->source, cursor, sys->ch ); - avgvol += fabs( pcf[0] * sys->vol ); - avgvol += fabs( pcf[1] * sys->vol ); - - pOut32F[ bpos*2+0 ] += pcf[0] * sys->vol; - pOut32F[ bpos*2+1 ] += pcf[1] * sys->vol; - - // Blend the fadeout cursor in to prevent popping + float vol = sys->vol; + if( sys->fadeout ) { - if( sys->fadeout_cursor < sys->end ) - { - audio_mixer_getsamples( pcf, sys->source, sys->fadeout_cursor, sys->ch ); - - float mul = (float)sys->fadeout * FADEOUT_DIVISOR; - - pOut32F[ bpos*2+0 ] += pcf[0] * sys->vol * mul; - pOut32F[ bpos*2+1 ] += pcf[1] * sys->vol * mul; - - sys->fadeout_cursor ++; - sys->fadeout --; - } - else - sys->fadeout = 0; + vol *= (float)sys->fadeout_current * fadeout_divisor; + sys->fadeout_current --; } + pOut32F[ buffer_pos*2+0 ] += pcf[0] * vol; + pOut32F[ buffer_pos*2+1 ] += pcf[1] * vol; + + avgvol += fabs( pcf[0] * vol ); + avgvol += fabs( pcf[1] * vol ); + cursor ++; - bpos ++; + buffer_pos ++; } frames_write -= samples_this_run; - if( sys->flags & SFX_FLAG_REPEAT) + if( sys->flags & SFX_FLAG_REPEAT ) { if( frames_write ) { @@ -501,8 +522,8 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput } sys->cur = cursor; - sys->fadeout_cursor = cursor; - sys->signal_average = avgvol / (float)(bpos*2); + sys->cur_lagged = cursor; + sys->signal_average = avgvol / (float)(buffer_pos*2); break; } @@ -622,6 +643,7 @@ void sfx_set_playrnd( sfx_set *source, sfx_system *sys, int min_id, int max_id ) int pick = (rand() % (max_id-min_id)) + min_id; + sys->fadeout = 0; sys->source = source->main; sys->cur = source->segments[ pick*2 + 0 ]; sys->end = source->segments[ pick*2 + 1 ]; @@ -630,6 +652,14 @@ void sfx_set_playrnd( sfx_set *source, sfx_system *sys, int min_id, int max_id ) sfx_save( sys ); } +static void sfx_system_fadeout( sfx_system *sys, u32 length_samples ) +{ + sys->fadeout_current = length_samples; + sys->fadeout = length_samples; + + sfx_save( sys ); +} + // Free set resources void sfx_set_free( sfx_set *set ) {