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)
This commit is contained in:
Tim Allen 2015-05-25 22:23:49 +10:00
parent 99b2b4b57c
commit 7bf4cff946
21 changed files with 280 additions and 250 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "094.21";
static const char Version[] = "094.22";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";

View File

@ -31,7 +31,7 @@ auto mFixedLayout::reset() -> type& {
auto mFixedLayout::setEnabled(bool enabled) -> type& {
mLayout::setEnabled(enabled);
for(auto n : range(sizables())) {
sizable(n)->setEnabled(sizable(n)->enabled(true));
sizable(n)->setEnabled(sizable(n)->enabled());
}
return *this;
}
@ -39,7 +39,7 @@ auto mFixedLayout::setEnabled(bool enabled) -> type& {
auto mFixedLayout::setFont(const string& font) -> type& {
mLayout::setFont(font);
for(auto n : range(sizables())) {
sizable(n)->setFont(sizable(n)->font(true));
sizable(n)->setFont(sizable(n)->font());
}
return *this;
}
@ -47,7 +47,7 @@ auto mFixedLayout::setFont(const string& font) -> type& {
auto mFixedLayout::setVisible(bool visible) -> type& {
mLayout::setVisible(visible);
for(auto n : range(sizables())) {
sizable(n)->setVisible(sizable(n)->visible(true));
sizable(n)->setVisible(sizable(n)->visible());
}
return *this;
}

View File

@ -51,7 +51,7 @@ auto mHorizontalLayout::setAlignment(double alignment) -> type& {
auto mHorizontalLayout::setEnabled(bool enabled) -> type& {
mLayout::setEnabled(enabled);
for(auto n : range(sizables())) {
sizable(n)->setEnabled(sizable(n)->enabled(true));
sizable(n)->setEnabled(sizable(n)->enabled());
}
return *this;
}
@ -59,7 +59,7 @@ auto mHorizontalLayout::setEnabled(bool enabled) -> type& {
auto mHorizontalLayout::setFont(const string& font) -> type& {
mLayout::setFont(font);
for(auto n : range(sizables())) {
sizable(n)->setFont(sizable(n)->font(true));
sizable(n)->setFont(sizable(n)->font());
}
return *this;
}
@ -121,7 +121,7 @@ auto mHorizontalLayout::setSpacing(signed spacing) -> type& {
auto mHorizontalLayout::setVisible(bool visible) -> type& {
mLayout::setVisible(visible);
for(auto n : range(sizables())) {
sizable(n)->setVisible(sizable(n)->visible(true));
sizable(n)->setVisible(sizable(n)->visible());
}
return *this;
}

View File

@ -51,7 +51,7 @@ auto mVerticalLayout::setAlignment(double alignment) -> type& {
auto mVerticalLayout::setEnabled(bool enabled) -> type& {
mLayout::setEnabled(enabled);
for(auto n : range(sizables())) {
sizable(n)->setEnabled(sizable(n)->enabled(true));
sizable(n)->setEnabled(sizable(n)->enabled());
}
return *this;
}
@ -59,7 +59,7 @@ auto mVerticalLayout::setEnabled(bool enabled) -> type& {
auto mVerticalLayout::setFont(const string& font) -> type& {
mLayout::setFont(font);
for(auto n : range(sizables())) {
sizable(n)->setFont(sizable(n)->font(true));
sizable(n)->setFont(sizable(n)->font());
}
return *this;
}
@ -123,7 +123,7 @@ auto mVerticalLayout::setSpacing(signed spacing) -> type& {
auto mVerticalLayout::setVisible(bool visible) -> type& {
mLayout::setVisible(visible);
for(auto n : range(sizables())) {
sizable(n)->setVisible(sizable(n)->visible(true));
sizable(n)->setVisible(sizable(n)->visible());
}
return *this;
}

View File

@ -11,21 +11,12 @@ auto pLayout::destruct() -> void {
}
auto pLayout::setEnabled(bool enabled) -> void {
for(auto& sizable : state().sizables) {
if(sizable->self()) sizable->self()->setEnabled(sizable->enabled(true));
}
}
auto pLayout::setFont(const string& font) -> void {
for(auto& sizable : state().sizables) {
if(sizable->self()) sizable->self()->setFont(sizable->font(true));
}
}
auto pLayout::setVisible(bool visible) -> void {
for(auto& sizable : state().sizables) {
if(sizable->self()) sizable->self()->setVisible(sizable->visible(true));
}
}
}

View File

@ -160,14 +160,14 @@ template<> struct stringify<char*> {
const char* _data;
auto data() const -> const char* { return _data; }
auto size() const -> unsigned { return strlen(_data); }
stringify(char* source) : _data(source) {}
stringify(char* source) : _data(source ? source : "") {}
};
template<> struct stringify<const char*> {
const char* _data;
auto data() const -> const char* { return _data; }
auto size() const -> unsigned { return strlen(_data); }
stringify(const char* source) : _data(source) {}
stringify(const char* source) : _data(source ? source : "") {}
};
//strings

View File

@ -1,18 +1,19 @@
struct Audio {
static const char* Handle;
static const char* Synchronize;
static const char* Frequency;
static const char* Latency;
static const nall::string Device;
static const nall::string Handle;
static const nall::string Synchronize;
static const nall::string Frequency;
static const nall::string Latency;
virtual bool cap(const nall::string& name) { return false; }
virtual nall::any get(const nall::string& name) { return false; }
virtual bool set(const nall::string& name, const nall::any& value) { return false; }
virtual ~Audio() = default;
virtual void sample(uint16_t left, uint16_t right) {}
virtual void clear() {}
virtual bool init() { return true; }
virtual void term() {}
virtual auto cap(const nall::string& name) -> bool { return false; }
virtual auto get(const nall::string& name) -> nall::any { return false; }
virtual auto set(const nall::string& name, const nall::any& value) -> bool { return false; }
Audio() {}
virtual ~Audio() {}
virtual auto sample(uint16_t left, uint16_t right) -> void {}
virtual auto clear() -> void {}
virtual auto init() -> bool { return true; }
virtual auto term() -> void {}
};

View File

@ -1,9 +1,3 @@
/*
audio.openal (2007-12-26)
author: Nach
contributors: byuu, wertigon, _willow_
*/
#if defined(PLATFORM_MACOSX)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
@ -14,15 +8,14 @@
namespace ruby {
class pAudioOpenAL {
public:
struct pAudioOpenAL {
struct {
ALCdevice* handle;
ALCcontext* context;
ALuint source;
ALenum format;
unsigned latency;
unsigned queue_length;
unsigned queueLength;
} device;
struct {
@ -37,21 +30,21 @@ public:
unsigned latency;
} settings;
bool cap(const string& name) {
auto cap(const string& name) -> bool {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
any get(const string& name) {
auto get(const string& name) -> any {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
return false;
}
bool set(const string& name, const any& value) {
auto set(const string& name, const any& value) -> bool {
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
return true;
@ -65,7 +58,7 @@ public:
if(name == Audio::Latency) {
if(settings.latency != any_cast<unsigned>(value)) {
settings.latency = any_cast<unsigned>(value);
update_latency();
updateLatency();
}
return true;
}
@ -73,7 +66,7 @@ public:
return false;
}
void sample(uint16_t sl, uint16_t sr) {
auto sample(uint16_t sl, uint16_t sr) -> void {
buffer.data[buffer.length++] = sl + (sr << 16);
if(buffer.length < buffer.size) return;
@ -84,17 +77,17 @@ public:
while(processed--) {
alSourceUnqueueBuffers(device.source, 1, &albuffer);
alDeleteBuffers(1, &albuffer);
device.queue_length--;
device.queueLength--;
}
//wait for buffer playback to catch up to sample generation if not synchronizing
if(settings.synchronize == false || device.queue_length < 3) break;
if(settings.synchronize == false || device.queueLength < 3) break;
}
if(device.queue_length < 3) {
if(device.queueLength < 3) {
alGenBuffers(1, &albuffer);
alBufferData(albuffer, device.format, buffer.data, buffer.size * 4, settings.frequency);
alSourceQueueBuffers(device.source, 1, &albuffer);
device.queue_length++;
device.queueLength++;
}
ALint playing;
@ -103,22 +96,16 @@ public:
buffer.length = 0;
}
void clear() {
auto clear() -> void {
}
void update_latency() {
if(buffer.data) delete[] buffer.data;
buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
buffer.data = new uint32_t[buffer.size];
}
bool init() {
update_latency();
device.queue_length = 0;
auto init() -> bool {
updateLatency();
device.queueLength = 0;
bool success = false;
if(device.handle = alcOpenDevice(NULL)) {
if(device.context = alcCreateContext(device.handle, NULL)) {
if(device.handle = alcOpenDevice(nullptr)) {
if(device.context = alcCreateContext(device.handle, nullptr)) {
alcMakeContextCurrent(device.context);
alGenSources(1, &device.source);
@ -147,7 +134,7 @@ public:
return true;
}
void term() {
auto term() -> void {
if(alIsSource(device.source) == AL_TRUE) {
int playing = 0;
alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
@ -159,7 +146,7 @@ public:
ALuint albuffer = 0;
alSourceUnqueueBuffers(device.source, 1, &albuffer);
alDeleteBuffers(1, &albuffer);
device.queue_length--;
device.queueLength--;
}
}
@ -168,7 +155,7 @@ public:
}
if(device.context) {
alcMakeContextCurrent(NULL);
alcMakeContextCurrent(nullptr);
alcDestroyContext(device.context);
device.context = 0;
}
@ -189,7 +176,7 @@ public:
device.handle = 0;
device.context = 0;
device.format = AL_FORMAT_STEREO16;
device.queue_length = 0;
device.queueLength = 0;
buffer.data = 0;
buffer.length = 0;
@ -203,6 +190,27 @@ public:
~pAudioOpenAL() {
term();
}
private:
auto queryDevices() -> lstring {
lstring result;
const char* buffer = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
if(!buffer) return result;
while(buffer[0] || buffer[1]) {
result.append(buffer);
while(buffer[0]) buffer++;
}
return result;
}
auto updateLatency() -> void {
if(buffer.data) delete[] buffer.data;
buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
buffer.data = new uint32_t[buffer.size]();
}
};
DeclareAudio(OpenAL)

View File

@ -1,8 +1,3 @@
/*
audio.oss (2007-12-26)
author: Nach
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
@ -16,95 +11,112 @@
//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, int)
#define SNDCTL_DSP_COOKEDMODE _IOW('P', 30, signed)
#endif
#ifndef SNDCTL_DSP_POLICY
#define SNDCTL_DSP_POLICY _IOW('P', 45, int)
#define SNDCTL_DSP_POLICY _IOW('P', 45, signed)
#endif
namespace ruby {
class pAudioOSS {
public:
struct pAudioOSS {
struct {
int fd;
int format;
int channels;
const char* name;
signed fd = -1;
signed format = AFMT_S16_LE;
signed channels = 2;
} device;
struct {
unsigned frequency;
string device = "/dev/dsp";
bool synchronize = true;
unsigned frequency = 22050;
} settings;
bool cap(const string& name) {
~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;
}
any get(const string& name) {
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;
}
bool set(const string& name, const any& value) {
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();
if(device.fd >= 0) init();
return true;
}
return false;
}
void sample(uint16_t sl, uint16_t sr) {
uint32_t sample = sl + (sr << 16);
unsigned unused = write(device.fd, &sample, 4);
auto sample(uint16_t left, uint16_t right) -> void {
uint32_t sample = left << 0 | right << 16;
auto unused = write(device.fd, &sample, 4);
}
void clear() {
auto clear() -> void {
}
bool init() {
auto init() -> bool {
term();
device.fd = open(device.name, O_WRONLY, O_NONBLOCK);
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
int cooked = 1, policy = 4; //policy should be 0 - 10, lower = less latency, more CPU usage
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
int freq = settings.frequency;
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;
}
void term() {
if(device.fd > 0) {
auto term() -> void {
if(device.fd >= 0) {
close(device.fd);
device.fd = -1;
}
}
pAudioOSS() {
device.fd = -1;
device.format = AFMT_S16_LE;
device.channels = 2;
device.name = "/dev/dsp";
settings.frequency = 22050;
}
~pAudioOSS() {
term();
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);
}
};

View File

@ -19,21 +19,21 @@ using namespace nall;
#define DeclareVideo(Name) \
struct Video##Name : Video { \
bool cap(const string& name) { return p.cap(name); } \
any get(const string& name) { return p.get(name); } \
bool set(const string& name, const any& value) { return p.set(name, value); } \
\
bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { return p.lock(data, pitch, width, height); } \
void unlock() { p.unlock(); } \
\
void clear() { p.clear(); } \
void refresh() { p.refresh(); } \
bool init() { return p.init(); } \
void term() { p.term(); } \
\
Video##Name() : p(*new pVideo##Name) {} \
~Video##Name() { delete &p; } \
\
auto cap(const string& name) -> bool { return p.cap(name); } \
auto get(const string& name) -> any { return p.get(name); } \
auto set(const string& name, const any& value) -> bool { return p.set(name, value); } \
\
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { return p.lock(data, pitch, width, height); } \
auto unlock() -> void { p.unlock(); } \
auto clear() -> void { p.clear(); } \
auto refresh() -> void { p.refresh(); } \
\
auto init() -> bool { return p.init(); } \
auto term() -> void { p.term(); } \
\
private: \
pVideo##Name& p; \
};
@ -78,18 +78,19 @@ using namespace nall;
#define DeclareAudio(Name) \
struct Audio##Name : Audio { \
bool cap(const string& name) { return p.cap(name); } \
any get(const string& name) { return p.get(name); } \
bool set(const string& name, const any& value) { return p.set(name, value); } \
\
void sample(uint16_t left, uint16_t right) { p.sample(left, right); } \
void clear() { p.clear(); } \
bool init() { return p.init(); } \
void term() { p.term(); } \
\
Audio##Name() : p(*new pAudio##Name) {} \
~Audio##Name() { delete &p; } \
\
auto cap(const string& name) -> bool { return p.cap(name); } \
auto get(const string& name) -> any { return p.get(name); } \
auto set(const string& name, const any& value) -> bool { return p.set(name, value); } \
\
auto sample(uint16_t left, uint16_t right) -> void { p.sample(left, right); } \
auto clear() -> void { p.clear(); } \
\
auto init() -> bool { return p.init(); } \
auto term() -> void { p.term(); } \
\
private: \
pAudio##Name& p; \
};
@ -140,9 +141,9 @@ using namespace nall;
auto acquire() -> bool { return p.acquire(); } \
auto unacquire() -> bool { return p.unacquire(); } \
auto acquired() -> bool { return p.acquired(); } \
\
auto poll() -> vector<shared_pointer<HID::Device>> { return p.poll(); } \
auto rumble(uint64_t id, bool enable) -> bool { return p.rumble(id, enable); } \
\
auto init() -> bool { return p.init(); } \
auto term() -> void { p.term(); } \
\

View File

@ -5,7 +5,6 @@ struct Input {
static const nall::string JoypadSupport;
static const nall::string JoypadRumbleSupport;
Input() = default;
virtual ~Input() = default;
virtual auto cap(const nall::string& name) -> bool { return false; }
@ -15,9 +14,9 @@ struct Input {
virtual auto acquire() -> bool { return false; }
virtual auto unacquire() -> bool { return false; }
virtual auto acquired() -> bool { return false; }
virtual auto poll() -> nall::vector<nall::shared_pointer<nall::HID::Device>> { return {}; }
virtual auto rumble(uint64_t id, bool enable) -> bool { return false; }
virtual auto init() -> bool { return true; }
virtual auto term() -> void {}
};

View File

@ -13,70 +13,70 @@ InputInterface input;
/* VideoInterface */
const char* Video::Handle = "Handle";
const char* Video::Synchronize = "Synchronize";
const char* Video::Depth = "Depth";
const char* Video::Filter = "Filter";
const char* Video::Shader = "Shader";
const string Video::Handle = "Handle";
const string Video::Synchronize = "Synchronize";
const string Video::Depth = "Depth";
const string Video::Filter = "Filter";
const string Video::Shader = "Shader";
const unsigned Video::FilterNearest = 0;
const unsigned Video::FilterLinear = 1;
void VideoInterface::driver(const char* driver) {
auto VideoInterface::driver(string driver) -> void {
if(p) term();
if(!driver || !*driver) driver = optimalDriver();
if(!driver) driver = optimalDriver();
if(0);
#ifdef VIDEO_CGL
else if(!strcmp(driver, "OpenGL")) p = new VideoCGL();
else if(driver == "OpenGL") p = new VideoCGL();
#endif
#ifdef VIDEO_DIRECT3D
else if(!strcmp(driver, "Direct3D")) p = new VideoD3D();
else if(driver == "Direct3D") p = new VideoD3D();
#endif
#ifdef VIDEO_DIRECTDRAW
else if(!strcmp(driver, "DirectDraw")) p = new VideoDD();
else if(driver == "DirectDraw") p = new VideoDD();
#endif
#ifdef VIDEO_GDI
else if(!strcmp(driver, "GDI")) p = new VideoGDI();
else if(driver == "GDI") p = new VideoGDI();
#endif
#ifdef VIDEO_GLX
else if(!strcmp(driver, "OpenGL")) p = new VideoGLX();
else if(driver == "OpenGL") p = new VideoGLX();
#endif
#ifdef VIDEO_QTOPENGL
else if(!strcmp(driver, "Qt-OpenGL")) p = new VideoQtOpenGL();
else if(driver == "Qt-OpenGL") p = new VideoQtOpenGL();
#endif
#ifdef VIDEO_QTRASTER
else if(!strcmp(driver, "Qt-Raster")) p = new VideoQtRaster();
else if(driver == "Qt-Raster") p = new VideoQtRaster();
#endif
#ifdef VIDEO_SDL
else if(!strcmp(driver, "SDL")) p = new VideoSDL();
else if(driver == "SDL") p = new VideoSDL();
#endif
#ifdef VIDEO_WGL
else if(!strcmp(driver, "OpenGL")) p = new VideoWGL();
else if(driver == "OpenGL") p = new VideoWGL();
#endif
#ifdef VIDEO_XSHM
else if(!strcmp(driver, "XShm")) p = new VideoXShm();
else if(driver == "XShm") p = new VideoXShm();
#endif
#ifdef VIDEO_XV
else if(!strcmp(driver, "X-Video")) p = new VideoXv();
else if(driver == "X-Video") p = new VideoXv();
#endif
else p = new Video();
}
const char* VideoInterface::optimalDriver() {
auto VideoInterface::optimalDriver() -> string {
#if defined(VIDEO_WGL)
return "OpenGL";
#elif defined(VIDEO_DIRECT3D)
@ -103,7 +103,7 @@ const char* VideoInterface::optimalDriver() {
#endif
}
const char* VideoInterface::safestDriver() {
auto VideoInterface::safestDriver() -> string {
#if defined(VIDEO_DIRECT3D)
return "Direct3D";
#elif defined(VIDEO_WGL)
@ -130,7 +130,7 @@ const char* VideoInterface::safestDriver() {
#endif
}
const char* VideoInterface::availableDrivers() {
auto VideoInterface::availableDrivers() -> string {
return
//Windows
@ -178,12 +178,12 @@ const char* VideoInterface::availableDrivers() {
"None";
}
bool VideoInterface::init() {
auto VideoInterface::init() -> bool {
if(!p) driver();
return p->init();
}
void VideoInterface::term() {
auto VideoInterface::term() -> void {
if(p) {
p->term();
delete p;
@ -191,66 +191,66 @@ void VideoInterface::term() {
}
}
bool VideoInterface::cap(const string& name) { return p ? p->cap(name) : false; }
any VideoInterface::get(const string& name) { return p ? p->get(name) : false; }
bool VideoInterface::set(const string& name, const any& value) { return p ? p->set(name, value) : false; }
bool VideoInterface::lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { return p ? p->lock(data, pitch, width, height) : false; }
void VideoInterface::unlock() { if(p) p->unlock(); }
void VideoInterface::clear() { if(p) p->clear(); }
void VideoInterface::refresh() { if(p) p->refresh(); }
VideoInterface::VideoInterface() : p(nullptr) {}
VideoInterface::~VideoInterface() { term(); }
auto VideoInterface::cap(const string& name) -> bool { return p ? p->cap(name) : false; }
auto VideoInterface::get(const string& name) -> any { return p ? p->get(name) : false; }
auto VideoInterface::set(const string& name, const any& value) -> bool { return p ? p->set(name, value) : false; }
auto VideoInterface::lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { return p ? p->lock(data, pitch, width, height) : false; }
auto VideoInterface::unlock() -> void { if(p) p->unlock(); }
auto VideoInterface::clear() -> void { if(p) p->clear(); }
auto VideoInterface::refresh() -> void { if(p) p->refresh(); }
/* AudioInterface */
const char* Audio::Handle = "Handle";
const char* Audio::Synchronize = "Synchronize";
const char* Audio::Frequency = "Frequency";
const char* Audio::Latency = "Latency";
const string Audio::Device = "Device";
const string Audio::Handle = "Handle";
const string Audio::Synchronize = "Synchronize";
const string Audio::Frequency = "Frequency";
const string Audio::Latency = "Latency";
void AudioInterface::driver(const char* driver) {
auto AudioInterface::driver(string driver) -> void {
if(p) term();
if(!driver || !*driver) driver = optimalDriver();
if(!driver) driver = optimalDriver();
if(0);
#ifdef AUDIO_ALSA
else if(!strcmp(driver, "ALSA")) p = new AudioALSA();
else if(driver == "ALSA") p = new AudioALSA();
#endif
#ifdef AUDIO_AO
else if(!strcmp(driver, "libao")) p = new AudioAO();
else if(driver == "libao") p = new AudioAO();
#endif
#ifdef AUDIO_DIRECTSOUND
else if(!strcmp(driver, "DirectSound")) p = new AudioDS();
else if(driver == "DirectSound") p = new AudioDS();
#endif
#ifdef AUDIO_OPENAL
else if(!strcmp(driver, "OpenAL")) p = new AudioOpenAL();
else if(driver == "OpenAL") p = new AudioOpenAL();
#endif
#ifdef AUDIO_OSS
else if(!strcmp(driver, "OSS")) p = new AudioOSS();
else if(driver == "OSS") p = new AudioOSS();
#endif
#ifdef AUDIO_PULSEAUDIO
else if(!strcmp(driver, "PulseAudio")) p = new AudioPulseAudio();
else if(driver == "PulseAudio") p = new AudioPulseAudio();
#endif
#ifdef AUDIO_PULSEAUDIOSIMPLE
else if(!strcmp(driver, "PulseAudioSimple")) p = new AudioPulseAudioSimple();
else if(driver == "PulseAudioSimple") p = new AudioPulseAudioSimple();
#endif
#ifdef AUDIO_XAUDIO2
else if(!strcmp(driver, "XAudio2")) p = new AudioXAudio2();
else if(driver == "XAudio2") p = new AudioXAudio2();
#endif
else p = new Audio();
}
const char* AudioInterface::optimalDriver() {
auto AudioInterface::optimalDriver() -> string {
#if defined(AUDIO_XAUDIO2)
return "XAudio2";
#elif defined(AUDIO_DIRECTSOUND)
@ -274,7 +274,7 @@ const char* AudioInterface::optimalDriver() {
#endif
}
const char* AudioInterface::safestDriver() {
auto AudioInterface::safestDriver() -> string {
#if defined(AUDIO_DIRECTSOUND)
return "DirectSound";
#elif defined(AUDIO_XAUDIO2)
@ -298,7 +298,7 @@ const char* AudioInterface::safestDriver() {
#endif
}
const char* AudioInterface::availableDrivers() {
auto AudioInterface::availableDrivers() -> string {
return
//Windows
@ -340,12 +340,12 @@ const char* AudioInterface::availableDrivers() {
"None";
}
bool AudioInterface::init() {
auto AudioInterface::init() -> bool {
if(!p) driver();
return p->init();
}
void AudioInterface::term() {
auto AudioInterface::term() -> void {
if(p) {
p->term();
delete p;
@ -353,13 +353,12 @@ void AudioInterface::term() {
}
}
bool AudioInterface::cap(const string& name) { return p ? p->cap(name) : false; }
any AudioInterface::get(const string& name) { return p ? p->get(name) : false; }
bool AudioInterface::set(const string& name, const any& value) { return p ? p->set(name, value) : false; }
void AudioInterface::sample(uint16_t left, uint16_t right) { if(p) p->sample(left, right); }
void AudioInterface::clear() { if(p) p->clear(); }
AudioInterface::AudioInterface() : p(nullptr) {}
AudioInterface::~AudioInterface() { term(); }
auto AudioInterface::cap(const string& name) -> bool { return p ? p->cap(name) : false; }
auto AudioInterface::get(const string& name) -> any { return p ? p->get(name) : false; }
auto AudioInterface::set(const string& name, const any& value) -> bool { return p ? p->set(name, value) : false; }
auto AudioInterface::sample(uint16_t left, uint16_t right) -> void { if(p) p->sample(left, right); }
auto AudioInterface::clear() -> void { if(p) p->clear(); }
/* InputInterface */

View File

@ -19,47 +19,45 @@ namespace ruby {
#include <ruby/input.hpp>
struct VideoInterface {
void driver(const char* driver = "");
const char* optimalDriver();
const char* safestDriver();
const char* availableDrivers();
bool init();
void term();
bool cap(const nall::string& name);
nall::any get(const nall::string& name);
bool set(const nall::string& name, const nall::any& value);
bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height);
void unlock();
void clear();
void refresh();
VideoInterface();
~VideoInterface();
auto driver(nall::string driver = "") -> void;
auto optimalDriver() -> nall::string;
auto safestDriver() -> nall::string;
auto availableDrivers() -> nall::string;
auto init() -> bool;
auto term() -> void;
auto cap(const nall::string& name) -> bool;
auto get(const nall::string& name) -> nall::any;
auto set(const nall::string& name, const nall::any& value) -> bool;
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool;
auto unlock() -> void;
auto clear() -> void;
auto refresh() -> void;
private:
Video* p = nullptr;
};
struct AudioInterface {
void driver(const char* driver = "");
const char* optimalDriver();
const char* safestDriver();
const char* availableDrivers();
bool init();
void term();
bool cap(const nall::string& name);
nall::any get(const nall::string& name);
bool set(const nall::string& name, const nall::any& value);
void sample(uint16_t left, uint16_t right);
void clear();
AudioInterface();
~AudioInterface();
auto driver(nall::string driver = "") -> void;
auto optimalDriver() -> nall::string;
auto safestDriver() -> nall::string;
auto availableDrivers() -> nall::string;
auto init() -> bool;
auto term() -> void;
auto cap(const nall::string& name) -> bool;
auto get(const nall::string& name) -> nall::any;
auto set(const nall::string& name, const nall::any& value) -> bool;
auto sample(uint16_t left, uint16_t right) -> void;
auto clear() -> void;
private:
Audio* p = nullptr;
};
@ -83,7 +81,6 @@ struct InputInterface {
auto acquire() -> bool;
auto unacquire() -> bool;
auto acquired() -> bool;
auto poll() -> nall::vector<nall::shared_pointer<nall::HID::Device>>;
auto rumble(uint64_t id, bool enable) -> bool;

View File

@ -1,25 +1,24 @@
struct Video {
static const char* Handle;
static const char* Synchronize;
static const char* Depth;
static const char* Filter;
static const char* Shader;
static const nall::string Handle;
static const nall::string Synchronize;
static const nall::string Depth;
static const nall::string Filter;
static const nall::string Shader;
static const unsigned FilterNearest;
static const unsigned FilterLinear;
virtual bool cap(const nall::string& name) { return false; }
virtual nall::any get(const nall::string& name) { return false; }
virtual bool set(const nall::string& name, const nall::any& value) { return false; }
virtual ~Video() = default;
virtual bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { return false; }
virtual void unlock() {}
virtual auto cap(const nall::string& name) -> bool { return false; }
virtual auto get(const nall::string& name) -> nall::any { return false; }
virtual auto set(const nall::string& name, const nall::any& value) -> bool { return false; }
virtual void clear() {}
virtual void refresh() {}
virtual bool init() { return true; }
virtual void term() {}
virtual auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { return false; }
virtual auto unlock() -> void {}
virtual auto clear() -> void {}
virtual auto refresh() -> void {}
Video() {}
virtual ~Video() {}
virtual auto init() -> bool { return true; }
virtual auto term() -> void {}
};

View File

@ -24,6 +24,7 @@ ConfigurationManager::ConfigurationManager() {
append(video, "Video");
audio.append(audio.driver, "Driver");
audio.append(audio.device, "Device");
audio.append(audio.synchronize, "Synchronize");
audio.append(audio.mute, "Mute");
append(audio, "Audio");

View File

@ -27,6 +27,7 @@ struct ConfigurationManager : Configuration::Document {
struct Audio : Configuration::Node {
string driver;
string device;
bool synchronize = true;
bool mute = false;
} audio;

View File

@ -1,5 +1,16 @@
//request from emulation core to load non-volatile media folder
auto Program::loadRequest(unsigned id, string name, string type) -> void {
string location = BrowserDialog()
.setParent(*presentation)
.setTitle({"Load ", name})
.setPath({config().library.location, name})
.setFilters({string{name, "|*.", type}})
.selectFolder();
if(!directory::exists(location)) return;
mediaPaths(id) = location;
folderPaths.append(location);
emulator->load(id);
}
//request from emulation core to load non-volatile media file

View File

@ -36,6 +36,7 @@ Program::Program() {
if(!video.init()) { video.driver("None"); video.init(); }
audio.driver(config().audio.driver);
audio.set(Audio::Device, config().audio.device);
audio.set(Audio::Handle, presentation->viewport.handle());
audio.set(Audio::Synchronize, config().audio.synchronize);
audio.set(Audio::Frequency, 96000u);

View File

@ -8,6 +8,12 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) {
mappingList.onChange([&] {
eraseButton.setEnabled((bool)mappingList.selected());
});
resetButton.setText("Reset").onActivate([&] {
if(MessageDialog("Are you sure you want to erase all hotkey mappings?").setParent(*settingsManager).question() == 0) {
for(auto& mapping : inputManager->hotkeys) mapping->unbind();
refreshMappings();
}
});
eraseButton.setText("Erase").onActivate([&] {
if(auto item = mappingList.selected()) {
inputManager->hotkeys[item->offset()]->unbind();
@ -43,6 +49,7 @@ auto HotkeySettings::assignMapping() -> void {
if(auto item = mappingList.selected()) {
activeMapping = inputManager->hotkeys[item->offset()];
settingsManager->layout.setEnabled(false);
settingsManager->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
}
}
@ -54,6 +61,7 @@ auto HotkeySettings::inputEvent(shared_pointer<HID::Device> device, unsigned gro
if(activeMapping->bind(device, group, input, oldValue, newValue)) {
activeMapping = nullptr;
settingsManager->statusBar.setText("");
settingsManager->layout.setEnabled(true);
refreshMappings();
}
}

View File

@ -102,12 +102,12 @@ auto InputSettings::refreshMappings() -> void {
auto InputSettings::assignMapping() -> void {
inputManager->poll(); //clear any pending events first
auto mapping = mappingList.selected();
if(auto mapping = mappingList.selected()) {
activeMapping = activeDevice().mappings[mapping->offset()];
//settingsManager->layout.setEnabled(false);
settingsManager->layout.setEnabled(false);
settingsManager->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
}
}
auto InputSettings::assignMouseInput(unsigned id) -> void {
if(auto mouse = inputManager->findMouse()) {
@ -130,7 +130,7 @@ auto InputSettings::inputEvent(shared_pointer<HID::Device> device, unsigned grou
if(activeMapping->bind(device, group, input, oldValue, newValue)) {
activeMapping = nullptr;
settingsManager->statusBar.setText("");
//settingsManager->layout.setEnabled(true); //todo: this isn't enabling child widgets properly (bug in hiro)
settingsManager->layout.setEnabled(true);
refreshMappings();
}
}

View File

@ -42,6 +42,7 @@ struct HotkeySettings : TabFrameItem {
ListView mappingList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
Button resetButton{&controlLayout, Size{80, 0}};
Button eraseButton{&controlLayout, Size{80, 0}};
};