snes9x/gtk/src/gtk_sound_driver_oss.cpp

239 lines
5.0 KiB
C++
Raw Normal View History

2010-09-25 17:46:12 +02:00
#include "gtk_s9x.h"
#include "gtk_sound_driver_oss.h"
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <fcntl.h>
static void
oss_samples_available (void *data)
{
((S9xOSSSoundDriver *) data)->samples_available ();
}
S9xOSSSoundDriver::S9xOSSSoundDriver (void)
{
filedes = -1;
sound_buffer = NULL;
sound_buffer_size = 0;
return;
}
void
S9xOSSSoundDriver::init (void)
{
return;
}
void
S9xOSSSoundDriver::terminate (void)
{
stop ();
S9xSetSamplesAvailableCallback (NULL, NULL);
if (filedes >= 0)
{
close (filedes);
}
if (sound_buffer)
{
free (sound_buffer);
sound_buffer = NULL;
}
return;
}
void
S9xOSSSoundDriver::start (void)
{
return;
}
void
S9xOSSSoundDriver::stop (void)
{
return;
}
bool8
S9xOSSSoundDriver::open_device (void)
{
int temp;
audio_buf_info info;
2010-09-25 17:46:12 +02:00
output_buffer_size = (gui_config->sound_buffer_size * Settings.SoundPlaybackRate) / 1000;
if (Settings.Stereo)
output_buffer_size *= 2;
if (Settings.SixteenBitSound)
output_buffer_size *= 2;
if (output_buffer_size < 256)
output_buffer_size = 256;
printf ("OSS sound driver initializing...\n");
printf (" --> (Device: /dev/dsp)...");
filedes = open ("/dev/dsp", O_WRONLY | O_NONBLOCK);
if (filedes < 0)
{
printf ("Failed\n --> (Device: /dev/dsp1)...");
filedes = open ("/dev/dsp1", O_WRONLY | O_NONBLOCK);
if (filedes < 0)
goto fail;
}
2010-09-25 17:46:12 +02:00
printf ("OK\n");
if (Settings.SixteenBitSound)
{
printf (" --> (Format: 16-bit)...");
temp = AFMT_S16_LE;
if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0)
goto close_fail;
}
else
{
printf (" --> (Format: 8-bit)...");
temp = AFMT_U8;
if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0)
goto close_fail;
}
printf ("OK\n");
if (Settings.Stereo)
{
temp = 2;
printf (" --> (Stereo)...");
}
else
{
temp = 1;
printf (" --> (Mono)...");
}
if (ioctl (filedes, SNDCTL_DSP_CHANNELS, &temp) < 0)
goto close_fail;
printf ("OK\n");
printf (" --> (Frequency: %d)...", Settings.SoundPlaybackRate);
if (ioctl (filedes, SNDCTL_DSP_SPEED, &Settings.SoundPlaybackRate) < 0)
goto close_fail;
printf ("OK\n");
/* OSS requires a power-of-two buffer size, first 16 bits are the number
* of fragments to generate, second 16 are the respective power-of-two. */
temp = (8 << 16) | (S9xSoundBase2log (output_buffer_size / 8));
if (ioctl (filedes, SNDCTL_DSP_SETFRAGMENT, &temp) < 0)
goto close_fail;
2010-09-25 17:46:12 +02:00
ioctl (filedes, SNDCTL_DSP_GETOSPACE, &info);
output_buffer_size = info.fragsize * info.fragstotal;
2010-09-25 17:46:12 +02:00
printf (" --> (Buffer size: %d bytes, %dms latency)...",
output_buffer_size,
(((output_buffer_size * 1000) >> (Settings.Stereo ? 1 : 0))
>> (Settings.SixteenBitSound ? 1 : 0))
/ (Settings.SoundPlaybackRate));
printf ("OK\n");
S9xSetSamplesAvailableCallback (oss_samples_available, this);
return TRUE;
close_fail:
close (filedes);
fail:
printf ("failed\n");
return FALSE;
}
void
S9xOSSSoundDriver::mix (void)
{
return;
}
void
S9xOSSSoundDriver::samples_available (void)
{
audio_buf_info info;
int samples_to_write;
int bytes_to_write;
int bytes_written;
ioctl (filedes, SNDCTL_DSP_GETOSPACE, &info);
if (Settings.DynamicRateControl)
{
S9xUpdateDynamicRate (info.bytes, output_buffer_size);
}
2010-09-25 17:46:12 +02:00
S9xFinalizeSamples ();
samples_to_write = S9xGetSampleCount ();
if (Settings.DynamicRateControl)
{
// Using rate control, we should always keep the emulator's sound buffers empty to
// maintain an accurate measurement.
if (samples_to_write > (info.bytes >> (Settings.SixteenBitSound ? 1 : 0)))
{
S9xClearSamples ();
return;
}
}
2010-09-25 17:46:12 +02:00
samples_to_write = MIN (info.bytes >> (Settings.SixteenBitSound ? 1 : 0),
samples_to_write);
if (samples_to_write < 0)
return;
if (sound_buffer_size < samples_to_write << (Settings.SixteenBitSound ? 1 : 0))
{
sound_buffer = (uint8 *) realloc (sound_buffer, samples_to_write << (Settings.SixteenBitSound ? 1 : 0));
sound_buffer_size = samples_to_write << (Settings.SixteenBitSound ? 1 : 0);
}
S9xMixSamples (sound_buffer, samples_to_write);
bytes_written = 0;
bytes_to_write = samples_to_write << (Settings.SixteenBitSound ? 1 : 0);
while (bytes_to_write > bytes_written)
{
int result;
result = write (filedes,
((char *) sound_buffer) + bytes_written,
bytes_to_write - bytes_written);
if (result < 0)
break;
bytes_written += result;
}
return;
}