snes9x/gtk/src/gtk_sound_driver_oss.cpp

179 lines
3.8 KiB
C++
Raw Normal View History

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
2010-09-25 17:46:12 +02:00
#include "gtk_sound_driver_oss.h"
#include <fcntl.h>
2010-09-25 17:46:12 +02:00
#include <sys/ioctl.h>
#include <sys/soundcard.h>
2010-09-25 17:46:12 +02:00
#include <sys/time.h>
#include <unistd.h>
2010-09-25 17:46:12 +02:00
S9xOSSSoundDriver::S9xOSSSoundDriver()
2010-09-25 17:46:12 +02:00
{
filedes = -1;
}
void S9xOSSSoundDriver::init()
2010-09-25 17:46:12 +02:00
{
}
void S9xOSSSoundDriver::deinit()
2010-09-25 17:46:12 +02:00
{
stop();
2010-09-25 17:46:12 +02:00
if (filedes >= 0)
{
close(filedes);
2010-09-25 17:46:12 +02:00
}
}
void S9xOSSSoundDriver::start()
2010-09-25 17:46:12 +02:00
{
}
void S9xOSSSoundDriver::stop()
2010-09-25 17:46:12 +02:00
{
}
bool S9xOSSSoundDriver::open_device(int playback_rate, int buffer_size_ms)
2010-09-25 17:46:12 +02:00
{
int temp;
audio_buf_info info;
2010-09-25 17:46:12 +02:00
output_buffer_size_bytes = (buffer_size_ms * playback_rate) / 1000;
2010-09-25 17:46:12 +02:00
output_buffer_size_bytes *= 4;
if (output_buffer_size_bytes < 256)
output_buffer_size_bytes = 256;
2010-09-25 17:46:12 +02:00
printf("OSS sound driver initializing...\n");
2010-09-25 17:46:12 +02:00
printf("Device: /dev/dsp: ");
2010-09-25 17:46:12 +02:00
filedes = open("/dev/dsp", O_WRONLY | O_NONBLOCK);
2010-09-25 17:46:12 +02:00
if (filedes < 0)
{
printf("Failed.\n");
2018-11-08 22:12:47 +01:00
char dspstring[16] = "/dev/dspX\0";
for (int i = 1; i <= 9; i++)
{
dspstring[8] = '0' + i;
printf("Trying %s: ", dspstring);
2018-11-08 22:12:47 +01:00
filedes = open(dspstring, O_WRONLY | O_NONBLOCK);
2018-11-08 22:12:47 +01:00
if (filedes < 0)
{
if (i == 9)
goto fail;
printf("Failed.\n");
2018-11-08 22:12:47 +01:00
}
else
break;
}
}
2010-09-25 17:46:12 +02:00
printf("OK\n");
2010-09-25 17:46:12 +02:00
printf(" --> (Format: 16-bit)...");
2010-09-25 17:46:12 +02:00
temp = AFMT_S16_LE;
if (ioctl(filedes, SNDCTL_DSP_SETFMT, &temp) < 0)
goto close_fail;
2010-09-25 17:46:12 +02:00
printf("OK\n");
2010-09-25 17:46:12 +02:00
temp = 2;
printf(" --> (Stereo)...");
2010-09-25 17:46:12 +02:00
if (ioctl(filedes, SNDCTL_DSP_CHANNELS, &temp) < 0)
2010-09-25 17:46:12 +02:00
goto close_fail;
printf("OK\n");
2010-09-25 17:46:12 +02:00
printf(" --> (Frequency: %d)...", playback_rate);
if (ioctl(filedes, SNDCTL_DSP_SPEED, &playback_rate) < 0)
2010-09-25 17:46:12 +02:00
goto close_fail;
printf("OK\n");
2010-09-25 17:46:12 +02:00
/* 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 = (4 << 16) | (S9xSoundBase2log(output_buffer_size_bytes / 4));
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_bytes = info.fragsize * info.fragstotal;
2010-09-25 17:46:12 +02:00
printf(" --> (Buffer size: %d bytes, %dms latency)...",
output_buffer_size_bytes,
(output_buffer_size_bytes * 250) / playback_rate);
2010-09-25 17:46:12 +02:00
printf("OK\n");
2010-09-25 17:46:12 +02:00
return true;
2010-09-25 17:46:12 +02:00
close_fail:
close(filedes);
2010-09-25 17:46:12 +02:00
fail:
printf("failed\n");
2010-09-25 17:46:12 +02:00
return false;
2010-09-25 17:46:12 +02:00
}
int S9xOSSSoundDriver::space_free()
2010-09-25 17:46:12 +02:00
{
audio_buf_info info;
ioctl(filedes, SNDCTL_DSP_GETOSPACE, &info);
return info.bytes / 2;
}
std::pair<int, int> S9xOSSSoundDriver::buffer_level()
{
return { space_free(), output_buffer_size_bytes / 2};
}
void S9xOSSSoundDriver::write_samples(int16_t *data, int samples)
{
audio_buf_info info;
int bytes_to_write;
int bytes_written;
2010-09-25 17:46:12 +02:00
ioctl(filedes, SNDCTL_DSP_GETOSPACE, &info);
2010-09-25 17:46:12 +02:00
if (samples > info.bytes / 2)
samples = info.bytes / 2;
2010-09-25 17:46:12 +02:00
if (samples == 0)
2010-09-25 17:46:12 +02:00
return;
bytes_written = 0;
bytes_to_write = samples * 2;
2010-09-25 17:46:12 +02:00
while (bytes_to_write > bytes_written)
{
int result;
result = write(filedes,
((char *)data) + bytes_written,
bytes_to_write - bytes_written);
2010-09-25 17:46:12 +02:00
if (result < 0)
break;
bytes_written += result;
}
}