From 7bf4cff94609a7cd6e2865033d9be2f85615e3f3 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 25 May 2015 22:23:49 +1000 Subject: [PATCH] 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) --- emulator/emulator.hpp | 2 +- hiro/extension/fixed-layout.cpp | 6 +- hiro/extension/horizontal-layout.cpp | 6 +- hiro/extension/vertical-layout.cpp | 6 +- hiro/gtk/layout.cpp | 9 -- nall/string/cast.hpp | 4 +- ruby/audio.hpp | 27 +++-- ruby/audio/openal.cpp | 90 +++++++------- ruby/audio/oss.cpp | 90 ++++++++------ ruby/implementation.cpp | 45 +++---- ruby/input.hpp | 3 +- ruby/ruby.cpp | 113 +++++++++--------- ruby/ruby.hpp | 63 +++++----- ruby/video.hpp | 31 +++-- target-tomoko/configuration/configuration.cpp | 1 + target-tomoko/configuration/configuration.hpp | 1 + target-tomoko/program/interface.cpp | 11 ++ target-tomoko/program/program.cpp | 1 + target-tomoko/settings/hotkeys.cpp | 8 ++ target-tomoko/settings/input.cpp | 12 +- target-tomoko/settings/settings.hpp | 1 + 21 files changed, 280 insertions(+), 250 deletions(-) diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 954581aa..06658f28 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -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/"; diff --git a/hiro/extension/fixed-layout.cpp b/hiro/extension/fixed-layout.cpp index 0b11f0b4..224c44ee 100644 --- a/hiro/extension/fixed-layout.cpp +++ b/hiro/extension/fixed-layout.cpp @@ -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; } diff --git a/hiro/extension/horizontal-layout.cpp b/hiro/extension/horizontal-layout.cpp index 4848a017..ccc0cfd7 100644 --- a/hiro/extension/horizontal-layout.cpp +++ b/hiro/extension/horizontal-layout.cpp @@ -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; } diff --git a/hiro/extension/vertical-layout.cpp b/hiro/extension/vertical-layout.cpp index fafef2da..e2d0bd90 100644 --- a/hiro/extension/vertical-layout.cpp +++ b/hiro/extension/vertical-layout.cpp @@ -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; } diff --git a/hiro/gtk/layout.cpp b/hiro/gtk/layout.cpp index 30f423b5..4872f933 100644 --- a/hiro/gtk/layout.cpp +++ b/hiro/gtk/layout.cpp @@ -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)); - } } } diff --git a/nall/string/cast.hpp b/nall/string/cast.hpp index 450bc430..cea0926c 100644 --- a/nall/string/cast.hpp +++ b/nall/string/cast.hpp @@ -160,14 +160,14 @@ template<> struct stringify { 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* _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 diff --git a/ruby/audio.hpp b/ruby/audio.hpp index 9d8603e3..5104a2de 100644 --- a/ruby/audio.hpp +++ b/ruby/audio.hpp @@ -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 {} }; diff --git a/ruby/audio/openal.cpp b/ruby/audio/openal.cpp index af478be0..b066b99a 100644 --- a/ruby/audio/openal.cpp +++ b/ruby/audio/openal.cpp @@ -1,9 +1,3 @@ -/* - audio.openal (2007-12-26) - author: Nach - contributors: byuu, wertigon, _willow_ -*/ - #if defined(PLATFORM_MACOSX) #include #include @@ -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(value); return true; @@ -65,7 +58,7 @@ public: if(name == Audio::Latency) { if(settings.latency != any_cast(value)) { settings.latency = any_cast(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,32 +96,26 @@ 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); - //alSourcef (device.source, AL_PITCH, 1.0); - //alSourcef (device.source, AL_GAIN, 1.0); - //alSource3f(device.source, AL_POSITION, 0.0, 0.0, 0.0); - //alSource3f(device.source, AL_VELOCITY, 0.0, 0.0, 0.0); - //alSource3f(device.source, AL_DIRECTION, 0.0, 0.0, 0.0); - //alSourcef (device.source, AL_ROLLOFF_FACTOR, 0.0); - //alSourcei (device.source, AL_SOURCE_RELATIVE, AL_TRUE); + //alSourcef (device.source, AL_PITCH, 1.0); + //alSourcef (device.source, AL_GAIN, 1.0); + //alSource3f(device.source, AL_POSITION, 0.0, 0.0, 0.0); + //alSource3f(device.source, AL_VELOCITY, 0.0, 0.0, 0.0); + //alSource3f(device.source, AL_DIRECTION, 0.0, 0.0, 0.0); + //alSourcef (device.source, AL_ROLLOFF_FACTOR, 0.0); + //alSourcei (device.source, AL_SOURCE_RELATIVE, AL_TRUE); alListener3f(AL_POSITION, 0.0, 0.0, 0.0); alListener3f(AL_VELOCITY, 0.0, 0.0, 0.0); @@ -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) diff --git a/ruby/audio/oss.cpp b/ruby/audio/oss.cpp index 2c77b6ae..eb7c3648 100644 --- a/ruby/audio/oss.cpp +++ b/ruby/audio/oss.cpp @@ -1,8 +1,3 @@ -/* - audio.oss (2007-12-26) - author: Nach -*/ - #include #include #include @@ -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(value); + if(!settings.device) settings.device = "/dev/dsp"; + return true; + } + + if(name == Audio::Synchronize) { + settings.synchronize = any_cast(value); + updateSynchronization(); + return true; + } + if(name == Audio::Frequency) { settings.frequency = any_cast(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); } }; diff --git a/ruby/implementation.cpp b/ruby/implementation.cpp index b4313b9a..b38f49f0 100644 --- a/ruby/implementation.cpp +++ b/ruby/implementation.cpp @@ -19,20 +19,20 @@ 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,17 +78,18 @@ 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> { 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(); } \ \ diff --git a/ruby/input.hpp b/ruby/input.hpp index c3d032dd..4c59a3cc 100644 --- a/ruby/input.hpp +++ b/ruby/input.hpp @@ -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> { return {}; } virtual auto rumble(uint64_t id, bool enable) -> bool { return false; } + virtual auto init() -> bool { return true; } virtual auto term() -> void {} }; diff --git a/ruby/ruby.cpp b/ruby/ruby.cpp index b06a1ddd..a4ac521a 100644 --- a/ruby/ruby.cpp +++ b/ruby/ruby.cpp @@ -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; +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 */ diff --git a/ruby/ruby.hpp b/ruby/ruby.hpp index 648b795f..888f1e4b 100644 --- a/ruby/ruby.hpp +++ b/ruby/ruby.hpp @@ -19,47 +19,45 @@ namespace ruby { #include 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>; auto rumble(uint64_t id, bool enable) -> bool; diff --git a/ruby/video.hpp b/ruby/video.hpp index 2fb68525..7a1357d9 100644 --- a/ruby/video.hpp +++ b/ruby/video.hpp @@ -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 {} }; diff --git a/target-tomoko/configuration/configuration.cpp b/target-tomoko/configuration/configuration.cpp index f2b7d868..781d564b 100644 --- a/target-tomoko/configuration/configuration.cpp +++ b/target-tomoko/configuration/configuration.cpp @@ -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"); diff --git a/target-tomoko/configuration/configuration.hpp b/target-tomoko/configuration/configuration.hpp index f02822d2..ca1f5180 100644 --- a/target-tomoko/configuration/configuration.hpp +++ b/target-tomoko/configuration/configuration.hpp @@ -27,6 +27,7 @@ struct ConfigurationManager : Configuration::Document { struct Audio : Configuration::Node { string driver; + string device; bool synchronize = true; bool mute = false; } audio; diff --git a/target-tomoko/program/interface.cpp b/target-tomoko/program/interface.cpp index 271e3e36..4431bcd0 100644 --- a/target-tomoko/program/interface.cpp +++ b/target-tomoko/program/interface.cpp @@ -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 diff --git a/target-tomoko/program/program.cpp b/target-tomoko/program/program.cpp index 33e91de0..7b01ee15 100644 --- a/target-tomoko/program/program.cpp +++ b/target-tomoko/program/program.cpp @@ -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); diff --git a/target-tomoko/settings/hotkeys.cpp b/target-tomoko/settings/hotkeys.cpp index 67f370a7..50f25710 100644 --- a/target-tomoko/settings/hotkeys.cpp +++ b/target-tomoko/settings/hotkeys.cpp @@ -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 device, unsigned gro if(activeMapping->bind(device, group, input, oldValue, newValue)) { activeMapping = nullptr; settingsManager->statusBar.setText(""); + settingsManager->layout.setEnabled(true); refreshMappings(); } } diff --git a/target-tomoko/settings/input.cpp b/target-tomoko/settings/input.cpp index 60eded27..e46ff460 100644 --- a/target-tomoko/settings/input.cpp +++ b/target-tomoko/settings/input.cpp @@ -102,11 +102,11 @@ auto InputSettings::refreshMappings() -> void { auto InputSettings::assignMapping() -> void { inputManager->poll(); //clear any pending events first - auto mapping = mappingList.selected(); - activeMapping = activeDevice().mappings[mapping->offset()]; - -//settingsManager->layout.setEnabled(false); - settingsManager->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); + if(auto mapping = mappingList.selected()) { + activeMapping = activeDevice().mappings[mapping->offset()]; + settingsManager->layout.setEnabled(false); + settingsManager->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); + } } auto InputSettings::assignMouseInput(unsigned id) -> void { @@ -130,7 +130,7 @@ auto InputSettings::inputEvent(shared_pointer 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(); } } diff --git a/target-tomoko/settings/settings.hpp b/target-tomoko/settings/settings.hpp index 4e7b8ae5..cf421e67 100644 --- a/target-tomoko/settings/settings.hpp +++ b/target-tomoko/settings/settings.hpp @@ -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}}; };