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