]> git.mxchange.org Git - simgear.git/blob - src/slDSP.cxx
Temporary destructor patch until Steve can release next version of PUI.
[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    waveOutReset( hWaveOut );
340 }
341
342 /* ------------------------------------------------------------ */
343 /* OpenBSD 2.3 this should be very close to SUN Audio           */
344 /* ------------------------------------------------------------ */
345
346 #elif defined(__OpenBSD__)
347 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
348 {
349
350   counter = 0;
351   
352   fd = ::open ( device, O_RDWR ) ;
353     
354   if ( fd < 0 )
355   {
356     perror ( "slDSP: open" ) ;
357     error = SL_TRUE ;
358   }
359   else
360   {    
361   
362     if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) == -1)
363     {
364       perror("slDSP: open - getinfo");
365       stereo     = SL_FALSE ;
366       bps        =    8     ;
367       rate       =  8000    ;
368       init_bytes =    0     ;
369       
370       return;
371     }
372       
373     ainfo.play.sample_rate  = _rate;
374     ainfo.play.precision    = _bps;    
375     ainfo.play.channels     = _stereo ? 2 : 1;
376     
377     ainfo.play.encoding     = AUDIO_ENCODING_ULINEAR;
378
379     if( :: ioctl(fd, AUDIO_SETINFO, &ainfo) == -1)
380     {
381       perror("slDSP: open - setinfo");
382       stereo     = SL_FALSE ;
383       bps        =    8     ;
384       rate       =  8000    ;
385       init_bytes =    0     ;
386       return;
387     }
388
389     rate    = _rate;
390     stereo  = _stereo;
391     bps     = _bps;
392
393     error = SL_FALSE ;
394
395     getBufferInfo ();
396     
397     // I could not change the size, 
398     // so let's try this ...
399     
400     init_bytes = 1024 * 8;
401   }
402 }
403
404
405 void slDSP::close ()
406 {
407   if ( fd >= 0 )
408     ::close ( fd ) ;
409 }
410
411
412 int slDSP::getDriverBufferSize ()
413 {
414   if ( error )
415     return 0 ;
416
417   getBufferInfo () ;
418   
419   // HW buffer is 0xffff on my box
420   //return ainfo.play.buffer_size;
421   
422   return  1024 * 8;
423 }
424
425 void slDSP::getBufferInfo ()
426 {
427   if ( error )
428     return ;
429
430   if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) < 0)
431   {
432     perror ( "slDSP: getBufferInfo" ) ;
433     error = SL_TRUE ;
434     return ;
435   }
436     
437   if( ::ioctl( fd, AUDIO_GETOOFFS, &audio_offset ) < 0)
438   {
439     perror ( "slDSP: getBufferInfo" ) ;
440     error = SL_TRUE ;
441     return ;
442   }
443 }
444
445
446 void slDSP::write ( void *buffer, size_t length )
447 {
448   if ( error || length <= 0 )
449     return ;
450   
451   int nwritten = ::write ( fd, (const char *) buffer, length ) ;
452
453   if ( nwritten < 0 )
454     perror ( "slDSP: write" ) ;
455   else if ( nwritten != length )
456       perror ( "slDSP: short write" ) ;
457       
458   counter ++; /* hmmm */
459 }
460
461
462 float slDSP::secondsRemaining ()
463 {
464     return 0.0f ;
465 }
466
467
468 float slDSP::secondsUsed ()
469 {
470   /*
471    * original formula from Steve:
472    * -----------------------------
473    *
474    * int samples_used = init_bytes - buff_info.bytes ;
475    *                    |            |
476    *                    |            +--- current available
477    *                    |                 space in bytes !
478    *                    +---------------- available space
479    *                                      when empty;
480    * 
481    * sample_used contains the number of bytes which are
482    * "used" or in the DSP "pipeline".
483    */
484
485
486   int samples_used;
487   
488   if ( error )
489     return 0.0f ;
490
491   getBufferInfo () ;
492
493   //This is wrong: this is the hw queue in the kernel !
494   //samples_used   = ainfo.play.buffer_size - audio_offset.offset ;
495
496   // This is: all data written minus where we are now in the queue
497   
498   if ( counter == 0 )
499       return 0.0;
500
501   samples_used = ( counter * init_bytes ) - audio_offset.samples;
502   
503   if (  stereo   ) samples_used /= 2 ;
504   if ( bps == 16 ) samples_used /= 2 ;
505
506   return   (float) samples_used / (float) rate ;
507 }
508
509
510 void slDSP::sync ()
511
512    if ( !error) ::ioctl ( fd, AUDIO_FLUSH , 0 ) ; 
513 }
514
515 void slDSP::stop ()
516
517    // nothing found yet 
518 }
519
520 /* ------------------------------------------------------------ */
521 /* SGI IRIX audio                                               */
522 /* ------------------------------------------------------------ */
523
524 #elif defined(sgi)
525
526 void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
527 {
528   if ( _bps != 8 )
529   {
530     perror ( "slDSP: supports only 8bit audio for sgi" ) ;
531     error = SL_TRUE;
532     return;
533   }
534
535   init_bytes = 1024 * 8;
536
537   config  = ALnewconfig();
538   
539   ALsetchannels (  config, _stereo ? AL_STEREO : AL_MONO );
540   ALsetwidth    (  config, _bps == 8 ? AL_SAMPLE_8 : AL_SAMPLE_16 );
541   ALsetqueuesize(  config, init_bytes );
542
543   port = ALopenport( device, "w", config );
544     
545   if ( port == NULL )
546   {
547     perror ( "slDSP: open" ) ;
548     error = SL_TRUE ;
549   }
550   else
551   {    
552     long params[2] = {AL_OUTPUT_RATE, 0 };
553
554     params[1] = _rate;
555
556     if ( ALsetparams(AL_DEFAULT_DEVICE, params, 2) != 0 )
557         {
558        perror ( "slDSP: open - ALsetparams" ) ;
559        error = SL_TRUE ;
560        return;
561         }
562   
563     rate    = _rate;
564     stereo  = _stereo;
565     bps     = _bps;
566
567     error = SL_FALSE ;
568
569   }
570 }
571
572
573 void slDSP::close ()
574 {
575   if ( port != NULL )
576   {
577      ALcloseport ( port   );
578      ALfreeconfig( config );
579      port = NULL;
580   }
581 }
582
583
584 int slDSP::getDriverBufferSize ()
585 {
586   if ( error )
587     return 0 ;
588
589   return  ALgetqueuesize( config );
590 }
591
592 void slDSP::getBufferInfo ()
593 {
594   if ( error )
595     return ;
596 }
597
598
599 void slDSP::write ( void *buffer, size_t length )
600 {
601   char *buf = (char *)buffer;
602   int  i;
603
604   if ( error || length <= 0 )
605     return ;
606
607   // Steve: is this a problem ??
608
609   for ( i = 0; i < length; i ++ )
610     buf[i] = buf[i] >> 1;
611
612   ALwritesamps(port, (void *)buf, length );
613 }
614
615
616 float slDSP::secondsRemaining ()
617 {
618   int   samples_remain;
619
620   if ( error )
621     return 0.0f ;
622
623   samples_remain = ALgetfillable(port);
624
625   if (  stereo   ) samples_remain /= 2 ;
626   if ( bps == 16 ) samples_remain /= 2 ;
627
628   return   (float) samples_remain / (float) rate ;
629 }
630
631
632 float slDSP::secondsUsed ()
633 {
634   int   samples_used;
635   
636   if ( error )
637     return 0.0f ;
638
639   samples_used = ALgetfilled(port);
640
641   if (  stereo   ) samples_used /= 2 ;
642   if ( bps == 16 ) samples_used /= 2 ;
643
644   return   (float) samples_used / (float) rate ;
645 }
646
647
648 void slDSP::sync ()
649
650   /* found this in the header file - but no description
651    * or example for the long parameter.
652    */
653
654   // ALflush(ALport, long);
655 }
656
657 void slDSP::stop ()
658
659 }
660
661
662 #endif
663