#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 ) ; } }