From: hgn Date: Sun, 24 Oct 2021 20:39:14 +0000 (+0100) Subject: bring audio code inline with current standards X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=e0e759c11d13aa83b2621268fb3f41b2dfc5033d bring audio code inline with current standards --- diff --git a/fishladder_resources.h b/fishladder_resources.h index a029421..841cf93 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -1,3 +1,6 @@ +// TEXTURES +// =========================================================================================================== + vg_tex2d tex_tile_data = { .path = "textures/tileset.png" }; vg_tex2d tex_tile_detail = { .path = "textures/tile_overlays.png" }; vg_tex2d tex_wood = { .path = "textures/wood.png" }; @@ -5,19 +8,22 @@ vg_tex2d tex_ball = { .path = "textures/ball.png", .flags = VG_TEXTURE_CLAMP vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_ball }; -sfx_system_t audio_system_sfx = +// AUDIO +// =========================================================================================================== + +sfx_vol_control audio_volume_sfx = { .val = 1.0f, .name = "Sound effects" }; +sfx_vol_control audio_volume_music = { .val = 1.0f, .name = "Music" }; + +sfx_system audio_system_sfx = { .vol = 1.f, - .spd = 1.f, .ch = 1, - .cur = 0, - .vol_src = &g_vol_sfx, - .flags = 0x00, - .fadeout = FADEOUT_LENGTH, + .vol_src = &audio_volume_sfx, + .fadeout_length = FADEOUT_LENGTH, .name = "sfx" }; -sfx_set_t audio_tile_mod = +sfx_set audio_tile_mod = { .sources = "\ sound/mod_01.ogg\0\ diff --git a/vg/vg_audio.h b/vg/vg_audio.h index 6d79771..a21a5d5 100644 --- a/vg/vg_audio.h +++ b/vg/vg_audio.h @@ -12,73 +12,64 @@ #define FADEOUT_LENGTH 441 #define FADEOUT_DIVISOR (1.f/(float)FADEOUT_LENGTH) -typedef struct sfx_vol sfx_vol_t; -typedef struct sfx_system sfx_system_t; +typedef struct sfx_vol_control sfx_vol_control; +typedef struct sfx_system sfx_system; -struct sfx_vol +struct sfx_vol_control { float val; - float cmp; + const char *name; }; struct sfx_system { // Source buffer start - float *source; - float *replacement; + float *source, *replacement; // Modifiers - sfx_vol_t *vol_src; + sfx_vol_control *vol_src; float vol; - float spd; - // Info - int ch; // channels - u32 end; // buffer end - u32 cur; // cursor position - u32 flags; + int ch, end, cur, flags; // Effects - u32 snh; - u32 fadeout; + u32 fadeout, fadeout_length, fadeout_cursor; - // The 'Opposite' pointer - sfx_system_t *optr; + sfx_system *thread_clone; // Memory of this structure is copied into thread 2 // Diagnostic - float cvol; // Current signal volume + float signal_average; // Current signal volume const char *name; }; -// 0 -int sfx_save( sfx_system_t *sys ); // Mark change to be uploaded to queue system -void sfx_sys_init(void); // Miniaudio.h init -void sfx_sys_free(void); // Shutdown audio device -sfx_system_t *sfx_alloc(void); // Create and return slot for a sound - -// 1 -void sfx_localize(void); // Copy in data from all queued -void sfx_redist(void); // Send out updates to sources -void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frameCount ); // miniaudio.h interface +// Set of up to 8 sound effects packed into one +typedef struct sfx_set sfx_set; +struct sfx_set +{ + float *main; + char *sources; + + u32 segments[16]; //from->to,from->to ... + u32 numsegments; + u32 ch; + u32 flags; +}; ma_device g_aud_device; ma_device_config g_aud_dconfig; -// Thread 2 - background loader ( to be moved ) -// ====================================================== - // Thread 1 - audio engine ( spawned from miniaudio.h ) // ====================================================== -sfx_system_t sfx_sys[SFX_MAX_SYSTEMS]; -int sfx_sys_len = 0; +sfx_system sfx_sys[SFX_MAX_SYSTEMS]; +int sfx_sys_len = 0; // Thread 0 - Critical transfer section // ====================================================== -MUTEX_TYPE sfx_mux_t01; // Resources share: 0 & 1 +MUTEX_TYPE sfx_mux_t01; // Resources share: 0 & 1 -sfx_system_t *sfx_q[SFX_MAX_SYSTEMS]; // Stuff changed -int sfx_q_len = 0; // How much +sfx_system *sfx_q[SFX_MAX_SYSTEMS]; // Stuff changed +int sfx_q_len = 0; // How much // x / 2 // ====================================================== @@ -86,14 +77,8 @@ int sfx_q_len = 0; // How much // g_vol_master is never directly acessed by users float g_master_volume = 1.f; -sfx_vol_t g_vol_music; -sfx_vol_t g_vol_sfx; - -#define SFX_NUM_VOLUMES 2 -sfx_vol_t *g_volumes[] = { &g_vol_music, &g_vol_sfx }; - // Decompress entire vorbis stream into buffer -float *sfx_vorbis_stream( const unsigned char *data, int len, int channels, uint32_t *samples ) +static float *sfx_vorbis_stream( const unsigned char *data, int len, int channels, u32 *samples ) { int err; stb_vorbis *pv = stb_vorbis_open_memory( data, len, &err, NULL ); @@ -126,7 +111,7 @@ float *sfx_vorbis_stream( const unsigned char *data, int len, int channels, uint return buffer; } -float *sfx_vorbis( const char *strFileName, int channels, u32 *samples ) +static float *sfx_vorbis( const char *strFileName, int channels, u32 *samples ) { i64 len; void *filedata = vg_asset_read_s( strFileName, &len ); @@ -188,13 +173,15 @@ int sfx_vorbis_a( const char *path, int channels, void(*OnComplete)(sfx_bgload_t // Asynchronous load-to-system callback struct sfx_vorbis_a_to_inf { - sfx_system_t *sys; - u32 flags; + sfx_system *sys; + u32 flags; }; #define SFX_A_FLAG_AUTOSTART 0x1 #define SFX_A_FLAG_AUTOFREE 0x2 +static int sfx_save( sfx_system *sys ); + // Asynchronous load-to-system callback void sfx_vorbis_a_to_c( sfx_bgload_t *loadinf ) { @@ -202,20 +189,14 @@ void sfx_vorbis_a_to_c( sfx_bgload_t *loadinf ) // Mark buffer for deallocation if autofree is set if( inf->flags & SFX_A_FLAG_AUTOFREE ) - { inf->sys->replacement = loadinf->buffer; - } else - { inf->sys->source = loadinf->buffer; - } inf->sys->end = loadinf->samples; if( inf->flags & SFX_A_FLAG_AUTOSTART ) - { sfx_save( inf->sys ); - } free( loadinf->path ); free( loadinf ); @@ -223,7 +204,7 @@ void sfx_vorbis_a_to_c( sfx_bgload_t *loadinf ) } // Asynchronous vorbis load into audio system -void sfx_vorbis_a_to( sfx_system_t *sys, const char *strFileName, int channels, uint32_t flags ) +void sfx_vorbis_a_to( sfx_system *sys, const char *strFileName, int channels, u32 flags ) { struct sfx_vorbis_a_to_inf *inf = malloc( sizeof( struct sfx_vorbis_a_to_inf ) ); inf->flags = flags; @@ -232,16 +213,14 @@ void sfx_vorbis_a_to( sfx_system_t *sys, const char *strFileName, int channels, sys->ch = channels; if( !sfx_vorbis_a( strFileName, channels, sfx_vorbis_a_to_c, inf ) ) - { free( inf ); - } } // 0 // ====================================================== // Mark change to be uploaded to queue system -int sfx_save( sfx_system_t *sys ) +static int sfx_save( sfx_system *sys ) { MUTEX_LOCK( sfx_mux_t01 ); @@ -261,20 +240,18 @@ int sfx_save( sfx_system_t *sys ) return 1; } -// Edit a volume float, has to be function round-tripped -// because of mutex -void sfx_vol_fset( sfx_vol_t *src, float to ) +// Edit a volume float, has to be function wrapped because of mutex +static void sfx_vol_fset( sfx_vol_control *src, float to ) { MUTEX_LOCK( sfx_mux_t01 ); - + src->val = to; - src->cmp = g_master_volume * to; - + MUTEX_UNLOCK( sfx_mux_t01 ); } // thread-safe get volume value -float sfx_vol_fget( sfx_vol_t *src ) +static float sfx_vol_fget( sfx_vol_control *src ) { float val; @@ -288,22 +265,17 @@ float sfx_vol_fget( sfx_vol_t *src ) } // thread-safe set master volume -void sfx_set_master( float to ) +static void sfx_set_master( float to ) { MUTEX_LOCK( sfx_mux_t01 ); g_master_volume = to; - for( int i = 0; i < SFX_NUM_VOLUMES; i ++ ) - { - g_volumes[ i ]->cmp = g_volumes[ i ]->val * g_master_volume; - } - MUTEX_UNLOCK( sfx_mux_t01 ); } // thread-safe get master volume -float sfx_get_master(void) +static float sfx_get_master(void) { float val; @@ -316,15 +288,11 @@ float sfx_get_master(void) return val; } +void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frameCount ); + // Miniaudio.h init -void vg_audio_init(void) +static void vg_audio_init(void) { - // Setup volume values - // Todo: load these from config - g_vol_sfx.val = 1.f; - g_vol_music.val = 1.f; - sfx_set_master( 1.f ); - g_aud_dconfig = ma_device_config_init( ma_device_type_playback ); g_aud_dconfig.playback.format = ma_format_f32; g_aud_dconfig.playback.channels = 2; @@ -350,17 +318,17 @@ void vg_audio_init(void) } #ifndef VYGER_RELEASE -uint32_t num_sfx_sets = 0; +u32 num_sfx_sets = 0; #endif // Shutdown audio device -void vg_audio_free(void) +static void vg_audio_free(void) { ma_device_uninit( &g_aud_device ); } // (debug) make sure we are shutting down safely -void sfx_sys_chkerr(void) +static void sfx_sys_chkerr(void) { #ifndef VYGER_RELEASE if( num_sfx_sets ) @@ -374,7 +342,7 @@ void sfx_sys_chkerr(void) // ====================================================== // Create and return slot for a sound -sfx_system_t *sfx_alloc(void) +static sfx_system *sfx_alloc(void) { if( sfx_sys_len >= SFX_MAX_SYSTEMS ) { @@ -390,142 +358,95 @@ sfx_system_t *sfx_alloc(void) return sfx_sys + (sfx_sys_len++); } -// Copy in data from all queued -void sfx_localize(void) +// Fetch samples into pcf +static void audio_mixer_getsamples( float *pcf, float *source, u32 cur, u32 ch ) { + if( ch == 2 ) + { + pcf[0] = source[ cur*2+0 ]; + pcf[1] = source[ cur*2+1 ]; + } + else + { + pcf[0] = source[ cur ]; + pcf[1] = source[ cur ]; + } +} + +// miniaudio.h interface +void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frameCount ) +{ + // Process incoming sound queue MUTEX_LOCK( sfx_mux_t01 ); while( sfx_q_len --> 0 ) { - sfx_system_t *src = sfx_q[sfx_q_len]; + sfx_system *src = sfx_q[sfx_q_len]; - // This is a 'new' sound if optr not set. - if( !src->optr || src->flags & SFX_FLAG_ONESHOT ) + // This is a 'new' sound if thread_clone not set. + if( !src->thread_clone || src->flags & SFX_FLAG_ONESHOT ) { - src->optr = sfx_alloc(); + src->thread_clone = sfx_alloc(); } // run replacement routine if one is waiting if( src->replacement ) { - if( src->source ) - { - printf( "Deallocating previous source buffer\n" ); - } - free( src->source ); src->source = src->replacement; src->replacement = NULL; } - src->optr->source = src->source; + src->thread_clone->source = src->source; // Localize data to thread 1's memory pool - // memcpy( src->optr, src, sizeof( sfx_system_t ) ); - - src->optr->spd = src->spd; - src->optr->ch = src->ch; - src->optr->end = src->end; - src->optr->cur = src->cur; - src->optr->flags = src->flags; - // src->optr->sng = src->snh; - src->optr->fadeout = src->fadeout; - // src->optr->optr = src->optr; - // src->optr->cvol = src->cvol; - src->optr->vol_src = src->vol_src; - src->optr->name = src->name; - - // loopback pointer on system system - src->optr->optr = src; + 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; + + // loopback pointer, mainly used for persistent sound handles + src->thread_clone->thread_clone = src; } + sfx_q_len = 0; // Pull in volume sliders for( int i = 0; i < sfx_sys_len; i ++ ) { - sfx_system_t *sys = sfx_sys + i; - sys->vol = sys->optr->vol; - if( sys->vol_src ) { sys->vol *= sys->vol_src->cmp; }; - } - - MUTEX_UNLOCK( sfx_mux_t01 ); -} - -// Send out updates to sources -void sfx_redist(void) -{ - MUTEX_LOCK( sfx_mux_t01 ); - - unsigned int idx = 0, wr = 0; - while( idx != sfx_sys_len ) - { - sfx_system_t *src = sfx_sys + idx; - - // Keep only if cursor is before end - if( src->cur < src->end ) - { - if( !(src->flags & SFX_FLAG_ONESHOT) ) - { - // Correct source pointer - src->optr->optr = sfx_sys + wr; - } - - sfx_sys[ wr ++ ] = sfx_sys[ idx ]; - } - else - { - if( !(src->flags & SFX_FLAG_ONESHOT) ) - { - // Clear link on source - src->optr->optr = NULL; - } - } + sfx_system *sys = sfx_sys + i; + sys->vol = sys->thread_clone->vol * g_master_volume; - idx ++ ; + if( sys->vol_src ) + sys->vol *= sys->vol_src->val; } - sfx_sys_len = wr; MUTEX_UNLOCK( sfx_mux_t01 ); -} - -// Fetch samples into pcf -void audio_mixer_getsamples( float *pcf, float *source, uint32_t cur, uint32_t ch ) -{ - if( ch == 2 ) - { - pcf[0] = source[ cur*2+0 ]; - pcf[1] = source[ cur*2+1 ]; - } - else - { - pcf[0] = source[ cur ]; - pcf[1] = source[ cur ]; - } -} - -// miniaudio.h interface -void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frameCount ) -{ - sfx_localize(); - + // Clear buffer ( is necessary ? ) float *pOut32F = (float *)pOutBuf; for( int i = 0; i < frameCount * 2; i ++ ){ pOut32F[i] = 0.f; } - + // Do something with local.. for( int i = 0; i < sfx_sys_len; i ++ ) { - sfx_system_t *sys = sfx_sys + i; + sfx_system *sys = sfx_sys + i; - uint32_t cursor = sys->cur; - uint32_t bpos = 0; + u32 cursor = sys->cur; + u32 bpos = 0; float avgvol = 0.f; + float pcf[2] = { 0.f, 0.0f }; - float pcf[2] = { 0.f }; + if( sys->fadeout_cursor != sys->cur ) + sys->fadeout = sys->fadeout_length; while( cursor < vg_min( sys->cur + frameCount, sys->end ) ) { @@ -538,61 +459,69 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput pOut32F[ bpos*2+1 ] += pcf[1] * sys->vol; // Blend the fadeout cursor in to prevent popping - // This lasts 441 samples if( sys->fadeout ) { - if( sys->snh < sys->end ) + if( sys->fadeout_cursor < sys->end ) { - audio_mixer_getsamples( pcf, sys->source, sys->snh, sys->ch ); + 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->snh ++; + sys->fadeout_cursor ++; sys->fadeout --; } else - { sys->fadeout = 0; - } } - + cursor ++; bpos ++; } - if( !sys->fadeout ) + sys->signal_average = avgvol / (float)(bpos*2); + sys->cur += frameCount; + sys->fadeout_cursor = sys->cur; + } + + // Redistribute sound systems + MUTEX_LOCK( sfx_mux_t01 ); + + unsigned int idx = 0, wr = 0; + while( idx != sfx_sys_len ) + { + sfx_system *src = sfx_sys + idx; + + // Keep only if cursor is before end + if( src->cur < src->end ) + { + // Correct source pointer on persisitent originals since we shifted ID's + if( !(src->flags & SFX_FLAG_ONESHOT) ) + src->thread_clone->thread_clone = sfx_sys + wr; + + sfx_sys[ wr ++ ] = sfx_sys[ idx ]; + } + else { - sys->snh = cursor; + // Clear link on persistent sources (done playing) + if( !(src->flags & SFX_FLAG_ONESHOT) ) + src->thread_clone->thread_clone = NULL; } - sys->cvol = avgvol / (float)(bpos*2); - sys->cur += frameCount; + idx ++ ; } - - sfx_redist(); + sfx_sys_len = wr; + + MUTEX_UNLOCK( sfx_mux_t01 ); (void)pInput; } -// Set of up to 8 sound effects packed into one -typedef struct sfx_set sfx_set_t; -struct sfx_set -{ - float *main; - char *sources; - - uint32_t segments[16]; //from->to,from->to ... - uint32_t numsegments; - uint32_t ch; - uint32_t flags; -}; - // Load strings into sfx_set's memory // String layout: "sounda.ogg\0soundb.ogg\0soundc.ogg\0\0" -void sfx_set_strings( sfx_set_t *dest, char *strSources, uint32_t flags, int bAsync ) +void sfx_set_strings( sfx_set *dest, char *strSources, u32 flags, int bAsync ) { printf( "Init sfx set\n| start | end | length | name \n" ); @@ -602,11 +531,11 @@ void sfx_set_strings( sfx_set_t *dest, char *strSources, uint32_t flags, int bAs dest->numsegments = 0; char *source = strSources; - uint32_t total = 0; + u32 total = 0; int len; while( (len = strlen( source )) ) { - uint32_t samples; + u32 samples; float *sound = sfx_vorbis( source, dest->ch, &samples ); if( !sound ) @@ -645,13 +574,7 @@ void sfx_set_strings( sfx_set_t *dest, char *strSources, uint32_t flags, int bAs vg_info( "finished, numsegments: %u\n", dest->numsegments ); } - -// If sources is non-null then it will try to pull from -// internally set string -// -// internal set string should be literal, otherwise leak if not -// handled correctly -void sfx_set_init( sfx_set_t *dest, char *sources ) +void sfx_set_init( sfx_set *dest, char *sources ) { #ifndef VYGER_RELEASE num_sfx_sets ++; @@ -668,7 +591,7 @@ void sfx_set_init( sfx_set_t *dest, char *sources ) } // Pick a random sound from the buffer and play it into system -void sfx_set_playrnd( sfx_set_t *source, sfx_system_t *sys, int min_id, int max_id ) +void sfx_set_playrnd( sfx_set *source, sfx_system *sys, int min_id, int max_id ) { if( !source->numsegments ) { @@ -686,7 +609,7 @@ void sfx_set_playrnd( sfx_set_t *source, sfx_system_t *sys, int min_id, int max_ } // Free set resources -void sfx_set_free( sfx_set_t *set ) +void sfx_set_free( sfx_set *set ) { #ifndef VYGER_RELEASE num_sfx_sets --;