mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-24 07:02:27 +01:00
byuu says: This WIP substantially restructures the ruby API for the first time since that project started. It is my hope that with this restructuring, destruction of the ruby objects should now be deterministic, which should fix the crashing on closing the emulator on Linux. We'll see I guess ... either way, it removed two layers of wrappers from ruby, so it's a pretty nice code cleanup. It won't compile on Windows due to a few issues I didn't see until uploading the WIP, too lazy to upload another. But I fixed all the compilation issues locally, so it'll work on Windows again with the next WIP (unless I break something else.) (Kind of annoying that Linux defines glActiveTexture but Windows doesn't.)
116 lines
3.3 KiB
C++
116 lines
3.3 KiB
C++
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/soundcard.h>
|
|
|
|
//OSS4 soundcard.h includes below SNDCTL defines, but OSS3 does not
|
|
//However, OSS4 soundcard.h does not reside in <sys/>
|
|
//Therefore, attempt to manually define SNDCTL values if using OSS3 header
|
|
//Note that if the defines below fail to work on any specific platform, one can point soundcard.h
|
|
//above to the correct location for OSS4 (usually /usr/lib/oss/include/sys/soundcard.h)
|
|
//Failing that, one can disable OSS4 ioctl calls inside init() and remove the below defines
|
|
|
|
#ifndef SNDCTL_DSP_COOKEDMODE
|
|
#define SNDCTL_DSP_COOKEDMODE _IOW('P', 30, signed)
|
|
#endif
|
|
|
|
#ifndef SNDCTL_DSP_POLICY
|
|
#define SNDCTL_DSP_POLICY _IOW('P', 45, signed)
|
|
#endif
|
|
|
|
struct AudioOSS : Audio {
|
|
~AudioOSS() { term(); }
|
|
|
|
struct {
|
|
signed fd = -1;
|
|
signed format = AFMT_S16_LE;
|
|
signed channels = 2;
|
|
} device;
|
|
|
|
struct {
|
|
string device = "/dev/dsp";
|
|
bool synchronize = true;
|
|
unsigned frequency = 22050;
|
|
} settings;
|
|
|
|
auto cap(const string& name) -> bool {
|
|
if(name == Audio::Device) return true;
|
|
if(name == Audio::Synchronize) return true;
|
|
if(name == Audio::Frequency) return true;
|
|
return false;
|
|
}
|
|
|
|
auto get(const string& name) -> any {
|
|
if(name == Audio::Device) return settings.device;
|
|
if(name == Audio::Synchronize) return settings.synchronize;
|
|
if(name == Audio::Frequency) return settings.frequency;
|
|
return {};
|
|
}
|
|
|
|
auto set(const string& name, const any& value) -> bool {
|
|
if(name == Audio::Device && value.is<string>()) {
|
|
settings.device = value.get<string>();
|
|
if(!settings.device) settings.device = "/dev/dsp";
|
|
return true;
|
|
}
|
|
|
|
if(name == Audio::Synchronize && value.is<bool>()) {
|
|
settings.synchronize = value.get<bool>();
|
|
updateSynchronization();
|
|
return true;
|
|
}
|
|
|
|
if(name == Audio::Frequency && value.is<unsigned>()) {
|
|
settings.frequency = value.get<unsigned>();
|
|
if(device.fd >= 0) init();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto sample(uint16_t left, uint16_t right) -> void {
|
|
uint32_t sample = left << 0 | right << 16;
|
|
auto unused = write(device.fd, &sample, 4);
|
|
}
|
|
|
|
auto clear() -> void {
|
|
}
|
|
|
|
auto init() -> bool {
|
|
device.fd = open(settings.device, O_WRONLY, O_NONBLOCK);
|
|
if(device.fd < 0) return false;
|
|
|
|
#if 1 //SOUND_VERSION >= 0x040000
|
|
//attempt to enable OSS4-specific features regardless of version
|
|
//OSS3 ioctl calls will silently fail, but sound will still work
|
|
signed cooked = 1, policy = 4; //policy should be 0 - 10, lower = less latency, more CPU usage
|
|
ioctl(device.fd, SNDCTL_DSP_COOKEDMODE, &cooked);
|
|
ioctl(device.fd, SNDCTL_DSP_POLICY, &policy);
|
|
#endif
|
|
signed freq = settings.frequency;
|
|
ioctl(device.fd, SNDCTL_DSP_CHANNELS, &device.channels);
|
|
ioctl(device.fd, SNDCTL_DSP_SETFMT, &device.format);
|
|
ioctl(device.fd, SNDCTL_DSP_SPEED, &freq);
|
|
|
|
updateSynchronization();
|
|
return true;
|
|
}
|
|
|
|
auto term() -> void {
|
|
if(device.fd >= 0) {
|
|
close(device.fd);
|
|
device.fd = -1;
|
|
}
|
|
}
|
|
|
|
private:
|
|
auto updateSynchronization() -> void {
|
|
if(device.fd < 0) return;
|
|
auto flags = fcntl(device.fd, F_GETFL);
|
|
if(flags < 0) return;
|
|
settings.synchronize ? flags &=~ O_NONBLOCK : flags |= O_NONBLOCK;
|
|
fcntl(device.fd, F_SETFL, flags);
|
|
}
|
|
};
|