mirror of https://github.com/PCSX2/pcsx2.git
SPU2: Add Cubeb SndOut driver
This commit is contained in:
parent
bd489647e9
commit
88ce192610
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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[];
|
||||
|
||||
|
|
|
@ -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, ¶ms, &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, ¶ms,
|
||||
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;
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue