X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=src%2Fvg%2Fvg_audio.h;h=80307b85951810fc49c6d2d929d5515c94120dbc;hb=3dd767bb10e6fee9cbffeb185d1a9685810c17b5;hp=bb4d0920feb889361506d16db83393fefd861138;hpb=94b61bed97af43179b37593f4453a05d03687cbc;p=vg.git diff --git a/src/vg/vg_audio.h b/src/vg/vg_audio.h index bb4d092..80307b8 100644 --- a/src/vg/vg_audio.h +++ b/src/vg/vg_audio.h @@ -6,7 +6,15 @@ #define MA_NO_GENERATION #define MA_NO_DECODING #define MA_NO_ENCODING +#define MA_NO_WAV +#define MA_NO_FLAC +#define MA_NO_MP3 +#define MA_NO_ENGINE +#define MA_NO_NODE_GRAPH +#define MA_NO_RESOURCE_MANAGER + #include "dr_soft/miniaudio.h" + #include "vg/vg.h" #include "vg/vg_stdint.h" #include "vg/vg_platform.h" @@ -16,17 +24,35 @@ #include "vg/vg_console.h" #include "vg/vg_store.h" -#include +#include + +#ifdef __GNUC__ + #ifndef __clang__ + #pragma GCC push_options + #pragma GCC optimize ("O3") + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #endif +#endif #define STB_VORBIS_MAX_CHANNELS 2 #include "stb/stb_vorbis.h" +#ifdef __GNUC__ + #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 4410 +#define FADEOUT_LENGTH 1100 #define FADEOUT_DIVISOR (1.0f/(float)FADEOUT_LENGTH) #define AUDIO_DECODE_SIZE (1024*256) /* 256 kb decoding buffers */ @@ -34,8 +60,7 @@ enum audio_source_mode { k_audio_source_mono, - k_audio_source_mono_compressed, - k_audio_source_stereo_compressed + k_audio_source_compressed, }; typedef struct audio_clip audio_clip; @@ -44,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; @@ -65,7 +88,7 @@ struct audio_player { aatree_ptr active_entity; /* non-nil if currently playing */ audio_mix_info info; - int enqued; + int enqued, init; /* Diagnostic */ const char *name; @@ -97,14 +120,15 @@ 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 */ int sync_locked; - MUTEX_TYPE mutex_checker; - MUTEX_TYPE mutex_sync; + + vg_mutex mux_checker, + mux_sync; /* Audio engine, thread 1 */ struct active_audio_player @@ -127,78 +151,72 @@ static struct vg_audio_system /* System queue, and access from thread 0 */ audio_entity entity_queue[SFX_MAX_SYSTEMS]; int queue_len; - - char performance_info[128]; - int debug_ui; + int debug_ui, debug_ui_3d; v3f listener_pos, listener_ears; } vg_audio; -static void *audio_alloc( u32 size ) -{ - u32 new_current = vg_audio.mem_current + size; - if( new_current > vg_audio.mem_total ) - { - vg_error( "audio pool over budget!\n" ); - free( vg_audio.mem ); - return NULL; - } - - void *ptr = vg_audio.mem + vg_audio.mem_current; - vg_audio.mem_current = new_current; - - return ptr; -} - +static struct vg_profile + _vg_prof_audio_decode = {.mode = k_profile_mode_accum, + .name = "[T2] audio_decode()"}, + _vg_prof_audio_mix = {.mode = k_profile_mode_accum, + .name = "[T2] audio_mix()"}, + vg_prof_audio_decode, + vg_prof_audio_mix; /* * 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; - MUTEX_LOCK( vg_audio.mutex_checker ); + vg_mutex_lock( &vg_audio.mux_checker ); value = vg_audio.sync_locked; - MUTEX_UNLOCK( vg_audio.mutex_checker ); + vg_mutex_unlock( &vg_audio.mux_checker ); return value; } -static void audio_lock_checker_store( int value ) +VG_STATIC void audio_lock_checker_store( int value ) { - MUTEX_LOCK( vg_audio.mutex_checker ); + vg_mutex_lock( &vg_audio.mux_checker ); vg_audio.sync_locked = value; - MUTEX_UNLOCK( vg_audio.mutex_checker ); + 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; - vg_exiterr( "Modifying sound effects systems requires locking\n" ); + vg_error( "Modifying sound effects systems requires locking\n" ); + abort(); } -static void audio_lock(void) +VG_STATIC void audio_lock(void) { - MUTEX_LOCK( vg_audio.mutex_sync ); + 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); - MUTEX_UNLOCK( vg_audio.mutex_sync ); + 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 int 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, @@ -207,11 +225,16 @@ static int vg_audio_init(void) .persistent = 1 }); - u32 decode_region = AUDIO_DECODE_SIZE * SFX_MAX_SYSTEMS; - vg_audio.mem_total = 1024*1024*32; - vg_audio.mem_current = 0; - vg_audio.mem = malloc( vg_audio.mem_total + decode_region ); - vg_audio.decode_mem = &((u8 *)vg_audio.mem)[vg_audio.mem_total]; + /* allocate memory */ + + /* 32mb fixed */ + vg_audio.audio_pool = + vg_create_linear_allocator( vg_mem.rtmemory, 1024*1024*32, + VG_MEMORY_SYSTEM ); + + /* 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; @@ -224,11 +247,12 @@ static int vg_audio_init(void) ma_device_config *dconf = &vg_audio.miniaudio_dconfig; ma_device *device = &vg_audio.miniaudio_device; - *dconf = ma_device_config_init( ma_device_type_playback ); + *dconf = ma_device_config_init( ma_device_type_playback ); dconf->playback.format = ma_format_f32; dconf->playback.channels = 2; dconf->sampleRate = 44100; dconf->dataCallback = audio_mixer_callback; + dconf->periodSizeInFrames = 441; dconf->pUserData = NULL; @@ -236,28 +260,29 @@ static int vg_audio_init(void) if( ma_device_init( NULL, dconf, device) != MA_SUCCESS ) { - vg_error( "ma_device failed to initialize" ); - return 0; + vg_fatal_exit_loop( "(audio) ma_device failed to initialize" ); } else { if( ma_device_start( device ) != MA_SUCCESS ) { ma_device_uninit( device ); - vg_error( "ma_device failed to start" ); - return 0; + vg_fatal_exit_loop( "(audio) ma_device failed to start" ); } } - - return 1; + + vg_success( "Ready\n" ); } -static void vg_audio_free(void) +VG_STATIC void vg_audio_free(void * nothing) { ma_device *device = &vg_audio.miniaudio_device; ma_device_uninit( device ); - free( vg_audio.mem ); +#if 0 + vg_free( vg_audio.mem ); + vg_audio.mem = NULL; +#endif } /* @@ -278,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; @@ -292,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 ) @@ -309,7 +334,7 @@ static void audio_entity_start( audio_entity *src ) audio_entity *ent = &vg_audio.active_players[ entid ].ent; ent->info = src->info; - ent->name = "todo"; + ent->name = src->info.source->path; ent->cur = 0; ent->player = src->player; @@ -323,8 +348,7 @@ static void audio_entity_start( audio_entity *src ) src->player->active_entity = entid; } - if( src->info.source->source_mode == k_audio_source_mono_compressed || - src->info.source->source_mode == k_audio_source_stereo_compressed ) + if( src->info.source->source_mode == k_audio_source_compressed ) { /* Setup vorbis decoder */ struct active_audio_player *aap = &vg_audio.active_players[ entid ]; @@ -336,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 ) { @@ -355,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(); @@ -387,7 +412,7 @@ static void audio_system_enque(void) audio_entity *ent = &vg_audio.active_players[ entid ].ent; if( !ent->fadeout ) { - ent->fadeout = 1; + ent->fadeout = FADEOUT_LENGTH; ent->fadeout_current = FADEOUT_LENGTH; } @@ -415,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; + } } } } @@ -425,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(); @@ -452,31 +483,123 @@ 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 ) + { + *vol = ent->info.vol; + *pan = 0.0f; + return; + } + v3f delta; v3_sub( ent->info.world_position, vg_audio.listener_pos, delta ); - float dist = v3_length( delta ), - attn = (dist / ent->info.vol) +1.0f; + float dist2 = v3_length2( delta ); - v3_muls( delta, 1.0f/dist, delta ); + if( dist2 < 0.0001f ) + { + *pan = 0.0f; + *vol = 1.0f; + } + else + { + float dist = sqrtf( dist2 ), + attn = (dist / ent->info.vol) +1.0f; - *pan = v3_dot( vg_audio.listener_ears, delta ); - *vol = 1.0f/(attn*attn); + v3_muls( delta, 1.0f/dist, delta ); + *pan = v3_dot( vg_audio.listener_ears, delta ); + *vol = 1.0f/(attn*attn); + } } -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 + */ +VG_STATIC int +stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis *f, float *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 ) + { + *buffer++ = f->channel_buffers[ 0 ][f->channel_buffer_start+j]; + *buffer++ = f->channel_buffers[ c ][f->channel_buffer_start+j]; + } + + n += k; + f->channel_buffer_start += k; + + if( n == len ) + break; + + if( !stb_vorbis_get_frame_float( f, NULL, NULL )) + break; + } + + return n; +} + +/* + * ........ 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; } -static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) +VG_STATIC void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) { + vg_profile_begin( &_vg_prof_audio_decode ); + struct active_audio_player *aap = &vg_audio.active_players[id]; audio_entity *ent = &aap->ent; @@ -490,19 +613,22 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) remaining -= samples_this_run; float *dst = &buf[ buffer_pos * 2 ]; + + int source_mode = ent->info.source->source_mode; - if( ent->info.source->source_mode == k_audio_source_mono ) + 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( ent->info.source->source_mode == k_audio_source_mono_compressed ) + else if( source_mode == k_audio_source_compressed ) { - int read_samples = stb_vorbis_get_samples_float_interleaved( + int read_samples = stb_vorbis_get_samples_float_interleaved_stereo( aap->vorbis_handle, - 2, dst, - samples_this_run * 2 ); + samples_this_run ); if( read_samples != samples_this_run ) { @@ -515,8 +641,7 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) if( (ent->info.flags & AUDIO_FLAG_LOOP) && remaining ) { - if( ent->info.source->source_mode == k_audio_source_mono_compressed || - ent->info.source->source_mode == k_audio_source_stereo_compressed ) + if( source_mode == k_audio_source_compressed ) { stb_vorbis_seek_start( aap->vorbis_handle ); } @@ -538,10 +663,11 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) } ent->cur = cursor; + 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; @@ -556,6 +682,8 @@ static void audio_entity_mix( aatree_ptr id, float *buffer, audio_entity_get_samples( id, frame_count, pcf ); + vg_profile_begin( &_vg_prof_audio_mix ); + if( ent->info.flags & AUDIO_FLAG_SPACIAL_3D ) audio_entity_spacialize( ent, &vol, &pan ); @@ -585,21 +713,14 @@ static void audio_entity_mix( aatree_ptr id, float *buffer, buffer_pos ++; } -} -static void vg_sleep_ms( long msec ) -{ - struct timespec ts; - - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - nanosleep( &ts, &ts ); + vg_profile_end( &_vg_prof_audio_mix ); } /* * 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; @@ -618,12 +739,10 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, struct active_audio_player *aap = &vg_audio.active_players[i]; if( aap->active ) + { audio_entity_mix( i, pOut32F, frame_count ); + } } - -#if 0 - vg_sleep_ms( 20 ); -#endif /* redistribute */ audio_system_cleanup(); @@ -631,159 +750,89 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, /* TODO: what the hell is this? */ (void)pInput; - /* - * Debug information - */ - clock_gettime( CLOCK_REALTIME, &time_end ); - double elapsed = 1000.0*time_end.tv_sec + 1e-6*time_end.tv_nsec - - (1000.0*time_start.tv_sec + 1e-6*time_start.tv_nsec), - budget = ((double)frame_count / 44100.0) * 1000.0, - percent = (elapsed/budget) * 100.0; + audio_lock(); + vg_profile_increment( &_vg_prof_audio_decode ); + vg_profile_increment( &_vg_prof_audio_mix ); + + vg_prof_audio_mix = _vg_prof_audio_mix; + vg_prof_audio_decode = _vg_prof_audio_decode; - snprintf( vg_audio.performance_info, 127, - "%.1fms/%.1fms (%.1f%%) (%u frames)", - elapsed, budget, percent, frame_count ); + vg_audio.samples_last = frame_count; + 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_exit(); - } - - 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; - } - - if( clip->source_mode == k_audio_source_mono ) - { - u32 samples; - float *sound = audio_decompress_vorbis( filedata, file_len, 1, &samples ); - clip->data = sound; - clip->len = samples; + int err; + stb_vorbis *decoder = stb_vorbis_open_memory( + filedata, fsize, &err, &alloc ); - float seconds = (float)samples / 44100.0f, - mb = (float)(samples*4) / (1024.0f*1024.0f); + if( !decoder ) + { + vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", + clip->path, err ); + vg_fatal_exit_loop( "Vorbis decode error" ); + } - vg_info( "Loaded audio clip[mono] '%s' (%.1fs, %.1fmb)\n", - clip->path, seconds, mb ); - } - else if( clip->source_mode == k_audio_source_mono_compressed ) - { - void *data = audio_alloc( file_len ); - memcpy( data, filedata, file_len ); + /* only mono is supported in uncompressed */ + u32 length_samples = stb_vorbis_stream_length_in_samples( decoder ), + data_size = length_samples * sizeof(i16); - clip->data = data; - clip->len = file_len; + audio_lock(); + clip->data = vg_linear_alloc( lin_alloc, data_size ); + clip->size = length_samples; + audio_unlock(); - float mb = (float)(file_len) / (1024.0f*1024.0f); - vg_info( "Loaded audio clip[mono_compressed] '%s' (%.1fmb)\n", - clip->path, mb ); - } - else if( clip->source_mode == k_audio_source_stereo_compressed ) - { - /* ... */ + int read_samples = stb_vorbis_get_samples_i16_downmixed( + decoder, clip->data, length_samples ); - clip->data = NULL; - clip->len = 0; + if( read_samples != length_samples ) + vg_fatal_exit_loop( "Decode error" ); - vg_error( "Source mode (%u) currently unsupported\n", clip->source_mode ); - return 0; + 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; ifadeout = 0; - sys->fadeout_current = 0; - sys->source = source->data; - sys->cur = source->segments[ id*2 + 0 ]; - sys->end = source->segments[ id*2 + 1 ]; - sys->ch = source->ch; - sys->source_mode = source->source_mode; - - /* for diagnostics */ - sys->clip_start = sys->cur; - sys->clip_end = sys->end; - sys->buffer_length = source->segments[ (source->numsegments-1)*2 + 1 ]; - sys->is_playing = 1; - - audio_player_push( sys ); + audio_clip_load( &arr[i], lin_alloc ); } -#endif - /* Mark change to be uploaded through queue system */ -static void audio_player_commit( audio_player *sys ) +VG_STATIC void audio_player_commit( audio_player *sys ) { audio_require_lock(); @@ -795,7 +844,7 @@ static void audio_player_commit( audio_player *sys ) if( sys->enqued ) { - vg_warn( "Audio commit spamming; already enqued (%s)\n", sys->name ); + vg_warn( "[2] Audio commit spamming; already enqued (%s)\n", sys->name ); return; } @@ -803,22 +852,81 @@ static void audio_player_commit( audio_player *sys ) audio_entity *ent = &vg_audio.entity_queue[ vg_audio.queue_len ++ ]; ent->info = sys->info; ent->player = sys; - sys->active_entity = AATREE_PTR_NIL; +} + +VG_STATIC void audio_require_init( audio_player *player ) +{ + if( player->init ) + return; + + vg_fatal_exit_loop( "Must init audio player before playing! \n" ); +} + +VG_STATIC void audio_require_clip_loaded( audio_clip *clip ) +{ + if( clip->data && clip->size ) + return; + + vg_fatal_exit_loop( "Must load audio clip before playing! \n" ); } /* 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 ); } -static void audio_player_playoneshot( audio_player *player, audio_clip *clip ) +#if 0 +VG_STATIC void audio_player_playoneshot( audio_player *player, audio_clip *clip ) { - + audio_require_lock(); + audio_require_init( player ); +} +#endif + +VG_STATIC void audio_play_oneshot( audio_clip *clip, float volume ) +{ + audio_require_lock(); + audio_require_clip_loaded( clip ); + + if( vg_audio.queue_len >= vg_list_size( vg_audio.entity_queue ) ) + { + vg_warn( "Audio commit queue full\n" ); + return; + } + + audio_entity *ent = &vg_audio.entity_queue[ vg_audio.queue_len ++ ]; + + ent->info.flags = AUDIO_FLAG_ONESHOT; + ent->info.pan = 0.0f; + ent->info.source = clip; + ent->info.vol = volume; + ent->player = NULL; +} + +VG_STATIC void audio_player_init( audio_player *player ) +{ + player->active_entity = AATREE_PTR_NIL; + player->init = 1; } /* @@ -829,43 +937,53 @@ static void audio_player_playoneshot( audio_player *player, audio_clip *clip ) * Safety enforced Get/set attributes */ -static void audio_player_set_position( audio_player *sys, v3f pos ) +VG_STATIC int audio_player_is_playing( audio_player *sys ) +{ + audio_require_lock(); + + if( sys->active_entity != AATREE_PTR_NIL ) + return 1; + else + return 0; +} + +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; @@ -876,7 +994,7 @@ static u32 audio_player_get_flags( audio_player *sys ) * Debugging */ -static void audio_debug_ui(void) +VG_STATIC void audio_debug_ui( m4x4f mtx_pv ) { if( !vg_audio.debug_ui ) return; @@ -886,13 +1004,12 @@ static void audio_debug_ui(void) { const char *name; u32 cursor, flags, length; + v3f pos; float vol; } infos[ SFX_MAX_SYSTEMS ]; int num_systems = 0; - char perf[128]; - audio_lock(); for( int i=0; iflags = ent->info.flags; snd->length = ent->length; snd->vol = ent->info.vol*100.0f; + v3_copy( ent->info.world_position, snd->pos ); } - strcpy( perf, vg_audio.performance_info ); + + float budget = ((double)vg_audio.samples_last / 44100.0) * 1000.0; + vg_profile_drawn( (struct vg_profile *[]){ &vg_prof_audio_decode, + &vg_prof_audio_mix }, 2, + budget, (ui_rect){ 4, VG_PROFILE_SAMPLE_COUNT*2 + 8, + 250, 0 }, 3 ); + audio_unlock(); + char perf[128]; + /* Draw UI */ - ui_global_ctx.cursor[0] = 10; - ui_global_ctx.cursor[1] = 10; - ui_global_ctx.cursor[2] = 150; - ui_global_ctx.cursor[3] = 12; - ui_text( &ui_global_ctx, ui_global_ctx.cursor, perf, 1, 0 ); + 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_global_ctx.cursor[1] += 20; - ui_text( &ui_global_ctx, ui_global_ctx.cursor, perf, 1, 0 ); + ui_text( vg_uictx.cursor, perf, 1, 0 ); + vg_uictx.cursor[1] += 20; - ui_global_ctx.cursor[1] += 20; + ui_rect overlap_buffer[ SFX_MAX_SYSTEMS ]; + u32 overlap_length = 0; /* 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 ) + { + v4f wpos; + v3_copy( inf->pos, wpos ); + wpos[3] = 1.0f; + m4x4_mulv( mtx_pv, wpos, wpos ); + + if( wpos[3] < 0.0f ) + goto projected_behind; + + v2_muls( wpos, (1.0f/wpos[3]) * 0.5f, wpos ); + v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos ); + + ui_rect wr; + wr[0] = wpos[0] * vg.window_x; + wr[1] = (1.0f-wpos[1]) * vg.window_y; + wr[2] = 100; + wr[3] = 17; + + for( int j=0; j<12; j++ ) + { + int collide = 0; + for( int k=0; k= wk[0])) && + ((wr[1] <= wk[1]+wk[3]) && (wr[1]+wr[3] >= wk[1])) ) + { + collide = 1; + break; + } + } + + if( !collide ) + break; + else + wr[1] += 18; + } + + ui_text( wr, perf, 1, 0 ); + + ui_rect_copy( wr, overlap_buffer[ overlap_length ++ ] ); + } } - ui_end_down( &ui_global_ctx ); - ui_global_ctx.cursor[1] += 1; +projected_behind: + + ui_end_down(); + vg_uictx.cursor[1] += 1; } }