]> git.mxchange.org Git - simgear.git/blob - src/slScheduler.cxx
Incorporated Steve's latest version of his audio library. This version
[simgear.git] / src / slScheduler.cxx
1
2 #include "sl.h"
3
4 slScheduler *slScheduler::current = NULL ;
5
6 void slScheduler::init ()
7 {
8   current = this ;
9
10   if ( not_working () )
11   {
12     fprintf ( stderr, "slScheduler: soundcard init failed.\n" ) ;
13     setError () ;
14     return ;
15   }
16
17   if ( getBps() != 8 )
18   {
19     fprintf ( stderr, "slScheduler: Needs a sound card that supports 8 bits per sample.\n" ) ;
20     setError () ;
21     return ;
22   }
23
24   if ( getStereo() )
25   {
26     fprintf ( stderr, "slScheduler: Needs a sound card that supports monophonic replay.\n" ) ;
27     setError () ;
28     return ;
29   }
30
31   for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
32     samplePlayer [ i ] = NULL ;
33
34   amount_left = 0 ;
35   now = 0 ;
36   num_pending_callbacks = 0 ;
37   safety_margin = 1.0 ;
38
39   mixer = NULL ;
40
41   mixer_buffer  = NULL ;
42   spare_buffer0 = NULL ;
43   spare_buffer1 = NULL ;
44   spare_buffer2 = NULL ;
45
46   initBuffers () ;
47 }
48
49 void slScheduler::initBuffers ()
50 {
51   if ( not_working () ) return ;
52
53   delete mixer_buffer ;
54   delete spare_buffer0 ;
55   delete spare_buffer1 ;
56   delete spare_buffer2 ;
57
58   mixer_buffer_size = getDriverBufferSize () ;
59
60   mixer_buffer = new Uchar [ mixer_buffer_size ] ;
61   memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
62
63   spare_buffer0 = new Uchar [ mixer_buffer_size ] ;
64   spare_buffer1 = new Uchar [ mixer_buffer_size ] ;
65   spare_buffer2 = new Uchar [ mixer_buffer_size ] ;
66 }
67
68 slScheduler::~slScheduler ()
69 {
70   if ( current == this )
71     current = NULL ;
72
73   delete mixer_buffer ;
74
75   delete spare_buffer0 ;
76   delete spare_buffer1 ;
77   delete spare_buffer2 ;
78 }
79
80
81
82
83
84 void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb )
85 {
86   register int    l = mixer_buffer_size ;
87   register Uchar *d = mixer_buffer ;
88
89   register Uchar *a = spare_buffer0 ;
90   register Uchar *b = spare_buffer1 ;
91
92   spa -> read ( l, a ) ;
93   spb -> read ( l, b ) ;
94
95   while ( l-- ) *d++ = mix ( *a++, *b++ ) ;
96 }
97
98
99
100 void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb,
101                               slSamplePlayer *spc )
102 {
103   register int    l = mixer_buffer_size ;
104   register Uchar *d = mixer_buffer ;
105
106   register Uchar *a = spare_buffer0 ;
107   register Uchar *b = spare_buffer1 ;
108   register Uchar *c = spare_buffer2 ;
109
110   spa -> read ( l, a ) ;
111   spb -> read ( l, b ) ;
112   spc -> read ( l, c ) ;
113
114   while ( l-- ) *d++ = mix ( *a++, *b++, *c++ ) ;
115 }
116
117
118 void slScheduler::realUpdate ( int dump_first )
119 {
120   int i ;
121
122   if ( not_working () )
123     return ;
124
125   while ( secondsUsed() <= safety_margin )
126   {
127     slSamplePlayer *psp [ 3 ] ;
128     int             pri [ 3 ] ;
129
130     pri [ 0 ] = pri [ 1 ] = pri [ 2 ] =  -1  ;
131
132     for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
133     {
134       if ( samplePlayer [ i ] == NULL )
135         continue ;
136
137       /* Clean up dead sample players */
138
139       if ( samplePlayer [ i ] -> isDone () )
140       {
141         delete samplePlayer [ i ] ;
142         samplePlayer [ i ] = NULL ;
143         continue ;
144       }
145
146       if ( samplePlayer [ i ] -> isPaused () )
147         continue ;
148
149       int lowest = ( pri [0] <= pri [2] ) ?
150                      (( pri [0] <= pri [1] ) ? 0 : 1 ) :
151                      (( pri [1] <= pri [2] ) ? 1 : 2 ) ;
152
153       if ( samplePlayer[i]->getPriority() > pri[lowest] )
154       {
155         psp[lowest] = samplePlayer[i] ;
156         pri[lowest] = samplePlayer[i]->getPriority() ;
157       }
158     }
159
160     for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
161     {
162       if ( samplePlayer [ i ] == NULL )
163         continue ;
164
165       if ( ! samplePlayer [ i ] -> isPaused () &&
166            samplePlayer [ i ] != psp[0] &&
167            samplePlayer [ i ] != psp[1] &&
168            samplePlayer [ i ] != psp[2] )
169       {
170         samplePlayer [ i ] -> preempt ( mixer_buffer_size ) ;
171       }
172     }
173
174     if ( pri[0] < 0 )
175     {
176       memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
177       amount_left = 0 ;
178     }
179     else
180     if ( pri[1] < 0 )
181       psp[0] -> read ( mixer_buffer_size, mixer_buffer ) ;
182     else
183     if ( pri[2] < 0 )
184       mixBuffer ( psp[0], psp[1] ) ;
185     else
186       mixBuffer ( psp[0], psp[1], psp[2] ) ;
187
188     if ( dump_first )
189     {
190       stop () ;
191       dump_first = SL_FALSE ;
192     }
193
194     play ( mixer_buffer, mixer_buffer_size ) ;
195
196     now += mixer_buffer_size ;
197   }
198
199   flushCallBacks () ;
200 }
201
202 void slScheduler::addCallBack ( slCallBack c, slSample *s, slEvent e, int m )
203 {
204   if ( num_pending_callbacks >= SL_MAX_CALLBACKS )
205   {
206     fprintf ( stderr, "slScheduler: Too many pending callback events!\n" ) ;
207     return ;
208   }
209
210   slPendingCallBack *p = & ( pending_callback [ num_pending_callbacks++ ] ) ;
211
212   p -> callback = c ;
213   p -> sample   = s ;
214   p -> event    = e ;
215   p -> magic    = m ;
216 }
217
218 void slScheduler::flushCallBacks ()
219 {
220   /*
221     Execute all the callbacks that we accumulated
222     in this iteration.
223
224     This is done at the end of 'update' to reduce the risk
225     of nasty side-effects caused by 'unusual' activities
226     in the application's callback function.
227   */
228
229   while ( num_pending_callbacks > 0 )
230   {
231     slPendingCallBack *p = & ( pending_callback [ --num_pending_callbacks ] ) ;
232
233     if ( p -> callback )
234       (*(p->callback))( p->sample, p->event, p->magic ) ;
235   }
236 }
237
238