yabadabadoo
[vg.git] / src / vg / vg_audio.h
index e4513d429a3b02e412de9c0173b2d5e9208827e9..cb6f41c3e99f5d4094d6de3b32e133dbbad71ba2 100644 (file)
 #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)
 
 #define AUDIO_DECODE_SIZE     (1024*256)  /* 256 kb decoding buffers */
 
+enum audio_source_mode
+{
+   k_audio_source_mono,
+   k_audio_source_compressed,
+};
+
 typedef struct audio_clip audio_clip;
 struct audio_clip
 {
    const char *path;
+   enum audio_source_mode source_mode;
+
    void *data;
    u32 size;
 };
@@ -337,33 +346,40 @@ VG_STATIC void audio_entity_start( audio_entity *src )
       src->player->active_entity = entid;
    }
 
-   /* Setup vorbis decoder */
-   struct active_audio_player *aap = &vg_audio.active_players[ entid ];
-   
-   stb_vorbis_alloc alloc = {
-      .alloc_buffer = (char *)audio_entity_vorbis_ptr( entid ),
-      .alloc_buffer_length_in_bytes = AUDIO_DECODE_SIZE
-   };
+   if( src->info.source->source_mode == k_audio_source_compressed )
+   {
+      /* Setup vorbis decoder */
+      struct active_audio_player *aap = &vg_audio.active_players[ entid ];
+      
+      stb_vorbis_alloc alloc = {
+         .alloc_buffer = (char *)audio_entity_vorbis_ptr( entid ),
+         .alloc_buffer_length_in_bytes = AUDIO_DECODE_SIZE
+      };
 
-   int err;
-   stb_vorbis *decoder = stb_vorbis_open_memory( 
-         src->info.source->data,
-         src->info.source->size, &err, &alloc );
+      int err;
+      stb_vorbis *decoder = stb_vorbis_open_memory( 
+            src->info.source->data,
+            src->info.source->size, &err, &alloc );
 
-   if( !decoder )
-   {
-      vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", 
-                  src->info.source->path, err );
+      if( !decoder )
+      {
+         vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", 
+                     src->info.source->path, err );
 
-      audio_entity_free_internal( entid );
-      return;
+         audio_entity_free_internal( entid );
+         return;
+      }
+      else
+      {
+         ent->length = stb_vorbis_stream_length_in_samples( decoder );
+      }
+      
+      aap->vorbis_handle = decoder;
    }
    else
    {
-      ent->length = stb_vorbis_stream_length_in_samples( decoder );
+      ent->length = src->info.source->size;
    }
-   
-   aap->vorbis_handle = decoder;
 }
 
 /*
@@ -422,6 +438,12 @@ VG_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;
+            }
          }
       }
    }
@@ -489,12 +511,12 @@ VG_STATIC void audio_entity_spacialize( audio_entity *ent, float *vol, float *pa
    }
 }
 
-VG_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; i<count; i++ )
    {
-      dst[ i*2 + 0 ] = src[i];
-      dst[ i*2 + 1 ] = src[i];
+      dst[ i*2 + 0 ] = (float)src[i] * (1.0f/32767.0f);
+      dst[ i*2 + 1 ] = (float)src[i] * (1.0f/32767.0f);
    }
 }
 
@@ -534,6 +556,45 @@ stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis *f, float *buffer,
    return n;
 }
 
+/* 
+ * ........ more wrecked code sorry!
+ */
+VG_STATIC int 
+stb_vorbis_get_samples_i16_interleaved_mono( 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 );
@@ -552,14 +613,24 @@ VG_STATIC void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf )
 
       float *dst = &buf[ buffer_pos * 2 ]; 
 
-      int read_samples = stb_vorbis_get_samples_float_interleaved_stereo( 
-            aap->vorbis_handle,
-            dst,
-            samples_this_run  );
-
-      if( read_samples != samples_this_run )
+      int source_mode = ent->info.source->source_mode;
+      
+      if( source_mode == k_audio_source_mono )
+      {
+         i16 *src = &((i16 *)ent->info.source->data)[ cursor ];
+         audio_decode_uncompressed_mono( src, samples_this_run, dst );
+      }
+      else if( source_mode == k_audio_source_compressed )
       {
-         vg_warn( "Invalid samples read (%s)\n", ent->info.source->path );
+         int read_samples = stb_vorbis_get_samples_float_interleaved_stereo( 
+               aap->vorbis_handle,
+               dst,
+               samples_this_run  );
+
+         if( read_samples != samples_this_run )
+         {
+            vg_warn( "Invalid samples read (%s)\n", ent->info.source->path );
+         }
       }
 
       cursor += samples_this_run;
@@ -567,7 +638,11 @@ VG_STATIC void audio_entity_get_samples( aatree_ptr id, u32 count, float *buf )
       
       if( (ent->info.flags & AUDIO_FLAG_LOOP) && remaining )
       {
-         stb_vorbis_seek_start( aap->vorbis_handle );
+         if( source_mode == k_audio_source_compressed )
+         {
+            stb_vorbis_seek_start( aap->vorbis_handle );
+         }
+
          cursor = 0;
          continue;
       }
@@ -686,14 +761,53 @@ VG_STATIC void audio_mixer_callback( ma_device *pDevice, void *pOutBuf,
 
 VG_STATIC void audio_clip_load( audio_clip *clip )
 {
-   clip->data = vg_file_read( vg_audio.audio_pool, clip->path );
-   clip->size = vg_file_size( vg_audio.audio_pool );
+   if( clip->source_mode == k_audio_source_mono )
+   {
+      vg_linear_clear( vg_mem.scratch );
+      u32 fsize;
+      void *filedata = vg_file_read( vg_mem.scratch, clip->path, &fsize );
+
+      stb_vorbis_alloc alloc = {
+         .alloc_buffer = vg_linear_alloc( vg_mem.scratch, AUDIO_DECODE_SIZE ),
+         .alloc_buffer_length_in_bytes = AUDIO_DECODE_SIZE
+      };
+
+      int err;
+      stb_vorbis *decoder = stb_vorbis_open_memory( 
+                            filedata, fsize, &err, &alloc );
+
+      if( !decoder )
+      {
+         vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", 
+                     clip->path, err );
+         vg_fatal_exit_loop( "Vorbis decode error" );
+      }
+
+      /* only mono is supported in uncompressed */
+      u32 length_samples = stb_vorbis_stream_length_in_samples( decoder ),
+          data_size      = length_samples * sizeof(i16);
+
+      clip->data = vg_linear_alloc( vg_audio.audio_pool, data_size );
+      clip->size = length_samples;
 
-   if( !clip->data )
-      vg_fatal_exit_loop( "Audio failed to load" );
+      int read_samples = stb_vorbis_get_samples_i16_interleaved_mono( 
+                              decoder, clip->data, length_samples );
 
-   float mb = (float)(clip->size) / (1024.0f*1024.0f);
-   vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb );
+      float mb = (float)(data_size) / (1024.0f*1024.0f);
+      vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb );
+   }
+
+   /* load in directly */
+   else if( clip->source_mode == k_audio_source_compressed )
+   {
+      clip->data = vg_file_read( vg_audio.audio_pool, clip->path, &clip->size );
+
+      if( !clip->data )
+         vg_fatal_exit_loop( "Audio failed to load" );
+
+      float mb = (float)(clip->size) / (1024.0f*1024.0f);
+      vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb );
+   }
 }
 
 VG_STATIC void audio_clip_loadn( audio_clip *arr, int count )
@@ -749,6 +863,12 @@ VG_STATIC void audio_player_playclip( audio_player *player, audio_clip *clip )
    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;
+   }
+
    player->info.source = clip;
    audio_player_commit( player );
 }