X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fvg%2Fvg_audio.h;h=80307b85951810fc49c6d2d929d5515c94120dbc;hb=3dd767bb10e6fee9cbffeb185d1a9685810c17b5;hp=a1d863e68baca746983656c9a0d23f8d50aa1203;hpb=2a8c3c81345133939e0893ae8a972e83532888b4;p=vg.git diff --git a/src/vg/vg_audio.h b/src/vg/vg_audio.h index a1d863e..80307b8 100644 --- a/src/vg/vg_audio.h +++ b/src/vg/vg_audio.h @@ -15,7 +15,6 @@ #include "dr_soft/miniaudio.h" - #include "vg/vg.h" #include "vg/vg_stdint.h" #include "vg/vg_platform.h" @@ -25,29 +24,33 @@ #include "vg/vg_console.h" #include "vg/vg_store.h" -#include +#include #ifdef __GNUC__ - #pragma GCC push_options - #pragma GCC optimize ("O3") + #ifndef __clang__ + #pragma GCC push_options + #pragma GCC optimize ("O3") + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #endif #endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #define STB_VORBIS_MAX_CHANNELS 2 #include "stb/stb_vorbis.h" -#pragma GCC diagnostic pop - #ifdef __GNUC__ - #pragma GCC pop_options + #ifndef __clang__ + #pragma GCC pop_options + #pragma GCC diagnostic pop + #endif #endif #define SFX_MAX_SYSTEMS 32 #define AUDIO_FLAG_LOOP 0x1 #define AUDIO_FLAG_ONESHOT 0x2 #define AUDIO_FLAG_SPACIAL_3D 0x4 +#define AUDIO_FLAG_AUTO_START 0x8 +#define AUDIO_FLAG_KILL 0x10 #define FADEOUT_LENGTH 1100 #define FADEOUT_DIVISOR (1.0f/(float)FADEOUT_LENGTH) @@ -66,10 +69,8 @@ struct audio_clip const char *path; enum audio_source_mode source_mode; - /* result */ + u32 size; void *data; - u32 len; /* decompressed: sample count, - compressed: file size */ }; typedef struct audio_mix_info audio_mix_info; @@ -119,9 +120,8 @@ static struct vg_audio_system ma_device miniaudio_device; ma_device_config miniaudio_dconfig; - void *mem, *decode_mem; - u32 mem_current, - mem_total; + void *audio_pool, + *decode_buffer; u32 samples_last; /* synchro */ @@ -166,24 +166,11 @@ static struct vg_profile vg_prof_audio_decode, vg_prof_audio_mix; -static void *audio_alloc( u32 size ) -{ - u32 new_current = vg_audio.mem_current + size; - if( new_current > vg_audio.mem_total ) - vg_fatal_exit_loop( "Audio pool ran out of memory" ); - - void *ptr = vg_audio.mem + vg_audio.mem_current; - vg_audio.mem_current = new_current; - - return ptr; -} - - /* * These functions are called from the main thread and used to prevent bad * access. TODO: They should be no-ops in release builds. */ -static int audio_lock_checker_load(void) +VG_STATIC int audio_lock_checker_load(void) { int value; vg_mutex_lock( &vg_audio.mux_checker ); @@ -192,14 +179,14 @@ static int audio_lock_checker_load(void) return value; } -static void audio_lock_checker_store( int value ) +VG_STATIC void audio_lock_checker_store( int value ) { vg_mutex_lock( &vg_audio.mux_checker ); vg_audio.sync_locked = value; vg_mutex_unlock( &vg_audio.mux_checker ); } -static void audio_require_lock(void) +VG_STATIC void audio_require_lock(void) { if( audio_lock_checker_load() ) return; @@ -208,27 +195,28 @@ static void audio_require_lock(void) abort(); } -static void audio_lock(void) +VG_STATIC void audio_lock(void) { vg_mutex_lock( &vg_audio.mux_sync ); audio_lock_checker_store(1); } -static void audio_unlock(void) +VG_STATIC void audio_unlock(void) { audio_lock_checker_store(0); vg_mutex_unlock( &vg_audio.mux_sync ); } -static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, +VG_STATIC void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frameCount ); -static void vg_audio_init(void) +VG_STATIC void vg_audio_init(void) { vg_mutex_init( &vg_audio.mux_checker ); vg_mutex_init( &vg_audio.mux_sync ); + /* TODO: Move here? */ vg_convar_push( (struct vg_convar){ .name = "debug_audio", .data = &vg_audio.debug_ui, @@ -237,19 +225,16 @@ static void vg_audio_init(void) .persistent = 1 }); - vg_convar_push( (struct vg_convar){ - .name = "debug_audio_clips", - .data = &vg_audio.debug_ui_3d, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=1 }, - .persistent = 1 - }); + /* allocate memory */ + + /* 32mb fixed */ + vg_audio.audio_pool = + vg_create_linear_allocator( vg_mem.rtmemory, 1024*1024*32, + VG_MEMORY_SYSTEM ); - u32 decode_region = AUDIO_DECODE_SIZE * SFX_MAX_SYSTEMS; - vg_audio.mem_total = 1024*1024*32; - vg_audio.mem_current = 0; - vg_audio.mem = vg_alloc( vg_audio.mem_total + decode_region ); - vg_audio.decode_mem = &((u8 *)vg_audio.mem)[vg_audio.mem_total]; + /* fixed */ + u32 decode_size = AUDIO_DECODE_SIZE * SFX_MAX_SYSTEMS; + vg_audio.decode_buffer = vg_linear_alloc( vg_mem.rtmemory, decode_size ); /* setup pool */ vg_audio.active_pool_info.base = vg_audio.active_players; @@ -289,13 +274,15 @@ static void vg_audio_init(void) vg_success( "Ready\n" ); } -static void vg_audio_free(void * nothing) +VG_STATIC void vg_audio_free(void * nothing) { ma_device *device = &vg_audio.miniaudio_device; ma_device_uninit( device ); +#if 0 vg_free( vg_audio.mem ); vg_audio.mem = NULL; +#endif } /* @@ -316,7 +303,7 @@ static aatree_ptr audio_alloc_entity_internal(void) return playerid; } -static void audio_entity_free_internal( aatree_ptr id ) +VG_STATIC void audio_entity_free_internal( aatree_ptr id ) { struct active_audio_player *aap = &vg_audio.active_players[ id ]; aap->active = 0; @@ -330,15 +317,15 @@ static void audio_entity_free_internal( aatree_ptr id ) &vg_audio.active_pool_head ); } -static void *audio_entity_vorbis_ptr( aatree_ptr entid ) +VG_STATIC void *audio_entity_vorbis_ptr( aatree_ptr entid ) { - u8 *buf = (u8*)vg_audio.decode_mem, + u8 *buf = (u8*)vg_audio.decode_buffer, *loc = &buf[AUDIO_DECODE_SIZE*entid]; return (void *)loc; } -static void audio_entity_start( audio_entity *src ) +VG_STATIC void audio_entity_start( audio_entity *src ) { aatree_ptr entid = audio_alloc_entity_internal(); if( entid == AATREE_PTR_NIL ) @@ -373,7 +360,8 @@ static void audio_entity_start( audio_entity *src ) int err; stb_vorbis *decoder = stb_vorbis_open_memory( - src->info.source->data, src->info.source->len, &err, &alloc ); + src->info.source->data, + src->info.source->size, &err, &alloc ); if( !decoder ) { @@ -392,14 +380,14 @@ static void audio_entity_start( audio_entity *src ) } else { - ent->length = src->info.source->len; + ent->length = src->info.source->size; } } /* * Read everything from the queue */ -static void audio_system_enque(void) +VG_STATIC void audio_system_enque(void) { /* Process incoming sound queue */ audio_lock(); @@ -452,6 +440,12 @@ static void audio_system_enque(void) if( aap->ent.player->enqued == 0 ) { aap->ent.info = aap->ent.player->info; + + if( (aap->ent.info.flags & AUDIO_FLAG_KILL) && !aap->ent.fadeout ) + { + aap->ent.fadeout = FADEOUT_LENGTH; + aap->ent.fadeout_current = FADEOUT_LENGTH; + } } } } @@ -462,7 +456,7 @@ static void audio_system_enque(void) /* * Redistribute sound systems */ -static void audio_system_cleanup(void) +VG_STATIC void audio_system_cleanup(void) { audio_lock(); @@ -489,7 +483,7 @@ static void audio_system_cleanup(void) /* * Get effective volume and pan from this entity */ -static void audio_entity_spacialize( audio_entity *ent, float *vol, float *pan ) +VG_STATIC void audio_entity_spacialize( audio_entity *ent, float *vol, float *pan ) { if( ent->info.vol < 0.01f ) { @@ -519,19 +513,19 @@ static void audio_entity_spacialize( audio_entity *ent, float *vol, float *pan ) } } -static void audio_decode_uncompressed_mono( float *src, u32 count, float *dst ) +VG_STATIC void audio_decode_uncompressed_mono( i16 *src, u32 count, float *dst ) { for( u32 i=0; istereo */ -static int +VG_STATIC int stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis *f, float *buffer, int len ) { @@ -564,7 +558,45 @@ stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis *f, float *buffer, return n; } -static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) +/* + * ........ more wrecked code sorry! + */ +VG_STATIC int +stb_vorbis_get_samples_i16_downmixed( stb_vorbis *f, i16 *buffer, int len ) +{ + int n = 0, + c = VG_MIN( 1, f->channels - 1 ); + + while( n < len ) + { + int k = f->channel_buffer_end - f->channel_buffer_start; + + if( n+k >= len ) + k = len - n; + + for( int j=0; j < k; ++j ) + { + float sl = f->channel_buffers[ 0 ][f->channel_buffer_start+j], + sr = f->channel_buffers[ c ][f->channel_buffer_start+j]; + + *buffer++ = vg_clampf( 0.5f*(sl+sr), -1.0f, 1.0f ) * 32767.0f; + //*buffer++ = vg_clampf( sr, -1.0f, 1.0f ) * 32767.0f; + } + + n += k; + f->channel_buffer_start += k; + + if( n == len ) + break; + + if( !stb_vorbis_get_frame_float( f, NULL, NULL )) + break; + } + + return n; +} + +VG_STATIC void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) { vg_profile_begin( &_vg_prof_audio_decode ); @@ -586,7 +618,9 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) if( source_mode == k_audio_source_mono ) { - float *src = &((float *)ent->info.source->data)[ cursor ]; + i16 *src_buffer = ent->info.source->data, + *src = &src_buffer[cursor]; + audio_decode_uncompressed_mono( src, samples_this_run, dst ); } else if( source_mode == k_audio_source_compressed ) @@ -632,8 +666,8 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) vg_profile_end( &_vg_prof_audio_decode ); } -static void audio_entity_mix( aatree_ptr id, float *buffer, - u32 frame_count ) +VG_STATIC void audio_entity_mix( aatree_ptr id, float *buffer, + u32 frame_count ) { audio_entity *ent = &vg_audio.active_players[id].ent; @@ -686,7 +720,7 @@ static void audio_entity_mix( aatree_ptr id, float *buffer, /* * callback from miniaudio.h interface */ -static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, +VG_STATIC void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput, ma_uint32 frame_count ) { struct timespec time_start, time_end; @@ -728,108 +762,77 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, audio_unlock(); } -/* Decompress entire vorbis stream into buffer */ -static float *audio_decompress_vorbis( const unsigned char *data, int len, - int channels, u32 *samples ) +VG_STATIC void audio_clip_load( audio_clip *clip, void *lin_alloc ) { - int err; - stb_vorbis *pv = stb_vorbis_open_memory( data, len, &err, NULL ); - - if( !pv ) - { - vg_error( "stb_vorbis_open_memory() failed with error code: %i\n", err ); - return NULL; - } - - u32 length_samples = stb_vorbis_stream_length_in_samples( pv ); + if( lin_alloc == NULL ) + lin_alloc = vg_audio.audio_pool; - vg_info( "decompress_vorbis: %u samples (%.2fs), %.1fkb\n", - length_samples, - (float)length_samples / (44100.0f*(float)channels), - (float)(length_samples*4*channels) / 1024.0f ); - - float *buffer = audio_alloc( length_samples * channels * sizeof(float) ); - if( !buffer ) + if( clip->source_mode == k_audio_source_mono ) { - stb_vorbis_close( pv ); - vg_error( "Failed to allocated memory for audio\n" ); - return NULL; - } - - int read_samples = stb_vorbis_get_samples_float_interleaved( - pv, channels, buffer, length_samples * channels ); + vg_linear_clear( vg_mem.scratch ); + u32 fsize; - if( read_samples != length_samples ) - { - vg_warn( "| warning: sample count mismatch. Expected %u got %i\n", - length_samples, read_samples ); - length_samples = read_samples; - } - - stb_vorbis_close( pv ); - *samples = length_samples; - return buffer; -} + stb_vorbis_alloc alloc = { + .alloc_buffer = vg_linear_alloc( vg_mem.scratch, AUDIO_DECODE_SIZE ), + .alloc_buffer_length_in_bytes = AUDIO_DECODE_SIZE + }; -static int audio_clip_load( audio_clip *clip ) -{ - /* Load and decompress */ - i64 file_len; - void *filedata = vg_asset_read_s( clip->path, &file_len ); + void *filedata = vg_file_read( vg_mem.scratch, clip->path, &fsize ); - if( !filedata ) - { - vg_error( "OGG load failed (%s)\n", clip->path ); - return 0; - } + int err; + stb_vorbis *decoder = stb_vorbis_open_memory( + filedata, fsize, &err, &alloc ); - if( clip->source_mode == k_audio_source_mono ) - { - u32 samples = 0; - float *sound = audio_decompress_vorbis( filedata, file_len, 1, &samples ); - clip->data = sound; - clip->len = samples; + if( !decoder ) + { + vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", + clip->path, err ); + vg_fatal_exit_loop( "Vorbis decode error" ); + } - float seconds = (float)samples / 44100.0f, - mb = (float)(samples*4) / (1024.0f*1024.0f); + /* only mono is supported in uncompressed */ + u32 length_samples = stb_vorbis_stream_length_in_samples( decoder ), + data_size = length_samples * sizeof(i16); - vg_info( "Loaded audio clip[mono] '%s' (%.1fs, %.1fmb)\n", - clip->path, seconds, mb ); - } - else if( clip->source_mode == k_audio_source_compressed ) - { - void *data = audio_alloc( file_len ); - memcpy( data, filedata, file_len ); + audio_lock(); + clip->data = vg_linear_alloc( lin_alloc, data_size ); + clip->size = length_samples; + audio_unlock(); + + int read_samples = stb_vorbis_get_samples_i16_downmixed( + decoder, clip->data, length_samples ); - clip->data = data; - clip->len = file_len; + if( read_samples != length_samples ) + vg_fatal_exit_loop( "Decode error" ); - float mb = (float)(file_len) / (1024.0f*1024.0f); - vg_info( "Loaded audio clip[compressed] '%s' (%.1fmb)\n", - clip->path, mb ); + float mb = (float)(data_size) / (1024.0f*1024.0f); + vg_info( "Loaded audio clip '%s' (%.1fmb) %u samples\n", clip->path, mb, + length_samples ); } - else + + /* load in directly */ + else if( clip->source_mode == k_audio_source_compressed ) { - /* ... */ + audio_lock(); + clip->data = vg_file_read( lin_alloc, clip->path, &clip->size ); + audio_unlock(); - clip->data = NULL; - clip->len = 0; + if( !clip->data ) + vg_fatal_exit_loop( "Audio failed to load" ); - vg_error( "Unkown source mode (%u)\n", clip->source_mode ); - return 0; + float mb = (float)(clip->size) / (1024.0f*1024.0f); + vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb ); } - - return 1; } -static void audio_clip_loadn( audio_clip *arr, int count ) +VG_STATIC void audio_clip_loadn( audio_clip *arr, int count, void *lin_alloc ) { for( int i=0; ienqued ) { - vg_warn( "Audio commit spamming; already enqued (%s)\n", sys->name ); + vg_warn( "[2] Audio commit spamming; already enqued (%s)\n", sys->name ); return; } @@ -851,7 +854,7 @@ static void audio_player_commit( audio_player *sys ) ent->player = sys; } -static void audio_require_init( audio_player *player ) +VG_STATIC void audio_require_init( audio_player *player ) { if( player->init ) return; @@ -859,9 +862,9 @@ static void audio_require_init( audio_player *player ) vg_fatal_exit_loop( "Must init audio player before playing! \n" ); } -static void audio_require_clip_loaded( audio_clip *clip ) +VG_STATIC void audio_require_clip_loaded( audio_clip *clip ) { - if( clip->data ) + if( clip->data && clip->size ) return; vg_fatal_exit_loop( "Must load audio clip before playing! \n" ); @@ -869,25 +872,38 @@ static void audio_require_clip_loaded( audio_clip *clip ) /* Play a clip using player. If its already playing something, it will * fadeout quickly and start the next sound */ -static void audio_player_playclip( audio_player *player, audio_clip *clip ) +VG_STATIC void audio_player_playclip( audio_player *player, audio_clip *clip ) { audio_require_lock(); audio_require_init( player ); audio_require_clip_loaded( clip ); + if( player->info.flags & AUDIO_FLAG_KILL ) + { + vg_error( "Can't start audio clip on player that is/has disconnected" ); + return; + } + + if( player->enqued ) + { + vg_warn( "[1] Audio commit spamming; already enqued (%s)\n", + player->name ); + return; + } + player->info.source = clip; audio_player_commit( player ); } #if 0 -static void audio_player_playoneshot( audio_player *player, audio_clip *clip ) +VG_STATIC void audio_player_playoneshot( audio_player *player, audio_clip *clip ) { audio_require_lock(); audio_require_init( player ); } #endif -static void audio_play_oneshot( audio_clip *clip, float volume ) +VG_STATIC void audio_play_oneshot( audio_clip *clip, float volume ) { audio_require_lock(); audio_require_clip_loaded( clip ); @@ -907,7 +923,7 @@ static void audio_play_oneshot( audio_clip *clip, float volume ) ent->player = NULL; } -static void audio_player_init( audio_player *player ) +VG_STATIC void audio_player_init( audio_player *player ) { player->active_entity = AATREE_PTR_NIL; player->init = 1; @@ -921,7 +937,7 @@ static void audio_player_init( audio_player *player ) * Safety enforced Get/set attributes */ -static int audio_player_is_playing( audio_player *sys ) +VG_STATIC int audio_player_is_playing( audio_player *sys ) { audio_require_lock(); @@ -931,43 +947,43 @@ static int audio_player_is_playing( audio_player *sys ) return 0; } -static void audio_player_set_position( audio_player *sys, v3f pos ) +VG_STATIC void audio_player_set_position( audio_player *sys, v3f pos ) { audio_require_lock(); v3_copy( pos, sys->info.world_position ); } -static void audio_player_set_vol( audio_player *sys, float vol ) +VG_STATIC void audio_player_set_vol( audio_player *sys, float vol ) { audio_require_lock(); sys->info.vol = vol; } -static float audio_player_get_vol( audio_player *sys ) +VG_STATIC float audio_player_get_vol( audio_player *sys ) { audio_require_lock(); return sys->info.vol; } -static void audio_player_set_pan( audio_player *sys, float pan ) +VG_STATIC void audio_player_set_pan( audio_player *sys, float pan ) { audio_require_lock(); sys->info.pan = pan; } -static float audio_player_get_pan( audio_player *sys ) +VG_STATIC float audio_player_get_pan( audio_player *sys ) { audio_require_lock(); return sys->info.pan; } -static void audio_player_set_flags( audio_player *sys, u32 flags ) +VG_STATIC void audio_player_set_flags( audio_player *sys, u32 flags ) { audio_require_lock(); sys->info.flags = flags; } -static u32 audio_player_get_flags( audio_player *sys ) +VG_STATIC u32 audio_player_get_flags( audio_player *sys ) { audio_require_lock(); return sys->info.flags; @@ -978,7 +994,7 @@ static u32 audio_player_get_flags( audio_player *sys ) * Debugging */ -static void audio_debug_ui( m4x4f mtx_pv ) +VG_STATIC void audio_debug_ui( m4x4f mtx_pv ) { if( !vg_audio.debug_ui ) return; @@ -1025,52 +1041,51 @@ static void audio_debug_ui( m4x4f mtx_pv ) char perf[128]; /* Draw UI */ - ui_global_ctx.cursor[0] = 258; - ui_global_ctx.cursor[1] = VG_PROFILE_SAMPLE_COUNT*2+8+24+12; - ui_global_ctx.cursor[2] = 150; - ui_global_ctx.cursor[3] = 12; + vg_uictx.cursor[0] = 258; + vg_uictx.cursor[1] = VG_PROFILE_SAMPLE_COUNT*2+8+24+12; + vg_uictx.cursor[2] = 150; + vg_uictx.cursor[3] = 12; - float usage = (float)vg_audio.mem_current / (1024.0f*1024.0f), - total = (float)vg_audio.mem_total / (1024.0f*1024.0f), - percent = (usage/total) * 100.0f; + float mb1 = 1024.0f*1024.0f, + usage = vg_linear_get_cur( vg_audio.audio_pool ) / mb1, + total = vg_linear_get_capacity( vg_audio.audio_pool ) / mb1, + percent = (usage/total) * 100.0f; + snprintf( perf, 127, "Mem: %.1f/%.1fmb (%.1f%%)\n", usage, total, percent ); - ui_text( &ui_global_ctx, ui_global_ctx.cursor, perf, 1, 0 ); - ui_global_ctx.cursor[1] += 20; + ui_text( vg_uictx.cursor, perf, 1, 0 ); + vg_uictx.cursor[1] += 20; ui_rect overlap_buffer[ SFX_MAX_SYSTEMS ]; u32 overlap_length = 0; - if( !vg_audio.debug_ui_3d ) - return; - /* Draw audio stack */ for( int i=0; icursor / (float)inf->length) * w; /* cursor */ - ui_global_ctx.cursor[2] = 2; - ui_global_ctx.cursor[0] = c; - ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0xffffffff ); + vg_uictx.cursor[2] = 2; + vg_uictx.cursor[0] = c; + ui_fill_rect( vg_uictx.cursor, 0xffffffff ); - ui_global_ctx.cursor[0] = baseline + 2; - ui_global_ctx.cursor[1] += 2; + vg_uictx.cursor[0] = baseline + 2; + vg_uictx.cursor[1] += 2; snprintf( perf, 127, "%s %.1f%%", infos[i].name, infos[i].vol ); - ui_text( &ui_global_ctx, ui_global_ctx.cursor, perf, 1, 0 ); + ui_text( vg_uictx.cursor, perf, 1, 0 ); if( inf->flags & AUDIO_FLAG_SPACIAL_3D ) { @@ -1111,7 +1126,7 @@ static void audio_debug_ui( m4x4f mtx_pv ) wr[1] += 18; } - ui_text( &ui_global_ctx, wr, perf, 1, 0 ); + ui_text( wr, perf, 1, 0 ); ui_rect_copy( wr, overlap_buffer[ overlap_length ++ ] ); } @@ -1119,8 +1134,8 @@ static void audio_debug_ui( m4x4f mtx_pv ) projected_behind: - ui_end_down( &ui_global_ctx ); - ui_global_ctx.cursor[1] += 1; + ui_end_down(); + vg_uictx.cursor[1] += 1; } }