253 lines
5.1 KiB
C++
253 lines
5.1 KiB
C++
|
|
#include "sl.h"
|
|
|
|
char *__slPendingError = NULL ;
|
|
|
|
slScheduler *slScheduler::current = NULL ;
|
|
|
|
void slScheduler::init ()
|
|
{
|
|
current = this ;
|
|
|
|
if ( not_working () )
|
|
{
|
|
fprintf ( stderr, "slScheduler: soundcard init failed.\n" ) ;
|
|
setError () ;
|
|
return ;
|
|
}
|
|
|
|
if ( getBps() != 8 )
|
|
{
|
|
fprintf ( stderr, "slScheduler: Needs a sound card that supports 8 bits per sample.\n" ) ;
|
|
setError () ;
|
|
return ;
|
|
}
|
|
|
|
if ( getStereo() )
|
|
{
|
|
fprintf ( stderr, "slScheduler: Needs a sound card that supports monophonic replay.\n" ) ;
|
|
setError () ;
|
|
return ;
|
|
}
|
|
|
|
for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
|
|
samplePlayer [ i ] = NULL ;
|
|
|
|
amount_left = 0 ;
|
|
now = 0 ;
|
|
num_pending_callbacks = 0 ;
|
|
safety_margin = 1.0 ;
|
|
|
|
mixer = NULL ;
|
|
|
|
mixer_buffer = NULL ;
|
|
spare_buffer0 = NULL ;
|
|
spare_buffer1 = NULL ;
|
|
spare_buffer2 = NULL ;
|
|
|
|
initBuffers () ;
|
|
}
|
|
|
|
void slScheduler::initBuffers ()
|
|
{
|
|
if ( not_working () )
|
|
return ;
|
|
|
|
delete mixer_buffer ;
|
|
delete spare_buffer0 ;
|
|
delete spare_buffer1 ;
|
|
delete spare_buffer2 ;
|
|
|
|
mixer_buffer_size = getDriverBufferSize () ;
|
|
|
|
mixer_buffer = new Uchar [ mixer_buffer_size ] ;
|
|
memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
|
|
|
|
spare_buffer0 = new Uchar [ mixer_buffer_size ] ;
|
|
spare_buffer1 = new Uchar [ mixer_buffer_size ] ;
|
|
spare_buffer2 = new Uchar [ mixer_buffer_size ] ;
|
|
}
|
|
|
|
slScheduler::~slScheduler ()
|
|
{
|
|
if ( current == this )
|
|
current = NULL ;
|
|
|
|
delete mixer_buffer ;
|
|
|
|
delete spare_buffer0 ;
|
|
delete spare_buffer1 ;
|
|
delete spare_buffer2 ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb )
|
|
{
|
|
register int l = mixer_buffer_size ;
|
|
register Uchar *d = mixer_buffer ;
|
|
|
|
register Uchar *a = spare_buffer0 ;
|
|
register Uchar *b = spare_buffer1 ;
|
|
|
|
spa -> read ( l, a ) ;
|
|
spb -> read ( l, b ) ;
|
|
|
|
while ( l-- ) *d++ = mix ( *a++, *b++ ) ;
|
|
}
|
|
|
|
|
|
|
|
void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb,
|
|
slSamplePlayer *spc )
|
|
{
|
|
register int l = mixer_buffer_size ;
|
|
register Uchar *d = mixer_buffer ;
|
|
|
|
register Uchar *a = spare_buffer0 ;
|
|
register Uchar *b = spare_buffer1 ;
|
|
register Uchar *c = spare_buffer2 ;
|
|
|
|
spa -> read ( l, a ) ;
|
|
spb -> read ( l, b ) ;
|
|
spc -> read ( l, c ) ;
|
|
|
|
while ( l-- ) *d++ = mix ( *a++, *b++, *c++ ) ;
|
|
}
|
|
|
|
|
|
void slScheduler::realUpdate ( int dump_first )
|
|
{
|
|
if ( not_working () )
|
|
return ;
|
|
|
|
if ( __slPendingError != NULL )
|
|
{
|
|
fprintf ( stderr, "%s", __slPendingError ) ;
|
|
exit ( 1 ) ;
|
|
}
|
|
|
|
int i ;
|
|
|
|
while ( secondsUsed() <= safety_margin )
|
|
{
|
|
slSamplePlayer *psp [ 3 ] ;
|
|
int pri [ 3 ] ;
|
|
|
|
pri [ 0 ] = pri [ 1 ] = pri [ 2 ] = -1 ;
|
|
|
|
for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
|
|
{
|
|
if ( samplePlayer [ i ] == NULL )
|
|
continue ;
|
|
|
|
/* Clean up dead sample players */
|
|
|
|
if ( samplePlayer [ i ] -> isDone () )
|
|
{
|
|
delete samplePlayer [ i ] ;
|
|
samplePlayer [ i ] = NULL ;
|
|
continue ;
|
|
}
|
|
|
|
if ( samplePlayer [ i ] -> isPaused () )
|
|
continue ;
|
|
|
|
int lowest = ( pri [0] <= pri [2] ) ?
|
|
(( pri [0] <= pri [1] ) ? 0 : 1 ) :
|
|
(( pri [1] <= pri [2] ) ? 1 : 2 ) ;
|
|
|
|
if ( samplePlayer[i]->getPriority() > pri[lowest] )
|
|
{
|
|
psp[lowest] = samplePlayer[i] ;
|
|
pri[lowest] = samplePlayer[i]->getPriority() ;
|
|
}
|
|
}
|
|
|
|
for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
|
|
{
|
|
if ( samplePlayer [ i ] == NULL )
|
|
continue ;
|
|
|
|
if ( ! samplePlayer [ i ] -> isPaused () &&
|
|
samplePlayer [ i ] != psp[0] &&
|
|
samplePlayer [ i ] != psp[1] &&
|
|
samplePlayer [ i ] != psp[2] )
|
|
{
|
|
samplePlayer [ i ] -> preempt ( mixer_buffer_size ) ;
|
|
}
|
|
}
|
|
|
|
if ( pri[0] < 0 )
|
|
{
|
|
memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
|
|
amount_left = 0 ;
|
|
}
|
|
else
|
|
if ( pri[1] < 0 )
|
|
psp[0] -> read ( mixer_buffer_size, mixer_buffer ) ;
|
|
else
|
|
if ( pri[2] < 0 )
|
|
mixBuffer ( psp[0], psp[1] ) ;
|
|
else
|
|
mixBuffer ( psp[0], psp[1], psp[2] ) ;
|
|
|
|
if ( dump_first )
|
|
{
|
|
stop () ;
|
|
dump_first = SL_FALSE ;
|
|
}
|
|
|
|
play ( mixer_buffer, mixer_buffer_size ) ;
|
|
|
|
now += mixer_buffer_size ;
|
|
}
|
|
|
|
flushCallBacks () ;
|
|
}
|
|
|
|
void slScheduler::addCallBack ( slCallBack c, slSample *s, slEvent e, int m )
|
|
{
|
|
if ( not_working () )
|
|
return ;
|
|
|
|
if ( num_pending_callbacks >= SL_MAX_CALLBACKS )
|
|
{
|
|
fprintf ( stderr, "slScheduler: Too many pending callback events!\n" ) ;
|
|
return ;
|
|
}
|
|
|
|
slPendingCallBack *p = & ( pending_callback [ num_pending_callbacks++ ] ) ;
|
|
|
|
p -> callback = c ;
|
|
p -> sample = s ;
|
|
p -> event = e ;
|
|
p -> magic = m ;
|
|
}
|
|
|
|
void slScheduler::flushCallBacks ()
|
|
{
|
|
if ( not_working () )
|
|
return ;
|
|
|
|
/*
|
|
Execute all the callbacks that we accumulated
|
|
in this iteration.
|
|
|
|
This is done at the end of 'update' to reduce the risk
|
|
of nasty side-effects caused by 'unusual' activities
|
|
in the application's callback function.
|
|
*/
|
|
|
|
while ( num_pending_callbacks > 0 )
|
|
{
|
|
slPendingCallBack *p = & ( pending_callback [ --num_pending_callbacks ] ) ;
|
|
|
|
if ( p -> callback )
|
|
(*(p->callback))( p->sample, p->event, p->magic ) ;
|
|
}
|
|
}
|
|
|
|
|