]> git.mxchange.org Git - simgear.git/blob - src/sl.h
added a working() method.
[simgear.git] / src / sl.h
1
2 #ifndef __SL_H__
3 #define __SL_H__ 1
4
5 #include "slPortability.h"
6
7 #ifdef SL_USING_OSS_AUDIO
8 #define SLDSP_DEFAULT_DEVICE "/dev/dsp"
9 #elif defined(WIN32)
10 #define SLDSP_DEFAULT_DEVICE "dsp"      
11 #elif defined(__OpenBSD__)
12 #define SLDSP_DEFAULT_DEVICE "/dev/audio"
13 #elif defined(sgi)
14 #define SLDSP_DEFAULT_DEVICE "dsp"              // dummy ...
15 #else
16 #error "Port me !"
17 #endif
18
19 # define SL_TRUE  1
20 # define SL_FALSE 0
21
22 typedef unsigned char  Uchar  ;
23 typedef unsigned short Ushort ;
24
25 #define SL_DEFAULT_SAMPLING_RATE 11025
26
27 /* Set if the next slScheduler::update will die */
28 extern char *__slPendingError ;
29
30 class slSample       ;
31 class slSamplePlayer ;
32 class slEnvelope     ;
33 class slScheduler    ;
34 class slDSP          ;
35
36 class slDSP
37 {
38 private:
39
40   int stereo ;
41   int rate ;
42   int bps ;
43
44   int error ;
45   int fd ;
46
47 #ifdef __OpenBSD__
48   audio_info_t    ainfo;        // ioctl structure
49   audio_offset_t  audio_offset; // offset in audiostream
50   long            counter;      // counter-written packets
51 #elif defined(SL_USING_OSS_AUDIO)
52   audio_buf_info buff_info ;
53 #elif defined(sgi)
54   ALconfig        config;       // configuration stuff
55   ALport          port;         // .. we are here 
56 #endif
57
58
59 #ifndef WIN32
60   int ioctl ( int cmd, int param = 0 )
61   {
62     if ( error ) return param ;
63
64     if ( ::ioctl ( fd, cmd, & param ) == -1 )
65     {
66       perror ( "slDSP: ioctl" ) ;
67       error = SL_TRUE ;
68     }
69
70     return param ;
71   }
72
73 #elif defined(WIN32)
74
75    HWAVEOUT       hWaveOut;      // device handle 
76    WAVEFORMATEX   Format;        // open needs this
77    MMTIME         mmt;           // timing 
78    WAVEHDR        wavehdr[ 3 ];  // for round robin ..
79    int            curr_header;   // index of actual wavehdr
80    long           counter;       // counter-written packets
81
82 #endif
83
84   void open ( char *device, int _rate, int _stereo, int _bps ) ;
85   void close () ;
86   void getBufferInfo () ;
87   void write ( void *buffer, size_t length ) ;
88
89 protected:
90
91   void setError () { error = SL_TRUE ; }
92   int getDriverBufferSize () ;
93
94 public:
95
96   slDSP ( int _rate = SL_DEFAULT_SAMPLING_RATE,
97           int _stereo = SL_FALSE, int _bps = 8 )
98   {
99     open ( SLDSP_DEFAULT_DEVICE, _rate, _stereo, _bps ) ;
100   } 
101
102   slDSP ( char *device, int _rate = SL_DEFAULT_SAMPLING_RATE,
103           int _stereo = SL_FALSE, int _bps = 8 )
104   {
105     open ( device, _rate, _stereo, _bps ) ;
106   } 
107
108  ~slDSP () { close () ; }
109   
110   float secondsRemaining () ;
111   float secondsUsed () ;
112
113   void play ( void *buffer, size_t length ) { write ( buffer, length ) ; } 
114
115   int working () { return !error ; }
116   int not_working () { return error ; }
117
118   int getBps   () { return bps    ; }
119   int getRate  () { return rate   ; }
120   int getStereo() { return stereo ; }
121
122   void sync () ;
123   void stop () ;
124 } ;
125
126
127 class slSample
128 {
129   int    ref_count ;
130 protected:
131
132   char  *comment;
133   int    rate   ;
134   int    bps    ;
135   int    stereo ;
136
137   Uchar *buffer ;
138   int    length ;
139
140   void init ()
141   {
142     ref_count = 0 ;
143     comment = NULL  ;
144     buffer  = NULL  ;
145     length  = 0     ;
146     rate    = SL_DEFAULT_SAMPLING_RATE ;
147     bps     = 8     ;
148     stereo  = SL_FALSE ;
149   }
150
151 public:
152
153   slSample () { init () ; }
154
155   slSample ( Uchar *buff, int leng )
156   {
157     init () ;
158     setBuffer ( buff, leng ) ;
159   }
160
161   slSample ( char *fname, class slDSP *dsp = NULL )
162   {
163     init () ;
164     loadFile ( fname ) ;
165     autoMatch ( dsp ) ;
166   }
167
168  ~slSample ()
169   {
170     if ( ref_count != 0 )
171     {
172     if ( __slPendingError == NULL )
173       __slPendingError =
174             "slXXXX: FATAL ERROR - Application deleted a sample while it was playing.\n" ;
175     }
176
177     delete buffer ;
178   }
179   
180   void ref   () { ref_count++ ; }
181   void unRef () { ref_count-- ; }
182
183   int getPlayCount () { return ref_count ; }
184
185   char  *getComment () { return comment ; }
186
187   void   setComment ( char *nc )
188   {
189     delete comment ;
190     comment = new char [ strlen ( nc ) + 1 ] ;
191     strcpy ( comment, nc ) ;
192   }
193
194   Uchar *getBuffer () { return buffer ; }
195   int    getLength () { return length ; }
196
197   void  autoMatch ( slDSP *dsp ) ;
198
199   void   setBuffer ( Uchar *buff, int leng )
200   {
201     delete buffer ;
202
203     buffer = new Uchar [ leng ] ;
204
205     if ( buff != NULL )
206       memcpy ( buffer, buff, leng ) ;
207
208     length = leng ;
209   }
210
211   /* These routines only set flags - use changeXXX () to convert a sound */
212
213   void setRate   ( int r ) { rate   = r ; }
214   void setBps    ( int b ) { bps    = b ; }
215   void setStereo ( int s ) { stereo = s ; }
216
217   int  getRate   ()        { return rate   ; }
218   int  getBps    ()        { return bps    ; }
219   int  getStereo ()        { return stereo ; }
220
221   float getDuration ()     { return (float) getLength() /
222                                     (float) ( (getStereo()?2.0f:1.0f)*
223                                               (getBps()/8.0f)*getRate() ) ; }
224
225   int loadFile    ( char *fname ) ;
226
227   int loadRawFile ( char *fname ) ;
228   int loadAUFile  ( char *fname ) ;
229   int loadWavFile ( char *fname ) ;
230
231   void changeRate       ( int r ) ;
232   void changeBps        ( int b ) ;
233   void changeStereo     ( int s ) ;
234   void changeToUnsigned () ;
235
236   void adjustVolume ( float vol ) ;
237
238   void print ( FILE *fd )
239   {
240     if ( buffer == NULL )
241     {
242       fprintf ( fd, "Empty sample buffer\n" ) ;
243     }
244     else
245     {
246       fprintf ( fd, "\"%s\"\n",(getComment() == NULL ||
247                                 getComment()[0]=='\0') ? "Sample" : comment  ) ;
248       fprintf ( fd, "%s, %d bits per sample.\n",
249                             getStereo() ? "Stereo" : "Mono", getBps() ) ;
250       fprintf ( fd, "%gKHz sample rate.\n", (float) getRate() / 1000.0f ) ;
251       fprintf ( fd, "%d bytes of samples == %g seconds duration.\n", getLength(), getDuration() ) ;
252     }
253   }
254 } ;
255
256
257 enum slSampleStatus
258 {
259   SL_SAMPLE_WAITING,  /* Sound hasn't started playing yet */
260   SL_SAMPLE_RUNNING,  /* Sound has started playing */
261   SL_SAMPLE_DONE   ,  /* Sound is complete */
262   SL_SAMPLE_PAUSED    /* Sound hasn't started playing yet */
263 } ;
264
265
266 enum slPreemptMode
267 {
268   SL_SAMPLE_CONTINUE,  /* Don't allow yourself to be preempted   */
269   SL_SAMPLE_ABORT   ,  /* Abort playing the sound when preempted */
270   SL_SAMPLE_RESTART ,  /* Restart the sound when load permits    */
271   SL_SAMPLE_MUTE    ,  /* Continue silently until load permits   */
272   SL_SAMPLE_DELAY      /* Pause until load permits               */
273 } ;
274
275
276 enum slReplayMode
277 {
278   SL_SAMPLE_LOOP,      /* Loop sound so that it plays forever */
279   SL_SAMPLE_ONE_SHOT   /* Play sound just once */
280 } ;
281
282 enum slEvent
283 {
284   SL_EVENT_COMPLETE,  /* Sound finished playing */
285   SL_EVENT_LOOPED,    /* Sound looped back to the start */
286   SL_EVENT_PREEMPTED  /* Sound was preempted */
287 } ;
288
289 typedef void (*slCallBack) ( slSample *, slEvent, int ) ;
290
291 class slEnvelope
292 {
293 public:  /* SJB TESTING! */
294
295   float *time  ;
296   float *value ;
297   int   nsteps ;
298   int   ref_count ;
299
300   slReplayMode replay_mode ;
301
302   int getStepDelta ( float *_time, float *delta ) ;
303
304 public:
305
306   slEnvelope ( int _nsteps, slReplayMode _rm, float *_times, float *_values )
307   {
308     ref_count = 0 ;
309     nsteps = _nsteps ;
310     time  = new float [ nsteps ] ;
311     value = new float [ nsteps ] ;
312     memcpy ( time , _times , sizeof(float) * nsteps ) ;
313     memcpy ( value, _values, sizeof(float) * nsteps ) ;
314
315     replay_mode = _rm ;
316   }
317
318
319   slEnvelope ( int _nsteps = 1, slReplayMode _rm = SL_SAMPLE_ONE_SHOT )
320   {
321     ref_count = 0 ;
322     nsteps = _nsteps ;
323     time  = new float [ nsteps ] ;
324     value = new float [ nsteps ] ;
325
326     for ( int i = 0 ; i < nsteps ; i++ )
327       time [ i ] = value [ i ] = 0.0 ;
328
329     replay_mode = _rm ;
330   }
331  
332  ~slEnvelope ()
333   {
334     if ( ref_count != 0 )
335     {
336     if ( __slPendingError == NULL )
337       __slPendingError =
338             "slXXXX: FATAL ERROR - Application deleted an envelope while it was playing.\n" ;
339     }
340
341     delete time ;
342     delete value ;
343   }
344
345   void ref   () { ref_count++ ; }
346   void unRef () { ref_count-- ; }
347
348   int getPlayCount () { return ref_count ; }
349
350   void setStep ( int n, float _time, float _value )
351   {
352     if ( n >= 0 && n < nsteps )
353     {
354       time  [ n ] = _time  ;
355       value [ n ] = _value ;
356     }
357   }
358
359   float getStepValue ( int s ) { return value [ s ] ; }
360   float getStepTime  ( int s ) { return time  [ s ] ; }
361
362   int   getNumSteps  () { return nsteps ; }
363
364   float getValue ( float _time ) ;
365
366   void applyToPitch     ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
367   void applyToInvPitch  ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
368   void applyToVolume    ( Uchar *dst, Uchar *src, int nframes, int start ) ;
369   void applyToInvVolume ( Uchar *dst, Uchar *src, int nframes, int start ) ;
370 } ;
371
372 #define SL_MAX_PRIORITY  16
373 #define SL_MAX_SAMPLES   16
374 #define SL_MAX_CALLBACKS (SL_MAX_SAMPLES * 2)
375 #define SL_MAX_ENVELOPES 4
376
377 enum slEnvelopeType
378 {
379   SL_PITCH_ENVELOPE , SL_INVERSE_PITCH_ENVELOPE ,
380   SL_VOLUME_ENVELOPE, SL_INVERSE_VOLUME_ENVELOPE,
381   SL_FILTER_ENVELOPE, SL_INVERSE_FILTER_ENVELOPE,
382   SL_PAN_ENVELOPE   , SL_INVERSE_PAN_ENVELOPE   ,
383   SL_ECHO_ENVELOPE  , SL_INVERSE_ECHO_ENVELOPE  ,
384
385   SL_NULL_ENVELOPE
386 } ;
387
388 struct slPendingCallBack
389 {
390   slCallBack callback ;
391   slSample  *sample   ;
392   slEvent    event    ;
393   int        magic    ;
394 } ;
395
396 class slSamplePlayer
397 {
398   int            lengthRemaining ;  /* Sample frames remaining until repeat */
399   Uchar         *bufferPos       ;  /* Sample frame to replay next */
400   slSample      *sample          ;
401
402   slEnvelope    *env            [ SL_MAX_ENVELOPES ] ;
403   slEnvelopeType env_type       [ SL_MAX_ENVELOPES ] ;
404   int            env_start_time [ SL_MAX_ENVELOPES ] ;
405
406   slReplayMode   replay_mode     ;
407   slPreemptMode  preempt_mode    ;
408   slSampleStatus status          ;
409   int            priority        ;
410
411   slCallBack     callback ;
412   int            magic ;
413
414   void  low_read ( int nframes, Uchar *dest ) ;
415
416 public:
417
418   slSamplePlayer ( slSample *s, slReplayMode  rp_mode = SL_SAMPLE_ONE_SHOT, 
419                    int pri = 0, slPreemptMode pr_mode = SL_SAMPLE_DELAY,
420                    int _magic = 0, slCallBack cb = NULL )
421   {
422     magic           = _magic ;
423     sample          = s ;
424     callback        = cb ;
425
426     for ( int i = 0 ; i < SL_MAX_ENVELOPES ; i++ )
427     {
428       env [ i ] = NULL ;
429       env_type [ i ] = SL_NULL_ENVELOPE ;
430     }
431
432     if ( sample ) sample -> ref () ;
433
434     reset () ;
435
436     replay_mode     = rp_mode ;
437     preempt_mode    = pr_mode ;
438     priority        = pri ;
439   }
440
441   ~slSamplePlayer () ;
442
443   slPreemptMode getPreemptMode () { return preempt_mode ; }
444
445   int getPriority ()
446   {
447     return ( isRunning() &&
448              preempt_mode == SL_SAMPLE_CONTINUE ) ? (SL_MAX_PRIORITY+1) :
449                                                                priority ;
450   }
451
452   int preempt ( int delay ) ;
453   
454   void addEnvelope ( int i, slEnvelope *_env, slEnvelopeType _type ) ;
455
456   void pause ()
457   {
458     if ( status != SL_SAMPLE_DONE )
459       status = SL_SAMPLE_PAUSED ;
460   }
461
462   void resume ()
463   {
464     if ( status == SL_SAMPLE_PAUSED )
465       status = SL_SAMPLE_RUNNING ;
466   }
467
468   void reset ()
469   {
470     status = SL_SAMPLE_WAITING ;
471     lengthRemaining = sample->getLength () ;
472     bufferPos       = sample->getBuffer () ;
473   } 
474
475   void start ()
476   {
477     status = SL_SAMPLE_RUNNING ;
478     lengthRemaining = sample->getLength () ;
479     bufferPos       = sample->getBuffer () ;
480   } 
481
482   void stop ()
483   {
484     status = SL_SAMPLE_DONE ;
485     lengthRemaining = 0    ;
486     bufferPos       = NULL ;
487   } 
488
489   int       getMagic  () { return magic  ; }
490   slSample *getSample () { return sample ; }
491
492   int isWaiting () { return status == SL_SAMPLE_WAITING ; } 
493   int isPaused  () { return status == SL_SAMPLE_PAUSED  ; } 
494   int isRunning () { return status == SL_SAMPLE_RUNNING ; } 
495   int isDone    () { return status == SL_SAMPLE_DONE    ; }
496
497   void skip ( int nframes ) ;
498   void read ( int nframes, Uchar *dest, int next_env = 0 ) ;
499 } ;
500
501
502 class slScheduler : public slDSP
503 {
504   slPendingCallBack pending_callback [ SL_MAX_CALLBACKS ] ;
505   int num_pending_callbacks ;
506
507   float safety_margin ;
508
509   int mixer_buffer_size ;
510
511   Uchar *mixer_buffer  ;
512   Uchar *spare_buffer0 ;
513   Uchar *spare_buffer1 ;
514   Uchar *spare_buffer2 ;
515   
516   Uchar *mixer ;
517   int amount_left ;
518
519   slSamplePlayer *samplePlayer [ SL_MAX_SAMPLES ] ;
520
521   void init () ;
522
523   void mixBuffer ( slSamplePlayer *a,
524                    slSamplePlayer *b ) ;
525
526   void mixBuffer ( slSamplePlayer *a,
527                    slSamplePlayer *b,
528                    slSamplePlayer *c ) ;
529
530   Uchar mix ( Uchar a, Uchar b )
531   {
532     register int r = a + b - 0x80 ;
533     return ( r > 255 ) ? 255 :
534            ( r <  0  ) ?  0  : r ;
535   }
536
537   Uchar mix ( Uchar a, Uchar b, Uchar c )
538   {
539     register int r = a + b + c - 0x80 - 0x80 ;
540     return ( r > 255 ) ? 255 :
541            ( r <  0  ) ?  0  : r ;
542   }
543
544   void realUpdate ( int dump_first = SL_FALSE ) ;
545
546   void initBuffers () ;
547
548   int now ;
549
550   static slScheduler *current ;
551
552 public:
553
554   slScheduler ( int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( _rate, SL_FALSE, 8 ) { init () ; }
555   slScheduler ( char *device,
556                 int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( device, _rate, SL_FALSE, 8 ) { init () ; }
557  ~slScheduler () ;
558
559   static slScheduler *getCurrent () { return current ; }
560
561   int   getTimeNow     () { return now ; }
562   float getElapsedTime ( int then ) { return (float)(now-then)/(float)getRate() ; }
563
564   void flushCallBacks () ;
565   void addCallBack    ( slCallBack c, slSample *s, slEvent e, int m ) ;
566
567   void update     () { realUpdate ( SL_FALSE ) ; }
568   void dumpUpdate () { realUpdate ( SL_TRUE  ) ; }
569
570   void addSampleEnvelope ( slSample *s = NULL, int magic = 0,
571                            int slot = 1, slEnvelope *e = NULL, 
572                            slEnvelopeType t =  SL_VOLUME_ENVELOPE )
573   {
574     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
575       if ( samplePlayer [ i ] != NULL &&
576            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
577            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
578         samplePlayer [ i ] -> addEnvelope ( slot, e, t ) ;
579   }
580  
581   void resumeSample ( slSample *s = NULL, int magic = 0 )
582   {
583     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
584       if ( samplePlayer [ i ] != NULL &&
585            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
586            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
587         samplePlayer [ i ] -> resume () ;
588   }
589  
590   void pauseSample ( slSample *s = NULL, int magic = 0 )
591   {
592     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
593       if ( samplePlayer [ i ] != NULL &&
594            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
595            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
596         samplePlayer [ i ] -> pause () ;
597   }
598  
599   void stopSample ( slSample *s = NULL, int magic = 0 )
600   {
601     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
602       if ( samplePlayer [ i ] != NULL &&
603            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
604            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
605         samplePlayer [ i ] -> stop () ;
606   }
607  
608   int loopSample ( slSample *s, int pri = 0, slPreemptMode mode = SL_SAMPLE_MUTE, int magic = 0, slCallBack cb = NULL )
609   {
610     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
611       if ( samplePlayer [ i ] == NULL )
612       {
613         samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_LOOP, pri, mode, magic, cb ) ;
614         return i ;
615       }
616
617     return -1 ;
618   }
619
620   int playSample ( slSample *s, int pri = 1, slPreemptMode mode = SL_SAMPLE_ABORT, int magic = 0, slCallBack cb = NULL )
621   {
622     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
623       if ( samplePlayer [ i ] == NULL )
624       {
625         samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_ONE_SHOT, pri, mode, magic, cb ) ;
626         return SL_TRUE ;
627       }
628
629     return SL_FALSE ;
630   }
631
632   void setSafetyMargin ( float seconds ) { safety_margin = seconds ; }
633 } ;
634
635 #endif
636