bsnes/ruby/audio/oss.cpp

116 lines
3.3 KiB
C++
Raw Normal View History

#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;
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
return {};
}
auto set(const string& name, const any& value) -> bool {
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
if(name == Audio::Device && value.is<string>()) {
settings.device = value.get<string>();
if(!settings.device) settings.device = "/dev/dsp";
return true;
}
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
if(name == Audio::Synchronize && value.is<bool>()) {
settings.synchronize = value.get<bool>();
updateSynchronization();
return true;
}
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
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);
}
};