#define STB_VORBIS_MAX_CHANNELS 2
#include "stb/stb_vorbis.h"
-#define SFX_MAX_SYSTEMS 16
+#define SFX_MAX_SYSTEMS 32
#define SFX_FLAG_ONESHOT 0x1
#define SFX_FLAG_STEREO 0x2
#define SFX_FLAG_REPEAT 0x4
+#define SFX_FLAG_GHOST 0x8
#define FADEOUT_LENGTH 441
#define FADEOUT_DIVISOR (1.f/(float)FADEOUT_LENGTH)
float vol;
// Info
- int ch, end, cur;
+ int ch, end, cur, cur_lagged;
u32 flags;
// Effects
- u32 fadeout, fadeout_length, fadeout_cursor;
+ u32 fadeout, fadeout_current;
sfx_system *thread_clone; // Memory of this structure is copied into thread 2
{
if( sfx_sys_len >= SFX_MAX_SYSTEMS )
{
- vg_error( "Warning: No free space in sound system\n" );
-
return NULL;
}
while( sfx_q_len --> 0 )
{
sfx_system *src = sfx_q[sfx_q_len];
+ sfx_system *clone;
// This is a 'new' sound if thread_clone not set.
if( !src->thread_clone || src->flags & SFX_FLAG_ONESHOT )
{
src->thread_clone = sfx_alloc();
+ if( !src->thread_clone )
+ break;
+ }
+ 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;
}
- // run replacement routine if one is waiting
+ clone = src->thread_clone;
+
+ // run replacement routine if one is waiting (todo: what is this?)
if( src->replacement )
{
free( src->source );
src->source = src->replacement;
src->replacement = NULL;
}
-
- src->thread_clone->source = src->source;
// Localize data to thread 1's memory pool
- src->thread_clone->ch = src->ch;
- src->thread_clone->end = src->end;
- src->thread_clone->cur = src->cur;
- src->thread_clone->flags = src->flags;
- src->thread_clone->fadeout = src->fadeout;
- src->thread_clone->fadeout_length = src->fadeout_length;
- src->thread_clone->vol_src = src->vol_src;
- src->thread_clone->name = src->name;
+ clone->source = src->source;
+ clone->ch = src->ch;
+ clone->end = src->end;
+ clone->cur = src->cur;
+ clone->flags = src->flags;
+ clone->vol_src = src->vol_src;
+ clone->name = src->name;
+ clone->fadeout = src->fadeout;
+ clone->fadeout_current = src->fadeout_current;
// loopback pointer, mainly used for persistent sound handles
- src->thread_clone->thread_clone = src;
+ clone->thread_clone = src;
}
sfx_q_len = 0;
{
sfx_system *sys = sfx_sys + i;
- u32 cursor = sys->cur;
- u32 bpos = 0;
+ u32 cursor = sys->cur, buffer_pos = 0;
float avgvol = 0.f;
float pcf[2] = { 0.f, 0.0f };
- if( sys->fadeout_cursor != sys->cur )
- sys->fadeout = sys->fadeout_length;
-
u32 frames_write = frameCount;
+ float fadeout_divisor = 1.0f / (float)sys->fadeout;
while( frames_write )
{
u32 samples_this_run = vg_min( frames_write, sys->end - cursor );
+ if( sys->fadeout )
+ {
+ // Force this system to be removed
+ if( sys->fadeout_current == 0 )
+ {
+ sys->flags = SFX_FLAG_GHOST;
+ sys->cur = sys->end;
+ break;
+ }
+
+ samples_this_run = vg_min( samples_this_run, sys->fadeout_current );
+ }
+
for( u32 j = 0; j < samples_this_run; j ++ )
{
audio_mixer_getsamples( pcf, sys->source, cursor, sys->ch );
- avgvol += fabs( pcf[0] * sys->vol );
- avgvol += fabs( pcf[1] * sys->vol );
-
- pOut32F[ bpos*2+0 ] += pcf[0] * sys->vol;
- pOut32F[ bpos*2+1 ] += pcf[1] * sys->vol;
-
- // Blend the fadeout cursor in to prevent popping
+ float vol = sys->vol;
+
if( sys->fadeout )
{
- if( sys->fadeout_cursor < sys->end )
- {
- audio_mixer_getsamples( pcf, sys->source, sys->fadeout_cursor, sys->ch );
-
- float mul = (float)sys->fadeout * FADEOUT_DIVISOR;
-
- pOut32F[ bpos*2+0 ] += pcf[0] * sys->vol * mul;
- pOut32F[ bpos*2+1 ] += pcf[1] * sys->vol * mul;
-
- sys->fadeout_cursor ++;
- sys->fadeout --;
- }
- else
- sys->fadeout = 0;
+ vol *= (float)sys->fadeout_current * fadeout_divisor;
+ sys->fadeout_current --;
}
+ 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 );
+
cursor ++;
- bpos ++;
+ buffer_pos ++;
}
frames_write -= samples_this_run;
- if( sys->flags & SFX_FLAG_REPEAT)
+ if( sys->flags & SFX_FLAG_REPEAT )
{
if( frames_write )
{
}
sys->cur = cursor;
- sys->fadeout_cursor = cursor;
- sys->signal_average = avgvol / (float)(bpos*2);
+ sys->cur_lagged = cursor;
+ sys->signal_average = avgvol / (float)(buffer_pos*2);
break;
}
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 ];
sfx_save( sys );
}
+static void sfx_system_fadeout( sfx_system *sys, u32 length_samples )
+{
+ sys->fadeout_current = length_samples;
+ sys->fadeout = length_samples;
+
+ sfx_save( sys );
+}
+
// Free set resources
void sfx_set_free( sfx_set *set )
{