]> git.mxchange.org Git - simgear.git/blob - src/sl.h
ab141bd74af2cd25dcedb0710d86519077b26831
[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 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 )
170     {
171     if ( __slPendingError == NULL )
172       __slPendingError =
173             "slXXXX: FATAL ERROR - Application deleted a sample while it was playing.\n" ;
174     }
175
176     delete buffer ;
177   }
178   
179   void ref   () { ref_count++ ; }
180   void unRef () { ref_count-- ; }
181
182   int getPlayCount () { return ref_count ; }
183
184   char  *getComment () { return comment ; }
185
186   void   setComment ( char *nc )
187   {
188     delete comment ;
189     comment = new char [ strlen ( nc ) + 1 ] ;
190     strcpy ( comment, nc ) ;
191   }
192
193   Uchar *getBuffer () { return buffer ; }
194   int    getLength () { return length ; }
195
196   void  autoMatch ( slDSP *dsp ) ;
197
198   void   setBuffer ( Uchar *buff, int leng )
199   {
200     delete buffer ;
201
202     buffer = new Uchar [ leng ] ;
203
204     if ( buff != NULL )
205       memcpy ( buffer, buff, leng ) ;
206
207     length = leng ;
208   }
209
210   /* These routines only set flags - use changeXXX () to convert a sound */
211
212   void setRate   ( int r ) { rate   = r ; }
213   void setBps    ( int b ) { bps    = b ; }
214   void setStereo ( int s ) { stereo = s ; }
215
216   int  getRate   ()        { return rate   ; }
217   int  getBps    ()        { return bps    ; }
218   int  getStereo ()        { return stereo ; }
219
220   float getDuration ()     { return (float) getLength() /
221                                     (float) ( (getStereo()?2.0f:1.0f)*
222                                               (getBps()/8.0f)*getRate() ) ; }
223
224   int loadFile    ( char *fname ) ;
225
226   int loadRawFile ( char *fname ) ;
227   int loadAUFile  ( char *fname ) ;
228   int loadWavFile ( char *fname ) ;
229
230   void changeRate       ( int r ) ;
231   void changeBps        ( int b ) ;
232   void changeStereo     ( int s ) ;
233   void changeToUnsigned () ;
234
235   void adjustVolume ( float vol ) ;
236
237   void print ( FILE *fd )
238   {
239     if ( buffer == NULL )
240     {
241       fprintf ( fd, "Empty sample buffer\n" ) ;
242     }
243     else
244     {
245       fprintf ( fd, "\"%s\"\n",(getComment() == NULL ||
246                                 getComment()[0]=='\0') ? "Sample" : comment  ) ;
247       fprintf ( fd, "%s, %d bits per sample.\n",
248                             getStereo() ? "Stereo" : "Mono", getBps() ) ;
249       fprintf ( fd, "%gKHz sample rate.\n", (float) getRate() / 1000.0f ) ;
250       fprintf ( fd, "%d bytes of samples == %g seconds duration.\n", getLength(), getDuration() ) ;
251     }
252   }
253 } ;
254
255
256 enum slSampleStatus
257 {
258   SL_SAMPLE_WAITING,  /* Sound hasn't started playing yet */
259   SL_SAMPLE_RUNNING,  /* Sound has started playing */
260   SL_SAMPLE_DONE   ,  /* Sound is complete */
261   SL_SAMPLE_PAUSED    /* Sound hasn't started playing yet */
262 } ;
263
264
265 enum slPreemptMode
266 {
267   SL_SAMPLE_CONTINUE,  /* Don't allow yourself to be preempted   */
268   SL_SAMPLE_ABORT   ,  /* Abort playing the sound when preempted */
269   SL_SAMPLE_RESTART ,  /* Restart the sound when load permits    */
270   SL_SAMPLE_MUTE    ,  /* Continue silently until load permits   */
271   SL_SAMPLE_DELAY      /* Pause until load permits               */
272 } ;
273
274
275 enum slReplayMode
276 {
277   SL_SAMPLE_LOOP,      /* Loop sound so that it plays forever */
278   SL_SAMPLE_ONE_SHOT   /* Play sound just once */
279 } ;
280
281 enum slEvent
282 {
283   SL_EVENT_COMPLETE,  /* Sound finished playing */
284   SL_EVENT_LOOPED,    /* Sound looped back to the start */
285   SL_EVENT_PREEMPTED  /* Sound was preempted */
286 } ;
287
288 typedef void (*slCallBack) ( slSample *, slEvent, int ) ;
289
290 class slEnvelope
291 {
292 public:  /* SJB TESTING! */
293
294   float *time  ;
295   float *value ;
296   int   nsteps ;
297   int   ref_count ;
298
299   slReplayMode replay_mode ;
300
301   int getStepDelta ( float *_time, float *delta ) ;
302
303 public:
304
305   slEnvelope ( int _nsteps, slReplayMode _rm, float *_times, float *_values )
306   {
307     ref_count = 0 ;
308     nsteps = _nsteps ;
309     time  = new float [ nsteps ] ;
310     value = new float [ nsteps ] ;
311     memcpy ( time , _times , sizeof(float) * nsteps ) ;
312     memcpy ( value, _values, sizeof(float) * nsteps ) ;
313
314     replay_mode = _rm ;
315   }
316
317
318   slEnvelope ( int _nsteps = 1, slReplayMode _rm = SL_SAMPLE_ONE_SHOT )
319   {
320     ref_count = 0 ;
321     nsteps = _nsteps ;
322     time  = new float [ nsteps ] ;
323     value = new float [ nsteps ] ;
324
325     for ( int i = 0 ; i < nsteps ; i++ )
326       time [ i ] = value [ i ] = 0.0 ;
327
328     replay_mode = _rm ;
329   }
330  
331  ~slEnvelope ()
332   {
333     if ( ref_count != 0 )
334     {
335     if ( __slPendingError == NULL )
336       __slPendingError =
337             "slXXXX: FATAL ERROR - Application deleted an envelope while it was playing.\n" ;
338     }
339
340     delete time ;
341     delete value ;
342   }
343
344   void ref   () { ref_count++ ; }
345   void unRef () { ref_count-- ; }
346
347   int getPlayCount () { return ref_count ; }
348
349   void setStep ( int n, float _time, float _value )
350   {
351     if ( n >= 0 && n < nsteps )
352     {
353       time  [ n ] = _time  ;
354       value [ n ] = _value ;
355     }
356   }
357
358   float getStepValue ( int s ) { return value [ s ] ; }
359   float getStepTime  ( int s ) { return time  [ s ] ; }
360
361   int   getNumSteps  () { return nsteps ; }
362
363   float getValue ( float _time ) ;
364
365   void applyToPitch     ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
366   void applyToInvPitch  ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
367   void applyToVolume    ( Uchar *dst, Uchar *src, int nframes, int start ) ;
368   void applyToInvVolume ( Uchar *dst, Uchar *src, int nframes, int start ) ;
369 } ;
370
371 #define SL_MAX_PRIORITY  16
372 #define SL_MAX_SAMPLES   16
373 #define SL_MAX_CALLBACKS (SL_MAX_SAMPLES * 2)
374 #define SL_MAX_ENVELOPES 4
375
376 enum slEnvelopeType
377 {
378   SL_PITCH_ENVELOPE , SL_INVERSE_PITCH_ENVELOPE ,
379   SL_VOLUME_ENVELOPE, SL_INVERSE_VOLUME_ENVELOPE,
380   SL_FILTER_ENVELOPE, SL_INVERSE_FILTER_ENVELOPE,
381   SL_PAN_ENVELOPE   , SL_INVERSE_PAN_ENVELOPE   ,
382   SL_ECHO_ENVELOPE  , SL_INVERSE_ECHO_ENVELOPE  ,
383
384   SL_NULL_ENVELOPE
385 } ;
386
387 struct slPendingCallBack
388 {
389   slCallBack callback ;
390   slSample  *sample   ;
391   slEvent    event    ;
392   int        magic    ;
393 } ;
394
395 class slSamplePlayer
396 {
397   int            lengthRemaining ;  /* Sample frames remaining until repeat */
398   Uchar         *bufferPos       ;  /* Sample frame to replay next */
399   slSample      *sample          ;
400
401   slEnvelope    *env            [ SL_MAX_ENVELOPES ] ;
402   slEnvelopeType env_type       [ SL_MAX_ENVELOPES ] ;
403   int            env_start_time [ SL_MAX_ENVELOPES ] ;
404
405   slReplayMode   replay_mode     ;
406   slPreemptMode  preempt_mode    ;
407   slSampleStatus status          ;
408   int            priority        ;
409
410   slCallBack     callback ;
411   int            magic ;
412
413   void  low_read ( int nframes, Uchar *dest ) ;
414
415 public:
416
417   slSamplePlayer ( slSample *s, slReplayMode  rp_mode = SL_SAMPLE_ONE_SHOT, 
418                    int pri = 0, slPreemptMode pr_mode = SL_SAMPLE_DELAY,
419                    int _magic = 0, slCallBack cb = NULL )
420   {
421     magic           = _magic ;
422     sample          = s ;
423     callback        = cb ;
424
425     for ( int i = 0 ; i < SL_MAX_ENVELOPES ; i++ )
426     {
427       env [ i ] = NULL ;
428       env_type [ i ] = SL_NULL_ENVELOPE ;
429     }
430
431     if ( sample ) sample -> ref () ;
432
433     reset () ;
434
435     replay_mode     = rp_mode ;
436     preempt_mode    = pr_mode ;
437     priority        = pri ;
438   }
439
440   ~slSamplePlayer () ;
441
442   slPreemptMode getPreemptMode () { return preempt_mode ; }
443
444   int getPriority ()
445   {
446     return ( isRunning() &&
447              preempt_mode == SL_SAMPLE_CONTINUE ) ? (SL_MAX_PRIORITY+1) :
448                                                                priority ;
449   }
450
451   int preempt ( int delay ) ;
452   
453   void addEnvelope ( int i, slEnvelope *_env, slEnvelopeType _type ) ;
454
455   void pause ()
456   {
457     if ( status != SL_SAMPLE_DONE )
458       status = SL_SAMPLE_PAUSED ;
459   }
460
461   void resume ()
462   {
463     if ( status == SL_SAMPLE_PAUSED )
464       status = SL_SAMPLE_RUNNING ;
465   }
466
467   void reset ()
468   {
469     status = SL_SAMPLE_WAITING ;
470     lengthRemaining = sample->getLength () ;
471     bufferPos       = sample->getBuffer () ;
472   } 
473
474   void start ()
475   {
476     status = SL_SAMPLE_RUNNING ;
477     lengthRemaining = sample->getLength () ;
478     bufferPos       = sample->getBuffer () ;
479   } 
480
481   void stop ()
482   {
483     status = SL_SAMPLE_DONE ;
484     lengthRemaining = 0    ;
485     bufferPos       = NULL ;
486   } 
487
488   int       getMagic  () { return magic  ; }
489   slSample *getSample () { return sample ; }
490
491   int isWaiting () { return status == SL_SAMPLE_WAITING ; } 
492   int isPaused  () { return status == SL_SAMPLE_PAUSED  ; } 
493   int isRunning () { return status == SL_SAMPLE_RUNNING ; } 
494   int isDone    () { return status == SL_SAMPLE_DONE    ; }
495
496   void skip ( int nframes ) ;
497   void read ( int nframes, Uchar *dest, int next_env = 0 ) ;
498 } ;
499
500
501 class slScheduler : public slDSP
502 {
503   slPendingCallBack pending_callback [ SL_MAX_CALLBACKS ] ;
504   int num_pending_callbacks ;
505
506   float safety_margin ;
507
508   int mixer_buffer_size ;
509
510   Uchar *mixer_buffer  ;
511   Uchar *spare_buffer0 ;
512   Uchar *spare_buffer1 ;
513   Uchar *spare_buffer2 ;
514   
515   Uchar *mixer ;
516   int amount_left ;
517
518   slSamplePlayer *samplePlayer [ SL_MAX_SAMPLES ] ;
519
520   void init () ;
521
522   void mixBuffer ( slSamplePlayer *a,
523                    slSamplePlayer *b ) ;
524
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