SPU2: Add Cubeb SndOut driver

This commit is contained in:
Connor McLaughlin 2021-09-26 18:26:42 +10:00 committed by refractionpcsx2
parent bd489647e9
commit 88ce192610
7 changed files with 441 additions and 24 deletions

View File

@ -60,6 +60,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "3rdparty\glad\glad.vcxproj", "{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "3rdparty\cubeb\cubeb.vcxproj", "{BF74C473-DC04-44B3-92E8-4145F4E77342}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|Win32 = Debug AVX2|Win32
@ -604,6 +606,30 @@ Global
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.Build.0 = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.ActiveCfg = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.Build.0 = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.Build.0 = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.ActiveCfg = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.Build.0 = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.ActiveCfg = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|Win32.Build.0 = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.ActiveCfg = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug|x64.Build.0 = Debug|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|Win32.Build.0 = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.ActiveCfg = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel AVX2|x64.Build.0 = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.ActiveCfg = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|Win32.Build.0 = Devel|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.ActiveCfg = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Devel|x64.Build.0 = Devel|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.ActiveCfg = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|Win32.Build.0 = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.ActiveCfg = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release AVX2|x64.Build.0 = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.ActiveCfg = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.Build.0 = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.ActiveCfg = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -629,6 +655,7 @@ Global
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{BF74C473-DC04-44B3-92E8-4145F4E77342} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}

View File

@ -304,6 +304,12 @@ if(TARGET PkgConfig::PORTAUDIO)
list(APPEND pcsx2SPU2Sources SPU2/SndOut_Portaudio.cpp)
endif()
if(CUBEB_API)
list(APPEND pcsx2SPU2Sources SPU2/SndOut_Cubeb.cpp)
target_compile_definitions(PCSX2_FLAGS INTERFACE "SPU2X_CUBEB")
target_link_libraries(PCSX2_FLAGS INTERFACE cubeb)
endif()
# SPU2 headers
set(pcsx2SPU2Headers
SPU2/Config.h

View File

@ -88,6 +88,9 @@ SndOutModule* mods[] =
#if defined(SPU2X_PORTAUDIO)
PortaudioOut,
#endif
#if defined(SPU2X_CUBEB)
CubebOut,
#endif
#if defined(__linux__) || defined(__APPLE__)
SDLOut,
#endif
@ -138,6 +141,7 @@ bool SndBuffer::CheckUnderrunStatus(int& nSamples, int& quietSampleCount)
if (data < toFill)
{
quietSampleCount = nSamples;
nSamples = 0;
return false;
}
@ -148,8 +152,8 @@ bool SndBuffer::CheckUnderrunStatus(int& nSamples, int& quietSampleCount)
}
else if (data < nSamples)
{
quietSampleCount = nSamples - data;
nSamples = data;
quietSampleCount = SndOutPacketSize - data;
m_underrun_freeze = true;
if (SynchMode == 0) // TimeStrech on
@ -236,10 +240,8 @@ void SndBuffer::_ReadSamples_Safe(StereoOut32* bData, int nSamples)
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
// to shift right to get a 16 bit result.
template <typename T>
void SndBuffer::ReadSamples(T* bData)
void SndBuffer::ReadSamples(T* bData, int nSamples)
{
int nSamples = SndOutPacketSize;
// Problem:
// If the SPU2 gets even the least bit out of sync with the SndOut device,
// the readpos of the circular buffer will overtake the writepos,
@ -293,29 +295,30 @@ void SndBuffer::ReadSamples(T* bData)
// If quietSamples != 0 it means we have an underrun...
// Let's just dull out some silence, because that's usually the least
// painful way of dealing with underruns:
std::fill_n(bData, quietSamples, T{});
if (quietSamples > 0)
std::memset(bData + nSamples, 0, sizeof(T) * quietSamples);
}
template void SndBuffer::ReadSamples(StereoOut16*);
template void SndBuffer::ReadSamples(StereoOut32*);
template void SndBuffer::ReadSamples(StereoOut16*, int);
template void SndBuffer::ReadSamples(StereoOut32*, int);
//template void SndBuffer::ReadSamples(StereoOutFloat*);
template void SndBuffer::ReadSamples(Stereo21Out16*);
template void SndBuffer::ReadSamples(Stereo40Out16*);
template void SndBuffer::ReadSamples(Stereo41Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
template void SndBuffer::ReadSamples(Stereo71Out16*);
template void SndBuffer::ReadSamples(Stereo21Out16*, int);
template void SndBuffer::ReadSamples(Stereo40Out16*, int);
template void SndBuffer::ReadSamples(Stereo41Out16*, int);
template void SndBuffer::ReadSamples(Stereo51Out16*, int);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl*, int);
template void SndBuffer::ReadSamples(Stereo51Out16DplII*, int);
template void SndBuffer::ReadSamples(Stereo71Out16*, int);
template void SndBuffer::ReadSamples(Stereo20Out32*);
template void SndBuffer::ReadSamples(Stereo21Out32*);
template void SndBuffer::ReadSamples(Stereo40Out32*);
template void SndBuffer::ReadSamples(Stereo41Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out32DplII*);
template void SndBuffer::ReadSamples(Stereo71Out32*);
template void SndBuffer::ReadSamples(Stereo20Out32*, int);
template void SndBuffer::ReadSamples(Stereo21Out32*, int);
template void SndBuffer::ReadSamples(Stereo40Out32*, int);
template void SndBuffer::ReadSamples(Stereo41Out32*, int);
template void SndBuffer::ReadSamples(Stereo51Out32*, int);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl*, int);
template void SndBuffer::ReadSamples(Stereo51Out32DplII*, int);
template void SndBuffer::ReadSamples(Stereo71Out32*, int);
void SndBuffer::_WriteSamples(StereoOut32* bData, int nSamples)
{

View File

@ -625,7 +625,7 @@ public:
// the sample output is determined by the SndOutVolumeShift, which is the number of bits
// to shift right to get a 16 bit result.
template <typename T>
static void ReadSamples(T* bData);
static void ReadSamples(T* bData, int nSamples = SndOutPacketSize);
};
class SndOutModule
@ -670,6 +670,9 @@ extern SndOutModule* XAudio2Out;
#if defined(SPU2X_PORTAUDIO)
extern SndOutModule* PortaudioOut;
#endif
#if defined(SPU2X_CUBEB)
extern SndOutModule* CubebOut;
#endif
extern SndOutModule* const SDLOut;
extern SndOutModule* mods[];

370
pcsx2/SPU2/SndOut_Cubeb.cpp Normal file
View File

@ -0,0 +1,370 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include "common/RedtapeWindows.h"
#include "cubeb/cubeb.h"
#include "Global.h"
#include "SndOut.h"
extern bool CfgReadBool(const wchar_t* Section, const wchar_t* Name, bool Default);
extern int CfgReadInt(const wchar_t* Section, const wchar_t* Name, int Default);
extern void CfgReadStr(const wchar_t* Section, const wchar_t* Name, wxString& Data, const wchar_t* Default);
class Cubeb : public SndOutModule
{
private:
static constexpr int MINIMUM_LATENCY_MS = 20;
static constexpr int MAXIMUM_LATENCY_MS = 200;
//////////////////////////////////////////////////////////////////////////////////////////
// Stuff necessary for speaker expansion
class SampleReader
{
public:
virtual void ReadSamples(void* outputBuffer, long frames) = 0;
};
template <class T>
class ConvertedSampleReader final : public SampleReader
{
u64* const written;
public:
ConvertedSampleReader() = delete;
ConvertedSampleReader(u64* pWritten)
: written(pWritten)
{
}
void ReadSamples(void* outputBuffer, long frames) override
{
T* p1 = static_cast<T*>(outputBuffer);
while (frames > 0)
{
const long frames_to_read = std::min<long>(frames, SndOutPacketSize);
SndBuffer::ReadSamples(p1, frames_to_read);
p1 += frames_to_read;
frames -= frames_to_read;
}
(*written) += frames;
}
};
void DestroyContextAndStream()
{
if (stream)
{
cubeb_stream_stop(stream);
cubeb_stream_destroy(stream);
stream = nullptr;
}
if (m_context)
{
cubeb_destroy(m_context);
m_context = nullptr;
}
ActualReader.reset();
#ifdef _WIN32
if (m_COMInitializedByUs)
{
CoUninitialize();
m_COMInitializedByUs = false;
}
#endif
}
static void LogCallback(const char* fmt, ...)
{
FastFormatAscii msg;
std::va_list ap;
va_start(ap, fmt);
msg.WriteV(fmt, ap);
va_end(ap);
Console.WriteLn("(Cubeb): %s", msg.c_str());
}
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars
bool m_COMInitializedByUs = false;
bool m_SuggestedLatencyMinimal = false;
int m_SuggestedLatencyMS = 20;
std::string m_Backend;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
u64 writtenSoFar = 0;
u64 writtenLastTime = 0;
u64 positionLastTime = 0;
u32 channels = 0;
cubeb* m_context = nullptr;
cubeb_stream* stream = nullptr;
std::unique_ptr<SampleReader> ActualReader;
bool m_paused = false;
public:
Cubeb() = default;
~Cubeb()
{
DestroyContextAndStream();
}
s32 Init() override
{
ReadSettings();
// TODO(Stenzek): Migrate the errors to Host::ReportErrorAsync() once more Qt stuff is merged.
#ifdef _WIN32
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
m_COMInitializedByUs = SUCCEEDED(hr);
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
{
Console.Error("Failed to initialize COM");
return -1;
}
#endif
#ifdef PCSX2_DEVBUILD
cubeb_set_log_callback(CUBEB_LOG_NORMAL, LogCallback);
#endif
int rv = cubeb_init(&m_context, "PCSX2", m_Backend.empty() ? nullptr : m_Backend.c_str());
if (rv != CUBEB_OK)
{
Console.Error("Could not initialize cubeb context: %d", rv);
return -1;
}
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0:
channels = 2;
break; // Stereo
case 1:
channels = 4;
break; // Quadrafonic
case 2:
channels = 6;
break; // Surround 5.1
case 3:
channels = 8;
break; // Surround 7.1
default:
channels = 2;
break;
}
cubeb_channel_layout layout = CUBEB_LAYOUT_UNDEFINED;
switch (channels)
{
case 2:
Console.WriteLn("(Cubeb) Using normal 2 speaker stereo output.");
ActualReader = std::make_unique<ConvertedSampleReader<StereoOut16>>(&writtenSoFar);
break;
case 3:
Console.WriteLn("(Cubeb) 2.1 speaker expansion enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo21Out16>>(&writtenSoFar);
layout = CUBEB_LAYOUT_STEREO_LFE;
break;
case 4:
Console.WriteLn("(Cubeb) 4 speaker expansion enabled [quadraphenia]");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo40Out16>>(&writtenSoFar);
layout = CUBEB_LAYOUT_QUAD;
break;
case 5:
Console.WriteLn("(Cubeb) 4.1 speaker expansion enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo41Out16>>(&writtenSoFar);
layout = CUBEB_LAYOUT_QUAD_LFE;
break;
case 6:
case 7:
switch (dplLevel)
{
case 0:
Console.WriteLn("(Cubeb) 5.1 speaker expansion enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo51Out16>>(&writtenSoFar); //"normal" stereo upmix
break;
case 1:
Console.WriteLn("(Cubeb) 5.1 speaker expansion with basic ProLogic dematrixing enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo51Out16Dpl>>(&writtenSoFar); // basic Dpl decoder without rear stereo balancing
break;
case 2:
Console.WriteLn("(Cubeb) 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo51Out16DplII>>(&writtenSoFar); //gigas PLII
break;
}
channels = 6; // we do not support 7.0 or 6.2 configurations, downgrade to 5.1
layout = CUBEB_LAYOUT_3F2_LFE;
break;
default: // anything 8 or more gets the 7.1 treatment!
Console.WriteLn("(Cubeb) 7.1 speaker expansion enabled.");
ActualReader = std::make_unique<ConvertedSampleReader<Stereo71Out16>>(&writtenSoFar);
channels = 8; // we do not support 7.2 or more, downgrade to 7.1
layout = CUBEB_LAYOUT_3F4_LFE;
break;
}
cubeb_stream_params params = {};
params.format = CUBEB_SAMPLE_S16LE;
params.rate = SampleRate;
params.channels = channels;
params.layout = layout;
params.prefs = CUBEB_STREAM_PREF_NONE;
const u32 requested_latency_frames = static_cast<u32>((m_SuggestedLatencyMS * static_cast<u32>(SampleRate)) / 1000u);
u32 latency_frames = 0;
rv = cubeb_get_min_latency(m_context, &params, &latency_frames);
if (rv == CUBEB_ERROR_NOT_SUPPORTED)
{
Console.WriteLn("(Cubeb) Cubeb backend does not support latency queries, using latency of %d ms (%u frames).",
m_SuggestedLatencyMS, requested_latency_frames);
latency_frames = requested_latency_frames;
}
else
{
if (rv != CUBEB_OK)
{
Console.Error("Could not get minimum latency: %d", rv);
DestroyContextAndStream();
return -1;
}
const float minimum_latency_ms = static_cast<float>(latency_frames * 1000u) / static_cast<float>(SampleRate);
Console.WriteLn("(Cubeb) Minimum latency: %.2f ms (%u audio frames)", minimum_latency_ms, latency_frames);
if (!m_SuggestedLatencyMinimal)
{
if (latency_frames > requested_latency_frames)
{
Console.Warning("(Cubeb) Minimum latency is above requested latency: %u vs %u, adjusting to compensate.",
latency_frames, requested_latency_frames);
}
else
{
latency_frames = requested_latency_frames;
}
}
}
char stream_name[32];
std::snprintf(stream_name, sizeof(stream_name), "%p", this);
rv = cubeb_stream_init(m_context, &stream, stream_name, nullptr, nullptr, nullptr, &params,
latency_frames, &Cubeb::DataCallback, &Cubeb::StateCallback, this);
if (rv != CUBEB_OK)
{
Console.Error("Could not create stream: %d", rv);
DestroyContextAndStream();
return -1;
}
rv = cubeb_stream_start(stream);
if (rv != CUBEB_OK)
{
Console.Error("Could not start stream: %d", rv);
DestroyContextAndStream();
return -1;
}
return 0;
}
void Close() override
{
DestroyContextAndStream();
}
static void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state)
{
}
static long DataCallback(cubeb_stream* stm, void* user_ptr, const void* input_buffer, void* output_buffer, long nframes)
{
static_cast<Cubeb*>(user_ptr)->ActualReader->ReadSamples(output_buffer, nframes);
return nframes;
}
void Configure(uptr parent) override
{
}
s32 Test() const override
{
return 0;
}
int GetEmptySampleCount() override
{
u64 pos;
if (cubeb_stream_get_position(stream, &pos) != CUBEB_OK)
pos = 0;
const int playedSinceLastTime = (writtenSoFar - writtenLastTime) + (pos - positionLastTime);
writtenLastTime = writtenSoFar;
positionLastTime = pos;
return playedSinceLastTime;
}
const wchar_t* GetIdent() const override
{
return L"cubeb";
}
const wchar_t* GetLongName() const override
{
return L"Cubeb (Cross-platform)";
}
void ReadSettings() override
{
m_SuggestedLatencyMinimal = CfgReadBool(L"Cubeb", L"MinimalSuggestedLatency", false);
m_SuggestedLatencyMS = std::clamp(CfgReadInt(L"Cubeb", L"ManualSuggestedLatencyMS", MINIMUM_LATENCY_MS), MINIMUM_LATENCY_MS, MAXIMUM_LATENCY_MS);
// TODO: Once the config stuff gets merged, drop the wxString here.
wxString backend;
CfgReadStr(L"Cubeb", L"BackendName", backend, L"");
m_Backend = StringUtil::wxStringToUTF8String(backend);
}
void SetApiSettings(wxString api) override
{
}
void WriteSettings() const override
{
}
};
static Cubeb s_Cubeb;
SndOutModule* CubebOut = &s_Cubeb;

View File

@ -41,13 +41,14 @@
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libpng;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\glad\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\cubeb\cubeb\include;$(SolutionDir)3rdparty\cubeb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
<ForcedIncludeFiles>PrecompiledHeader.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/Zc:externConstexpr %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_PORTAUDIO;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_CUBEB;SPU2X_PORTAUDIO;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -357,6 +358,7 @@
<ClCompile Include="SPU2\DplIIdecoder.cpp" />
<ClCompile Include="SPU2\debug.cpp" />
<ClCompile Include="SPU2\RegLog.cpp" />
<ClCompile Include="SPU2\SndOut_Cubeb.cpp" />
<ClCompile Include="SPU2\SndOut_Portaudio.cpp" />
<ClCompile Include="SPU2\wavedump_wav.cpp" />
<ClCompile Include="SPU2\SndOut.cpp" />
@ -1157,6 +1159,9 @@
<ProjectReference Include="$(SolutionDir)3rdparty\jpgd\jpgd.vcxproj">
<Project>{ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\cubeb\cubeb.vcxproj">
<Project>{bf74c473-dc04-44b3-92e8-4145f4e77342}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{4639972e-424e-4e13-8b07-ca403c481346}</Project>
</ProjectReference>

View File

@ -1647,6 +1647,9 @@
<ClCompile Include="PerformanceMetrics.cpp">
<Filter>System</Filter>
</ClCompile>
<ClCompile Include="SPU2\SndOut_Cubeb.cpp">
<Filter>System\Ps2\SPU2</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">