]> git.mxchange.org Git - simgear.git/blob - src/sl.h
Incorporated Steve's latest version of his audio library. This version
[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   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 )
331     {
332       fprintf ( stderr,
333         "slEnvelope: FATAL ERROR - Application deleted an envelope while it was playing.\n" ) ;
334       exit ( 1 ) ;
335     }
336
337     delete time ;
338     delete value ;
339   }
340
341   void ref   () { ref_count++ ; }
342   void unRef () { ref_count-- ; }
343
344   int getPlayCount () { return ref_count ; }
345
346   void setStep ( int n, float _time, float _value )
347   {
348     if ( n >= 0 && n < nsteps )
349     {
350       time  [ n ] = _time  ;
351       value [ n ] = _value ;
352     }
353   }
354
355   float getStepValue ( int s ) { return value [ s ] ; }
356   float getStepTime  ( int s ) { return time  [ s ] ; }
357
358   int   getNumSteps  () { return nsteps ; }
359
360   float getValue ( float _time ) ;
361
362   void applyToPitch     ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
363   void applyToInvPitch  ( Uchar *dst, slSamplePlayer *src, int nframes, int start, int next_env ) ;
364   void applyToVolume    ( Uchar *dst, Uchar *src, int nframes, int start ) ;
365   void applyToInvVolume ( Uchar *dst, Uchar *src, int nframes, int start ) ;
366 } ;
367
368 #define SL_MAX_PRIORITY  16
369 #define SL_MAX_SAMPLES   16
370 #define SL_MAX_CALLBACKS (SL_MAX_SAMPLES * 2)
371 #define SL_MAX_ENVELOPES 4
372
373 enum slEnvelopeType
374 {
375   SL_PITCH_ENVELOPE , SL_INVERSE_PITCH_ENVELOPE ,
376   SL_VOLUME_ENVELOPE, SL_INVERSE_VOLUME_ENVELOPE,
377   SL_FILTER_ENVELOPE, SL_INVERSE_FILTER_ENVELOPE,
378   SL_PAN_ENVELOPE   , SL_INVERSE_PAN_ENVELOPE   ,
379   SL_ECHO_ENVELOPE  , SL_INVERSE_ECHO_ENVELOPE  ,
380
381   SL_NULL_ENVELOPE
382 } ;
383
384 struct slPendingCallBack
385 {
386   slCallBack callback ;
387   slSample  *sample   ;
388   slEvent    event    ;
389   int        magic    ;
390 } ;
391
392 class slSamplePlayer
393 {
394   int            lengthRemaining ;  /* Sample frames remaining until repeat */
395   Uchar         *bufferPos       ;  /* Sample frame to replay next */
396   slSample      *sample          ;
397
398   slEnvelope    *env            [ SL_MAX_ENVELOPES ] ;
399   slEnvelopeType env_type       [ SL_MAX_ENVELOPES ] ;
400   int            env_start_time [ SL_MAX_ENVELOPES ] ;
401
402   slReplayMode   replay_mode     ;
403   slPreemptMode  preempt_mode    ;
404   slSampleStatus status          ;
405   int            priority        ;
406
407   slCallBack     callback ;
408   int            magic ;
409
410   void  low_read ( int nframes, Uchar *dest ) ;
411
412 public:
413
414   slSamplePlayer ( slSample *s, slReplayMode  rp_mode = SL_SAMPLE_ONE_SHOT, 
415                    int pri = 0, slPreemptMode pr_mode = SL_SAMPLE_DELAY,
416                    int _magic = 0, slCallBack cb = NULL )
417   {
418     magic           = _magic ;
419     sample          = s ;
420     callback        = cb ;
421
422     for ( int i = 0 ; i < SL_MAX_ENVELOPES ; i++ )
423     {
424       env [ i ] = NULL ;
425       env_type [ i ] = SL_NULL_ENVELOPE ;
426     }
427
428     if ( sample ) sample -> ref () ;
429
430     reset () ;
431
432     replay_mode     = rp_mode ;
433     preempt_mode    = pr_mode ;
434     priority        = pri ;
435   }
436
437   ~slSamplePlayer () ;
438
439   slPreemptMode getPreemptMode () { return preempt_mode ; }
440
441   int getPriority ()
442   {
443     return ( isRunning() &&
444              preempt_mode == SL_SAMPLE_CONTINUE ) ? (SL_MAX_PRIORITY+1) :
445                                                                priority ;
446   }
447
448   int preempt ( int delay ) ;
449   
450   void addEnvelope ( int i, slEnvelope *_env, slEnvelopeType _type ) ;
451
452   void pause ()
453   {
454     if ( status != SL_SAMPLE_DONE )
455       status = SL_SAMPLE_PAUSED ;
456   }
457
458   void resume ()
459   {
460     if ( status == SL_SAMPLE_PAUSED )
461       status = SL_SAMPLE_RUNNING ;
462   }
463
464   void reset ()
465   {
466     status = SL_SAMPLE_WAITING ;
467     lengthRemaining = sample->getLength () ;
468     bufferPos       = sample->getBuffer () ;
469   } 
470
471   void start ()
472   {
473     status = SL_SAMPLE_RUNNING ;
474     lengthRemaining = sample->getLength () ;
475     bufferPos       = sample->getBuffer () ;
476   } 
477
478   void stop ()
479   {
480     status = SL_SAMPLE_DONE ;
481     lengthRemaining = 0    ;
482     bufferPos       = NULL ;
483   } 
484
485   int       getMagic  () { return magic  ; }
486   slSample *getSample () { return sample ; }
487
488   int isWaiting () { return status == SL_SAMPLE_WAITING ; } 
489   int isPaused  () { return status == SL_SAMPLE_PAUSED  ; } 
490   int isRunning () { return status == SL_SAMPLE_RUNNING ; } 
491   int isDone    () { return status == SL_SAMPLE_DONE    ; }
492
493   void skip ( int nframes ) ;
494   void read ( int nframes, Uchar *dest, int next_env = 0 ) ;
495 } ;
496
497
498 class slScheduler : public slDSP
499 {
500   slPendingCallBack pending_callback [ SL_MAX_CALLBACKS ] ;
501   int num_pending_callbacks ;
502
503   float safety_margin ;
504
505   int mixer_buffer_size ;
506
507   Uchar *mixer_buffer  ;
508   Uchar *spare_buffer0 ;
509   Uchar *spare_buffer1 ;
510   Uchar *spare_buffer2 ;
511   
512   Uchar *mixer ;
513   int amount_left ;
514
515   slSamplePlayer *samplePlayer [ SL_MAX_SAMPLES ] ;
516
517   void init () ;
518
519   void mixBuffer ( slSamplePlayer *a,
520                    slSamplePlayer *b ) ;
521
522   void mixBuffer ( slSamplePlayer *a,
523                    slSamplePlayer *b,
524                    slSamplePlayer *c ) ;
525
526   Uchar mix ( Uchar a, Uchar b )
527   {
528     register int r = a + b - 0x80 ;
529     return ( r > 255 ) ? 255 :
530            ( r <  0  ) ?  0  : r ;
531   }
532
533   Uchar mix ( Uchar a, Uchar b, Uchar c )
534   {
535     register int r = a + b + c - 0x80 - 0x80 ;
536     return ( r > 255 ) ? 255 :
537            ( r <  0  ) ?  0  : r ;
538   }
539
540   void realUpdate ( int dump_first = SL_FALSE ) ;
541
542   void initBuffers () ;
543
544   int now ;
545
546   static slScheduler *current ;
547
548 public:
549
550   slScheduler ( int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( _rate, SL_FALSE, 8 ) { init () ; }
551   slScheduler ( char *device,
552                 int _rate = SL_DEFAULT_SAMPLING_RATE ) : slDSP ( device, _rate, SL_FALSE, 8 ) { init () ; }
553  ~slScheduler () ;
554
555   static slScheduler *getCurrent () { return current ; }
556
557   int   getTimeNow     () { return now ; }
558   float getElapsedTime ( int then ) { return (float)(now-then)/(float)getRate() ; }
559
560   void flushCallBacks () ;
561   void addCallBack    ( slCallBack c, slSample *s, slEvent e, int m ) ;
562
563   void update     () { realUpdate ( SL_FALSE ) ; }
564   void dumpUpdate () { realUpdate ( SL_TRUE  ) ; }
565
566   void addSampleEnvelope ( slSample *s = NULL, int magic = 0,
567                            int slot = 1, slEnvelope *e = NULL, 
568                            slEnvelopeType t =  SL_VOLUME_ENVELOPE )
569   {
570     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
571       if ( samplePlayer [ i ] != NULL &&
572            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
573            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
574         samplePlayer [ i ] -> addEnvelope ( slot, e, t ) ;
575   }
576  
577   void resumeSample ( slSample *s = NULL, int magic = 0 )
578   {
579     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
580       if ( samplePlayer [ i ] != NULL &&
581            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
582            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
583         samplePlayer [ i ] -> resume () ;
584   }
585  
586   void pauseSample ( slSample *s = NULL, int magic = 0 )
587   {
588     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
589       if ( samplePlayer [ i ] != NULL &&
590            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
591            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
592         samplePlayer [ i ] -> pause () ;
593   }
594  
595   void stopSample ( slSample *s = NULL, int magic = 0 )
596   {
597     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
598       if ( samplePlayer [ i ] != NULL &&
599            ( s  == NULL || samplePlayer [ i ] -> getSample () ==   s   ) &&
600            ( magic == 0 || samplePlayer [ i ] -> getMagic  () == magic ) )
601         samplePlayer [ i ] -> stop () ;
602   }
603  
604   int loopSample ( slSample *s, int pri = 0, slPreemptMode mode = SL_SAMPLE_MUTE, int magic = 0, slCallBack cb = NULL )
605   {
606     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
607       if ( samplePlayer [ i ] == NULL )
608       {
609         samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_LOOP, pri, mode, magic, cb ) ;
610         return i ;
611       }
612
613     return -1 ;
614   }
615
616   int playSample ( slSample *s, int pri = 1, slPreemptMode mode = SL_SAMPLE_ABORT, int magic = 0, slCallBack cb = NULL )
617   {
618     for ( int i = 0 ; i < SL_MAX_SAMPLES ; i++ )
619       if ( samplePlayer [ i ] == NULL )
620       {
621         samplePlayer [ i ] = new slSamplePlayer ( s, SL_SAMPLE_ONE_SHOT, pri, mode, magic, cb ) ;
622         return SL_TRUE ;
623       }
624
625     return SL_FALSE ;
626   }
627
628   void setSafetyMargin ( float seconds ) { safety_margin = seconds ; }
629 } ;
630
631 #endif
632