]> git.mxchange.org Git - simgear.git/blob - src/slScheduler.cxx
Temporary destructor patch until Steve can release next version of PUI.
[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   mixer_buffer = NULL ;
41   spare_buffer1 [ 0 ] = NULL ;
42   spare_buffer1 [ 1 ] = NULL ;
43   spare_buffer1 [ 2 ] = NULL ;
44   spare_buffer2 [ 0 ] = NULL ;
45   spare_buffer2 [ 1 ] = NULL ;
46   spare_buffer2 [ 2 ] = NULL ;
47
48   initBuffers () ;
49 }
50
51 void slScheduler::initBuffers ()
52 {
53   if ( not_working () ) return ;
54
55   delete mixer_buffer ;
56   delete spare_buffer1 [ 0 ] ;
57   delete spare_buffer1 [ 1 ] ;
58   delete spare_buffer1 [ 2 ] ;
59   delete spare_buffer2 [ 0 ] ;
60   delete spare_buffer2 [ 1 ] ;
61   delete spare_buffer2 [ 2 ] ;
62
63   mixer_buffer_size = getDriverBufferSize () ;
64
65   mixer_buffer = new Uchar [ mixer_buffer_size ] ;
66   memset ( mixer_buffer, 0x80, mixer_buffer_size ) ;
67
68   spare_buffer1 [ 0 ] = new Uchar [ mixer_buffer_size ] ;
69   spare_buffer1 [ 1 ] = new Uchar [ mixer_buffer_size ] ;
70   spare_buffer1 [ 2 ] = new Uchar [ mixer_buffer_size ] ;
71
72   spare_buffer2 [ 0 ] = new Uchar [ mixer_buffer_size ] ;
73   spare_buffer2 [ 1 ] = new Uchar [ mixer_buffer_size ] ;
74   spare_buffer2 [ 2 ] = new Uchar [ mixer_buffer_size ] ;
75 }
76
77 slScheduler::~slScheduler ()
78 {
79   if ( current == this )
80     current = NULL ;
81
82   delete mixer_buffer ;
83
84   delete spare_buffer1 [ 0 ] ;
85   delete spare_buffer1 [ 1 ] ;
86   delete spare_buffer1 [ 2 ] ;
87   delete spare_buffer2 [ 0 ] ;
88   delete spare_buffer2 [ 1 ] ;
89   delete spare_buffer2 [ 2 ] ;
90 }
91
92 Uchar *slScheduler::mergeBlock ( Uchar *d )
93 {
94   register int l = amount_left ;
95   amount_left = 0 ;
96   memset ( d, 0x80, l ) ;
97
98   return d + l ;
99 }
100
101
102 Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa )
103 {
104   register int l = spa -> getAmountLeft () ;
105
106   if ( l > amount_left )
107     l = amount_left ;
108
109   amount_left -= l ;
110
111   memcpy ( d, spa->read(l, spare_buffer1[0], spare_buffer2[0]), l ) ;
112
113   return d + l ;
114 }
115
116
117 Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa, slSamplePlayer *spb )
118 {
119   int la = spa -> getAmountLeft () ;
120   int lb = spb -> getAmountLeft () ;
121
122   register int l = ( la < lb ) ? la : lb ;
123
124   if ( l > amount_left )
125     l = amount_left ;
126
127   amount_left -= l ;
128
129   register Uchar *a = spa -> read ( l, spare_buffer1[0], spare_buffer2[0] ) ;
130   register Uchar *b = spb -> read ( l, spare_buffer1[1], spare_buffer2[1] ) ;
131
132   while ( l-- ) *d++ = mix ( *a++, *b++ ) ;
133
134   return d ;
135 }
136
137 Uchar *slScheduler::mergeBlock ( Uchar *d, slSamplePlayer *spa, slSamplePlayer *spb, slSamplePlayer *spc )
138 {
139   int la = spa -> getAmountLeft () ;
140   int lb = spb -> getAmountLeft () ;
141   int lc = spc -> getAmountLeft () ;
142
143   register int l = ( la < lb ) ?
144                     (( la < lc ) ? la : lc ) :
145                     (( lb < lc ) ? lb : lc ) ;
146
147   if ( l > amount_left )
148     l = amount_left ;
149
150   amount_left -= l ;
151
152   register Uchar *a = spa -> read ( l, spare_buffer1[0], spare_buffer2[0] ) ;
153   register Uchar *b = spb -> read ( l, spare_buffer1[1], spare_buffer2[1] ) ;
154   register Uchar *c = spc -> read ( l, spare_buffer1[2], spare_buffer2[2] ) ;
155
156   while ( l-- ) *d++ = mix ( *a++, *b++, *c++ ) ;
157
158   return d ;
159 }
160
161
162 void slScheduler::mixBuffer ()
163 {
164   register Uchar *d = mixer_buffer ;
165
166   amount_left = mixer_buffer_size ;
167
168   while ( amount_left > 0 )
169     d = mergeBlock ( d ) ;
170 }
171
172
173 void slScheduler::mixBuffer ( slSamplePlayer *spa )
174 {
175   register Uchar *d = mixer_buffer ;
176
177   amount_left = mixer_buffer_size ;
178
179   while ( amount_left > 0 )
180   {
181     int la = spa -> getAmountLeft () ;
182
183     if ( la > 0 ) /* Buffer has data left... */
184       d = mergeBlock ( d, spa ) ;
185     else          /* Buffer is empty */
186       d = mergeBlock ( d ) ;
187   }
188 }
189
190
191 void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb )
192 {
193   register Uchar *d = mixer_buffer ;
194   amount_left = mixer_buffer_size ;
195
196   while ( amount_left > 0 )
197   {
198     int la = spa -> getAmountLeft () ;
199     int lb = spb -> getAmountLeft () ;
200
201     if ( la > 0 && lb > 0 ) /* Both buffers have data left... */
202       d = mergeBlock ( d, spa, spb ) ;
203     else
204     if ( la > 0 && lb <= 0 ) /* Only the A buffer has data left... */
205       d = mergeBlock ( d, spa ) ;
206     else
207     if ( la <= 0 && lb > 0 ) /* Only the B buffer has data left... */
208       d = mergeBlock ( d, spb ) ;
209     else                     /* Both buffers are empty */
210       d = mergeBlock ( d ) ;
211   }
212 }
213
214
215
216 void slScheduler::mixBuffer ( slSamplePlayer *spa, slSamplePlayer *spb,
217                               slSamplePlayer *spc )
218 {
219   register Uchar *d = mixer_buffer ;
220
221   amount_left = mixer_buffer_size ;
222
223   while ( amount_left > 0 )
224   {
225     int la = spa -> getAmountLeft () ;
226     int lb = spb -> getAmountLeft () ;
227     int lc = spc -> getAmountLeft () ;
228
229     if ( lc > 0 )  /* C buffer has data left... */
230     {
231       if ( la > 0 && lb > 0 ) /* All three buffers have data left... */
232         d = mergeBlock ( d, spa, spb, spc ) ;
233       else
234       if ( la > 0 && lb <= 0 ) /* Only the A&C buffers have data left... */
235         d = mergeBlock ( d, spa, spc ) ;
236       else
237       if ( la <= 0 && lb > 0 ) /* Only the B&C buffers have data left... */
238         d = mergeBlock ( d, spb, spc ) ;
239       else                     /* Only the C buffer has data left */
240         d = mergeBlock ( d, spc ) ;
241     }
242     else
243     {
244       if ( la > 0 && lb > 0 ) /* Only the A&B buffers have data left... */
245         d = mergeBlock ( d, spa, spb ) ;
246       else
247       if ( la > 0 && lb <= 0 ) /* Only the A buffer has data left... */
248         d = mergeBlock ( d, spa ) ;
249       else
250       if ( la <= 0 && lb > 0 ) /* Only the B buffer has data left... */
251         d = mergeBlock ( d, spb ) ;
252       else                     /* All three buffers are empty */
253         d = mergeBlock ( d ) ;
254     }
255   }
256 }
257
258
259 void slScheduler::realUpdate ( int dump_first )
260 {
261   int i ;
262
263   if ( not_working () )
264     return ;
265
266   while ( secondsUsed() <= safety_margin )
267   {
268     slSamplePlayer *psp [ 3 ] ;
269     int             pri [ 3 ] ;
270
271     pri [ 0 ] = pri [ 1 ] = pri [ 2 ] =  -1  ;
272
273     for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
274     {
275       if ( samplePlayer [ i ] == NULL )
276         continue ;
277
278       /* Clean up dead sample players */
279
280       if ( samplePlayer [ i ] -> isDone () )
281       {
282         delete samplePlayer [ i ] ;
283         samplePlayer [ i ] = NULL ;
284         continue ;
285       }
286
287       if ( samplePlayer [ i ] -> isPaused () )
288         continue ;
289
290       int lowest = ( pri [0] <= pri [2] ) ?
291                      (( pri [0] <= pri [1] ) ? 0 : 1 ) :
292                      (( pri [1] <= pri [2] ) ? 1 : 2 ) ;
293
294       if ( samplePlayer[i]->getPriority() > pri[lowest] )
295       {
296         psp[lowest] = samplePlayer[i] ;
297         pri[lowest] = samplePlayer[i]->getPriority() ;
298       }
299     }
300
301     for ( i = 0 ; i < SL_MAX_SAMPLES ; i++ )
302     {
303       if ( samplePlayer [ i ] == NULL )
304         continue ;
305
306       if ( ! samplePlayer [ i ] -> isPaused () &&
307            samplePlayer [ i ] != psp[0] &&
308            samplePlayer [ i ] != psp[1] &&
309            samplePlayer [ i ] != psp[2] )
310       {
311         samplePlayer [ i ] -> preempt ( mixer_buffer_size ) ;
312       }
313     }
314
315     if ( pri[0] < 0 ) mixBuffer () ; else
316     if ( pri[1] < 0 ) mixBuffer ( psp[0] ) ; else
317     if ( pri[2] < 0 ) mixBuffer ( psp[0], psp[1] ) ; else
318                       mixBuffer ( psp[0], psp[1], psp[2] ) ;
319
320     if ( dump_first )
321     {
322       stop () ;
323       dump_first = SL_FALSE ;
324     }
325
326     play ( mixer_buffer, mixer_buffer_size ) ;
327
328     now += mixer_buffer_size ;
329   }
330
331   flushCallBacks () ;
332 }
333
334 void slScheduler::addCallBack ( slCallBack c, slSample *s, slEvent e, int m )
335 {
336   if ( num_pending_callbacks >= SL_MAX_CALLBACKS )
337   {
338     fprintf ( stderr, "slScheduler: Too many pending callback events!\n" ) ;
339     return ;
340   }
341
342   slPendingCallBack *p = & ( pending_callback [ num_pending_callbacks++ ] ) ;
343
344   p -> callback = c ;
345   p -> sample   = s ;
346   p -> event    = e ;
347   p -> magic    = m ;
348 }
349
350 void slScheduler::flushCallBacks ()
351 {
352   /*
353     Execute all the callbacks that we accumulated
354     in this iteration.
355
356     This is done at the end of 'update' to reduce the risk
357     of nasty side-effects caused by 'unusual' activities
358     in the application's callback function.
359   */
360
361   while ( num_pending_callbacks > 0 )
362   {
363     slPendingCallBack *p = & ( pending_callback [ --num_pending_callbacks ] ) ;
364
365     if ( p -> callback )
366       (*(p->callback))( p->sample, p->event, p->magic ) ;
367   }
368 }
369
370