Files
simgear/src/slDSP.cxx
1998-07-16 17:48:11 +00:00

664 lines
12 KiB
C++

#include "sl.h"
static int init_bytes ;
#ifdef SL_USING_OSS_AUDIO
/* ------------------------------------------------------------ */
/* OSSAUDIO - Linux, FreeBSD, etc */
/* ------------------------------------------------------------ */
void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
{
fd = ::open ( device, O_WRONLY ) ;
if ( fd < 0 )
{
perror ( "slDSP: open" ) ;
error = SL_TRUE ;
stereo = SL_FALSE ;
bps = 1 ;
rate = 8000 ;
init_bytes = 0 ;
}
else
{
error = SL_FALSE ;
/* Set up a driver fragment size of 1024 (ie 2^10) */
ioctl ( SNDCTL_DSP_SETFRAGMENT, 0x7FFF000A ) ;
stereo = ioctl ( SOUND_PCM_WRITE_CHANNELS, _stereo ? 2 : 1 ) >= 2 ;
bps = ioctl ( SOUND_PCM_WRITE_BITS, _bps ) ;
rate = ioctl ( SOUND_PCM_WRITE_RATE, _rate ) ;
getBufferInfo () ;
init_bytes = buff_info.bytes ;
}
}
void slDSP::close ()
{
if ( fd >= 0 )
::close ( fd ) ;
}
int slDSP::getDriverBufferSize ()
{
if ( error )
return 0 ;
getBufferInfo () ;
return buff_info.fragsize ;
}
void slDSP::getBufferInfo ()
{
if ( error )
return ;
if ( ::ioctl ( fd, SNDCTL_DSP_GETOSPACE, & buff_info ) < 0 )
{
perror ( "slDSP: getBufferInfo" ) ;
error = SL_TRUE ;
return ;
}
}
void slDSP::write ( void *buffer, size_t length )
{
if ( error || length <= 0 )
return ;
int nwritten = ::write ( fd, (const char *) buffer, length ) ;
if ( nwritten < 0 )
perror ( "slDSP: write" ) ;
else
if ( nwritten != length )
perror ( "slDSP: short write" ) ;
}
float slDSP::secondsRemaining ()
{
if ( error )
return 0.0f ;
getBufferInfo () ;
int samples_left = buff_info.fragments * buff_info.fragsize ;
if ( stereo ) samples_left /= 2 ;
if ( bps == 16 ) samples_left /= 2 ;
return (float) samples_left / (float) rate ;
}
float slDSP::secondsUsed ()
{
if ( error )
return 0.0f ;
getBufferInfo () ;
int samples_used = init_bytes - buff_info.bytes ;
if ( stereo ) samples_used /= 2 ;
if ( bps == 16 ) samples_used /= 2 ;
return (float) samples_used / (float) rate ;
}
void slDSP::sync ()
{
if ( !error) ::ioctl ( fd, SOUND_PCM_SYNC , 0 ) ;
}
void slDSP::stop ()
{
if ( !error) ::ioctl ( fd, SOUND_PCM_RESET, 0 ) ;
}
#endif
#ifdef WIN32
/* ------------------------------------------------------------ */
/* win32 */
/* ------------------------------------------------------------ */
static void wperror(MMRESULT num)
{
char buffer[0xff]; // yes, this is hardcoded :-)
waveOutGetErrorText( num, buffer, sizeof(buffer)-1);
fprintf( stderr, "SlDSP: %s\n", buffer );
fflush ( stderr );
}
void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg,
DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
switch( uMsg )
{
case WOM_CLOSE:
break;
case WOM_OPEN:
break;
case WOM_DONE:
waveOutUnprepareHeader( (HWAVEOUT)dwParam1,
(LPWAVEHDR)dwParam2, sizeof( WAVEHDR ));
break;
}
}
void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
{
MMRESULT result;
hWaveOut = NULL;
curr_header = 0;
counter = 0;
Format.wFormatTag = WAVE_FORMAT_PCM;
Format.nChannels = _stereo ? 2 : 1;
Format.nSamplesPerSec = _rate;
Format.wBitsPerSample = _bps;
Format.nBlockAlign = 1;
Format.nAvgBytesPerSec = _rate * Format.nChannels;
Format.cbSize = 0;
result = waveOutOpen( & hWaveOut, WAVE_MAPPER, & Format, NULL,
0L, WAVE_FORMAT_QUERY );
if ( result != MMSYSERR_NOERROR )
{
wperror( result);
error = SL_TRUE ;
stereo = SL_FALSE ;
bps = _bps ;
rate = _rate ;
init_bytes = 0 ;
return;
}
// Now the hwaveouthandle "should" be valid
if ( ( result = waveOutOpen( & hWaveOut, WAVE_MAPPER,
(WAVEFORMATEX *)& Format, (DWORD)waveOutProc,
0L, CALLBACK_FUNCTION )) != MMSYSERR_NOERROR )
{
wperror( result);
error = SL_TRUE ;
stereo = SL_FALSE ;
bps = _bps ;
rate = _rate ;
init_bytes = 0 ;
return;
}
else
{
error = SL_FALSE ;
stereo = _stereo;
bps = _bps;
rate = _rate;
/* hmm ?! */
init_bytes = 1024*8;
}
}
void slDSP::close ()
{
if ( hWaveOut != NULL )
{
waveOutClose( hWaveOut );
hWaveOut = NULL;
}
}
int slDSP::getDriverBufferSize ()
{
if ( error )
return 0 ;
/* hmm ?! */
return 1024*8;
}
void slDSP::getBufferInfo ()
{
return ;
}
void slDSP::write ( void *buffer, size_t length )
{
MMRESULT result;
if ( error || length <= 0 )
return ;
wavehdr[curr_header].lpData = (LPSTR) buffer;
wavehdr[curr_header].dwBufferLength = (long) length;
wavehdr[curr_header].dwBytesRecorded = 0L;
wavehdr[curr_header].dwUser = NULL;
wavehdr[curr_header].dwFlags = 0;
wavehdr[curr_header].dwLoops = 0;
wavehdr[curr_header].lpNext = NULL;
wavehdr[curr_header].reserved = 0;
result = waveOutPrepareHeader( hWaveOut, & wavehdr[curr_header],
sizeof(WAVEHDR));
if ( result != MMSYSERR_NOERROR )
{
wperror ( result );
error = SL_TRUE;
}
result = waveOutWrite(hWaveOut, & wavehdr[curr_header],
sizeof(WAVEHDR));
if ( result != MMSYSERR_NOERROR )
{
wperror ( result );
error = SL_TRUE;
}
counter ++;
curr_header = ( curr_header + 1 ) % 3;
}
float slDSP::secondsRemaining ()
{
if ( error )
return 0.0f ;
return 0.0f ;
}
float slDSP::secondsUsed ()
{
int samples_used;
MMRESULT result;
float samp_time;
if ( error )
return 0.0f ;
mmt.wType = TIME_BYTES;
result = waveOutGetPosition( hWaveOut, &mmt, sizeof( mmt ));
if ( mmt.u.cb == 0 || counter == 0)
return (float)0.0;
samples_used = ( init_bytes * counter ) - mmt.u.cb;
if ( stereo ) samples_used /= 2 ;
if ( bps == 16 ) samples_used /= 2 ;
samp_time = (float) samples_used / (float) rate ;
//printf("%0.2f position=%ld total written=%ld\n",
// samp_time, mmt.u.cb, init_bytes * counter );
return samp_time;
}
void slDSP::sync ()
{
}
void slDSP::stop ()
{
waveOutReset( hWaveOut );
}
/* ------------------------------------------------------------ */
/* OpenBSD 2.3 this should be very close to SUN Audio */
/* ------------------------------------------------------------ */
#elif defined(__OpenBSD__)
void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
{
counter = 0;
fd = ::open ( device, O_RDWR ) ;
if ( fd < 0 )
{
perror ( "slDSP: open" ) ;
error = SL_TRUE ;
}
else
{
if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) == -1)
{
perror("slDSP: open - getinfo");
stereo = SL_FALSE ;
bps = 8 ;
rate = 8000 ;
init_bytes = 0 ;
return;
}
ainfo.play.sample_rate = _rate;
ainfo.play.precision = _bps;
ainfo.play.channels = _stereo ? 2 : 1;
ainfo.play.encoding = AUDIO_ENCODING_ULINEAR;
if( :: ioctl(fd, AUDIO_SETINFO, &ainfo) == -1)
{
perror("slDSP: open - setinfo");
stereo = SL_FALSE ;
bps = 8 ;
rate = 8000 ;
init_bytes = 0 ;
return;
}
rate = _rate;
stereo = _stereo;
bps = _bps;
error = SL_FALSE ;
getBufferInfo ();
// I could not change the size,
// so let's try this ...
init_bytes = 1024 * 8;
}
}
void slDSP::close ()
{
if ( fd >= 0 )
::close ( fd ) ;
}
int slDSP::getDriverBufferSize ()
{
if ( error )
return 0 ;
getBufferInfo () ;
// HW buffer is 0xffff on my box
//return ainfo.play.buffer_size;
return 1024 * 8;
}
void slDSP::getBufferInfo ()
{
if ( error )
return ;
if( ::ioctl( fd, AUDIO_GETINFO, &ainfo) < 0)
{
perror ( "slDSP: getBufferInfo" ) ;
error = SL_TRUE ;
return ;
}
if( ::ioctl( fd, AUDIO_GETOOFFS, &audio_offset ) < 0)
{
perror ( "slDSP: getBufferInfo" ) ;
error = SL_TRUE ;
return ;
}
}
void slDSP::write ( void *buffer, size_t length )
{
if ( error || length <= 0 )
return ;
int nwritten = ::write ( fd, (const char *) buffer, length ) ;
if ( nwritten < 0 )
perror ( "slDSP: write" ) ;
else if ( nwritten != length )
perror ( "slDSP: short write" ) ;
counter ++; /* hmmm */
}
float slDSP::secondsRemaining ()
{
return 0.0f ;
}
float slDSP::secondsUsed ()
{
/*
* original formula from Steve:
* -----------------------------
*
* int samples_used = init_bytes - buff_info.bytes ;
* | |
* | +--- current available
* | space in bytes !
* +---------------- available space
* when empty;
*
* sample_used contains the number of bytes which are
* "used" or in the DSP "pipeline".
*/
int samples_used;
if ( error )
return 0.0f ;
getBufferInfo () ;
//This is wrong: this is the hw queue in the kernel !
//samples_used = ainfo.play.buffer_size - audio_offset.offset ;
// This is: all data written minus where we are now in the queue
if ( counter == 0 )
return 0.0;
samples_used = ( counter * init_bytes ) - audio_offset.samples;
if ( stereo ) samples_used /= 2 ;
if ( bps == 16 ) samples_used /= 2 ;
return (float) samples_used / (float) rate ;
}
void slDSP::sync ()
{
if ( !error) ::ioctl ( fd, AUDIO_FLUSH , 0 ) ;
}
void slDSP::stop ()
{
// nothing found yet
}
/* ------------------------------------------------------------ */
/* SGI IRIX audio */
/* ------------------------------------------------------------ */
#elif defined(sgi)
void slDSP::open ( char *device, int _rate, int _stereo, int _bps )
{
if ( _bps != 8 )
{
perror ( "slDSP: supports only 8bit audio for sgi" ) ;
error = SL_TRUE;
return;
}
init_bytes = 1024 * 8;
config = ALnewconfig();
ALsetchannels ( config, _stereo ? AL_STEREO : AL_MONO );
ALsetwidth ( config, _bps == 8 ? AL_SAMPLE_8 : AL_SAMPLE_16 );
ALsetqueuesize( config, init_bytes );
port = ALopenport( device, "w", config );
if ( port == NULL )
{
perror ( "slDSP: open" ) ;
error = SL_TRUE ;
}
else
{
long params[2] = {AL_OUTPUT_RATE, 0 };
params[1] = _rate;
if ( ALsetparams(AL_DEFAULT_DEVICE, params, 2) != 0 )
{
perror ( "slDSP: open - ALsetparams" ) ;
error = SL_TRUE ;
return;
}
rate = _rate;
stereo = _stereo;
bps = _bps;
error = SL_FALSE ;
}
}
void slDSP::close ()
{
if ( port != NULL )
{
ALcloseport ( port );
ALfreeconfig( config );
port = NULL;
}
}
int slDSP::getDriverBufferSize ()
{
if ( error )
return 0 ;
return ALgetqueuesize( config );
}
void slDSP::getBufferInfo ()
{
if ( error )
return ;
}
void slDSP::write ( void *buffer, size_t length )
{
char *buf = (char *)buffer;
int i;
if ( error || length <= 0 )
return ;
// Steve: is this a problem ??
for ( i = 0; i < length; i ++ )
buf[i] = buf[i] >> 1;
ALwritesamps(port, (void *)buf, length );
}
float slDSP::secondsRemaining ()
{
int samples_remain;
if ( error )
return 0.0f ;
samples_remain = ALgetfillable(port);
if ( stereo ) samples_remain /= 2 ;
if ( bps == 16 ) samples_remain /= 2 ;
return (float) samples_remain / (float) rate ;
}
float slDSP::secondsUsed ()
{
int samples_used;
if ( error )
return 0.0f ;
samples_used = ALgetfilled(port);
if ( stereo ) samples_used /= 2 ;
if ( bps == 16 ) samples_used /= 2 ;
return (float) samples_used / (float) rate ;
}
void slDSP::sync ()
{
/* found this in the header file - but no description
* or example for the long parameter.
*/
// ALflush(ALport, long);
}
void slDSP::stop ()
{
}
#endif