From: hgn Date: Wed, 28 Sep 2022 00:33:37 +0000 (+0100) Subject: audio pt. 2 X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=commitdiff_plain;h=143eccd9c2df0970a7bdd08d27fe4b5e6194cafb audio pt. 2 --- diff --git a/src/vg/vg.h b/src/vg/vg.h index fc6e0af..25771ff 100644 --- a/src/vg/vg.h +++ b/src/vg/vg.h @@ -280,7 +280,7 @@ static void vg_init( int argc, char *argv[], const char *window_name ) ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], vg_get_button_state( "primary" ) ); - audio_debug_ui(); + audio_debug_ui( vg_pv ); vg_ui(); vg_console_draw(); diff --git a/src/vg/vg_audio.h b/src/vg/vg_audio.h index bb4d092..2171359 100644 --- a/src/vg/vg_audio.h +++ b/src/vg/vg_audio.h @@ -26,7 +26,7 @@ #define AUDIO_FLAG_ONESHOT 0x2 #define AUDIO_FLAG_SPACIAL_3D 0x4 -#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 +34,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; @@ -65,7 +64,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; @@ -128,11 +127,19 @@ static struct vg_audio_system audio_entity entity_queue[SFX_MAX_SYSTEMS]; int queue_len; - char performance_info[128]; + char performance_info[128], + performance_sub0[64], + performance_sub1[64]; + int debug_ui; v3f listener_pos, listener_ears; + + double perf_ms_decode, + perf_ms_mix; + + u32 perf_measurements; } vg_audio; @@ -229,6 +236,7 @@ static int vg_audio_init(void) dconf->playback.channels = 2; dconf->sampleRate = 44100; dconf->dataCallback = audio_mixer_callback; + dconf->periodSizeInFrames = 441; dconf->pUserData = NULL; @@ -309,7 +317,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 +331,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 ]; @@ -387,7 +394,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; } @@ -475,8 +482,47 @@ static void audio_decode_uncompressed_mono( float *src, u32 count, float *dst ) } } +/* + * adapted from stb_vorbis.h, since the original does not handle mono->stereo + */ +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; +} + static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) { + struct timespec time_start, time_end; + clock_gettime( CLOCK_REALTIME, &time_start ); + struct active_audio_player *aap = &vg_audio.active_players[id]; audio_entity *ent = &aap->ent; @@ -490,19 +536,20 @@ 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 ]; 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 +562,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,6 +584,9 @@ static void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf ) } ent->cur = cursor; + + clock_gettime( CLOCK_REALTIME, &time_end ); + vg_audio.perf_ms_decode += vg_time_diff( time_start, time_end ); } static void audio_entity_mix( aatree_ptr id, float *buffer, @@ -556,6 +605,9 @@ static void audio_entity_mix( aatree_ptr id, float *buffer, audio_entity_get_samples( id, frame_count, pcf ); + struct timespec time_start, time_end; + clock_gettime( CLOCK_REALTIME, &time_start ); + if( ent->info.flags & AUDIO_FLAG_SPACIAL_3D ) audio_entity_spacialize( ent, &vol, &pan ); @@ -585,15 +637,9 @@ 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 ); + clock_gettime( CLOCK_REALTIME, &time_end ); + vg_audio.perf_ms_mix += vg_time_diff( time_start, time_end ); } /* @@ -636,14 +682,28 @@ static void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, */ 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), + double elapsed = vg_time_diff( time_start, time_end ), budget = ((double)frame_count / 44100.0) * 1000.0, percent = (elapsed/budget) * 100.0; snprintf( vg_audio.performance_info, 127, - "%.1fms/%.1fms (%.1f%%) (%u frames)", + "%.2fms/%.2fms (%.1f%%) (%u frames)", elapsed, budget, percent, frame_count ); + + vg_audio.perf_measurements ++; + if( vg_audio.perf_measurements >= 30 ) + { + double ms_decode = vg_audio.perf_ms_decode * (1.0/30.0), + ms_mix = vg_audio.perf_ms_mix * (1.0/30.0); + + snprintf( vg_audio.performance_sub0, 63, "Decode %.2fms", ms_decode ); + snprintf( vg_audio.performance_sub1, 63, "mix %.2fms", ms_mix ); + + vg_audio.perf_ms_decode = 0.0; + vg_audio.perf_ms_mix = 0.0; + + vg_audio.perf_measurements = 0; + } } /* Decompress entire vorbis stream into buffer */ @@ -713,7 +773,7 @@ static int audio_clip_load( audio_clip *clip ) vg_info( "Loaded audio clip[mono] '%s' (%.1fs, %.1fmb)\n", clip->path, seconds, mb ); } - else if( clip->source_mode == k_audio_source_mono_compressed ) + else if( clip->source_mode == k_audio_source_compressed ) { void *data = audio_alloc( file_len ); memcpy( data, filedata, file_len ); @@ -722,19 +782,9 @@ static int audio_clip_load( audio_clip *clip ) clip->len = file_len; float mb = (float)(file_len) / (1024.0f*1024.0f); - vg_info( "Loaded audio clip[mono_compressed] '%s' (%.1fmb)\n", + vg_info( "Loaded audio clip[compressed] '%s' (%.1fmb)\n", clip->path, mb ); } - else if( clip->source_mode == k_audio_source_stereo_compressed ) - { - /* ... */ - - clip->data = NULL; - clip->len = 0; - - vg_error( "Source mode (%u) currently unsupported\n", clip->source_mode ); - return 0; - } else { /* ... */ @@ -755,33 +805,6 @@ static void audio_clip_loadn( audio_clip *arr, int count ) audio_clip_load( &arr[i] ); } -#if 0 -/* - * Client code - */ -static void audio_pack_play( audio_pack *source, audio_player *sys, int id ) -{ - audio_require_lock(); - - sys->fadeout = 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 ); -} - -#endif - /* Mark change to be uploaded through queue system */ static void audio_player_commit( audio_player *sys ) { @@ -803,7 +826,16 @@ 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; +} + +static void audio_require_init( audio_player *player ) +{ + if( player->init ) + return; + + char err[128]; + snprintf( err, 127, "Must init before playing! (%s)\n", player->name ); + vg_exiterr( err ); } /* Play a clip using player. If its already playing something, it will @@ -811,14 +843,43 @@ static void audio_player_commit( audio_player *sys ) static void audio_player_playclip( audio_player *player, audio_clip *clip ) { audio_require_lock(); + audio_require_init( player ); player->info.source = clip; audio_player_commit( player ); } +#if 0 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 ) +{ + audio_require_lock(); + + 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; +} + +static void audio_player_init( audio_player *player ) +{ + player->active_entity = AATREE_PTR_NIL; + player->init = 1; } /* @@ -876,7 +937,7 @@ static u32 audio_player_get_flags( audio_player *sys ) * Debugging */ -static void audio_debug_ui(void) +static void audio_debug_ui( m4x4f mtx_pv ) { if( !vg_audio.debug_ui ) return; @@ -886,12 +947,15 @@ 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]; + char perf[128], + psub0[64], + psub1[64]; audio_lock(); @@ -910,8 +974,12 @@ static void audio_debug_ui(void) snd->flags = 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 ); + strcpy( psub0, vg_audio.performance_sub0 ); + strcpy( psub1, vg_audio.performance_sub1 ); + audio_unlock(); /* Draw UI */ @@ -919,25 +987,34 @@ static void audio_debug_ui(void) 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 ); + ui_global_ctx.cursor[1] += 20; + + ui_text( &ui_global_ctx, ui_global_ctx.cursor, psub0, 1, 0 ); + ui_global_ctx.cursor[1] += 20; + + ui_text( &ui_global_ctx, ui_global_ctx.cursor, psub1, 1, 0 ); + ui_global_ctx.cursor[1] += 20; 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; 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_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 */ @@ -958,8 +1035,54 @@ static void audio_debug_ui(void) ui_global_ctx.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 ); + + 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( &ui_global_ctx, wr, perf, 1, 0 ); + + ui_rect_copy( wr, overlap_buffer[ overlap_length ++ ] ); + } } +projected_behind: + ui_end_down( &ui_global_ctx ); ui_global_ctx.cursor[1] += 1; } diff --git a/src/vg/vg_platform.h b/src/vg/vg_platform.h index ca8b55a..be9a225 100644 --- a/src/vg/vg_platform.h +++ b/src/vg/vg_platform.h @@ -102,4 +102,22 @@ int vg_thread_run( void *pfunc, void *data ) #endif } +static void vg_sleep_ms( long msec ) +{ + struct timespec ts; + + ts.tv_sec = msec / 1000; + ts.tv_nsec = (msec % 1000) * 1000000; + nanosleep( &ts, &ts ); +} + +/* diff two timespecs in MS */ +static double vg_time_diff( struct timespec start, struct timespec end ) +{ + double elapsed = 1000.0*end.tv_sec + 1e-6*end.tv_nsec + - (1000.0*start.tv_sec + 1e-6*start.tv_nsec); + + return elapsed; +} + #endif