]> git.mxchange.org Git - simgear.git/blob - src/slDSP.cxx
Minor optimization tweaks.
[simgear.git] / src / slDSP.cxx
1
2 #include "sl.h"
3
4 static int init_bytes ;
5
6 #ifdef SL_USING_OSS_AUDIO
7
8 /* ------------------------------------------------------------ */
9 /* OSSAUDIO - Linux, FreeBSD, etc                               */
10 /* ------------------------------------------------------------ */
11
12 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
13 {
14   fd = ::open ( device, O_WRONLY ) ;
15
16   if ( fd < 0 )
17   {
18     perror ( "slDSP: open" ) ;
19     error = SL_TRUE ;
20
21     stereo     = SL_FALSE ;
22     bps        =    1     ;
23     rate       =  8000    ;
24     init_bytes =    0     ;
25   }
26   else
27   {
28     error = SL_FALSE ;
29
30     /* Set up a driver fragment size of 1024 (ie 2^10) */
31
32     ioctl ( SNDCTL_DSP_SETFRAGMENT, 0x7FFF000A ) ;
33
34     stereo = ioctl ( SOUND_PCM_WRITE_CHANNELS, _stereo ? 2 : 1 ) >= 2 ; 
35     bps    = ioctl ( SOUND_PCM_WRITE_BITS, _bps ) ; 
36     rate   = ioctl ( SOUND_PCM_WRITE_RATE, _rate ) ; 
37
38     getBufferInfo () ;
39     init_bytes = buff_info.bytes ;
40   }
41 }
42
43
44 void slDSP::close ()
45 {
46   if ( fd >= 0 )
47     ::close ( fd ) ;
48 }
49
50
51 int slDSP::getDriverBufferSize ()
52 {
53   if ( error )
54     return 0 ;
55
56   getBufferInfo () ;
57   return buff_info.fragsize ;
58 }
59
60 void slDSP::getBufferInfo ()
61 {
62   if ( error )
63     return ;
64
65   if ( ::ioctl ( fd, SNDCTL_DSP_GETOSPACE, & buff_info ) < 0 )
66   {
67     perror ( "slDSP: getBufferInfo" ) ;
68     error = SL_TRUE ;
69     return ;
70   }
71 }
72
73
74 void slDSP::write ( void *buffer, size_t length )
75 {
76   if ( error || length <= 0 )
77     return ;
78
79   int nwritten = ::write ( fd, (const char *) buffer, length ) ;
80
81   if ( nwritten < 0 )
82     perror ( "slDSP: write" ) ;
83   else
84   if ( nwritten != length )
85     perror ( "slDSP: short write" ) ;
86 }
87
88
89 float slDSP::secondsRemaining ()
90 {
91   if ( error )
92     return 0.0f ;
93
94   getBufferInfo () ;
95
96   int samples_left = buff_info.fragments * buff_info.fragsize ;
97
98   if (   stereo  ) samples_left /= 2 ;
99   if ( bps == 16 ) samples_left /= 2 ;
100   return   (float) samples_left / (float) rate ;
101 }
102
103
104 float slDSP::secondsUsed ()
105 {
106   if ( error )
107     return 0.0f ;
108
109   getBufferInfo () ;
110
111   int samples_used = init_bytes - buff_info.bytes ;
112
113   if (  stereo   ) samples_used /= 2 ;
114   if ( bps == 16 ) samples_used /= 2 ;
115   return   (float) samples_used / (float) rate ;
116 }
117
118
119 void slDSP::sync ()
120
121    if ( !error) ::ioctl ( fd, SOUND_PCM_SYNC , 0 ) ; 
122 }
123
124 void slDSP::stop ()
125
126    if ( !error) ::ioctl ( fd, SOUND_PCM_RESET, 0 ) ; 
127 }
128
129 #endif
130
131 #ifdef WIN32
132
133 /* ------------------------------------------------------------ */
134 /* win32                                                        */
135 /* ------------------------------------------------------------ */
136
137 static  void    wperror(MMRESULT num)
138 {
139    char buffer[0xff];  // yes, this is hardcoded :-)
140
141    waveOutGetErrorText( num, buffer, sizeof(buffer)-1);
142
143    fprintf( stderr, "SlDSP: %s\n", buffer );
144    fflush ( stderr );
145 }
146
147
148
149 void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg,     
150       DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
151 {   
152    switch( uMsg )
153    {
154    case    WOM_CLOSE:
155       break;
156
157    case    WOM_OPEN:
158       break;
159
160    case    WOM_DONE:
161       waveOutUnprepareHeader( (HWAVEOUT)dwParam1, 
162          (LPWAVEHDR)dwParam2, sizeof( WAVEHDR ));
163       break;
164    }
165 }
166
167
168 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
169 {
170    MMRESULT     result;
171
172    hWaveOut     = NULL;
173    curr_header  = 0;
174    counter     = 0;
175
176    Format.wFormatTag       = WAVE_FORMAT_PCM;           
177    Format.nChannels        = _stereo ? 2 : 1;
178    Format.nSamplesPerSec   = _rate;
179    Format.wBitsPerSample   = _bps;
180    Format.nBlockAlign      = 1;
181    Format.nAvgBytesPerSec  = _rate * Format.nChannels;
182    Format.cbSize           = 0;
183
184    result = waveOutOpen( & hWaveOut, WAVE_MAPPER, & Format, NULL, 
185       0L, WAVE_FORMAT_QUERY );
186
187    if ( result != MMSYSERR_NOERROR )
188    {
189       wperror( result);
190
191       error      = SL_TRUE  ;
192       stereo     = SL_FALSE ;
193       bps        = _bps     ;
194       rate       = _rate    ;
195       init_bytes =    0     ;
196       
197       return;
198    }
199
200    // Now the hwaveouthandle "should" be valid 
201
202    if ( ( result = waveOutOpen( & hWaveOut, WAVE_MAPPER, 
203          (WAVEFORMATEX *)& Format, (DWORD)waveOutProc, 
204          0L, CALLBACK_FUNCTION )) != MMSYSERR_NOERROR )
205    {
206       wperror( result);
207
208       error      = SL_TRUE ;
209       stereo     = SL_FALSE ;
210       bps        = _bps     ;
211       rate       = _rate    ;
212       init_bytes =    0     ;
213       return;
214    }
215    else
216    {
217       error  = SL_FALSE ;
218       stereo = _stereo;
219       bps    = _bps;
220       rate   = _rate;
221
222       /* hmm ?! */ 
223
224       init_bytes = 1024*8;
225    }
226 }
227
228
229 void slDSP::close ()
230 {
231    if ( hWaveOut != NULL )
232    {
233       waveOutClose( hWaveOut );
234       hWaveOut = NULL;
235    }
236 }
237
238 int slDSP::getDriverBufferSize ()
239 {
240    if ( error )
241       return 0 ;
242
243    /* hmm ?! */
244
245    return    1024*8;
246 }
247
248 void slDSP::getBufferInfo ()
249 {
250     return ;
251 }
252
253
254 void slDSP::write ( void *buffer, size_t length )
255 {
256    MMRESULT     result;
257
258    if ( error || length <= 0 )
259       return ;
260
261    wavehdr[curr_header].lpData          = (LPSTR) buffer;
262    wavehdr[curr_header].dwBufferLength  = (long) length;
263    wavehdr[curr_header].dwBytesRecorded = 0L;
264    wavehdr[curr_header].dwUser          = NULL;
265    wavehdr[curr_header].dwFlags         = 0;
266    wavehdr[curr_header].dwLoops         = 0;
267    wavehdr[curr_header].lpNext          = NULL;
268    wavehdr[curr_header].reserved        = 0;
269
270
271    result = waveOutPrepareHeader( hWaveOut, & wavehdr[curr_header], 
272       sizeof(WAVEHDR));
273
274    if ( result != MMSYSERR_NOERROR ) 
275    {
276       wperror ( result );
277       error = SL_TRUE;
278    }
279
280    result = waveOutWrite(hWaveOut, & wavehdr[curr_header], 
281       sizeof(WAVEHDR));
282    if ( result != MMSYSERR_NOERROR )
283    {
284       wperror ( result );
285       error = SL_TRUE;
286    }
287    
288    counter ++; 
289    
290    curr_header = ( curr_header + 1 ) % 3;
291 }
292
293
294 float slDSP::secondsRemaining ()
295 {
296    if ( error )
297       return 0.0f ;
298    
299    return 0.0f ;
300 }
301
302
303 float slDSP::secondsUsed ()
304 {
305    int      samples_used;
306    MMRESULT     result;
307    float    samp_time;
308
309    if ( error )
310       return 0.0f ;
311
312    mmt.wType = TIME_BYTES;
313
314    result = waveOutGetPosition( hWaveOut, &mmt, sizeof( mmt ));
315
316    if ( mmt.u.cb == 0 || counter == 0)
317       return    (float)0.0;
318
319    samples_used = ( init_bytes * counter ) - mmt.u.cb;
320
321    if (  stereo   ) samples_used /= 2 ;
322    if ( bps == 16 ) samples_used /= 2 ;
323
324    samp_time  = (float) samples_used / (float) rate ;
325
326    //printf("%0.2f position=%ld total written=%ld\n", 
327    // samp_time, mmt.u.cb, init_bytes * counter );
328    
329    return   samp_time;
330 }
331
332
333 void slDSP::sync ()
334 {
335 }
336
337 void slDSP::stop ()
338 {
339    if ( error )
340      return ;
341
342    waveOutReset( hWaveOut );
343 }
344
345 /* ------------------------------------------------------------ */
346 /* OpenBSD 2.3 this should be very close to SUN Audio           */
347 /* ------------------------------------------------------------ */
348
349 #elif defined(__OpenBSD__)
350 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
351 {
352
353   counter = 0;
354   
355   fd = ::open ( device, O_RDWR ) ;
356     
357   if ( fd < 0 )
358   {
359     perror ( "slDSP: open" ) ;
360     error = SL_TRUE ;
361   }
362   else
363   {    
364   
365     if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) == -1)
366     {
367       perror("slDSP: open - getinfo");
368       stereo     = SL_FALSE ;
369       bps        =    8     ;
370       rate       =  8000    ;
371       init_bytes =    0     ;
372       
373       return;
374     }
375       
376     ainfo.play.sample_rate  = _rate;
377     ainfo.play.precision    = _bps;    
378     ainfo.play.channels     = _stereo ? 2 : 1;
379     
380     ainfo.play.encoding     = AUDIO_ENCODING_ULINEAR;
381
382     if( :: ioctl(fd, AUDIO_SETINFO, &ainfo) == -1)
383     {
384       perror("slDSP: open - setinfo");
385       stereo     = SL_FALSE ;
386       bps        =    8     ;
387       rate       =  8000    ;
388       init_bytes =    0     ;
389       return;
390     }
391
392     rate    = _rate;
393     stereo  = _stereo;
394     bps     = _bps;
395
396     error = SL_FALSE ;
397
398     getBufferInfo ();
399     
400     // I could not change the size, 
401     // so let's try this ...
402     
403     init_bytes = 1024 * 8;
404   }
405 }
406
407
408 void slDSP::close ()
409 {
410   if ( fd >= 0 )
411     ::close ( fd ) ;
412 }
413
414
415 int slDSP::getDriverBufferSize ()
416 {
417   if ( error )
418     return 0 ;
419
420   getBufferInfo () ;
421   
422   // HW buffer is 0xffff on my box
423   //return ainfo.play.buffer_size;
424   
425   return  1024 * 8;
426 }
427
428 void slDSP::getBufferInfo ()
429 {
430   if ( error )
431     return ;
432
433   if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) < 0)
434   {
435     perror ( "slDSP: getBufferInfo" ) ;
436     error = SL_TRUE ;
437     return ;
438   }
439     
440   if( ::ioctl( fd, AUDIO_GETOOFFS, &audio_offset ) < 0)
441   {
442     perror ( "slDSP: getBufferInfo" ) ;
443     error = SL_TRUE ;
444     return ;
445   }
446 }
447
448
449 void slDSP::write ( void *buffer, size_t length )
450 {
451   if ( error || length <= 0 )
452     return ;
453   
454   int nwritten = ::write ( fd, (const char *) buffer, length ) ;
455
456   if ( nwritten < 0 )
457     perror ( "slDSP: write" ) ;
458   else if ( nwritten != length )
459       perror ( "slDSP: short write" ) ;
460       
461   counter ++; /* hmmm */
462 }
463
464
465 float slDSP::secondsRemaining ()
466 {
467     return 0.0f ;
468 }
469
470
471 float slDSP::secondsUsed ()
472 {
473   /*
474    * original formula from Steve:
475    * -----------------------------
476    *
477    * int samples_used = init_bytes - buff_info.bytes ;
478    *                    |            |
479    *                    |            +--- current available
480    *                    |                 space in bytes !
481    *                    +---------------- available space
482    *                                      when empty;
483    * 
484    * sample_used contains the number of bytes which are
485    * "used" or in the DSP "pipeline".
486    */
487
488
489   int samples_used;
490   
491   if ( error )
492     return 0.0f ;
493
494   getBufferInfo () ;
495
496   //This is wrong: this is the hw queue in the kernel !
497   //samples_used   = ainfo.play.buffer_size - audio_offset.offset ;
498
499   // This is: all data written minus where we are now in the queue
500   
501   if ( counter == 0 )
502       return 0.0;
503
504   samples_used = ( counter * init_bytes ) - audio_offset.samples;
505   
506   if (  stereo   ) samples_used /= 2 ;
507   if ( bps == 16 ) samples_used /= 2 ;
508
509   return   (float) samples_used / (float) rate ;
510 }
511
512
513 void slDSP::sync ()
514
515    if ( !error) ::ioctl ( fd, AUDIO_FLUSH , 0 ) ; 
516 }
517
518 void slDSP::stop ()
519
520    // nothing found yet 
521 }
522
523 /* ------------------------------------------------------------ */
524 /* SGI IRIX audio                                               */
525 /* ------------------------------------------------------------ */
526
527 #elif defined(sgi)
528
529 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
530 {
531   if ( _bps != 8 )
532   {
533     perror ( "slDSP: supports only 8bit audio for sgi" ) ;
534     error = SL_TRUE;
535     return;
536   }
537
538   init_bytes = 1024 * 8;
539
540   config  = ALnewconfig();
541   
542   ALsetchannels (  config, _stereo ? AL_STEREO : AL_MONO );
543   ALsetwidth    (  config, _bps == 8 ? AL_SAMPLE_8 : AL_SAMPLE_16 );
544   ALsetqueuesize(  config, init_bytes );
545
546   port = ALopenport( device, "w", config );
547     
548   if ( port == NULL )
549   {
550     perror ( "slDSP: open" ) ;
551     error = SL_TRUE ;
552   }
553   else
554   {    
555     long params[2] = {AL_OUTPUT_RATE, 0 };
556
557     params[1] = _rate;
558
559     if ( ALsetparams(AL_DEFAULT_DEVICE, params, 2) != 0 )
560         {
561        perror ( "slDSP: open - ALsetparams" ) ;
562        error = SL_TRUE ;
563        return;
564         }
565   
566     rate    = _rate;
567     stereo  = _stereo;
568     bps     = _bps;
569
570     error = SL_FALSE ;
571
572   }
573 }
574
575
576 void slDSP::close ()
577 {
578   if ( port != NULL )
579   {
580      ALcloseport ( port   );
581      ALfreeconfig( config );
582      port = NULL;
583   }
584 }
585
586
587 int slDSP::getDriverBufferSize ()
588 {
589   if ( error )
590     return 0 ;
591
592   return  ALgetqueuesize( config );
593 }
594
595 void slDSP::getBufferInfo ()
596 {
597   if ( error )
598     return ;
599 }
600
601
602 void slDSP::write ( void *buffer, size_t length )
603 {
604   char *buf = (char *)buffer;
605   int  i;
606
607   if ( error || length <= 0 )
608     return ;
609
610   // Steve: is this a problem ??
611
612   for ( i = 0; i < length; i ++ )
613     buf[i] = buf[i] >> 1;
614
615   ALwritesamps(port, (void *)buf, length );
616 }
617
618
619 float slDSP::secondsRemaining ()
620 {
621   int   samples_remain;
622
623   if ( error )
624     return 0.0f ;
625
626   samples_remain = ALgetfillable(port);
627
628   if (  stereo   ) samples_remain /= 2 ;
629   if ( bps == 16 ) samples_remain /= 2 ;
630
631   return   (float) samples_remain / (float) rate ;
632 }
633
634
635 float slDSP::secondsUsed ()
636 {
637   int   samples_used;
638   
639   if ( error )
640     return 0.0f ;
641
642   samples_used = ALgetfilled(port);
643
644   if (  stereo   ) samples_used /= 2 ;
645   if ( bps == 16 ) samples_used /= 2 ;
646
647   return   (float) samples_used / (float) rate ;
648 }
649
650
651 void slDSP::sync ()
652
653    if ( error )
654      return ;
655
656   /* found this in the header file - but no description
657    * or example for the long parameter.
658    */
659
660   // ALflush(ALport, long);
661 }
662
663 void slDSP::stop ()
664
665 }
666
667
668 #endif
669