audio pt. 2
authorhgn <hgodden00@gmail.com>
Wed, 28 Sep 2022 00:33:37 +0000 (01:33 +0100)
committerhgn <hgodden00@gmail.com>
Wed, 28 Sep 2022 00:33:37 +0000 (01:33 +0100)
src/vg/vg.h
src/vg/vg_audio.h
src/vg/vg_platform.h

index fc6e0afda1d970ada7f555292295b4bd95ec5685..25771ff8d142fc9ff7b180a0048172691feb78d3 100644 (file)
@@ -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();
          
index bb4d0920feb889361506d16db83393fefd861138..2171359eda030edc572e0e1d5fafdd0af589d1d8 100644 (file)
@@ -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; i<num_systems; i ++ )
        {
       struct sound_info *inf = &infos[i];
 
-               ui_global_ctx.cursor[2] = 150;
-               ui_global_ctx.cursor[3] = 12;
+               ui_global_ctx.cursor[2] = 200;
+               ui_global_ctx.cursor[3] = 18;
                
                u32 alpha = 0xa0000000;
 
@@ -946,7 +1023,7 @@ static void audio_debug_ui(void)
                        ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x00333333|alpha );
 
                        ui_px baseline = ui_global_ctx.cursor[0],
-               w  = 150,
+               w  = 200,
                c  = baseline + ((float)inf->cursor / (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<overlap_length; k++ )
+               {
+                  ui_px *wk = overlap_buffer[k];
+                  if( ((wr[0] <= wk[0]+wk[2]) && (wr[0]+wr[2] >= 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;
        }
index ca8b55a88cb3ff58bcd8b63e6a19394d2e08b3a6..be9a225bf8fc56f97d3481f7f1a5bf5f39ff529a 100644 (file)
@@ -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