fixed REALLY bad threading bugs with audio
[fishladder.git] / vg / vg_audio.h
index 35b36c5f07a13aac6395a83200b4008bc1f3e6a0..249bedc8f390452ba9a98adab4d6cbaecee7d535 100644 (file)
@@ -11,7 +11,7 @@
 #define SFX_FLAG_STEREO                0x2
 #define SFX_FLAG_REPEAT        0x4
 #define SFX_FLAG_GHOST         0x8
-#define FADEOUT_LENGTH                 441
+#define FADEOUT_LENGTH                 4410
 #define FADEOUT_DIVISOR        (1.f/(float)FADEOUT_LENGTH)
 
 typedef struct sfx_vol_control sfx_vol_control;
@@ -33,9 +33,11 @@ struct sfx_system
        float   vol;
        
        // Info
-       int ch, end, cur, cur_lagged;
+       u32 ch, end, cur;
        u32 flags;
        
+       int is_queued;
+       
        // Effects
        u32 fadeout, fadeout_current;
        
@@ -183,6 +185,7 @@ struct sfx_vorbis_a_to_inf
 #define SFX_A_FLAG_AUTOSTART 0x1
 #define SFX_A_FLAG_AUTOFREE  0x2
 
+/*
 static int sfx_save( sfx_system *sys );
 
 // Asynchronous load-to-system callback
@@ -217,16 +220,30 @@ void sfx_vorbis_a_to( sfx_system *sys, const char *strFileName, int channels, u3
        
        if( !sfx_vorbis_a( strFileName, channels, sfx_vorbis_a_to_c, inf ) )
                free( inf );
-}
+}*/
 
 // 0
 // ======================================================
 
-// Mark change to be uploaded to queue system
-static int sfx_save( sfx_system *sys )
+static int sfx_begin_edit( sfx_system *sys )
 {
        MUTEX_LOCK( sfx_mux_t01 );
+       
+       if( sys->is_queued )
+       {
+               MUTEX_UNLOCK( sfx_mux_t01 );
+               
+               vg_warn( "Sfx system locked for writing.. Spam is being created!\n" );
+               return 0;
+       }
+       
+       sys->is_queued = 1;
+       return 1;
+}
 
+// Mark change to be uploaded to queue system
+static int sfx_save( sfx_system *sys )
+{
        if( sfx_q_len >= SFX_MAX_SYSTEMS )
        {
                vg_error( "Warning: No free space in sound queue\n" );
@@ -366,36 +383,43 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
        while( sfx_q_len --> 0 )
        {
                sfx_system *src = sfx_q[sfx_q_len];
+               src->is_queued = 0;
+               
                sfx_system *clone;
                
                // This is a 'new' sound if thread_clone not set.
-               if( !src->thread_clone || src->flags & SFX_FLAG_ONESHOT )
+               if( !src->thread_clone || (src->flags & SFX_FLAG_ONESHOT) )
                {
-                       src->thread_clone = sfx_alloc();
-                       if( !src->thread_clone )
+                       clone = sfx_alloc();
+                       if( !clone )
                                break;
+                               
+                       src->thread_clone = clone;
                }
                else
                {
-                       // Modifying an active system spawns a small fadeout ghost system
-                       sfx_system *ghost_system = sfx_alloc();
-                       
-                       if( !ghost_system )
-                               break;
-                       
-                       ghost_system->source = src->source;
-                       ghost_system->ch = src->ch;
-                       ghost_system->end = src->end;
-                       ghost_system->cur = src->cur_lagged;
-                       ghost_system->flags = SFX_FLAG_GHOST;
-                       ghost_system->fadeout = FADEOUT_LENGTH;
-                       ghost_system->fadeout_current = FADEOUT_LENGTH;
-                       ghost_system->vol_src = src->vol_src;
-                       ghost_system->name = src->name;
-                       ghost_system->thread_clone = src;
-               }
+                       clone = src->thread_clone;
                
-               clone = src->thread_clone;
+                       // Modifying an active system's cursor spawns a small fadeout ghost system
+                       if( clone->cur != src->cur )
+                       {
+                               sfx_system *ghost_system = sfx_alloc();
+                               
+                               if( !ghost_system )
+                                       break;
+                               
+                               ghost_system->source = clone->source;
+                               ghost_system->ch = clone->ch;
+                               ghost_system->end = clone->end;
+                               ghost_system->cur = clone->cur;
+                               ghost_system->flags = SFX_FLAG_GHOST;
+                               ghost_system->fadeout = FADEOUT_LENGTH;
+                               ghost_system->fadeout_current = FADEOUT_LENGTH;
+                               ghost_system->vol_src = clone->vol_src;
+                               ghost_system->name = clone->name;
+                               ghost_system->thread_clone = src;
+                       }
+               }               
                
                // run replacement routine if one is waiting (todo: what is this?)
                if( src->replacement )
@@ -446,8 +470,7 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
        {
                sfx_system *sys = sfx_sys + i;
                
-               u32 cursor = sys->cur, buffer_pos = 0;
-               
+               u32 cursor = sys->cur, buffer_pos = 0;          
                float avgvol = 0.f;
                float pcf[2] = { 0.f, 0.0f };
                
@@ -456,7 +479,7 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
                
                while( frames_write )
                {
-                       u32 samples_this_run = vg_min( frames_write, sys->end - cursor );
+                       u32 samples_this_run = VG_MIN( frames_write, sys->end - cursor );
                
                        if( sys->fadeout )
                        {
@@ -468,7 +491,7 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
                                        break;
                                }
                                
-                               samples_this_run = vg_min( samples_this_run, sys->fadeout_current );
+                               samples_this_run = VG_MIN( samples_this_run, sys->fadeout_current );
                        }
                        
                        for( u32 j = 0; j < samples_this_run; j ++ )
@@ -482,10 +505,15 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
                                        vol *= (float)sys->fadeout_current * fadeout_divisor;
                                        sys->fadeout_current --;
                                }
+                               
+                               if( buffer_pos >= frameCount )
+                               {
+                                       break;
+                               }
 
                                pOut32F[ buffer_pos*2+0 ] += pcf[0] * vol;
                                pOut32F[ buffer_pos*2+1 ] += pcf[1] * vol;
-                                                               
+                               
                                avgvol += fabs( pcf[0] * vol );
                                avgvol += fabs( pcf[1] * vol );
                                
@@ -505,7 +533,6 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
                        }
 
                        sys->cur = cursor;
-                       sys->cur_lagged = cursor;
                        sys->signal_average = avgvol / (float)(buffer_pos*2);
                        
                        break;
@@ -514,25 +541,27 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput
 
        // Redistribute sound systems
        MUTEX_LOCK( sfx_mux_t01 );
-       
-       unsigned int idx = 0, wr = 0;
+
+       u32 idx = 0, wr = 0;
        while( idx != sfx_sys_len )
        {
                sfx_system *src = sfx_sys + idx;
-       
+               
                // Keep only if cursor is before end or repeating
                if( src->cur < src->end || (src->flags & SFX_FLAG_REPEAT) ) 
                {
                        // Correct source pointer on persisitent originals since we shifted ID's
-                       if( !(src->flags & SFX_FLAG_ONESHOT) )
+                       if( !(src->flags & (SFX_FLAG_ONESHOT|SFX_FLAG_GHOST)) )
+                       {
                                src->thread_clone->thread_clone = sfx_sys + wr;
+                       }
                        
                        sfx_sys[ wr ++ ] = sfx_sys[ idx ];
                }
                else
                {
                        // Clear link on persistent sources (done playing)
-                       if( !(src->flags & SFX_FLAG_ONESHOT) )
+                       if( !(src->flags & (SFX_FLAG_ONESHOT|SFX_FLAG_GHOST)) )
                                src->thread_clone->thread_clone = NULL;
                }
                
@@ -616,21 +645,30 @@ static void sfx_set_playrnd( sfx_set *source, sfx_system *sys, int min_id, int m
 
        int pick = (rand() % (max_id-min_id)) + min_id;
 
-       sys->fadeout = 0;
-       sys->source = source->main;
-       sys->cur        = source->segments[ pick*2 + 0 ];
-       sys->end        = source->segments[ pick*2 + 1 ];
-       sys->ch                 = source->ch;
-       
-       sfx_save( sys );
+       if( sfx_begin_edit( sys ) )
+       {
+               sys->fadeout = 0;
+               sys->source = source->main;
+               sys->cur        = source->segments[ pick*2 + 0 ];
+               sys->end        = source->segments[ pick*2 + 1 ];
+               sys->ch                 = source->ch;
+               
+               sfx_save( sys );
+       }
 }
 
 static void sfx_system_fadeout( sfx_system *sys, u32 length_samples )
 {
-       sys->fadeout_current = length_samples;
-       sys->fadeout = length_samples;
+       if( sfx_begin_edit( sys ) )
+       {
+               sys->fadeout_current = length_samples;
+               sys->fadeout = length_samples;
+               
+               if( sys->thread_clone )
+                       sys->cur = sys->thread_clone->cur;
        
-       sfx_save( sys );
+               sfx_save( sys );
+       }
 }
 
 // Free set resources