Merge branch 'master' into GLSL-master
Conflicts: Source/Core/DolphinWX/Src/VideoConfigDiag.h Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h Source/Plugins/Plugin_VideoOGL/Src/Render.cpp Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include "CoreAudioSoundStream.h"
|
||||
#include "OpenALStream.h"
|
||||
#include "PulseAudioStream.h"
|
||||
#include "../../Core/Src/Movie.h"
|
||||
|
||||
namespace AudioCommon
|
||||
{
|
||||
@@ -115,7 +116,12 @@ namespace AudioCommon
|
||||
return backends;
|
||||
}
|
||||
|
||||
bool UseJIT() {
|
||||
bool UseJIT()
|
||||
{
|
||||
if (!Movie::IsDSPHLE() && Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return ac_Config.m_EnableJIT;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,13 @@ bool CoreAudioSound::Start()
|
||||
return false;
|
||||
}
|
||||
|
||||
err = AudioUnitSetParameter(audioUnit,
|
||||
kHALOutputParam_Volume,
|
||||
kAudioUnitParameterFlag_Output, 0,
|
||||
m_volume / 100., 0);
|
||||
if (err != noErr)
|
||||
ERROR_LOG(AUDIO, "error setting volume");
|
||||
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
if (err != noErr) {
|
||||
ERROR_LOG(AUDIO, "error initializing audiounit");
|
||||
@@ -105,6 +112,7 @@ bool CoreAudioSound::Start()
|
||||
void CoreAudioSound::SetVolume(int volume)
|
||||
{
|
||||
OSStatus err;
|
||||
m_volume = volume;
|
||||
|
||||
err = AudioUnitSetParameter(audioUnit,
|
||||
kHALOutputParam_Volume,
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
|
||||
private:
|
||||
AudioUnit audioUnit;
|
||||
int m_volume;
|
||||
|
||||
static OSStatus callback(void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
|
||||
@@ -123,7 +123,6 @@ void OpenALStream::SoundLoop()
|
||||
{
|
||||
Common::SetCurrentThreadName("Audio thread - openal");
|
||||
|
||||
ALenum err;
|
||||
u32 ulFrequency = m_mixer->GetSampleRate();
|
||||
|
||||
memset(uiBuffers, 0, OAL_NUM_BUFFERS * sizeof(ALuint));
|
||||
@@ -144,8 +143,8 @@ void OpenALStream::SoundLoop()
|
||||
// Set the default sound volume as saved in the config file.
|
||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
||||
|
||||
err = alGetError();
|
||||
// TODO: Error handling
|
||||
//ALenum err = alGetError();
|
||||
|
||||
ALint iBuffersFilled = 0;
|
||||
ALint iBuffersProcessed = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "CDUtils.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include <memory> // for std::unique_ptr
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __APPLE__
|
||||
|
||||
@@ -173,9 +173,7 @@ void CPUInfo::Detect()
|
||||
if (max_ex_fn >= 0x80000001) {
|
||||
// Check for more features.
|
||||
__cpuid(cpu_id, 0x80000001);
|
||||
bool cmp_legacy = false;
|
||||
if (cpu_id[2] & 1) bLAHFSAHF64 = true;
|
||||
if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this?
|
||||
if ((cpu_id[3] >> 29) & 1) bLongMode = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,11 +60,6 @@ private:
|
||||
#undef STACKALIGN
|
||||
#define STACKALIGN __attribute__((__force_align_arg_pointer__))
|
||||
#endif
|
||||
// We use wxWidgets on OS X only if it is version 2.9+ with Cocoa support.
|
||||
#ifdef __WXOSX_COCOA__
|
||||
#define HAVE_WX 1
|
||||
#define USE_WX 1 // Use wxGLCanvas
|
||||
#endif
|
||||
|
||||
#elif defined _WIN32
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
#define WII_EUR_SETTING "setting-eur.txt"
|
||||
#define WII_USA_SETTING "setting-usa.txt"
|
||||
#define WII_JAP_SETTING "setting-jpn.txt"
|
||||
#define WII_KOR_SETTING "setting-kor.txt"
|
||||
|
||||
#define GECKO_CODE_HANDLER "codehandler.bin"
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
virtual void step() {}
|
||||
virtual void runToBreakpoint() {}
|
||||
virtual void breakNow() {}
|
||||
virtual void insertBLR(unsigned int /*address*/, unsigned int) {}
|
||||
virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {}
|
||||
virtual void showJitResults(unsigned int /*address*/) {};
|
||||
virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;}
|
||||
virtual std::string getDescription(unsigned int /*address*/) = 0;
|
||||
|
||||
@@ -299,7 +299,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,13 +310,19 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
ERROR_LOG(COMMON,
|
||||
"Copy: failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
// close flushs
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return true;
|
||||
bail:
|
||||
if (input)
|
||||
fclose(input);
|
||||
if (output)
|
||||
fclose(output);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -643,13 +649,12 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
if (paths[D_USER_IDX].empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: use GetExeDirectory() here instead of ROOT_DIR so that if the cwd is changed we still have the correct paths?
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
#else
|
||||
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
else
|
||||
paths[D_USER_IDX] = std::string(getenv("HOME")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = std::string(getenv("HOME") ? getenv("HOME") : getenv("PWD")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
|
||||
#endif
|
||||
INFO_LOG(COMMON, "GetUserPath: Setting user directory to %s:", paths[D_USER_IDX].c_str());
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ struct Rectangle
|
||||
Rectangle(T theLeft, T theTop, T theRight, T theBottom)
|
||||
: left(theLeft), top(theTop), right(theRight), bottom(theBottom)
|
||||
{ }
|
||||
|
||||
bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; }
|
||||
|
||||
T GetWidth() const { return abs(right - left); }
|
||||
T GetHeight() const { return abs(bottom - top); }
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _SETUP_H_
|
||||
#define _SETUP_H_
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// File description:
|
||||
// Compilation settings. I avoid placing this in Common.h or some place where lots of files needs
|
||||
// to be rebuilt if any of these settings are changed. I'd rather have it in as few files as possible.
|
||||
// This file can be kept on the ignore list in your SVN program. It allows local optional settings
|
||||
// depending on what works on your computer.
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Settings:
|
||||
|
||||
// This may remove sound artifacts in Wario Land Shake It and perhaps other games
|
||||
//#define SETUP_AVOID_SOUND_ARTIFACTS
|
||||
|
||||
// Build with playback rerecording options
|
||||
//#define RERECORDING
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
#endif // _SETUP_H_
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Setup.h"
|
||||
#include "Thread.h"
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
@@ -97,12 +97,6 @@ void Timer::AddTimeDifference()
|
||||
m_StartTime += GetTimeDifference();
|
||||
}
|
||||
|
||||
// Wind back the starting time to a custom time
|
||||
void Timer::WindBackStartingTime(u64 WindBack)
|
||||
{
|
||||
m_StartTime += WindBack;
|
||||
}
|
||||
|
||||
// Get the time elapsed since the Start()
|
||||
u64 Timer::GetTimeElapsed()
|
||||
{
|
||||
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
||||
u64 GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
void WindBackStartingTime(u64 WindBack);
|
||||
|
||||
static void IncreaseResolution();
|
||||
static void RestoreResolution();
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h"
|
||||
#include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h"
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
#include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h"
|
||||
#endif
|
||||
#include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h"
|
||||
|
||||
std::vector<VideoBackend*> g_available_video_backends;
|
||||
@@ -41,7 +43,7 @@ static bool IsGteVista()
|
||||
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
|
||||
return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask);
|
||||
return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask) != FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -52,7 +54,9 @@ void VideoBackend::PopulateList()
|
||||
if (IsGteVista())
|
||||
g_available_video_backends.push_back(new DX11::VideoBackend);
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
g_available_video_backends.push_back(new OGL::VideoBackend);
|
||||
#endif
|
||||
g_available_video_backends.push_back(new SW::VideoSoftware);
|
||||
|
||||
g_video_backend = g_available_video_backends.front();
|
||||
|
||||
@@ -137,6 +137,8 @@ public:
|
||||
|
||||
// the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
virtual void CheckInvalidState() = 0;
|
||||
};
|
||||
|
||||
extern std::vector<VideoBackend*> g_available_video_backends;
|
||||
@@ -176,9 +178,15 @@ class VideoBackendHardware : public VideoBackend
|
||||
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
bool m_invalid;
|
||||
|
||||
public:
|
||||
void CheckInvalidState();
|
||||
|
||||
protected:
|
||||
void InitializeShared();
|
||||
void InvalidState();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,12 +31,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
info.hasImmediate = false;
|
||||
info.isMemoryWrite = false;
|
||||
|
||||
int addressSize = 8;
|
||||
u8 modRMbyte = 0;
|
||||
u8 sibByte = 0;
|
||||
bool hasModRM = false;
|
||||
bool hasSIBbyte = false;
|
||||
bool hasDisplacement = false;
|
||||
|
||||
int displacementSize = 0;
|
||||
|
||||
@@ -47,7 +44,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
}
|
||||
else if (*codePtr == 0x67)
|
||||
{
|
||||
addressSize = 4;
|
||||
codePtr++;
|
||||
}
|
||||
|
||||
@@ -113,7 +109,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
info.otherReg = (sibByte & 7);
|
||||
if (rex & 2) info.scaledReg += 8;
|
||||
if (rex & 1) info.otherReg += 8;
|
||||
hasSIBbyte = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,7 +117,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
}
|
||||
if (mrm.mod == 1 || mrm.mod == 2)
|
||||
{
|
||||
hasDisplacement = true;
|
||||
if (mrm.mod == 1)
|
||||
displacementSize = 1;
|
||||
else
|
||||
|
||||
@@ -870,7 +870,6 @@ void XEmitter::BTC(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest,
|
||||
//shift can be either imm8 or cl
|
||||
void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift)
|
||||
{
|
||||
bool writeImm = false;
|
||||
if (dest.IsImm())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination");
|
||||
@@ -901,7 +900,6 @@ void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift)
|
||||
|
||||
void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift)
|
||||
{
|
||||
bool writeImm = false;
|
||||
if (dest.IsImm())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination");
|
||||
|
||||
@@ -5,7 +5,6 @@ set(SRCS Src/ActionReplay.cpp
|
||||
Src/Console.cpp
|
||||
Src/Core.cpp
|
||||
Src/CoreParameter.cpp
|
||||
Src/CoreRerecording.cpp
|
||||
Src/CoreTiming.cpp
|
||||
Src/DSPEmulator.cpp
|
||||
Src/GeckoCodeConfig.cpp
|
||||
@@ -71,7 +70,8 @@ set(SRCS Src/ActionReplay.cpp
|
||||
Src/HW/CPU.cpp
|
||||
Src/HW/DSP.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AX.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
|
||||
@@ -192,7 +192,11 @@ set(SRCS Src/ActionReplay.cpp
|
||||
Src/PowerPC/JitCommon/JitCache.cpp
|
||||
Src/PowerPC/JitCommon/Jit_Util.cpp)
|
||||
|
||||
set(LIBS bdisasm inputcommon videoogl videosoftware sfml-network)
|
||||
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
||||
|
||||
if(NOT USE_GLES)
|
||||
set(LIBS ${LIBS} videoogl)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp
|
||||
|
||||
@@ -207,7 +207,6 @@
|
||||
<ClCompile Include="Src\Console.cpp" />
|
||||
<ClCompile Include="Src\Core.cpp" />
|
||||
<ClCompile Include="Src\CoreParameter.cpp" />
|
||||
<ClCompile Include="Src\CoreRerecording.cpp" />
|
||||
<ClCompile Include="Src\CoreTiming.cpp" />
|
||||
<ClCompile Include="Src\Debugger\Debugger_SymbolMap.cpp" />
|
||||
<ClCompile Include="Src\Debugger\Dump.cpp" />
|
||||
@@ -262,6 +261,7 @@
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCodes.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AX.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_GBA.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_InitAudioSystem.cpp" />
|
||||
@@ -385,7 +385,11 @@
|
||||
<ClCompile Include="Src\PowerPC\PPCTables.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\Profiler.cpp" />
|
||||
<ClCompile Include="Src\PowerPC\SignatureDB.cpp" />
|
||||
<ClCompile Include="Src\State.cpp" />
|
||||
<ClCompile Include="Src\State.cpp">
|
||||
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport>
|
||||
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport>
|
||||
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
@@ -459,9 +463,11 @@
|
||||
<ClInclude Include="Src\HW\DSPHLE\MailHandler.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCodes.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_GBA.h" />
|
||||
@@ -592,4 +598,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -197,6 +197,9 @@
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
@@ -727,18 +730,24 @@
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h">
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
@@ -1174,4 +1183,4 @@
|
||||
<UniqueIdentifier>{3e9e6e83-c1bf-45f9-aeff-231f98f60d29}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -285,7 +285,6 @@ bool RunCode(const ARCode &arcode)
|
||||
// used for conditional codes
|
||||
int skip_count = 0;
|
||||
|
||||
u32 addr_last = 0;
|
||||
u32 val_last = 0;
|
||||
|
||||
current_code = &arcode;
|
||||
@@ -394,7 +393,6 @@ bool RunCode(const ARCode &arcode)
|
||||
{
|
||||
LogInfo("ZCode: Memory Copy");
|
||||
doMemoryCopy = true;
|
||||
addr_last = addr;
|
||||
val_last = data;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -187,8 +187,10 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
|
||||
switch((DiscIO::IVolume::ECountry)_CountryCode)
|
||||
{
|
||||
case DiscIO::IVolume::COUNTRY_KOREA:
|
||||
region_filename = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP + WII_KOR_SETTING;
|
||||
break;
|
||||
case DiscIO::IVolume::COUNTRY_TAIWAN:
|
||||
// TODO: Determine if Korea / Taiwan have their own specific settings.
|
||||
// TODO: Determine if Taiwan has their own specific settings.
|
||||
case DiscIO::IVolume::COUNTRY_JAPAN:
|
||||
region_filename = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP + WII_JAP_SETTING;
|
||||
break;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "Core.h"
|
||||
#include "Host.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "Movie.h"
|
||||
|
||||
|
||||
namespace BootManager
|
||||
@@ -115,6 +116,19 @@ bool BootCore(const std::string& _rFilename)
|
||||
game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str());
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
StartUp.bCPUThread = Movie::IsDualCore();
|
||||
StartUp.bSkipIdle = Movie::IsSkipIdle();
|
||||
StartUp.bDSPHLE = Movie::IsDSPHLE();
|
||||
StartUp.bProgressive = Movie::IsProgressive();
|
||||
StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed();
|
||||
if (Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave() && !StartUp.bWii)
|
||||
{
|
||||
if (File::Exists("Movie.raw"))
|
||||
File::Delete("Movie.raw");
|
||||
}
|
||||
}
|
||||
// Wii settings
|
||||
if (StartUp.bWii)
|
||||
{
|
||||
|
||||
@@ -131,6 +131,7 @@ void SConfig::SaveSettings()
|
||||
|
||||
// General
|
||||
ini.Set("General", "LastFilename", m_LastFilename);
|
||||
ini.Set("General", "ShowLag", m_ShowLag);
|
||||
|
||||
// ISO folders
|
||||
// clear removed folders
|
||||
@@ -155,10 +156,12 @@ void SConfig::SaveSettings()
|
||||
|
||||
ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder);
|
||||
ini.Set("General", "NANDRoot", m_NANDPath);
|
||||
ini.Set("General", "WirelessMac", m_WirelessMac);
|
||||
|
||||
// Interface
|
||||
ini.Set("Interface", "ConfirmStop", m_LocalCoreStartupParameter.bConfirmStop);
|
||||
ini.Set("Interface", "UsePanicHandlers", m_LocalCoreStartupParameter.bUsePanicHandlers);
|
||||
ini.Set("Interface", "OnScreenDisplayMessages", m_LocalCoreStartupParameter.bOnScreenDisplayMessages);
|
||||
ini.Set("Interface", "HideCursor", m_LocalCoreStartupParameter.bHideCursor);
|
||||
ini.Set("Interface", "AutoHideCursor", m_LocalCoreStartupParameter.bAutoHideCursor);
|
||||
ini.Set("Interface", "Theme", m_LocalCoreStartupParameter.iTheme);
|
||||
@@ -208,6 +211,8 @@ void SConfig::SaveSettings()
|
||||
ini.Set("GameList", "ListKorea", m_ListKorea);
|
||||
ini.Set("GameList", "ListTaiwan", m_ListTaiwan);
|
||||
ini.Set("GameList", "ListUnknown", m_ListUnknown);
|
||||
ini.Set("GameList", "ListSort", m_ListSort);
|
||||
ini.Set("GameList", "ListSortSecondary", m_ListSort2);
|
||||
|
||||
// Core
|
||||
ini.Set("Core", "HLE_BS2", m_LocalCoreStartupParameter.bHLE_BS2);
|
||||
@@ -246,6 +251,10 @@ void SConfig::SaveSettings()
|
||||
// GFX Backend
|
||||
ini.Set("Core", "GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend);
|
||||
|
||||
// Movie
|
||||
ini.Set("Movie", "PauseMovie", m_PauseMovie);
|
||||
ini.Set("Movie", "Author", m_strMovieAuthor);
|
||||
|
||||
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||
m_SYSCONF->Save();
|
||||
}
|
||||
@@ -260,6 +269,7 @@ void SConfig::LoadSettings()
|
||||
// General
|
||||
{
|
||||
ini.Get("General", "LastFilename", &m_LastFilename);
|
||||
ini.Get("General", "ShowLag", &m_ShowLag, false);
|
||||
|
||||
m_ISOFolder.clear();
|
||||
int numGCMPaths;
|
||||
@@ -282,12 +292,14 @@ void SConfig::LoadSettings()
|
||||
m_NANDPath = File::GetUserPath(D_WIIROOT_IDX, m_NANDPath);
|
||||
DiscIO::cUIDsys::AccessInstance().UpdateLocation();
|
||||
DiscIO::CSharedContent::AccessInstance().UpdateLocation();
|
||||
ini.Get("General", "WirelessMac", &m_WirelessMac);
|
||||
}
|
||||
|
||||
{
|
||||
// Interface
|
||||
ini.Get("Interface", "ConfirmStop", &m_LocalCoreStartupParameter.bConfirmStop, false);
|
||||
ini.Get("Interface", "UsePanicHandlers", &m_LocalCoreStartupParameter.bUsePanicHandlers, true);
|
||||
ini.Get("Interface", "OnScreenDisplayMessages", &m_LocalCoreStartupParameter.bOnScreenDisplayMessages, true);
|
||||
ini.Get("Interface", "HideCursor", &m_LocalCoreStartupParameter.bHideCursor, false);
|
||||
ini.Get("Interface", "AutoHideCursor", &m_LocalCoreStartupParameter.bAutoHideCursor, false);
|
||||
ini.Get("Interface", "Theme", &m_LocalCoreStartupParameter.iTheme, 0);
|
||||
@@ -334,11 +346,13 @@ void SConfig::LoadSettings()
|
||||
ini.Get("GameList", "ListPal", &m_ListPal, true);
|
||||
ini.Get("GameList", "ListUsa", &m_ListUsa, true);
|
||||
|
||||
ini.Get("GameList", "ListFrance", &m_ListFrance, true);
|
||||
ini.Get("GameList", "ListItaly", &m_ListItaly, true);
|
||||
ini.Get("GameList", "ListKorea", &m_ListKorea, true);
|
||||
ini.Get("GameList", "ListTaiwan", &m_ListTaiwan, true);
|
||||
ini.Get("GameList", "ListUnknown", &m_ListUnknown, true);
|
||||
ini.Get("GameList", "ListFrance", &m_ListFrance, true);
|
||||
ini.Get("GameList", "ListItaly", &m_ListItaly, true);
|
||||
ini.Get("GameList", "ListKorea", &m_ListKorea, true);
|
||||
ini.Get("GameList", "ListTaiwan", &m_ListTaiwan, true);
|
||||
ini.Get("GameList", "ListUnknown", &m_ListUnknown, true);
|
||||
ini.Get("GameList", "ListSort", &m_ListSort, 3);
|
||||
ini.Get("GameList", "ListSortSecondary",&m_ListSort2, 0);
|
||||
|
||||
// Core
|
||||
ini.Get("Core", "HLE_BS2", &m_LocalCoreStartupParameter.bHLE_BS2, false);
|
||||
@@ -384,6 +398,10 @@ void SConfig::LoadSettings()
|
||||
|
||||
// GFX Backend
|
||||
ini.Get("Core", "GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");
|
||||
|
||||
// Movie
|
||||
ini.Get("General", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "Author", &m_strMovieAuthor, "");
|
||||
}
|
||||
|
||||
m_SYSCONF = new SysConf();
|
||||
|
||||
@@ -75,6 +75,13 @@ struct SConfig : NonCopyable
|
||||
bool m_ListKorea;
|
||||
bool m_ListTaiwan;
|
||||
bool m_ListUnknown;
|
||||
int m_ListSort;
|
||||
int m_ListSort2;
|
||||
|
||||
std::string m_WirelessMac;
|
||||
bool m_PauseMovie;
|
||||
bool m_ShowLag;
|
||||
std::string m_strMovieAuthor;
|
||||
|
||||
SysConf* m_SYSCONF;
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include "EmuWindow.h"
|
||||
#endif
|
||||
|
||||
#include "Setup.h" // Common
|
||||
#include "Atomic.h"
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
@@ -61,9 +61,6 @@
|
||||
#include "VideoBackendBase.h"
|
||||
#include "AudioCommon.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#ifdef _WIN32
|
||||
#include "EmuWindow.h"
|
||||
#endif
|
||||
|
||||
#include "VolumeHandler.h"
|
||||
#include "FileMonitor.h"
|
||||
@@ -293,7 +290,7 @@ void Stop() // - Hammertime!
|
||||
SConfig::GetInstance().m_SYSCONF->Reload();
|
||||
|
||||
INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----");
|
||||
Movie::g_currentInputCount = 0;
|
||||
Movie::Shutdown();
|
||||
g_bStopping = false;
|
||||
}
|
||||
|
||||
@@ -434,7 +431,7 @@ void EmuThread()
|
||||
CBoot::BootUp();
|
||||
|
||||
// Setup our core, but can't use dynarec if we are compare server
|
||||
if (_CoreParameter.iCPUCore && (!_CoreParameter.bRunCompareServer ||
|
||||
if (Movie::GetCPUMode() && (!_CoreParameter.bRunCompareServer ||
|
||||
_CoreParameter.bRunCompareClient))
|
||||
PowerPC::SetMode(PowerPC::MODE_JIT);
|
||||
else
|
||||
|
||||
@@ -95,21 +95,6 @@ void RequestRefreshInfo();
|
||||
// the return value of the first call should be passed in as the second argument of the second call.
|
||||
bool PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
|
||||
|
||||
#ifdef RERECORDING
|
||||
|
||||
void FrameUpdate();
|
||||
void FrameAdvance();
|
||||
void FrameStepOnOff();
|
||||
void WriteStatus();
|
||||
void RerecordingStart();
|
||||
void RerecordingStop();
|
||||
void WindBack(int Counter);
|
||||
|
||||
extern int g_FrameCounter,g_InputCounter;
|
||||
extern bool g_FrameStep;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||
bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
bAutoHideCursor(false), bUsePanicHandlers(true),
|
||||
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
|
||||
iRenderWindowXPos(-1), iRenderWindowYPos(-1),
|
||||
iRenderWindowWidth(640), iRenderWindowHeight(480),
|
||||
bRenderWindowAutoSize(false), bKeepWindowOnTop(false),
|
||||
|
||||
@@ -122,7 +122,7 @@ struct SCoreStartupParameter
|
||||
bool bDisableWiimoteSpeaker;
|
||||
|
||||
// Interface settings
|
||||
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers;
|
||||
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages;
|
||||
|
||||
// Hotkeys
|
||||
int iHotkey[NUM_HOTKEYS];
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
#include "Setup.h"
|
||||
#ifndef RERECORDING
|
||||
bool rerecording = false;
|
||||
#else
|
||||
|
||||
// Include
|
||||
// --------------
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Thread.h" // Common
|
||||
|
||||
#include "Timer.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include "Console.h"
|
||||
#include "Core.h"
|
||||
#include "CPUDetect.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "Boot/Boot.h"
|
||||
#include "PatchEngine.h"
|
||||
|
||||
#include "HW/Memmap.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/CPU.h"
|
||||
#include "HW/HW.h"
|
||||
#include "HW/DSP.h"
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/AudioInterface.h"
|
||||
#include "HW/VideoInterface.h"
|
||||
#include "HW/CommandProcessor.h"
|
||||
#include "HW/PixelEngine.h"
|
||||
#include "HW/SystemTimers.h"
|
||||
|
||||
#include "PowerPC/PowerPC.h"
|
||||
|
||||
#include "ConfigManager.h"
|
||||
|
||||
#include "MemTools.h"
|
||||
#include "Host.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// File description: Rerecording Functions
|
||||
/* ---------------
|
||||
|
||||
How the timer works: We measure the time between drawn frames, not when the game is paused. So time
|
||||
should be a fairly comparable measure of the time it took to play the game. However the time it takes
|
||||
to draw a frame will be lower on a fast computer. Therefore we could perhaps measure time as an
|
||||
internal game time that is adjusted by the average time it takes to draw a frame. Also if it only takes
|
||||
ten or twenty milliseconds to draw a frame I'm not certain about how accurate the mmsystem timers are for
|
||||
such short periods.
|
||||
|
||||
//////////////////////////////////////*/
|
||||
|
||||
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Declarations and definitions
|
||||
// ---------------
|
||||
int g_FrameCounter = 0;
|
||||
bool g_FrameStep = false;
|
||||
Common::Timer ReRecTimer;
|
||||
|
||||
|
||||
|
||||
|
||||
// Control Run, Pause, Stop and the Timer.
|
||||
// ---------------
|
||||
|
||||
// Subtract the paused time when we run again
|
||||
void Run()
|
||||
{
|
||||
ReRecTimer.AddTimeDifference();
|
||||
}
|
||||
// Update the time
|
||||
void Pause()
|
||||
{
|
||||
ReRecTimer.Update();
|
||||
}
|
||||
|
||||
// Start the timer when a game is booted
|
||||
void RerecordingStart()
|
||||
{
|
||||
g_FrameCounter = 0;
|
||||
ReRecTimer.Start();
|
||||
|
||||
// Logging
|
||||
//DEBUG_LOG(CONSOLE, "RerecordingStart: %i\n", g_FrameCounter);
|
||||
}
|
||||
|
||||
// Reset the frame counter
|
||||
void RerecordingStop()
|
||||
{
|
||||
// Write the final time and Stop the timer
|
||||
ReRecTimer.Stop();
|
||||
|
||||
// Update status bar
|
||||
WriteStatus();
|
||||
}
|
||||
|
||||
/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in
|
||||
time so we just guess that the time is proportional the the number of frames
|
||||
|
||||
Todo: There are many assumptions here: We probably want to replace the time here by the actual time
|
||||
that we save together with the save state or the input recording for example. And have it adjusted
|
||||
for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively
|
||||
capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more
|
||||
often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts
|
||||
to frame updates.
|
||||
*/
|
||||
void WindBack(int Counter)
|
||||
{
|
||||
/* Counter should be smaller than g_FrameCounter, however it currently updates faster than the
|
||||
frames so currently it may not be the same. Therefore I use the abs() function. */
|
||||
int AbsoluteFrameDifference = abs(g_FrameCounter - Counter);
|
||||
float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter;
|
||||
|
||||
// Update the frame counter
|
||||
g_FrameCounter = Counter;
|
||||
|
||||
// Approximate a time to wind back the clock to
|
||||
// Get the current time
|
||||
u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed();
|
||||
// Save the current time in seconds in a new double
|
||||
double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000);
|
||||
// Reduce it by the same proportion as the counter was wound back
|
||||
CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference;
|
||||
// Update the clock
|
||||
ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000);
|
||||
|
||||
// Logging
|
||||
DEBUG_LOG(CONSOLE, "WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Frame advance
|
||||
// ---------------
|
||||
void FrameAdvance()
|
||||
{
|
||||
// Update status bar
|
||||
WriteStatus();
|
||||
|
||||
// If a game is not started, return
|
||||
if (Core::GetState() == Core::CORE_UNINITIALIZED) return;
|
||||
|
||||
// Play to the next frame
|
||||
if (g_FrameStep)
|
||||
{
|
||||
Run();
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
}
|
||||
}
|
||||
|
||||
// Turn on frame stepping
|
||||
void FrameStepOnOff()
|
||||
{
|
||||
/* Turn frame step on or off. If a game is running and we turn this on it means that the game
|
||||
will pause after the next frame update */
|
||||
g_FrameStep = !g_FrameStep;
|
||||
|
||||
// Update status bar
|
||||
WriteStatus();
|
||||
|
||||
// If a game is not started, return
|
||||
if(Core::GetState() == Core::CORE_UNINITIALIZED) return;
|
||||
|
||||
// Run the emulation if we turned off framestepping
|
||||
if (!g_FrameStep)
|
||||
{
|
||||
Run();
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// General functions
|
||||
// ---------------
|
||||
|
||||
// Write to the status bar
|
||||
void WriteStatus()
|
||||
{
|
||||
std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted();
|
||||
TmpStr += StringFromFormat(" Frame: %s", ThousandSeparate(g_FrameCounter).c_str());
|
||||
// The FPS is the total average since the game was booted
|
||||
TmpStr += StringFromFormat(" FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed());
|
||||
TmpStr += StringFromFormat(" FrameStep: %s", g_FrameStep ? "On" : "Off");
|
||||
Host_UpdateStatusBar(TmpStr.c_str(), 1);
|
||||
}
|
||||
|
||||
|
||||
// When a new frame is drawn
|
||||
void FrameUpdate()
|
||||
{
|
||||
// Write to the status bar
|
||||
WriteStatus();
|
||||
/* I don't think the frequent update has any material speed inpact at all, but should it
|
||||
have you can controls the update speed by changing the "% 10" in this line */
|
||||
//if (g_FrameCounter % 10 == 0) WriteStatus();
|
||||
|
||||
// Pause if frame stepping is on
|
||||
if(g_FrameStep)
|
||||
{
|
||||
Pause();
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
}
|
||||
|
||||
// Count one frame
|
||||
g_FrameCounter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // Core
|
||||
|
||||
|
||||
#endif // RERECORDING
|
||||
@@ -119,7 +119,7 @@ int RegisterEvent(const char *name, TimedCallback callback)
|
||||
|
||||
// check for existing type with same name.
|
||||
// we want event type names to remain unique so that we can use them for serialization.
|
||||
for (int i = 0; i < event_types.size(); ++i)
|
||||
for (unsigned int i = 0; i < event_types.size(); ++i)
|
||||
{
|
||||
if (!strcmp(name, event_types[i].name))
|
||||
{
|
||||
@@ -188,7 +188,7 @@ void EventDoState(PointerWrap &p, BaseEvent* ev)
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
bool foundMatch = false;
|
||||
for (int i = 0; i < event_types.size(); ++i)
|
||||
for (unsigned int i = 0; i < event_types.size(); ++i)
|
||||
{
|
||||
if (!strcmp(name.c_str(), event_types[i].name))
|
||||
{
|
||||
|
||||
@@ -168,7 +168,8 @@ u16 dsp_read_accelerator()
|
||||
if (Address >= EndAddress)
|
||||
{
|
||||
// Set address back to start address.
|
||||
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
|
||||
if ((Address & ~0x1f) == (EndAddress & ~0x1f))
|
||||
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
|
||||
DSPCore_SetException(EXP_ACCOV);
|
||||
}
|
||||
|
||||
|
||||
@@ -220,8 +220,8 @@ void DSPJitRegCache::flushRegs(DSPJitRegCache &cache, bool emit)
|
||||
for(i = 0; i <= DSP_REG_MAX_MEM_BACKED; i++) {
|
||||
if (cache.regs[i].loc.GetSimpleReg() !=
|
||||
regs[i].loc.GetSimpleReg() &&
|
||||
xregs[cache.regs[i].loc.GetSimpleReg()].guest_reg ==
|
||||
DSP_REG_NONE) {
|
||||
xregs[cache.regs[i].loc.GetSimpleReg()].guest_reg == DSP_REG_NONE)
|
||||
{
|
||||
movToHostReg(i,
|
||||
cache.regs[i].loc.GetSimpleReg(),
|
||||
true);
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
virtual void step() {}
|
||||
virtual void breakNow();
|
||||
virtual void runToBreakpoint();
|
||||
virtual void insertBLR(unsigned int address, unsigned int);
|
||||
virtual void insertBLR(unsigned int address, unsigned int value);
|
||||
virtual int getColor(unsigned int address);
|
||||
virtual std::string getDescription(unsigned int address);
|
||||
virtual void showJitResults(u32 address);
|
||||
|
||||
@@ -171,7 +171,7 @@ bool InstallCodeHandler()
|
||||
Memory::Write_U8(1, 0x80001807);
|
||||
|
||||
// Invalidate the icache
|
||||
for (int i = 0; i < data.length(); i += 32)
|
||||
for (unsigned int i = 0; i < data.length(); i += 32)
|
||||
{
|
||||
PowerPC::ppcState.iCache.Invalidate(0x80001800 + i);
|
||||
}
|
||||
|
||||
@@ -42,8 +42,6 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||
|
||||
std::istringstream ss(*lines_iter);
|
||||
|
||||
int read_state = 0;
|
||||
|
||||
switch ((*lines_iter)[0])
|
||||
{
|
||||
|
||||
@@ -61,7 +59,6 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||
gcode.name = StripSpaces(gcode.name);
|
||||
// read the code creator name
|
||||
std::getline(ss, gcode.creator, ']');
|
||||
read_state = 0;
|
||||
break;
|
||||
|
||||
// notes
|
||||
|
||||
@@ -354,9 +354,6 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
|
||||
|
||||
static s16 l1 = 0;
|
||||
static s16 l2 = 0;
|
||||
static s16 r1 = 0;
|
||||
static s16 r2 = 0;
|
||||
|
||||
|
||||
if ( frac >= 0x10000 || frac == 0)
|
||||
{
|
||||
@@ -364,9 +361,6 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
|
||||
|
||||
l1 = l2; //current
|
||||
l2 = pcm[pos * 2]; //next
|
||||
|
||||
r1 = r2; //current
|
||||
r2 = pcm[pos * 2 + 1]; //next
|
||||
}
|
||||
|
||||
pcm_l = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../Core.h"
|
||||
#include "CPU.h"
|
||||
#include "DSP.h"
|
||||
#include "Movie.h"
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
@@ -36,6 +37,10 @@ namespace
|
||||
|
||||
void CCPU::Init(int cpu_core)
|
||||
{
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
cpu_core = Movie::GetCPUMode();
|
||||
}
|
||||
PowerPC::Init(cpu_core);
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
|
||||
@@ -697,14 +697,12 @@ void UpdateAudioDMA()
|
||||
|
||||
void Do_ARAM_DMA()
|
||||
{
|
||||
// Fake the DMA taking time to complete. The delay is not accurate, but
|
||||
// seems like a good estimate
|
||||
CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
|
||||
// Emulating the DMA wait time fixes Knockout Kings 2003 in DSP HLE mode
|
||||
if (!GetDSPEmulator()->IsLLE())
|
||||
g_dspState.DSPControl.DMAState = 1;
|
||||
|
||||
GenerateDSPInterrupt(INT_ARAM, true);
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
if (g_arDMA.Cnt.dir)
|
||||
{
|
||||
@@ -720,6 +718,8 @@ void Do_ARAM_DMA()
|
||||
{
|
||||
while (g_arDMA.Cnt.count)
|
||||
{
|
||||
// These are logically seperated in code to show that a memory map has been set up
|
||||
// See below in the write section for more information
|
||||
if ((g_ARAM_Info.Hex & 0xf) == 3)
|
||||
{
|
||||
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "ChunkFile.h"
|
||||
#include "IniFile.h"
|
||||
#include "HLEMixer.h"
|
||||
#include "Setup.h"
|
||||
#include "StringUtil.h"
|
||||
#include "LogManager.h"
|
||||
#include "IniFile.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,52 +12,162 @@
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX
|
||||
#define _UCODE_AX
|
||||
// High-level emulation for the AX Gamecube UCode.
|
||||
//
|
||||
// TODO:
|
||||
// * Depop support
|
||||
// * ITD support
|
||||
// * Polyphase sample interpolation support (not very useful)
|
||||
// * Dolby Pro 2 mixing with recent AX versions
|
||||
|
||||
#include <iostream>
|
||||
#include "UCode_AXStructs.h"
|
||||
#ifndef _UCODE_AX_H
|
||||
#define _UCODE_AX_H
|
||||
|
||||
enum
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
|
||||
// We can't directly use the mixer_control field from the PB because it does
|
||||
// not mean the same in all AX versions. The AX UCode converts the
|
||||
// mixer_control value to an AXMixControl bitfield.
|
||||
enum AXMixControl
|
||||
{
|
||||
NUMBER_OF_PBS = 128
|
||||
MIX_L = 0x000001,
|
||||
MIX_L_RAMP = 0x000002,
|
||||
MIX_R = 0x000004,
|
||||
MIX_R_RAMP = 0x000008,
|
||||
MIX_S = 0x000010,
|
||||
MIX_S_RAMP = 0x000020,
|
||||
|
||||
MIX_AUXA_L = 0x000040,
|
||||
MIX_AUXA_L_RAMP = 0x000080,
|
||||
MIX_AUXA_R = 0x000100,
|
||||
MIX_AUXA_R_RAMP = 0x000200,
|
||||
MIX_AUXA_S = 0x000400,
|
||||
MIX_AUXA_S_RAMP = 0x000800,
|
||||
|
||||
MIX_AUXB_L = 0x001000,
|
||||
MIX_AUXB_L_RAMP = 0x002000,
|
||||
MIX_AUXB_R = 0x004000,
|
||||
MIX_AUXB_R_RAMP = 0x008000,
|
||||
MIX_AUXB_S = 0x010000,
|
||||
MIX_AUXB_S_RAMP = 0x020000,
|
||||
|
||||
MIX_AUXC_L = 0x040000,
|
||||
MIX_AUXC_L_RAMP = 0x080000,
|
||||
MIX_AUXC_R = 0x100000,
|
||||
MIX_AUXC_R_RAMP = 0x200000,
|
||||
MIX_AUXC_S = 0x400000,
|
||||
MIX_AUXC_S_RAMP = 0x800000
|
||||
};
|
||||
|
||||
class CUCode_AX : public IUCode
|
||||
class CUCode_AX : public IUCode
|
||||
{
|
||||
public:
|
||||
CUCode_AX(DSPHLE *dsp_hle, u32 _CRC);
|
||||
CUCode_AX(DSPHLE* dsp_hle, u32 crc);
|
||||
virtual ~CUCode_AX();
|
||||
|
||||
void HandleMail(u32 _uMail);
|
||||
void MixAdd(short* _pBuffer, int _iSize);
|
||||
void Update(int cycles);
|
||||
void DoState(PointerWrap &p);
|
||||
virtual void HandleMail(u32 mail);
|
||||
virtual void MixAdd(short* out_buffer, int nsamples);
|
||||
virtual void Update(int cycles);
|
||||
virtual void DoState(PointerWrap& p);
|
||||
|
||||
// PBs
|
||||
u8 numPBaddr;
|
||||
u32 PBaddr[8]; //2 needed for MP2
|
||||
u32 m_addressPBs;
|
||||
// Needed because StdThread.h std::thread implem does not support member
|
||||
// pointers.
|
||||
static void SpawnAXThread(CUCode_AX* self);
|
||||
|
||||
private:
|
||||
enum
|
||||
protected:
|
||||
enum MailType
|
||||
{
|
||||
MAIL_AX_ALIST = 0xBABE0000,
|
||||
AXLIST_STUDIOADDR = 0x0000,
|
||||
AXLIST_PBADDR = 0x0002,
|
||||
AXLIST_SBUFFER = 0x0007,
|
||||
AXLIST_COMPRESSORTABLE = 0x000A,
|
||||
AXLIST_END = 0x000F
|
||||
MAIL_RESUME = 0xCDD10000,
|
||||
MAIL_NEW_UCODE = 0xCDD10001,
|
||||
MAIL_RESET = 0xCDD10002,
|
||||
MAIL_CONTINUE = 0xCDD10003,
|
||||
|
||||
// CPU sends 0xBABE0000 | cmdlist_size to the DSP
|
||||
MAIL_CMDLIST = 0xBABE0000,
|
||||
MAIL_CMDLIST_MASK = 0xFFFF0000
|
||||
};
|
||||
|
||||
int *templbuffer;
|
||||
int *temprbuffer;
|
||||
// 32 * 5 because 32 samples per millisecond, for max 5 milliseconds.
|
||||
int m_samples_left[32 * 5];
|
||||
int m_samples_right[32 * 5];
|
||||
int m_samples_surround[32 * 5];
|
||||
int m_samples_auxA_left[32 * 5];
|
||||
int m_samples_auxA_right[32 * 5];
|
||||
int m_samples_auxA_surround[32 * 5];
|
||||
int m_samples_auxB_left[32 * 5];
|
||||
int m_samples_auxB_right[32 * 5];
|
||||
int m_samples_auxB_surround[32 * 5];
|
||||
|
||||
// ax task message handler
|
||||
bool AXTask(u32& _uMail);
|
||||
// Volatile because it's set by HandleMail and accessed in
|
||||
// HandleCommandList, which are running in two different threads.
|
||||
volatile u16 m_cmdlist[512];
|
||||
volatile u32 m_cmdlist_size;
|
||||
|
||||
std::thread m_axthread;
|
||||
|
||||
// Sync objects
|
||||
std::mutex m_processing;
|
||||
std::condition_variable m_cmdlist_cv;
|
||||
std::mutex m_cmdlist_mutex;
|
||||
|
||||
// Copy a command list from memory to our temp buffer
|
||||
void CopyCmdList(u32 addr, u16 size);
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
// Send a notification to the AX thread to tell him a new cmdlist addr is
|
||||
// available for processing.
|
||||
void NotifyAXThread();
|
||||
|
||||
void AXThread();
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
|
||||
void UploadLRS(u32 dst_addr);
|
||||
void SetMainLR(u32 src_addr);
|
||||
void OutputSamples(u32 out_addr, u32 surround_addr);
|
||||
void MixAUXBLR(u32 ul_addr, u32 dl_addr);
|
||||
void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
|
||||
u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl);
|
||||
|
||||
// Handle save states for main AX.
|
||||
void DoAXState(PointerWrap& p);
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_DL_AND_VOL_MIX = 0x01,
|
||||
CMD_PB_ADDR = 0x02,
|
||||
CMD_PROCESS = 0x03,
|
||||
CMD_MIX_AUXA = 0x04,
|
||||
CMD_MIX_AUXB = 0x05,
|
||||
CMD_UPLOAD_LRS = 0x06,
|
||||
CMD_SET_LR = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_MIX_AUXB_NOWRITE = 0x09,
|
||||
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
|
||||
CMD_UNK_0B = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_MORE = 0x0D,
|
||||
CMD_OUTPUT = 0x0E,
|
||||
CMD_END = 0x0F,
|
||||
CMD_MIX_AUXB_LR = 0x10,
|
||||
CMD_UNK_11 = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_SEND_AUX_AND_MIX = 0x13,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AX
|
||||
#endif // !_UCODE_AX_H
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
#include "UCode_AX.h" // for some functions in CUCode_AX
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_AX_Voice.h"
|
||||
#include "UCode_AXWii_Voice.h"
|
||||
|
||||
|
||||
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
@@ -159,8 +159,8 @@ void CUCode_AXWii::Update(int cycles)
|
||||
bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
{
|
||||
u32 uAddress = _uMail;
|
||||
u32 Addr__AXStudio;
|
||||
u32 Addr__AXOutSBuffer;
|
||||
//u32 Addr__AXStudio;
|
||||
//u32 Addr__AXOutSBuffer;
|
||||
bool bExecuteList = true;
|
||||
|
||||
/*
|
||||
@@ -178,7 +178,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
switch (iCommand)
|
||||
{
|
||||
case 0x0000:
|
||||
Addr__AXStudio = HLEMemory_Read_U32(uAddress);
|
||||
//Addr__AXStudio = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
@@ -193,7 +193,8 @@ bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
case 0x0004:
|
||||
// PBs are here now
|
||||
m_addressPBs = HLEMemory_Read_U32(uAddress);
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
if (soundStream)
|
||||
soundStream->GetMixer()->SetHLEReady(true);
|
||||
// soundStream->Update();
|
||||
uAddress += 4;
|
||||
break;
|
||||
@@ -208,7 +209,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
break;
|
||||
|
||||
case 0x0007: // AXLIST_SBUFFER
|
||||
Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress);
|
||||
//Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress);
|
||||
uAddress += 10;
|
||||
break;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef _UCODE_AXWII
|
||||
#define _UCODE_AXWII
|
||||
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
|
||||
#define NUMBER_OF_PBS 128
|
||||
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AXWII_VOICE_H
|
||||
#define _UCODE_AXWII_VOICE_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXWii_ADPCM.h"
|
||||
#include "UCode_AX.h"
|
||||
#include "Mixer.h"
|
||||
#include "../../AudioInterface.h"
|
||||
|
||||
// MRAM -> ARAM for GC
|
||||
inline bool ReadPB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRAM -> ARAM for Wii
|
||||
inline bool ReadPB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
// preswap the mixer_control
|
||||
PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for GC
|
||||
inline bool WritePB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for Wii
|
||||
inline bool WritePB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
// preswap the mixer_control
|
||||
*(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: fix handling of gc/wii PB differences
|
||||
// TODO: generally fix up the mess - looks crazy and kinda wrong
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb,
|
||||
int *templbuffer, int *temprbuffer,
|
||||
int _iSize)
|
||||
{
|
||||
if (pb.running)
|
||||
{
|
||||
const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo)
|
||||
* /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate()));
|
||||
u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
|
||||
u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
|
||||
|
||||
u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo;
|
||||
u32 frac = pb.src.cur_addr_frac;
|
||||
|
||||
// =======================================================================================
|
||||
// Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0
|
||||
// and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This
|
||||
// makes samplePos update in the correct way. I'm unsure how we are actually supposed to
|
||||
// detect that this setting. Updates did not fix this automatically.
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Stream settings
|
||||
// src_type = 2 (most other games have src_type = 0)
|
||||
// Affected games:
|
||||
// Baten Kaitos - Eternal Wings (2003)
|
||||
// Baten Kaitos - Origins (2006)?
|
||||
// Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps
|
||||
// the sound format plays in to, Baten use ADPCM, SC2 use PCM16
|
||||
//if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
{
|
||||
pb.src.ratio_hi = 1;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Games that use looping to play non-looping music streams - SSBM has info in all
|
||||
// pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams
|
||||
// like any other looping streams the music works. I'm unsure how we are actually supposed to
|
||||
// detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may
|
||||
// identify these types of blocks. Updates did not write any looping values.
|
||||
if (
|
||||
(pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2)
|
||||
&& pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F
|
||||
)
|
||||
{
|
||||
pb.audio_addr.looping = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top Spin 3 Wii
|
||||
if (pb.audio_addr.sample_format > 25)
|
||||
pb.audio_addr.sample_format = 0;
|
||||
|
||||
// =======================================================================================
|
||||
// Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to
|
||||
// compensate for that. _iSize can be as low as 100 or as high as 2000 some cases.
|
||||
for (int s = 0; s < _iSize; s++)
|
||||
{
|
||||
int sample = 0;
|
||||
u32 oldFrac = frac;
|
||||
frac += ratio;
|
||||
u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac
|
||||
|
||||
// =======================================================================================
|
||||
// Process sample format
|
||||
switch (pb.audio_addr.sample_format)
|
||||
{
|
||||
case AUDIOFORMAT_PCM8:
|
||||
pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample
|
||||
pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_PCM16:
|
||||
pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample
|
||||
pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_ADPCM:
|
||||
ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac);
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overall volume control. In addition to this there is also separate volume settings to
|
||||
// different channels (left, right etc).
|
||||
frac &= 0xffff;
|
||||
|
||||
int vol = pb.vol_env.cur_volume >> 9;
|
||||
sample = sample * vol >> 8;
|
||||
|
||||
if (pb.mixer_control & MIXCONTROL_RAMPING)
|
||||
{
|
||||
int x = pb.vol_env.cur_volume;
|
||||
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||
// that use this? Or how does it work?
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 0x7fff)
|
||||
x = 0x7fff;
|
||||
pb.vol_env.cur_volume = x; // maybe not per sample?? :P
|
||||
}
|
||||
|
||||
int leftmix = pb.mixer.left >> 5;
|
||||
int rightmix = pb.mixer.right >> 5;
|
||||
int left = sample * leftmix >> 8;
|
||||
int right = sample * rightmix >> 8;
|
||||
// adpcm has to walk from oldSamplePos to samplePos here
|
||||
templbuffer[s] += left;
|
||||
temprbuffer[s] += right;
|
||||
|
||||
// Control the behavior when we reach the end of the sample
|
||||
if (samplePos >= sampleEnd)
|
||||
{
|
||||
if (pb.audio_addr.looping == 1)
|
||||
{
|
||||
if ((samplePos & ~0x1f) == (sampleEnd & ~0x1f) || (pb.audio_addr.sample_format != AUDIOFORMAT_ADPCM))
|
||||
samplePos = loopPos;
|
||||
if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM))
|
||||
{
|
||||
pb.adpcm.yn1 = pb.adpcm_loop_info.yn1;
|
||||
pb.adpcm.yn2 = pb.adpcm_loop_info.yn2;
|
||||
pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pb.running = 0;
|
||||
samplePos = loopPos;
|
||||
//samplePos = samplePos - sampleEnd + loopPos;
|
||||
memset(&pb.dpop, 0, sizeof(pb.dpop));
|
||||
memset(pb.src.last_samples, 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of the _iSize loop
|
||||
|
||||
// Update volume
|
||||
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
|
||||
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
|
||||
|
||||
pb.src.cur_addr_frac = (u16)frac;
|
||||
pb.audio_addr.cur_addr_hi = samplePos >> 16;
|
||||
pb.audio_addr.cur_addr_lo = (u16)samplePos;
|
||||
|
||||
} // if (pb.running)
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,392 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX_STRUCTS_H
|
||||
#define _UCODE_AX_STRUCTS_H
|
||||
|
||||
struct PBMixer
|
||||
{
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 auxA_left;
|
||||
u16 auxA_left_delta;
|
||||
u16 auxA_right;
|
||||
u16 auxA_right_delta;
|
||||
|
||||
u16 auxB_left;
|
||||
u16 auxB_left_delta;
|
||||
u16 auxB_right;
|
||||
u16 auxB_right_delta;
|
||||
|
||||
u16 auxB_surround;
|
||||
u16 auxB_surround_delta;
|
||||
u16 surround;
|
||||
u16 surround_delta;
|
||||
u16 auxA_surround;
|
||||
u16 auxA_surround_delta;
|
||||
};
|
||||
|
||||
struct PBMixerWii
|
||||
{
|
||||
// volume mixing values in .15, 0x8000 = ca. 1.0
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 auxA_left;
|
||||
u16 auxA_left_delta;
|
||||
u16 auxA_right;
|
||||
u16 auxA_right_delta;
|
||||
|
||||
u16 auxB_left;
|
||||
u16 auxB_left_delta;
|
||||
u16 auxB_right;
|
||||
u16 auxB_right_delta;
|
||||
|
||||
// Note: the following elements usage changes a little in DPL2 mode
|
||||
// TODO: implement and comment it in the mixer
|
||||
u16 auxC_left;
|
||||
u16 auxC_left_delta;
|
||||
u16 auxC_right;
|
||||
u16 auxC_right_delta;
|
||||
|
||||
u16 surround;
|
||||
u16 surround_delta;
|
||||
u16 auxA_surround;
|
||||
u16 auxA_surround_delta;
|
||||
u16 auxB_surround;
|
||||
u16 auxB_surround_delta;
|
||||
u16 auxC_surround;
|
||||
u16 auxC_surround_delta;
|
||||
};
|
||||
|
||||
struct PBMixerWM
|
||||
{
|
||||
u16 main0;
|
||||
u16 main0_delta;
|
||||
u16 aux0;
|
||||
u16 aux0_delta;
|
||||
|
||||
u16 main1;
|
||||
u16 main1_delta;
|
||||
u16 aux1;
|
||||
u16 aux1_delta;
|
||||
|
||||
u16 main2;
|
||||
u16 main2_delta;
|
||||
u16 aux2;
|
||||
u16 aux2_delta;
|
||||
|
||||
u16 main3;
|
||||
u16 main3_delta;
|
||||
u16 aux3;
|
||||
u16 aux3_delta;
|
||||
};
|
||||
|
||||
struct PBInitialTimeDelay
|
||||
{
|
||||
u16 on;
|
||||
u16 addrMemHigh;
|
||||
u16 addrMemLow;
|
||||
u16 offsetLeft;
|
||||
u16 offsetRight;
|
||||
u16 targetLeft;
|
||||
u16 targetRight;
|
||||
};
|
||||
|
||||
// Update data - read these each 1ms subframe and use them!
|
||||
// It seems that to provide higher time precisions for MIDI events, some games
|
||||
// use this thing to update the parameter blocks per 1ms sub-block (a block is 5ms).
|
||||
// Using this data should fix games that are missing MIDI notes.
|
||||
struct PBUpdates
|
||||
{
|
||||
u16 num_updates[5];
|
||||
u16 data_hi; // These point to main RAM. Not sure about the structure of the data.
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
// The DSP stores the final sample values for each voice after every frame of processing.
|
||||
// The values are then accumulated for all dropped voices, added to the next frame of audio,
|
||||
// and ramped down on a per-sample basis to provide a gentle "roll off."
|
||||
struct PBDpop
|
||||
{
|
||||
s16 left;
|
||||
s16 auxA_left;
|
||||
s16 auxB_left;
|
||||
|
||||
s16 right;
|
||||
s16 auxA_right;
|
||||
s16 auxB_right;
|
||||
|
||||
s16 surround;
|
||||
s16 auxA_surround;
|
||||
s16 auxB_surround;
|
||||
};
|
||||
|
||||
struct PBDpopWii
|
||||
{
|
||||
s16 left;
|
||||
s16 auxA_left;
|
||||
s16 auxB_left;
|
||||
s16 auxC_left;
|
||||
|
||||
s16 right;
|
||||
s16 auxA_right;
|
||||
s16 auxB_right;
|
||||
s16 auxC_right;
|
||||
|
||||
s16 surround;
|
||||
s16 auxA_surround;
|
||||
s16 auxB_surround;
|
||||
s16 auxC_surround;
|
||||
};
|
||||
|
||||
struct PBDpopWM
|
||||
{
|
||||
s16 aMain0;
|
||||
s16 aMain1;
|
||||
s16 aMain2;
|
||||
s16 aMain3;
|
||||
|
||||
s16 aAux0;
|
||||
s16 aAux1;
|
||||
s16 aAux2;
|
||||
s16 aAux3;
|
||||
};
|
||||
|
||||
struct PBVolumeEnvelope
|
||||
{
|
||||
u16 cur_volume; // volume at start of frame
|
||||
s16 cur_volume_delta; // signed per sample delta (96 samples per frame)
|
||||
};
|
||||
|
||||
struct PBUnknown2
|
||||
{
|
||||
u16 unknown_reserved[3];
|
||||
};
|
||||
|
||||
struct PBAudioAddr
|
||||
{
|
||||
u16 looping;
|
||||
u16 sample_format;
|
||||
u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active)
|
||||
u16 loop_addr_lo;
|
||||
u16 end_addr_hi; // End of sample (and loop), inclusive
|
||||
u16 end_addr_lo;
|
||||
u16 cur_addr_hi;
|
||||
u16 cur_addr_lo;
|
||||
};
|
||||
|
||||
struct PBADPCMInfo
|
||||
{
|
||||
s16 coefs[16];
|
||||
u16 gain;
|
||||
u16 pred_scale;
|
||||
s16 yn1;
|
||||
s16 yn2;
|
||||
};
|
||||
|
||||
struct PBSampleRateConverter
|
||||
{
|
||||
// ratio = (f32)ratio * 0x10000;
|
||||
// valid range is 1/512 to 4.0000
|
||||
u16 ratio_hi; // integer part of sampling ratio
|
||||
u16 ratio_lo; // fraction part of sampling ratio
|
||||
u16 cur_addr_frac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBSampleRateConverterWM
|
||||
{
|
||||
u16 currentAddressFrac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBADPCMLoopInfo
|
||||
{
|
||||
u16 pred_scale;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
};
|
||||
|
||||
struct PBLowPassFilter
|
||||
{
|
||||
u16 enabled;
|
||||
u16 yn1;
|
||||
u16 a0;
|
||||
u16 b0;
|
||||
};
|
||||
|
||||
struct AXPB
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, ?, linear)
|
||||
u16 coef_select;
|
||||
u16 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixer mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdates updates;
|
||||
PBDpop dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBUnknown2 unknown3;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
|
||||
u16 padding[25];
|
||||
};
|
||||
|
||||
struct PBBiquadFilter
|
||||
{
|
||||
|
||||
u16 on; // on = 2, off = 0
|
||||
u16 xn1; // History data
|
||||
u16 xn2;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
u16 b0; // Filter coefficients
|
||||
u16 b1;
|
||||
u16 b2;
|
||||
u16 a1;
|
||||
u16 a2;
|
||||
|
||||
};
|
||||
|
||||
union PBInfImpulseResponseWM
|
||||
{
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
};
|
||||
|
||||
struct AXPBWii
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u16 mixer_control_hi;
|
||||
u16 mixer_control_lo;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[12]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p
|
||||
struct PBUpdatesWiiSports
|
||||
{
|
||||
u16 num_updates[3];
|
||||
u16 data_hi;
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
struct AXPBWiiSports
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u32 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdatesWiiSports updates;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[7]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// TODO: All these enums have changed a lot for wii
|
||||
enum {
|
||||
AUDIOFORMAT_ADPCM = 0,
|
||||
AUDIOFORMAT_PCM8 = 0x19,
|
||||
AUDIOFORMAT_PCM16 = 0xA,
|
||||
};
|
||||
|
||||
enum {
|
||||
SRCTYPE_POLYPHASE = 0,
|
||||
SRCTYPE_LINEAR = 1,
|
||||
SRCTYPE_NEAREST = 2,
|
||||
};
|
||||
|
||||
// Both may be used at once
|
||||
enum {
|
||||
FILTER_LOWPASS = 1,
|
||||
FILTER_BIQUAD = 2,
|
||||
};
|
||||
|
||||
#endif // _UCODE_AX_STRUCTS_H
|
||||
@@ -12,259 +12,389 @@
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
// This file is UGLY (full of #ifdef) so that it can be used with both GC and
|
||||
// Wii version of AX. Maybe it would be better to abstract away the parts that
|
||||
// can be made common.
|
||||
|
||||
#ifndef _UCODE_AX_VOICE_H
|
||||
#define _UCODE_AX_VOICE_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_ADPCM.h"
|
||||
#include "UCode_AX.h"
|
||||
#include "Mixer.h"
|
||||
#include "../../AudioInterface.h"
|
||||
|
||||
// MRAM -> ARAM for GC
|
||||
inline bool ReadPB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRAM -> ARAM for Wii
|
||||
inline bool ReadPB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
// preswap the mixer_control
|
||||
PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for GC
|
||||
inline bool WritePB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for Wii
|
||||
inline bool WritePB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
// preswap the mixer_control
|
||||
*(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: fix handling of gc/wii PB differences
|
||||
// TODO: generally fix up the mess - looks crazy and kinda wrong
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb,
|
||||
int *templbuffer, int *temprbuffer,
|
||||
int _iSize)
|
||||
{
|
||||
if (pb.running)
|
||||
{
|
||||
const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo)
|
||||
* /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate()));
|
||||
u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
|
||||
u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
|
||||
|
||||
u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo;
|
||||
u32 frac = pb.src.cur_addr_frac;
|
||||
|
||||
// =======================================================================================
|
||||
// Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0
|
||||
// and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This
|
||||
// makes samplePos update in the correct way. I'm unsure how we are actually supposed to
|
||||
// detect that this setting. Updates did not fix this automatically.
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Stream settings
|
||||
// src_type = 2 (most other games have src_type = 0)
|
||||
// Affected games:
|
||||
// Baten Kaitos - Eternal Wings (2003)
|
||||
// Baten Kaitos - Origins (2006)?
|
||||
// Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps
|
||||
// the sound format plays in to, Baten use ADPCM, SC2 use PCM16
|
||||
//if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
{
|
||||
pb.src.ratio_hi = 1;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Games that use looping to play non-looping music streams - SSBM has info in all
|
||||
// pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams
|
||||
// like any other looping streams the music works. I'm unsure how we are actually supposed to
|
||||
// detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may
|
||||
// identify these types of blocks. Updates did not write any looping values.
|
||||
if (
|
||||
(pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2)
|
||||
&& pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F
|
||||
)
|
||||
{
|
||||
pb.audio_addr.looping = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top Spin 3 Wii
|
||||
if (pb.audio_addr.sample_format > 25)
|
||||
pb.audio_addr.sample_format = 0;
|
||||
|
||||
// =======================================================================================
|
||||
// Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to
|
||||
// compensate for that. _iSize can be as low as 100 or as high as 2000 some cases.
|
||||
for (int s = 0; s < _iSize; s++)
|
||||
{
|
||||
int sample = 0;
|
||||
u32 oldFrac = frac;
|
||||
frac += ratio;
|
||||
u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac
|
||||
|
||||
// =======================================================================================
|
||||
// Process sample format
|
||||
switch (pb.audio_addr.sample_format)
|
||||
{
|
||||
case AUDIOFORMAT_PCM8:
|
||||
pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample
|
||||
pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_PCM16:
|
||||
pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample
|
||||
pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_ADPCM:
|
||||
ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac);
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overall volume control. In addition to this there is also separate volume settings to
|
||||
// different channels (left, right etc).
|
||||
frac &= 0xffff;
|
||||
|
||||
int vol = pb.vol_env.cur_volume >> 9;
|
||||
sample = sample * vol >> 8;
|
||||
|
||||
if (pb.mixer_control & MIXCONTROL_RAMPING)
|
||||
{
|
||||
int x = pb.vol_env.cur_volume;
|
||||
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||
// that use this? Or how does it work?
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 0x7fff)
|
||||
x = 0x7fff;
|
||||
pb.vol_env.cur_volume = x; // maybe not per sample?? :P
|
||||
}
|
||||
|
||||
int leftmix = pb.mixer.left >> 5;
|
||||
int rightmix = pb.mixer.right >> 5;
|
||||
int left = sample * leftmix >> 8;
|
||||
int right = sample * rightmix >> 8;
|
||||
// adpcm has to walk from oldSamplePos to samplePos here
|
||||
templbuffer[s] += left;
|
||||
temprbuffer[s] += right;
|
||||
|
||||
// Control the behavior when we reach the end of the sample
|
||||
if (samplePos >= sampleEnd)
|
||||
{
|
||||
if (pb.audio_addr.looping == 1)
|
||||
{
|
||||
samplePos = loopPos;
|
||||
if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM))
|
||||
{
|
||||
pb.adpcm.yn1 = pb.adpcm_loop_info.yn1;
|
||||
pb.adpcm.yn2 = pb.adpcm_loop_info.yn2;
|
||||
pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pb.running = 0;
|
||||
samplePos = loopPos;
|
||||
//samplePos = samplePos - sampleEnd + loopPos;
|
||||
memset(&pb.dpop, 0, sizeof(pb.dpop));
|
||||
memset(pb.src.last_samples, 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of the _iSize loop
|
||||
|
||||
// Update volume
|
||||
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
|
||||
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
|
||||
|
||||
pb.src.cur_addr_frac = (u16)frac;
|
||||
pb.audio_addr.cur_addr_hi = samplePos >> 16;
|
||||
pb.audio_addr.cur_addr_lo = (u16)samplePos;
|
||||
|
||||
} // if (pb.running)
|
||||
}
|
||||
|
||||
#if !defined(AX_GC) && !defined(AX_WII)
|
||||
#error UCode_AX_Voice.h included without specifying version
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "../../DSP.h"
|
||||
|
||||
#ifdef AX_GC
|
||||
# define PB_TYPE AXPB
|
||||
#else
|
||||
# define PB_TYPE AXPBWii
|
||||
#endif
|
||||
|
||||
// Put all of that in an anonymous namespace to avoid stupid compilers merging
|
||||
// functions from AX GC and AX Wii.
|
||||
namespace {
|
||||
|
||||
// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits.
|
||||
#define HILO_TO_32(name) \
|
||||
((name##_hi << 16) | name##_lo)
|
||||
|
||||
// Used to pass a large amount of buffers to the mixing function.
|
||||
union AXBuffers
|
||||
{
|
||||
struct
|
||||
{
|
||||
int* left;
|
||||
int* right;
|
||||
int* surround;
|
||||
|
||||
int* auxA_left;
|
||||
int* auxA_right;
|
||||
int* auxA_surround;
|
||||
|
||||
int* auxB_left;
|
||||
int* auxB_right;
|
||||
int* auxB_surround;
|
||||
|
||||
#ifdef AX_WII
|
||||
int* auxC_left;
|
||||
int* auxC_right;
|
||||
int* auxC_surround;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef AX_GC
|
||||
int* ptrs[9];
|
||||
#else
|
||||
int* ptrs[12];
|
||||
#endif
|
||||
};
|
||||
|
||||
// Read a PB from MRAM/ARAM
|
||||
bool ReadPB(u32 addr, PB_TYPE& pb)
|
||||
{
|
||||
u16* dst = (u16*)&pb;
|
||||
const u16* src = (const u16*)Memory::GetPointer(addr);
|
||||
if (!src)
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i)
|
||||
dst[i] = Common::swap16(src[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write a PB back to MRAM/ARAM
|
||||
bool WritePB(u32 addr, const PB_TYPE& pb)
|
||||
{
|
||||
const u16* src = (const u16*)&pb;
|
||||
u16* dst = (u16*)Memory::GetPointer(addr);
|
||||
if (!dst)
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i)
|
||||
dst[i] = Common::swap16(src[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dump the value of a PB for debugging
|
||||
#define DUMP_U16(field) WARN_LOG(DSPHLE, " %04x (%s)", pb.field, #field)
|
||||
#define DUMP_U32(field) WARN_LOG(DSPHLE, " %08x (%s)", HILO_TO_32(pb.field), #field)
|
||||
void DumpPB(const PB_TYPE& pb)
|
||||
{
|
||||
DUMP_U32(next_pb);
|
||||
DUMP_U32(this_pb);
|
||||
DUMP_U16(src_type);
|
||||
DUMP_U16(coef_select);
|
||||
#ifdef AX_GC
|
||||
DUMP_U16(mixer_control);
|
||||
#else
|
||||
DUMP_U32(mixer_control);
|
||||
#endif
|
||||
DUMP_U16(running);
|
||||
DUMP_U16(is_stream);
|
||||
|
||||
// TODO: complete as needed
|
||||
}
|
||||
|
||||
// Simulated accelerator state.
|
||||
static u32 acc_loop_addr, acc_end_addr;
|
||||
static u32* acc_cur_addr;
|
||||
static PB_TYPE* acc_pb;
|
||||
|
||||
// Sets up the simulated accelerator.
|
||||
void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||
{
|
||||
acc_pb = pb;
|
||||
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
||||
acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
|
||||
acc_cur_addr = cur_addr;
|
||||
}
|
||||
|
||||
// Reads a sample from the simulated accelerator. Also handles looping and
|
||||
// disabling streams that reached the end (this is done by an exception raised
|
||||
// by the accelerator on real hardware).
|
||||
u16 AcceleratorGetSample()
|
||||
{
|
||||
u16 ret;
|
||||
|
||||
switch (acc_pb->audio_addr.sample_format)
|
||||
{
|
||||
case 0x00: // ADPCM
|
||||
{
|
||||
// ADPCM decoding, not much to explain here.
|
||||
if ((*acc_cur_addr & 15) == 0)
|
||||
{
|
||||
acc_pb->adpcm.pred_scale = DSP::ReadARAM((*acc_cur_addr & ~15) >> 1);
|
||||
*acc_cur_addr += 2;
|
||||
}
|
||||
|
||||
int scale = 1 << (acc_pb->adpcm.pred_scale & 0xF);
|
||||
int coef_idx = (acc_pb->adpcm.pred_scale >> 4) & 0x7;
|
||||
|
||||
s32 coef1 = acc_pb->adpcm.coefs[coef_idx * 2 + 0];
|
||||
s32 coef2 = acc_pb->adpcm.coefs[coef_idx * 2 + 1];
|
||||
|
||||
int temp = (*acc_cur_addr & 1) ?
|
||||
(DSP::ReadARAM(*acc_cur_addr >> 1) & 0xF) :
|
||||
(DSP::ReadARAM(*acc_cur_addr >> 1) >> 4);
|
||||
|
||||
if (temp >= 8)
|
||||
temp -= 16;
|
||||
|
||||
int val = (scale * temp) + ((0x400 + coef1 * acc_pb->adpcm.yn1 + coef2 * acc_pb->adpcm.yn2) >> 11);
|
||||
|
||||
if (val > 0x7FFF) val = 0x7FFF;
|
||||
else if (val < -0x7FFF) val = -0x7FFF;
|
||||
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = val;
|
||||
*acc_cur_addr += 1;
|
||||
ret = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0A: // 16-bit PCM audio
|
||||
ret = (DSP::ReadARAM(*acc_cur_addr * 2) << 8) | DSP::ReadARAM(*acc_cur_addr * 2 + 1);
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = ret;
|
||||
*acc_cur_addr += 1;
|
||||
break;
|
||||
|
||||
case 0x19: // 8-bit PCM audio
|
||||
ret = DSP::ReadARAM(*acc_cur_addr) << 8;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = ret;
|
||||
*acc_cur_addr += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(DSPHLE, "Unknown sample format: %d", acc_pb->audio_addr.sample_format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Have we reached the end address?
|
||||
//
|
||||
// On real hardware, this would raise an interrupt that is handled by the
|
||||
// UCode. We simulate what this interrupt does here.
|
||||
if (*acc_cur_addr >= acc_end_addr)
|
||||
{
|
||||
// If we are really at the end (and we don't simply have cur_addr >
|
||||
// end_addr all the time), loop back to loop_addr.
|
||||
if ((*acc_cur_addr & ~0x1F) == (acc_end_addr & ~0x1F))
|
||||
*acc_cur_addr = acc_loop_addr;
|
||||
|
||||
if (acc_pb->audio_addr.looping)
|
||||
{
|
||||
// Set the ADPCM infos to continue processing at loop_addr.
|
||||
//
|
||||
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
||||
// stream type. This is what the AX UCode does and I don't really
|
||||
// know why.
|
||||
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
||||
if (!acc_pb->is_stream)
|
||||
{
|
||||
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non looping voice reached the end -> running = 0.
|
||||
acc_pb->running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read 32 input samples from ARAM, decoding and converting rate if required.
|
||||
void GetInputSamples(PB_TYPE& pb, s16* samples)
|
||||
{
|
||||
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
||||
AcceleratorSetup(&pb, &cur_addr);
|
||||
|
||||
// TODO: support polyphase interpolation if coefficients are available.
|
||||
if (pb.src_type == SRCTYPE_POLYPHASE || pb.src_type == SRCTYPE_LINEAR)
|
||||
{
|
||||
// Convert the input to a higher or lower sample rate using a linear
|
||||
// interpolation algorithm. The input to output ratio is set in
|
||||
// pb.src.ratio, which is a floating point num stored as a 32b integer:
|
||||
// * Upper 16 bits of the ratio are the integer part
|
||||
// * Lower 16 bits are the decimal part
|
||||
u32 ratio = HILO_TO_32(pb.src.ratio);
|
||||
|
||||
// We start getting samples not from sample 0, but 0.<cur_addr_frac>.
|
||||
// This avoids discontinuties in the audio stream, especially with very
|
||||
// low ratios which interpolate a lot of values between two "real"
|
||||
// samples.
|
||||
u32 curr_pos = pb.src.cur_addr_frac;
|
||||
|
||||
// These are the two samples between which we interpolate. The initial
|
||||
// values are stored in the PB, and we update them when resampling the
|
||||
// input data.
|
||||
s16 curr0 = pb.src.last_samples[2];
|
||||
s16 curr1 = pb.src.last_samples[3];
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
// Get our current fractional position, used to know how much of
|
||||
// curr0 and how much of curr1 the output sample should be.
|
||||
s32 curr_frac_pos = curr_pos & 0xFFFF;
|
||||
|
||||
// Linear interpolation: s1 + (s2 - s1) * pos
|
||||
s16 sample = curr0 + (s16)(((curr1 - curr0) * (s32)curr_frac_pos) >> 16);
|
||||
samples[i] = sample;
|
||||
|
||||
curr_pos += ratio;
|
||||
|
||||
// While our current position is >= 1.0, shift to the next 2
|
||||
// samples for interpolation.
|
||||
while ((curr_pos >> 16) != 0)
|
||||
{
|
||||
curr0 = curr1;
|
||||
curr1 = AcceleratorGetSample();
|
||||
curr_pos -= 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the two last_samples values in the PB as well as the current
|
||||
// position.
|
||||
pb.src.last_samples[2] = curr0;
|
||||
pb.src.last_samples[3] = curr1;
|
||||
pb.src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||
}
|
||||
else // SRCTYPE_NEAREST
|
||||
{
|
||||
// No sample rate conversion here: simply read 32 samples from the
|
||||
// accelerator to the output buffer.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
samples[i] = AcceleratorGetSample();
|
||||
|
||||
memcpy(pb.src.last_samples, samples + 28, 4 * sizeof (u16));
|
||||
}
|
||||
|
||||
// Update current position in the PB.
|
||||
pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16);
|
||||
pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF);
|
||||
}
|
||||
|
||||
// Add samples to an output buffer, with optional volume ramping.
|
||||
void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp)
|
||||
{
|
||||
u16& volume = pvol[0];
|
||||
u16 volume_delta = pvol[1];
|
||||
|
||||
// If volume ramping is disabled, set volume_delta to 0. That way, the
|
||||
// mixing loop can avoid testing if volume ramping is enabled at each step,
|
||||
// and just add volume_delta.
|
||||
if (!ramp)
|
||||
volume_delta = 0;
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
s64 sample = input[i];
|
||||
sample *= volume;
|
||||
sample >>= 15;
|
||||
|
||||
out[i] += (s16)sample;
|
||||
volume += volume_delta;
|
||||
|
||||
*dpop = (s16)sample;
|
||||
}
|
||||
}
|
||||
|
||||
// Process 1ms of audio (32 samples) from a PB and mix it to the buffers.
|
||||
void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
||||
{
|
||||
// If the voice is not running, nothing to do.
|
||||
if (!pb.running)
|
||||
return;
|
||||
|
||||
// Read input samples, performing sample rate conversion if needed.
|
||||
s16 samples[32];
|
||||
GetInputSamples(pb, samples);
|
||||
|
||||
// Apply a global volume ramp using the volume envelope parameters.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
s64 sample = 2 * (s16)samples[i] * (s16)pb.vol_env.cur_volume;
|
||||
samples[i] = (s16)(sample >> 16);
|
||||
pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta;
|
||||
}
|
||||
|
||||
// Optionally, execute a low pass filter
|
||||
if (pb.lpf.enabled)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
||||
if (mctrl & MIX_L)
|
||||
MixAdd(buffers.left, samples, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||
if (mctrl & MIX_R)
|
||||
MixAdd(buffers.right, samples, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||
if (mctrl & MIX_S)
|
||||
MixAdd(buffers.surround, samples, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXA_L)
|
||||
MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||
if (mctrl & MIX_AUXA_R)
|
||||
MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||
if (mctrl & MIX_AUXA_S)
|
||||
MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXB_L)
|
||||
MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||
if (mctrl & MIX_AUXB_R)
|
||||
MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||
if (mctrl & MIX_AUXB_S)
|
||||
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
|
||||
#ifdef AX_WII
|
||||
if (mctrl & MIX_AUXC_L)
|
||||
MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
if (mctrl & MIX_AUXC_R)
|
||||
MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
if (mctrl & MIX_AUXC_S)
|
||||
MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
#endif
|
||||
|
||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||
if (pb.initial_time_delay.on)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // !_UCODE_AX_VOICE_H
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include "../MailHandler.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
|
||||
#define AX_WII
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
|
||||
CUCode_NewAXWii::CUCode_NewAXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
: CUCode_AX(dsp_hle, l_CRC)
|
||||
{
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_NewAXWii");
|
||||
}
|
||||
|
||||
CUCode_NewAXWii::~CUCode_NewAXWii()
|
||||
{
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::HandleCommandList()
|
||||
{
|
||||
// Temp variables for addresses computation
|
||||
u16 addr_hi, addr_lo;
|
||||
u16 addr2_hi, addr2_lo;
|
||||
u16 volume;
|
||||
|
||||
// WARN_LOG(DSPHLE, "Command list:");
|
||||
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
|
||||
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
|
||||
// WARN_LOG(DSPHLE, "-------------");
|
||||
|
||||
u32 curr_idx = 0;
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
u16 cmd = m_cmdlist[curr_idx++];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case CMD_SETUP:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_01: curr_idx += 2; break;
|
||||
case CMD_UNK_02: curr_idx += 2; break;
|
||||
case CMD_UNK_03: curr_idx += 2; break;
|
||||
|
||||
case CMD_PROCESS:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
ProcessPBList(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_MIX_AUXA:
|
||||
case CMD_MIX_AUXB:
|
||||
case CMD_MIX_AUXC:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume);
|
||||
break;
|
||||
|
||||
// These two go together and manipulate some AUX buffers.
|
||||
case CMD_UNK_08: curr_idx += 13; break;
|
||||
case CMD_UNK_09: curr_idx += 13; break;
|
||||
|
||||
case CMD_UNK_0A: curr_idx += 4; break;
|
||||
|
||||
case CMD_OUTPUT:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume);
|
||||
break;
|
||||
|
||||
case CMD_UNK_0C: curr_idx += 5; break;
|
||||
|
||||
case CMD_WM_OUTPUT:
|
||||
{
|
||||
u32 addresses[4] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
};
|
||||
curr_idx += 8;
|
||||
OutputWMSamples(addresses);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_END:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::SetupProcessing(u32 init_addr)
|
||||
{
|
||||
// TODO: should be easily factorizable with AX
|
||||
s16 init_data[60];
|
||||
|
||||
for (u32 i = 0; i < 60; ++i)
|
||||
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
|
||||
|
||||
// List of all buffers we have to initialize
|
||||
struct {
|
||||
int* ptr;
|
||||
u32 samples;
|
||||
} buffers[] = {
|
||||
{ m_samples_left, 32 },
|
||||
{ m_samples_right, 32 },
|
||||
{ m_samples_surround, 32 },
|
||||
{ m_samples_auxA_left, 32 },
|
||||
{ m_samples_auxA_right, 32 },
|
||||
{ m_samples_auxA_surround, 32 },
|
||||
{ m_samples_auxB_left, 32 },
|
||||
{ m_samples_auxB_right, 32 },
|
||||
{ m_samples_auxB_surround, 32 },
|
||||
{ m_samples_auxC_left, 32 },
|
||||
{ m_samples_auxC_right, 32 },
|
||||
{ m_samples_auxC_surround, 32 },
|
||||
|
||||
{ m_samples_wm0, 6 },
|
||||
{ m_samples_aux0, 6 },
|
||||
{ m_samples_wm1, 6 },
|
||||
{ m_samples_aux1, 6 },
|
||||
{ m_samples_wm2, 6 },
|
||||
{ m_samples_aux2, 6 },
|
||||
{ m_samples_wm3, 6 },
|
||||
{ m_samples_aux3, 6 }
|
||||
};
|
||||
|
||||
u32 init_idx = 0;
|
||||
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
|
||||
{
|
||||
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
|
||||
s16 delta = (s16)init_data[init_idx + 2];
|
||||
|
||||
init_idx += 3;
|
||||
|
||||
if (!init_val)
|
||||
memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int));
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < 3 * buffers[i].samples; ++j)
|
||||
{
|
||||
buffers[i].ptr[j] = init_val;
|
||||
init_val += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AXMixControl CUCode_NewAXWii::ConvertMixerControl(u32 mixer_control)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
if (mixer_control & 0x00000001) ret |= MIX_L;
|
||||
if (mixer_control & 0x00000002) ret |= MIX_R;
|
||||
if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
|
||||
if (mixer_control & 0x00000008) ret |= MIX_S;
|
||||
if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
|
||||
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
|
||||
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
|
||||
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
|
||||
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
|
||||
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
|
||||
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
|
||||
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
|
||||
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
|
||||
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
|
||||
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
|
||||
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
|
||||
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
|
||||
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
|
||||
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
|
||||
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
|
||||
|
||||
return (AXMixControl)ret;
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::ProcessPBList(u32 pb_addr)
|
||||
{
|
||||
const u32 spms = 32;
|
||||
|
||||
AXPBWii pb;
|
||||
|
||||
while (pb_addr)
|
||||
{
|
||||
AXBuffers buffers = {{
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround,
|
||||
m_samples_auxA_left,
|
||||
m_samples_auxA_right,
|
||||
m_samples_auxA_surround,
|
||||
m_samples_auxB_left,
|
||||
m_samples_auxB_right,
|
||||
m_samples_auxB_surround,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround
|
||||
}};
|
||||
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||
{
|
||||
Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
|
||||
|
||||
// Forward the buffers
|
||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||
buffers.ptrs[i] += spms;
|
||||
}
|
||||
|
||||
WritePB(pb_addr, pb);
|
||||
pb_addr = HILO_TO_32(pb.next_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
|
||||
{
|
||||
int* buffers[3] = { 0 };
|
||||
int* main_buffers[3] = {
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround
|
||||
};
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffers[0] = m_samples_auxC_left;
|
||||
buffers[1] = m_samples_auxC_right;
|
||||
buffers[2] = m_samples_auxC_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send the content of AUX buffers to the CPU
|
||||
if (write_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
*ptr++ = Common::swap32(buffers[i][j]);
|
||||
}
|
||||
|
||||
// Then read the buffers from the CPU and add to our main buffers.
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
{
|
||||
s64 new_val = main_buffers[i][j] + Common::swap32(*ptr++);
|
||||
main_buffers[i][j] = (new_val * volume) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume)
|
||||
{
|
||||
int surround_buffer[3 * 32] = { 0 };
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
surround_buffer[i] = Common::swap32(m_samples_surround[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
|
||||
|
||||
short buffer[3 * 32 * 2];
|
||||
|
||||
// Clamp internal buffers to 16 bits.
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
int left = m_samples_left[i];
|
||||
int right = m_samples_right[i];
|
||||
|
||||
// Apply global volume. Cast to s64 to avoid overflow.
|
||||
left = ((s64)left * volume) >> 15;
|
||||
right = ((s64)right * volume) >> 15;
|
||||
|
||||
if (left < -32767) left = -32767;
|
||||
if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
if (right > 32767) right = 32767;
|
||||
|
||||
m_samples_left[i] = left;
|
||||
m_samples_right[i] = right;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
buffer[2 * i] = Common::swap16(m_samples_left[i]);
|
||||
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
|
||||
}
|
||||
|
||||
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputWMSamples(u32* addresses)
|
||||
{
|
||||
int* buffers[] = {
|
||||
m_samples_wm0,
|
||||
m_samples_wm1,
|
||||
m_samples_wm2,
|
||||
m_samples_wm3
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
{
|
||||
int* in = buffers[i];
|
||||
u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
|
||||
for (u32 j = 0; j < 3 * 6; ++j)
|
||||
{
|
||||
int sample = in[j];
|
||||
if (sample < -32767) sample = -32767;
|
||||
if (sample > 32767) sample = 32767;
|
||||
out[j] = Common::swap16((u16)sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_processing);
|
||||
|
||||
DoStateShared(p);
|
||||
DoAXState(p);
|
||||
|
||||
p.Do(m_samples_auxC_left);
|
||||
p.Do(m_samples_auxC_right);
|
||||
p.Do(m_samples_auxC_surround);
|
||||
|
||||
p.Do(m_samples_wm0);
|
||||
p.Do(m_samples_wm1);
|
||||
p.Do(m_samples_wm2);
|
||||
p.Do(m_samples_wm3);
|
||||
|
||||
p.Do(m_samples_aux0);
|
||||
p.Do(m_samples_aux1);
|
||||
p.Do(m_samples_aux2);
|
||||
p.Do(m_samples_aux3);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_NEWAXWII_H
|
||||
#define _UCODE_NEWAXWII_H
|
||||
|
||||
#include "UCode_AX.h"
|
||||
|
||||
class CUCode_NewAXWii : public CUCode_AX
|
||||
{
|
||||
public:
|
||||
CUCode_NewAXWii(DSPHLE *dsp_hle, u32 _CRC);
|
||||
virtual ~CUCode_NewAXWii();
|
||||
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
int m_samples_auxC_left[32 * 3];
|
||||
int m_samples_auxC_right[32 * 3];
|
||||
int m_samples_auxC_surround[32 * 3];
|
||||
|
||||
// Wiimote buffers
|
||||
int m_samples_wm0[6 * 3];
|
||||
int m_samples_aux0[6 * 3];
|
||||
int m_samples_wm1[6 * 3];
|
||||
int m_samples_aux1[6 * 3];
|
||||
int m_samples_wm2[6 * 3];
|
||||
int m_samples_aux2[6 * 3];
|
||||
int m_samples_wm3[6 * 3];
|
||||
int m_samples_aux3[6 * 3];
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume);
|
||||
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume);
|
||||
void OutputWMSamples(u32* addresses); // 4 addresses
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_UNK_02 = 0x02,
|
||||
CMD_UNK_03 = 0x03,
|
||||
CMD_PROCESS = 0x04,
|
||||
CMD_MIX_AUXA = 0x05,
|
||||
CMD_MIX_AUXB = 0x06,
|
||||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_UNK_09 = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_WM_OUTPUT = 0x0D,
|
||||
CMD_END = 0x0E
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AXWII
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "UCode_AX.h"
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
#include "UCode_Zelda.h"
|
||||
#include "UCode_ROM.h"
|
||||
#include "UCode_CARD.h"
|
||||
@@ -26,6 +27,12 @@
|
||||
#include "UCode_GBA.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#if 0
|
||||
# define AXWII CUCode_NewAXWii
|
||||
#else
|
||||
# define AXWII CUCode_AXWii
|
||||
#endif
|
||||
|
||||
IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
||||
{
|
||||
switch (_CRC)
|
||||
@@ -90,13 +97,13 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
||||
case 0x4cc52064: // Bleach: Versus Crusade
|
||||
case 0xd9c4bf34: // WiiMenu
|
||||
INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
|
||||
default:
|
||||
if (bWii)
|
||||
{
|
||||
PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AXWii.\n\nTry LLE emulator if this is homebrew.", _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ void DSPDebugInterface::toggleMemCheck(unsigned int address)
|
||||
PanicAlert("MemCheck functionality not supported in DSP module.");
|
||||
}
|
||||
|
||||
void DSPDebugInterface::insertBLR(unsigned int address)
|
||||
void DSPDebugInterface::insertBLR(unsigned int address, unsigned int value)
|
||||
{
|
||||
PanicAlert("insertBLR functionality not supported in DSP module.");
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
virtual void setPC(unsigned int address);
|
||||
virtual void step() {}
|
||||
virtual void runToBreakpoint();
|
||||
virtual void insertBLR(unsigned int address);
|
||||
virtual void insertBLR(unsigned int address, unsigned int value);
|
||||
virtual int getColor(unsigned int address);
|
||||
virtual std::string getDescription(unsigned int address);
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Memmap.h"
|
||||
#include "../VolumeHandler.h"
|
||||
#include "AudioInterface.h"
|
||||
#include "../Movie.h"
|
||||
|
||||
// Disc transfer rate measured in bytes per second
|
||||
static const u32 DISC_TRANSFER_RATE_GC = 3125 * 1024;
|
||||
@@ -334,6 +335,17 @@ void ChangeDisc(const char* _newFileName)
|
||||
std::string* _FileName = new std::string(_newFileName);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, ejectDisc);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(500000000, insertDisc, (u64)_FileName);
|
||||
if (Movie::IsRecordingInput())
|
||||
{
|
||||
Movie::g_bDiscChange = true;
|
||||
std::string fileName = _newFileName;
|
||||
int sizeofpath = fileName.find_last_of("/\\") + 1;
|
||||
if (fileName.substr(sizeofpath).length() > 40)
|
||||
{
|
||||
PanicAlert("Saving iso filename to .dtm failed; max file name length is 40 characters.");
|
||||
}
|
||||
Movie::g_discChange = fileName.substr(sizeofpath);
|
||||
}
|
||||
}
|
||||
|
||||
void SetLidOpen(bool _bOpen)
|
||||
|
||||
@@ -52,6 +52,9 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
||||
, m_bDirty(false)
|
||||
{
|
||||
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave())
|
||||
m_strFilename = "Movie.raw";
|
||||
|
||||
// we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ bool GCMemcard::Save()
|
||||
mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&bat, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE);
|
||||
for (int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i)
|
||||
for (unsigned int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i)
|
||||
{
|
||||
mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE);
|
||||
}
|
||||
@@ -473,11 +473,20 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const
|
||||
return format;
|
||||
}
|
||||
|
||||
u16 GCMemcard::DEntry_AnimSpeed(u8 index) const
|
||||
std::string GCMemcard::DEntry_AnimSpeed(u8 index) const
|
||||
{
|
||||
if (!m_valid || index > DIRLEN)
|
||||
return 0xFF;
|
||||
return BE16(CurrentDir->Dir[index].AnimSpeed);
|
||||
return "";
|
||||
int x = CurrentDir->Dir[index].AnimSpeed[0];
|
||||
std::string speed;
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
if (i == 8) x = CurrentDir->Dir[index].AnimSpeed[1];
|
||||
speed.push_back((x & 0x80) ? '1' : '0');
|
||||
x = x << 1;
|
||||
}
|
||||
speed.push_back(0);
|
||||
return speed;
|
||||
}
|
||||
|
||||
std::string GCMemcard::DEntry_Permissions(u8 index) const
|
||||
@@ -578,7 +587,7 @@ u16 GCMemcard::BlockAlloc::NextFreeBlock(u16 StartingBlock) const
|
||||
for (u16 i = StartingBlock; i < BAT_SIZE; ++i)
|
||||
if (Map[i-MC_FST_BLOCKS] == 0)
|
||||
return i;
|
||||
for (u16 i = 0; i < StartingBlock; ++i)
|
||||
for (u16 i = MC_FST_BLOCKS; i < StartingBlock; ++i)
|
||||
if (Map[i-MC_FST_BLOCKS] == 0)
|
||||
return i;
|
||||
}
|
||||
@@ -600,7 +609,7 @@ bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; ++i)
|
||||
for (unsigned int i = 0; i < length; ++i)
|
||||
Map[blocks.at(i)-MC_FST_BLOCKS] = 0;
|
||||
FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount);
|
||||
|
||||
@@ -616,7 +625,7 @@ u32 GCMemcard::GetSaveData(u8 index, std::vector<GCMBlock> & Blocks) const
|
||||
|
||||
u16 block = DEntry_FirstBlock(index);
|
||||
u16 BlockCount = DEntry_BlockCount(index);
|
||||
u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS;
|
||||
//u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS;
|
||||
|
||||
if ((block == 0xFFFF) || (BlockCount == 0xFFFF))
|
||||
{
|
||||
@@ -660,12 +669,10 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks)
|
||||
Directory UpdatedDir = *CurrentDir;
|
||||
|
||||
// find first free dir entry
|
||||
int index = -1;
|
||||
for (int i=0; i < DIRLEN; i++)
|
||||
{
|
||||
if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF)
|
||||
{
|
||||
index = i;
|
||||
UpdatedDir.Dir[i] = direntry;
|
||||
*(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock);
|
||||
UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter+1;
|
||||
@@ -878,7 +885,7 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s
|
||||
std::vector<GCMBlock> saveData;
|
||||
saveData.reserve(size);
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
{
|
||||
GCMBlock b;
|
||||
gci.ReadBytes(b.block, BLOCK_SIZE);
|
||||
@@ -991,7 +998,7 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, const std::string &dire
|
||||
return NOMEMCARD;
|
||||
}
|
||||
gci.Seek(DENTRY_SIZE + offset, SEEK_SET);
|
||||
for (int i = 0; i < size; ++i)
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
{
|
||||
gci.WriteBytes(saveData[i].block, BLOCK_SIZE);
|
||||
}
|
||||
@@ -1086,15 +1093,18 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
|
||||
|
||||
// To ensure only one type of icon is used
|
||||
// Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon
|
||||
int fmtCheck = 0;
|
||||
//int fmtCheck = 0;
|
||||
|
||||
int formats = BE16(CurrentDir->Dir[index].IconFmt);
|
||||
int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed);
|
||||
|
||||
int flags = CurrentDir->Dir[index].BIFlags;
|
||||
// Timesplitters 2 is the only game that I see this in
|
||||
// Timesplitters 2 and 3 is the only game that I see this in
|
||||
// May be a hack
|
||||
if (flags == 0xFB) flags = ~flags;
|
||||
//if (flags == 0xFB) flags = ~flags;
|
||||
// Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant.
|
||||
// Something similar happens with Wario Ware Inc. AnimSpeed
|
||||
|
||||
int bnrFormat = (flags&3);
|
||||
|
||||
u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset);
|
||||
@@ -1110,7 +1120,6 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
|
||||
switch (bnrFormat)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
animData += 96*32 + 2*256; // image+palette
|
||||
break;
|
||||
case 2:
|
||||
@@ -1122,40 +1131,48 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
|
||||
u8* data[8];
|
||||
int frames = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
fmts[i] = (formats >> (2*i))&3;
|
||||
delays[i] = ((fdelays >> (2*i))&3) << 2;
|
||||
delays[i] = ((fdelays >> (2*i))&3);
|
||||
data[i] = animData;
|
||||
|
||||
if (!fmtCheck) fmtCheck = fmts[i];
|
||||
if (fmtCheck == fmts[i])
|
||||
if (!delays[i])
|
||||
{
|
||||
//First icon_speed = 0 indicates there aren't any more icons
|
||||
break;
|
||||
}
|
||||
//If speed is set there is an icon (it can be a "blank frame")
|
||||
frames++;
|
||||
if (fmts[i] != 0)
|
||||
{
|
||||
switch (fmts[i])
|
||||
{
|
||||
case CI8SHARED: // CI8 with shared palette
|
||||
animData += 32*32;
|
||||
frames++;
|
||||
break;
|
||||
case RGB5A3: // RGB5A3
|
||||
animData += 32*32*2;
|
||||
frames++;
|
||||
break;
|
||||
case CI8: // CI8 with own palette
|
||||
animData += 32*32 + 2*256;
|
||||
frames++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u16* sharedPal = (u16*)(animData);
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
|
||||
if (fmtCheck == fmts[i])
|
||||
if (!delays[i])
|
||||
{
|
||||
//First icon_speed = 0 indicates there aren't any more icons
|
||||
break;
|
||||
}
|
||||
if (fmts[i] != 0)
|
||||
{
|
||||
switch (fmts[i])
|
||||
{
|
||||
@@ -1165,6 +1182,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
|
||||
break;
|
||||
case RGB5A3: // RGB5A3
|
||||
decode5A3image(buffer, (u16*)(data[i]), 32, 32);
|
||||
buffer += 32*32;
|
||||
break;
|
||||
case CI8: // CI8 with own palette
|
||||
u16 *paldata = (u16*)(data[i] + 32*32);
|
||||
@@ -1173,6 +1191,33 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Speed is set but there's no actual icon
|
||||
//This is used to reduce animation speed in Pikmin and Luigi's Mansion for example
|
||||
//These "blank frames" show the next icon
|
||||
for(j=i; j<8;++j)
|
||||
{
|
||||
if (fmts[j] != 0)
|
||||
{
|
||||
switch (fmts[j])
|
||||
{
|
||||
case CI8SHARED: // CI8 with shared palette
|
||||
decodeCI8image(buffer,data[j],sharedPal,32,32);
|
||||
break;
|
||||
case RGB5A3: // RGB5A3
|
||||
decode5A3image(buffer, (u16*)(data[j]), 32, 32);
|
||||
buffer += 32*32;
|
||||
break;
|
||||
case CI8: // CI8 with own palette
|
||||
u16 *paldata = (u16*)(data[j] + 32*32);
|
||||
decodeCI8image(buffer, data[j], paldata, 32, 32);
|
||||
buffer += 32*32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
@@ -1269,7 +1314,6 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP)
|
||||
calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv);
|
||||
}
|
||||
|
||||
|
||||
void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2)
|
||||
{
|
||||
u32 serial[8];
|
||||
@@ -1349,7 +1393,7 @@ s32 GCMemcard::PSO_MakeSaveGameValid(DEntry& direntry, std::vector<GCMBlock> &Fi
|
||||
if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0)
|
||||
{
|
||||
// check for PSO3 system file
|
||||
if (strcmp((char*)&FileBuffer[0].block[0x08],"PSO3_SYSTEM")==0)
|
||||
if (strcmp((char*)direntry.Filename,"PSO3_SYSTEM")==0)
|
||||
{
|
||||
// PSO3 data block size adjustment
|
||||
pso3offset = 0x10;
|
||||
|
||||
@@ -116,8 +116,8 @@ private:
|
||||
// bits 0 and 1: image format
|
||||
// 00 no banner
|
||||
// 01 CI8 banner
|
||||
// 01 RGB5A3 banner
|
||||
// 11 ? maybe ==01? haven't seen it
|
||||
// 10 RGB5A3 banner
|
||||
// 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner
|
||||
//
|
||||
u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename
|
||||
u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000
|
||||
@@ -213,7 +213,7 @@ public:
|
||||
u32 DEntry_ModTime(u8 index) const;
|
||||
u32 DEntry_ImageOffset(u8 index) const;
|
||||
std::string DEntry_IconFmt(u8 index) const;
|
||||
u16 DEntry_AnimSpeed(u8 index) const;
|
||||
std::string DEntry_AnimSpeed(u8 index) const;
|
||||
std::string DEntry_Permissions(u8 index) const;
|
||||
u8 DEntry_CopyCounter(u8 index) const;
|
||||
// get first block for file
|
||||
|
||||
@@ -656,8 +656,10 @@ u8 *GetPointer(const u32 _Address)
|
||||
case 0x9:
|
||||
case 0xd:
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||
{
|
||||
if ((_Address & 0xfffffff) < EXRAM_SIZE)
|
||||
return m_pPhysicalEXRAM + (_Address & EXRAM_MASK);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ void Init()
|
||||
g_Channel[i].m_InLo.Hex = 0;
|
||||
|
||||
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
|
||||
AddDevice(Movie::IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
|
||||
AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
|
||||
else
|
||||
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
|
||||
}
|
||||
|
||||
@@ -262,7 +262,6 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
{
|
||||
|
||||
int cmd = *jvs_io++;
|
||||
int unknown = 0;
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "JVS IO, node=%d, cmd=%02x", node, cmd);
|
||||
|
||||
switch (cmd)
|
||||
@@ -362,10 +361,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
}
|
||||
case 0xf0:
|
||||
if (*jvs_io++ == 0xD9)
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "JVS RESET");
|
||||
} else
|
||||
unknown = 1;
|
||||
msg.addData(1);
|
||||
|
||||
d10_1 |= 1;
|
||||
|
||||
@@ -132,15 +132,17 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
||||
if(Movie::IsPlayingInput())
|
||||
{
|
||||
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
if(!Core::g_CoreStartupParameter.bWii)
|
||||
if(!Movie::IsUsingWiimote(0))
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else if(Movie::IsRecordingInput())
|
||||
{
|
||||
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
if(!Core::g_CoreStartupParameter.bWii)
|
||||
if(!Movie::IsUsingWiimote(0))
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else
|
||||
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
|
||||
// Thankfully changing mode does not change the high bits ;)
|
||||
_Hi = (u32)((u8)PadStatus.stickY);
|
||||
|
||||
@@ -136,9 +136,9 @@ void DoState(unsigned char **ptr, int mode)
|
||||
{
|
||||
// TODO:
|
||||
|
||||
//PointerWrap p(ptr, mode);
|
||||
//for (unsigned int i=0; i<4; ++i)
|
||||
// ((WiimoteEmu::Wiimote*)g_plugin.controllers[i])->DoState(p);
|
||||
PointerWrap p(ptr, mode);
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
((WiimoteEmu::Wiimote*)g_plugin.controllers[i])->DoState(p);
|
||||
}
|
||||
|
||||
// ___________________________________________________________________________
|
||||
|
||||
@@ -594,13 +594,69 @@ void Wiimote::SendReadDataReply(ReadRequest& _request)
|
||||
|
||||
void Wiimote::DoState(PointerWrap& p)
|
||||
{
|
||||
// not working :(
|
||||
//if (p.MODE_READ == p.GetMode())
|
||||
//{
|
||||
// // LOAD
|
||||
// Reset(); // should cause a status report to be sent, then wii should re-setup wiimote
|
||||
//}
|
||||
//p.Do(m_reporting_channel);
|
||||
p.Do(m_extension->active_extension);
|
||||
p.Do(m_extension->switch_extension);
|
||||
|
||||
p.Do(m_accel);
|
||||
p.Do(m_index);
|
||||
p.Do(ir_sin);
|
||||
p.Do(ir_cos);
|
||||
p.Do(m_rumble_on);
|
||||
p.Do(m_speaker_mute);
|
||||
p.Do(m_motion_plus_present);
|
||||
p.Do(m_motion_plus_active);
|
||||
p.Do(m_reporting_auto);
|
||||
p.Do(m_reporting_mode);
|
||||
p.Do(m_reporting_channel);
|
||||
p.Do(m_shake_step);
|
||||
p.Do(m_sensor_bar_on_top);
|
||||
p.Do(m_status);
|
||||
p.Do(m_adpcm_state);
|
||||
p.Do(m_ext_key);
|
||||
p.DoArray(m_eeprom, sizeof(m_eeprom));
|
||||
p.Do(m_reg_motion_plus);
|
||||
p.Do(m_reg_ir);
|
||||
p.Do(m_reg_ext);
|
||||
p.Do(m_reg_speaker);
|
||||
|
||||
//Do 'm_read_requests' queue
|
||||
{
|
||||
u32 size = 0;
|
||||
if (p.mode == PointerWrap::MODE_READ)
|
||||
{
|
||||
//clear
|
||||
while (m_read_requests.size())
|
||||
m_read_requests.pop();
|
||||
|
||||
p.Do(size);
|
||||
while (size--)
|
||||
{
|
||||
ReadRequest tmp;
|
||||
p.Do(tmp.address);
|
||||
p.Do(tmp.position);
|
||||
p.Do(tmp.size);
|
||||
tmp.data = new u8[tmp.size];
|
||||
p.DoArray(tmp.data, tmp.size);
|
||||
m_read_requests.push(tmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::queue<ReadRequest> tmp_queue(m_read_requests);
|
||||
size = m_read_requests.size();
|
||||
p.Do(size);
|
||||
while (!tmp_queue.empty())
|
||||
{
|
||||
ReadRequest tmp = tmp_queue.front();
|
||||
p.Do(tmp.address);
|
||||
p.Do(tmp.position);
|
||||
p.Do(tmp.size);
|
||||
p.DoArray(tmp.data, tmp.size);
|
||||
tmp_queue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
p.DoMarker("Wiimote");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -762,9 +762,9 @@ void Wiimote::Update()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Movie::IsRecordingInput())
|
||||
if (!Movie::IsPlayingInput())
|
||||
{
|
||||
Movie::RecordWiimote(m_index, data, rptf, m_reg_ir.mode);
|
||||
Movie::CheckWiimoteStatus(m_index, data, rptf, m_reg_ir.mode);
|
||||
}
|
||||
|
||||
// don't send a data report if auto reporting is off
|
||||
|
||||
@@ -185,6 +185,11 @@ bool Wiimote::Connect()
|
||||
RealDisconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
// As of 10.8 these need explicit retaining or writing to the wiimote has a very high
|
||||
// chance of crashing and burning.
|
||||
[ichan retain];
|
||||
[cchan retain];
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
|
||||
index + 1, [[btd getAddressString] UTF8String]);
|
||||
@@ -215,7 +220,8 @@ void Wiimote::RealDisconnect()
|
||||
m_wiimote_thread.join();
|
||||
|
||||
[btd closeConnection];
|
||||
|
||||
[ichan release];
|
||||
[cchan release];
|
||||
btd = NULL;
|
||||
cchan = NULL;
|
||||
ichan = NULL;
|
||||
|
||||
@@ -512,14 +512,14 @@ void StateChange(EMUSTATE_CHANGE newState)
|
||||
// TODO: disable/enable auto reporting, maybe
|
||||
}
|
||||
|
||||
#define ARRAYSIZE(_arr) (sizeof(_arr)/(sizeof(_arr[0])))
|
||||
|
||||
bool IsValidBluetoothName(const char* name) {
|
||||
static const char* kValidWiiRemoteBluetoothNames[] = {
|
||||
"Nintendo RVL-CNT-01",
|
||||
"Nintendo RVL-CNT-01-TR",
|
||||
"Nintendo RVL-WBC-01",
|
||||
};
|
||||
if (name == NULL)
|
||||
return false;
|
||||
for (size_t i = 0; i < ARRAYSIZE(kValidWiiRemoteBluetoothNames); i++)
|
||||
if (strcmp(name, kValidWiiRemoteBluetoothNames[i]) == 0)
|
||||
return true;
|
||||
|
||||
@@ -321,7 +321,7 @@ void ExecuteCommand(u32 _Address)
|
||||
bool CmdSuccess = false;
|
||||
|
||||
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
|
||||
volatile int DeviceID = Memory::Read_U32(_Address + 8);
|
||||
volatile s32 DeviceID = Memory::Read_U32(_Address + 8);
|
||||
|
||||
IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;
|
||||
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
#include <queue>
|
||||
#include "../HW/Memmap.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#define FS_SUCCESS (u32)0 // Success
|
||||
#define FS_EACCES (u32)-1 // Permission denied
|
||||
@@ -62,7 +61,11 @@ public:
|
||||
|
||||
virtual ~IWII_IPC_HLE_Device() { }
|
||||
|
||||
virtual void DoState(PointerWrap& p) { DoStateShared(p); }
|
||||
virtual void DoState(PointerWrap& p)
|
||||
{
|
||||
DoStateShared(p);
|
||||
p.Do(m_Active);
|
||||
}
|
||||
|
||||
void DoStateShared(PointerWrap& p);
|
||||
|
||||
|
||||
@@ -183,8 +183,8 @@ void CWII_IPC_HLE_Device_FileIO::CloseFile()
|
||||
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
{
|
||||
u32 ReturnValue = FS_RESULT_FATAL;
|
||||
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
const u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
|
||||
const u32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
|
||||
|
||||
if (OpenFile())
|
||||
@@ -205,7 +205,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
s32 wantedPos = SeekPosition+m_SeekPos;
|
||||
u32 wantedPos = SeekPosition+m_SeekPos;
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
@@ -215,7 +215,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
s32 wantedPos = fileSize+m_SeekPos;
|
||||
u64 wantedPos = fileSize+m_SeekPos;
|
||||
if (wantedPos >=0 && wantedPos <= fileSize)
|
||||
{
|
||||
m_SeekPos = wantedPos;
|
||||
@@ -371,6 +371,8 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
|
||||
p.Do(have_file_handle);
|
||||
p.Do(m_Mode);
|
||||
p.Do(seek);
|
||||
p.Do(m_SeekPos);
|
||||
p.Do(m_Filename);
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,11 @@
|
||||
#include "NandPaths.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
||||
#include "../Movie.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
std::string CWII_IPC_HLE_Device_es::m_ContentFile;
|
||||
|
||||
@@ -783,14 +787,17 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
||||
}
|
||||
else
|
||||
{
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
bool* wiiMoteConnected = new bool[s_Usb->m_WiiMotes.size()];
|
||||
for(unsigned int i = 0; i < s_Usb->m_WiiMotes.size();
|
||||
i++) wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
|
||||
|
||||
std::string tContentFile(m_ContentFile.c_str());
|
||||
WII_IPC_HLE_Interface::Reset(true);
|
||||
WII_IPC_HLE_Interface::Init();
|
||||
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
|
||||
{
|
||||
if (s_Usb->m_WiiMotes[i].IsConnected())
|
||||
if (wiiMoteConnected[i])
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
s_Usb->m_WiiMotes[i].Activate(true);
|
||||
@@ -801,6 +808,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
||||
}
|
||||
}
|
||||
|
||||
delete[] wiiMoteConnected;
|
||||
WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile);
|
||||
}
|
||||
// Pass the "#002 check"
|
||||
@@ -891,6 +899,52 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
|
||||
|
||||
File::CreateFullPath(tmdPath);
|
||||
File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
|
||||
|
||||
Movie::g_titleID = tmdTitleID;
|
||||
std::string savePath = Common::GetTitleDataPath(tmdTitleID);
|
||||
if (Movie::IsRecordingInput())
|
||||
{
|
||||
// TODO: Check for the actual save data
|
||||
if (File::Exists((savePath + "banner.bin").c_str()))
|
||||
Movie::g_bClearSave = false;
|
||||
else
|
||||
Movie::g_bClearSave = true;
|
||||
}
|
||||
|
||||
// TODO: Force the game to save to another location, instead of moving the user's save.
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave())
|
||||
{
|
||||
if (File::Exists((savePath + "banner.bin").c_str()))
|
||||
{
|
||||
if (File::Exists((savePath + "../backup/").c_str()))
|
||||
{
|
||||
// The last run of this game must have been to play back a movie, so their save is already backed up.
|
||||
File::DeleteDirRecursively(savePath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
MoveFile(savePath.c_str(), (savePath + "../backup/").c_str());
|
||||
#else
|
||||
File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str());
|
||||
File::DeleteDirRecursively(savePath.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (File::Exists((savePath + "../backup/").c_str()))
|
||||
{
|
||||
// Delete the save made by a previous movie, and copy back the user's save.
|
||||
if (File::Exists((savePath + "banner.bin").c_str()))
|
||||
File::DeleteDirRecursively(savePath);
|
||||
#ifdef _WIN32
|
||||
MoveFile((savePath + "../backup/").c_str(), savePath.c_str());
|
||||
#else
|
||||
File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str());
|
||||
File::DeleteDirRecursively((savePath + "../backup/").c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
if(!File::Exists(tmdPath))
|
||||
{
|
||||
File::IOFile _pTMDFile(tmdPath, "wb");
|
||||
|
||||
@@ -46,6 +46,7 @@ it failed)
|
||||
#endif
|
||||
|
||||
#include "WII_IPC_HLE_Device_net.h"
|
||||
#include "../ConfigManager.h"
|
||||
#include "FileUtil.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
@@ -276,11 +277,36 @@ bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress)
|
||||
// No idea why the fifth and sixth bytes are left untouched.
|
||||
{
|
||||
// hardcoded address as a fallback
|
||||
// TODO: Make this configurable? Different MAC addresses MIGHT be needed for requesting a user id or encrypting content with NWC24
|
||||
const u8 default_address[] = { 0x00, 0x19, 0x1e, 0xfd, 0x71, 0x84 };
|
||||
|
||||
INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETWIRELESSMACADDRESS");
|
||||
|
||||
if (!SConfig::GetInstance().m_WirelessMac.empty())
|
||||
{
|
||||
int x = 0;
|
||||
int tmpaddress[6];
|
||||
for (unsigned int i = 0; i < SConfig::GetInstance().m_WirelessMac.length() && x < 6; i++)
|
||||
{
|
||||
if (SConfig::GetInstance().m_WirelessMac[i] == ':' || SConfig::GetInstance().m_WirelessMac[i] == '-')
|
||||
continue;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << SConfig::GetInstance().m_WirelessMac[i];
|
||||
if (SConfig::GetInstance().m_WirelessMac[i+1] != ':' && SConfig::GetInstance().m_WirelessMac[i+1] != '-')
|
||||
{
|
||||
ss << std::hex << SConfig::GetInstance().m_WirelessMac[i+1];
|
||||
i++;
|
||||
}
|
||||
ss >> tmpaddress[x];
|
||||
x++;
|
||||
}
|
||||
u8 address[6];
|
||||
for (int i = 0; i < 6;i++)
|
||||
address[i] = tmpaddress[i];
|
||||
Memory::WriteBigEData(address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
const char *check_devices[3] = { "wlan0", "ath0", "eth0" };
|
||||
int fd, ret;
|
||||
@@ -324,7 +350,6 @@ bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress)
|
||||
|
||||
if (SUCCEEDED(ret)) Memory::WriteBigEData(adapter_info->Address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4);
|
||||
else Memory::WriteBigEData(default_address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4);
|
||||
|
||||
delete[] adapter_info;
|
||||
#else
|
||||
Memory::WriteBigEData(default_address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4);
|
||||
|
||||
@@ -104,14 +104,8 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305()
|
||||
|
||||
void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
|
||||
{
|
||||
/*
|
||||
//things that do not get saved: (why not?)
|
||||
|
||||
std::vector<CWII_IPC_HLE_WiiMote> m_WiiMotes;
|
||||
|
||||
std::deque<SQueuedEvent> m_EventQueue;
|
||||
*/
|
||||
|
||||
p.Do(m_Active);
|
||||
p.Do(m_ControllerBD);
|
||||
p.Do(m_CtrlSetup);
|
||||
p.Do(m_ACLSetup);
|
||||
p.Do(m_HCIEndpoint);
|
||||
@@ -119,75 +113,30 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
|
||||
p.Do(m_last_ticks);
|
||||
p.DoArray(m_PacketCount,4);
|
||||
p.Do(m_ScanEnable);
|
||||
p.Do(m_EventQueue);
|
||||
m_acl_pool.DoState(p);
|
||||
|
||||
bool storeFullData = (Movie::IsRecordingInput() || Movie::IsPlayingInput());
|
||||
p.Do(storeFullData);
|
||||
p.DoMarker("storeFullData in CWII_IPC_HLE_Device_usb_oh1_57e_305");
|
||||
|
||||
if (!storeFullData)
|
||||
{
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
m_EventQueue.clear();
|
||||
|
||||
if (SConfig::GetInstance().m_WiimoteReconnectOnLoad)
|
||||
{
|
||||
// Reset the connection of all connected wiimotes
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!m_WiiMotes[i].IsInactive())
|
||||
{
|
||||
m_WiiMotes[i].Activate(false);
|
||||
m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
m_WiiMotes[i].DoState(p);
|
||||
|
||||
// Reset the connection of real and hybrid wiimotes
|
||||
if (p.GetMode() == PointerWrap::MODE_READ && SConfig::GetInstance().m_WiimoteReconnectOnLoad)
|
||||
{
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (WIIMOTE_SRC_EMU == g_wiimote_sources[i] || WIIMOTE_SRC_NONE == g_wiimote_sources[i])
|
||||
continue;
|
||||
// TODO: Selectively clear real wiimote messages if possible. Or create a real wiimote channel and reporting mode pre-setup to vacate the need for m_WiimoteReconnectOnLoad.
|
||||
m_EventQueue.clear();
|
||||
if (!m_WiiMotes[i].IsInactive())
|
||||
{
|
||||
m_WiiMotes[i].Activate(false);
|
||||
m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// I'm not sure why these things aren't normally saved, but I think they can affect the emulation state,
|
||||
// so if sync matters (e.g. if a movie is active), we really should save them.
|
||||
// also, it's definitely not safe to do the above auto-reconnect hack either.
|
||||
// (unless we can do it without changing anything that affects emulation state, which is not currently the case)
|
||||
|
||||
p.Do(m_EventQueue);
|
||||
p.DoMarker("m_EventQueue");
|
||||
|
||||
// m_WiiMotes is kind of annoying to save. maybe this could be done in a more general way.
|
||||
u32 vec_size = (u32)m_WiiMotes.size();
|
||||
p.Do(vec_size);
|
||||
for (u32 i = 0; i < vec_size; ++i)
|
||||
{
|
||||
if (i < m_WiiMotes.size())
|
||||
{
|
||||
CWII_IPC_HLE_WiiMote& wiimote = m_WiiMotes[i];
|
||||
wiimote.DoState(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
bdaddr_t tmpBD = BDADDR_ANY;
|
||||
CWII_IPC_HLE_WiiMote wiimote = CWII_IPC_HLE_WiiMote(this, i, tmpBD, false);
|
||||
wiimote.DoState(p);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
m_WiiMotes.push_back(wiimote);
|
||||
_dbg_assert_(WII_IPC_WIIMOTE, m_WiiMotes.size() == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
while ((u32)m_WiiMotes.size() > vec_size)
|
||||
m_WiiMotes.pop_back();
|
||||
p.DoMarker("m_WiiMotes");
|
||||
}
|
||||
|
||||
DoStateShared(p);
|
||||
}
|
||||
|
||||
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::RemoteDisconnect(u16 _connectionHandle)
|
||||
@@ -1518,9 +1467,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkPolicy(u8* _Input)
|
||||
DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", pLinkPolicy->con_handle);
|
||||
DEBUG_LOG(WII_IPC_WIIMOTE, " Policy: 0x%04x", pLinkPolicy->settings);
|
||||
|
||||
hci_write_link_policy_settings_rp Reply;
|
||||
Reply.status = 0x00;
|
||||
Reply.con_handle = pLinkPolicy->con_handle;
|
||||
//hci_write_link_policy_settings_rp Reply;
|
||||
//Reply.status = 0x00;
|
||||
//Reply.con_handle = pLinkPolicy->con_handle;
|
||||
|
||||
SendEventCommandStatus(HCI_CMD_WRITE_LINK_POLICY_SETTINGS);
|
||||
|
||||
@@ -1929,4 +1878,4 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::LOG_LinkKey(const u8* _pLinkKey)
|
||||
, _pLinkKey[0], _pLinkKey[1], _pLinkKey[2], _pLinkKey[3], _pLinkKey[4], _pLinkKey[5], _pLinkKey[6], _pLinkKey[7]
|
||||
, _pLinkKey[8], _pLinkKey[9], _pLinkKey[10], _pLinkKey[11], _pLinkKey[12], _pLinkKey[13], _pLinkKey[14], _pLinkKey[15]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ void CWII_IPC_HLE_WiiMote::DoState(PointerWrap &p)
|
||||
p.Do(uclass);
|
||||
p.Do(features);
|
||||
p.Do(lmp_version);
|
||||
p.Do(lmp_subversion);
|
||||
p.Do(m_LinkKey);
|
||||
p.Do(m_Name);
|
||||
|
||||
|
||||
+394
-99
@@ -27,12 +27,18 @@
|
||||
#include "HW/WiimoteEmu/WiimoteEmu.h"
|
||||
#include "HW/WiimoteEmu/WiimoteHid.h"
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "State.h"
|
||||
#include "Timer.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "HW/EXI.h"
|
||||
#include "HW/EXI_Device.h"
|
||||
#include "HW/EXI_Channel.h"
|
||||
#include "HW/DVDInterface.h"
|
||||
#include "../../Common/Src/NandPaths.h"
|
||||
#include "Crypto/md5.h"
|
||||
|
||||
// large enough for just over 24 hours of single-player recording
|
||||
#define MAX_DTM_LENGTH (40 * 1024 * 1024)
|
||||
// The chunk to allocate movie data in multiples of.
|
||||
#define DTM_BASE_LENGTH (1024)
|
||||
|
||||
std::mutex cs_frameSkip;
|
||||
|
||||
@@ -50,11 +56,22 @@ u8 g_numPads = 0;
|
||||
ControllerState g_padState;
|
||||
DTMHeader tmpHeader;
|
||||
u8* tmpInput = NULL;
|
||||
size_t tmpInputAllocated = 0;
|
||||
u64 g_currentByte = 0, g_totalBytes = 0;
|
||||
u64 g_currentFrame = 0, g_totalFrames = 0; // VI
|
||||
u64 g_currentLagCount = 0, g_totalLagCount = 0; // just stats
|
||||
u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats
|
||||
u64 g_recordingStartTime; // seconds since 1970 that recording started
|
||||
bool bSaveConfig, bSkipIdle, bDualCore, bProgressive, bDSPHLE, bFastDiscSpeed = false;
|
||||
bool bMemcard, g_bClearSave = false;
|
||||
std::string videoBackend = "unknown";
|
||||
int iCPUCore = 1;
|
||||
bool g_bDiscChange = false;
|
||||
std::string g_discChange = "";
|
||||
std::string author = "";
|
||||
u64 g_titleID = 0;
|
||||
unsigned char MD5[16];
|
||||
u8 bongos;
|
||||
|
||||
bool g_bRecordingFromSaveState = false;
|
||||
bool g_bPolled = false;
|
||||
@@ -66,9 +83,39 @@ std::string g_InputDisplay[8];
|
||||
|
||||
ManipFunction mfunc = NULL;
|
||||
|
||||
void EnsureTmpInputSize(size_t bound)
|
||||
{
|
||||
if (tmpInputAllocated >= bound)
|
||||
return;
|
||||
// The buffer expands in powers of two of DTM_BASE_LENGTH
|
||||
// (standard exponential buffer growth).
|
||||
size_t newAlloc = DTM_BASE_LENGTH;
|
||||
while (newAlloc < bound)
|
||||
newAlloc *= 2;
|
||||
u8* newTmpInput = new u8[newAlloc];
|
||||
tmpInputAllocated = newAlloc;
|
||||
if (tmpInput != NULL)
|
||||
{
|
||||
if (g_totalBytes > 0)
|
||||
memcpy(newTmpInput, tmpInput, (size_t)g_totalBytes);
|
||||
delete[] tmpInput;
|
||||
}
|
||||
tmpInput = newTmpInput;
|
||||
}
|
||||
|
||||
std::string GetInputDisplay()
|
||||
{
|
||||
if (!IsPlayingInput() && !IsRecordingInput())
|
||||
{
|
||||
g_numPads = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA)
|
||||
g_numPads |= (1 << i);
|
||||
if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE)
|
||||
g_numPads |= (1 << (i + 4));
|
||||
}
|
||||
}
|
||||
std::string inputDisplay = "";
|
||||
for (int i = 0; i < 8; ++i)
|
||||
if ((g_numPads & (1 << i)) != 0)
|
||||
@@ -87,6 +134,10 @@ void FrameUpdate()
|
||||
g_totalFrames = g_currentFrame;
|
||||
g_totalLagCount = g_currentLagCount;
|
||||
}
|
||||
if (IsPlayingInput() && IsConfigSaved())
|
||||
{
|
||||
SetGraphicsConfig();
|
||||
}
|
||||
|
||||
if (g_bFrameStep)
|
||||
{
|
||||
@@ -112,8 +163,29 @@ void Init()
|
||||
g_bPolled = false;
|
||||
g_bFrameStep = false;
|
||||
g_bFrameStop = false;
|
||||
bSaveConfig = false;
|
||||
iCPUCore = SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore;
|
||||
if (IsPlayingInput())
|
||||
{
|
||||
ReadHeader();
|
||||
std::thread md5thread(CheckMD5);
|
||||
if ((strncmp((char *)tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6)))
|
||||
{
|
||||
PanicAlert("The recorded game (%s) is not the same as the selected game (%s)", tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str());
|
||||
EndPlayInput(false);
|
||||
}
|
||||
}
|
||||
if (IsRecordingInput())
|
||||
{
|
||||
GetSettings();
|
||||
std::thread md5thread(GetMD5);
|
||||
}
|
||||
|
||||
g_frameSkipCounter = g_framesToSkip;
|
||||
memset(&g_padState, 0, sizeof(g_padState));
|
||||
if (!tmpHeader.bFromSaveState || !IsPlayingInput())
|
||||
Core::SetStateFileName("");
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
g_InputDisplay[i].clear();
|
||||
|
||||
@@ -121,15 +193,10 @@ void Init()
|
||||
{
|
||||
g_bRecordingFromSaveState = false;
|
||||
g_rerecords = 0;
|
||||
g_numPads = 0;
|
||||
g_currentByte = 0;
|
||||
g_currentFrame = 0;
|
||||
g_currentLagCount = 0;
|
||||
g_currentInputCount = 0;
|
||||
// we don't clear these things because otherwise we can't resume playback if we load a movie state later
|
||||
//g_totalFrames = g_totalBytes = 0;
|
||||
//delete tmpInput;
|
||||
//tmpInput = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +205,9 @@ void InputUpdate()
|
||||
g_currentInputCount++;
|
||||
if (IsRecordingInput())
|
||||
g_totalInputCount = g_currentInputCount;
|
||||
|
||||
if (IsPlayingInput() && g_currentInputCount == (g_totalInputCount -1) && SConfig::GetInstance().m_PauseMovie)
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
}
|
||||
|
||||
void SetFrameSkipping(unsigned int framesToSkip)
|
||||
@@ -197,7 +267,7 @@ void FrameSkipping()
|
||||
g_frameSkipCounter++;
|
||||
if (g_frameSkipCounter > g_framesToSkip || Core::ShouldSkipFrame(g_frameSkipCounter) == false)
|
||||
g_frameSkipCounter = 0;
|
||||
|
||||
|
||||
g_video_backend->Video_SetRendering(!g_frameSkipCounter);
|
||||
}
|
||||
}
|
||||
@@ -217,6 +287,11 @@ bool IsJustStartingRecordingInputFromSaveState()
|
||||
return IsRecordingInputFromSaveState() && g_currentFrame == 0;
|
||||
}
|
||||
|
||||
bool IsJustStartingPlayingInputFromSaveState()
|
||||
{
|
||||
return IsRecordingInputFromSaveState() && g_currentFrame == 1 && IsPlayingInput();
|
||||
}
|
||||
|
||||
bool IsPlayingInput()
|
||||
{
|
||||
return (g_playMode == MODE_PLAYING);
|
||||
@@ -237,11 +312,60 @@ bool IsUsingPad(int controller)
|
||||
return ((g_numPads & (1 << controller)) != 0);
|
||||
}
|
||||
|
||||
bool IsUsingBongo(int controller)
|
||||
{
|
||||
return ((bongos & (1 << controller)) != 0);
|
||||
}
|
||||
|
||||
bool IsUsingWiimote(int wiimote)
|
||||
{
|
||||
return ((g_numPads & (1 << (wiimote + 4))) != 0);
|
||||
}
|
||||
|
||||
bool IsConfigSaved()
|
||||
{
|
||||
return bSaveConfig;
|
||||
}
|
||||
bool IsDualCore()
|
||||
{
|
||||
return bDualCore;
|
||||
}
|
||||
|
||||
bool IsProgressive()
|
||||
{
|
||||
return bProgressive;
|
||||
}
|
||||
|
||||
bool IsSkipIdle()
|
||||
{
|
||||
return bSkipIdle;
|
||||
}
|
||||
|
||||
bool IsDSPHLE()
|
||||
{
|
||||
return bDSPHLE;
|
||||
}
|
||||
|
||||
bool IsFastDiscSpeed()
|
||||
{
|
||||
return bFastDiscSpeed;
|
||||
}
|
||||
|
||||
int GetCPUMode()
|
||||
{
|
||||
return iCPUCore;
|
||||
}
|
||||
|
||||
bool IsStartingFromClearSave()
|
||||
{
|
||||
return g_bClearSave;
|
||||
}
|
||||
|
||||
bool IsUsingMemcard()
|
||||
{
|
||||
return bMemcard;
|
||||
}
|
||||
|
||||
void ChangePads(bool instantly)
|
||||
{
|
||||
if (Core::GetState() == Core::CORE_UNINITIALIZED)
|
||||
@@ -250,7 +374,7 @@ void ChangePads(bool instantly)
|
||||
int controllers = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER)
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA)
|
||||
controllers |= (1 << i);
|
||||
|
||||
if (instantly && (g_numPads & 0x0F) == controllers)
|
||||
@@ -258,9 +382,9 @@ void ChangePads(bool instantly)
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (instantly) // Changes from savestates need to be instantaneous
|
||||
SerialInterface::AddDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
|
||||
SerialInterface::AddDevice(IsUsingPad(i) ? (IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
|
||||
else
|
||||
SerialInterface::ChangeDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
|
||||
SerialInterface::ChangeDevice(IsUsingPad(i) ? (IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
|
||||
}
|
||||
|
||||
void ChangeWiiPads(bool instantly)
|
||||
@@ -287,6 +411,17 @@ bool BeginRecordingInput(int controllers)
|
||||
if(g_playMode != MODE_NONE || controllers == 0)
|
||||
return false;
|
||||
|
||||
g_numPads = controllers;
|
||||
g_currentFrame = g_totalFrames = 0;
|
||||
g_currentLagCount = g_totalLagCount = 0;
|
||||
g_currentInputCount = g_totalInputCount = 0;
|
||||
g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
|
||||
g_rerecords = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA)
|
||||
bongos |= (1 << i);
|
||||
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
if(File::Exists(tmpStateFilename))
|
||||
@@ -294,20 +429,25 @@ bool BeginRecordingInput(int controllers)
|
||||
|
||||
State::SaveAs(tmpStateFilename.c_str());
|
||||
g_bRecordingFromSaveState = true;
|
||||
}
|
||||
|
||||
g_numPads = controllers;
|
||||
g_currentFrame = g_totalFrames = 0;
|
||||
g_currentLagCount = g_totalLagCount = 0;
|
||||
g_currentInputCount = g_totalInputCount = 0;
|
||||
g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
|
||||
g_rerecords = 0;
|
||||
g_playMode = MODE_RECORDING;
|
||||
|
||||
delete [] tmpInput;
|
||||
tmpInput = new u8[MAX_DTM_LENGTH];
|
||||
// This is only done here if starting from save state because otherwise we won't have the titleid. Otherwise it's set in WII_IPC_HLE_Device_es.cpp.
|
||||
// TODO: find a way to GetTitleDataPath() from Movie::Init()
|
||||
if (Core::g_CoreStartupParameter.bWii)
|
||||
{
|
||||
if (File::Exists((Common::GetTitleDataPath(g_titleID) + "banner.bin").c_str()))
|
||||
Movie::g_bClearSave = false;
|
||||
else
|
||||
Movie::g_bClearSave = true;
|
||||
}
|
||||
std::thread md5thread(GetMD5);
|
||||
}
|
||||
g_playMode = MODE_RECORDING;
|
||||
GetSettings();
|
||||
author = SConfig::GetInstance().m_strMovieAuthor;
|
||||
EnsureTmpInputSize(1);
|
||||
|
||||
g_currentByte = g_totalBytes = 0;
|
||||
|
||||
|
||||
Core::DisplayMessage("Starting movie recording", 2000);
|
||||
return true;
|
||||
}
|
||||
@@ -390,15 +530,6 @@ void SetInputDisplayString(ControllerState padState, int controllerID)
|
||||
if(g_padState.DPadRight)
|
||||
g_InputDisplay[controllerID].append(" RIGHT");
|
||||
|
||||
//if(g_padState.L)
|
||||
//{
|
||||
// g_InputDisplay[controllerID].append(" L");
|
||||
//}
|
||||
//if(g_padState.R)
|
||||
//{
|
||||
// g_InputDisplay[controllerID].append(" R");
|
||||
//}
|
||||
|
||||
Analog1DToString(g_padState.TriggerL, " L", inp);
|
||||
g_InputDisplay[controllerID].append(inp);
|
||||
|
||||
@@ -465,60 +596,121 @@ void SetWiiInputDisplayString(int remoteID, u8* const coreData, u8* const accelD
|
||||
g_InputDisplay[controllerID].append("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RecordInput(SPADStatus *PadStatus, int controllerID)
|
||||
void CheckPadStatus(SPADStatus *PadStatus, int controllerID)
|
||||
{
|
||||
if(!IsRecordingInput() || !IsUsingPad(controllerID))
|
||||
return;
|
||||
|
||||
g_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0);
|
||||
g_padState.B = ((PadStatus->button & PAD_BUTTON_B) != 0);
|
||||
g_padState.X = ((PadStatus->button & PAD_BUTTON_X) != 0);
|
||||
g_padState.Y = ((PadStatus->button & PAD_BUTTON_Y) != 0);
|
||||
g_padState.Z = ((PadStatus->button & PAD_TRIGGER_Z) != 0);
|
||||
g_padState.Start = ((PadStatus->button & PAD_BUTTON_START) != 0);
|
||||
|
||||
|
||||
g_padState.DPadUp = ((PadStatus->button & PAD_BUTTON_UP) != 0);
|
||||
g_padState.DPadDown = ((PadStatus->button & PAD_BUTTON_DOWN) != 0);
|
||||
g_padState.DPadLeft = ((PadStatus->button & PAD_BUTTON_LEFT) != 0);
|
||||
g_padState.DPadRight = ((PadStatus->button & PAD_BUTTON_RIGHT) != 0);
|
||||
|
||||
|
||||
g_padState.L = ((PadStatus->button & PAD_TRIGGER_L) != 0);
|
||||
g_padState.R = ((PadStatus->button & PAD_TRIGGER_R) != 0);
|
||||
g_padState.TriggerL = PadStatus->triggerLeft;
|
||||
g_padState.TriggerR = PadStatus->triggerRight;
|
||||
|
||||
|
||||
g_padState.AnalogStickX = PadStatus->stickX;
|
||||
g_padState.AnalogStickY = PadStatus->stickY;
|
||||
|
||||
|
||||
g_padState.CStickX = PadStatus->substickX;
|
||||
g_padState.CStickY = PadStatus->substickY;
|
||||
|
||||
|
||||
memcpy(&(tmpInput[g_currentByte]), &g_padState, 8);
|
||||
g_currentByte += 8;
|
||||
g_totalBytes = g_currentByte;
|
||||
|
||||
SetInputDisplayString(g_padState, controllerID);
|
||||
}
|
||||
|
||||
void RecordWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
|
||||
void RecordInput(SPADStatus *PadStatus, int controllerID)
|
||||
{
|
||||
if(!IsRecordingInput() || !IsUsingWiimote(wiimote))
|
||||
if (!IsRecordingInput() || !IsUsingPad(controllerID))
|
||||
return;
|
||||
|
||||
CheckPadStatus(PadStatus, controllerID);
|
||||
|
||||
if (g_bDiscChange)
|
||||
{
|
||||
g_padState.disc = g_bDiscChange;
|
||||
g_bDiscChange = false;
|
||||
}
|
||||
|
||||
EnsureTmpInputSize((size_t)(g_currentByte + 8));
|
||||
memcpy(&(tmpInput[g_currentByte]), &g_padState, 8);
|
||||
g_currentByte += 8;
|
||||
g_totalBytes = g_currentByte;
|
||||
}
|
||||
|
||||
void CheckWiimoteStatus(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
|
||||
{
|
||||
u8* const coreData = rptf.core?(data+rptf.core):NULL;
|
||||
u8* const accelData = rptf.accel?(data+rptf.accel):NULL;
|
||||
u8* const irData = rptf.ir?(data+rptf.ir):NULL;
|
||||
u8 size = rptf.size;
|
||||
SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
|
||||
|
||||
if (IsRecordingInput())
|
||||
RecordWiimote(wiimote, data, size);
|
||||
}
|
||||
|
||||
void RecordWiimote(int wiimote, u8 *data, u8 size)
|
||||
{
|
||||
if(!IsRecordingInput() || !IsUsingWiimote(wiimote))
|
||||
return;
|
||||
|
||||
InputUpdate();
|
||||
EnsureTmpInputSize((size_t)(g_currentByte + size + 1));
|
||||
tmpInput[g_currentByte++] = size;
|
||||
memcpy(&(tmpInput[g_currentByte]), data, size);
|
||||
g_currentByte += size;
|
||||
g_totalBytes = g_currentByte;
|
||||
SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
|
||||
}
|
||||
|
||||
void ReadHeader()
|
||||
{
|
||||
g_numPads = tmpHeader.numControllers;
|
||||
g_recordingStartTime = tmpHeader.recordingStartTime;
|
||||
if (g_rerecords < tmpHeader.numRerecords)
|
||||
g_rerecords = tmpHeader.numRerecords;
|
||||
|
||||
if (tmpHeader.bSaveConfig)
|
||||
{
|
||||
bSaveConfig = true;
|
||||
bSkipIdle = tmpHeader.bSkipIdle;
|
||||
bDualCore = tmpHeader.bDualCore;
|
||||
bProgressive = tmpHeader.bProgressive;
|
||||
bDSPHLE = tmpHeader.bDSPHLE;
|
||||
bFastDiscSpeed = tmpHeader.bFastDiscSpeed;
|
||||
iCPUCore = tmpHeader.CPUCore;
|
||||
g_bClearSave = tmpHeader.bClearSave;
|
||||
bMemcard = tmpHeader.bMemcard;
|
||||
bongos = tmpHeader.bongos;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSettings();
|
||||
}
|
||||
|
||||
videoBackend.resize(ARRAYSIZE(tmpHeader.videoBackend));
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.videoBackend);i++)
|
||||
{
|
||||
videoBackend[i] = tmpHeader.videoBackend[i];
|
||||
}
|
||||
|
||||
g_discChange.resize(ARRAYSIZE(tmpHeader.discChange));
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.discChange);i++)
|
||||
{
|
||||
g_discChange[i] = tmpHeader.discChange[i];
|
||||
}
|
||||
|
||||
author.resize(ARRAYSIZE(tmpHeader.author));
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.author);i++)
|
||||
{
|
||||
author[i] = tmpHeader.author[i];
|
||||
}
|
||||
memcpy(MD5, tmpHeader.md5, 16);
|
||||
}
|
||||
|
||||
bool PlayInput(const char *filename)
|
||||
@@ -528,19 +720,19 @@ bool PlayInput(const char *filename)
|
||||
|
||||
if(!File::Exists(filename))
|
||||
return false;
|
||||
|
||||
|
||||
File::IOFile g_recordfd;
|
||||
|
||||
|
||||
if (!g_recordfd.Open(filename, "rb"))
|
||||
return false;
|
||||
|
||||
|
||||
g_recordfd.ReadArray(&tmpHeader, 1);
|
||||
|
||||
if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A) {
|
||||
PanicAlertT("Invalid recording file");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Load savestate (and skip to frame data)
|
||||
if(tmpHeader.bFromSaveState)
|
||||
{
|
||||
@@ -548,29 +740,13 @@ bool PlayInput(const char *filename)
|
||||
if(File::Exists(stateFilename))
|
||||
Core::SetStateFileName(stateFilename);
|
||||
g_bRecordingFromSaveState = true;
|
||||
Movie::LoadInput(filename);
|
||||
}
|
||||
|
||||
/* TODO: Put this verification somewhere we have the gameID of the played game
|
||||
// TODO: Replace with Unique ID
|
||||
if(tmpHeader.uniqueID != 0) {
|
||||
PanicAlert("Recording Unique ID Verification Failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(strncmp((char *)tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6)) {
|
||||
PanicAlert("The recorded game (%s) is not the same as the selected game (%s)", header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str());
|
||||
goto cleanup;
|
||||
}
|
||||
*/
|
||||
|
||||
g_numPads = tmpHeader.numControllers;
|
||||
g_rerecords = tmpHeader.numRerecords;
|
||||
|
||||
ReadHeader();
|
||||
g_totalFrames = tmpHeader.frameCount;
|
||||
g_totalLagCount = tmpHeader.lagCount;
|
||||
g_totalInputCount = tmpHeader.inputCount;
|
||||
g_recordingStartTime = tmpHeader.recordingStartTime;
|
||||
|
||||
g_currentFrame = 0;
|
||||
g_currentLagCount = 0;
|
||||
g_currentInputCount = 0;
|
||||
@@ -578,14 +754,13 @@ bool PlayInput(const char *filename)
|
||||
g_playMode = MODE_PLAYING;
|
||||
|
||||
g_totalBytes = g_recordfd.GetSize() - 256;
|
||||
delete tmpInput;
|
||||
tmpInput = new u8[MAX_DTM_LENGTH];
|
||||
EnsureTmpInputSize((size_t)g_totalBytes);
|
||||
g_recordfd.ReadArray(tmpInput, (size_t)g_totalBytes);
|
||||
g_currentByte = 0;
|
||||
g_recordfd.Close();
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
cleanup:
|
||||
g_recordfd.Close();
|
||||
return false;
|
||||
@@ -609,28 +784,24 @@ void DoState(PointerWrap &p)
|
||||
void LoadInput(const char *filename)
|
||||
{
|
||||
File::IOFile t_record(filename, "r+b");
|
||||
|
||||
|
||||
t_record.ReadArray(&tmpHeader, 1);
|
||||
|
||||
|
||||
if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A)
|
||||
{
|
||||
PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename);
|
||||
EndPlayInput(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ReadHeader();
|
||||
if (!g_bReadOnly)
|
||||
{
|
||||
if (g_rerecords > tmpHeader.numRerecords)
|
||||
{
|
||||
tmpHeader.numRerecords = g_rerecords;
|
||||
}
|
||||
tmpHeader.numRerecords++;
|
||||
g_rerecords++;
|
||||
tmpHeader.numRerecords = g_rerecords;
|
||||
t_record.Seek(0, SEEK_SET);
|
||||
t_record.WriteArray(&tmpHeader, 1);
|
||||
}
|
||||
|
||||
g_numPads = tmpHeader.numControllers;
|
||||
|
||||
ChangePads(true);
|
||||
if (Core::g_CoreStartupParameter.bWii)
|
||||
ChangeWiiPads(true);
|
||||
@@ -650,9 +821,8 @@ void LoadInput(const char *filename)
|
||||
g_totalLagCount = tmpHeader.lagCount;
|
||||
g_totalInputCount = tmpHeader.inputCount;
|
||||
|
||||
EnsureTmpInputSize((size_t)totalSavedBytes);
|
||||
g_totalBytes = totalSavedBytes;
|
||||
delete [] tmpInput;
|
||||
tmpInput = new u8[MAX_DTM_LENGTH];
|
||||
t_record.ReadArray(tmpInput, (size_t)g_totalBytes);
|
||||
}
|
||||
else if (g_currentByte > 0)
|
||||
@@ -710,7 +880,7 @@ void LoadInput(const char *filename)
|
||||
}
|
||||
t_record.Close();
|
||||
|
||||
g_rerecords = tmpHeader.numRerecords;
|
||||
bSaveConfig = tmpHeader.bSaveConfig;
|
||||
|
||||
if (!afterEnd)
|
||||
{
|
||||
@@ -752,6 +922,18 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
|
||||
if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == NULL)
|
||||
return;
|
||||
|
||||
if (g_currentFrame == 1)
|
||||
{
|
||||
if (tmpHeader.bMemcard)
|
||||
{
|
||||
ExpansionInterface::ChangeDevice(0, EXIDEVICE_MEMORYCARD, 0);
|
||||
}
|
||||
else if (!tmpHeader.bMemcard)
|
||||
{
|
||||
ExpansionInterface::ChangeDevice(0, EXIDEVICE_NONE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_currentByte + 8 > g_totalBytes)
|
||||
{
|
||||
PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)g_currentByte, (u32)g_totalBytes);
|
||||
@@ -759,8 +941,7 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
|
||||
return;
|
||||
}
|
||||
|
||||
// dtm files don't save the mic button or error bit. not sure if they're actually
|
||||
// used, but better safe than sorry
|
||||
// dtm files don't save the mic button or error bit. not sure if they're actually used, but better safe than sorry
|
||||
signed char e = PadStatus->err;
|
||||
memset(PadStatus, 0, sizeof(SPADStatus));
|
||||
PadStatus->err = e;
|
||||
@@ -812,9 +993,35 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
|
||||
PadStatus->button |= PAD_TRIGGER_L;
|
||||
if(g_padState.R)
|
||||
PadStatus->button |= PAD_TRIGGER_R;
|
||||
if (g_padState.disc)
|
||||
{
|
||||
// This implementation assumes the disc change will only happen once. Trying to change more than that will cause
|
||||
// it to load the last disc every time. As far as i know though, there are no 3+ disc games, so this should be fine.
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
int numPaths = (int)SConfig::GetInstance().m_ISOFolder.size();
|
||||
bool found = false;
|
||||
std::string path;
|
||||
for (int i = 0; i < numPaths; i++)
|
||||
{
|
||||
path = SConfig::GetInstance().m_ISOFolder[i];
|
||||
if (File::Exists((path + '/' + g_discChange.c_str()).c_str()))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
DVDInterface::ChangeDisc((path + '/' + g_discChange.c_str()).c_str());
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Change the disc to %s", g_discChange.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SetInputDisplayString(g_padState, controllerID);
|
||||
|
||||
CheckInputEnd();
|
||||
}
|
||||
|
||||
@@ -873,10 +1080,11 @@ void EndPlayInput(bool cont)
|
||||
}
|
||||
else if(g_playMode != MODE_NONE)
|
||||
{
|
||||
g_numPads = g_rerecords = 0;
|
||||
g_rerecords = 0;
|
||||
g_currentByte = 0;
|
||||
g_playMode = MODE_NONE;
|
||||
Core::DisplayMessage("Movie End.", 2000);
|
||||
g_bRecordingFromSaveState = 0;
|
||||
// we don't clear these things because otherwise we can't resume playback if we load a movie state later
|
||||
//g_totalFrames = g_totalBytes = 0;
|
||||
//delete tmpInput;
|
||||
@@ -887,7 +1095,6 @@ void EndPlayInput(bool cont)
|
||||
void SaveRecording(const char *filename)
|
||||
{
|
||||
File::IOFile save_record(filename, "wb");
|
||||
|
||||
// Create the real header now and write it
|
||||
DTMHeader header;
|
||||
memset(&header, 0, sizeof(DTMHeader));
|
||||
@@ -903,13 +1110,33 @@ void SaveRecording(const char *filename)
|
||||
header.inputCount = g_totalInputCount;
|
||||
header.numRerecords = g_rerecords;
|
||||
header.recordingStartTime = g_recordingStartTime;
|
||||
|
||||
|
||||
header.bSaveConfig = true;
|
||||
header.bSkipIdle = bSkipIdle;
|
||||
header.bDualCore = bDualCore;
|
||||
header.bProgressive = bProgressive;
|
||||
header.bDSPHLE = bDSPHLE;
|
||||
header.bFastDiscSpeed = bFastDiscSpeed;
|
||||
strncpy((char *)header.videoBackend, videoBackend.c_str(),ARRAYSIZE(header.videoBackend));
|
||||
header.CPUCore = iCPUCore;
|
||||
header.bEFBAccessEnable = g_ActiveConfig.bEFBAccessEnable;
|
||||
header.bEFBCopyEnable = g_ActiveConfig.bEFBCopyEnable;
|
||||
header.bCopyEFBToTexture = g_ActiveConfig.bCopyEFBToTexture;
|
||||
header.bEFBCopyCacheEnable = g_ActiveConfig.bEFBCopyCacheEnable;
|
||||
header.bEFBEmulateFormatChanges = g_ActiveConfig.bEFBEmulateFormatChanges;
|
||||
header.bUseXFB = g_ActiveConfig.bUseXFB;
|
||||
header.bUseRealXFB = g_ActiveConfig.bUseRealXFB;
|
||||
header.bMemcard = bMemcard;
|
||||
header.bClearSave = g_bClearSave;
|
||||
strncpy((char *)header.discChange, g_discChange.c_str(),ARRAYSIZE(header.discChange));
|
||||
strncpy((char *)header.author, author.c_str(),ARRAYSIZE(header.author));
|
||||
memcpy(header.md5,MD5,16);
|
||||
header.bongos = bongos;
|
||||
|
||||
// TODO
|
||||
header.uniqueID = 0;
|
||||
// header.author;
|
||||
// header.videoBackend;
|
||||
// header.audioEmulator;
|
||||
|
||||
|
||||
save_record.WriteArray(&header, 1);
|
||||
|
||||
bool success = save_record.WriteArray(tmpInput, (size_t)g_totalBytes);
|
||||
@@ -937,4 +1164,72 @@ void CallInputManip(SPADStatus *PadStatus, int controllerID)
|
||||
if (mfunc)
|
||||
(*mfunc)(PadStatus, controllerID);
|
||||
}
|
||||
|
||||
void SetGraphicsConfig()
|
||||
{
|
||||
g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable;
|
||||
g_Config.bEFBCopyEnable = tmpHeader.bEFBCopyEnable;
|
||||
g_Config.bCopyEFBToTexture = tmpHeader.bCopyEFBToTexture;
|
||||
g_Config.bEFBCopyCacheEnable = tmpHeader.bEFBCopyCacheEnable;
|
||||
g_Config.bEFBEmulateFormatChanges = tmpHeader.bEFBEmulateFormatChanges;
|
||||
g_Config.bUseXFB = tmpHeader.bUseXFB;
|
||||
g_Config.bUseRealXFB = tmpHeader.bUseRealXFB;
|
||||
}
|
||||
|
||||
void GetSettings()
|
||||
{
|
||||
bSaveConfig = true;
|
||||
bSkipIdle = SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle;
|
||||
bDualCore = SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread;
|
||||
bProgressive = SConfig::GetInstance().m_LocalCoreStartupParameter.bProgressive;
|
||||
bDSPHLE = SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE;
|
||||
bFastDiscSpeed = SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed;
|
||||
videoBackend = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend;
|
||||
iCPUCore = SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore;
|
||||
if (!Core::g_CoreStartupParameter.bWii)
|
||||
g_bClearSave = !File::Exists(SConfig::GetInstance().m_strMemoryCardA);
|
||||
bMemcard = SConfig::GetInstance().m_EXIDevice[0] == EXIDEVICE_MEMORYCARD;
|
||||
}
|
||||
|
||||
void CheckMD5()
|
||||
{
|
||||
for (int i=0, n=0; i<16; i++)
|
||||
{
|
||||
if (tmpHeader.md5[i] != 0)
|
||||
continue;
|
||||
n++;
|
||||
if (n == 16)
|
||||
return;
|
||||
}
|
||||
Core::DisplayMessage("Verifying checksum...", 2000);
|
||||
|
||||
unsigned char gameMD5[16];
|
||||
char game[255];
|
||||
memcpy(game, SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.c_str(), SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.size());
|
||||
md5_file(game, gameMD5);
|
||||
|
||||
if (memcmp(gameMD5,MD5,16) == 0)
|
||||
Core::DisplayMessage("Checksum of current game matches the recorded game.", 2000);
|
||||
else
|
||||
PanicAlert("Checksum of current game does not match the recorded game!");
|
||||
}
|
||||
|
||||
void GetMD5()
|
||||
{
|
||||
Core::DisplayMessage("Calculating checksum of game file...", 2000);
|
||||
for (int i = 0; i < 16; i++)
|
||||
MD5[i] = 0;
|
||||
char game[255];
|
||||
memcpy(game, SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.c_str(),SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.size());
|
||||
md5_file(game, MD5);
|
||||
Core::DisplayMessage("Finished calculating checksum.", 2000);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
g_currentInputCount = g_totalInputCount = g_totalFrames = g_totalBytes = 0;
|
||||
delete [] tmpInput;
|
||||
tmpInput = NULL;
|
||||
tmpInputAllocated = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#define __MOVIE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "../../InputCommon/Src/GCPadStatus.h"
|
||||
|
||||
#include <string>
|
||||
@@ -48,19 +47,22 @@ struct ControllerState {
|
||||
bool Start:1, A:1, B:1, X:1, Y:1, Z:1; // Binary buttons, 6 bits
|
||||
bool DPadUp:1, DPadDown:1, // Binary D-Pad buttons, 4 bits
|
||||
DPadLeft:1, DPadRight:1;
|
||||
bool L:1, R:1; // Binary triggers, 2 bits
|
||||
bool reserved:4; // Reserved bits used for padding, 4 bits
|
||||
bool L:1, R:1; // Binary triggers, 2 bits
|
||||
bool disc:1; // Checks for disc being changed
|
||||
bool reserved:3; // Reserved bits used for padding, 4 bits
|
||||
|
||||
u8 TriggerL, TriggerR; // Triggers, 16 bits
|
||||
u8 TriggerL, TriggerR; // Triggers, 16 bits
|
||||
u8 AnalogStickX, AnalogStickY; // Main Stick, 16 bits
|
||||
u8 CStickX, CStickY; // Sub-Stick, 16 bits
|
||||
|
||||
}; // Total: 60 + 4 = 64 bits per frame
|
||||
static_assert(sizeof(ControllerState) == 8, "ControllerState should be 8 bytes");
|
||||
#pragma pack(pop)
|
||||
|
||||
// Global declarations
|
||||
extern bool g_bFrameStep, g_bPolled, g_bReadOnly;
|
||||
extern bool g_bFrameStep, g_bPolled, g_bReadOnly, g_bDiscChange, g_bClearSave;
|
||||
extern PlayMode g_playMode;
|
||||
extern u64 g_titleID;
|
||||
|
||||
extern u32 g_framesToSkip, g_frameSkipCounter;
|
||||
|
||||
@@ -73,6 +75,7 @@ extern u64 g_currentByte, g_totalBytes;
|
||||
extern u64 g_currentFrame, g_totalFrames;
|
||||
extern u64 g_currentLagCount, g_totalLagCount;
|
||||
extern u64 g_currentInputCount, g_totalInputCount;
|
||||
extern std::string g_discChange;
|
||||
|
||||
extern u32 g_rerecords;
|
||||
|
||||
@@ -92,15 +95,36 @@ struct DTMHeader {
|
||||
u64 uniqueID; // (not implemented) A Unique ID comprised of: md5(time + Game ID)
|
||||
u32 numRerecords; // Number of rerecords/'cuts' of this TAS
|
||||
u8 author[32]; // Author's name (encoded in UTF-8)
|
||||
|
||||
|
||||
u8 videoBackend[16]; // UTF-8 representation of the video backend
|
||||
u8 audioEmulator[16]; // UTF-8 representation of the audio emulator
|
||||
u8 padBackend[16]; // UTF-8 representation of the input backend
|
||||
unsigned char md5[16]; // MD5 of game iso
|
||||
|
||||
u64 recordingStartTime; // seconds since 1970 that recording started (used for RTC)
|
||||
|
||||
u8 reserved[119]; // Make heading 256 bytes, just because we can
|
||||
bool bSaveConfig; // Loads the settings below on startup if true
|
||||
bool bSkipIdle;
|
||||
bool bDualCore;
|
||||
bool bProgressive;
|
||||
bool bDSPHLE;
|
||||
bool bFastDiscSpeed;
|
||||
u8 CPUCore; // 0 = interpreter, 1 = JIT, 2 = JITIL
|
||||
bool bEFBAccessEnable;
|
||||
bool bEFBCopyEnable;
|
||||
bool bCopyEFBToTexture;
|
||||
bool bEFBCopyCacheEnable;
|
||||
bool bEFBEmulateFormatChanges;
|
||||
bool bUseXFB;
|
||||
bool bUseRealXFB;
|
||||
bool bMemcard;
|
||||
bool bClearSave; // Create a new memory card when playing back a movie if true
|
||||
u8 bongos;
|
||||
u8 reserved[15]; // Padding for any new config options
|
||||
u8 discChange[40]; // Name of iso file to switch to, for two disc games.
|
||||
u8 reserved2[47]; // Make heading 256 bytes, just because we can
|
||||
};
|
||||
static_assert(sizeof(DTMHeader) == 256, "DTMHeader should be 256 bytes");
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
void FrameUpdate();
|
||||
@@ -109,16 +133,29 @@ void Init();
|
||||
|
||||
void SetPolledDevice();
|
||||
|
||||
bool IsAutoFiring();
|
||||
bool IsRecordingInput();
|
||||
bool IsRecordingInputFromSaveState();
|
||||
bool IsJustStartingRecordingInputFromSaveState();
|
||||
bool IsJustStartingPlayingInputFromSaveState();
|
||||
bool IsPlayingInput();
|
||||
bool IsReadOnly();
|
||||
u64 GetRecordingStartTime();
|
||||
|
||||
bool IsConfigSaved();
|
||||
bool IsDualCore();
|
||||
bool IsProgressive();
|
||||
bool IsSkipIdle();
|
||||
bool IsDSPHLE();
|
||||
bool IsFastDiscSpeed();
|
||||
int GetCPUMode();
|
||||
bool IsStartingFromClearSave();
|
||||
bool IsUsingMemcard();
|
||||
void SetGraphicsConfig();
|
||||
void GetSettings();
|
||||
|
||||
bool IsUsingPad(int controller);
|
||||
bool IsUsingWiimote(int wiimote);
|
||||
bool IsUsingBongo(int controller);
|
||||
void ChangePads(bool instantly = false);
|
||||
void ChangeWiiPads(bool instantly = false);
|
||||
|
||||
@@ -131,15 +168,21 @@ void FrameSkipping();
|
||||
|
||||
bool BeginRecordingInput(int controllers);
|
||||
void RecordInput(SPADStatus *PadStatus, int controllerID);
|
||||
void RecordWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode);
|
||||
void RecordWiimote(int wiimote, u8 *data, u8 size);
|
||||
|
||||
bool PlayInput(const char *filename);
|
||||
void LoadInput(const char *filename);
|
||||
void ReadHeader();
|
||||
void PlayController(SPADStatus *PadStatus, int controllerID);
|
||||
bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode);
|
||||
void EndPlayInput(bool cont);
|
||||
void SaveRecording(const char *filename);
|
||||
void DoState(PointerWrap &p);
|
||||
void CheckMD5();
|
||||
void GetMD5();
|
||||
void Shutdown();
|
||||
void CheckPadStatus(SPADStatus *PadStatus, int controllerID);
|
||||
void CheckWiimoteStatus(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode);
|
||||
|
||||
std::string GetInputDisplay();
|
||||
|
||||
@@ -150,4 +193,4 @@ void SetInputManip(ManipFunction);
|
||||
void CallInputManip(SPADStatus *PadStatus, int controllerID);
|
||||
};
|
||||
|
||||
#endif // __FRAME_H
|
||||
#endif // __MOVIE_H
|
||||
|
||||
@@ -295,6 +295,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{266, Interpreter::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{778, Interpreter::addx, {"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{10, Interpreter::addcx, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{522, Interpreter::addcx, {"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{138, Interpreter::addex, {"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{234, Interpreter::addmex, {"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{202, Interpreter::addzex, {"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
@@ -310,6 +311,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{40, Interpreter::subfx, {"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{552, Interpreter::subfx, {"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{8, Interpreter::subfcx, {"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{520, Interpreter::subfcx, {"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{136, Interpreter::subfex, {"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{232, Interpreter::subfmex, {"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
{200, Interpreter::subfzex, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
|
||||
|
||||
@@ -308,6 +308,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{266, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{778, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{10, &Jit64::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{522, &Jit64::addcx}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
@@ -323,6 +324,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{40, &Jit64::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{552, &Jit64::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{8, &Jit64::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{520, &Jit64::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{136, &Jit64::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{232, &Jit64::subfmex}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{200, &Jit64::subfzex}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
|
||||
@@ -1097,7 +1097,7 @@ void Jit64::mulli(UGeckoInstruction inst)
|
||||
gpr.BindToRegister(d, (d == a), true);
|
||||
if (imm == 0)
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
else if(imm == -1)
|
||||
else if(imm == (u32)-1)
|
||||
{
|
||||
if (d != a)
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
@@ -1147,7 +1147,7 @@ void Jit64::mullwx(UGeckoInstruction inst)
|
||||
int src = gpr.R(a).IsImm() ? b : a;
|
||||
if (imm == 0)
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
else if(imm == -1)
|
||||
else if(imm == (u32)-1)
|
||||
{
|
||||
if (d != src)
|
||||
MOV(32, gpr.R(d), gpr.R(src));
|
||||
@@ -1263,7 +1263,7 @@ void Jit64::divwux(UGeckoInstruction inst)
|
||||
while(!(divisor & (1 << shift)))
|
||||
shift--;
|
||||
|
||||
if (divisor == (1 << shift))
|
||||
if (divisor == (u32)(1 << shift))
|
||||
{
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, d == a, true);
|
||||
@@ -1387,7 +1387,7 @@ void Jit64::divwx(UGeckoInstruction inst)
|
||||
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
|
||||
{
|
||||
s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
|
||||
if( j == 0 || i == 0x80000000 && j == -1)
|
||||
if( j == 0 || (i == (s32)0x80000000 && j == -1))
|
||||
{
|
||||
gpr.SetImmediate32(d, (i >> 31) ^ j);
|
||||
if (inst.OE)
|
||||
|
||||
@@ -472,10 +472,10 @@ static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI,
|
||||
#else
|
||||
// 64-bit
|
||||
if (Profiled) {
|
||||
RI.Jit->LEA(32, EAX, M((void*)addr));
|
||||
RI.Jit->LEA(32, EAX, M((void*)(u64)addr));
|
||||
return MComplex(RBX, EAX, SCALE_1, 0);
|
||||
}
|
||||
return M((void*)addr);
|
||||
return M((void*)(u64)addr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +309,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{778, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{10, &JitIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{522, &JitIL::Default}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{234, &JitIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
@@ -324,6 +325,7 @@ static GekkoOPTemplate table31_2[] =
|
||||
{40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{552, &JitIL::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
|
||||
{8, &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{520, &JitIL::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
|
||||
{136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{232, &JitIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{200, &JitIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
|
||||
@@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
||||
static std::thread g_save_thread;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
static const int STATE_VERSION = 8;
|
||||
static const u32 STATE_VERSION = 10;
|
||||
|
||||
struct StateHeader
|
||||
{
|
||||
@@ -196,10 +196,18 @@ void CompressAndDumpState(CompressAndDumpState_args save_args)
|
||||
{
|
||||
if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
|
||||
File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"));
|
||||
if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"))
|
||||
File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"));
|
||||
|
||||
if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
|
||||
Core::DisplayMessage("Failed to move previous state to state undo backup", 1000);
|
||||
else
|
||||
File::Rename(filename + ".dtm", File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm");
|
||||
}
|
||||
if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsJustStartingRecordingInputFromSaveState())
|
||||
Movie::SaveRecording((filename + ".dtm").c_str());
|
||||
else if (!Movie::IsRecordingInput() && !Movie::IsPlayingInput())
|
||||
File::Delete(filename + ".dtm");
|
||||
|
||||
File::IOFile f(filename, "wb");
|
||||
if (!f)
|
||||
@@ -273,10 +281,6 @@ void SaveAs(const std::string& filename)
|
||||
if (p.GetMode() == PointerWrap::MODE_WRITE)
|
||||
{
|
||||
Core::DisplayMessage("Saving State...", 1000);
|
||||
if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsJustStartingRecordingInputFromSaveState())
|
||||
Movie::SaveRecording((filename + ".dtm").c_str());
|
||||
else if (!Movie::IsRecordingInput() && !Movie::IsPlayingInput())
|
||||
File::Delete(filename + ".dtm");
|
||||
|
||||
CompressAndDumpState_args save_args;
|
||||
save_args.buffer_vector = &g_current_buffer;
|
||||
@@ -383,9 +387,14 @@ void LoadAs(const std::string& filename)
|
||||
g_loadDepth++;
|
||||
|
||||
// Save temp buffer for undo load state
|
||||
if (!Movie::IsJustStartingRecordingInputFromSaveState())
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
|
||||
SaveToBuffer(g_undo_load_buffer);
|
||||
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
|
||||
Movie::SaveRecording("undo.dtm");
|
||||
else if (File::Exists("undo.dtm"))
|
||||
File::Delete("undo.dtm");
|
||||
}
|
||||
|
||||
bool loaded = false;
|
||||
@@ -413,7 +422,7 @@ void LoadAs(const std::string& filename)
|
||||
Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()).c_str(), 2000);
|
||||
if (File::Exists(filename + ".dtm"))
|
||||
Movie::LoadInput((filename + ".dtm").c_str());
|
||||
else if (!Movie::IsJustStartingRecordingInputFromSaveState())
|
||||
else if (!Movie::IsJustStartingRecordingInputFromSaveState() && !Movie::IsJustStartingPlayingInputFromSaveState())
|
||||
Movie::EndPlayInput(false);
|
||||
}
|
||||
else
|
||||
@@ -534,7 +543,16 @@ void UndoLoadState()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
|
||||
if (!g_undo_load_buffer.empty())
|
||||
LoadFromBuffer(g_undo_load_buffer);
|
||||
{
|
||||
if (File::Exists("undo.dtm") || (!Movie::IsRecordingInput() && !Movie::IsPlayingInput()))
|
||||
{
|
||||
LoadFromBuffer(g_undo_load_buffer);
|
||||
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
|
||||
Movie::LoadInput("undo.dtm");
|
||||
}
|
||||
else
|
||||
PanicAlert("No undo.dtm found, aborting undo load state to prevent movie desyncs");
|
||||
}
|
||||
else
|
||||
PanicAlert("There is nothing to undo!");
|
||||
}
|
||||
@@ -542,7 +560,7 @@ void UndoLoadState()
|
||||
// Load the state that the last save state overwritten on
|
||||
void UndoSaveState()
|
||||
{
|
||||
LoadAs((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav").c_str());
|
||||
LoadAs((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav").c_str());
|
||||
}
|
||||
|
||||
} // namespace State
|
||||
|
||||
@@ -8,7 +8,6 @@ set(LIBS core
|
||||
z
|
||||
sfml-network
|
||||
${GTK2_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${XRANDR_LIBRARIES}
|
||||
${X11_LIBRARIES})
|
||||
|
||||
@@ -31,7 +30,8 @@ if(LIBAV_FOUND)
|
||||
endif()
|
||||
|
||||
if(wxWidgets_FOUND)
|
||||
set(SRCS Src/ARCodeAddEdit.cpp
|
||||
set(SRCS
|
||||
Src/ARCodeAddEdit.cpp
|
||||
Src/AboutDolphin.cpp
|
||||
Src/CheatsWindow.cpp
|
||||
Src/ConfigMain.cpp
|
||||
@@ -79,7 +79,27 @@ if(wxWidgets_FOUND)
|
||||
|
||||
set(WXLIBS ${wxWidgets_LIBRARIES})
|
||||
else()
|
||||
set(SRCS Src/MainNoGUI.cpp)
|
||||
set(SRCS
|
||||
Src/MainNoGUI.cpp)
|
||||
endif()
|
||||
|
||||
if(USE_EGL)
|
||||
set(SRCS ${SRCS} Src/GLInterface/EGL.cpp
|
||||
Src/GLInterface/X11_Util.cpp)
|
||||
else()
|
||||
if(WIN32)
|
||||
set(SRCS ${SRCS} Src/GLInterface/GLW.cpp)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if(USE_WX)
|
||||
set(SRCS ${SRCS} Src/GLInterface/WX.cpp)
|
||||
else()
|
||||
set(SRCS ${SRCS} Src/GLInterface/AGL.cpp)
|
||||
endif()
|
||||
else()
|
||||
set(SRCS ${SRCS} Src/GLInterface/GLX.cpp
|
||||
Src/GLInterface/X11_Util.cpp)
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -153,6 +173,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/postprocess_bundle.cmake "
|
||||
include(BundleUtilities)
|
||||
message(\"Fixing up application bundle: ${BUNDLE_PATH}\")
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
fixup_bundle(\"${BUNDLE_PATH}\" \"\" \"\")
|
||||
")
|
||||
add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
|
||||
@@ -195,3 +216,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
else()
|
||||
install(TARGETS ${DOLPHIN_EXE} RUNTIME DESTINATION ${bindir})
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${DOLPHIN_EXE})
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
@@ -144,7 +144,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
@@ -158,7 +158,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OpenMPSupport>
|
||||
</OpenMPSupport>
|
||||
</ClCompile>
|
||||
@@ -174,7 +174,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
@@ -188,7 +188,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OpenMPSupport>
|
||||
</OpenMPSupport>
|
||||
</ClCompile>
|
||||
@@ -201,10 +201,12 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
</Command>
|
||||
<Message>Copying Data\* to $(TargetDir)</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
@@ -265,6 +267,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
<ClCompile Include="Src\PHackSettings.cpp" />
|
||||
<ClCompile Include="Src\Debugger\RegisterView.cpp" />
|
||||
<ClCompile Include="Src\Debugger\RegisterWindow.cpp" />
|
||||
<ClCompile Include="Src\GLInterface\WGL.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
|
||||
@@ -326,6 +329,9 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
<ClInclude Include="Src\WiimoteConfigDiag.h" />
|
||||
<ClInclude Include="Src\WXInputBase.h" />
|
||||
<ClInclude Include="Src\WxUtils.h" />
|
||||
<ClInclude Include="Src\GLInterface.h" />
|
||||
<ClInclude Include="Src\GLInterface\InterfaceBase.h" />
|
||||
<ClInclude Include="Src\GLInterface\WGL.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\Installer\Dolphin.ico" />
|
||||
@@ -387,4 +393,4 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
//
|
||||
#include "resource.h"
|
||||
IDI_ICON1 ICON "..\\..\\..\\Installer\\Dolphin.ico"
|
||||
"dolphin" ICON "..\\..\\..\\Installer\\Dolphin.ico"
|
||||
#define wxUSE_NO_MANIFEST 1
|
||||
#include <wx/msw/wx.rc>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ AboutDolphin::AboutDolphin(wxWindow *parent, wxWindowID id,
|
||||
wxBitmap(iDolphinLogo));
|
||||
|
||||
std::string Text = "Dolphin " SCM_DESC_STR "\n"
|
||||
"Copyright (c) 2003-2011+ Dolphin Team\n"
|
||||
"Copyright (c) 2003-2013+ Dolphin Team\n"
|
||||
"\n"
|
||||
"Branch: " SCM_BRANCH_STR "\n"
|
||||
"Revision: " SCM_REV_STR "\n"
|
||||
|
||||
@@ -36,7 +36,7 @@ extern CFrame* main_frame;
|
||||
static wxCheatsWindow *g_cheat_window;
|
||||
|
||||
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, _("Cheats Manager"), wxDefaultPosition, wxDefaultSize)
|
||||
: wxDialog(parent, wxID_ANY, _("Cheats Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxDIALOG_NO_PARENT)
|
||||
{
|
||||
::g_cheat_window = this;
|
||||
|
||||
@@ -57,6 +57,7 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||
}
|
||||
}
|
||||
|
||||
SetSize(wxSize(-1, 600));
|
||||
Center();
|
||||
Show();
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ EVT_SLIDER(ID_VOLUME, CConfigMain::AudioSettingsChanged)
|
||||
|
||||
EVT_CHECKBOX(ID_INTERFACE_CONFIRMSTOP, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_CHECKBOX(ID_INTERFACE_USEPANICHANDLERS, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_CHECKBOX(ID_INTERFACE_ONSCREENDISPLAYMESSAGES, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_RADIOBOX(ID_INTERFACE_THEME, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_CHOICE(ID_INTERFACE_LANG, CConfigMain::DisplaySettingsChanged)
|
||||
EVT_BUTTON(ID_HOTKEY_CONFIG, CConfigMain::DisplaySettingsChanged)
|
||||
@@ -337,6 +338,7 @@ void CConfigMain::InitializeGUIValues()
|
||||
// Display - Interface
|
||||
ConfirmStop->SetValue(startup_params.bConfirmStop);
|
||||
UsePanicHandlers->SetValue(startup_params.bUsePanicHandlers);
|
||||
OnScreenDisplayMessages->SetValue(startup_params.bOnScreenDisplayMessages);
|
||||
Theme->SetSelection(startup_params.iTheme);
|
||||
// need redesign
|
||||
for (unsigned int i = 0; i < sizeof(langIds) / sizeof(wxLanguage); i++)
|
||||
@@ -490,6 +492,7 @@ void CConfigMain::InitializeGUITooltips()
|
||||
// Display - Interface
|
||||
ConfirmStop->SetToolTip(_("Show a confirmation box before stopping a game."));
|
||||
UsePanicHandlers->SetToolTip(_("Show a message box when a potentially serious error has occured.\nDisabling this may avoid annoying and non-fatal messages, but it may also mean that Dolphin suddenly crashes without any explanation at all."));
|
||||
OnScreenDisplayMessages->SetToolTip(_("Show messages on the emulation screen area.\nThese messages include memory card writes, video backend and CPU information, and JIT cache clearing."));
|
||||
|
||||
// Display - Themes: Copyright notice
|
||||
Theme->SetItemToolTip(0, _("Created by Milosz Wlazlo [[email protected], miloszwl.deviantart.com]"));
|
||||
@@ -579,6 +582,8 @@ void CConfigMain::CreateGUIControls()
|
||||
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
UsePanicHandlers = new wxCheckBox(DisplayPage, ID_INTERFACE_USEPANICHANDLERS,
|
||||
_("Use Panic Handlers"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
OnScreenDisplayMessages = new wxCheckBox(DisplayPage, ID_INTERFACE_ONSCREENDISPLAYMESSAGES,
|
||||
_("On-Screen Display Messages"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
|
||||
wxBoxSizer* sInterface = new wxBoxSizer(wxHORIZONTAL);
|
||||
sInterface->Add(TEXT_BOX(DisplayPage, _("Language:")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
@@ -588,6 +593,7 @@ void CConfigMain::CreateGUIControls()
|
||||
sbInterface = new wxStaticBoxSizer(wxVERTICAL, DisplayPage, _("Interface Settings"));
|
||||
sbInterface->Add(ConfirmStop, 0, wxALL, 5);
|
||||
sbInterface->Add(UsePanicHandlers, 0, wxALL, 5);
|
||||
sbInterface->Add(OnScreenDisplayMessages, 0, wxALL, 5);
|
||||
sbInterface->Add(Theme, 0, wxEXPAND | wxALL, 5);
|
||||
sbInterface->Add(sInterface, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
@@ -865,6 +871,10 @@ void CConfigMain::DisplaySettingsChanged(wxCommandEvent& event)
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bUsePanicHandlers = UsePanicHandlers->IsChecked();
|
||||
SetEnableAlert(UsePanicHandlers->IsChecked());
|
||||
break;
|
||||
case ID_INTERFACE_ONSCREENDISPLAYMESSAGES:
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bOnScreenDisplayMessages = OnScreenDisplayMessages->IsChecked();
|
||||
SetEnableAlert(OnScreenDisplayMessages->IsChecked());
|
||||
break;
|
||||
case ID_INTERFACE_THEME:
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme = Theme->GetSelection();
|
||||
main_frame->InitBitmaps();
|
||||
@@ -891,7 +901,8 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event)
|
||||
{
|
||||
case ID_DSPENGINE:
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE = DSPEngine->GetSelection() == 0;
|
||||
ac_Config.m_EnableJIT = DSPEngine->GetSelection() == 1;
|
||||
if (!DSPEngine->GetSelection() == 0)
|
||||
ac_Config.m_EnableJIT = DSPEngine->GetSelection() == 1;
|
||||
ac_Config.Update();
|
||||
break;
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ private:
|
||||
// Interface settings
|
||||
ID_INTERFACE_CONFIRMSTOP,
|
||||
ID_INTERFACE_USEPANICHANDLERS,
|
||||
ID_INTERFACE_ONSCREENDISPLAYMESSAGES,
|
||||
ID_INTERFACE_THEME,
|
||||
ID_INTERFACE_LANG,
|
||||
ID_HOTKEY_CONFIG,
|
||||
@@ -163,6 +164,7 @@ private:
|
||||
// Interface
|
||||
wxCheckBox* ConfirmStop;
|
||||
wxCheckBox* UsePanicHandlers;
|
||||
wxCheckBox* OnScreenDisplayMessages;
|
||||
wxRadioBox* Theme;
|
||||
wxChoice* InterfaceLang;
|
||||
wxButton* HotkeyConfig;
|
||||
|
||||
@@ -319,7 +319,7 @@ void CCodeWindow::UpdateLists()
|
||||
{
|
||||
int idx = callers->Append(wxString::FromAscii(StringFromFormat
|
||||
("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str()));
|
||||
callers->SetClientData(idx, (void*)caller_addr);
|
||||
callers->SetClientData(idx, (void*)(u64)caller_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ void CCodeWindow::UpdateLists()
|
||||
{
|
||||
int idx = calls->Append(wxString::FromAscii(StringFromFormat
|
||||
("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str()));
|
||||
calls->SetClientData(idx, (void*)call_addr);
|
||||
calls->SetClientData(idx, (void*)(u64)call_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
|
||||
if (DSPCore_GetState() == DSPCORE_STEPPING)
|
||||
{
|
||||
DSPCore_Step();
|
||||
Refresh();
|
||||
Update();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -155,10 +155,10 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
|
||||
void Host_RefreshDSPDebuggerWindow()
|
||||
{
|
||||
if (m_DebuggerFrame)
|
||||
m_DebuggerFrame->Refresh();
|
||||
m_DebuggerFrame->Update();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::Refresh()
|
||||
void DSPDebuggerLLE::Update()
|
||||
{
|
||||
#if defined __WXGTK__
|
||||
if (!wxIsMainThread())
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
DSPDebuggerLLE(wxWindow *parent, wxWindowID id = wxID_ANY);
|
||||
virtual ~DSPDebuggerLLE();
|
||||
|
||||
void Refresh();
|
||||
void Update();
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "FifoPlayer/FifoRecorder.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
DECLARE_EVENT_TYPE(RECORDING_FINISHED_EVENT, -1)
|
||||
DEFINE_EVENT_TYPE(RECORDING_FINISHED_EVENT)
|
||||
@@ -323,6 +324,13 @@ void FifoPlayerDlg::CreateGUIControls()
|
||||
m_searchField->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(FifoPlayerDlg::OnBeginSearch), NULL, this);
|
||||
m_searchField->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(FifoPlayerDlg::OnSearchFieldTextChanged), NULL, this);
|
||||
|
||||
// Setup command copying
|
||||
wxAcceleratorEntry entry;
|
||||
entry.Set(wxACCEL_CTRL, (int)'C', wxID_COPY);
|
||||
wxAcceleratorTable accel(1, &entry);
|
||||
m_objectCmdList->SetAcceleratorTable(accel);
|
||||
m_objectCmdList->Connect(wxID_COPY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionCopy), NULL, this);
|
||||
|
||||
Connect(RECORDING_FINISHED_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnRecordingFinished), NULL, this);
|
||||
Connect(FRAME_WRITTEN_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnFrameWritten), NULL, this);
|
||||
|
||||
@@ -616,7 +624,6 @@ void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event)
|
||||
int cmd = *objectdata++;
|
||||
int stream_size = Common::swap16(objectdata);
|
||||
objectdata += 2;
|
||||
int vertex_size = (objectdata_end - objectdata) / stream_size;
|
||||
wxString newLabel = wxString::Format(wxT("%08X: %02X %04X "), obj_offset, cmd, stream_size);
|
||||
if ((objectdata_end - objectdata) % stream_size) newLabel += _("NOTE: Stream size doesn't match actual data length\n");
|
||||
while (objectdata < objectdata_end)
|
||||
@@ -763,6 +770,15 @@ void FifoPlayerDlg::OnObjectCmdListSelectionChanged(wxCommandEvent& event)
|
||||
Fit();
|
||||
}
|
||||
|
||||
void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
wxTheClipboard->SetData(new wxTextDataObject(m_objectCmdList->GetStringSelection()));
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
Hide();
|
||||
|
||||
@@ -57,6 +57,7 @@ private:
|
||||
void OnFrameListSelectionChanged(wxCommandEvent& event);
|
||||
void OnObjectListSelectionChanged(wxCommandEvent& event);
|
||||
void OnObjectCmdListSelectionChanged(wxCommandEvent& event);
|
||||
void OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event));
|
||||
|
||||
void UpdatePlayGui();
|
||||
void UpdateRecorderGui();
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "Common.h" // Common
|
||||
#include "FileUtil.h"
|
||||
#include "Timer.h"
|
||||
#include "Setup.h"
|
||||
|
||||
#include "Globals.h" // Local
|
||||
#include "Frame.h"
|
||||
@@ -72,30 +71,7 @@ extern "C" {
|
||||
};
|
||||
|
||||
|
||||
// Windows functions. Setting the cursor with wxSetCursor() did not work in
|
||||
// this instance. Probably because it's somehow reset from the WndProc() in
|
||||
// the child window
|
||||
#ifdef _WIN32
|
||||
// Declare a blank icon and one that will be the normal cursor
|
||||
HCURSOR hCursor = NULL, hCursorBlank = NULL;
|
||||
|
||||
// Create the default cursor
|
||||
void CreateCursor()
|
||||
{
|
||||
hCursor = LoadCursor( NULL, IDC_ARROW );
|
||||
}
|
||||
|
||||
void MSWSetCursor(bool Show)
|
||||
{
|
||||
if(Show)
|
||||
SetCursor(hCursor);
|
||||
else
|
||||
{
|
||||
SetCursor(hCursorBlank);
|
||||
//wxSetCursor(wxCursor(wxNullCursor));
|
||||
}
|
||||
}
|
||||
|
||||
// I could not use FindItemByHWND() instead of this, it crashed on that occation I used it */
|
||||
HWND MSWGetParent_(HWND Parent)
|
||||
{
|
||||
@@ -134,10 +110,11 @@ CPanel::CPanel(
|
||||
|
||||
case WM_USER_SETCURSOR:
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor &&
|
||||
main_frame->RendererHasFocus() && Core::GetState() == Core::CORE_RUN)
|
||||
MSWSetCursor(!SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor);
|
||||
main_frame->RendererHasFocus() && Core::GetState() == Core::CORE_RUN &&
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
|
||||
SetCursor(wxCURSOR_BLANK);
|
||||
else
|
||||
MSWSetCursor(true);
|
||||
SetCursor(wxNullCursor);
|
||||
break;
|
||||
|
||||
case WIIMOTE_DISCONNECT:
|
||||
@@ -244,6 +221,8 @@ EVT_MENU(IDM_PLAYRECORD, CFrame::OnPlayRecording)
|
||||
EVT_MENU(IDM_RECORDEXPORT, CFrame::OnRecordExport)
|
||||
EVT_MENU(IDM_RECORDREADONLY, CFrame::OnRecordReadOnly)
|
||||
EVT_MENU(IDM_TASINPUT, CFrame::OnTASInput)
|
||||
EVT_MENU(IDM_TOGGLE_PAUSEMOVIE, CFrame::OnTogglePauseMovie)
|
||||
EVT_MENU(IDM_SHOWLAG, CFrame::OnShowLag)
|
||||
EVT_MENU(IDM_FRAMESTEP, CFrame::OnFrameStep)
|
||||
EVT_MENU(IDM_SCREENSHOT, CFrame::OnScreenshot)
|
||||
EVT_MENU(wxID_PREFERENCES, CFrame::OnConfigMain)
|
||||
@@ -434,9 +413,7 @@ CFrame::CFrame(wxFrame* parent,
|
||||
// Commit
|
||||
m_Mgr->Update();
|
||||
|
||||
// Create cursors
|
||||
#ifdef _WIN32
|
||||
CreateCursor();
|
||||
SetToolTip(wxT(""));
|
||||
GetToolTip()->SetAutoPop(25000);
|
||||
#endif
|
||||
@@ -456,13 +433,6 @@ CFrame::CFrame(wxFrame* parent,
|
||||
|
||||
// Update controls
|
||||
UpdateGUI();
|
||||
|
||||
// If we are rerecording create the status bar now instead of later when a game starts
|
||||
#ifdef RERECORDING
|
||||
ModifyStatusBar();
|
||||
// It's to early for the OnHostMessage(), we will update the status when Ctrl or Space is pressed
|
||||
//Core::WriteStatus();
|
||||
#endif
|
||||
}
|
||||
// Destructor
|
||||
CFrame::~CFrame()
|
||||
@@ -500,20 +470,6 @@ void CFrame::OnActive(wxActivateEvent& event)
|
||||
{
|
||||
if (event.GetActive() && event.GetEventObject() == m_RenderFrame)
|
||||
{
|
||||
// 32x32, 8bpp b/w image
|
||||
// We want all transparent, so we can just use the same buffer for
|
||||
// the "image" as for the transparency mask
|
||||
static const char cursor_data[32 * 32] = { 0 };
|
||||
|
||||
#ifdef __WXGTK__
|
||||
wxCursor cursor_transparent = wxCursor(cursor_data, 32, 32, 6, 14,
|
||||
cursor_data, wxWHITE, wxBLACK);
|
||||
#else
|
||||
wxBitmap cursor_bitmap(cursor_data, 32, 32);
|
||||
cursor_bitmap.SetMask(new wxMask(cursor_bitmap));
|
||||
wxCursor cursor_transparent = wxCursor(cursor_bitmap.ConvertToImage());
|
||||
#endif
|
||||
|
||||
#ifdef __WXMSW__
|
||||
::SetFocus((HWND)m_RenderParent->GetHandle());
|
||||
#else
|
||||
@@ -522,7 +478,7 @@ void CFrame::OnActive(wxActivateEvent& event)
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor &&
|
||||
Core::GetState() == Core::CORE_RUN)
|
||||
m_RenderParent->SetCursor(cursor_transparent);
|
||||
m_RenderParent->SetCursor(wxCURSOR_BLANK);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -652,12 +608,12 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef __WXGTK__
|
||||
case WM_USER_CREATE:
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
|
||||
m_RenderParent->SetCursor(wxCURSOR_BLANK);
|
||||
break;
|
||||
|
||||
#ifdef __WXGTK__
|
||||
case IDM_PANIC:
|
||||
{
|
||||
wxString caption = event.GetString().BeforeFirst(':');
|
||||
|
||||
@@ -297,6 +297,8 @@ private:
|
||||
void OnRecordExport(wxCommandEvent& event);
|
||||
void OnRecordReadOnly(wxCommandEvent& event);
|
||||
void OnTASInput(wxCommandEvent& event);
|
||||
void OnTogglePauseMovie(wxCommandEvent& event);
|
||||
void OnShowLag(wxCommandEvent& event);
|
||||
void OnChangeDisc(wxCommandEvent& event);
|
||||
void OnScreenshot(wxCommandEvent& event);
|
||||
void OnActive(wxActivateEvent& event);
|
||||
|
||||
@@ -27,9 +27,6 @@ window handle that is returned by CreateWindow() can be accessed from
|
||||
Core::GetWindowHandle().
|
||||
*/
|
||||
|
||||
|
||||
#include "Setup.h" // Common
|
||||
|
||||
#include "NetWindow.h"
|
||||
#include "Common.h" // Common
|
||||
#include "FileUtil.h"
|
||||
@@ -142,9 +139,13 @@ void CFrame::CreateMenu()
|
||||
emulationMenu->Append(IDM_RECORDEXPORT, GetMenuLabel(HK_EXPORT_RECORDING));
|
||||
emulationMenu->Append(IDM_RECORDREADONLY, GetMenuLabel(HK_READ_ONLY_MODE), wxEmptyString, wxITEM_CHECK);
|
||||
emulationMenu->Append(IDM_TASINPUT, _("TAS Input"));
|
||||
emulationMenu->AppendCheckItem(IDM_TOGGLE_PAUSEMOVIE, _("Pause at end of movie"));
|
||||
emulationMenu->Check(IDM_TOGGLE_PAUSEMOVIE, SConfig::GetInstance().m_PauseMovie);
|
||||
emulationMenu->AppendCheckItem(IDM_SHOWLAG, _("Show lag counter"));
|
||||
emulationMenu->Check(IDM_SHOWLAG, SConfig::GetInstance().m_ShowLag);
|
||||
emulationMenu->Check(IDM_RECORDREADONLY, true);
|
||||
emulationMenu->AppendSeparator();
|
||||
|
||||
|
||||
emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString);
|
||||
|
||||
wxMenu *skippingMenu = new wxMenu;
|
||||
@@ -162,7 +163,7 @@ void CFrame::CreateMenu()
|
||||
emulationMenu->Append(IDM_SAVESTATE, _("Sa&ve State"), saveMenu);
|
||||
|
||||
saveMenu->Append(IDM_SAVESTATEFILE, _("Save State..."));
|
||||
loadMenu->Append(IDM_UNDOSAVESTATE, _("Last Overwritten State") + wxString(wxT("\tShift+F12")));
|
||||
loadMenu->Append(IDM_UNDOSAVESTATE, _("Last Overwritten State") + wxString(wxT("\tF12")));
|
||||
saveMenu->AppendSeparator();
|
||||
|
||||
loadMenu->Append(IDM_LOADSTATEFILE, _("Load State..."));
|
||||
@@ -173,7 +174,7 @@ void CFrame::CreateMenu()
|
||||
else
|
||||
loadMenu->Append(IDM_LOADLASTSTATE, _("Last Saved State") + wxString(wxT("\tF11")));
|
||||
|
||||
loadMenu->Append(IDM_UNDOLOADSTATE, _("Undo Load State") + wxString(wxT("\tF12")));
|
||||
loadMenu->Append(IDM_UNDOLOADSTATE, _("Undo Load State") + wxString(wxT("\tShift+F12")));
|
||||
loadMenu->AppendSeparator();
|
||||
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
@@ -702,6 +703,18 @@ void CFrame::OnTASInput(wxCommandEvent& event)
|
||||
g_TASInputDlg->Show(true);
|
||||
}
|
||||
|
||||
void CFrame::OnTogglePauseMovie(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
SConfig::GetInstance().m_PauseMovie = !SConfig::GetInstance().m_PauseMovie;
|
||||
SConfig::GetInstance().SaveSettings();
|
||||
}
|
||||
|
||||
void CFrame::OnShowLag(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
SConfig::GetInstance().m_ShowLag = !SConfig::GetInstance().m_ShowLag;
|
||||
SConfig::GetInstance().SaveSettings();
|
||||
}
|
||||
|
||||
void CFrame::OnFrameStep(wxCommandEvent& event)
|
||||
{
|
||||
bool wasPaused = (Core::GetState() == Core::CORE_PAUSE);
|
||||
@@ -732,7 +745,7 @@ void CFrame::OnRecord(wxCommandEvent& WXUNUSED (event))
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER)
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA)
|
||||
controllers |= (1 << i);
|
||||
|
||||
if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE)
|
||||
@@ -1042,27 +1055,14 @@ void CFrame::DoPause()
|
||||
{
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
|
||||
m_RenderParent->SetCursor(wxCURSOR_ARROW);
|
||||
m_RenderParent->SetCursor(wxNullCursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 32x32, 8bpp b/w image
|
||||
// We want all transparent, so we can just use the same buffer for
|
||||
// the "image" as for the transparency mask
|
||||
static const char cursor_data[32 * 32] = { 0 };
|
||||
#ifdef __WXGTK__
|
||||
wxCursor cursor_transparent = wxCursor(cursor_data, 32, 32, 6, 14,
|
||||
cursor_data, wxWHITE, wxBLACK);
|
||||
#else
|
||||
wxBitmap cursor_bitmap(cursor_data, 32, 32);
|
||||
cursor_bitmap.SetMask(new wxMask(cursor_bitmap));
|
||||
wxCursor cursor_transparent = wxCursor(cursor_bitmap.ConvertToImage());
|
||||
#endif
|
||||
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor &&
|
||||
RendererHasFocus())
|
||||
m_RenderParent->SetCursor(cursor_transparent);
|
||||
m_RenderParent->SetCursor(wxCURSOR_BLANK);
|
||||
}
|
||||
UpdateGUI();
|
||||
}
|
||||
@@ -1138,10 +1138,13 @@ void CFrame::DoStop()
|
||||
wxMouseEventHandler(CFrame::OnMouse),
|
||||
(wxObject*)0, this);
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
|
||||
m_RenderParent->SetCursor(wxCURSOR_ARROW);
|
||||
m_RenderParent->SetCursor(wxNullCursor);
|
||||
DoFullscreen(false);
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain)
|
||||
m_RenderFrame->Destroy();
|
||||
else
|
||||
// Make sure the window is not longer set to stay on top
|
||||
m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
|
||||
m_RenderParent = NULL;
|
||||
|
||||
// Clean framerate indications from the status bar.
|
||||
@@ -1289,7 +1292,7 @@ void CFrame::OnHelp(wxCommandEvent& event)
|
||||
}
|
||||
break;
|
||||
case IDM_HELPWEBSITE:
|
||||
WxUtils::Launch("http://www.dolphin-emulator.com/");
|
||||
WxUtils::Launch("http://dolphin-emu.org/");
|
||||
break;
|
||||
case IDM_HELPGOOGLECODE:
|
||||
WxUtils::Launch("http://code.google.com/p/dolphin-emu/");
|
||||
@@ -1307,9 +1310,8 @@ void CFrame::StatusBarMessage(const char * Text, ...)
|
||||
const int MAX_BYTES = 1024*10;
|
||||
char Str[MAX_BYTES];
|
||||
va_list ArgPtr;
|
||||
int Cnt;
|
||||
va_start(ArgPtr, Text);
|
||||
Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
|
||||
vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
|
||||
va_end(ArgPtr);
|
||||
|
||||
if (this->GetStatusBar()->IsEnabled()) this->GetStatusBar()->SetStatusText(wxString::FromAscii(Str),0);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _GLINTERFACE_H_
|
||||
#define _GLINTERFACE_H_
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
#include "GLInterface/EGL.h"
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
#include "GLInterface/WX.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include "GLInterface/AGL.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "GLInterface/WGL.h"
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#include "GLInterface/GLX.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
#if defined(USE_EGL) && USE_EGL // This is currently a X11/EGL implementation for desktop
|
||||
int screen;
|
||||
Display *dpy;
|
||||
Display *evdpy;
|
||||
Window win;
|
||||
Window parent;
|
||||
EGLSurface egl_surf;
|
||||
EGLContext egl_ctx;
|
||||
EGLDisplay egl_dpy;
|
||||
XVisualInfo *vi;
|
||||
XSetWindowAttributes attr;
|
||||
std::thread xEventThread;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
wxGLCanvas *glCanvas;
|
||||
wxGLContext *glCtxt;
|
||||
wxPanel *panel;
|
||||
#elif defined(__APPLE__)
|
||||
NSWindow *cocoaWin;
|
||||
NSOpenGLContext *cocoaCtx;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
int screen;
|
||||
Window win;
|
||||
Window parent;
|
||||
// dpy used for glx stuff, evdpy for window events etc.
|
||||
// evdpy is to be used by XEventThread only
|
||||
Display *dpy, *evdpy;
|
||||
XVisualInfo *vi;
|
||||
GLXContext ctx;
|
||||
XSetWindowAttributes attr;
|
||||
std::thread xEventThread;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
#endif
|
||||
} GLWindow;
|
||||
|
||||
extern cInterfaceBase *GLInterface;
|
||||
extern GLWindow GLWin;
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user