mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07: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:
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user