bsnes/ruby/audio/oss.cpp
Tim Allen 7bf4cff946 Update to v094r22 release.
byuu says:

I fixed the hiro layout enable bug, so when you go to assign joypad
input, the window disables itself so your input doesn't mess with the
controls.

I added "reset" to the hotkeys, in case you feel like clearing all of
them at once.

I added device selection support and the ability to disable audio
synchronization (run > 60fps) to the ruby/OSS driver. This is exposed in
tomoko's configuration file.

I added checks to stringify so that assigning null char* strings to
nall::string won't cause crashes anymore (technically the crash was in
strlen(), which doesn't check for null strings, but whatever ... I'll do
the check myself.)

I hooked up BrowserDialog::folderSelect() to loading slotted media for
now. Tested it by loading a Game Boy game successfully through the Super
Game Boy. Definitely want to write a custom window for this though, that
looks more like the library dialog.

Remaining issues:
- finish slotted cart loader (SGB, BSX, ST)
- add DIP switch selection window (NSS) [I may end up punting this one
  to v096]
- add more configuration panels (video, audio, timing)
2015-05-30 21:40:07 +10:00

125 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
namespace ruby {
struct pAudioOSS {
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;
~pAudioOSS() {
term();
}
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 false;
}
auto set(const string& name, const any& value) -> bool {
if(name == Audio::Device) {
settings.device = any_cast<string>(value);
if(!settings.device) settings.device = "/dev/dsp";
return true;
}
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
updateSynchronization();
return true;
}
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
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 {
term();
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);
}
};
DeclareAudio(OSS)
};