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