X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=vg%2Fvg_audio.h;h=e62d5845447e35f09c3e3b6536911a38ff2e3e42;hb=3363633178b1eea582304742ad1202487af0feb1;hp=330be30a17319588d572247737d2ff3aa3231905;hpb=076dd0fbd6e35277edaf474b041e570728575f56;p=fishladder.git diff --git a/vg/vg_audio.h b/vg/vg_audio.h index 330be30..e62d584 100644 --- a/vg/vg_audio.h +++ b/vg/vg_audio.h @@ -6,79 +6,75 @@ #define STB_VORBIS_MAX_CHANNELS 2 #include "stb/stb_vorbis.h" -#define SFX_MAX_SYSTEMS 16 -#define SFX_FLAG_ONESHOT 0x1 -#define SFX_FLAG_STEREO 0x2 -#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; - -struct sfx_vol +#define SFX_MAX_SYSTEMS 32 +//#define SFX_FLAG_ONESHOT 0x1 +#define SFX_FLAG_STEREO 0x2 +#define SFX_FLAG_REPEAT 0x4 +#define SFX_FLAG_PERSISTENT 0x8 +#define FADEOUT_LENGTH 4410 +#define FADEOUT_DIVISOR (1.f/(float)FADEOUT_LENGTH) + +typedef struct sfx_vol_control sfx_vol_control; +typedef struct sfx_system sfx_system; + +struct sfx_vol_control { float val; - float cmp; + const char *name; }; struct sfx_system { + sfx_system *persisitent_source; + int in_queue; + // Source buffer start - float *source; - float *replacement; + float *source, *replacement; - // Modifiers - sfx_vol_t *vol_src; - float vol; + u32 clip_start, clip_end, buffer_length; - float spd; + // Modifiers + sfx_vol_control *vol_src; + float vol, cvol; // Info - int ch; // channels - u32 end; // buffer end - u32 cur; // cursor position + u32 ch, end, cur; u32 flags; // Effects - u32 snh; - u32 fadeout; - - // The 'Opposite' pointer - sfx_system_t *optr; + u32 fadeout, fadeout_current; // Diagnostic - float cvol; // 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[32]; //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 +82,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 +116,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 +178,16 @@ 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 +195,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 +210,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,49 +219,58 @@ 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_begin_edit( sfx_system *sys ) { MUTEX_LOCK( sfx_mux_t01 ); - - if( sfx_q_len >= SFX_MAX_SYSTEMS ) + + if( sfx_q_len >= SFX_MAX_SYSTEMS && !sys->in_queue ) { - vg_error( "Warning: No free space in sound queue\n" ); - MUTEX_UNLOCK( sfx_mux_t01 ); + vg_warn( "Warning: No free space in sound queue\n" ); return 0; } - // Mark change in queue - sfx_q[ sfx_q_len ++ ] = sys; + return 1; +} + +static void sfx_end_edit( sfx_system *sys ) +{ + MUTEX_UNLOCK( sfx_mux_t01 ); +} + +// Mark change to be uploaded to queue system +static int sfx_push( sfx_system *sys ) +{ + if( !sys->in_queue ) + { + // Mark change in queue + sfx_q[ sfx_q_len ++ ] = sys; + sys->in_queue = 1; + } MUTEX_UNLOCK( sfx_mux_t01 ); 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 +284,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 +307,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; @@ -349,39 +336,20 @@ void vg_audio_init(void) } } -#ifndef VYGER_RELEASE -uint32_t 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) -{ -#ifndef VYGER_RELEASE - if( num_sfx_sets ) - { - vg_error( "Leaked %u sfx sets\n", num_sfx_sets ); - } -#endif -} - // 1 // ====================================================== // 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 ) - { - vg_error( "Warning: No free space in sound system\n" ); - return NULL; - } // A conditional is done against this in localization step, // Needs to be initialized. @@ -390,223 +358,188 @@ 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]; + sfx_system *clone; - // This is a 'new' sound if optr not set. - if( !src->optr || src->flags & SFX_FLAG_ONESHOT ) - { - src->optr = sfx_alloc(); - } + src->in_queue = 0; - // 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; - - // Localize data to thread 1's memory pool - // memcpy( src->optr, src, sizeof( sfx_system_t ) ); + // Copy + clone = sfx_alloc(); + *clone = *src; - 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; + // Links need to exist on persistent sounds + clone->persisitent_source = src->flags & SFX_FLAG_PERSISTENT? src: NULL; } + sfx_q_len = 0; - // Pull in volume sliders + // Volume modifiers 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 ) + sfx_system *sys = sfx_sys + i; + + // Apply persistent volume if linked + if( sys->flags & SFX_FLAG_PERSISTENT ) { - if( !(src->flags & SFX_FLAG_ONESHOT) ) - { - // Correct source pointer - src->optr->optr = sfx_sys + wr; - } + sys->vol = sys->persisitent_source->vol * g_master_volume; - sfx_sys[ wr ++ ] = sfx_sys[ idx ]; - } - else - { - if( !(src->flags & SFX_FLAG_ONESHOT) ) + // Persistent triggers + // ------------------- + + // Fadeout effect ( + remove ) + if( sys->persisitent_source->fadeout ) { - // Clear link on source - src->optr->optr = NULL; + sys->fadeout_current = sys->persisitent_source->fadeout_current; + sys->fadeout = sys->persisitent_source->fadeout; + + sys->persisitent_source = NULL; + sys->flags &= ~SFX_FLAG_PERSISTENT; } } - - idx ++ ; + + // Apply volume slider if it has one linked + if( sys->vol_src ) + sys->cvol = sys->vol * sys->vol_src->val; + else + sys->cvol = sys->vol; } - 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 ? ) + + // Clear buffer 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, buffer_pos = 0; + float pcf[2] = { 0.f, 0.0f }; - float avgvol = 0.f; + u32 frames_write = frameCount; + float fadeout_divisor = 1.0f / (float)sys->fadeout; - float pcf[2] = { 0.f }; - - while( cursor < vg_min( sys->cur + frameCount, sys->end ) ) + while( frames_write ) { - 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 - // This lasts 441 samples + u32 samples_this_run = VG_MIN( frames_write, sys->end - cursor ); + if( sys->fadeout ) { - if( sys->snh < sys->end ) + // Force this system to be removed now + if( sys->fadeout_current == 0 ) + { + sys->flags &= 0x00000000; + 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 ); + + float vol = sys->vol; + + if( sys->fadeout ) { - audio_mixer_getsamples( pcf, sys->source, sys->snh, 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 --; + vol *= (float)sys->fadeout_current * fadeout_divisor; + sys->fadeout_current --; } - else + + if( buffer_pos >= frameCount ) { - sys->fadeout = 0; + break; } + + pOut32F[ buffer_pos*2+0 ] += pcf[0] * vol; + pOut32F[ buffer_pos*2+1 ] += pcf[1] * vol; + + cursor ++; + buffer_pos ++; } - cursor ++; - bpos ++; + frames_write -= samples_this_run; + + if( sys->flags & SFX_FLAG_REPEAT ) + { + if( frames_write ) + { + cursor = 0; + continue; + } + } + + sys->cur = cursor; + break; } + } + + // Redistribute sound systems + MUTEX_LOCK( sfx_mux_t01 ); + + u32 idx = 0, wr = 0; + while( idx != sfx_sys_len ) + { + sfx_system *src = sfx_sys + idx; - if( !sys->fadeout ) + // Keep only if cursor is before end or repeating + if( src->cur < src->end || (src->flags & SFX_FLAG_REPEAT) ) { - sys->snh = cursor; + sfx_sys[ wr ++ ] = sfx_sys[ idx ]; } - 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 ) +static void sfx_set_strings( sfx_set *dest, char *strSources, u32 flags, int bAsync ) { - printf( "Init sfx set\n| start | end | length | name \n" ); - dest->ch = (flags & SFX_FLAG_STEREO)? 2: 1; dest->main = NULL; 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 ) @@ -628,8 +561,6 @@ void sfx_set_strings( sfx_set_t *dest, char *strSources, uint32_t flags, int bAs dest->segments[ dest->numsegments*2+0 ] = total-samples; dest->segments[ dest->numsegments*2+1 ] = total; - - printf( "| %09u | %09u | %09u | %s\n", total-samples, total, samples, source ); } else { @@ -641,55 +572,66 @@ void sfx_set_strings( sfx_set_t *dest, char *strSources, uint32_t flags, int bAs source += len +1; dest->numsegments ++; } - - 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 ) +static void sfx_set_init( sfx_set *dest, char *sources ) { -#ifndef VYGER_RELEASE - num_sfx_sets ++; -#endif - if( !sources ) - { sfx_set_strings( dest, dest->sources, dest->flags, 0 ); - } else - { sfx_set_strings( dest, sources, dest->flags, 0 ); +} + +static void sfx_set_play( sfx_set *source, sfx_system *sys, int id ) +{ + if( sfx_begin_edit( sys ) ) + { + sys->fadeout = 0; + sys->fadeout_current = 0; + sys->source = source->main; + sys->cur = source->segments[ id*2 + 0 ]; + sys->end = source->segments[ id*2 + 1 ]; + sys->ch = source->ch; + + // Diagnostics + sys->clip_start = sys->cur; + sys->clip_end = sys->end; + sys->buffer_length = source->segments[ (source->numsegments-1)*2 + 1 ]; + + sfx_push( sys ); } } // Pick a random sound from the buffer and play it into system -void sfx_set_playrnd( sfx_set_t *source, sfx_system_t *sys ) +static void sfx_set_playrnd( sfx_set *source, sfx_system *sys, int min_id, int max_id ) { if( !source->numsegments ) - { return; + + if( max_id > source->numsegments ) + { + vg_error( "Max ID out of range for playrnd\n" ); + return; } - int pick = rand() % source->numsegments; - - sys->source = source->main; - sys->cur = source->segments[ pick*2 + 0 ]; - sys->end = source->segments[ pick*2 + 1 ]; - sys->ch = source->ch; + int pick = (rand() % (max_id-min_id)) + min_id; - sfx_save( sys ); + sfx_set_play( source, sys, pick ); +} + +static void sfx_system_fadeout( sfx_system *sys, u32 length_samples ) +{ + if( sfx_begin_edit( sys ) ) + { + sys->fadeout_current = length_samples; + sys->fadeout = length_samples; + + sfx_end_edit( sys ); + } } // Free set resources -void sfx_set_free( sfx_set_t *set ) +static void sfx_set_free( sfx_set *set ) { -#ifndef VYGER_RELEASE - num_sfx_sets --; -#endif free( set->main ); }