mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 20:28:56 +00:00
Merge branch 'immediate-removal' into GLSL-master
Conflicts: Source/Core/VideoCommon/Src/PixelShaderGen.cpp Source/Plugins/Plugin_VideoSoftware/Src/SWRenderer.cpp immediate-removal is a new created branch seperated from master but reverted the revert of immediate-removal so we get less conflicts by merging
This commit is contained in:
commit
e0ffdda26e
338 changed files with 40275 additions and 44293 deletions
|
@ -109,78 +109,89 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouchD.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win32;..\..\..\Externals\SoundTouch\Win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouchD.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win64;..\..\..\Externals\SoundTouch\Win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouch.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win32;..\..\..\Externals\SoundTouch\Win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouch.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win32;..\..\..\Externals\SoundTouch\Win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouch.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win64;..\..\..\Externals\SoundTouch\Win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\Core\Src;..\Common\Src;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<AdditionalDependencies>SoundTouch.lib;OpenAL32.lib;dsound.lib;dxerr.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\OpenAL\Win64;..\..\..\Externals\SoundTouch\Win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\aldlist.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\aldlist.cpp" />
|
||||
<ClCompile Include="Src\AOSoundStream.cpp" />
|
||||
<ClCompile Include="Src\AudioCommon.cpp" />
|
||||
<ClCompile Include="Src\AudioCommonConfig.cpp" />
|
||||
<ClCompile Include="Src\DPL2Decoder.cpp" />
|
||||
<ClCompile Include="Src\DSoundStream.cpp" />
|
||||
<ClCompile Include="Src\Mixer.cpp" />
|
||||
<ClCompile Include="Src\NullSoundStream.cpp" />
|
||||
|
@ -189,17 +200,10 @@
|
|||
<ClCompile Include="Src\XAudio2Stream.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\aldlist.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\aldlist.h" />
|
||||
<ClInclude Include="Src\AOSoundStream.h" />
|
||||
<ClInclude Include="Src\AudioCommon.h" />
|
||||
<ClInclude Include="Src\AudioCommonConfig.h" />
|
||||
<ClInclude Include="Src\DPL2Decoder.h" />
|
||||
<ClInclude Include="Src\DSoundStream.h" />
|
||||
<ClInclude Include="Src\Mixer.h" />
|
||||
<ClInclude Include="Src\NullSoundStream.h" />
|
||||
|
@ -212,6 +216,14 @@
|
|||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Externals\SoundTouch\SoundTouch.vcxproj">
|
||||
<Project>{68a5dd20-7057-448b-8fe0-b6ac8d205509}</Project>
|
||||
<Private>true</Private>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||
<Project>{c87a4178-44f6-49b2-b7aa-c79af1b8c534}</Project>
|
||||
<Private>true</Private>
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="Src\aldlist.cpp" />
|
||||
<ClCompile Include="Src\AudioCommon.cpp" />
|
||||
<ClCompile Include="Src\AudioCommonConfig.cpp" />
|
||||
<ClCompile Include="Src\Mixer.cpp" />
|
||||
<ClCompile Include="Src\WaveFile.cpp" />
|
||||
<ClCompile Include="Src\AOSoundStream.cpp">
|
||||
|
@ -21,11 +20,11 @@
|
|||
<ClCompile Include="Src\NullSoundStream.cpp">
|
||||
<Filter>SoundStreams</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\DPL2Decoder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\aldlist.h" />
|
||||
<ClInclude Include="Src\AudioCommon.h" />
|
||||
<ClInclude Include="Src\AudioCommonConfig.h" />
|
||||
<ClInclude Include="Src\Mixer.h" />
|
||||
<ClInclude Include="Src\SoundStream.h" />
|
||||
<ClInclude Include="Src\WaveFile.h" />
|
||||
|
@ -44,6 +43,7 @@
|
|||
<ClInclude Include="Src\XAudio2Stream.h">
|
||||
<Filter>SoundStreams</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\DPL2Decoder.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(SRCS Src/AudioCommon.cpp
|
||||
Src/AudioCommonConfig.cpp
|
||||
Src/DPL2Decoder.cpp
|
||||
Src/Mixer.cpp
|
||||
Src/WaveFile.cpp
|
||||
Src/NullSoundStream.cpp)
|
||||
|
@ -18,7 +18,7 @@ endif(AO_FOUND)
|
|||
|
||||
if(OPENAL_FOUND)
|
||||
set(SRCS ${SRCS} Src/OpenALStream.cpp Src/aldlist.cpp)
|
||||
set(LIBS ${LIBS} ${OPENAL_LIBRARY})
|
||||
set(LIBS ${LIBS} ${OPENAL_LIBRARY} SoundTouch )
|
||||
endif(OPENAL_FOUND)
|
||||
|
||||
if(PULSEAUDIO_FOUND)
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "OpenALStream.h"
|
||||
#include "PulseAudioStream.h"
|
||||
#include "../../Core/Src/Movie.h"
|
||||
#include "../../Core/Src/ConfigManager.h"
|
||||
|
||||
// This shouldn't be a global, at least not here.
|
||||
SoundStream *soundStream;
|
||||
|
||||
namespace AudioCommon
|
||||
{
|
||||
|
@ -34,7 +38,7 @@ namespace AudioCommon
|
|||
{
|
||||
// TODO: possible memleak with mixer
|
||||
|
||||
std::string backend = ac_Config.sBackend;
|
||||
std::string backend = SConfig::GetInstance().sBackend;
|
||||
if (backend == BACKEND_OPENAL && OpenALStream::isValid())
|
||||
soundStream = new OpenALStream(mixer);
|
||||
else if (backend == BACKEND_NULLSOUND && NullSound::isValid())
|
||||
|
@ -54,10 +58,10 @@ namespace AudioCommon
|
|||
|
||||
if (soundStream != NULL)
|
||||
{
|
||||
ac_Config.Update();
|
||||
UpdateSoundStream();
|
||||
if (soundStream->Start())
|
||||
{
|
||||
if (ac_Config.m_DumpAudio)
|
||||
if (SConfig::GetInstance().m_DumpAudio)
|
||||
{
|
||||
std::string audio_file_name = File::GetUserPath(D_DUMPAUDIO_IDX) + "audiodump.wav";
|
||||
File::CreateFullPath(audio_file_name);
|
||||
|
@ -82,7 +86,7 @@ namespace AudioCommon
|
|||
if (soundStream)
|
||||
{
|
||||
soundStream->Stop();
|
||||
if (ac_Config.m_DumpAudio)
|
||||
if (SConfig::GetInstance().m_DumpAudio)
|
||||
soundStream->GetMixer()->StopLogAudio();
|
||||
//soundStream->StopLogAudio();
|
||||
delete soundStream;
|
||||
|
@ -96,22 +100,22 @@ namespace AudioCommon
|
|||
{
|
||||
std::vector<std::string> backends;
|
||||
|
||||
if (NullSound::isValid())
|
||||
if (NullSound::isValid())
|
||||
backends.push_back(BACKEND_NULLSOUND);
|
||||
if (DSound::isValid())
|
||||
if (DSound::isValid())
|
||||
backends.push_back(BACKEND_DIRECTSOUND);
|
||||
if (XAudio2::isValid())
|
||||
if (XAudio2::isValid())
|
||||
backends.push_back(BACKEND_XAUDIO2);
|
||||
if (AOSound::isValid())
|
||||
backends.push_back(BACKEND_AOSOUND);
|
||||
if (AlsaSound::isValid())
|
||||
backends.push_back(BACKEND_ALSA);
|
||||
if (CoreAudioSound::isValid())
|
||||
backends.push_back(BACKEND_COREAUDIO);
|
||||
if (PulseAudio::isValid())
|
||||
backends.push_back(BACKEND_PULSEAUDIO);
|
||||
if (OpenALStream::isValid())
|
||||
backends.push_back(BACKEND_OPENAL);
|
||||
if (AOSound::isValid())
|
||||
backends.push_back(BACKEND_AOSOUND);
|
||||
if (AlsaSound::isValid())
|
||||
backends.push_back(BACKEND_ALSA);
|
||||
if (CoreAudioSound::isValid())
|
||||
backends.push_back(BACKEND_COREAUDIO);
|
||||
if (PulseAudio::isValid())
|
||||
backends.push_back(BACKEND_PULSEAUDIO);
|
||||
|
||||
return backends;
|
||||
}
|
||||
|
@ -122,7 +126,7 @@ namespace AudioCommon
|
|||
{
|
||||
return true;
|
||||
}
|
||||
return ac_Config.m_EnableJIT;
|
||||
return SConfig::GetInstance().m_EnableJIT;
|
||||
}
|
||||
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
||||
|
@ -143,4 +147,12 @@ namespace AudioCommon
|
|||
}
|
||||
}
|
||||
}
|
||||
void UpdateSoundStream()
|
||||
{
|
||||
if (soundStream)
|
||||
{
|
||||
soundStream->GetMixer()->SetThrottle(SConfig::GetInstance().m_Framelimit == 2);
|
||||
soundStream->SetVolume(SConfig::GetInstance().m_Volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,12 @@
|
|||
#define _AUDIO_COMMON_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "AudioCommonConfig.h"
|
||||
#include "SoundStream.h"
|
||||
|
||||
|
||||
class CMixer;
|
||||
|
||||
extern SoundStream *soundStream;
|
||||
extern AudioCommonConfig ac_Config;
|
||||
|
||||
// UDSPControl
|
||||
union UDSPControl
|
||||
|
@ -60,6 +58,7 @@ namespace AudioCommon
|
|||
std::vector<std::string> GetSoundBackends();
|
||||
bool UseJIT();
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
|
||||
void UpdateSoundStream();
|
||||
}
|
||||
|
||||
#endif // _AUDIO_COMMON_H_
|
||||
|
|
|
@ -1,70 +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 "AudioCommon.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "FileUtil.h"
|
||||
#include "../../Core/Src/ConfigManager.h"
|
||||
|
||||
AudioCommonConfig ac_Config;
|
||||
|
||||
// This shouldn't be a global, at least not here.
|
||||
SoundStream *soundStream;
|
||||
|
||||
// Load from given file
|
||||
void AudioCommonConfig::Load()
|
||||
{
|
||||
IniFile file;
|
||||
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
|
||||
|
||||
file.Get("Config", "EnableJIT", &m_EnableJIT, true);
|
||||
file.Get("Config", "DumpAudio", &m_DumpAudio, false);
|
||||
#if defined __linux__ && HAVE_ALSA
|
||||
file.Get("Config", "Backend", &sBackend, BACKEND_ALSA);
|
||||
#elif defined __APPLE__
|
||||
file.Get("Config", "Backend", &sBackend, BACKEND_COREAUDIO);
|
||||
#elif defined _WIN32
|
||||
file.Get("Config", "Backend", &sBackend, BACKEND_DIRECTSOUND);
|
||||
#else
|
||||
file.Get("Config", "Backend", &sBackend, BACKEND_NULLSOUND);
|
||||
#endif
|
||||
file.Get("Config", "Frequency", &iFrequency, 48000);
|
||||
file.Get("Config", "Volume", &m_Volume, 100);
|
||||
}
|
||||
|
||||
// Set the values for the file
|
||||
void AudioCommonConfig::SaveSettings()
|
||||
{
|
||||
IniFile file;
|
||||
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
|
||||
|
||||
file.Set("Config", "EnableJIT", m_EnableJIT);
|
||||
file.Set("Config", "DumpAudio", m_DumpAudio);
|
||||
file.Set("Config", "Backend", sBackend);
|
||||
file.Set("Config", "Frequency", iFrequency);
|
||||
file.Set("Config", "Volume", m_Volume);
|
||||
|
||||
file.Save(File::GetUserPath(F_DSPCONFIG_IDX));
|
||||
}
|
||||
|
||||
// Update according to the values (stream/mixer)
|
||||
void AudioCommonConfig::Update() {
|
||||
if (soundStream) {
|
||||
soundStream->GetMixer()->SetThrottle(SConfig::GetInstance().m_Framelimit == 2);
|
||||
soundStream->SetVolume(m_Volume);
|
||||
}
|
||||
}
|
|
@ -1,52 +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 _AUDIO_COMMON_CONFIG_H_
|
||||
#define _AUDIO_COMMON_CONFIG_H_
|
||||
|
||||
#include <string>
|
||||
#include "IniFile.h"
|
||||
|
||||
// Backend Types
|
||||
#define BACKEND_NULLSOUND "No audio output"
|
||||
#define BACKEND_ALSA "ALSA"
|
||||
#define BACKEND_AOSOUND "AOSound"
|
||||
#define BACKEND_COREAUDIO "CoreAudio"
|
||||
#define BACKEND_DIRECTSOUND "DSound"
|
||||
#define BACKEND_OPENAL "OpenAL"
|
||||
#define BACKEND_PULSEAUDIO "Pulse"
|
||||
#define BACKEND_XAUDIO2 "XAudio2"
|
||||
|
||||
struct AudioCommonConfig
|
||||
{
|
||||
bool m_EnableJIT;
|
||||
bool m_DumpAudio;
|
||||
int m_Volume;
|
||||
std::string sBackend;
|
||||
int iFrequency;
|
||||
|
||||
// Load from given file
|
||||
void Load();
|
||||
|
||||
// Self explanatory
|
||||
void SaveSettings();
|
||||
|
||||
// Update according to the values (stream/mixer)
|
||||
void Update();
|
||||
};
|
||||
|
||||
#endif //AUDIO_COMMON_CONFIG
|
400
Source/Core/AudioCommon/Src/DPL2Decoder.cpp
Normal file
400
Source/Core/AudioCommon/Src/DPL2Decoder.cpp
Normal file
|
@ -0,0 +1,400 @@
|
|||
// 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/
|
||||
|
||||
// Dolby Pro Logic 2 decoder from ffdshow-tryout
|
||||
// * Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
|
||||
// * Copyright (c) 2004-2006 Milan Cutka
|
||||
// * based on mplayer HRTF plugin by ylai
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "DPL2Decoder.h"
|
||||
|
||||
#define M_PI 3.14159265358979323846
|
||||
#define M_SQRT1_2 0.70710678118654752440
|
||||
|
||||
int olddelay = -1;
|
||||
unsigned int oldfreq = 0;
|
||||
unsigned int dlbuflen;
|
||||
int cyc_pos;
|
||||
float l_fwr, r_fwr, lpr_fwr, lmr_fwr;
|
||||
std::vector<float> fwrbuf_l, fwrbuf_r;
|
||||
float adapt_l_gain, adapt_r_gain, adapt_lpr_gain, adapt_lmr_gain;
|
||||
std::vector<float> lf, rf, lr, rr, cf, cr;
|
||||
float LFE_buf[256];
|
||||
unsigned int lfe_pos;
|
||||
float *filter_coefs_lfe;
|
||||
unsigned int len125;
|
||||
|
||||
template<class T,class _ftype_t> static _ftype_t dotproduct(int count,const T *buf,const _ftype_t *coefficients)
|
||||
{
|
||||
float sum0=0,sum1=0,sum2=0,sum3=0;
|
||||
for (;count>=4;buf+=4,coefficients+=4,count-=4)
|
||||
{
|
||||
sum0+=buf[0]*coefficients[0];
|
||||
sum1+=buf[1]*coefficients[1];
|
||||
sum2+=buf[2]*coefficients[2];
|
||||
sum3+=buf[3]*coefficients[3];
|
||||
}
|
||||
while (count--) sum0+= *buf++ * *coefficients++;
|
||||
return sum0+sum1+sum2+sum3;
|
||||
}
|
||||
|
||||
template<class T> static T firfilter(const T *buf, int pos, int len, int count, const float *coefficients)
|
||||
{
|
||||
int count1, count2;
|
||||
|
||||
if (pos >= count)
|
||||
{
|
||||
pos -= count;
|
||||
count1 = count; count2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
count2 = pos;
|
||||
count1 = count - pos;
|
||||
pos = len - count1;
|
||||
}
|
||||
|
||||
// high part of window
|
||||
const T *ptr = &buf[pos];
|
||||
|
||||
float r1=dotproduct(count1,ptr,coefficients);coefficients+=count1;
|
||||
float r2=dotproduct(count2,buf,coefficients);
|
||||
return T(r1+r2);
|
||||
}
|
||||
|
||||
template<class T> inline const T& limit(const T& val, const T& min, const T& max)
|
||||
{
|
||||
if (val < min) {
|
||||
return min;
|
||||
} else if (val > max) {
|
||||
return max;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Hamming
|
||||
// 2*pi*k
|
||||
// w(k) = 0.54 - 0.46*cos(------), where 0 <= k < N
|
||||
// N-1
|
||||
//
|
||||
// n window length
|
||||
// w buffer for the window parameters
|
||||
*/
|
||||
void hamming(int n, float* w)
|
||||
{
|
||||
int i;
|
||||
float k = float(2*M_PI/((float)(n-1))); // 2*pi/(N-1)
|
||||
|
||||
// Calculate window coefficients
|
||||
for (i=0; i<n; i++)
|
||||
*w++ = float(0.54 - 0.46*cos(k*(float)i));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FIR filter design
|
||||
******************************************************************************/
|
||||
|
||||
/* Design FIR filter using the Window method
|
||||
|
||||
n filter length must be odd for HP and BS filters
|
||||
w buffer for the filter taps (must be n long)
|
||||
fc cutoff frequencies (1 for LP and HP, 2 for BP and BS)
|
||||
0 < fc < 1 where 1 <=> Fs/2
|
||||
flags window and filter type as defined in filter.h
|
||||
variables are ored together: i.e. LP|HAMMING will give a
|
||||
low pass filter designed using a hamming window
|
||||
opt beta constant used only when designing using kaiser windows
|
||||
|
||||
returns 0 if OK, -1 if fail
|
||||
*/
|
||||
float* design_fir(unsigned int *n, float* fc, float opt)
|
||||
{
|
||||
unsigned int o = *n & 1; // Indicator for odd filter length
|
||||
unsigned int end = ((*n + 1) >> 1) - o; // Loop end
|
||||
unsigned int i; // Loop index
|
||||
|
||||
float k1 = 2 * float(M_PI); // 2*pi*fc1
|
||||
float k2 = 0.5f * (float)(1 - o);// Constant used if the filter has even length
|
||||
float g = 0.0f; // Gain
|
||||
float t1; // Temporary variables
|
||||
float fc1; // Cutoff frequencies
|
||||
|
||||
// Sanity check
|
||||
if(*n==0) return NULL;
|
||||
fc[0]=limit(fc[0],float(0.001),float(1));
|
||||
|
||||
float *w=(float*)calloc(sizeof(float),*n);
|
||||
|
||||
// Get window coefficients
|
||||
hamming(*n,w);
|
||||
|
||||
fc1=*fc;
|
||||
// Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2
|
||||
fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25f;
|
||||
k1 *= fc1;
|
||||
|
||||
// Low pass filter
|
||||
|
||||
// If the filter length is odd, there is one point which is exactly
|
||||
// in the middle. The value at this point is 2*fCutoff*sin(x)/x,
|
||||
// where x is zero. To make sure nothing strange happens, we set this
|
||||
// value separately.
|
||||
if (o)
|
||||
{
|
||||
w[end] = fc1 * w[end] * 2.0f;
|
||||
g=w[end];
|
||||
}
|
||||
|
||||
// Create filter
|
||||
for (i=0 ; i<end ; i++)
|
||||
{
|
||||
t1 = (float)(i+1) - k2;
|
||||
w[end-i-1] = w[*n-end+i] = float(w[end-i-1] * sin(k1 * t1)/(M_PI * t1)); // Sinc
|
||||
g += 2*w[end-i-1]; // Total gain in filter
|
||||
}
|
||||
|
||||
|
||||
// Normalize gain
|
||||
g=1/g;
|
||||
for (i=0; i<*n; i++)
|
||||
w[i] *= g;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void onSeek(void)
|
||||
{
|
||||
l_fwr = r_fwr = lpr_fwr = lmr_fwr = 0;
|
||||
std::fill(fwrbuf_l.begin(), fwrbuf_l.end(), 0.0f);
|
||||
std::fill(fwrbuf_r.begin(), fwrbuf_r.end(), 0.0f);
|
||||
adapt_l_gain = adapt_r_gain = adapt_lpr_gain = adapt_lmr_gain = 0;
|
||||
std::fill(lf.begin(), lf.end(), 0.0f);
|
||||
std::fill(rf.begin(), rf.end(), 0.0f);
|
||||
std::fill(lr.begin(), lr.end(), 0.0f);
|
||||
std::fill(rr.begin(), rr.end(), 0.0f);
|
||||
std::fill(cf.begin(), cf.end(), 0.0f);
|
||||
std::fill(cr.begin(), cr.end(), 0.0f);
|
||||
lfe_pos = 0;
|
||||
memset(LFE_buf, 0, sizeof(LFE_buf));
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
onSeek();
|
||||
if (filter_coefs_lfe)
|
||||
{
|
||||
free(filter_coefs_lfe);
|
||||
}
|
||||
filter_coefs_lfe = NULL;
|
||||
}
|
||||
|
||||
float* calc_coefficients_125Hz_lowpass(int rate)
|
||||
{
|
||||
len125 = 256;
|
||||
float f = 125.0f / (rate / 2);
|
||||
float *coeffs = design_fir(&len125, &f, 0);
|
||||
static const float M3_01DB = 0.7071067812f;
|
||||
for (unsigned int i = 0; i < len125; i++)
|
||||
{
|
||||
coeffs[i] *= M3_01DB;
|
||||
}
|
||||
return coeffs;
|
||||
}
|
||||
|
||||
float passive_lock(float x)
|
||||
{
|
||||
static const float MATAGCLOCK = 0.2f; /* AGC range (around 1) where the matrix behaves passively */
|
||||
const float x1 = x - 1;
|
||||
const float ax1s = fabs(x - 1) * (1.0f / MATAGCLOCK);
|
||||
return x1 - x1 / (1 + ax1s * ax1s) + 1;
|
||||
}
|
||||
|
||||
void matrix_decode(const float *in, const int k, const int il,
|
||||
const int ir, bool decode_rear,
|
||||
const int dlbuflen,
|
||||
float l_fwr, float r_fwr,
|
||||
float lpr_fwr, float lmr_fwr,
|
||||
float *adapt_l_gain, float *adapt_r_gain,
|
||||
float *adapt_lpr_gain, float *adapt_lmr_gain,
|
||||
float *lf, float *rf, float *lr,
|
||||
float *rr, float *cf)
|
||||
{
|
||||
static const float M9_03DB = 0.3535533906f;
|
||||
static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */
|
||||
static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */
|
||||
static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */
|
||||
|
||||
const int kr = (k + olddelay) % dlbuflen;
|
||||
float l_gain = (l_fwr + r_fwr) / (1 + l_fwr + l_fwr);
|
||||
float r_gain = (l_fwr + r_fwr) / (1 + r_fwr + r_fwr);
|
||||
/* The 2nd axis has strong gain fluctuations, and therefore require
|
||||
limits. The factor corresponds to the 1 / amplification of (Lt
|
||||
- Rt) when (Lt, Rt) is strongly correlated. (e.g. during
|
||||
dialogues). It should be bigger than -12 dB to prevent
|
||||
distortion. */
|
||||
float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ? lmr_fwr : M9_03DB * lpr_fwr;
|
||||
float lpr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lpr_fwr + lpr_fwr);
|
||||
float lmr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
|
||||
float lmr_unlim_gain = (lpr_fwr + lmr_fwr) / (1 + lmr_fwr + lmr_fwr);
|
||||
float lpr, lmr;
|
||||
float l_agc, r_agc, lpr_agc, lmr_agc;
|
||||
float f, d_gain, c_gain, c_agc_cfk;
|
||||
|
||||
/*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
|
||||
/* AGC adaption */
|
||||
d_gain = (fabs(l_gain - *adapt_l_gain) + fabs(r_gain - *adapt_r_gain)) * 0.5f;
|
||||
f = d_gain * (1.0f / MATAGCTRIG);
|
||||
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
|
||||
*adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
|
||||
*adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
|
||||
/* Matrix */
|
||||
l_agc = in[il] * passive_lock(*adapt_l_gain);
|
||||
r_agc = in[ir] * passive_lock(*adapt_r_gain);
|
||||
cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
|
||||
if (decode_rear)
|
||||
{
|
||||
lr[kr] = rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
|
||||
/* Stereo rear channel is steered with the same AGC steering as
|
||||
the decoding matrix. Note this requires a fast updating AGC
|
||||
at the order of 20 ms (which is the case here). */
|
||||
lr[kr] *= (l_fwr + l_fwr) / (1 + l_fwr + r_fwr);
|
||||
rr[kr] *= (r_fwr + r_fwr) / (1 + l_fwr + r_fwr);
|
||||
}
|
||||
|
||||
/*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
|
||||
lpr = (in[il] + in[ir]) * (float)M_SQRT1_2;
|
||||
lmr = (in[il] - in[ir]) * (float)M_SQRT1_2;
|
||||
/* AGC adaption */
|
||||
d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
|
||||
f = d_gain * (1.0f / MATAGCTRIG);
|
||||
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
|
||||
*adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
|
||||
*adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
|
||||
/* Matrix */
|
||||
lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
|
||||
lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
|
||||
lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
|
||||
rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
|
||||
|
||||
/*** CENTER FRONT CANCELLATION ***/
|
||||
/* A heuristic approach exploits that Lt + Rt gain contains the
|
||||
information about Lt, Rt correlation. This effectively reshapes
|
||||
the front and rear "cones" to concentrate Lt + Rt to C and
|
||||
introduce Lt - Rt in L, R. */
|
||||
/* 0.67677 is the empirical lower bound for lpr_gain. */
|
||||
c_gain = 8 * (*adapt_lpr_gain - 0.67677f);
|
||||
c_gain = c_gain > 0 ? c_gain : 0;
|
||||
/* c_gain should not be too high, not even reaching full
|
||||
cancellation (~ 0.50 - 0.55 at current AGC implementation), or
|
||||
the center will sound too narrow. */
|
||||
c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
|
||||
c_agc_cfk = c_gain * cf[k];
|
||||
lf[k] -= c_agc_cfk;
|
||||
rf[k] -= c_agc_cfk;
|
||||
cf[k] += c_agc_cfk + c_agc_cfk;
|
||||
}
|
||||
|
||||
void dpl2decode(float *samples, int numsamples, float *out)
|
||||
{
|
||||
static const unsigned int FWRDURATION = 240; /* FWR average duration (samples) */
|
||||
static const int cfg_delay = 0;
|
||||
static const unsigned int fmt_freq = 48000;
|
||||
static const unsigned int fmt_nchannels = 2; // input channels
|
||||
|
||||
int cur = 0;
|
||||
|
||||
if (olddelay != cfg_delay || oldfreq != fmt_freq)
|
||||
{
|
||||
done();
|
||||
olddelay = cfg_delay;
|
||||
oldfreq = fmt_freq;
|
||||
dlbuflen = std::max(FWRDURATION, (fmt_freq * cfg_delay / 1000)); //+(len7000-1);
|
||||
cyc_pos = dlbuflen - 1;
|
||||
fwrbuf_l.resize(dlbuflen);
|
||||
fwrbuf_r.resize(dlbuflen);
|
||||
lf.resize(dlbuflen);
|
||||
rf.resize(dlbuflen);
|
||||
lr.resize(dlbuflen);
|
||||
rr.resize(dlbuflen);
|
||||
cf.resize(dlbuflen);
|
||||
cr.resize(dlbuflen);
|
||||
filter_coefs_lfe = calc_coefficients_125Hz_lowpass(fmt_freq);
|
||||
lfe_pos = 0;
|
||||
memset(LFE_buf, 0, sizeof(LFE_buf));
|
||||
}
|
||||
|
||||
float *in = samples; // Input audio data
|
||||
float *end = in + numsamples * fmt_nchannels; // Loop end
|
||||
|
||||
while (in < end)
|
||||
{
|
||||
const int k = cyc_pos;
|
||||
|
||||
const int fwr_pos = (k + FWRDURATION) % dlbuflen;
|
||||
/* Update the full wave rectified total amplitude */
|
||||
/* Input matrix decoder */
|
||||
l_fwr += fabs(in[0]) - fabs(fwrbuf_l[fwr_pos]);
|
||||
r_fwr += fabs(in[1]) - fabs(fwrbuf_r[fwr_pos]);
|
||||
lpr_fwr += fabs(in[0] + in[1]) - fabs(fwrbuf_l[fwr_pos] + fwrbuf_r[fwr_pos]);
|
||||
lmr_fwr += fabs(in[0] - in[1]) - fabs(fwrbuf_l[fwr_pos] - fwrbuf_r[fwr_pos]);
|
||||
|
||||
/* Matrix encoded 2 channel sources */
|
||||
fwrbuf_l[k] = in[0];
|
||||
fwrbuf_r[k] = in[1];
|
||||
matrix_decode(in, k, 0, 1, true, dlbuflen,
|
||||
l_fwr, r_fwr,
|
||||
lpr_fwr, lmr_fwr,
|
||||
&adapt_l_gain, &adapt_r_gain,
|
||||
&adapt_lpr_gain, &adapt_lmr_gain,
|
||||
&lf[0], &rf[0], &lr[0], &rr[0], &cf[0]);
|
||||
|
||||
out[cur + 0] = lf[k];
|
||||
out[cur + 1] = rf[k];
|
||||
out[cur + 2] = cf[k];
|
||||
LFE_buf[lfe_pos] = (out[0] + out[1]) / 2;
|
||||
out[cur + 3] = firfilter(LFE_buf, lfe_pos, len125, len125, filter_coefs_lfe);
|
||||
lfe_pos++;
|
||||
if (lfe_pos == len125)
|
||||
{
|
||||
lfe_pos = 0;
|
||||
}
|
||||
out[cur + 4] = lr[k];
|
||||
out[cur + 5] = rr[k];
|
||||
// Next sample...
|
||||
in += 2;
|
||||
cur += 6;
|
||||
cyc_pos--;
|
||||
if (cyc_pos < 0)
|
||||
{
|
||||
cyc_pos += dlbuflen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dpl2reset()
|
||||
{
|
||||
olddelay = -1;
|
||||
oldfreq = 0;
|
||||
filter_coefs_lfe = NULL;
|
||||
}
|
24
Source/Core/AudioCommon/Src/DPL2Decoder.h
Normal file
24
Source/Core/AudioCommon/Src/DPL2Decoder.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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 _DPL2DECODER_H_
|
||||
#define _DPL2DECODER_H_
|
||||
|
||||
void dpl2decode(float *samples, int numsamples, float *out);
|
||||
void dpl2reset();
|
||||
|
||||
#endif // _DPL2DECODER_H_
|
|
@ -92,6 +92,9 @@ public:
|
|||
|
||||
std::mutex& MixerCritical() { return m_csMixing; }
|
||||
|
||||
volatile float GetCurrentSpeed() const { return m_speed; }
|
||||
void UpdateSpeed(volatile float val) { m_speed = val; }
|
||||
|
||||
protected:
|
||||
unsigned int m_sampleRate;
|
||||
unsigned int m_aiSampleRate;
|
||||
|
@ -113,6 +116,8 @@ protected:
|
|||
|
||||
bool m_AIplaying;
|
||||
std::mutex m_csMixing;
|
||||
|
||||
volatile float m_speed; // Current rate of the emulation (1.0 = 100% speed)
|
||||
private:
|
||||
|
||||
};
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "aldlist.h"
|
||||
#include "OpenALStream.h"
|
||||
#include "DPL2Decoder.h"
|
||||
|
||||
#if defined HAVE_OPENAL && HAVE_OPENAL
|
||||
|
||||
soundtouch::SoundTouch soundTouch;
|
||||
|
||||
//
|
||||
// AyuanX: Spec says OpenAL1.1 is thread safe already
|
||||
//
|
||||
|
@ -35,14 +36,21 @@ bool OpenALStream::Start()
|
|||
pDeviceList = new ALDeviceList();
|
||||
if ((pDeviceList) && (pDeviceList->GetNumDevices()))
|
||||
{
|
||||
char *defDevName = pDeviceList-> \
|
||||
GetDeviceName(pDeviceList->GetDefaultDevice());
|
||||
char *defDevName = pDeviceList->GetDeviceName(pDeviceList->GetDefaultDevice());
|
||||
|
||||
WARN_LOG(AUDIO, "Found OpenAL device %s", defDevName);
|
||||
|
||||
pDevice = alcOpenDevice(defDevName);
|
||||
if (pDevice)
|
||||
{
|
||||
pContext = alcCreateContext(pDevice, NULL);
|
||||
if (pContext)
|
||||
{
|
||||
// Used to determine an appropriate period size (2x period = total buffer size)
|
||||
//ALCint refresh;
|
||||
//alcGetIntegerv(pDevice, ALC_REFRESH, 1, &refresh);
|
||||
//period_size_in_millisec = 1000 / refresh;
|
||||
|
||||
alcMakeContextCurrent(pContext);
|
||||
thread = std::thread(std::mem_fun(&OpenALStream::SoundLoop), this);
|
||||
bReturn = true;
|
||||
|
@ -50,8 +58,7 @@ bool OpenALStream::Start()
|
|||
else
|
||||
{
|
||||
alcCloseDevice(pDevice);
|
||||
PanicAlertT("OpenAL: can't create context "
|
||||
"for device %s", defDevName);
|
||||
PanicAlertT("OpenAL: can't create context for device %s", defDevName);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -65,6 +72,10 @@ bool OpenALStream::Start()
|
|||
PanicAlertT("OpenAL: can't find sound devices");
|
||||
}
|
||||
|
||||
// Initialise DPL2 parameters
|
||||
dpl2reset();
|
||||
|
||||
soundTouch.clear();
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
|
@ -74,6 +85,8 @@ void OpenALStream::Stop()
|
|||
// kick the thread if it's waiting
|
||||
soundSyncEvent.Set();
|
||||
|
||||
soundTouch.clear();
|
||||
|
||||
thread.join();
|
||||
|
||||
alSourceStop(uiSource);
|
||||
|
@ -82,7 +95,7 @@ void OpenALStream::Stop()
|
|||
// Clean up buffers and sources
|
||||
alDeleteSources(1, &uiSource);
|
||||
uiSource = 0;
|
||||
alDeleteBuffers(OAL_NUM_BUFFERS, uiBuffers);
|
||||
alDeleteBuffers(numBuffers, uiBuffers);
|
||||
|
||||
ALCcontext *pContext = alcGetCurrentContext();
|
||||
ALCdevice *pDevice = alcGetContextsDevice(pContext);
|
||||
|
@ -111,6 +124,7 @@ void OpenALStream::Clear(bool mute)
|
|||
|
||||
if(m_muted)
|
||||
{
|
||||
soundTouch.clear();
|
||||
alSourceStop(uiSource);
|
||||
}
|
||||
else
|
||||
|
@ -124,20 +138,29 @@ void OpenALStream::SoundLoop()
|
|||
Common::SetCurrentThreadName("Audio thread - openal");
|
||||
|
||||
u32 ulFrequency = m_mixer->GetSampleRate();
|
||||
numBuffers = Core::g_CoreStartupParameter.iLatency + 2; // OpenAL requires a minimum of two buffers
|
||||
|
||||
memset(uiBuffers, 0, OAL_NUM_BUFFERS * sizeof(ALuint));
|
||||
memset(uiBuffers, 0, numBuffers * sizeof(ALuint));
|
||||
uiSource = 0;
|
||||
|
||||
// Generate some AL Buffers for streaming
|
||||
alGenBuffers(OAL_NUM_BUFFERS, (ALuint *)uiBuffers);
|
||||
alGenBuffers(numBuffers, (ALuint *)uiBuffers);
|
||||
// Generate a Source to playback the Buffers
|
||||
alGenSources(1, &uiSource);
|
||||
|
||||
// Short Silence
|
||||
memset(sampleBuffer, 0, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * numBuffers);
|
||||
memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4);
|
||||
for (int i = 0; i < OAL_NUM_BUFFERS; i++)
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES, ulFrequency);
|
||||
alSourceQueueBuffers(uiSource, OAL_NUM_BUFFERS, uiBuffers);
|
||||
for (int i = 0; i < numBuffers; i++)
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
if (Core::g_CoreStartupParameter.bDPL2Decoder)
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, 4 * SIZE_FLOAT * SURROUND_CHANNELS, ulFrequency);
|
||||
else
|
||||
#endif
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, 4 * 2 * 2, ulFrequency);
|
||||
}
|
||||
alSourceQueueBuffers(uiSource, numBuffers, uiBuffers);
|
||||
alSourcePlay(uiSource);
|
||||
|
||||
// Set the default sound volume as saved in the config file.
|
||||
|
@ -148,41 +171,175 @@ void OpenALStream::SoundLoop()
|
|||
|
||||
ALint iBuffersFilled = 0;
|
||||
ALint iBuffersProcessed = 0;
|
||||
ALuint uiBufferTemp[OAL_NUM_BUFFERS] = {0};
|
||||
ALint iState = 0;
|
||||
ALuint uiBufferTemp[OAL_MAX_BUFFERS] = {0};
|
||||
|
||||
soundTouch.setChannels(2);
|
||||
soundTouch.setSampleRate(ulFrequency);
|
||||
soundTouch.setTempo(1.0);
|
||||
soundTouch.setSetting(SETTING_USE_QUICKSEEK, 0);
|
||||
soundTouch.setSetting(SETTING_USE_AA_FILTER, 0);
|
||||
soundTouch.setSetting(SETTING_SEQUENCE_MS, 1);
|
||||
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28);
|
||||
soundTouch.setSetting(SETTING_OVERLAP_MS, 12);
|
||||
|
||||
bool surround_capable = Core::g_CoreStartupParameter.bDPL2Decoder;
|
||||
#if defined(__APPLE__)
|
||||
bool float32_capable = false;
|
||||
#else
|
||||
bool float32_capable = true;
|
||||
#endif
|
||||
|
||||
while (!threadData)
|
||||
{
|
||||
// num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD.
|
||||
const u32 stereo_16_bit_size = 4;
|
||||
const u32 dma_length = 32;
|
||||
const u64 ais_samples_per_second = 48000 * stereo_16_bit_size;
|
||||
u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length);
|
||||
u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond();
|
||||
|
||||
unsigned int numSamples = (unsigned int)num_samples_to_render;
|
||||
|
||||
numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
|
||||
numSamples = m_mixer->Mix(realtimeBuffer, numSamples);
|
||||
|
||||
// Convert the samples from short to float
|
||||
float dest[OAL_MAX_SAMPLES * 2 * 2 * OAL_MAX_BUFFERS];
|
||||
for (u32 i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i * 2 + 0] = (float)realtimeBuffer[i * 2 + 0] / (1 << 16);
|
||||
dest[i * 2 + 1] = (float)realtimeBuffer[i * 2 + 1] / (1 << 16);
|
||||
}
|
||||
|
||||
soundTouch.putSamples(dest, numSamples);
|
||||
|
||||
if (iBuffersProcessed == iBuffersFilled)
|
||||
{
|
||||
alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed);
|
||||
iBuffersFilled = 0;
|
||||
}
|
||||
|
||||
unsigned int numSamples = m_mixer->GetNumSamples();
|
||||
|
||||
if (iBuffersProcessed && (numSamples >= OAL_THRESHOLD))
|
||||
if (iBuffersProcessed)
|
||||
{
|
||||
numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
|
||||
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
|
||||
if (iBuffersFilled == 0)
|
||||
alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
|
||||
float rate = m_mixer->GetCurrentSpeed();
|
||||
if (rate <= 0)
|
||||
{
|
||||
Core::RequestRefreshInfo();
|
||||
rate = m_mixer->GetCurrentSpeed();
|
||||
}
|
||||
|
||||
m_mixer->Mix(realtimeBuffer, numSamples);
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, realtimeBuffer, numSamples * 4, ulFrequency);
|
||||
alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
|
||||
iBuffersFilled++;
|
||||
// Place a lower limit of 10% speed. When a game boots up, there will be
|
||||
// many silence samples. These do not need to be timestretched.
|
||||
if (rate > 0.10)
|
||||
{
|
||||
// Adjust SETTING_SEQUENCE_MS to balance between lag vs hollow audio
|
||||
soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)(1 / (rate * rate)));
|
||||
soundTouch.setTempo(rate);
|
||||
}
|
||||
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS);
|
||||
if (nSamples > 0)
|
||||
{
|
||||
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
|
||||
if (iBuffersFilled == 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err);
|
||||
}
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
// OSX does not have the alext AL_FORMAT_51CHN32 yet.
|
||||
surround_capable = false;
|
||||
#else
|
||||
if (surround_capable)
|
||||
{
|
||||
float dpl2[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS];
|
||||
dpl2decode(sampleBuffer, nSamples, dpl2);
|
||||
|
||||
if (iBuffersFilled == OAL_NUM_BUFFERS)
|
||||
alSourcePlay(uiSource);
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, nSamples * SIZE_FLOAT * SURROUND_CHANNELS, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
// 5.1 is not supported by the host, fallback to stereo
|
||||
WARN_LOG(AUDIO, "Unable to set 5.1 surround mode. Updating OpenAL Soft might fix this issue.");
|
||||
surround_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!surround_capable)
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
if (float32_capable)
|
||||
{
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, nSamples * 4 * 2, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
float32_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
if (!float32_capable)
|
||||
{
|
||||
// Convert the samples from float to short
|
||||
short stereo[OAL_MAX_SAMPLES * 2 * 2 * OAL_MAX_BUFFERS];
|
||||
for (u32 i = 0; i < nSamples; ++i)
|
||||
{
|
||||
stereo[i * 2 + 0] = (short)((float)sampleBuffer[i * 2 + 0] * (1 << 16));
|
||||
stereo[i * 2 + 1] = (short)((float)sampleBuffer[i * 2 + 1] * (1 << 16));
|
||||
}
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, nSamples * 2 * 2, ulFrequency);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err);
|
||||
}
|
||||
iBuffersFilled++;
|
||||
|
||||
if (iBuffersFilled == numBuffers)
|
||||
{
|
||||
alSourcePlay(uiSource);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
alGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
|
||||
if (iState != AL_PLAYING)
|
||||
{
|
||||
// Buffer underrun occurred, resume playback
|
||||
alSourcePlay(uiSource);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (numSamples >= OAL_THRESHOLD)
|
||||
else
|
||||
{
|
||||
ALint state = 0;
|
||||
alGetSourcei(uiSource, AL_SOURCE_STATE, &state);
|
||||
if (state == AL_STOPPED)
|
||||
alSourcePlay(uiSource);
|
||||
soundSyncEvent.Wait();
|
||||
}
|
||||
soundSyncEvent.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,21 +24,30 @@
|
|||
|
||||
#if defined HAVE_OPENAL && HAVE_OPENAL
|
||||
#ifdef _WIN32
|
||||
#include "../../../../Externals/OpenAL/include/al.h"
|
||||
#include "../../../../Externals/OpenAL/include/alc.h"
|
||||
#include <OpenAL/include/al.h>
|
||||
#include <OpenAL/include/alc.h>
|
||||
#include <OpenAL/include/alext.h>
|
||||
#elif defined __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <AL/alext.h>
|
||||
#endif
|
||||
|
||||
#include "Core.h"
|
||||
#include "HW/SystemTimers.h"
|
||||
#include "HW/AudioInterface.h"
|
||||
#include <soundtouch/SoundTouch.h>
|
||||
#include <soundtouch/STTypes.h>
|
||||
|
||||
// 16 bit Stereo
|
||||
#define SFX_MAX_SOURCE 1
|
||||
#define OAL_NUM_BUFFERS 16
|
||||
#define OAL_MAX_SAMPLES 512 // AyuanX: Don't make it too large, as larger buffer means longer delay
|
||||
#define OAL_THRESHOLD 128 // Some games are quite sensitive to delay
|
||||
#define OAL_MAX_BUFFERS 32
|
||||
#define OAL_MAX_SAMPLES 256
|
||||
#define SURROUND_CHANNELS 6 // number of channels in surround mode
|
||||
#define SIZE_FLOAT 4 // size of a float in bytes
|
||||
#endif
|
||||
|
||||
class OpenALStream: public SoundStream
|
||||
|
@ -64,11 +73,14 @@ public:
|
|||
private:
|
||||
std::thread thread;
|
||||
Common::Event soundSyncEvent;
|
||||
|
||||
|
||||
short realtimeBuffer[OAL_MAX_SAMPLES * 2];
|
||||
ALuint uiBuffers[OAL_NUM_BUFFERS];
|
||||
soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS];
|
||||
ALuint uiBuffers[OAL_MAX_BUFFERS];
|
||||
ALuint uiSource;
|
||||
ALfloat fVolume;
|
||||
|
||||
u8 numBuffers;
|
||||
#else
|
||||
public:
|
||||
OpenALStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}
|
||||
|
|
|
@ -22,31 +22,31 @@
|
|||
|
||||
#include "PulseAudioStream.h"
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
#define BUFFER_SIZE_BYTES (BUFFER_SIZE * 4)
|
||||
namespace
|
||||
{
|
||||
const size_t BUFFER_SAMPLES = 512;
|
||||
const size_t CHANNEL_COUNT = 2;
|
||||
const size_t BUFFER_SIZE = BUFFER_SAMPLES * CHANNEL_COUNT;
|
||||
}
|
||||
|
||||
PulseAudio::PulseAudio(CMixer *mixer)
|
||||
: SoundStream(mixer), thread_running(false), mainloop(NULL)
|
||||
, context(NULL), stream(NULL), iVolume(100)
|
||||
{
|
||||
mix_buffer = new u8[BUFFER_SIZE_BYTES];
|
||||
}
|
||||
|
||||
PulseAudio::~PulseAudio()
|
||||
{
|
||||
delete [] mix_buffer;
|
||||
}
|
||||
: SoundStream(mixer)
|
||||
, mix_buffer(BUFFER_SIZE)
|
||||
, thread()
|
||||
, run_thread()
|
||||
, pa()
|
||||
{}
|
||||
|
||||
bool PulseAudio::Start()
|
||||
{
|
||||
thread_running = true;
|
||||
run_thread = true;
|
||||
thread = std::thread(std::mem_fun(&PulseAudio::SoundLoop), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseAudio::Stop()
|
||||
{
|
||||
thread_running = false;
|
||||
run_thread = false;
|
||||
thread.join();
|
||||
}
|
||||
|
||||
|
@ -60,260 +60,53 @@ void PulseAudio::SoundLoop()
|
|||
{
|
||||
Common::SetCurrentThreadName("Audio thread - pulse");
|
||||
|
||||
thread_running = PulseInit();
|
||||
|
||||
while (thread_running)
|
||||
if (PulseInit())
|
||||
{
|
||||
int frames_to_deliver = 512;
|
||||
m_mixer->Mix((short *)mix_buffer, frames_to_deliver);
|
||||
if (!Write(mix_buffer, frames_to_deliver * 4))
|
||||
ERROR_LOG(AUDIO, "PulseAudio failure writing data");
|
||||
while (run_thread)
|
||||
{
|
||||
m_mixer->Mix(&mix_buffer[0], mix_buffer.size() / CHANNEL_COUNT);
|
||||
Write(&mix_buffer[0], mix_buffer.size() * sizeof(s16));
|
||||
}
|
||||
|
||||
PulseShutdown();
|
||||
}
|
||||
PulseShutdown();
|
||||
}
|
||||
|
||||
bool PulseAudio::PulseInit()
|
||||
{
|
||||
// The Sample format to use
|
||||
const pa_sample_spec ss =
|
||||
pa_sample_spec ss = {};
|
||||
ss.format = PA_SAMPLE_S16LE;
|
||||
ss.channels = 2;
|
||||
ss.rate = m_mixer->GetSampleRate();
|
||||
|
||||
int error;
|
||||
pa = pa_simple_new(nullptr, "dolphin-emu", PA_STREAM_PLAYBACK,
|
||||
nullptr, "audio", &ss, nullptr, nullptr, &error);
|
||||
|
||||
if (!pa)
|
||||
{
|
||||
PA_SAMPLE_S16LE,
|
||||
m_mixer->GetSampleRate(),
|
||||
2
|
||||
};
|
||||
|
||||
mainloop = pa_threaded_mainloop_new();
|
||||
|
||||
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "dolphin-emu");
|
||||
pa_context_set_state_callback(context, ContextStateCB, this);
|
||||
|
||||
if (pa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio failed to connect context: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s",
|
||||
pa_strerror(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
pa_threaded_mainloop_start(mainloop);
|
||||
|
||||
for (;;)
|
||||
else
|
||||
{
|
||||
pa_context_state_t state;
|
||||
|
||||
state = pa_context_get_state(context);
|
||||
|
||||
if (state == PA_CONTEXT_READY)
|
||||
break;
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD(state))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio context state failure: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait until the context is ready
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
NOTICE_LOG(AUDIO, "Pulse successfully initialized.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(stream = pa_stream_new(context, "emulator", &ss, NULL)))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio failed to create playback stream: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set callbacks for the playback stream
|
||||
pa_stream_set_state_callback(stream, StreamStateCB, this);
|
||||
pa_stream_set_write_callback(stream, StreamWriteCB, this);
|
||||
|
||||
if (pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_NOFLAGS, NULL, NULL) < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio failed to connect playback stream: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
|
||||
state = pa_stream_get_state(stream);
|
||||
|
||||
if (state == PA_STREAM_READY)
|
||||
break;
|
||||
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio stream state failure: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait until the stream is ready
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
|
||||
SetVolume(iVolume);
|
||||
|
||||
NOTICE_LOG(AUDIO, "Pulse successfully initialized.");
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseAudio::PulseShutdown()
|
||||
{
|
||||
if (mainloop)
|
||||
pa_threaded_mainloop_stop(mainloop);
|
||||
|
||||
if (stream)
|
||||
pa_stream_unref(stream);
|
||||
|
||||
if (context)
|
||||
{
|
||||
pa_context_disconnect(context);
|
||||
pa_context_unref(context);
|
||||
}
|
||||
|
||||
if (mainloop)
|
||||
pa_threaded_mainloop_free(mainloop);
|
||||
pa_simple_free(pa);
|
||||
}
|
||||
|
||||
void PulseAudio::SignalMainLoop()
|
||||
void PulseAudio::Write(const void *data, size_t length)
|
||||
{
|
||||
pa_threaded_mainloop_signal(mainloop, 0);
|
||||
}
|
||||
|
||||
void PulseAudio::ContextStateCB(pa_context *c, void *userdata)
|
||||
{
|
||||
switch (pa_context_get_state(c))
|
||||
int error;
|
||||
if (pa_simple_write(pa, data, length, &error) < 0)
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
((PulseAudio *)userdata)->SignalMainLoop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
ERROR_LOG(AUDIO, "PulseAudio failed to write data: %s",
|
||||
pa_strerror(error));
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudio::StreamStateCB(pa_stream *s, void * userdata)
|
||||
{
|
||||
switch (pa_stream_get_state(s))
|
||||
{
|
||||
case PA_STREAM_READY:
|
||||
case PA_STREAM_TERMINATED:
|
||||
case PA_STREAM_FAILED:
|
||||
((PulseAudio *)userdata)->SignalMainLoop();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudio::StreamWriteCB(pa_stream *s, size_t length, void *userdata)
|
||||
{
|
||||
((PulseAudio *)userdata)->SignalMainLoop();
|
||||
}
|
||||
|
||||
static bool StateIsGood(pa_context *context, pa_stream *stream)
|
||||
{
|
||||
if (!context || !PA_CONTEXT_IS_GOOD(pa_context_get_state(context)) ||
|
||||
!stream || !PA_STREAM_IS_GOOD(pa_stream_get_state(stream)))
|
||||
{
|
||||
if ((context && pa_context_get_state(context) == PA_CONTEXT_FAILED) ||
|
||||
(stream && pa_stream_get_state(stream) == PA_STREAM_FAILED))
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio state failure: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio state failure: %s",
|
||||
pa_strerror(PA_ERR_BADSTATE));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PulseAudio::Write(const void *data, size_t length)
|
||||
{
|
||||
if (!data || length == 0 || !stream)
|
||||
return false;
|
||||
|
||||
pa_threaded_mainloop_lock(mainloop);
|
||||
|
||||
if (!StateIsGood(context, stream))
|
||||
{
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
while (!(l = pa_stream_writable_size(stream)))
|
||||
{
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
if (!StateIsGood(context, stream))
|
||||
{
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (l == (size_t)-1)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio invalid stream: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (l > length)
|
||||
l = length;
|
||||
|
||||
r = pa_stream_write(stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
if (r < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "PulseAudio error writing to stream: %s",
|
||||
pa_strerror(pa_context_errno(context)));
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return false;
|
||||
}
|
||||
|
||||
data = (const uint8_t*) data + l;
|
||||
length -= l;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(mainloop);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PulseAudio::SetVolume(int volume)
|
||||
{
|
||||
iVolume = volume;
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
pa_cvolume cvolume;
|
||||
const pa_channel_map *channels = pa_stream_get_channel_map(stream);
|
||||
pa_cvolume_set(&cvolume, channels->channels,
|
||||
iVolume * (PA_VOLUME_NORM - PA_VOLUME_MUTED) / 100);
|
||||
|
||||
pa_context_set_sink_input_volume(context, pa_stream_get_index(stream),
|
||||
&cvolume, NULL, this);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#define _PULSE_AUDIO_STREAM_H
|
||||
|
||||
#if defined(HAVE_PULSEAUDIO) && HAVE_PULSEAUDIO
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
@ -27,16 +28,16 @@
|
|||
|
||||
#include "Thread.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class PulseAudio : public SoundStream
|
||||
{
|
||||
#if defined(HAVE_PULSEAUDIO) && HAVE_PULSEAUDIO
|
||||
public:
|
||||
PulseAudio(CMixer *mixer);
|
||||
virtual ~PulseAudio();
|
||||
|
||||
virtual bool Start();
|
||||
virtual void Stop();
|
||||
virtual void SetVolume(int volume);
|
||||
|
||||
static bool isValid() {return true;}
|
||||
|
||||
|
@ -46,22 +47,16 @@ public:
|
|||
|
||||
private:
|
||||
virtual void SoundLoop();
|
||||
|
||||
bool PulseInit();
|
||||
void PulseShutdown();
|
||||
bool Write(const void *data, size_t bytes);
|
||||
void SignalMainLoop();
|
||||
static void ContextStateCB(pa_context *c, void *userdata);
|
||||
static void StreamStateCB(pa_stream *s, void * userdata);
|
||||
static void StreamWriteCB(pa_stream *s, size_t length, void *userdata);
|
||||
void Write(const void *data, size_t bytes);
|
||||
|
||||
u8 *mix_buffer;
|
||||
std::vector<s16> mix_buffer;
|
||||
std::thread thread;
|
||||
volatile bool thread_running;
|
||||
volatile bool run_thread;
|
||||
|
||||
pa_threaded_mainloop *mainloop;
|
||||
pa_context *context;
|
||||
pa_stream *stream;
|
||||
int iVolume;
|
||||
pa_simple* pa;
|
||||
#else
|
||||
public:
|
||||
PulseAudio(CMixer *mixer) : SoundStream(mixer) {}
|
||||
|
|
|
@ -100,39 +100,52 @@ void WaveFileWriter::Write4(const char *ptr)
|
|||
file.WriteBytes(ptr, 4);
|
||||
}
|
||||
|
||||
void WaveFileWriter::AddStereoSamples(const short *sample_data, int count)
|
||||
void WaveFileWriter::AddStereoSamples(const short *sample_data, u32 count)
|
||||
{
|
||||
if (!file)
|
||||
PanicAlertT("WaveFileWriter - file not open.");
|
||||
if (skip_silence) {
|
||||
|
||||
if (skip_silence)
|
||||
{
|
||||
bool all_zero = true;
|
||||
for (int i = 0; i < count * 2; i++)
|
||||
if (sample_data[i]) all_zero = false;
|
||||
if (all_zero) return;
|
||||
|
||||
for (u32 i = 0; i < count * 2; i++)
|
||||
{
|
||||
if (sample_data[i])
|
||||
all_zero = false;
|
||||
}
|
||||
|
||||
if (all_zero)
|
||||
return;
|
||||
}
|
||||
|
||||
file.WriteBytes(sample_data, count * 4);
|
||||
audio_size += count * 4;
|
||||
}
|
||||
|
||||
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, int count)
|
||||
void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, u32 count)
|
||||
{
|
||||
if (!file)
|
||||
PanicAlertT("WaveFileWriter - file not open.");
|
||||
|
||||
if (count > BUF_SIZE * 2)
|
||||
PanicAlert("WaveFileWriter - buffer too small (count = %i).", count);
|
||||
PanicAlert("WaveFileWriter - buffer too small (count = %u).", count);
|
||||
|
||||
if (skip_silence)
|
||||
{
|
||||
bool all_zero = true;
|
||||
for (int i = 0; i < count * 2; i++)
|
||||
|
||||
for (u32 i = 0; i < count * 2; i++)
|
||||
{
|
||||
if (sample_data[i])
|
||||
all_zero = false;
|
||||
}
|
||||
|
||||
if (all_zero)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count * 2; i++)
|
||||
for (u32 i = 0; i < count * 2; i++)
|
||||
conv_buffer[i] = Common::swap16((u16)sample_data[i]);
|
||||
|
||||
file.WriteBytes(conv_buffer, count * 4);
|
||||
|
|
|
@ -50,8 +50,8 @@ public:
|
|||
|
||||
void SetSkipSilence(bool skip) { skip_silence = skip; }
|
||||
|
||||
void AddStereoSamples(const short *sample_data, int count);
|
||||
void AddStereoSamplesBE(const short *sample_data, int count); // big endian
|
||||
void AddStereoSamples(const short *sample_data, u32 count);
|
||||
void AddStereoSamplesBE(const short *sample_data, u32 count); // big endian
|
||||
u32 GetAudioSize() { return audio_size; }
|
||||
};
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ ALDeviceList::ALDeviceList()
|
|||
const char *actualDeviceName = NULL;
|
||||
|
||||
// DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
|
||||
vDeviceInfo.empty();
|
||||
vDeviceInfo.clear();
|
||||
vDeviceInfo.reserve(10);
|
||||
|
||||
defaultDeviceIndex = 0;
|
||||
|
@ -146,12 +146,12 @@ ALDeviceList::~ALDeviceList()
|
|||
{
|
||||
for (u32 i = 0; i < vDeviceInfo.size(); i++) {
|
||||
if (vDeviceInfo[i].pvstrExtensions) {
|
||||
vDeviceInfo[i].pvstrExtensions->empty();
|
||||
vDeviceInfo[i].pvstrExtensions->clear();
|
||||
delete vDeviceInfo[i].pvstrExtensions;
|
||||
}
|
||||
}
|
||||
|
||||
vDeviceInfo.empty();
|
||||
vDeviceInfo.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include "DebugInterface.h"
|
||||
#include "BreakPoints.h"
|
||||
#include "../../Core/Src/PowerPC/JitCommon/JitBase.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
bool BreakPoints::IsAddressBreakPoint(u32 _iAddress)
|
||||
{
|
||||
|
@ -110,12 +112,17 @@ void BreakPoints::Remove(u32 em_address)
|
|||
|
||||
void BreakPoints::Clear()
|
||||
{
|
||||
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
|
||||
if (jit)
|
||||
{
|
||||
if (jit)
|
||||
jit->GetBlockCache()->InvalidateICache(i->iAddress, 4);
|
||||
m_BreakPoints.erase(i);
|
||||
std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(),
|
||||
[](const TBreakPoint& bp)
|
||||
{
|
||||
jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
m_BreakPoints.clear();
|
||||
}
|
||||
|
||||
MemChecks::TMemChecksStr MemChecks::GetStrings() const
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: x = (wchar_t*)*ptr; break;
|
||||
case MODE_READ: x.assign((wchar_t*)*ptr, (stringLen / sizeof(wchar_t)) - 1); break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
|
|
|
@ -81,8 +81,9 @@ private:
|
|||
#define GC_ALIGNED16_DECL(x) __declspec(align(16)) x
|
||||
#define GC_ALIGNED64_DECL(x) __declspec(align(64)) x
|
||||
|
||||
// Since it is always around on windows
|
||||
// Since they are always around on windows
|
||||
#define HAVE_WX 1
|
||||
#define HAVE_OPENAL 1
|
||||
|
||||
#define HAVE_PORTAUDIO 1
|
||||
|
||||
|
|
|
@ -89,11 +89,11 @@
|
|||
#define MAIL_LOGS_DIR LOGS_DIR DIR_SEP "Mail"
|
||||
#define SHADERS_DIR "Shaders"
|
||||
#define WII_SYSCONF_DIR "shared2" DIR_SEP "sys"
|
||||
#define THEMES_DIR "Themes"
|
||||
|
||||
// Filenames
|
||||
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
|
||||
#define DOLPHIN_CONFIG "Dolphin.ini"
|
||||
#define DSP_CONFIG "DSP.ini"
|
||||
#define DEBUGGER_CONFIG "Debugger.ini"
|
||||
#define LOGGER_CONFIG "Logger.ini"
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "FileSearch.h"
|
||||
|
||||
|
@ -72,36 +73,36 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
|
|||
|
||||
|
||||
#else
|
||||
size_t dot_pos = _searchString.rfind(".");
|
||||
// TODO: super lame/broken
|
||||
|
||||
if (dot_pos == std::string::npos)
|
||||
return;
|
||||
auto end_match(_searchString);
|
||||
|
||||
// assuming we have a "*.blah"-like pattern
|
||||
if (!end_match.empty() && end_match[0] == '*')
|
||||
end_match.erase(0, 1);
|
||||
|
||||
// ugly
|
||||
if (end_match == ".*")
|
||||
end_match.clear();
|
||||
|
||||
std::string ext = _searchString.substr(dot_pos);
|
||||
DIR* dir = opendir(_strPath.c_str());
|
||||
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
dirent* dp;
|
||||
|
||||
while (true)
|
||||
while (auto const dp = readdir(dir))
|
||||
{
|
||||
dp = readdir(dir);
|
||||
std::string found(dp->d_name);
|
||||
|
||||
if (!dp)
|
||||
break;
|
||||
|
||||
std::string s(dp->d_name);
|
||||
|
||||
if ( (!ext.compare(".*") && s.compare(".") && s.compare("..")) ||
|
||||
((s.size() > ext.size()) && (!strcasecmp(s.substr(s.size() - ext.size()).c_str(), ext.c_str())) ))
|
||||
if ((found != ".") && (found != "..")
|
||||
&& (found.size() >= end_match.size())
|
||||
&& std::equal(end_match.rbegin(), end_match.rend(), found.rbegin()))
|
||||
{
|
||||
std::string full_name;
|
||||
if (_strPath.c_str()[_strPath.size()-1] == DIR_SEP_CHR)
|
||||
full_name = _strPath + s;
|
||||
full_name = _strPath + found;
|
||||
else
|
||||
full_name = _strPath + DIR_SEP + s;
|
||||
full_name = _strPath + DIR_SEP + found;
|
||||
|
||||
m_FileNames.push_back(full_name);
|
||||
}
|
||||
|
|
|
@ -512,12 +512,24 @@ bool DeleteDirRecursively(const std::string &directory)
|
|||
if (IsDirectory(newPath))
|
||||
{
|
||||
if (!DeleteDirRecursively(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Delete(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -678,9 +690,9 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
|||
paths[D_DUMPDSP_IDX] = paths[D_USER_IDX] + DUMP_DSP_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_MAILLOGS_IDX] = paths[D_USER_IDX] + MAIL_LOGS_DIR DIR_SEP;
|
||||
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
|
||||
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
|
||||
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
|
||||
paths[F_DSPCONFIG_IDX] = paths[D_CONFIG_IDX] + DSP_CONFIG;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
|
|
|
@ -50,8 +50,8 @@ enum {
|
|||
D_LOGS_IDX,
|
||||
D_MAILLOGS_IDX,
|
||||
D_WIISYSCONF_IDX,
|
||||
D_THEMES_IDX,
|
||||
F_DOLPHINCONFIG_IDX,
|
||||
F_DSPCONFIG_IDX,
|
||||
F_DEBUGGERCONFIG_IDX,
|
||||
F_LOGGERCONFIG_IDX,
|
||||
F_MAINLOG_IDX,
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
// Increment this every time you change shader generation code.
|
||||
enum
|
||||
{
|
||||
LINEAR_DISKCACHE_VER = 6975
|
||||
LINEAR_DISKCACHE_VER = 6979
|
||||
};
|
||||
|
||||
// On disk format:
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include <unistd.h> // for unlink()
|
||||
#endif
|
||||
|
||||
/* believe me, you *don't* want to change these constants !! */
|
||||
/* Believe me, you *don't* want to change these constants !! */
|
||||
#define BYTES_PER_SECTOR 512
|
||||
#define RESERVED_SECTORS 32
|
||||
#define BACKUP_BOOT_SECTOR 6
|
||||
|
@ -52,15 +52,15 @@
|
|||
#define POKES(p,v) ( BYTE_(p,0) = (u8)(v), BYTE_(p,1) = (u8)((v) >> 8) )
|
||||
#define POKEW(p,v) ( BYTE_(p,0) = (u8)(v), BYTE_(p,1) = (u8)((v) >> 8), BYTE_(p,2) = (u8)((v) >> 16), BYTE_(p,3) = (u8)((v) >> 24) )
|
||||
|
||||
static u8 s_boot_sector [ BYTES_PER_SECTOR ]; /* boot sector */
|
||||
static u8 s_boot_sector [ BYTES_PER_SECTOR ]; /* Boot sector */
|
||||
static u8 s_fsinfo_sector [ BYTES_PER_SECTOR ]; /* FS Info sector */
|
||||
static u8 s_fat_head [ BYTES_PER_SECTOR ]; /* first FAT sector */
|
||||
static u8 s_fat_head [ BYTES_PER_SECTOR ]; /* First FAT sector */
|
||||
|
||||
/* this is the date and time when creating the disk */
|
||||
static int get_serial_id()
|
||||
/* This is the date and time when creating the disk */
|
||||
static unsigned int get_serial_id()
|
||||
{
|
||||
u16 lo, hi;
|
||||
time_t now = time(NULL);
|
||||
time_t now = time(nullptr);
|
||||
struct tm tm = gmtime( &now )[0];
|
||||
|
||||
lo = (u16)(tm.tm_mday + ((tm.tm_mon+1) << 8) + (tm.tm_sec << 8));
|
||||
|
@ -69,7 +69,7 @@ static int get_serial_id()
|
|||
return lo + (hi << 16);
|
||||
}
|
||||
|
||||
static int get_sectors_per_cluster(u64 disk_size)
|
||||
static unsigned int get_sectors_per_cluster(u64 disk_size)
|
||||
{
|
||||
u64 disk_MB = disk_size/(1024*1024);
|
||||
|
||||
|
@ -88,60 +88,60 @@ static int get_sectors_per_cluster(u64 disk_size)
|
|||
return 32;
|
||||
}
|
||||
|
||||
static int get_sectors_per_fat(u64 disk_size, int sectors_per_cluster)
|
||||
static unsigned int get_sectors_per_fat(u64 disk_size, u32 sectors_per_cluster)
|
||||
{
|
||||
u64 divider;
|
||||
|
||||
/* weird computation from MS - see fatgen103.doc for details */
|
||||
disk_size -= RESERVED_SECTORS * BYTES_PER_SECTOR; /* don't count 32 reserved sectors */
|
||||
disk_size /= BYTES_PER_SECTOR; /* disk size in sectors */
|
||||
/* Weird computation from MS - see fatgen103.doc for details */
|
||||
disk_size -= RESERVED_SECTORS * BYTES_PER_SECTOR; /* Don't count 32 reserved sectors */
|
||||
disk_size /= BYTES_PER_SECTOR; /* Disk size in sectors */
|
||||
divider = ((256 * sectors_per_cluster) + NUM_FATS) / 2;
|
||||
|
||||
return (int)( (disk_size + (divider-1)) / divider );
|
||||
return (u32)( (disk_size + (divider-1)) / divider );
|
||||
}
|
||||
|
||||
static void boot_sector_init(u8* boot, u8* info, u64 disk_size, const char* label)
|
||||
{
|
||||
int sectors_per_cluster = get_sectors_per_cluster(disk_size);
|
||||
int sectors_per_fat = get_sectors_per_fat(disk_size, sectors_per_cluster);
|
||||
int sectors_per_disk = (int)(disk_size / BYTES_PER_SECTOR);
|
||||
int serial_id = get_serial_id();
|
||||
int free_count;
|
||||
u32 sectors_per_cluster = get_sectors_per_cluster(disk_size);
|
||||
u32 sectors_per_fat = get_sectors_per_fat(disk_size, sectors_per_cluster);
|
||||
u32 sectors_per_disk = (u32)(disk_size / BYTES_PER_SECTOR);
|
||||
u32 serial_id = get_serial_id();
|
||||
u32 free_count;
|
||||
|
||||
if (label == NULL)
|
||||
if (label == nullptr)
|
||||
label = "DOLPHINSD";
|
||||
|
||||
POKEB(boot, 0xeb);
|
||||
POKEB(boot+1, 0x5a);
|
||||
POKEB(boot+2, 0x90);
|
||||
strcpy( (char*)boot + 3, "MSWIN4.1" );
|
||||
POKES( boot + 0x0b, BYTES_PER_SECTOR ); /* sector size */
|
||||
POKEB( boot + 0xd, sectors_per_cluster ); /* sectors per cluster */
|
||||
POKES( boot + 0xe, RESERVED_SECTORS ); /* reserved sectors before first FAT */
|
||||
POKEB( boot + 0x10, NUM_FATS ); /* number of FATs */
|
||||
POKES( boot + 0x11, 0 ); /* max root directory entries for FAT12/FAT16, 0 for FAT32 */
|
||||
POKES( boot + 0x13, 0 ); /* total sectors, 0 to use 32-bit value at offset 0x20 */
|
||||
POKEB( boot + 0x15, 0xF8 ); /* media descriptor, 0xF8 == hard disk */
|
||||
POKES( boot + 0x0b, BYTES_PER_SECTOR ); /* Sector size */
|
||||
POKEB( boot + 0xd, sectors_per_cluster ); /* Sectors per cluster */
|
||||
POKES( boot + 0xe, RESERVED_SECTORS ); /* Reserved sectors before first FAT */
|
||||
POKEB( boot + 0x10, NUM_FATS ); /* Number of FATs */
|
||||
POKES( boot + 0x11, 0 ); /* Max root directory entries for FAT12/FAT16, 0 for FAT32 */
|
||||
POKES( boot + 0x13, 0 ); /* Total sectors, 0 to use 32-bit value at offset 0x20 */
|
||||
POKEB( boot + 0x15, 0xF8 ); /* Media descriptor, 0xF8 == hard disk */
|
||||
POKES( boot + 0x16, 0 ); /* Sectors per FAT for FAT12/16, 0 for FAT32 */
|
||||
POKES( boot + 0x18, 9 ); /* Sectors per track (whatever) */
|
||||
POKES( boot + 0x1a, 2 ); /* Number of heads (whatever) */
|
||||
POKEW( boot + 0x1c, 0 ); /* Hidden sectors */
|
||||
POKEW( boot + 0x20, sectors_per_disk ); /* Total sectors */
|
||||
|
||||
/* extension */
|
||||
/* Extension */
|
||||
POKEW( boot + 0x24, sectors_per_fat ); /* Sectors per FAT */
|
||||
POKES( boot + 0x28, 0 ); /* FAT flags */
|
||||
POKES( boot + 0x2a, 0 ); /* version */
|
||||
POKEW( boot + 0x2c, 2 ); /* cluster number of root directory start */
|
||||
POKES( boot + 0x30, 1 ); /* sector number of FS information sector */
|
||||
POKES( boot + 0x32, BACKUP_BOOT_SECTOR ); /* sector number of a copy of this boot sector */
|
||||
POKEB( boot + 0x40, 0x80 ); /* physical drive number */
|
||||
POKEB( boot + 0x42, 0x29 ); /* extended boot signature ?? */
|
||||
POKEW( boot + 0x43, serial_id ); /* serial ID */
|
||||
POKES( boot + 0x2a, 0 ); /* Version */
|
||||
POKEW( boot + 0x2c, 2 ); /* Cluster number of root directory start */
|
||||
POKES( boot + 0x30, 1 ); /* Sector number of FS information sector */
|
||||
POKES( boot + 0x32, BACKUP_BOOT_SECTOR ); /* Sector number of a copy of this boot sector */
|
||||
POKEB( boot + 0x40, 0x80 ); /* Physical drive number */
|
||||
POKEB( boot + 0x42, 0x29 ); /* Extended boot signature ?? */
|
||||
POKEW( boot + 0x43, serial_id ); /* Serial ID */
|
||||
strncpy( (char*)boot + 0x47, label, 11 ); /* Volume Label */
|
||||
memcpy( boot + 0x52, "FAT32 ", 8 ); /* FAT system type, padded with 0x20 */
|
||||
|
||||
POKEB( boot + BYTES_PER_SECTOR-2, 0x55 ); /* boot sector signature */
|
||||
POKEB( boot + BYTES_PER_SECTOR-2, 0x55 ); /* Boot sector signature */
|
||||
POKEB( boot + BYTES_PER_SECTOR-1, 0xAA );
|
||||
|
||||
/* FSInfo sector */
|
||||
|
@ -149,25 +149,25 @@ static void boot_sector_init(u8* boot, u8* info, u64 disk_size, const char* labe
|
|||
|
||||
POKEW( info + 0, 0x41615252 );
|
||||
POKEW( info + 484, 0x61417272 );
|
||||
POKEW( info + 488, free_count ); /* number of free clusters */
|
||||
POKEW( info + 492, 3 ); /* next free clusters, 0-1 reserved, 2 is used for the root dir */
|
||||
POKEW( info + 488, free_count ); /* Number of free clusters */
|
||||
POKEW( info + 492, 3 ); /* Next free clusters, 0-1 reserved, 2 is used for the root dir */
|
||||
POKEW( info + 508, 0xAA550000 );
|
||||
}
|
||||
|
||||
static void fat_init(u8* fat)
|
||||
{
|
||||
POKEW( fat, 0x0ffffff8 ); /* reserve cluster 1, media id in low byte */
|
||||
POKEW( fat + 4, 0x0fffffff ); /* reserve cluster 2 */
|
||||
POKEW( fat + 8, 0x0fffffff ); /* end of clust chain for root dir */
|
||||
POKEW( fat, 0x0ffffff8 ); /* Reserve cluster 1, media id in low byte */
|
||||
POKEW( fat + 4, 0x0fffffff ); /* Reserve cluster 2 */
|
||||
POKEW( fat + 8, 0x0fffffff ); /* End of cluster chain for root dir */
|
||||
}
|
||||
|
||||
|
||||
static int write_sector(FILE* file, u8* sector)
|
||||
static unsigned int write_sector(FILE* file, u8* sector)
|
||||
{
|
||||
return fwrite(sector, 1, 512, file) != 512;
|
||||
}
|
||||
|
||||
static int write_empty(FILE* file, u64 count)
|
||||
static unsigned int write_empty(FILE* file, u64 count)
|
||||
{
|
||||
static u8 empty[64*1024];
|
||||
|
||||
|
@ -188,8 +188,8 @@ static int write_empty(FILE* file, u64 count)
|
|||
|
||||
bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
|
||||
{
|
||||
int sectors_per_fat;
|
||||
int sectors_per_disk;
|
||||
u32 sectors_per_fat;
|
||||
u32 sectors_per_disk;
|
||||
FILE* f;
|
||||
|
||||
// Convert MB to bytes
|
||||
|
@ -200,21 +200,21 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
|
|||
return false;
|
||||
}
|
||||
|
||||
// pretty unlikely to overflow.
|
||||
sectors_per_disk = (int)(disk_size / 512);
|
||||
// Pretty unlikely to overflow.
|
||||
sectors_per_disk = (u32)(disk_size / 512);
|
||||
sectors_per_fat = get_sectors_per_fat(disk_size, get_sectors_per_cluster(disk_size));
|
||||
|
||||
boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, NULL );
|
||||
boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, nullptr);
|
||||
fat_init(s_fat_head);
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
{
|
||||
ERROR_LOG(COMMON, "could not create file '%s', aborting...\n", filename);
|
||||
ERROR_LOG(COMMON, "Could not create file '%s', aborting...\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* here's the layout:
|
||||
/* Here's the layout:
|
||||
*
|
||||
* boot_sector
|
||||
* fsinfo_sector
|
||||
|
@ -251,7 +251,7 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
|
|||
return true;
|
||||
|
||||
FailWrite:
|
||||
ERROR_LOG(COMMON, "could not write to '%s', aborting...\n", filename);
|
||||
ERROR_LOG(COMMON, "Could not write to '%s', aborting...\n", filename);
|
||||
if (unlink(filename) < 0)
|
||||
ERROR_LOG(COMMON, "unlink(%s) failed\n%s", filename, GetLastErrorMsg());
|
||||
fclose(f);
|
||||
|
|
|
@ -318,9 +318,12 @@ public:
|
|||
|
||||
mutex_type* release()
|
||||
{
|
||||
return mutex();
|
||||
auto const ret = mutex();
|
||||
|
||||
pm = NULL;
|
||||
owns = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool owns_lock() const
|
||||
|
|
|
@ -115,6 +115,7 @@ set(SRCS Src/ActionReplay.cpp
|
|||
Src/HW/SI_Device.cpp
|
||||
Src/HW/SI_DeviceGBA.cpp
|
||||
Src/HW/SI_DeviceGCController.cpp
|
||||
Src/HW/SI_DeviceGCSteeringWheel.cpp
|
||||
Src/HW/Sram.cpp
|
||||
Src/HW/StreamADPCM.cpp
|
||||
Src/HW/SystemTimers.cpp
|
||||
|
|
|
@ -301,6 +301,7 @@
|
|||
<ClCompile Include="Src\HW\SI_DeviceAMBaseboard.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGBA.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGCController.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp" />
|
||||
<ClCompile Include="Src\HW\Sram.cpp" />
|
||||
<ClCompile Include="Src\HW\StreamADPCM.cpp" />
|
||||
<ClCompile Include="Src\HW\SystemTimers.cpp" />
|
||||
|
@ -503,6 +504,7 @@
|
|||
<ClInclude Include="Src\HW\SI_DeviceAMBaseboard.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGBA.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGCController.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h" />
|
||||
<ClInclude Include="Src\HW\Sram.h" />
|
||||
<ClInclude Include="Src\HW\StreamADPCM.h" />
|
||||
<ClInclude Include="Src\HW\SystemTimers.h" />
|
||||
|
|
|
@ -290,6 +290,9 @@
|
|||
<ClCompile Include="Src\HW\SI_DeviceGCController.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\VideoInterface.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\VI - Video Interface</Filter>
|
||||
</ClCompile>
|
||||
|
@ -814,6 +817,9 @@
|
|||
<ClInclude Include="Src\HW\SI_DeviceGCController.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\SI.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -679,7 +679,8 @@ bool Subtype_MasterCodeAndWriteToCCXXXXXX(const ARAddr addr, const u32 data)
|
|||
// u8 mcode_type = (data & 0xFF0000) >> 16;
|
||||
// u8 mcode_count = (data & 0xFF00) >> 8;
|
||||
// u8 mcode_number = data & 0xFF;
|
||||
PanicAlertT("Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)", current_code->name.c_str());
|
||||
PanicAlertT("Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)\n"
|
||||
"Master codes are not needed. Do not use master codes.", current_code->name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -257,6 +257,19 @@ bool CBoot::BootUp()
|
|||
EmulatedBS2(_StartupPara.bWii);
|
||||
}
|
||||
|
||||
// Scan for common HLE functions
|
||||
if (_StartupPara.bSkipIdle && !_StartupPara.bEnableDebugging)
|
||||
{
|
||||
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
|
||||
SignatureDB db;
|
||||
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
|
||||
{
|
||||
db.Apply(&g_symbolDB);
|
||||
HLE::PatchFunctions();
|
||||
db.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to load the symbol map if there is one, and then scan it for
|
||||
and eventually replace code */
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
|
||||
|
|
|
@ -375,7 +375,7 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
|
||||
u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
|
||||
|
||||
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
|
||||
} while(PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "VideoBackendBase.h"
|
||||
#include "Movie.h"
|
||||
|
||||
|
||||
namespace BootManager
|
||||
{
|
||||
|
||||
|
@ -55,9 +54,9 @@ namespace BootManager
|
|||
// Apply fire liberally
|
||||
struct ConfigCache
|
||||
{
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bMMUBAT,
|
||||
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bDisableWiimoteSpeaker;
|
||||
int iTLBHack;
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
||||
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bDisableWiimoteSpeaker, bHLE_BS2;
|
||||
int iTLBHack, iCPUCore;
|
||||
std::string strBackend;
|
||||
};
|
||||
static ConfigCache config_cache;
|
||||
|
@ -90,9 +89,10 @@ bool BootCore(const std::string& _rFilename)
|
|||
config_cache.valid = true;
|
||||
config_cache.bCPUThread = StartUp.bCPUThread;
|
||||
config_cache.bSkipIdle = StartUp.bSkipIdle;
|
||||
config_cache.iCPUCore = StartUp.iCPUCore;
|
||||
config_cache.bEnableFPRF = StartUp.bEnableFPRF;
|
||||
config_cache.bMMU = StartUp.bMMU;
|
||||
config_cache.bMMUBAT = StartUp.bMMUBAT;
|
||||
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
|
||||
config_cache.iTLBHack = StartUp.iTLBHack;
|
||||
config_cache.bVBeam = StartUp.bVBeam;
|
||||
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
|
||||
|
@ -100,20 +100,23 @@ bool BootCore(const std::string& _rFilename)
|
|||
config_cache.bDSPHLE = StartUp.bDSPHLE;
|
||||
config_cache.bDisableWiimoteSpeaker = StartUp.bDisableWiimoteSpeaker;
|
||||
config_cache.strBackend = StartUp.m_strVideoBackend;
|
||||
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
|
||||
|
||||
// General settings
|
||||
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
|
||||
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
|
||||
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
|
||||
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
|
||||
game_ini.Get("Core", "BAT", &StartUp.bMMUBAT, StartUp.bMMUBAT);
|
||||
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
|
||||
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
|
||||
game_ini.Get("Core", "VBeam", &StartUp.bVBeam, StartUp.bVBeam);
|
||||
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
|
||||
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
|
||||
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
|
||||
game_ini.Get("Wii", "DisableWiimoteSpeaker",&StartUp.bDisableWiimoteSpeaker, StartUp.bDisableWiimoteSpeaker);
|
||||
game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str());
|
||||
game_ini.Get("Core", "CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore);
|
||||
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
|
@ -123,6 +126,7 @@ bool BootCore(const std::string& _rFilename)
|
|||
StartUp.bDSPHLE = Movie::IsDSPHLE();
|
||||
StartUp.bProgressive = Movie::IsProgressive();
|
||||
StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed();
|
||||
StartUp.iCPUCore = Movie::GetCPUMode();
|
||||
if (Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave() && !StartUp.bWii)
|
||||
{
|
||||
if (File::Exists("Movie.raw"))
|
||||
|
@ -154,14 +158,16 @@ void Stop()
|
|||
|
||||
SCoreStartupParameter& StartUp = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
StartUp.m_strUniqueID = "00000000";
|
||||
if (config_cache.valid)
|
||||
{
|
||||
config_cache.valid = false;
|
||||
StartUp.bCPUThread = config_cache.bCPUThread;
|
||||
StartUp.bSkipIdle = config_cache.bSkipIdle;
|
||||
StartUp.iCPUCore = config_cache.iCPUCore;
|
||||
StartUp.bEnableFPRF = config_cache.bEnableFPRF;
|
||||
StartUp.bMMU = config_cache.bMMU;
|
||||
StartUp.bMMUBAT = config_cache.bMMUBAT;
|
||||
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
|
||||
StartUp.iTLBHack = config_cache.iTLBHack;
|
||||
StartUp.bVBeam = config_cache.bVBeam;
|
||||
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
|
||||
|
@ -170,6 +176,7 @@ void Stop()
|
|||
StartUp.bDisableWiimoteSpeaker = config_cache.bDisableWiimoteSpeaker;
|
||||
StartUp.m_strVideoBackend = config_cache.strBackend;
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,6 @@ void SConfig::SaveSettings()
|
|||
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);
|
||||
ini.Set("Interface", "MainWindowPosX", (m_LocalCoreStartupParameter.iPosX == -32000) ? 0 : m_LocalCoreStartupParameter.iPosX); // TODO - HAX
|
||||
ini.Set("Interface", "MainWindowPosY", (m_LocalCoreStartupParameter.iPosY == -32000) ? 0 : m_LocalCoreStartupParameter.iPosY); // TODO - HAX
|
||||
ini.Set("Interface", "MainWindowWidth", m_LocalCoreStartupParameter.iWidth);
|
||||
|
@ -175,6 +174,7 @@ void SConfig::SaveSettings()
|
|||
ini.Set("Interface", "ShowLogWindow", m_InterfaceLogWindow);
|
||||
ini.Set("Interface", "ShowLogConfigWindow", m_InterfaceLogConfigWindow);
|
||||
ini.Set("Interface", "ShowConsole", m_InterfaceConsole);
|
||||
ini.Set("Interface", "ThemeName", m_LocalCoreStartupParameter.theme_name);
|
||||
|
||||
// Hotkeys
|
||||
for (int i = 0; i < NUM_HOTKEYS; i++)
|
||||
|
@ -221,12 +221,13 @@ void SConfig::SaveSettings()
|
|||
ini.Set("Core", "DSPThread", m_LocalCoreStartupParameter.bDSPThread);
|
||||
ini.Set("Core", "DSPHLE", m_LocalCoreStartupParameter.bDSPHLE);
|
||||
ini.Set("Core", "SkipIdle", m_LocalCoreStartupParameter.bSkipIdle);
|
||||
ini.Set("Core", "LockThreads", m_LocalCoreStartupParameter.bLockThreads);
|
||||
ini.Set("Core", "DefaultGCM", m_LocalCoreStartupParameter.m_strDefaultGCM);
|
||||
ini.Set("Core", "DVDRoot", m_LocalCoreStartupParameter.m_strDVDRoot);
|
||||
ini.Set("Core", "Apploader", m_LocalCoreStartupParameter.m_strApploader);
|
||||
ini.Set("Core", "EnableCheats", m_LocalCoreStartupParameter.bEnableCheats);
|
||||
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
|
||||
ini.Set("Core", "DPL2Decoder", m_LocalCoreStartupParameter.bDPL2Decoder);
|
||||
ini.Set("Core", "Latency", m_LocalCoreStartupParameter.iLatency);
|
||||
ini.Set("Core", "MemcardA", m_strMemoryCardA);
|
||||
ini.Set("Core", "MemcardB", m_strMemoryCardB);
|
||||
ini.Set("Core", "SlotA", m_EXIDevice[0]);
|
||||
|
@ -255,6 +256,12 @@ void SConfig::SaveSettings()
|
|||
ini.Set("Movie", "PauseMovie", m_PauseMovie);
|
||||
ini.Set("Movie", "Author", m_strMovieAuthor);
|
||||
|
||||
// DSP
|
||||
ini.Set("DSP", "EnableJIT", m_EnableJIT);
|
||||
ini.Set("DSP", "DumpAudio", m_DumpAudio);
|
||||
ini.Set("DSP", "Backend", sBackend);
|
||||
ini.Set("DSP", "Volume", m_Volume);
|
||||
|
||||
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||
m_SYSCONF->Save();
|
||||
}
|
||||
|
@ -302,7 +309,6 @@ void SConfig::LoadSettings()
|
|||
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);
|
||||
ini.Get("Interface", "MainWindowPosX", &m_LocalCoreStartupParameter.iPosX, 100);
|
||||
ini.Get("Interface", "MainWindowPosY", &m_LocalCoreStartupParameter.iPosY, 100);
|
||||
ini.Get("Interface", "MainWindowWidth", &m_LocalCoreStartupParameter.iWidth, 800);
|
||||
|
@ -313,6 +319,7 @@ void SConfig::LoadSettings()
|
|||
ini.Get("Interface", "ShowLogWindow", &m_InterfaceLogWindow, false);
|
||||
ini.Get("Interface", "ShowLogConfigWindow", &m_InterfaceLogConfigWindow, false);
|
||||
ini.Get("Interface", "ShowConsole", &m_InterfaceConsole, false);
|
||||
ini.Get("Interface", "ThemeName", &m_LocalCoreStartupParameter.theme_name, "Boomy");
|
||||
|
||||
// Hotkeys
|
||||
for (int i = 0; i < NUM_HOTKEYS; i++)
|
||||
|
@ -361,12 +368,13 @@ void SConfig::LoadSettings()
|
|||
ini.Get("Core", "DSPHLE", &m_LocalCoreStartupParameter.bDSPHLE, true);
|
||||
ini.Get("Core", "CPUThread", &m_LocalCoreStartupParameter.bCPUThread, true);
|
||||
ini.Get("Core", "SkipIdle", &m_LocalCoreStartupParameter.bSkipIdle, true);
|
||||
ini.Get("Core", "LockThreads", &m_LocalCoreStartupParameter.bLockThreads, false);
|
||||
ini.Get("Core", "DefaultGCM", &m_LocalCoreStartupParameter.m_strDefaultGCM);
|
||||
ini.Get("Core", "DVDRoot", &m_LocalCoreStartupParameter.m_strDVDRoot);
|
||||
ini.Get("Core", "Apploader", &m_LocalCoreStartupParameter.m_strApploader);
|
||||
ini.Get("Core", "EnableCheats", &m_LocalCoreStartupParameter.bEnableCheats, false);
|
||||
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
|
||||
ini.Get("Core", "DPL2Decoder", &m_LocalCoreStartupParameter.bDPL2Decoder, false);
|
||||
ini.Get("Core", "Latency", &m_LocalCoreStartupParameter.iLatency, 14);
|
||||
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
|
||||
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
|
||||
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
|
||||
|
@ -392,7 +400,7 @@ void SConfig::LoadSettings()
|
|||
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
||||
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeam, false);
|
||||
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
|
||||
ini.Get("Core", "BAT", &m_LocalCoreStartupParameter.bMMUBAT, false);
|
||||
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
|
||||
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
|
||||
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default
|
||||
|
||||
|
@ -402,6 +410,20 @@ void SConfig::LoadSettings()
|
|||
// Movie
|
||||
ini.Get("General", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "Author", &m_strMovieAuthor, "");
|
||||
|
||||
// DSP
|
||||
ini.Get("DSP", "EnableJIT", &m_EnableJIT, true);
|
||||
ini.Get("DSP", "DumpAudio", &m_DumpAudio, false);
|
||||
#if defined __linux__ && HAVE_ALSA
|
||||
ini.Get("DSP", "Backend", &sBackend, BACKEND_ALSA);
|
||||
#elif defined __APPLE__
|
||||
ini.Get("DSP", "Backend", &sBackend, BACKEND_COREAUDIO);
|
||||
#elif defined _WIN32
|
||||
ini.Get("DSP", "Backend", &sBackend, BACKEND_DIRECTSOUND);
|
||||
#else
|
||||
ini.Get("DSP", "Backend", &sBackend, BACKEND_NULLSOUND);
|
||||
#endif
|
||||
ini.Get("DSP", "Volume", &m_Volume, 100);
|
||||
}
|
||||
|
||||
m_SYSCONF = new SysConf();
|
||||
|
|
|
@ -26,6 +26,16 @@
|
|||
#include "HW/SI_Device.h"
|
||||
#include "SysConf.h"
|
||||
|
||||
// DSP Backend Types
|
||||
#define BACKEND_NULLSOUND "No audio output"
|
||||
#define BACKEND_ALSA "ALSA"
|
||||
#define BACKEND_AOSOUND "AOSound"
|
||||
#define BACKEND_COREAUDIO "CoreAudio"
|
||||
#define BACKEND_DIRECTSOUND "DSound"
|
||||
#define BACKEND_OPENAL "OpenAL"
|
||||
#define BACKEND_PULSEAUDIO "Pulse"
|
||||
#define BACKEND_XAUDIO2 "XAudio2"
|
||||
|
||||
struct SConfig : NonCopyable
|
||||
{
|
||||
// Wii Devices
|
||||
|
@ -83,6 +93,12 @@ struct SConfig : NonCopyable
|
|||
bool m_ShowLag;
|
||||
std::string m_strMovieAuthor;
|
||||
|
||||
// DSP settings
|
||||
bool m_EnableJIT;
|
||||
bool m_DumpAudio;
|
||||
int m_Volume;
|
||||
std::string sBackend;
|
||||
|
||||
SysConf* m_SYSCONF;
|
||||
|
||||
// save settings
|
||||
|
|
|
@ -310,10 +310,7 @@ void CpuThread()
|
|||
g_video_backend->Video_Prepare();
|
||||
}
|
||||
|
||||
if (_CoreParameter.bLockThreads)
|
||||
Common::SetCurrentThreadAffinity(1); // Force to first core
|
||||
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
#if defined(_M_X64)
|
||||
EMM::InstallExceptionHandler(); // Let's run under memory watch
|
||||
#endif
|
||||
|
||||
|
@ -344,9 +341,6 @@ void FifoPlayerThread()
|
|||
Common::SetCurrentThreadName("FIFO-GPU thread");
|
||||
}
|
||||
|
||||
if (_CoreParameter.bLockThreads)
|
||||
Common::SetCurrentThreadAffinity(1); // Force to first core
|
||||
|
||||
g_bStarted = true;
|
||||
|
||||
// Enter CPU run loop. When we leave it - we are done.
|
||||
|
@ -371,14 +365,6 @@ void EmuThread()
|
|||
|
||||
Common::SetCurrentThreadName("Emuthread - Starting");
|
||||
|
||||
if (_CoreParameter.bLockThreads)
|
||||
{
|
||||
if (cpu_info.num_cores > 3) // Force to third, non-HT core
|
||||
Common::SetCurrentThreadAffinity(4);
|
||||
else // Force to second core
|
||||
Common::SetCurrentThreadAffinity(2);
|
||||
}
|
||||
|
||||
DisplayMessage(cpu_info.brand_string, 8000);
|
||||
DisplayMessage(cpu_info.Summarize(), 8000);
|
||||
DisplayMessage(_CoreParameter.m_strFilename, 3000);
|
||||
|
@ -431,7 +417,7 @@ void EmuThread()
|
|||
CBoot::BootUp();
|
||||
|
||||
// Setup our core, but can't use dynarec if we are compare server
|
||||
if (Movie::GetCPUMode() && (!_CoreParameter.bRunCompareServer ||
|
||||
if (_CoreParameter.iCPUCore && (!_CoreParameter.bRunCompareServer ||
|
||||
_CoreParameter.bRunCompareClient))
|
||||
PowerPC::SetMode(PowerPC::MODE_JIT);
|
||||
else
|
||||
|
@ -628,70 +614,7 @@ void VideoThrottle()
|
|||
u32 ElapseTime = (u32)Timer.GetTimeDifference();
|
||||
if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
|
||||
{
|
||||
g_requestRefreshInfo = false;
|
||||
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
if (ElapseTime == 0)
|
||||
ElapseTime = 1;
|
||||
|
||||
u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
|
||||
u32 VPS = DrawnVideo * 1000 / ElapseTime;
|
||||
u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);
|
||||
|
||||
// Settings are shown the same for both extended and summary info
|
||||
std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC");
|
||||
|
||||
// Use extended or summary information. The summary information does not print the ticks data,
|
||||
// that's more of a debugging interest, it can always be optional of course if someone is interested.
|
||||
//#define EXTENDED_INFO
|
||||
#ifdef EXTENDED_INFO
|
||||
u64 newTicks = CoreTiming::GetTicks();
|
||||
u64 newIdleTicks = CoreTiming::GetIdleTicks();
|
||||
|
||||
u64 diff = (newTicks - ticks) / 1000000;
|
||||
u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
|
||||
|
||||
ticks = newTicks;
|
||||
idleTicks = newIdleTicks;
|
||||
|
||||
float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;
|
||||
|
||||
std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
(int)(diff),
|
||||
(int)(diff - idleDiff),
|
||||
(int)(idleDiff),
|
||||
SystemTimers::GetTicksPerSecond() / 1000000,
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
TicksPercentage);
|
||||
|
||||
#else // Summary information
|
||||
std::string SFPS;
|
||||
if (Movie::IsPlayingInput())
|
||||
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
|
||||
else if (Movie::IsRecordingInput())
|
||||
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
|
||||
else
|
||||
SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
#endif
|
||||
|
||||
// This is our final "frame counter" string
|
||||
std::string SMessage = StringFromFormat("%s | %s",
|
||||
SSettings.c_str(), SFPS.c_str());
|
||||
std::string TMessage = StringFromFormat("%s | ", scm_rev_str) +
|
||||
SMessage;
|
||||
|
||||
// Show message
|
||||
g_video_backend->UpdateFPSDisplay(SMessage.c_str());
|
||||
|
||||
if (_CoreParameter.bRenderToMain &&
|
||||
SConfig::GetInstance().m_InterfaceStatusbar) {
|
||||
Host_UpdateStatusBar(SMessage.c_str());
|
||||
Host_UpdateTitle(scm_rev_str);
|
||||
} else
|
||||
Host_UpdateTitle(TMessage.c_str());
|
||||
|
||||
UpdateTitle();
|
||||
|
||||
// Reset counter
|
||||
Timer.Update();
|
||||
|
@ -738,4 +661,79 @@ const char *Callback_ISOName()
|
|||
return "";
|
||||
}
|
||||
|
||||
void UpdateTitle()
|
||||
{
|
||||
u32 ElapseTime = (u32)Timer.GetTimeDifference();
|
||||
g_requestRefreshInfo = false;
|
||||
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
if (ElapseTime == 0)
|
||||
ElapseTime = 1;
|
||||
|
||||
u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
|
||||
u32 VPS = DrawnVideo * 1000 / ElapseTime;
|
||||
u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);
|
||||
|
||||
// Settings are shown the same for both extended and summary info
|
||||
std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC");
|
||||
|
||||
// Use extended or summary information. The summary information does not print the ticks data,
|
||||
// that's more of a debugging interest, it can always be optional of course if someone is interested.
|
||||
//#define EXTENDED_INFO
|
||||
#ifdef EXTENDED_INFO
|
||||
u64 newTicks = CoreTiming::GetTicks();
|
||||
u64 newIdleTicks = CoreTiming::GetIdleTicks();
|
||||
|
||||
u64 diff = (newTicks - ticks) / 1000000;
|
||||
u64 idleDiff = (newIdleTicks - idleTicks) / 1000000;
|
||||
|
||||
ticks = newTicks;
|
||||
idleTicks = newIdleTicks;
|
||||
|
||||
float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;
|
||||
|
||||
std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
(int)(diff),
|
||||
(int)(diff - idleDiff),
|
||||
(int)(idleDiff),
|
||||
SystemTimers::GetTicksPerSecond() / 1000000,
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
TicksPercentage);
|
||||
|
||||
#else // Summary information
|
||||
std::string SFPS;
|
||||
if (Movie::IsPlayingInput())
|
||||
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
|
||||
else if (Movie::IsRecordingInput())
|
||||
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
|
||||
else
|
||||
SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
#endif
|
||||
|
||||
// This is our final "frame counter" string
|
||||
std::string SMessage = StringFromFormat("%s | %s",
|
||||
SSettings.c_str(), SFPS.c_str());
|
||||
std::string TMessage = StringFromFormat("%s | ", scm_rev_str) +
|
||||
SMessage;
|
||||
|
||||
// Show message
|
||||
g_video_backend->UpdateFPSDisplay(SMessage.c_str());
|
||||
|
||||
// Update the audio timestretcher with the current speed
|
||||
if (soundStream)
|
||||
{
|
||||
CMixer* pMixer = soundStream->GetMixer();
|
||||
pMixer->UpdateSpeed((float)Speed / 100);
|
||||
}
|
||||
|
||||
if (_CoreParameter.bRenderToMain &&
|
||||
SConfig::GetInstance().m_InterfaceStatusbar) {
|
||||
Host_UpdateStatusBar(SMessage.c_str());
|
||||
Host_UpdateTitle(scm_rev_str);
|
||||
} else
|
||||
Host_UpdateTitle(TMessage.c_str());
|
||||
}
|
||||
|
||||
} // Core
|
||||
|
|
|
@ -89,6 +89,8 @@ bool ShouldSkipFrame(int skipped);
|
|||
void VideoThrottle();
|
||||
void RequestRefreshInfo();
|
||||
|
||||
void UpdateTitle();
|
||||
|
||||
// waits until all systems are paused and fully idle, and acquires a lock on that state.
|
||||
// or, if doLock is false, releases a lock on that state and optionally unpauses.
|
||||
// calls must be balanced (once with doLock true, then once with doLock false) but may be recursive.
|
||||
|
|
|
@ -45,11 +45,11 @@ SCoreStartupParameter::SCoreStartupParameter()
|
|||
bEnableFPRF(false),
|
||||
bCPUThread(true), bDSPThread(false), bDSPHLE(true),
|
||||
bSkipIdle(true), bNTSC(false), bForceNTSCJ(false),
|
||||
bHLE_BS2(true), bLockThreads(false),
|
||||
bEnableCheats(false),
|
||||
bHLE_BS2(true), bEnableCheats(false),
|
||||
bMergeBlocks(false),
|
||||
bDPL2Decoder(false), iLatency(14),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
bMMU(false), bMMUBAT(false), iTLBHack(0), bVBeam(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
||||
bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
|
@ -59,7 +59,6 @@ SCoreStartupParameter::SCoreStartupParameter()
|
|||
bRenderWindowAutoSize(false), bKeepWindowOnTop(false),
|
||||
bFullscreen(false), bRenderToMain(false),
|
||||
bProgressive(false), bDisableScreenSaver(false),
|
||||
iTheme(0),
|
||||
iPosX(100), iPosY(100), iWidth(800), iHeight(600)
|
||||
{
|
||||
LoadDefaults();
|
||||
|
@ -74,16 +73,17 @@ void SCoreStartupParameter::LoadDefaults()
|
|||
bRunCompareServer = false;
|
||||
bDSPHLE = true;
|
||||
bDSPThread = true;
|
||||
bLockThreads = true;
|
||||
bEnableFPRF = false;
|
||||
bMMU = false;
|
||||
bMMUBAT = false;
|
||||
bDCBZOFF = false;
|
||||
iTLBHack = 0;
|
||||
bVBeam = false;
|
||||
bFastDiscSpeed = false;
|
||||
bMergeBlocks = false;
|
||||
SelectedLanguage = 0;
|
||||
bWii = false;
|
||||
bDPL2Decoder = false;
|
||||
iLatency = 14;
|
||||
|
||||
iPosX = 100;
|
||||
iPosY = 100;
|
||||
|
@ -348,7 +348,11 @@ void SCoreStartupParameter::CheckMemcardPath(std::string& memcardPath, std::stri
|
|||
{
|
||||
// Use default memcard path if there is no user defined name
|
||||
std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB;
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
#ifdef _WIN32
|
||||
memcardPath = "." + File::GetUserPath(D_GCUSER_IDX).substr(File::GetExeDirectory().size()) + defaultFilename + ext;
|
||||
#else
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -103,15 +103,17 @@ struct SCoreStartupParameter
|
|||
bool bNTSC;
|
||||
bool bForceNTSCJ;
|
||||
bool bHLE_BS2;
|
||||
bool bLockThreads;
|
||||
bool bEnableCheats;
|
||||
bool bMergeBlocks;
|
||||
|
||||
bool bDPL2Decoder;
|
||||
int iLatency;
|
||||
|
||||
bool bRunCompareServer;
|
||||
bool bRunCompareClient;
|
||||
|
||||
bool bMMU;
|
||||
bool bMMUBAT;
|
||||
bool bDCBZOFF;
|
||||
int iTLBHack;
|
||||
bool bVBeam;
|
||||
bool bFastDiscSpeed;
|
||||
|
@ -123,6 +125,7 @@ struct SCoreStartupParameter
|
|||
|
||||
// Interface settings
|
||||
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages;
|
||||
std::string theme_name;
|
||||
|
||||
// Hotkeys
|
||||
int iHotkey[NUM_HOTKEYS];
|
||||
|
@ -136,9 +139,8 @@ struct SCoreStartupParameter
|
|||
bool bFullscreen, bRenderToMain;
|
||||
bool bProgressive, bDisableScreenSaver;
|
||||
|
||||
int iTheme;
|
||||
int iPosX, iPosY, iWidth, iHeight;
|
||||
|
||||
|
||||
enum EBootBS2
|
||||
{
|
||||
BOOT_DEFAULT,
|
||||
|
|
|
@ -104,10 +104,10 @@ bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
|
|||
return code1.size() == code2.size() && code1.size() == count_equal;
|
||||
}
|
||||
|
||||
void GenRandomCode(int size, std::vector<u16> &code)
|
||||
void GenRandomCode(u32 size, std::vector<u16> &code)
|
||||
{
|
||||
code.resize(size);
|
||||
for (int i = 0; i < size; i++)
|
||||
for (u32 i = 0; i < size; i++)
|
||||
{
|
||||
code[i] = rand() ^ (rand() << 8);
|
||||
}
|
||||
|
@ -144,28 +144,28 @@ void CodeToHeader(const std::vector<u16> &code, std::string _filename,
|
|||
}
|
||||
|
||||
void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
|
||||
int numCodes, const char *name, std::string &header)
|
||||
u32 numCodes, const char *name, std::string &header)
|
||||
{
|
||||
std::vector<std::vector<u16> > codes_padded;
|
||||
char buffer[1024];
|
||||
int reserveSize = 0;
|
||||
for(int i = 0; i < numCodes; i++)
|
||||
u32 reserveSize = 0;
|
||||
for(u32 i = 0; i < numCodes; i++)
|
||||
{
|
||||
codes_padded.push_back(codes[i]);
|
||||
// Pad with nops to 32byte boundary
|
||||
while (codes_padded.at(i).size() & 0x7f)
|
||||
codes_padded.at(i).push_back(0);
|
||||
|
||||
reserveSize += (int)codes_padded.at(i).size();
|
||||
reserveSize += (u32)codes_padded.at(i).size();
|
||||
}
|
||||
|
||||
|
||||
header.clear();
|
||||
header.reserve(reserveSize * 4);
|
||||
sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes);
|
||||
sprintf(buffer, "#define NUM_UCODES %u\n\n", numCodes);
|
||||
header.append(buffer);
|
||||
header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n");
|
||||
for (int i = 0; i < numCodes; i++)
|
||||
for (u32 i = 0; i < numCodes; i++)
|
||||
{
|
||||
std::string filename;
|
||||
if (! SplitPath(filenames->at(i), NULL, &filename, NULL))
|
||||
|
@ -176,7 +176,7 @@ void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>
|
|||
header.append("};\n\n");
|
||||
header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n");
|
||||
|
||||
for(int i = 0; i < numCodes; i++)
|
||||
for(u32 i = 0; i < numCodes; i++)
|
||||
{
|
||||
if(codes[i].size() == 0)
|
||||
continue;
|
||||
|
@ -197,7 +197,7 @@ void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>
|
|||
void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
|
||||
{
|
||||
str.resize(code.size() * 2);
|
||||
for (int i = 0; i < (int)code.size(); i++)
|
||||
for (size_t i = 0; i < code.size(); i++)
|
||||
{
|
||||
str[i * 2 + 0] = code[i] >> 8;
|
||||
str[i * 2 + 1] = code[i] & 0xff;
|
||||
|
@ -207,7 +207,7 @@ void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
|
|||
void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
|
||||
{
|
||||
code.resize(str.size() / 2);
|
||||
for (int i = 0; i < (int)code.size(); i++)
|
||||
for (size_t i = 0; i < code.size(); i++)
|
||||
{
|
||||
code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
|
||||
}
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
bool Assemble(const char *text, std::vector<u16> &code, bool force = false);
|
||||
bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
|
||||
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
|
||||
void GenRandomCode(int size, std::vector<u16> &code);
|
||||
void GenRandomCode(u32 size, std::vector<u16> &code);
|
||||
void CodeToHeader(const std::vector<u16> &code, std::string _filename,
|
||||
const char *name, std::string &header);
|
||||
void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
|
||||
int numCodes, const char *name, std::string &header);
|
||||
u32 numCodes, const char *name, std::string &header);
|
||||
|
||||
// Big-endian, for writing straight to file using File::WriteStringToFile.
|
||||
void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
|
||||
DSPEmulator *CreateDSPEmulator(bool HLE)
|
||||
{
|
||||
ac_Config.Load();
|
||||
|
||||
if (HLE)
|
||||
{
|
||||
return new DSPHLE();
|
||||
|
|
|
@ -90,9 +90,9 @@ void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &
|
|||
|
||||
// TODO - figure out a cleaner way.
|
||||
if (Core::g_CoreStartupParameter.bWii)
|
||||
memAddr = bpmem.tmem_config.tlut_src << 5;
|
||||
memAddr = bpMem.tmem_config.tlut_src << 5;
|
||||
else
|
||||
memAddr = (bpmem.tmem_config.tlut_src & 0xFFFFF) << 5;
|
||||
memAddr = (bpMem.tmem_config.tlut_src & 0xFFFFF) << 5;
|
||||
}
|
||||
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
|
||||
|
|
|
@ -33,7 +33,7 @@ struct MemoryUpdate
|
|||
TEXTURE_MAP = 0x01,
|
||||
XF_DATA = 0x02,
|
||||
VERTEX_STREAM = 0x04,
|
||||
TLUT = 0x08
|
||||
TMEM = 0x08,
|
||||
};
|
||||
|
||||
u32 fifoPosition;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include "HW/GPFifo.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
@ -28,7 +27,6 @@
|
|||
#include "PowerPC/PowerPC.h"
|
||||
|
||||
#include "BPMemory.h"
|
||||
#include "CommandProcessor.h"
|
||||
|
||||
FifoPlayer::~FifoPlayer()
|
||||
{
|
||||
|
@ -96,40 +94,7 @@ bool FifoPlayer::Play()
|
|||
if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart)
|
||||
WriteAllMemoryUpdates();
|
||||
|
||||
// Stop Fifo processing until we've written the new frame
|
||||
WriteCP(CommandProcessor::CTRL_REGISTER, 0x10); // disable read & breakpoints, enable GP link
|
||||
|
||||
// Write frame data
|
||||
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
||||
|
||||
// Enable frame processing and break when done
|
||||
u16 write_ptr_lo = ReadCP(CommandProcessor::FIFO_WRITE_POINTER_LO);
|
||||
u16 write_ptr_hi = ReadCP(CommandProcessor::FIFO_WRITE_POINTER_HI);
|
||||
WriteCP(CommandProcessor::FIFO_BP_LO, write_ptr_lo);
|
||||
WriteCP(CommandProcessor::FIFO_BP_HI, write_ptr_hi);
|
||||
WriteCP(CommandProcessor::CTRL_REGISTER, 0x13); // enable read, breakpoints & GP link
|
||||
|
||||
// If necessary, wait until GP has reached the breakpoint to prevent fifo overflows
|
||||
// TODO: Can this be done any better? Dual core mode is slower than single core mode even with these conditions..
|
||||
if (m_CurrentFrame < m_FrameRangeEnd)
|
||||
{
|
||||
// Check if FIFO would be overflown when writing the next frame
|
||||
u32 CPRWDistance = (ReadCP(CommandProcessor::FIFO_RW_DISTANCE_HI)<<16) | ReadCP(CommandProcessor::FIFO_RW_DISTANCE_LO);
|
||||
CPRWDistance += m_File->GetFrame(m_CurrentFrame+1).fifoDataSize + CommandProcessor::GATHER_PIPE_SIZE;
|
||||
u32 CPFifoBase = (ReadCP(CommandProcessor::FIFO_BASE_HI)<<16) | ReadCP(CommandProcessor::FIFO_BASE_LO);
|
||||
u32 CPFifoEnd = (ReadCP(CommandProcessor::FIFO_END_HI)<<16) | ReadCP(CommandProcessor::FIFO_END_LO);
|
||||
|
||||
bool bWait = (CPRWDistance > CPFifoEnd - CPFifoBase);
|
||||
while (bWait && (ReadCP(CommandProcessor::FIFO_READ_POINTER_LO) != write_ptr_lo ||
|
||||
ReadCP(CommandProcessor::FIFO_READ_POINTER_HI) != write_ptr_hi))
|
||||
{
|
||||
Common::YieldCPU();
|
||||
CoreTiming::Advance(); // Process scheduled events (esp. PixelEngine::SetFinish!)
|
||||
|
||||
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]);
|
||||
|
||||
++m_CurrentFrame;
|
||||
}
|
||||
|
@ -422,11 +387,6 @@ void FifoPlayer::LoadMemory()
|
|||
FlushWGP();
|
||||
}
|
||||
|
||||
u16 FifoPlayer::ReadCP(u32 address)
|
||||
{
|
||||
return Memory::Read_U16(0xCC000000 | address);
|
||||
}
|
||||
|
||||
void FifoPlayer::WriteCP(u32 address, u16 value)
|
||||
{
|
||||
Memory::Write_U16(value, 0xCC000000 | address);
|
||||
|
|
|
@ -87,7 +87,6 @@ private:
|
|||
|
||||
void LoadMemory();
|
||||
|
||||
u16 ReadCP(u32 address);
|
||||
void WriteCP(u32 address, u16 value);
|
||||
void WritePI(u32 address, u32 value);
|
||||
|
||||
|
|
|
@ -114,6 +114,8 @@ void FifoRecordAnalyzer::DecodeOpcode(u8 *data)
|
|||
|
||||
if (bp.address == BPMEM_LOADTLUT1)
|
||||
ProcessLoadTlut1();
|
||||
if (bp.address == BPMEM_PRELOAD_MODE)
|
||||
ProcessPreloadTexture();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -143,7 +145,16 @@ void FifoRecordAnalyzer::ProcessLoadTlut1()
|
|||
|
||||
GetTlutLoadData(tlutMemAddr, memAddr, tlutXferCount, *m_BpMem);
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(memAddr, tlutXferCount, MemoryUpdate::TLUT);
|
||||
FifoRecorder::GetInstance().WriteMemory(memAddr, tlutXferCount, MemoryUpdate::TMEM);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessPreloadTexture()
|
||||
{
|
||||
BPS_TmemConfig& tmem_cfg = m_BpMem->tmem_config;
|
||||
//u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE; // TODO: Should this be half size for RGBA8 preloads?
|
||||
|
||||
FifoRecorder::GetInstance().WriteMemory(tmem_cfg.preload_addr << 5, size, MemoryUpdate::TMEM);
|
||||
}
|
||||
|
||||
void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array)
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
void DecodeOpcode(u8 *data);
|
||||
|
||||
void ProcessLoadTlut1();
|
||||
void ProcessPreloadTexture();
|
||||
void ProcessLoadIndexedXf(u32 val, int array);
|
||||
void ProcessVertexArrays(u8 *data, u8 vtxAttrGroup);
|
||||
void ProcessTexMaps();
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <map>
|
||||
#include "Common.h"
|
||||
|
||||
#include "HLE.h"
|
||||
|
@ -27,6 +26,9 @@
|
|||
|
||||
#include "HLE_OS.h"
|
||||
#include "HLE_Misc.h"
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_es.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "Core.h"
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
|
@ -45,55 +47,72 @@ struct SPatch
|
|||
{
|
||||
char m_szPatchName[128];
|
||||
TPatchFunction PatchFunction;
|
||||
int type;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static const SPatch OSPatches[] =
|
||||
{
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// speedup
|
||||
//{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse },
|
||||
//{ "THPPlayerGetState", HLE_Misc:THPPlayerGetState },
|
||||
//{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "THPPlayerGetState", HLE_Misc:THPPlayerGetState, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "memcpy", HLE_Misc::gc_memcpy, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memcmp", HLE_Misc::gc_memcmp, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memset", HLE_Misc::gc_memset, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memmove", HLE_Misc::gc_memmove, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
|
||||
//{ "__div2i", HLE_Misc::div2i, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, // Slower?
|
||||
//{ "__div2u", HLE_Misc::div2u, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, // Slower?
|
||||
|
||||
//{ "DCFlushRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "DCInvalidateRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "DCZeroRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// debug out is very nice ;)
|
||||
{ "OSReport", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "OSPanic", HLE_OS::HLE_OSPanic },
|
||||
{ "vprintf", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "printf", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "puts", HLE_OS::HLE_GeneralDebugPrint }, // gcc-optimized printf?
|
||||
{ "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint }, // used for early init things (normally)
|
||||
{ "___blank", HLE_OS::HLE_GeneralDebugPrint },
|
||||
{ "__write_console", HLE_OS::HLE_write_console }, // used by sysmenu (+more?)
|
||||
{ "OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // gcc-optimized printf?
|
||||
{ "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used for early init things (normally)
|
||||
{ "___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used by sysmenu (+more?)
|
||||
|
||||
// wii only
|
||||
//{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction },
|
||||
//{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// Super Monkey Ball - no longer needed.
|
||||
//{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine },
|
||||
//{ ".evil_normalize", HLE_Misc::SMB_EvilNormalize },
|
||||
//{ ".evil_vec_setlength", HLE_Misc::SMB_evil_vec_setlength },
|
||||
//{ ".evil_vec_something", HLE_Misc::FZero_evil_vec_normalize },
|
||||
{ "PanicAlert", HLE_Misc::HLEPanicAlert },
|
||||
//{ ".sqrt_internal_needs_cr1", HLE_Misc::SMB_sqrt_internal },
|
||||
//{ ".rsqrt_internal_needs_cr1", HLE_Misc::SMB_rsqrt_internal },
|
||||
//{ ".atan2", HLE_Misc::SMB_atan2},
|
||||
//{ ".sqrt_fz", HLE_Misc::FZ_sqrt},
|
||||
//{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_normalize", HLE_Misc::SMB_EvilNormalize, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_vec_setlength", HLE_Misc::SMB_evil_vec_setlength, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_vec_something", HLE_Misc::FZero_evil_vec_normalize, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
{ "PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
//{ ".sqrt_internal_needs_cr1", HLE_Misc::SMB_sqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".rsqrt_internal_needs_cr1", HLE_Misc::SMB_rsqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".atan2", HLE_Misc::SMB_atan2HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".sqrt_fz", HLE_Misc::FZ_sqrtHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// F-zero still isn't working correctly, but these aren't really helping.
|
||||
|
||||
//{ ".sqrt_internal_fz", HLE_Misc::FZ_sqrt_internal },
|
||||
//{ ".rsqrt_internal_fz", HLE_Misc::FZ_rsqrt_internal },
|
||||
//{ ".sqrt_internal_fz", HLE_Misc::FZ_sqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".rsqrt_internal_fz", HLE_Misc::FZ_rsqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
//{ ".kill_infinites", HLE_Misc::FZero_kill_infinites },
|
||||
//{ ".kill_infinites", HLE_Misc::FZero_kill_infinites, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
// special
|
||||
// { "GXPeekZ", HLE_Misc::GXPeekZ},
|
||||
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
|
||||
// { "GXPeekZ", HLE_Misc::GXPeekZHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
// { "GXPeekARGB", HLE_Misc::GXPeekARGBHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// Name doesn't matter, installed in CBoot::BootUp()
|
||||
{ "HBReload", HLE_Misc::HBReload },
|
||||
{ "HBReload", HLE_Misc::HBReload, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// ES_LAUNCH
|
||||
{ "__OSBootDol", HLE_Misc::OSBootDol, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
{ "OSGetResetCode", HLE_Misc::OSGetResetCode, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
};
|
||||
|
||||
static const SPatch OSBreakPoints[] =
|
||||
|
@ -101,17 +120,13 @@ static const SPatch OSBreakPoints[] =
|
|||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
};
|
||||
|
||||
|
||||
static std::map<u32, u32> orig_instruction;
|
||||
|
||||
void Patch(u32 address, const char *hle_func_name)
|
||||
void Patch(u32 addr, const char *hle_func_name)
|
||||
{
|
||||
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
||||
{
|
||||
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name))
|
||||
{
|
||||
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
||||
Memory::Write_U32(HLEPatchValue | i, address);
|
||||
orig_instruction[addr] = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -125,23 +140,24 @@ void PatchFunctions()
|
|||
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||
if (symbol > 0)
|
||||
{
|
||||
u32 HLEPatchValue = (1 & 0x3f) << 26;
|
||||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||
{
|
||||
orig_instruction[addr] = Memory::ReadUnchecked_U32(addr);
|
||||
Memory::Write_U32(HLEPatchValue | i, addr);
|
||||
orig_instruction[addr] = i;
|
||||
}
|
||||
INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||
if (symbol > 0)
|
||||
for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
||||
{
|
||||
PowerPC::breakpoints.Add(symbol->address, false);
|
||||
INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
|
||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||
if (symbol > 0)
|
||||
{
|
||||
PowerPC::breakpoints.Add(symbol->address, false);
|
||||
INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,10 +179,46 @@ void Execute(u32 _CurrentPC, u32 _Instruction)
|
|||
// _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName);
|
||||
}
|
||||
|
||||
u32 GetOrigInstruction(u32 addr)
|
||||
u32 GetFunctionIndex(u32 addr)
|
||||
{
|
||||
std::map<u32, u32>::const_iterator iter = orig_instruction.find(addr);
|
||||
return (iter != orig_instruction.end()) ? iter->second : 0;
|
||||
}
|
||||
|
||||
int GetFunctionTypeByIndex(u32 index)
|
||||
{
|
||||
return OSPatches[index].type;
|
||||
}
|
||||
|
||||
int GetFunctionFlagsByIndex(u32 index)
|
||||
{
|
||||
return OSPatches[index].flags;
|
||||
}
|
||||
|
||||
bool IsEnabled(int flags)
|
||||
{
|
||||
if (flags == HLE::HLE_TYPE_MEMORY && Core::g_CoreStartupParameter.bMMU)
|
||||
return false;
|
||||
|
||||
if (flags == HLE::HLE_TYPE_DEBUG && !Core::g_CoreStartupParameter.bEnableDebugging && PowerPC::GetMode() != MODE_INTERPRETER)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 UnPatch(std::string patchName)
|
||||
{
|
||||
Symbol *symbol = g_symbolDB.GetSymbolFromName(patchName.c_str());
|
||||
if (symbol > 0)
|
||||
{
|
||||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||
{
|
||||
orig_instruction[addr] = 0;
|
||||
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||
}
|
||||
return symbol->address;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end of namespace HLE
|
||||
|
|
|
@ -18,15 +18,40 @@
|
|||
#ifndef _HLE_H
|
||||
#define _HLE_H
|
||||
|
||||
#include <map>
|
||||
#include "Common.h"
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
enum
|
||||
{
|
||||
HLE_HOOK_START = 0, // Hook the beginning of the function and execute the function afterwards
|
||||
HLE_HOOK_END = 1, // Hook the end of the function, executing the function first before the hook
|
||||
HLE_HOOK_REPLACE = 2, // Replace the function with the HLE version
|
||||
HLE_HOOK_NONE = 3, // Do not hook the function
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
HLE_TYPE_GENERIC = 0, // Miscellaneous function
|
||||
HLE_TYPE_MEMORY = 1, // Memory operation
|
||||
HLE_TYPE_FP = 2, // Floating Point operation
|
||||
HLE_TYPE_DEBUG = 3, // Debug output function
|
||||
};
|
||||
|
||||
void PatchFunctions();
|
||||
|
||||
void Patch(u32 pc, const char *func_name);
|
||||
u32 UnPatch(std::string patchName);
|
||||
void Execute(u32 _CurrentPC, u32 _Instruction);
|
||||
|
||||
u32 GetOrigInstruction(u32 em_address);
|
||||
u32 GetFunctionIndex(u32 em_address);
|
||||
int GetFunctionTypeByIndex(u32 index);
|
||||
int GetFunctionFlagsByIndex(u32 index);
|
||||
|
||||
bool IsEnabled(int flags);
|
||||
|
||||
static std::map<u32, u32> orig_instruction;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,10 +22,25 @@
|
|||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../Host.h"
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_DI.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "VolumeCreator.h"
|
||||
#include "Filesystem.h"
|
||||
#include "../Boot/Boot_DOL.h"
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
||||
#include "HLE.h"
|
||||
#include "PowerPC/PPCAnalyst.h"
|
||||
#include "PowerPC/SignatureDB.h"
|
||||
#include "PowerPC/PPCSymbolDB.h"
|
||||
#include "CommonPaths.h"
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
|
||||
std::string args;
|
||||
u32 argsPtr;
|
||||
u32 bootType;
|
||||
|
||||
// Helper to quickly read the floating point value at a memory location.
|
||||
inline float F(u32 addr)
|
||||
{
|
||||
|
@ -282,4 +297,253 @@ void HBReload()
|
|||
Host_Message(WM_USER_STOP);
|
||||
}
|
||||
|
||||
void ExecuteDOL(u8* dolFile, u32 fileSize)
|
||||
{
|
||||
// Clear memory before loading the dol
|
||||
for (u32 i = 0x80004000; i < Memory::Read_U32(0x00000034); i += 4)
|
||||
{
|
||||
// TODO: Should not write over the "save region"
|
||||
Memory::Write_U32(0x00000000, i);
|
||||
}
|
||||
CDolLoader dolLoader(dolFile, fileSize);
|
||||
dolLoader.Load();
|
||||
|
||||
// Scan for common HLE functions
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
g_symbolDB.Clear();
|
||||
PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB);
|
||||
SignatureDB db;
|
||||
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
|
||||
{
|
||||
db.Apply(&g_symbolDB);
|
||||
HLE::PatchFunctions();
|
||||
db.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
|
||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
size_t size = s_Usb->m_WiiMotes.size();
|
||||
bool* wiiMoteConnected = new bool[size];
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
|
||||
|
||||
WII_IPC_HLE_Interface::Reset(true);
|
||||
WII_IPC_HLE_Interface::Init();
|
||||
s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
|
||||
{
|
||||
if (wiiMoteConnected[i])
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
s_Usb->m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] wiiMoteConnected;
|
||||
|
||||
if (argsPtr)
|
||||
{
|
||||
u32 args_base = Memory::Read_U32(0x800000f4);
|
||||
u32 ptr_to_num_args = 0xc;
|
||||
u32 num_args = 1;
|
||||
u32 hi_ptr = args_base + ptr_to_num_args + 4;
|
||||
u32 new_args_ptr = args_base + ptr_to_num_args + 8;
|
||||
|
||||
Memory::Write_U32(ptr_to_num_args, args_base + 8);
|
||||
Memory::Write_U32(num_args, args_base + ptr_to_num_args);
|
||||
Memory::Write_U32(0x14, hi_ptr);
|
||||
|
||||
for (unsigned int i = 0; i < args.length(); i++)
|
||||
Memory::WriteUnchecked_U8(args[i], new_args_ptr+i);
|
||||
}
|
||||
|
||||
NPC = dolLoader.GetEntryPoint() | 0x80000000;
|
||||
}
|
||||
|
||||
void LoadDOLFromDisc(std::string dol)
|
||||
{
|
||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
|
||||
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);
|
||||
|
||||
if (dol.length() > 1 && dol.compare(0, 1, "/") == 0)
|
||||
dol = dol.substr(1);
|
||||
|
||||
u32 fileSize = (u32) pFileSystem->GetFileSize(dol.c_str());
|
||||
u8* dolFile = new u8[fileSize];
|
||||
if (fileSize > 0)
|
||||
{
|
||||
pFileSystem->ReadFile(dol.c_str(), dolFile, fileSize);
|
||||
ExecuteDOL(dolFile, fileSize);
|
||||
}
|
||||
delete[] dolFile;
|
||||
}
|
||||
|
||||
void LoadBootDOLFromDisc()
|
||||
{
|
||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
|
||||
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);
|
||||
u32 fileSize = pFileSystem->GetBootDOLSize();
|
||||
u8* dolFile = new u8[fileSize];
|
||||
if (fileSize > 0)
|
||||
{
|
||||
pFileSystem->GetBootDOL(dolFile, fileSize);
|
||||
ExecuteDOL(dolFile, fileSize);
|
||||
}
|
||||
delete[] dolFile;
|
||||
}
|
||||
|
||||
u32 GetDolFileSize(std::string dol)
|
||||
{
|
||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(SConfig::GetInstance().m_LastFilename.c_str());
|
||||
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);
|
||||
|
||||
std::string dolFile;
|
||||
|
||||
if (dol.length() > 1 && dol.compare(0, 1, "/") == 0)
|
||||
dolFile = dol.substr(1);
|
||||
else
|
||||
dolFile = dol;
|
||||
|
||||
return (u32)pFileSystem->GetFileSize(dolFile.c_str());
|
||||
}
|
||||
|
||||
void gc_memmove()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memmove((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memcpy()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memcpy((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memset()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 ch = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memset((u8*)(Memory::base + dest), ch, count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memcmp()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
GPR(3) = memcmp((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void div2i()
|
||||
{
|
||||
s64 num = (s64)(GPR(3)) << 32 | GPR(4);
|
||||
s64 den = (s64)(GPR(5)) << 32 | GPR(6);
|
||||
s64 quo = num / den;
|
||||
GPR(3) = quo >> 32;
|
||||
GPR(4) = quo & 0xffffffff;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void div2u()
|
||||
{
|
||||
u64 num = (u64)(GPR(3)) << 32 | GPR(4);
|
||||
u64 den = (u64)(GPR(5)) << 32 | GPR(6);
|
||||
u64 quo = num / den;
|
||||
GPR(3) = quo >> 32;
|
||||
GPR(4) = quo & 0xffffffff;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void OSGetResetCode()
|
||||
{
|
||||
u32 resetCode = Memory::Read_U32(0xCC003024);
|
||||
|
||||
if ((resetCode & 0x1fffffff) != 0)
|
||||
{
|
||||
GPR(3) = resetCode | 0x80000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPR(3) = 0;
|
||||
}
|
||||
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
u16 GetIOSVersion()
|
||||
{
|
||||
return Memory::Read_U16(0x00003140);
|
||||
}
|
||||
|
||||
void OSBootDol()
|
||||
{
|
||||
if (GetIOSVersion() >= 30)
|
||||
{
|
||||
bootType = GPR(4);
|
||||
|
||||
if ((GPR(4) >> 28) == 0x8)
|
||||
{
|
||||
u32 resetCode = GPR(30);
|
||||
|
||||
// Reset game
|
||||
Memory::Write_U32(resetCode, 0xCC003024);
|
||||
LoadBootDOLFromDisc();
|
||||
return;
|
||||
}
|
||||
else if ((GPR(4) >> 28) == 0xA)
|
||||
{
|
||||
// Boot from disc partition
|
||||
PanicAlert("Boot Partition: %08x", GPR(26));
|
||||
}
|
||||
else if ((GPR(4) >> 28) == 0xC)
|
||||
{
|
||||
std::string dol;
|
||||
|
||||
// Boot DOL from disc
|
||||
u32 ptr = GPR(28);
|
||||
Memory::GetString(dol, ptr);
|
||||
|
||||
if (GetDolFileSize(dol) == 0)
|
||||
{
|
||||
ptr = GPR(30);
|
||||
Memory::GetString(dol, ptr);
|
||||
if (GetDolFileSize(dol) == 0)
|
||||
{
|
||||
// Cannot locate the dol file, exit.
|
||||
HLE::UnPatch("__OSBootDol");
|
||||
NPC = PC;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
argsPtr = Memory::Read_U32(GPR(5));
|
||||
Memory::GetString(args, argsPtr);
|
||||
LoadDOLFromDisc(dol);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Unknown boot type: %08x", GPR(4));
|
||||
}
|
||||
}
|
||||
HLE::UnPatch("__OSBootDol");
|
||||
NPC = PC;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,15 @@ namespace HLE_Misc
|
|||
void FZ_sqrt_internal();
|
||||
void FZ_rsqrt_internal();
|
||||
void HBReload();
|
||||
void OSBootDol();
|
||||
void OSGetResetCode();
|
||||
void memcpy();
|
||||
void memset();
|
||||
void memmove();
|
||||
void memcmp();
|
||||
void div2i();
|
||||
void div2u();
|
||||
void ExecuteDOL(u8* dolFile, u32 fileSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,10 +37,6 @@ namespace
|
|||
|
||||
void CCPU::Init(int cpu_core)
|
||||
{
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
cpu_core = Movie::GetCPUMode();
|
||||
}
|
||||
PowerPC::Init(cpu_core);
|
||||
m_SyncEvent = 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "DSPHLE.h"
|
||||
#include "UCodes/UCodes.h"
|
||||
#include "../AudioInterface.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
DSPHLE::DSPHLE() {
|
||||
m_InitMixer = false;
|
||||
|
@ -251,7 +252,7 @@ void DSPHLE::InitMixer()
|
|||
unsigned int AISampleRate, DACSampleRate;
|
||||
AudioInterface::Callback_GetSampleRate(AISampleRate, DACSampleRate);
|
||||
delete soundStream;
|
||||
soundStream = AudioCommon::InitSoundStream(new HLEMixer(this, AISampleRate, DACSampleRate, ac_Config.iFrequency), m_hWnd);
|
||||
soundStream = AudioCommon::InitSoundStream(new HLEMixer(this, AISampleRate, DACSampleRate, 48000), m_hWnd);
|
||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||
// Mixer is initialized
|
||||
m_InitMixer = true;
|
||||
|
|
|
@ -104,27 +104,6 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
|
|||
{
|
||||
Common::SetCurrentThreadName("DSP thread");
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bLockThreads)
|
||||
{
|
||||
if (cpu_info.num_cores > 3)
|
||||
{
|
||||
// HACK (delroth): there is no way to know where hyperthreads are in
|
||||
// the current Dolphin version.
|
||||
bool windows = false;
|
||||
#ifdef _WIN32
|
||||
windows = true;
|
||||
#endif
|
||||
|
||||
u8 core_id;
|
||||
if (windows && cpu_info.num_cores > 4) // Probably HT
|
||||
core_id = 5; // 3rd non HT core
|
||||
else
|
||||
core_id = 3; // 3rd core
|
||||
|
||||
Common::SetCurrentThreadAffinity(1 << (core_id - 1));
|
||||
}
|
||||
}
|
||||
|
||||
while (dsp_lle->m_bIsRunning)
|
||||
{
|
||||
int cycles = (int)dsp_lle->m_cycle_count;
|
||||
|
@ -204,7 +183,7 @@ void DSPLLE::InitMixer()
|
|||
unsigned int AISampleRate, DACSampleRate;
|
||||
AudioInterface::Callback_GetSampleRate(AISampleRate, DACSampleRate);
|
||||
delete soundStream;
|
||||
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DACSampleRate, ac_Config.iFrequency), m_hWnd);
|
||||
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DACSampleRate, 48000), m_hWnd);
|
||||
if(!soundStream) PanicAlert("Error starting up sound stream");
|
||||
// Mixer is initialized
|
||||
m_InitMixer = true;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "EXI.h"
|
||||
#include "Sram.h"
|
||||
#include "../Movie.h"
|
||||
SRAM g_SRAM;
|
||||
|
||||
namespace ExpansionInterface
|
||||
|
@ -44,7 +45,12 @@ void Init()
|
|||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||
g_Channels[i] = new CEXIChannel(i);
|
||||
|
||||
g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA
|
||||
if (Movie::IsPlayingInput() && Movie::IsUsingMemcard() && Movie::IsConfigSaved())
|
||||
g_Channels[0]->AddDevice(EXIDEVICE_MEMORYCARD, 0); // SlotA
|
||||
else if(Movie::IsPlayingInput() && !Movie::IsUsingMemcard() && Movie::IsConfigSaved())
|
||||
g_Channels[0]->AddDevice(EXIDEVICE_NONE, 0); // SlotA
|
||||
else
|
||||
g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA
|
||||
g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1);
|
||||
g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1
|
||||
g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "ControllerInterface/ControllerInterface.h"
|
||||
#include "GCPadEmu.h"
|
||||
#include "../ConfigManager.h"
|
||||
|
||||
#include "../../InputCommon/Src/InputConfig.h"
|
||||
|
||||
|
@ -55,7 +56,7 @@ void Initialize(void* const hwnd)
|
|||
g_controller_interface.Initialize();
|
||||
|
||||
// load the saved controller config
|
||||
g_plugin.LoadConfig();
|
||||
g_plugin.LoadConfig(true);
|
||||
}
|
||||
|
||||
void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
|
||||
|
@ -101,7 +102,36 @@ void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
|||
{
|
||||
// TODO: this has potential to not stop rumble if user is messing with GUI at the perfect time
|
||||
// set rumble
|
||||
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( 1 == _uType && _uStrength > 2 );
|
||||
if (1 == _uType && _uStrength > 2)
|
||||
{
|
||||
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput(255);
|
||||
}
|
||||
else
|
||||
{
|
||||
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Motor
|
||||
// Purpose: For devices with constant Force feedback
|
||||
// input: Type - 06 = Motor On, 04 = Motor Off
|
||||
// Strength - 00 = Left Strong, 127 = Left Weak, 128 = Right Weak, 255 = Right Strong
|
||||
// output: none
|
||||
//
|
||||
void Motor(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lk(g_plugin.controls_lock, std::try_to_lock);
|
||||
|
||||
if (lk.owns_lock())
|
||||
{
|
||||
// TODO: this has potential to not stop rumble if user is messing with GUI at the perfect time
|
||||
// set rumble
|
||||
if (_uType == 6)
|
||||
{
|
||||
((GCPad*)g_plugin.controllers[ _numPAD ])->SetMotor(_uStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ InputPlugin *GetPlugin();
|
|||
|
||||
void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus);
|
||||
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
|
||||
void Motor(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
|
||||
|
||||
bool GetMicButton(u8 pad);
|
||||
}
|
||||
|
|
|
@ -130,7 +130,21 @@ void GCPad::GetInput(SPADStatus* const pad)
|
|||
}
|
||||
}
|
||||
|
||||
void GCPad::SetOutput(const bool on)
|
||||
void GCPad::SetMotor(const u8 on)
|
||||
{
|
||||
float state = (float)on / 255;
|
||||
float force = abs(state - 0.5) * 2;
|
||||
if (state < 0.5)
|
||||
force = -force;
|
||||
|
||||
// only rumble if window has focus or background input is enabled
|
||||
if (Host_RendererHasFocus() || m_options[0].settings[0]->value)
|
||||
m_rumble->controls[0]->control_ref->State(force);
|
||||
else
|
||||
m_rumble->controls[0]->control_ref->State(0);
|
||||
}
|
||||
|
||||
void GCPad::SetOutput(const u8 on)
|
||||
{
|
||||
// only rumble if window has focus or background input is enabled
|
||||
m_rumble->controls[0]->control_ref->State(on && (Host_RendererHasFocus() || m_options[0].settings[0]->value));
|
||||
|
|
|
@ -28,7 +28,8 @@ public:
|
|||
|
||||
GCPad(const unsigned int index);
|
||||
void GetInput(SPADStatus* const pad);
|
||||
void SetOutput(const bool on);
|
||||
void SetOutput(const u8 on);
|
||||
void SetMotor(const u8 on);
|
||||
|
||||
bool GetMicButton() const;
|
||||
|
||||
|
|
|
@ -416,10 +416,7 @@ bool AreMemoryBreakpointsActivated()
|
|||
u32 Read_Instruction(const u32 em_address)
|
||||
{
|
||||
UGeckoInstruction inst = ReadUnchecked_U32(em_address);
|
||||
if (inst.OPCD == 1)
|
||||
return HLE::GetOrigInstruction(em_address);
|
||||
else
|
||||
return inst.hex;
|
||||
return inst.hex;
|
||||
}
|
||||
|
||||
u32 Read_Opcode_JIT_Uncached(const u32 _Address)
|
||||
|
|
|
@ -956,7 +956,7 @@ u32 TranslateAddress(const u32 _Address, const XCheckTLBFlag _Flag)
|
|||
// Check MSR[DR] bit before translating data addresses
|
||||
//if (((_Flag == FLAG_READ) || (_Flag == FLAG_WRITE)) && !(MSR & (1 << (31 - 27)))) return _Address;
|
||||
|
||||
u32 tlb_addr = Core::g_CoreStartupParameter.bMMUBAT?TranslateBlockAddress(_Address, _Flag):0;
|
||||
u32 tlb_addr = TranslateBlockAddress(_Address, _Flag);
|
||||
if (tlb_addr == 0)
|
||||
{
|
||||
tlb_addr = TranslatePageAddress(_Address, _Flag);
|
||||
|
|
|
@ -96,8 +96,7 @@ void Init()
|
|||
m_FlipperRev = 0x246500B1; // revision C
|
||||
m_Unknown = 0;
|
||||
|
||||
// Bleh, why?
|
||||
//m_ResetCode |= 0x80000000;
|
||||
m_ResetCode = 0x80000000; // Cold reset
|
||||
m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI;
|
||||
|
||||
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", &ToggleResetButtonCallback);
|
||||
|
@ -199,6 +198,7 @@ void Write32(const u32 _uValue, const u32 _iAddress)
|
|||
|
||||
case PI_RESET_CODE:
|
||||
DEBUG_LOG(PROCESSORINTERFACE, "Write %08x to PI_RESET_CODE", _uValue);
|
||||
m_ResetCode = _uValue;
|
||||
break;
|
||||
|
||||
case PI_FLIPPER_UNK:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "SI_Device.h"
|
||||
#include "SI_DeviceGCController.h"
|
||||
#include "SI_DeviceGCSteeringWheel.h"
|
||||
#include "SI_DeviceGBA.h"
|
||||
#include "SI_DeviceAMBaseboard.h"
|
||||
|
||||
|
@ -76,6 +77,10 @@ ISIDevice* SIDevice_Create(const SIDevices device, const int port_number)
|
|||
return new CSIDevice_GCController(device, port_number);
|
||||
break;
|
||||
|
||||
case SIDEVICE_GC_STEERING:
|
||||
return new CSIDevice_GCSteeringWheel(device, port_number);
|
||||
break;
|
||||
|
||||
case SIDEVICE_GC_TARUKONGA:
|
||||
return new CSIDevice_TaruKonga(device, port_number);
|
||||
break;
|
||||
|
|
314
Source/Core/Core/Src/HW/SI_DeviceGCSteeringWheel.cpp
Normal file
314
Source/Core/Core/Src/HW/SI_DeviceGCSteeringWheel.cpp
Normal file
|
@ -0,0 +1,314 @@
|
|||
// 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SI.h"
|
||||
#include "SI_Device.h"
|
||||
#include "SI_DeviceGCSteeringWheel.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceMic.h"
|
||||
|
||||
#include "GCPad.h"
|
||||
|
||||
#include "../Movie.h"
|
||||
|
||||
#include "../CoreTiming.h"
|
||||
#include "SystemTimers.h"
|
||||
#include "ProcessorInterface.h"
|
||||
#include "../Core.h"
|
||||
|
||||
// --- standard gamecube controller ---
|
||||
CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber)
|
||||
: ISIDevice(device, _iDeviceNumber)
|
||||
, m_TButtonComboStart(0)
|
||||
, m_TButtonCombo(0)
|
||||
, m_LastButtonCombo(COMBO_NONE)
|
||||
{
|
||||
memset(&m_Origin, 0, sizeof(SOrigin));
|
||||
m_Origin.uCommand = CMD_ORIGIN;
|
||||
m_Origin.uOriginStickX = 0x80; // center
|
||||
m_Origin.uOriginStickY = 0x80;
|
||||
m_Origin.uSubStickStickX = 0x80;
|
||||
m_Origin.uSubStickStickY = 0x80;
|
||||
m_Origin.uTrigger_L = 0x1F; // 0-30 is the lower deadzone
|
||||
m_Origin.uTrigger_R = 0x1F;
|
||||
|
||||
// Dunno if we need to do this, game/lib should set it?
|
||||
m_Mode = 0x03;
|
||||
}
|
||||
|
||||
int CSIDevice_GCSteeringWheel::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
{
|
||||
// For debug logging only
|
||||
ISIDevice::RunBuffer(_pBuffer, _iLength);
|
||||
|
||||
// Read the command
|
||||
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
|
||||
|
||||
// Handle it
|
||||
switch (command)
|
||||
{
|
||||
case CMD_RESET:
|
||||
*(u32*)&_pBuffer[0] = SI_GC_STEERING;
|
||||
break;
|
||||
|
||||
case CMD_ORIGIN:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
|
||||
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
|
||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||
{
|
||||
_pBuffer[i ^ 3] = *pCalibration++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Recalibrate (FiRES: i am not 100 percent sure about this)
|
||||
case CMD_RECALIBRATE:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
|
||||
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
|
||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||
{
|
||||
_pBuffer[i ^ 3] = *pCalibration++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Seen in F-Zero GX
|
||||
case CMD_MOTOR_OFF:
|
||||
break;
|
||||
|
||||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return _iLength;
|
||||
}
|
||||
|
||||
|
||||
// GetData
|
||||
|
||||
// Return true on new data (max 7 Bytes and 6 bits ;)
|
||||
// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r]
|
||||
// |\_ ERR_LATCH (error latched - check SISR)
|
||||
// |_ ERR_STATUS (error on last GetData or SendCmd?)
|
||||
bool CSIDevice_GCSteeringWheel::GetData(u32& _Hi, u32& _Low)
|
||||
{
|
||||
SPADStatus PadStatus;
|
||||
memset(&PadStatus, 0, sizeof(PadStatus));
|
||||
|
||||
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||
Movie::CallInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
|
||||
u32 netValues[2];
|
||||
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus, netValues))
|
||||
{
|
||||
_Hi = netValues[0]; // first 4 bytes
|
||||
_Low = netValues[1]; // last 4 bytes
|
||||
return true;
|
||||
}
|
||||
|
||||
Movie::SetPolledDevice();
|
||||
|
||||
if(Movie::IsPlayingInput())
|
||||
{
|
||||
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else if(Movie::IsRecordingInput())
|
||||
{
|
||||
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else
|
||||
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
|
||||
// Thankfully changing mode does not change the high bits ;)
|
||||
_Hi = (u32)((u8)PadStatus.stickX); // Steering
|
||||
_Hi |= 0x800; // Pedal connected flag
|
||||
_Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16);
|
||||
|
||||
// Low bits are packed differently per mode
|
||||
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 7)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits
|
||||
}
|
||||
else if (m_Mode == 1)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
|
||||
}
|
||||
else if (m_Mode == 2)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 16); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 20); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
|
||||
}
|
||||
else if (m_Mode == 3)
|
||||
{
|
||||
// Analog A/B are always 0
|
||||
_Low = (u8)PadStatus.triggerRight; // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
|
||||
}
|
||||
else if (m_Mode == 4)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
|
||||
// triggerLeft/Right are always 0
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
|
||||
}
|
||||
else if (m_Mode == 6)
|
||||
{
|
||||
_Low = (u8)PadStatus.triggerRight; // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
|
||||
|
||||
// The GC Steering Wheel appears to have combined pedals
|
||||
// (both the Accelerate and Brake pedals are mapped to a single axis)
|
||||
// We use the stickY axis for the pedals.
|
||||
if (PadStatus.stickY < 128)
|
||||
_Low |= (u32)((u8)(255 - ((PadStatus.stickY & 0x7f) * 2)) << 16); // All 8 bits (Brake)
|
||||
if (PadStatus.stickY >= 128)
|
||||
_Low |= (u32)((u8)((PadStatus.stickY & 0x7f) * 2) << 24); // All 8 bits (Accelerate)
|
||||
}
|
||||
|
||||
// Keep track of the special button combos (embedded in controller hardware... :( )
|
||||
EButtonCombo tempCombo;
|
||||
if ((PadStatus.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START))
|
||||
tempCombo = COMBO_ORIGIN;
|
||||
else if ((PadStatus.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START))
|
||||
tempCombo = COMBO_RESET;
|
||||
else
|
||||
tempCombo = COMBO_NONE;
|
||||
if (tempCombo != m_LastButtonCombo)
|
||||
{
|
||||
m_LastButtonCombo = tempCombo;
|
||||
if (m_LastButtonCombo != COMBO_NONE)
|
||||
m_TButtonComboStart = CoreTiming::GetTicks();
|
||||
}
|
||||
if (m_LastButtonCombo != COMBO_NONE)
|
||||
{
|
||||
m_TButtonCombo = CoreTiming::GetTicks();
|
||||
if ((m_TButtonCombo - m_TButtonComboStart) > SystemTimers::GetTicksPerSecond() * 3)
|
||||
{
|
||||
if (m_LastButtonCombo == COMBO_RESET)
|
||||
ProcessorInterface::ResetButton_Tap();
|
||||
else if (m_LastButtonCombo == COMBO_ORIGIN)
|
||||
{
|
||||
m_Origin.uOriginStickX = PadStatus.stickX;
|
||||
m_Origin.uOriginStickY = PadStatus.stickY;
|
||||
m_Origin.uSubStickStickX = PadStatus.substickX;
|
||||
m_Origin.uSubStickStickY = PadStatus.substickY;
|
||||
m_Origin.uTrigger_L = PadStatus.triggerLeft;
|
||||
m_Origin.uTrigger_R = PadStatus.triggerRight;
|
||||
}
|
||||
m_LastButtonCombo = COMBO_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// SendCommand
|
||||
void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
{
|
||||
UCommand command(_Cmd);
|
||||
|
||||
switch (command.Command)
|
||||
{
|
||||
// Costis sent it in some demos :)
|
||||
case 0x00:
|
||||
break;
|
||||
|
||||
case CMD_FORCE:
|
||||
{
|
||||
unsigned int uStrength = command.Parameter1; // 0 = left strong, 127 = left weak, 128 = right weak, 255 = right strong
|
||||
unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Motor(numPAD, uType, uStrength);
|
||||
|
||||
if (!_Poll)
|
||||
{
|
||||
m_Mode = command.Parameter2;
|
||||
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_WRITE:
|
||||
{
|
||||
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
|
||||
unsigned int uStrength = command.Parameter2;
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Rumble(numPAD, uType, uStrength);
|
||||
|
||||
if (!_Poll)
|
||||
{
|
||||
m_Mode = command.Parameter2;
|
||||
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Savestate support
|
||||
void CSIDevice_GCSteeringWheel::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(m_Origin);
|
||||
p.Do(m_Mode);
|
||||
p.Do(m_TButtonComboStart);
|
||||
p.Do(m_TButtonCombo);
|
||||
p.Do(m_LastButtonCombo);
|
||||
}
|
119
Source/Core/Core/Src/HW/SI_DeviceGCSteeringWheel.h
Normal file
119
Source/Core/Core/Src/HW/SI_DeviceGCSteeringWheel.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
// 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 _SI_DEVICEGCSTEERINGWHEEL_H
|
||||
#define _SI_DEVICEGCSTEERINGWHEEL_H
|
||||
|
||||
#include "SI_Device.h"
|
||||
#include "GCPadStatus.h"
|
||||
|
||||
|
||||
// standard gamecube controller
|
||||
class CSIDevice_GCSteeringWheel : public ISIDevice
|
||||
{
|
||||
private:
|
||||
|
||||
// Commands
|
||||
enum EBufferCommands
|
||||
{
|
||||
CMD_RESET = 0x00,
|
||||
CMD_ORIGIN = 0x41,
|
||||
CMD_RECALIBRATE = 0x42,
|
||||
CMD_MOTOR_OFF = 0xff,
|
||||
};
|
||||
|
||||
struct SOrigin
|
||||
{
|
||||
u8 uCommand;// Maybe should be button bits?
|
||||
u8 unk_1; // ..and this would be the other half
|
||||
u8 uOriginStickX;
|
||||
u8 uOriginStickY;
|
||||
u8 uSubStickStickX;
|
||||
u8 uSubStickStickY;
|
||||
u8 uTrigger_L;
|
||||
u8 uTrigger_R;
|
||||
u8 unk_4;
|
||||
u8 unk_5;
|
||||
u8 unk_6;
|
||||
u8 unk_7;
|
||||
};
|
||||
|
||||
enum EDirectCommands
|
||||
{
|
||||
CMD_FORCE = 0x30,
|
||||
CMD_WRITE = 0x40
|
||||
};
|
||||
|
||||
union UCommand
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
u32 Parameter1 : 8;
|
||||
u32 Parameter2 : 8;
|
||||
u32 Command : 8;
|
||||
u32 : 8;
|
||||
};
|
||||
UCommand() {Hex = 0;}
|
||||
UCommand(u32 _iValue) {Hex = _iValue;}
|
||||
};
|
||||
|
||||
enum EButtonCombo
|
||||
{
|
||||
COMBO_NONE = 0,
|
||||
COMBO_ORIGIN,
|
||||
COMBO_RESET
|
||||
};
|
||||
|
||||
// struct to compare input against
|
||||
// Set on connection and (standard pad only) on button combo
|
||||
SOrigin m_Origin;
|
||||
|
||||
// PADAnalogMode
|
||||
u8 m_Mode;
|
||||
|
||||
// Timer to track special button combos:
|
||||
// y, X, start for 3 seconds updates origin with current status
|
||||
// Technically, the above is only on standard pad, wavebird does not support it for example
|
||||
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
|
||||
u64 m_TButtonComboStart, m_TButtonCombo;
|
||||
// Type of button combo from the last/current poll
|
||||
EButtonCombo m_LastButtonCombo;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber);
|
||||
|
||||
// Run the SI Buffer
|
||||
virtual int RunBuffer(u8* _pBuffer, int _iLength);
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus);
|
||||
static u8 NetPlay_GetPadNum(u8 numPAD);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
// Send a command directly
|
||||
virtual void SendCommand(u32 _Cmd, u8 _Poll);
|
||||
|
||||
// Savestate support
|
||||
virtual void DoState(PointerWrap& p);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -144,8 +144,8 @@ void Preset(bool _bNTSC)
|
|||
m_HorizontalStepping.FbSteps = 40;
|
||||
m_HorizontalStepping.FieldSteps = 40;
|
||||
|
||||
m_HBeamPos = 1;
|
||||
m_VBeamPos = 1;
|
||||
m_HBeamPos = 0;
|
||||
m_VBeamPos = 0;
|
||||
|
||||
// 54MHz, capable of progressive scan
|
||||
m_Clock = Core::g_CoreStartupParameter.bProgressive;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "WiimoteReal/WiimoteReal.h"
|
||||
#include "WiimoteEmu/WiimoteEmu.h"
|
||||
#include "Movie.h"
|
||||
#include "../ConfigManager.h"
|
||||
|
||||
#include "ControllerInterface/ControllerInterface.h"
|
||||
|
||||
|
@ -44,7 +45,7 @@ void Initialize(void* const hwnd)
|
|||
g_controller_interface.SetHwnd(hwnd);
|
||||
g_controller_interface.Initialize();
|
||||
|
||||
g_plugin.LoadConfig();
|
||||
g_plugin.LoadConfig(false);
|
||||
|
||||
WiimoteReal::Initialize();
|
||||
|
||||
|
|
|
@ -97,8 +97,9 @@ void Turntable::GetState(u8* const data, const bool focus)
|
|||
|
||||
// crossfade slider
|
||||
{
|
||||
u8 cfs = 0;
|
||||
m_crossfade->GetState(&cfs, 8, 7);
|
||||
s8 cfs = 0;
|
||||
m_crossfade->GetState(&cfs, focus ? 7 : 0);
|
||||
cfs += 8;
|
||||
|
||||
ttdata->slider = cfs;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Attachment/Classic.h"
|
||||
#include "Attachment/Nunchuk.h"
|
||||
#include "Attachment/Guitar.h"
|
||||
|
@ -89,23 +91,32 @@ const ReportFeatures reporting_mode_features[] =
|
|||
{ 0, 0, 0, 0, 23 },
|
||||
};
|
||||
|
||||
void EmulateShake( AccelData* const accel
|
||||
void EmulateShake(AccelData* const accel
|
||||
, ControllerEmu::Buttons* const buttons_group
|
||||
, u8* const shake_step )
|
||||
{
|
||||
static const double shake_data[] = { -2.5f, -5.0f, -2.5f, 0.0f, 2.5f, 5.0f, 2.5f, 0.0f };
|
||||
// frame count of one up/down shake
|
||||
// < 9 no shake detection in "Wario Land: Shake It"
|
||||
auto const shake_step_max = 15;
|
||||
|
||||
// peak G-force
|
||||
auto const shake_intensity = 3.f;
|
||||
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = { 0x01, 0x02, 0x04 };
|
||||
unsigned int shake = 0;
|
||||
|
||||
buttons_group->GetState( &shake, btns );
|
||||
for ( unsigned int i=0; i<3; ++i )
|
||||
|
||||
for (int i = 0; i != 3; ++i)
|
||||
{
|
||||
if (shake & (1 << i))
|
||||
{
|
||||
(&(accel->x))[i] = shake_data[shake_step[i]++];
|
||||
shake_step[i] %= sizeof(shake_data)/sizeof(double);
|
||||
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity;
|
||||
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
|
||||
}
|
||||
else
|
||||
shake_step[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EmulateTilt(AccelData* const accel
|
||||
|
@ -113,7 +124,8 @@ void EmulateTilt(AccelData* const accel
|
|||
, const bool focus, const bool sideways, const bool upright)
|
||||
{
|
||||
float roll, pitch;
|
||||
tilt_group->GetState( &roll, &pitch, 0, focus ? (PI / 2) : 0 ); // 90 degrees
|
||||
// 180 degrees
|
||||
tilt_group->GetState(&roll, &pitch, 0, focus ? PI : 0);
|
||||
|
||||
unsigned int ud = 0, lr = 0, fb = 0;
|
||||
|
||||
|
@ -256,6 +268,9 @@ Wiimote::Wiimote( const unsigned int index )
|
|||
for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i)
|
||||
m_buttons->controls.push_back(new ControlGroup::Input( named_buttons[i]));
|
||||
|
||||
// udp
|
||||
groups.push_back(m_udp = new UDPWrapper(m_index, _trans("UDP Wiimote")));
|
||||
|
||||
// ir
|
||||
groups.push_back(m_ir = new Cursor(_trans("IR")));
|
||||
|
||||
|
@ -265,9 +280,6 @@ Wiimote::Wiimote( const unsigned int index )
|
|||
// tilt
|
||||
groups.push_back(m_tilt = new Tilt(_trans("Tilt")));
|
||||
|
||||
// udp
|
||||
groups.push_back(m_udp = new UDPWrapper(m_index, _trans("UDP Wiimote")));
|
||||
|
||||
// shake
|
||||
groups.push_back(m_shake = new Buttons(_trans("Shake")));
|
||||
m_shake->controls.push_back(new ControlGroup::Input("X"));
|
||||
|
|
|
@ -30,7 +30,12 @@
|
|||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#define PI 3.14159265358979323846
|
||||
namespace
|
||||
{
|
||||
// :)
|
||||
auto const TAU = 6.28318530717958647692;
|
||||
auto const PI = TAU / 2.0;
|
||||
}
|
||||
|
||||
// Registry sizes
|
||||
#define WIIMOTE_EEPROM_SIZE (16*1024)
|
||||
|
|
|
@ -36,6 +36,11 @@ void Wiimote::RealDisconnect()
|
|||
return;
|
||||
}
|
||||
|
||||
bool Wiimote::IsOpen() const
|
||||
{
|
||||
return IsConnected();
|
||||
}
|
||||
|
||||
int Wiimote::IORead(unsigned char* buf)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -34,11 +34,6 @@
|
|||
#include "WiimoteReal.h"
|
||||
#include "Host.h"
|
||||
|
||||
// Identify the wiimote device by its class
|
||||
#define WM_DEV_CLASS_0 0x04
|
||||
#define WM_DEV_CLASS_1 0x25
|
||||
#define WM_DEV_CLASS_2 0x00
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
||||
|
@ -95,9 +90,15 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes)
|
|||
// Display discovered devices
|
||||
for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i)
|
||||
{
|
||||
if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) &&
|
||||
(scan_info[i].dev_class[1] == WM_DEV_CLASS_1) &&
|
||||
(scan_info[i].dev_class[2] == WM_DEV_CLASS_2))
|
||||
char name[1000];
|
||||
memset(name, 0, sizeof(name));
|
||||
ERROR_LOG(WIIMOTE, "found a device...");
|
||||
if (hci_read_remote_name(device_sock, &scan_info[i].bdaddr, sizeof(name), name, 0) < 0) {
|
||||
ERROR_LOG(WIIMOTE, "name request failed");
|
||||
continue;
|
||||
}
|
||||
ERROR_LOG(WIIMOTE, "device name %s", name);
|
||||
if (IsValidBluetoothName(name))
|
||||
{
|
||||
bool new_wiimote = true;
|
||||
// Determine if this wiimote has already been found.
|
||||
|
@ -136,34 +137,34 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes)
|
|||
// Connect to a wiimote with a known address.
|
||||
bool Wiimote::Connect()
|
||||
{
|
||||
struct sockaddr_l2 addr;
|
||||
|
||||
if (IsConnected()) return false;
|
||||
if (IsConnected())
|
||||
return false;
|
||||
|
||||
sockaddr_l2 addr;
|
||||
addr.l2_family = AF_BLUETOOTH;
|
||||
addr.l2_bdaddr = bdaddr;
|
||||
addr.l2_cid = 0;
|
||||
|
||||
// Output channel
|
||||
addr.l2_psm = htobs(WM_OUTPUT_CHANNEL);
|
||||
if ((out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
|
||||
connect(out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
if ((cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
|
||||
connect(cmd_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
DEBUG_LOG(WIIMOTE, "Unable to open output socket to wiimote.");
|
||||
close(out_sock);
|
||||
out_sock = -1;
|
||||
close(cmd_sock);
|
||||
cmd_sock = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Input channel
|
||||
addr.l2_psm = htobs(WM_INPUT_CHANNEL);
|
||||
if ((in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
|
||||
connect(in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
if ((int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
|
||||
connect(int_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
DEBUG_LOG(WIIMOTE, "Unable to open input socket from wiimote.");
|
||||
close(in_sock);
|
||||
close(out_sock);
|
||||
in_sock = out_sock = -1;
|
||||
close(int_sock);
|
||||
close(cmd_sock);
|
||||
int_sock = cmd_sock = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -195,42 +196,50 @@ void Wiimote::RealDisconnect()
|
|||
if (m_wiimote_thread.joinable())
|
||||
m_wiimote_thread.join();
|
||||
|
||||
Host_ConnectWiimote(index, false);
|
||||
Close();
|
||||
}
|
||||
|
||||
close(out_sock);
|
||||
close(in_sock);
|
||||
void Wiimote::Close()
|
||||
{
|
||||
if (IsOpen())
|
||||
{
|
||||
Host_ConnectWiimote(index, false);
|
||||
|
||||
out_sock = -1;
|
||||
in_sock = -1;
|
||||
close(cmd_sock);
|
||||
close(int_sock);
|
||||
|
||||
cmd_sock = -1;
|
||||
int_sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wiimote::IsOpen() const
|
||||
{
|
||||
return IsConnected() && cmd_sock != -1 && int_sock != -1;
|
||||
}
|
||||
|
||||
int Wiimote::IORead(unsigned char *buf)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
int r;
|
||||
|
||||
if (!IsConnected())
|
||||
return 0;
|
||||
|
||||
// Block select for 1/2000th of a second
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = WIIMOTE_DEFAULT_TIMEOUT * 1000;
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(in_sock, &fds);
|
||||
FD_SET(int_sock, &fds);
|
||||
|
||||
if (select(in_sock + 1, &fds, NULL, NULL, &tv) == -1)
|
||||
if (select(int_sock + 1, &fds, NULL, NULL, &tv) == -1)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FD_ISSET(in_sock, &fds))
|
||||
if (!FD_ISSET(int_sock, &fds))
|
||||
return 0;
|
||||
|
||||
// Read the pending message into the buffer
|
||||
r = read(in_sock, buf, MAX_PAYLOAD);
|
||||
int r = read(int_sock, buf, MAX_PAYLOAD);
|
||||
if (r == -1)
|
||||
{
|
||||
// Error reading data
|
||||
|
@ -241,23 +250,23 @@ int Wiimote::IORead(unsigned char *buf)
|
|||
// This can happen if the bluetooth dongle is disconnected
|
||||
ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. "
|
||||
"Wiimote %i will be disconnected.", index + 1);
|
||||
RealDisconnect();
|
||||
Close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (!r)
|
||||
else if (!r)
|
||||
{
|
||||
// Disconnect
|
||||
RealDisconnect();
|
||||
return 0;
|
||||
Close();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(unsigned char* buf, int len)
|
||||
{
|
||||
return write(out_sock, buf, len);
|
||||
return write(int_sock, buf, len);
|
||||
}
|
||||
|
||||
}; // WiimoteReal
|
||||
|
|
|
@ -294,6 +294,11 @@ void Wiimote::RealDisconnect()
|
|||
ResetEvent(&hid_overlap);
|
||||
}
|
||||
|
||||
bool Wiimote::IsOpen() const
|
||||
{
|
||||
return IsConnected();
|
||||
}
|
||||
|
||||
int Wiimote::IORead(unsigned char* buf)
|
||||
{
|
||||
DWORD b, r;
|
||||
|
|
|
@ -227,6 +227,11 @@ void Wiimote::RealDisconnect()
|
|||
ichan = NULL;
|
||||
}
|
||||
|
||||
bool Wiimote::IsOpen() const
|
||||
{
|
||||
return IsConnected();
|
||||
}
|
||||
|
||||
int Wiimote::IORead(unsigned char *buf)
|
||||
{
|
||||
int bytes;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common.h"
|
||||
|
@ -44,7 +45,7 @@ Wiimote::Wiimote(const unsigned int _index)
|
|||
#ifdef __APPLE__
|
||||
, inputlen(0)
|
||||
#elif defined(__linux__) && HAVE_BLUEZ
|
||||
, out_sock(-1), in_sock(-1)
|
||||
, cmd_sock(-1), int_sock(-1)
|
||||
#elif defined(_WIN32)
|
||||
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
|
||||
#endif
|
||||
|
@ -240,7 +241,7 @@ void Wiimote::Disconnect()
|
|||
DisableDataReporting();
|
||||
}
|
||||
|
||||
bool Wiimote::IsConnected()
|
||||
bool Wiimote::IsConnected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
@ -312,14 +313,14 @@ void Wiimote::ThreadFunc()
|
|||
Rumble();
|
||||
|
||||
// main loop
|
||||
while (IsConnected())
|
||||
while (IsOpen())
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
while (Write()) {}
|
||||
Common::SleepCurrentThread(1);
|
||||
#else
|
||||
bool read = false;
|
||||
while (Write() || (read = true, Read()))
|
||||
while (Write() || (read = true, IsOpen() && Read()))
|
||||
{
|
||||
if (m_audio_reports.Size() && !read)
|
||||
Read();
|
||||
|
@ -512,19 +513,11 @@ void StateChange(EMUSTATE_CHANGE newState)
|
|||
// TODO: disable/enable auto reporting, maybe
|
||||
}
|
||||
|
||||
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;
|
||||
return false;
|
||||
bool IsValidBluetoothName(const std::string& name)
|
||||
{
|
||||
std::string const prefix("Nintendo RVL-");
|
||||
return name.size() > prefix.size() &&
|
||||
std::equal(prefix.begin(), prefix.end(), name.begin());
|
||||
}
|
||||
|
||||
|
||||
}; // end of namespace
|
||||
|
|
|
@ -53,7 +53,8 @@ public:
|
|||
bool Read();
|
||||
bool Write();
|
||||
bool Connect();
|
||||
bool IsConnected();
|
||||
bool IsConnected() const;
|
||||
bool IsOpen() const;
|
||||
void Disconnect();
|
||||
void DisableDataReporting();
|
||||
void Rumble();
|
||||
|
@ -70,8 +71,11 @@ public:
|
|||
int inputlen;
|
||||
#elif defined(__linux__) && HAVE_BLUEZ
|
||||
bdaddr_t bdaddr; // Bluetooth address
|
||||
int out_sock; // Output socket
|
||||
int in_sock; // Input socket
|
||||
int cmd_sock; // Command socket
|
||||
int int_sock; // Interrupt socket
|
||||
|
||||
void Close();
|
||||
|
||||
#elif defined(_WIN32)
|
||||
char devicepath[255]; // Unique wiimote reference
|
||||
//ULONGLONG btaddr; // Bluetooth address
|
||||
|
@ -113,7 +117,7 @@ void StateChange(EMUSTATE_CHANGE newState);
|
|||
|
||||
int FindWiimotes(Wiimote** wm, int max_wiimotes);
|
||||
|
||||
bool IsValidBluetoothName(const char* name);
|
||||
bool IsValidBluetoothName(const std::string& name);
|
||||
|
||||
}; // WiimoteReal
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
|
||||
// The 4 most significant bits of the first byte of an outgoing command must be
|
||||
// 0x50 if sending on the command channel and 0xA0 if sending on the interrupt
|
||||
// channel. On Mac we use interrupt channel; on Windows/Linux, command.
|
||||
#ifndef __APPLE__
|
||||
// channel. On Mac and Linux we use interrupt channel; on Windows, command.
|
||||
#ifdef _WIN32
|
||||
#define WM_SET_REPORT 0x50
|
||||
#else
|
||||
#define WM_SET_REPORT 0xA0
|
||||
|
|
|
@ -253,15 +253,15 @@ void DoState(PointerWrap &p)
|
|||
u32 i;
|
||||
for (i=0; i<IPC_MAX_FDS; i++)
|
||||
{
|
||||
u32 exists;
|
||||
u32 exists = 0;
|
||||
p.Do(exists);
|
||||
if (exists)
|
||||
{
|
||||
u32 isHw;
|
||||
u32 isHw = 0;
|
||||
p.Do(isHw);
|
||||
if (isHw)
|
||||
{
|
||||
u32 hwId;
|
||||
u32 hwId = 0;
|
||||
p.Do(hwId);
|
||||
g_FdMap[i] = AccessDeviceByID(hwId);
|
||||
}
|
||||
|
|
|
@ -780,21 +780,23 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
// someone with an affected game should test
|
||||
IOSv = TitleID & 0xffff;
|
||||
}
|
||||
if (!bSuccess)
|
||||
if (!bSuccess && IOSv >= 30 && IOSv != 0xffff)
|
||||
{
|
||||
PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available in your nand dump\n"
|
||||
"TitleID %016llx.\n Dolphin will likely hang now", TitleID);
|
||||
}
|
||||
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++)
|
||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
size_t size = s_Usb->m_WiiMotes.size();
|
||||
bool* wiiMoteConnected = new bool[size];
|
||||
for (unsigned int i = 0; i < 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();
|
||||
s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
|
||||
{
|
||||
if (wiiMoteConnected[i])
|
||||
|
|
|
@ -38,7 +38,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De
|
|||
// Activate only first Wiimote by default
|
||||
|
||||
_conf_pads BT_DINF;
|
||||
|
||||
SetUsbPointer(this);
|
||||
if (!SConfig::GetInstance().m_SYSCONF->GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)))
|
||||
{
|
||||
PanicAlertT("Trying to read from invalid SYSCONF\nWiimote bt ids are not available");
|
||||
|
@ -100,6 +100,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De
|
|||
CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305()
|
||||
{
|
||||
m_WiiMotes.clear();
|
||||
SetUsbPointer(NULL);
|
||||
}
|
||||
|
||||
void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
|
||||
|
|
|
@ -27,13 +27,19 @@
|
|||
#include "l2cap.h" // Local
|
||||
#include "WiiMote_HID_Attr.h"
|
||||
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb;
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = NULL;
|
||||
|
||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* GetUsbPointer()
|
||||
{
|
||||
return s_Usb;
|
||||
}
|
||||
|
||||
void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr)
|
||||
{
|
||||
s_Usb = ptr;
|
||||
}
|
||||
|
||||
|
||||
CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bdaddr_t _BD, bool ready)
|
||||
: m_HIDControlChannel_Connected(false)
|
||||
, m_HIDControlChannel_ConnectedWait(false)
|
||||
|
@ -49,8 +55,6 @@ CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305*
|
|||
{
|
||||
DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote: #%i Constructed", _Number);
|
||||
|
||||
s_Usb = _pHost;
|
||||
|
||||
m_ConnectionState = (ready) ? CONN_READY : CONN_INACTIVE;
|
||||
m_ConnectionHandle = 0x100 + _Number;
|
||||
memset(m_LinkKey, 0xA0 + _Number, HCI_KEY_SIZE);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
class CWII_IPC_HLE_Device_usb_oh1_57e_305;
|
||||
|
||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* GetUsbPointer();
|
||||
void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr);
|
||||
|
||||
class CBigEndianBuffer
|
||||
{
|
||||
|
|
|
@ -736,16 +736,6 @@ bool PlayInput(const char *filename)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
// Load savestate (and skip to frame data)
|
||||
if(tmpHeader.bFromSaveState)
|
||||
{
|
||||
const std::string stateFilename = std::string(filename) + ".sav";
|
||||
if(File::Exists(stateFilename))
|
||||
Core::SetStateFileName(stateFilename);
|
||||
g_bRecordingFromSaveState = true;
|
||||
Movie::LoadInput(filename);
|
||||
}
|
||||
|
||||
ReadHeader();
|
||||
g_totalFrames = tmpHeader.frameCount;
|
||||
g_totalLagCount = tmpHeader.lagCount;
|
||||
|
@ -762,6 +752,16 @@ bool PlayInput(const char *filename)
|
|||
g_currentByte = 0;
|
||||
g_recordfd.Close();
|
||||
|
||||
// Load savestate (and skip to frame data)
|
||||
if(tmpHeader.bFromSaveState)
|
||||
{
|
||||
const std::string stateFilename = std::string(filename) + ".sav";
|
||||
if(File::Exists(stateFilename))
|
||||
Core::SetStateFileName(stateFilename);
|
||||
g_bRecordingFromSaveState = true;
|
||||
Movie::LoadInput(filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
|
@ -786,7 +786,13 @@ void DoState(PointerWrap &p)
|
|||
|
||||
void LoadInput(const char *filename)
|
||||
{
|
||||
File::IOFile t_record(filename, "r+b");
|
||||
File::IOFile t_record;
|
||||
if (!t_record.Open(filename, "r+b"))
|
||||
{
|
||||
PanicAlertT("Failed to read %s", filename);
|
||||
EndPlayInput(false);
|
||||
return;
|
||||
}
|
||||
|
||||
t_record.ReadArray(&tmpHeader, 1);
|
||||
|
||||
|
@ -849,7 +855,7 @@ void LoadInput(const char *filename)
|
|||
{
|
||||
// this is a "you did something wrong" alert for the user's benefit.
|
||||
// we'll try to say what's going on in excruciating detail, otherwise the user might not believe us.
|
||||
if(Core::g_CoreStartupParameter.bWii)
|
||||
if(IsUsingWiimote(0))
|
||||
{
|
||||
// TODO: more detail
|
||||
PanicAlertT("Warning: You loaded a save whose movie mismatches on byte %d (0x%X). You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync.", i+256, i+256);
|
||||
|
@ -925,18 +931,6 @@ 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);
|
||||
|
@ -1194,9 +1188,13 @@ void GetSettings()
|
|||
g_bClearSave = !File::Exists(SConfig::GetInstance().m_strMemoryCardA);
|
||||
bMemcard = SConfig::GetInstance().m_EXIDevice[0] == EXIDEVICE_MEMORYCARD;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << SCM_REV_STR;
|
||||
ss >> revision;
|
||||
int temp;
|
||||
|
||||
for(int i = 0; i < 4; ++i )
|
||||
{
|
||||
sscanf(SCM_REV_STR + 2 * i, "%2x", &temp );
|
||||
revision[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void CheckMD5()
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
|
||||
// for gcpad
|
||||
#include "HW/SI_DeviceGCController.h"
|
||||
#include "HW/SI_DeviceGCSteeringWheel.h"
|
||||
// for gctime
|
||||
#include "HW/EXI_DeviceIPL.h"
|
||||
// for wiimote/ OSD messages
|
||||
|
@ -296,6 +297,11 @@ bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
|
||||
{
|
||||
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
|
||||
}
|
||||
|
||||
// called from ---CPU--- thread
|
||||
// so all players' games get the same time
|
||||
u32 CEXIIPL::NetPlay_GetGCTime()
|
||||
|
@ -320,6 +326,11 @@ u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
|
|||
return numPAD;
|
||||
}
|
||||
|
||||
u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD)
|
||||
{
|
||||
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
|
||||
}
|
||||
|
||||
// called from ---CPU--- thread
|
||||
// wiimote update / used for frame counting
|
||||
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "PowerPCDisasm.h"
|
||||
#include "../../IPC_HLE/WII_IPC_HLE.h"
|
||||
#include "Atomic.h"
|
||||
#include "HLE/HLE.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -79,57 +80,63 @@ int startTrace = 0;
|
|||
|
||||
void Trace( UGeckoInstruction &instCode )
|
||||
{
|
||||
char regs[500]="";
|
||||
char reg[25]="";
|
||||
std::string regs = "";
|
||||
for (int i=0; i<32; i++) {
|
||||
sprintf(regs, "%sr%02d: %08x ", regs, i, PowerPC::ppcState.gpr[i]);
|
||||
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
|
||||
regs.append(reg);
|
||||
}
|
||||
|
||||
char fregs[500]="";
|
||||
char freg[25]="";
|
||||
std::string fregs = "";
|
||||
for (int i=0; i<32; i++) {
|
||||
sprintf(fregs, "%sf%02d: %08llx %08llx ", fregs, i,
|
||||
PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
|
||||
sprintf(freg, "f%02d: %08llx %08llx ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
|
||||
fregs.append(freg);
|
||||
}
|
||||
|
||||
char ppcInst[256];
|
||||
DisassembleGekko(instCode.hex, PC, ppcInst, 256);
|
||||
|
||||
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, instCode.hex, ppcInst);
|
||||
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str(), instCode.hex, ppcInst);
|
||||
}
|
||||
|
||||
int Interpreter::SingleStepInner(void)
|
||||
{
|
||||
static UGeckoInstruction instCode;
|
||||
|
||||
NPC = PC + sizeof(UGeckoInstruction);
|
||||
instCode.hex = Memory::Read_Opcode(PC);
|
||||
|
||||
// Uncomment to trace the interpreter
|
||||
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
|
||||
// startTrace = 1;
|
||||
//else
|
||||
// startTrace = 0;
|
||||
|
||||
if (startTrace)
|
||||
u32 function = m_EndBlock ? HLE::GetFunctionIndex(PC) : 0; // Check for HLE functions after branches
|
||||
if (function != 0)
|
||||
{
|
||||
Trace(instCode);
|
||||
}
|
||||
|
||||
if (instCode.hex != 0)
|
||||
{
|
||||
UReg_MSR& msr = (UReg_MSR&)MSR;
|
||||
if (msr.FP) //If FPU is enabled, just execute
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
m_opTable[instCode.OPCD](instCode);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
HLEFunction(function);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
NPC = PC + sizeof(UGeckoInstruction);
|
||||
instCode.hex = Memory::Read_Opcode(PC);
|
||||
|
||||
// Uncomment to trace the interpreter
|
||||
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
|
||||
// startTrace = 1;
|
||||
//else
|
||||
// startTrace = 0;
|
||||
|
||||
if (startTrace)
|
||||
{
|
||||
// check if we have to generate a FPU unavailable exception
|
||||
if (!PPCTables::UsesFPU(instCode))
|
||||
Trace(instCode);
|
||||
}
|
||||
|
||||
if (instCode.hex != 0)
|
||||
{
|
||||
UReg_MSR& msr = (UReg_MSR&)MSR;
|
||||
if (msr.FP) //If FPU is enabled, just execute
|
||||
{
|
||||
m_opTable[instCode.OPCD](instCode);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
|
@ -140,17 +147,30 @@ int Interpreter::SingleStepInner(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
// check if we have to generate a FPU unavailable exception
|
||||
if (!PPCTables::UsesFPU(instCode))
|
||||
{
|
||||
m_opTable[instCode.OPCD](instCode);
|
||||
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory exception on instruction fetch
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
else
|
||||
{
|
||||
// Memory exception on instruction fetch
|
||||
PowerPC::CheckExceptions();
|
||||
m_EndBlock = true;
|
||||
}
|
||||
}
|
||||
last_pc = PC;
|
||||
PC = NPC;
|
||||
|
|
|
@ -407,7 +407,7 @@ void Interpreter::dcbtst(UGeckoInstruction _inst)
|
|||
void Interpreter::dcbz(UGeckoInstruction _inst)
|
||||
{
|
||||
// HACK but works... we think
|
||||
if (HID2.WPE || !HID0.DCFA)
|
||||
if (!Core::g_CoreStartupParameter.bDCBZOFF)
|
||||
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
|
||||
if (!jit)
|
||||
PowerPC::CheckExceptions();
|
||||
|
|
|
@ -293,7 +293,8 @@ void Interpreter::mfspr(UGeckoInstruction _inst)
|
|||
|
||||
case SPR_WPAR:
|
||||
{
|
||||
// If wpar_empty ever is false, Paper Mario hangs. Strange.
|
||||
// TODO: If wpar_empty ever is false, Paper Mario hangs. Strange.
|
||||
// Maybe WPAR is automatically flushed after a certain amount of time?
|
||||
bool wpar_empty = true; //GPFifo::IsEmpty();
|
||||
if (!wpar_empty)
|
||||
rSPR(iIndex) |= 1; // BNE = buffer not empty
|
||||
|
|
|
@ -252,8 +252,6 @@ void Jit64::HLEFunction(UGeckoInstruction _inst)
|
|||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
WriteExitDestInEAX();
|
||||
}
|
||||
|
||||
void Jit64::DoNothing(UGeckoInstruction _inst)
|
||||
|
@ -566,6 +564,27 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
ABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
||||
}
|
||||
|
||||
u32 function = HLE::GetFunctionIndex(ops[i].address);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
HLEFunction(function);
|
||||
if (type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
js.downcountAmount += js.st.numCycles;
|
||||
WriteExitDestInEAX();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
|
||||
|
@ -668,6 +687,20 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
break;
|
||||
}
|
||||
|
||||
u32 function = HLE::GetFunctionIndex(js.blockStart);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_END)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
HLEFunction(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memory_exception)
|
||||
{
|
||||
// Address of instruction could not be translated
|
||||
|
|
|
@ -199,7 +199,7 @@ namespace JitILProfiler
|
|||
static u64 beginTime;
|
||||
static Block& Add(u64 codeHash)
|
||||
{
|
||||
const u32 _blockIndex = blocks.size();
|
||||
const u32 _blockIndex = (u32)blocks.size();
|
||||
blocks.push_back(Block());
|
||||
Block& block = blocks.back();
|
||||
block.index = _blockIndex;
|
||||
|
@ -649,6 +649,27 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
js.next_compilerPC = ops[i + 1].address;
|
||||
}
|
||||
|
||||
u32 function = HLE::GetFunctionIndex(ops[i].address);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
HLEFunction(function);
|
||||
if (type == HLE::HLE_HOOK_REPLACE)
|
||||
{
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
jit->js.downcountAmount += jit->js.st.numCycles;
|
||||
WriteExitDestInOpArg(R(EAX));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ops[i].skip)
|
||||
{
|
||||
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
|
||||
|
@ -665,7 +686,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
{
|
||||
ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
|
||||
}
|
||||
|
||||
|
||||
JitILTables::CompileInstruction(ops[i]);
|
||||
|
||||
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||
|
@ -681,6 +702,20 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
|||
}
|
||||
}
|
||||
|
||||
u32 function = HLE::GetFunctionIndex(jit->js.blockStart);
|
||||
if (function != 0)
|
||||
{
|
||||
int type = HLE::GetFunctionTypeByIndex(function);
|
||||
if (type == HLE::HLE_HOOK_END)
|
||||
{
|
||||
int flags = HLE::GetFunctionFlagsByIndex(function);
|
||||
if (HLE::IsEnabled(flags))
|
||||
{
|
||||
HLEFunction(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memory_exception)
|
||||
{
|
||||
ibuild.EmitISIException(ibuild.EmitIntConst(em_address));
|
||||
|
|
|
@ -90,6 +90,13 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info)
|
|||
case 4:
|
||||
CALL(thunks.ProtectFunction((void *)&Memory::Read_U32, 1));
|
||||
break;
|
||||
case 2:
|
||||
CALL(thunks.ProtectFunction((void *)&Memory::Read_U16, 1));
|
||||
SHL(32, R(EAX), Imm8(16));
|
||||
break;
|
||||
case 1:
|
||||
CALL(thunks.ProtectFunction((void *)&Memory::Read_U8, 1));
|
||||
break;
|
||||
}
|
||||
ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||
if (dataReg != EAX) {
|
||||
|
@ -176,10 +183,6 @@ const u8 *JitBase::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void *c
|
|||
codePtr, emAddress);
|
||||
}*/
|
||||
|
||||
if (info.operandSize != 4) {
|
||||
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
|
||||
}
|
||||
|
||||
if (info.otherReg != RBX)
|
||||
PanicAlert("BackPatch : Base reg not RBX."
|
||||
"\n\nAttempted to access %08x.", emAddress);
|
||||
|
@ -188,7 +191,6 @@ const u8 *JitBase::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void *c
|
|||
PanicAlert("BackPatch : Currently only supporting reads."
|
||||
"\n\nAttempted to write to %08x.", emAddress);
|
||||
|
||||
// In the first iteration, we assume that all accesses are 32-bit. We also only deal with reads.
|
||||
if (accessType == 0)
|
||||
{
|
||||
XEmitter emitter(codePtr);
|
||||
|
|
|
@ -135,7 +135,11 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
|||
// is full and when saving and loading states.
|
||||
void JitBlockCache::Clear()
|
||||
{
|
||||
Core::DisplayMessage("Clearing code cache.", 3000);
|
||||
if (IsFull())
|
||||
Core::DisplayMessage("Clearing block cache.", 3000);
|
||||
else
|
||||
Core::DisplayMessage("Clearing code cache.", 3000);
|
||||
|
||||
for (int i = 0; i < num_blocks; i++)
|
||||
{
|
||||
DestroyBlock(i, false);
|
||||
|
@ -370,29 +374,27 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
|||
{
|
||||
LinkBlockExits(i);
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
// equal_range(b) returns pair<iterator,iterator> representing the range
|
||||
// of element with key b
|
||||
ppp = links_to.equal_range(b.originalAddress);
|
||||
if (ppp.first == ppp.second)
|
||||
return;
|
||||
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
||||
// PanicAlert("Linking block %i to block %i", iter2->second, i);
|
||||
LinkBlockExits(iter2->second);
|
||||
for (multimap<u32, int>::iterator iter = ppp.first; iter != ppp.second; ++iter) {
|
||||
// PanicAlert("Linking block %i to block %i", iter->second, i);
|
||||
LinkBlockExits(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlockCache::UnlinkBlock(int i)
|
||||
{
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
ppp = links_to.equal_range(b.originalAddress);
|
||||
if (ppp.first == ppp.second)
|
||||
return;
|
||||
for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
|
||||
JitBlock &sourceBlock = blocks[iter2->second];
|
||||
for (multimap<u32, int>::iterator iter = ppp.first; iter != ppp.second; ++iter) {
|
||||
JitBlock &sourceBlock = blocks[iter->second];
|
||||
for (int e = 0; e < 2; e++)
|
||||
{
|
||||
if (sourceBlock.exitAddress[e] == b.originalAddress)
|
||||
|
@ -458,7 +460,7 @@ bool JitBlock::ContainsAddress(u32 em_address)
|
|||
// !! this works correctly under assumption that any two overlapping blocks end at the same address
|
||||
if (destroy_block)
|
||||
{
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1, it;
|
||||
std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1;
|
||||
while (it2 != block_map.end() && it2->first.second < pAddr + length)
|
||||
{
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
|
|
|
@ -96,7 +96,11 @@ void EmuCodeBlock::UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize,
|
|||
MOVZX(32, accessSize, EAX, MDisp(EAX, (u32)Memory::base + offset));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Add a 2 bytes NOP to have some space for the backpatching
|
||||
if (accessSize == 8)
|
||||
NOP(2);
|
||||
|
||||
if (accessSize == 32)
|
||||
{
|
||||
BSWAP(32, EAX);
|
||||
|
@ -118,14 +122,13 @@ void EmuCodeBlock::UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize,
|
|||
|
||||
void EmuCodeBlock::SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend)
|
||||
{
|
||||
#if defined(_WIN32) && defined(_M_X64)
|
||||
#if defined(_M_X64)
|
||||
#ifdef ENABLE_MEM_CHECK
|
||||
if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
if (!Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
#else
|
||||
if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU)
|
||||
if (!Core::g_CoreStartupParameter.bMMU)
|
||||
#endif
|
||||
{
|
||||
// BackPatch only supports 32-bits accesses
|
||||
UnsafeLoadToEAX(opAddress, accessSize, offset, signExtend);
|
||||
}
|
||||
else
|
||||
|
@ -269,23 +272,18 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
|||
|
||||
void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
|
||||
{
|
||||
u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;
|
||||
|
||||
if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack)
|
||||
{
|
||||
mem_mask |= Memory::ADDR_MASK_MEM1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MEM_CHECK
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
{
|
||||
mem_mask |= Memory::EXRAM_MASK;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||
if (false && cpu_info.bSSSE3) {
|
||||
// This path should be faster but for some reason it causes errors so I've disabled it.
|
||||
u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;
|
||||
|
||||
if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack)
|
||||
mem_mask |= Memory::ADDR_MASK_MEM1;
|
||||
|
||||
#ifdef ENABLE_MEM_CHECK
|
||||
if (Core::g_CoreStartupParameter.bEnableDebugging)
|
||||
mem_mask |= Memory::EXRAM_MASK;
|
||||
#endif
|
||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||
FixupBranch argh = J_CC(CC_Z);
|
||||
MOVSS(M(&float_buffer), xmm_value);
|
||||
MOV(32, R(EAX), M(&float_buffer));
|
||||
|
|
|
@ -246,17 +246,13 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
|
|||
return false;
|
||||
}
|
||||
|
||||
// For now, only integer ops acceptable.
|
||||
switch (b_info->type) {
|
||||
case OPTYPE_INTEGER:
|
||||
case OPTYPE_LOAD:
|
||||
case OPTYPE_STORE:
|
||||
//case OPTYPE_LOADFP:
|
||||
//case OPTYPE_STOREFP:
|
||||
break;
|
||||
default:
|
||||
// For now, only integer ops acceptable. Any instruction which can raise an
|
||||
// interrupt is *not* a possible swap candidate: see [1] for an example of
|
||||
// a crash caused by this error.
|
||||
//
|
||||
// [1] https://code.google.com/p/dolphin-emu/issues/detail?id=5864#c7
|
||||
if (b_info->type != OPTYPE_INTEGER)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we have no register collisions.
|
||||
// That is, check that none of b's outputs matches any of a's inputs,
|
||||
|
|
|
@ -296,9 +296,13 @@ bool DecompressBlobToFile(const char* infile, const char* outfile, CompressCB ca
|
|||
}
|
||||
|
||||
CompressedBlobReader* reader = CompressedBlobReader::Create(infile);
|
||||
if (!reader) return false;
|
||||
if (!reader)
|
||||
return false;
|
||||
|
||||
File::IOFile f(outfile, "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
const CompressedBlobHeader &header = reader->GetHeader();
|
||||
u8* buffer = new u8[header.block_size];
|
||||
int progress_monitor = max<int>(1, header.num_blocks / 100);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "FileUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "FileSystemGCWii.h"
|
||||
#include "StringUtil.h"
|
||||
|
@ -95,7 +96,7 @@ bool CFileSystemGCWii::ExportFile(const char* _rFullPath, const char* _rExportFi
|
|||
|
||||
const SFileInfo* pFileInfo = FindFileInfo(_rFullPath);
|
||||
|
||||
if (!pFileInfo || pFileInfo->m_FileSize == 0)
|
||||
if (!pFileInfo)
|
||||
return false;
|
||||
|
||||
u64 remainingSize = pFileInfo->m_FileSize;
|
||||
|
@ -112,22 +113,17 @@ bool CFileSystemGCWii::ExportFile(const char* _rFullPath, const char* _rExportFi
|
|||
// Limit read size to 128 MB
|
||||
size_t readSize = (size_t)min(remainingSize, (u64)0x08000000);
|
||||
|
||||
u8* buffer = new u8[readSize];
|
||||
std::vector<u8> buffer(readSize);
|
||||
|
||||
result = m_rVolume->Read(fileOffset, readSize, buffer);
|
||||
result = m_rVolume->Read(fileOffset, readSize, &buffer[0]);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
delete[] buffer;
|
||||
break;
|
||||
}
|
||||
|
||||
f.WriteBytes(buffer, readSize);
|
||||
f.WriteBytes(&buffer[0], readSize);
|
||||
|
||||
remainingSize -= readSize;
|
||||
fileOffset += readSize;
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -140,26 +136,24 @@ bool CFileSystemGCWii::ExportApploader(const char* _rExportFolder) const
|
|||
AppSize += 0x20; // + header size
|
||||
DEBUG_LOG(DISCIO,"AppSize -> %x", AppSize);
|
||||
|
||||
u8* buffer = new u8[AppSize];
|
||||
if (m_rVolume->Read(0x2440, AppSize, buffer))
|
||||
std::vector<u8> buffer(AppSize);
|
||||
if (m_rVolume->Read(0x2440, AppSize, &buffer[0]))
|
||||
{
|
||||
char exportName[512];
|
||||
sprintf(exportName, "%s/apploader.img", _rExportFolder);
|
||||
std::string exportName(_rExportFolder);
|
||||
exportName += "/apploader.img";
|
||||
|
||||
File::IOFile AppFile(exportName, "wb");
|
||||
if (AppFile)
|
||||
{
|
||||
AppFile.WriteBytes(buffer, AppSize);
|
||||
delete[] buffer;
|
||||
AppFile.WriteBytes(&buffer[0], AppSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
|
||||
u32 CFileSystemGCWii::GetBootDOLSize() const
|
||||
{
|
||||
u32 DolOffset = Read32(0x420) << m_OffsetShift;
|
||||
u32 DolSize = 0, offset = 0, size = 0;
|
||||
|
@ -181,22 +175,34 @@ bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
|
|||
if (offset + size > DolSize)
|
||||
DolSize = offset + size;
|
||||
}
|
||||
return DolSize;
|
||||
}
|
||||
|
||||
u8* buffer = new u8[DolSize];
|
||||
if (m_rVolume->Read(DolOffset, DolSize, buffer))
|
||||
bool CFileSystemGCWii::GetBootDOL(u8* &buffer, u32 DolSize) const
|
||||
{
|
||||
u32 DolOffset = Read32(0x420) << m_OffsetShift;
|
||||
return m_rVolume->Read(DolOffset, DolSize, buffer);
|
||||
}
|
||||
|
||||
bool CFileSystemGCWii::ExportDOL(const char* _rExportFolder) const
|
||||
{
|
||||
u32 DolOffset = Read32(0x420) << m_OffsetShift;
|
||||
u32 DolSize = GetBootDOLSize();
|
||||
|
||||
std::vector<u8> buffer(DolSize);
|
||||
if (m_rVolume->Read(DolOffset, DolSize, &buffer[0]))
|
||||
{
|
||||
char exportName[512];
|
||||
sprintf(exportName, "%s/boot.dol", _rExportFolder);
|
||||
std::string exportName(_rExportFolder);
|
||||
exportName += "/boot.dol";
|
||||
|
||||
File::IOFile DolFile(exportName, "wb");
|
||||
if (DolFile)
|
||||
{
|
||||
DolFile.WriteBytes(buffer, DolSize);
|
||||
delete[] buffer;
|
||||
DolFile.WriteBytes(&buffer[0], DolSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
virtual bool ExportFile(const char* _rFullPath, const char* _rExportFilename);
|
||||
virtual bool ExportApploader(const char* _rExportFolder) const;
|
||||
virtual bool ExportDOL(const char* _rExportFolder) const;
|
||||
virtual bool GetBootDOL(u8* &buffer, u32 DolSize) const;
|
||||
virtual u32 GetBootDOLSize() const;
|
||||
|
||||
private:
|
||||
bool m_Initialized;
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
virtual bool ExportApploader(const char* _rExportFolder) const = 0;
|
||||
virtual bool ExportDOL(const char* _rExportFolder) const = 0;
|
||||
virtual const char* GetFileName(u64 _Address) = 0;
|
||||
virtual bool GetBootDOL(u8* &buffer, u32 DolSize) const = 0;
|
||||
virtual u32 GetBootDOLSize() const = 0;
|
||||
|
||||
virtual const IVolume *GetVolume() const { return m_rVolume; }
|
||||
protected:
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
COUNTRY_TAIWAN,
|
||||
COUNTRY_SDK,
|
||||
COUNTRY_UNKNOWN,
|
||||
COUNTRY_GERMANY,
|
||||
NUMBER_OF_COUNTRIES
|
||||
};
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue