Update to v103r14 release.

byuu says:

Changelog:

  - tomoko: by popular choice, default to adaptive mode on new installs
  - hiro/windows: fix bug that was preventing the escape key from
    closing some dialog windows
  - nall/registry: use "\\\\" as separator instead of "/" ... because
    some registry keys contain "/" in them >_>
  - ruby: add ASIO driver stub (so far it can only initialize and grab
    the driver name/version information)
This commit is contained in:
Tim Allen 2017-07-15 22:00:20 +10:00
parent ed5ec58595
commit 17697317d4
10 changed files with 296 additions and 18 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "103.13";
static const string Version = "103.14";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -19,7 +19,7 @@ ui_objects += $(if $(call streq,$(platform),windows),ui-resource)
# platform
ifeq ($(platform),windows)
ruby += video.direct3d video.wgl video.directdraw video.gdi
ruby += audio.wasapi audio.xaudio2 audio.directsound
ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound
ruby += input.windows
else ifeq ($(platform),macosx)
ruby += video.cgl

View File

@ -30,7 +30,7 @@ Settings::Settings() {
set("Video/Windowed/AspectCorrection", true);
set("Video/Windowed/IntegralScaling", true);
set("Video/Windowed/Adaptive", false);
set("Video/Windowed/Adaptive", true);
set("Video/Windowed/Scale", "Small");
set("Video/Windowed/Scale/Small", "640x480");
set("Video/Windowed/Scale/Medium", "960x720");

View File

@ -142,7 +142,10 @@ static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
auto object = (mObject*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
if(!object) return false;
if(auto window = dynamic_cast<mWindow*>(object)) {
auto objectWindow = (mObject*)GetWindowLongPtr(GetAncestor(info.hwndFocus, GA_ROOT), GWLP_USERDATA);
if(!objectWindow) return false;
if(auto window = dynamic_cast<mWindow*>(objectWindow)) {
if(auto self = window->self()) {
if(!self->_modalityDisabled()) {
if(auto code = pKeyboard::_translate(wparam, lparam)) {
@ -158,7 +161,6 @@ static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
}
}
}
return false;
}
if(auto window = object->parentWindow(true)) {
@ -218,7 +220,6 @@ static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
}
}
CloseClipboard();
return false;
}
}
#endif

View File

@ -41,8 +41,8 @@ static auto BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) ->
if(path) {
//clear COMDLG32 MRU (most recently used) file list
//this is required in order for lpstrInitialDir to be honored in Windows 7 and above
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/");
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/");
registry::remove("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU\\");
registry::remove("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSavePidlMRU\\");
}
OPENFILENAME ofn;

View File

@ -24,7 +24,7 @@ namespace nall {
struct registry {
static auto exists(const string& name) -> bool {
auto part = name.split("/");
auto part = name.split("\\");
HKEY handle, rootKey = root(part.takeLeft());
string node = part.takeRight();
string path = part.merge("\\");
@ -39,7 +39,7 @@ struct registry {
}
static auto read(const string& name) -> string {
auto part = name.split("/");
auto part = name.split("\\");
HKEY handle, rootKey = root(part.takeLeft());
string node = part.takeRight();
string path = part.merge("\\");
@ -54,7 +54,7 @@ struct registry {
}
static auto write(const string& name, const string& data = "") -> void {
auto part = name.split("/");
auto part = name.split("\\");
HKEY handle, rootKey = root(part.takeLeft());
string node = part.takeRight(), path;
DWORD disposition;
@ -71,7 +71,7 @@ struct registry {
}
static auto remove(const string& name) -> bool {
auto part = name.split("/");
auto part = name.split("\\");
HKEY rootKey = root(part.takeLeft());
string node = part.takeRight();
string path = part.merge("\\");
@ -81,7 +81,7 @@ struct registry {
static auto contents(const string& name) -> string_vector {
string_vector result;
auto part = name.split("/");
auto part = name.split("\\");
HKEY handle, rootKey = root(part.takeLeft());
part.removeRight();
string path = part.merge("\\");
@ -92,7 +92,7 @@ struct registry {
wchar_t name[NWR_SIZE] = L"";
DWORD size = NWR_SIZE * sizeof(wchar_t);
RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
result.append(string{(const char*)utf8_t(name), "/"});
result.append(string{(const char*)utf8_t(name), "\\"});
}
for(uint n = 0; n < nodes; n++) {
wchar_t name[NWR_SIZE] = L"";

90
ruby/audio/asio.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "asio.hpp"
struct AudioASIO : Audio {
~AudioASIO() { term(); }
struct Settings {
HWND handle = nullptr;
bool synchronize = true;
uint frequency = 48000;
} settings;
struct Driver {
string name;
string classID;
};
vector<Driver> drivers;
Driver driver;
IASIO* device = nullptr;
auto cap(const string& name) -> bool {
if(name == Audio::Handle) 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::Handle) return (uintptr)settings.handle;
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::Handle && value.is<uintptr>()) {
settings.handle = (HWND)value.get<uintptr>();
return true;
}
if(name == Audio::Synchronize && value.is<bool>()) {
settings.synchronize = value.get<bool>();
return true;
}
if(name == Audio::Frequency && value.is<uint>()) {
settings.frequency = value.get<uint>();
return true;
}
return false;
}
auto sample(int16_t left, int16_t right) -> void {
}
auto clear() -> void {
}
auto init() -> bool {
//enumerate available ASIO drivers from the registry
for(auto candidate : registry::contents("HKLM\\SOFTWARE\\ASIO\\")) {
if(auto classID = registry::read({"HKLM\\SOFTWARE\\ASIO\\", candidate, "CLSID"})) {
drivers.append({candidate.trimRight("\\", 1L), classID});
}
}
if(!drivers) return false;
//default to first driver for now
driver = drivers[0];
CLSID classID;
if(CLSIDFromString((LPOLESTR)utf16_t(driver.classID), (LPCLSID)&classID) != S_OK) return false;
if(CoCreateInstance(classID, 0, CLSCTX_INPROC_SERVER, classID, (void**)&device) != S_OK) return false;
if(!device->init((void*)settings.handle)) return false;
//temporary debugging information
char driverName[4096] = {0};
device->getDriverName(driverName);
print("Driver: ", driverName, "\n");
print("Version: ", device->getDriverVersion(), "\n");
print("---\n");
return true;
}
auto term() -> void {
}
};

171
ruby/audio/asio.hpp Normal file
View File

@ -0,0 +1,171 @@
using ASIOError = long;
enum : long {
ASE_OK = 0,
ASE_SUCCESS = 0x3f4847a0,
ASE_NotPresent = -1000,
ASE_HWMalfunction,
ASE_InvalidParameter,
ASE_InvalidMode,
ASE_SPNotAdvancing,
ASE_NoClock,
ASE_NoMemory,
};
using ASIOBool = long;
enum : long {
ASIOFalse = 0,
ASIOTrue = 1,
};
using ASIOSampleRate = double;
using ASIOSamples = long long int;
using ASIOTimeStamp = long long int;
using ASIOSampleType = long;
enum : long {
ASIOSTInt16MSB = 0,
ASIOSTInt24MSB = 1,
ASIOSTInt32MSB = 2,
ASIOSTFloat32MSB = 3,
ASIOSTFloat64MSB = 4,
ASIOSTInt32MSB16 = 8,
ASIOSTInt32MSB18 = 9,
ASIOSTInt32MSB20 = 10,
ASIOSTInt32MSB24 = 11,
ASIOSTInt16LSB = 16,
ASIOSTInt24LSB = 17,
ASIOSTInt32LSB = 18,
ASIOSTFloat32LSB = 19,
ASIOSTFloat64LSB = 20,
ASIOSTInt32LSB16 = 24,
ASIOSTInt32LSB18 = 25,
ASIOSTInt32LSB20 = 26,
ASIOSTInt32LSB24 = 27,
ASIOSTDSDInt8LSB1 = 32,
ASIOSTDSDInt8MSB1 = 33,
ASIOSTDSDInt8NER8 = 40,
ASIOSTLastEntry,
};
struct ASIODriverInfo {
long asioVersion;
long driverVersion;
char name[32];
char errorMessage[124];
void* sysRef;
};
struct ASIOBufferInfo {
ASIOBool isInput;
long channelNum;
void* buffers[2];
};
struct ASIOChannelInfo {
long channel;
ASIOBool isInput;
ASIOBool isActive;
long channelGroup;
ASIOSampleType type;
char name[32];
};
struct ASIOClockSource {
long index;
long associatedChannel;
long associatedGroup;
ASIOBool isCurrentSource;
char name[32];
};
struct ASIOTimeInfo {
double speed;
ASIOTimeStamp systemTime;
ASIOSamples samplePosition;
ASIOSampleRate sampleRate;
unsigned long flags;
char reserved[12];
};
enum : unsigned long {
kSystemTimeValid = 1 << 0,
kSamplePositionValid = 1 << 1,
kSampleRateValid = 1 << 2,
kSpeedValid = 1 << 3,
kSampleRateChanged = 1 << 4,
kClockSourceChanged = 1 << 5,
};
struct ASIOTimeCode {
double speed;
ASIOSamples timeCodeSamples;
unsigned long flags;
char future[64];
};
enum : unsigned long {
kTcValid = 1 << 0,
kTcRunning = 1 << 1,
kTcReverse = 1 << 2,
kTcOnspeed = 1 << 3,
kTcStill = 1 << 4,
kTcSpeedValid = 1 << 8,
};
struct ASIOTime {
long reserved[4];
ASIOTimeInfo timeInfo;
ASIOTimeCode timeCode;
};
struct ASIOCallbacks {
auto (*bufferSwitch)(long doubleBufferIndex, ASIOBool directProcess) -> void;
auto (*sampleRateDidChange)(ASIOSampleRate sRate) -> void;
auto (*asioMessage)(long selector, long value, void* message, double* opt) -> long;
auto (*bufferSwitchTimeInfo)(ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess) -> ASIOTime*;
};
enum : long {
kAsioSelectorSupported = 1,
kAsioEngineVersion,
kAsioResetRequest,
kAsioBufferSizeChange,
kAsioResyncRequest,
kAsioLatenciesChanged,
kAsioSupportsTimeInfo,
kAsioSupportsTimeCode,
kAsioMMCCommand,
kAsioSupportsInputMonitor,
kAsioSupportsInputGain,
kAsioSupportsInputMeter,
kAsioSupportsOutputGain,
kAsioSupportsOutputMeter,
kAsioOverload,
kAsioNumMessageSelectors,
};
struct IASIO : public IUnknown {
virtual auto init(void* sysHandle) -> ASIOBool;
virtual auto getDriverName(char* name) -> void;
virtual auto getDriverVersion() -> long;
virtual auto getErrorMessage(char* error) -> void;
virtual auto start() -> ASIOError;
virtual auto stop() -> ASIOError;
virtual auto getChannels(long* numInputChannels, long* numOutputChannels) -> ASIOError = 0;
virtual auto getLatencies(long* inputLatency, long* outputLatency) -> ASIOError = 0;
virtual auto getBufferSize(long* minSize, long* maxSize, long* preferredSize, long* granularity) -> ASIOError = 0;
virtual auto canSampleRate(ASIOSampleRate sampleRate) -> ASIOError = 0;
virtual auto getSampleRate(ASIOSampleRate* sampleRate) -> ASIOError = 0;
virtual auto setSampleRate(ASIOSampleRate sampleRate) -> ASIOError = 0;
virtual auto getClockSources(ASIOClockSource* clocks, long* numSources) -> ASIOError = 0;
virtual auto setClockSource(long reference) -> ASIOError = 0;
virtual auto getSamplePosition(ASIOSamples* sPos, ASIOTimeStamp* tStamp) -> ASIOError = 0;
virtual auto getChannelInfo(ASIOChannelInfo* info) -> ASIOError = 0;
virtual auto createBuffers(ASIOBufferInfo* bufferInfos, long numChannels, long bufferSize, ASIOCallbacks* callbacks) -> ASIOError = 0;
virtual auto disposeBuffers() -> ASIOError = 0;
virtual auto controlPanel() -> ASIOError = 0;
virtual auto future(long selector, void* opt) -> ASIOError = 0;
virtual auto outputReady() -> ASIOError = 0;
};

View File

@ -1,7 +1,7 @@
#include <dsound.h>
struct AudioDS : Audio {
~AudioDS() { term(); }
struct AudioDirectSound : Audio {
~AudioDirectSound() { term(); }
LPDIRECTSOUND ds = nullptr;
LPDIRECTSOUNDBUFFER dsb_p = nullptr;

View File

@ -238,6 +238,10 @@ auto Video::availableDrivers() -> string_vector {
#include <ruby/audio/ao.cpp>
#endif
#if defined(AUDIO_ASIO)
#include <ruby/audio/asio.cpp>
#endif
#if defined(AUDIO_DIRECTSOUND)
#include <ruby/audio/directsound.cpp>
#endif
@ -286,8 +290,12 @@ auto Audio::create(const string& driver) -> Audio* {
if(driver == "libao") return new AudioAO;
#endif
#if defined(AUDIO_ASIO)
if(driver == "ASIO") return new AudioASIO;
#endif
#if defined(AUDIO_DIRECTSOUND)
if(driver == "DirectSound") return new AudioDS;
if(driver == "DirectSound") return new AudioDirectSound;
#endif
#if defined(AUDIO_OPENAL)
@ -318,7 +326,9 @@ auto Audio::create(const string& driver) -> Audio* {
}
auto Audio::optimalDriver() -> string {
#if defined(AUDIO_WASAPI)
#if defined(AUDIO_ASIO)
return "ASIO";
#elif defined(AUDIO_WASAPI)
return "WASAPI";
#elif defined(AUDIO_XAUDIO2)
return "XAudio2";
@ -360,6 +370,8 @@ auto Audio::safestDriver() -> string {
return "PulseAudioSimple";
#elif defined(AUDIO_AO)
return "libao";
#elif defined(AUDIO_ASIO)
return "ASIO";
#else
return "None";
#endif
@ -368,6 +380,10 @@ auto Audio::safestDriver() -> string {
auto Audio::availableDrivers() -> string_vector {
return {
#if defined(AUDIO_ASIO)
"ASIO",
#endif
#if defined(AUDIO_WASAPI)
"WASAPI",
#endif