SPU2: Remove Portaudio and SDL2 output modules

This commit is contained in:
Connor McLaughlin 2021-12-18 20:55:48 +10:00 committed by refractionpcsx2
parent 88ce192610
commit f3d51a242d
17 changed files with 210 additions and 1151 deletions

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2020 PCSX2 Dev Team * Copyright (C) 2002-2021 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * 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- * of the GNU Lesser General Public License as published by the Free Software Found-

View File

@ -46,9 +46,8 @@ option(PACKAGE_MODE "Use this option to ease packaging of PCSX2 (developer/distr
option(DISABLE_PCSX2_WRAPPER "Disable including the PCSX2-linux.sh file") option(DISABLE_PCSX2_WRAPPER "Disable including the PCSX2-linux.sh file")
option(DISABLE_SETCAP "Do not set files capabilities") option(DISABLE_SETCAP "Do not set files capabilities")
option(XDG_STD "Use XDG standard path instead of the standard PCSX2 path") option(XDG_STD "Use XDG standard path instead of the standard PCSX2 path")
option(PORTAUDIO_API "Build portaudio support on SPU2" ON)
option(CUBEB_API "Build Cubeb support on SPU2" ON) option(CUBEB_API "Build Cubeb support on SPU2" ON)
option(SDL2_API "Use SDL2 on SPU2 and PAD Linux (wxWidget mustn't be built with SDL1.2 support" ON) option(SDL2_API "Use SDL2 on PAD Linux (wxWidget mustn't be built with SDL1.2 support" ON)
option(GTK2_API "Use GTK2 api (legacy)") option(GTK2_API "Use GTK2 api (legacy)")
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)

View File

@ -12,7 +12,6 @@ if (WIN32)
add_subdirectory(3rdparty/libsamplerate EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/libsamplerate EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/baseclasses EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/baseclasses EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/freetype EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/freetype EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/portaudio EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/pthreads4w EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/pthreads4w EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/soundtouch EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/soundtouch EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL) add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL)
@ -144,9 +143,6 @@ else()
endif() endif()
endif() endif()
if(PORTAUDIO_API)
check_lib(PORTAUDIO portaudio portaudio.h pa_linux_alsa.h)
endif()
check_lib(SOUNDTOUCH SoundTouch SoundTouch.h PATH_SUFFIXES soundtouch) check_lib(SOUNDTOUCH SoundTouch SoundTouch.h PATH_SUFFIXES soundtouch)
check_lib(SAMPLERATE samplerate samplerate.h) check_lib(SAMPLERATE samplerate samplerate.h)

View File

@ -51,11 +51,6 @@ elseif("${PGO}" STREQUAL "use")
target_compile_options(PCSX2_FLAGS INTERFACE -fprofile-use) target_compile_options(PCSX2_FLAGS INTERFACE -fprofile-use)
endif() endif()
if(TARGET PkgConfig::PORTAUDIO)
target_compile_definitions(PCSX2_FLAGS INTERFACE SPU2X_PORTAUDIO)
target_link_libraries(PCSX2_FLAGS INTERFACE PkgConfig::PORTAUDIO)
endif()
if(TARGET PulseAudio::PulseAudio) if(TARGET PulseAudio::PulseAudio)
target_compile_definitions(PCSX2_FLAGS INTERFACE SPU2X_PULSEAUDIO) target_compile_definitions(PCSX2_FLAGS INTERFACE SPU2X_PULSEAUDIO)
target_link_libraries(PCSX2_FLAGS INTERFACE PulseAudio::PulseAudio) target_link_libraries(PCSX2_FLAGS INTERFACE PulseAudio::PulseAudio)
@ -293,17 +288,12 @@ set(pcsx2SPU2Sources
SPU2/RegTable.cpp SPU2/RegTable.cpp
SPU2/Reverb.cpp SPU2/Reverb.cpp
SPU2/SndOut.cpp SPU2/SndOut.cpp
SPU2/SndOut_SDL.cpp
SPU2/spu2freeze.cpp SPU2/spu2freeze.cpp
SPU2/spu2sys.cpp SPU2/spu2sys.cpp
SPU2/Timestretcher.cpp SPU2/Timestretcher.cpp
SPU2/Wavedump_wav.cpp SPU2/Wavedump_wav.cpp
) )
if(TARGET PkgConfig::PORTAUDIO)
list(APPEND pcsx2SPU2Sources SPU2/SndOut_Portaudio.cpp)
endif()
if(CUBEB_API) if(CUBEB_API)
list(APPEND pcsx2SPU2Sources SPU2/SndOut_Cubeb.cpp) list(APPEND pcsx2SPU2Sources SPU2/SndOut_Cubeb.cpp)
target_compile_definitions(PCSX2_FLAGS INTERFACE "SPU2X_CUBEB") target_compile_definitions(PCSX2_FLAGS INTERFACE "SPU2X_CUBEB")

View File

@ -64,10 +64,6 @@ bool _visual_debug_enabled = false; // Windows-only feature
u32 OutputModule = 0; u32 OutputModule = 0;
int SndOutLatencyMS = 100; int SndOutLatencyMS = 100;
int SynchMode = 0; // Time Stretch, Async or Disabled. int SynchMode = 0; // Time Stretch, Async or Disabled.
#ifdef SPU2X_PORTAUDIO
u32 OutputAPI = 0;
#endif
u32 SdlOutputAPI = 0;
int numSpeakers = 0; int numSpeakers = 0;
int dplLevel = 0; int dplLevel = 0;
@ -105,54 +101,20 @@ void ReadSettings()
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10); VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10); VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
#ifdef SPU2X_CUBEB
const SndOutModule* const defaultModule = CubebOut;
#else
const SndOutModule* const defaultModule = NullOut;
#endif
wxString temp; wxString temp;
CfgReadStr(L"OUTPUT", L"Output_Module", temp, defaultModule->GetIdent());
#if SDL_MAJOR_VERSION >= 2 || !defined(SPU2X_PORTAUDIO)
CfgReadStr(L"OUTPUT", L"Output_Module", temp, SDLOut->GetIdent());
#else
CfgReadStr(L"OUTPUT", L"Output_Module", temp, PortaudioOut->GetIdent());
#endif
OutputModule = FindOutputModuleById(temp.c_str()); // Find the driver index of this module... OutputModule = FindOutputModuleById(temp.c_str()); // Find the driver index of this module...
// Find current API.
#ifdef SPU2X_PORTAUDIO
#ifdef __linux__
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"ALSA");
if (temp == L"OSS")
OutputAPI = 1;
else if (temp == L"JACK")
OutputAPI = 2;
else // L"ALSA"
OutputAPI = 0;
#else
CfgReadStr(L"PORTAUDIO", L"HostApi", temp, L"OSS");
OutputAPI = 0; // L"OSS"
#endif
#endif
#if defined(__unix__) || defined(__APPLE__)
CfgReadStr(L"SDL", L"HostApi", temp, L"pulseaudio");
SdlOutputAPI = 0;
#if SDL_MAJOR_VERSION >= 2
// Yes, it sucks ...
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i)
{
if (!temp.Cmp(wxString(SDL_GetAudioDriver(i), wxConvUTF8)))
SdlOutputAPI = i;
}
#endif
#endif
SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 100); SndOutLatencyMS = CfgReadInt(L"OUTPUT", L"Latency", 100);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0); SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0); numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->ReadSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->ReadSettings();
#endif
SoundtouchCfg::ReadSettings(); SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings(); DebugConfig::ReadSettings();
@ -164,8 +126,8 @@ void ReadSettings()
if (mods[OutputModule] == nullptr) if (mods[OutputModule] == nullptr)
{ {
Console.Warning("* SPU2: Unknown output module '%s' specified in configuration file.", temp.wc_str()); Console.Warning("* SPU2: Unknown output module '%s' specified in configuration file.", temp.wc_str());
Console.Warning("* SPU2: Defaulting to SDL (%s).", SDLOut->GetIdent()); Console.Warning("* SPU2: Defaulting to %s (%s).", defaultModule->GetLongName(), defaultModule->GetIdent());
OutputModule = FindOutputModuleById(SDLOut->GetIdent()); OutputModule = FindOutputModuleById(defaultModule->GetIdent());
} }
WriteSettings(); WriteSettings();
@ -200,12 +162,6 @@ void WriteSettings()
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode); CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers); CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->WriteSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->WriteSettings();
#endif
SoundtouchCfg::WriteSettings(); SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings(); DebugConfig::WriteSettings();
} }

View File

@ -78,11 +78,6 @@ extern int dspPluginModule;
extern bool dspPluginEnabled; extern bool dspPluginEnabled;
extern int SynchMode; extern int SynchMode;
#ifdef SPU2X_PORTAUDIO
extern u32 OutputAPI;
#endif
extern u32 SdlOutputAPI;
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
const int LATENCY_MAX = 3000; const int LATENCY_MAX = 3000;
#else #else

View File

@ -49,50 +49,47 @@ StereoOut32 StereoOut16::UpSample() const
class NullOutModule : public SndOutModule class NullOutModule : public SndOutModule
{ {
public: public:
s32 Init() { return 0; } s32 Init() override { return 0; }
void Close() {} void Close() override {}
s32 Test() const { return 0; } s32 Test() const override { return 0; }
void Configure(uptr parent) {} void Configure(uptr parent) override {}
int GetEmptySampleCount() { return 0; } int GetEmptySampleCount() override { return 0; }
const wchar_t* GetIdent() const const wchar_t* GetIdent() const override
{ {
return L"nullout"; return L"nullout";
} }
const wchar_t* GetLongName() const const wchar_t* GetLongName() const override
{ {
return L"No Sound (Emulate SPU2 only)"; return L"No Sound (Emulate SPU2 only)";
} }
void ReadSettings() void ReadSettings() override
{ {
} }
void SetApiSettings(wxString api) void SetApiSettings(wxString api) override
{ {
} }
void WriteSettings() const void WriteSettings() const override
{ {
} }
} NullOut; };
static NullOutModule s_NullOut;
SndOutModule* NullOut = &s_NullOut;
SndOutModule* mods[] = SndOutModule* mods[] =
{ {
&NullOut, NullOut,
#ifdef _MSC_VER #ifdef _WIN32
XAudio2Out, XAudio2Out,
#endif #endif
#if defined(SPU2X_PORTAUDIO)
PortaudioOut,
#endif
#if defined(SPU2X_CUBEB) #if defined(SPU2X_CUBEB)
CubebOut, CubebOut,
#endif
#if defined(__linux__) || defined(__APPLE__)
SDLOut,
#endif #endif
nullptr // signals the end of our list nullptr // signals the end of our list
}; };
@ -169,7 +166,7 @@ void SndBuffer::_InitFail()
{ {
// If a failure occurs, just initialize the NoSound driver. This'll allow // If a failure occurs, just initialize the NoSound driver. This'll allow
// the game to emulate properly (hopefully), albeit without sound. // the game to emulate properly (hopefully), albeit without sound.
OutputModule = FindOutputModuleById(NullOut.GetIdent()); OutputModule = FindOutputModuleById(NullOut->GetIdent());
mods[OutputModule]->Init(); mods[OutputModule]->Init();
} }
@ -447,7 +444,7 @@ void SndBuffer::Write(const StereoOut32& Sample)
if (WavRecordEnabled) if (WavRecordEnabled)
RecordWrite(Sample.DownSample()); RecordWrite(Sample.DownSample());
if (mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p if (mods[OutputModule] == NullOut) // null output doesn't need buffering or stretching! :p
return; return;
sndTempBuffer[sndTempProgress++] = Sample; sndTempBuffer[sndTempProgress++] = Sample;
@ -464,7 +461,7 @@ void SndBuffer::Write(const StereoOut32& Sample)
// Play silence // Play silence
std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{}); std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{});
} }
#ifndef __POSIX__ #if defined(_WIN32) && !defined(PCSX2_CORE)
if (dspPluginEnabled) if (dspPluginEnabled)
{ {
// Convert in, send to winamp DSP, and convert out. // Convert in, send to winamp DSP, and convert out.

View File

@ -663,17 +663,13 @@ public:
virtual int GetEmptySampleCount() = 0; virtual int GetEmptySampleCount() = 0;
}; };
#ifdef _MSC_VER extern SndOutModule* NullOut;
//internal #ifdef _WIN32
extern SndOutModule* XAudio2Out; extern SndOutModule* XAudio2Out;
#endif #endif
#if defined(SPU2X_PORTAUDIO)
extern SndOutModule* PortaudioOut;
#endif
#if defined(SPU2X_CUBEB) #if defined(SPU2X_CUBEB)
extern SndOutModule* CubebOut; extern SndOutModule* CubebOut;
#endif #endif
extern SndOutModule* const SDLOut;
extern SndOutModule* mods[]; extern SndOutModule* mods[];
// ===================================================================================================== // =====================================================================================================

View File

@ -1,757 +0,0 @@
/* 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 "Mixer.h"
#include "Global.h"
#include "SndOut.h"
#define _WIN32_DCOM
#ifdef _WIN32
#include <portaudio/include/portaudio.h>
#include "Windows/Dialogs.h"
#elif defined(__linux__) || defined(__APPLE__)
#include "portaudio.h"
#include "Linux/Dialogs.h"
#endif
#include "wchar.h"
#include <vector>
#ifdef _WIN32
#include <portaudio/include/pa_win_wasapi.h>
#endif
#include "Debug.h"
int PaCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData);
class Portaudio : public SndOutModule
{
private:
//////////////////////////////////////////////////////////////////////////////////////////
// Configuration Vars (unused still)
int m_ApiId;
wxString m_Device;
bool m_UseHardware;
bool m_WasapiExclusiveMode;
bool m_SuggestedLatencyMinimal;
int m_SuggestedLatencyMS;
//////////////////////////////////////////////////////////////////////////////////////////
// Instance vars
int writtenSoFar;
int writtenLastTime;
int availableLastTime;
int actualUsedChannels;
bool started;
PaStream* stream;
//////////////////////////////////////////////////////////////////////////////////////////
// Stuff necessary for speaker expansion
class SampleReader
{
public:
virtual int ReadSamples(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData) = 0;
};
template <class T>
class ConvertedSampleReader : public SampleReader
{
int* written;
public:
ConvertedSampleReader(int* pWritten)
{
written = pWritten;
}
virtual int ReadSamples(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
T* p1 = (T*)outputBuffer;
int packets = framesPerBuffer / SndOutPacketSize;
for (int p = 0; p < packets; p++, p1 += SndOutPacketSize)
SndBuffer::ReadSamples(p1);
(*written) += packets * SndOutPacketSize;
return 0;
}
};
public:
SampleReader* ActualPaCallback;
Portaudio()
{
m_SuggestedLatencyMinimal = true;
m_UseHardware = false;
m_WasapiExclusiveMode = false;
started = false;
stream = nullptr;
ActualPaCallback = nullptr;
m_ApiId = -1;
m_SuggestedLatencyMS = 20;
actualUsedChannels = 0;
writtenSoFar = 0;
writtenLastTime = 0;
availableLastTime = 0;
}
s32 Init()
{
started = false;
stream = nullptr;
ReadSettings();
PaError err = Pa_Initialize();
if (err != paNoError)
{
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
return -1;
}
started = true;
int deviceIndex = -1;
fprintf(stderr, "* SPU2: Enumerating PortAudio devices:\n");
for (int i = 0, j = 0; i < Pa_GetDeviceCount(); i++)
{
const PaDeviceInfo* info = Pa_GetDeviceInfo(i);
if (info->maxOutputChannels > 0)
{
const PaHostApiInfo* apiinfo = Pa_GetHostApiInfo(info->hostApi);
fprintf(stderr, " *** Device %d: '%s' (%s)", j, info->name, apiinfo->name);
if (apiinfo->type == m_ApiId)
{
if (m_Device == wxString::FromUTF8(info->name))
{
deviceIndex = i;
fprintf(stderr, " (selected)");
}
}
fprintf(stderr, "\n");
j++;
}
}
fflush(stderr);
if (deviceIndex < 0 && m_ApiId >= 0)
{
for (int i = 0; i < Pa_GetHostApiCount(); i++)
{
const PaHostApiInfo* apiinfo = Pa_GetHostApiInfo(i);
if (apiinfo->type == m_ApiId)
{
deviceIndex = apiinfo->defaultOutputDevice;
}
}
}
if (deviceIndex >= 0)
{
void* infoPtr = nullptr;
const PaDeviceInfo* devinfo = Pa_GetDeviceInfo(deviceIndex);
int speakers;
switch (numSpeakers) // speakers = (numSpeakers + 1) *2; ?
{
case 0:
speakers = 2;
break; // Stereo
case 1:
speakers = 4;
break; // Quadrafonic
case 2:
speakers = 6;
break; // Surround 5.1
case 3:
speakers = 8;
break; // Surround 7.1
default:
speakers = 2;
}
actualUsedChannels = std::min(speakers, devinfo->maxOutputChannels);
switch (actualUsedChannels)
{
case 2:
ConLog("* SPU2 > Using normal 2 speaker stereo output.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo20Out32>(&writtenSoFar);
break;
case 3:
ConLog("* SPU2 > 2.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo21Out32>(&writtenSoFar);
break;
case 4:
ConLog("* SPU2 > 4 speaker expansion enabled [quadraphenia]\n");
ActualPaCallback = new ConvertedSampleReader<Stereo40Out32>(&writtenSoFar);
break;
case 5:
ConLog("* SPU2 > 4.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo41Out32>(&writtenSoFar);
break;
case 6:
case 7:
switch (dplLevel)
{
case 0:
ConLog("* SPU2 > 5.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32>(&writtenSoFar); //"normal" stereo upmix
break;
case 1:
ConLog("* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32Dpl>(&writtenSoFar); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog("* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32DplII>(&writtenSoFar); //gigas PLII
break;
}
actualUsedChannels = 6; // we do not support 7.0 or 6.2 configurations, downgrade to 5.1
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog("* SPU2 > 7.1 speaker expansion enabled.\n");
ActualPaCallback = new ConvertedSampleReader<Stereo71Out32>(&writtenSoFar);
actualUsedChannels = 8; // we do not support 7.2 or more, downgrade to 7.1
break;
}
#ifdef _WIN32
PaWasapiStreamInfo info = {
sizeof(PaWasapiStreamInfo),
paWASAPI,
1,
paWinWasapiExclusive};
if ((m_ApiId == paWASAPI) && m_WasapiExclusiveMode)
{
// Pass it the Exclusive mode enable flag
infoPtr = &info;
}
#endif
PaStreamParameters outParams = {
// PaDeviceIndex device;
// int channelCount;
// PaSampleFormat sampleFormat;
// PaTime suggestedLatency;
// void *hostApiSpecificStreamInfo;
deviceIndex,
actualUsedChannels,
paInt32,
m_SuggestedLatencyMinimal ? (SndOutPacketSize / (float)SampleRate) : (m_SuggestedLatencyMS / 1000.0f),
infoPtr};
err = Pa_OpenStream(&stream,
nullptr, &outParams, SampleRate,
SndOutPacketSize,
paNoFlag,
PaCallback,
nullptr);
if (err == paInvalidSampleRate && SampleRate == 48000)
{
DevCon.Warning("Failed to create device at 48khz, trying 96khz");
SampleRate = 96000;
err = Pa_OpenStream(&stream,
nullptr, &outParams, SampleRate,
SndOutPacketSize,
paNoFlag,
PaCallback,
nullptr);
}
if (err == paInvalidSampleRate && SampleRate == 96000) // It didn't work, so lets just put the samplerate back
SampleRate = 48000;
}
else
{
err = Pa_OpenDefaultStream(&stream,
0, actualUsedChannels, paInt32, 48000,
SndOutPacketSize,
PaCallback,
nullptr);
}
if (err != paNoError)
{
if (err == paInvalidSampleRate)
Console.Warning("Failed to create Port Audio Device %dkhz, Please use Exclusive Mode", SampleRate / 1000);
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
Pa_Terminate();
return -1;
}
err = Pa_StartStream(stream);
if (err != paNoError)
{
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
Pa_CloseStream(stream);
stream = nullptr;
Pa_Terminate();
return -1;
}
return 0;
}
void Close()
{
PaError err;
if (started)
{
if (stream)
{
if (Pa_IsStreamActive(stream))
{
err = Pa_StopStream(stream);
if (err != paNoError)
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
}
err = Pa_CloseStream(stream);
if (err != paNoError)
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
stream = nullptr;
}
PaError err = Pa_Terminate();
if( err != paNoError )
fprintf(stderr,"* SPU2: PortAudio error: %s\n", Pa_GetErrorText( err ) );
started = false;
}
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
#ifdef _WIN32
private:
bool _ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
int tSel = 0;
switch (uMsg)
{
case WM_INITDIALOG:
{
wchar_t temp[128];
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, 0, 0);
SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_ADDSTRING, 0, (LPARAM) "Unspecified");
int idx = 0;
for (int i = 0; i < Pa_GetHostApiCount(); i++)
{
const PaHostApiInfo* apiinfo = Pa_GetHostApiInfo(i);
if (apiinfo->deviceCount > 0)
{
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_ADDSTRING, 0, (LPARAM)apiinfo->name);
SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_SETITEMDATA, i + 1, apiinfo->type);
}
if (apiinfo->type == m_ApiId)
{
idx = i + 1;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_SETCURSEL, idx, 0);
if (idx > 0)
{
int api_idx = idx - 1;
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, 0, 0);
int _idx = 0;
int i = 1;
for (int j = 0; j < Pa_GetDeviceCount(); j++)
{
const PaDeviceInfo* info = Pa_GetDeviceInfo(j);
if (info->hostApi == api_idx && info->maxOutputChannels > 0)
{
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM)wxString::FromUTF8(info->name).wc_str());
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, i, (LPARAM)info);
if (wxString::FromUTF8(info->name) == m_Device)
{
_idx = i;
}
i++;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, _idx, 0);
}
INIT_SLIDER(IDC_LATENCY, 10, 200, 10, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_SETPOS, TRUE, m_SuggestedLatencyMS);
swprintf_s(temp, L"%d ms", m_SuggestedLatencyMS);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
if (m_SuggestedLatencyMinimal)
SET_CHECK(IDC_MINIMIZE, true);
else
SET_CHECK(IDC_MANUAL, true);
SET_CHECK(IDC_EXCLUSIVE, m_WasapiExclusiveMode);
}
break;
case WM_COMMAND:
{
//wchar_t temp[128];
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETCURSEL, 0, 0);
m_ApiId = SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETITEMDATA, idx, 0);
idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_GETCURSEL, 0, 0);
const PaDeviceInfo* info = (const PaDeviceInfo*)SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_GETITEMDATA, idx, 0);
if (info)
m_Device = wxString::FromUTF8(info->name);
else
m_Device = L"default";
m_SuggestedLatencyMS = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_GETPOS, 0, 0);
if (m_SuggestedLatencyMS < 10)
m_SuggestedLatencyMS = 10;
if (m_SuggestedLatencyMS > 200)
m_SuggestedLatencyMS = 200;
m_SuggestedLatencyMinimal = SendMessage(GetDlgItem(hWnd, IDC_MINIMIZE), BM_GETCHECK, 0, 0) == BST_CHECKED;
m_WasapiExclusiveMode = SendMessage(GetDlgItem(hWnd, IDC_EXCLUSIVE), BM_GETCHECK, 0, 0) == BST_CHECKED;
EndDialog(hWnd, 0);
}
break;
case IDCANCEL:
EndDialog(hWnd, 0);
break;
case IDC_PA_HOSTAPI:
{
if (wmEvent == CBN_SELCHANGE)
{
int api_idx = (int)SendMessage(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETCURSEL, 0, 0) - 1;
int apiId = SendMessageA(GetDlgItem(hWnd, IDC_PA_HOSTAPI), CB_GETITEMDATA, api_idx, 0);
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_RESETCONTENT, 0, 0);
SendMessageA(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM) "Default Device");
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, 0, 0);
int idx = 0;
int i = 1;
for (int j = 0; j < Pa_GetDeviceCount(); j++)
{
const PaDeviceInfo* info = Pa_GetDeviceInfo(j);
if (info->hostApi == api_idx && info->maxOutputChannels > 0)
{
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_ADDSTRING, 0, (LPARAM)wxString::FromUTF8(info->name).wc_str());
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETITEMDATA, i, (LPARAM)info);
i++;
}
}
SendMessage(GetDlgItem(hWnd, IDC_PA_DEVICE), CB_SETCURSEL, idx, 0);
}
}
break;
default:
return FALSE;
}
}
break;
case WM_HSCROLL:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK:
{
wchar_t temp[128];
if (wmEvent < 10)
wmEvent = 10;
if (wmEvent > 200)
wmEvent = 200;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d ms", wmEvent);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
}
default:
return FALSE;
}
}
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext);
public:
virtual void Configure(uptr parent)
{
PaError err = Pa_Initialize(); // Initialization can be done multiple times, PA keeps a counter
if (err != paNoError)
{
fprintf(stderr, "* SPU2: PortAudio error: %s\n", Pa_GetErrorText(err));
return;
}
// keep portaudio initialized until the dialog closes
INT_PTR ret;
ret = DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_PORTAUDIO), (HWND)parent, (DLGPROC)ConfigProc, 1);
if (ret == -1)
{
MessageBox((HWND)parent, L"Error Opening the config dialog.", L"OMG ERROR!", MB_OK | MB_SETFOREGROUND);
return;
}
Pa_Terminate();
}
#else
virtual void Configure(uptr parent)
{
}
#endif
s32 Test() const
{
return 0;
}
int GetEmptySampleCount()
{
long availableNow = Pa_GetStreamWriteAvailable(stream);
int playedSinceLastTime = (writtenSoFar - writtenLastTime) + (availableNow - availableLastTime);
writtenLastTime = writtenSoFar;
availableLastTime = availableNow;
// Lowest resolution here is the SndOutPacketSize we use.
return playedSinceLastTime;
}
const wchar_t* GetIdent() const
{
return L"portaudio";
}
const wchar_t* GetLongName() const
{
return L"PortAudio (Cross-platform)";
}
void ReadSettings()
{
wxString api(L"EMPTYEMPTYEMPTY");
m_Device = L"EMPTYEMPTYEMPTY";
#ifdef __linux__
// By default on linux use the ALSA API (+99% users) -- Gregory
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"ALSA");
#elif defined(__APPLE__)
// Suppose OSX only has CoreAudio...
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"CoreAudio");
#else
CfgReadStr(L"PORTAUDIO", L"HostApi", api, L"WASAPI");
#endif
CfgReadStr(L"PORTAUDIO", L"Device", m_Device, L"default");
SetApiSettings(api);
m_WasapiExclusiveMode = CfgReadBool(L"PORTAUDIO", L"Wasapi_Exclusive_Mode", false);
m_SuggestedLatencyMinimal = CfgReadBool(L"PORTAUDIO", L"Minimal_Suggested_Latency", true);
m_SuggestedLatencyMS = CfgReadInt(L"PORTAUDIO", L"Manual_Suggested_Latency_MS", 20);
if (m_SuggestedLatencyMS < 10)
m_SuggestedLatencyMS = 10;
if (m_SuggestedLatencyMS > 200)
m_SuggestedLatencyMS = 200;
}
void SetApiSettings(wxString api)
{
m_ApiId = -1;
if (api == L"InDevelopment")
m_ApiId = paInDevelopment; /* use while developing support for a new host API */
if (api == L"DirectSound")
m_ApiId = paDirectSound;
if (api == L"MME")
m_ApiId = paMME;
if (api == L"ASIO")
m_ApiId = paASIO;
if (api == L"SoundManager")
m_ApiId = paSoundManager;
if (api == L"CoreAudio")
m_ApiId = paCoreAudio;
if (api == L"OSS")
m_ApiId = paOSS;
if (api == L"ALSA")
m_ApiId = paALSA;
if (api == L"AL")
m_ApiId = paAL;
if (api == L"BeOS")
m_ApiId = paBeOS;
if (api == L"WDMKS")
m_ApiId = paWDMKS;
if (api == L"JACK")
m_ApiId = paJACK;
if (api == L"WASAPI")
m_ApiId = paWASAPI;
if (api == L"AudioScienceHPI")
m_ApiId = paAudioScienceHPI;
}
void WriteSettings() const
{
wxString api;
switch (m_ApiId)
{
case paInDevelopment:
api = L"InDevelopment";
break; /* use while developing support for a new host API */
case paDirectSound:
api = L"DirectSound";
break;
case paMME:
api = L"MME";
break;
case paASIO:
api = L"ASIO";
break;
case paSoundManager:
api = L"SoundManager";
break;
case paCoreAudio:
api = L"CoreAudio";
break;
case paOSS:
api = L"OSS";
break;
case paALSA:
api = L"ALSA";
break;
case paAL:
api = L"AL";
break;
case paBeOS:
api = L"BeOS";
break;
case paWDMKS:
api = L"WDMKS";
break;
case paJACK:
api = L"JACK";
break;
case paWASAPI:
api = L"WASAPI";
break;
case paAudioScienceHPI:
api = L"AudioScienceHPI";
break;
default:
api = L"Unknown";
}
CfgWriteStr(L"PORTAUDIO", L"HostApi", api);
CfgWriteStr(L"PORTAUDIO", L"Device", m_Device);
CfgWriteBool(L"PORTAUDIO", L"Wasapi_Exclusive_Mode", m_WasapiExclusiveMode);
CfgWriteBool(L"PORTAUDIO", L"Minimal_Suggested_Latency", m_SuggestedLatencyMinimal);
CfgWriteInt(L"PORTAUDIO", L"Manual_Suggested_Latency_MS", m_SuggestedLatencyMS);
}
} static PA;
int PaCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
return PA.ActualPaCallback->ReadSamples(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
}
#ifdef _WIN32
BOOL CALLBACK Portaudio::ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return PA._ConfigProc(hWnd, uMsg, wParam, lParam);
}
#endif
SndOutModule* PortaudioOut = &PA;

View File

@ -1,196 +0,0 @@
/* 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"
#ifdef SDL_BUILD
#include <cassert>
#include <iostream>
#include "Global.h"
#include "SndOut.h"
#if defined(_WIN32)
#include "Windows/Dialogs.h"
#else // BSD, Macos
#include "Linux/Dialogs.h"
#endif
#include <memory>
/* Using SDL2 requires other SDL dependencies in pcsx2 get upgraded as well, or the
* symbol tables would conflict. Other dependencies in Linux are wxwidgets (you can
* build wx without sdl support, though) and onepad at the time of writing this. */
#include <SDL.h>
#include <SDL_audio.h>
typedef StereoOut16 StereoOut_SDL;
namespace
{
/* Since spu2 only ever outputs stereo, we don't worry about emitting surround sound
* even though SDL2 supports it */
const Uint8 channels = 2;
/* SDL2 supports s32 audio */
/* Samples should vary from [512,8192] according to SDL spec. Take note this is the desired
* sample count and SDL may provide otherwise. Pulseaudio will cut this value in half if
* PA_STREAM_ADJUST_LATENCY is set in the backened, for example. */
const Uint16 desiredSamples = 2048;
const Uint16 format = AUDIO_S16SYS;
Uint16 samples = desiredSamples;
void callback_fillBuffer(void* userdata, Uint8* stream, int len)
{
StereoOut16* out = (StereoOut16*)stream;
// Length should always be samples in bytes.
assert(len / sizeof(StereoOut_SDL) == samples);
for (Uint16 i = 0; i < samples; i += SndOutPacketSize)
SndBuffer::ReadSamples(&out[i]);
}
} // namespace
struct SDLAudioMod : public SndOutModule
{
static SDLAudioMod mod;
std::string m_api;
s32 Init()
{
ReadSettings();
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Request SDL audio driver: " << m_api.c_str() << std::endl;
#endif
/* SDL backends will mangle the AudioSpec and change the sample count. If we reopen
* the audio backend, we need to make sure we keep our desired samples in the spec */
spec.samples = desiredSamples;
// Mandatory otherwise, init will be redone in SDL_OpenAudio
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
std::cerr << "SPU2: SDL INIT audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
if (m_api.compare("pulseaudio"))
{
// Close the audio, but keep the subsystem open
SDL_AudioQuit();
// Reopen the audio
if (SDL_AudioInit(m_api.c_str()) < 0)
{
std::cerr << "SPU2: SDL audio init error: " << SDL_GetError() << std::endl;
return -1;
}
}
#endif
if (SDL_OpenAudio(&spec, nullptr) < 0)
{
std::cerr << "SPU2: SDL audio error: " << SDL_GetError() << std::endl;
return -1;
}
#if SDL_MAJOR_VERSION >= 2
std::cerr << "Opened SDL audio driver: " << SDL_GetCurrentAudioDriver() << std::endl;
#endif
if (samples != spec.samples)
{
fprintf(stderr, "SPU2: SDL failed to get desired samples (%d) got %d samples instead\n", samples, spec.samples);
// Samples must always be a multiple of packet size.
assert(spec.samples % SndOutPacketSize == 0);
samples = spec.samples;
}
SDL_PauseAudio(0);
return 0;
}
const wchar_t* GetIdent() const { return L"SDLAudio"; }
const wchar_t* GetLongName() const { return L"SDL Audio"; }
void Close()
{
// Related to SDL_Init(SDL_INIT_AUDIO)
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
~SDLAudioMod() { Close(); }
s32 Test() const { return 0; }
int GetEmptySampleCount() { return 0; }
void Configure(uptr parent) {}
void ReadSettings()
{
wxString api(L"EMPTYEMPTYEMPTY");
CfgReadStr(L"SDL", L"HostApi", api, L"pulseaudio");
SetApiSettings(api);
}
void WriteSettings() const
{
CfgWriteStr(L"SDL", L"HostApi", wxString(m_api.c_str(), wxConvUTF8));
};
void SetApiSettings(wxString api)
{
#if SDL_MAJOR_VERSION >= 2
// Validate the api name
bool valid = false;
std::string api_name = std::string(api.utf8_str());
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i)
{
valid |= (api_name.compare(SDL_GetAudioDriver(i)) == 0);
}
if (valid)
{
m_api = api.utf8_str();
}
else
{
std::cerr << "SDL audio driver configuration is invalid!" << std::endl
<< "It will be replaced by pulseaudio!" << std::endl;
m_api = "pulseaudio";
}
#endif
}
private:
SDL_AudioSpec spec;
SDLAudioMod()
: m_api("pulseaudio")
, spec({SampleRate, format, channels, 0,
desiredSamples, 0, 0, &callback_fillBuffer, nullptr})
{
// Number of samples must be a multiple of packet size.
assert(samples % SndOutPacketSize == 0);
}
};
SDLAudioMod SDLAudioMod::mod;
SndOutModule* const SDLOut = &SDLAudioMod::mod;
#endif // SDL_BUILD

View File

@ -126,8 +126,6 @@ void ReadSettings()
dspPluginModule = CfgReadInt(L"DSP PLUGIN", L"ModuleNum", 0); dspPluginModule = CfgReadInt(L"DSP PLUGIN", L"ModuleNum", 0);
dspPluginEnabled = CfgReadBool(L"DSP PLUGIN", L"Enabled", false); dspPluginEnabled = CfgReadBool(L"DSP PLUGIN", L"Enabled", false);
PortaudioOut->ReadSettings();
SoundtouchCfg::ReadSettings(); SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings(); DebugConfig::ReadSettings();
@ -173,7 +171,6 @@ void WriteSettings()
CfgWriteInt(L"DSP PLUGIN", L"ModuleNum", dspPluginModule); CfgWriteInt(L"DSP PLUGIN", L"ModuleNum", dspPluginModule);
CfgWriteBool(L"DSP PLUGIN", L"Enabled", dspPluginEnabled); CfgWriteBool(L"DSP PLUGIN", L"Enabled", dspPluginEnabled);
PortaudioOut->WriteSettings();
SoundtouchCfg::WriteSettings(); SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings(); DebugConfig::WriteSettings();
} }
@ -181,16 +178,131 @@ void WriteSettings()
void CheckOutputModule(HWND window) void CheckOutputModule(HWND window)
{ {
OutputModule = SendMessage(GetDlgItem(window, IDC_OUTPUT), CB_GETCURSEL, 0, 0); OutputModule = SendMessage(GetDlgItem(window, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
const bool IsConfigurable = mods[OutputModule] == PortaudioOut; const bool IsConfigurable = mods[OutputModule] == CubebOut;
const bool AudioExpansion = const bool AudioExpansion =
mods[OutputModule] == XAudio2Out || mods[OutputModule] == XAudio2Out ||
mods[OutputModule] == PortaudioOut; mods[OutputModule] == CubebOut;
EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable); EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS), AudioExpansion); EnableWindow(GetDlgItem(window, IDC_SPEAKERS), AudioExpansion);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS_TEXT), AudioExpansion); EnableWindow(GetDlgItem(window, IDC_SPEAKERS_TEXT), AudioExpansion);
} }
static BOOL CALLBACK CubebConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
static constexpr wchar_t* cubeb_backend_names[][2] = {
{L"Unspecified", L""},
{L"WASAPI", L"wasapi"},
{L"WinMM", L"winmm"}};
const bool minimalLatency = CfgReadBool(L"Cubeb", L"MinimalSuggestedLatency", false);
const int suggestedLatencyMS = CfgReadInt(L"Cubeb", L"ManualSuggestedLatencyMS", 20);
wxString backend;
CfgReadStr(L"Cubeb", L"BackendName", backend, L"");
SendMessage(GetDlgItem(hWnd, IDC_BACKEND), CB_RESETCONTENT, 0, 0);
for (size_t i = 0; i < std::size(cubeb_backend_names); i++)
{
SendMessageW(GetDlgItem(hWnd, IDC_BACKEND), CB_ADDSTRING, (WPARAM)i, (LPARAM)cubeb_backend_names[i][0]);
SendMessageW(GetDlgItem(hWnd, IDC_BACKEND), CB_SETITEMDATA, (WPARAM)i, (LPARAM)cubeb_backend_names[i][1]);
if (backend == cubeb_backend_names[i][1])
SendMessage(GetDlgItem(hWnd, IDC_BACKEND), CB_SETCURSEL, (WPARAM)i, 0);
}
INIT_SLIDER(IDC_LATENCY, 10, 200, 10, 1, 1);
SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_SETPOS, TRUE, suggestedLatencyMS);
wchar_t temp[128];
swprintf_s(temp, L"%d ms", suggestedLatencyMS);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
if (minimalLatency)
SET_CHECK(IDC_MINIMIZE, true);
else
SET_CHECK(IDC_MANUAL, true);
return TRUE;
}
break;
case WM_COMMAND:
{
const DWORD wmId = LOWORD(wParam);
const DWORD wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int idx = (int)SendMessage(GetDlgItem(hWnd, IDC_BACKEND), CB_GETCURSEL, 0, 0);
const wchar_t* backend = (const wchar_t*)SendMessage(GetDlgItem(hWnd, IDC_BACKEND), CB_GETITEMDATA, idx, 0);
CfgWriteStr(L"Cubeb", L"BackendName", backend);
const int suggestedLatencyMS = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY), TBM_GETPOS, 0, 0);
const bool minimalLatency = SendMessage(GetDlgItem(hWnd, IDC_MINIMIZE), BM_GETCHECK, 0, 0) == BST_CHECKED;
CfgWriteBool(L"Cubeb", L"MinimalSuggestedLatency", minimalLatency);
CfgWriteInt(L"Cubeb", L"ManualSuggestedLatencyMS", suggestedLatencyMS);
EndDialog(hWnd, 0);
return TRUE;
}
break;
case IDCANCEL:
EndDialog(hWnd, 0);
return TRUE;
default:
return FALSE;
}
}
break;
case WM_HSCROLL:
{
const DWORD wmId = LOWORD(wParam);
DWORD wmEvent = HIWORD(wParam);
switch (wmId)
{
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
wmEvent = (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
case TB_THUMBPOSITION:
case TB_THUMBTRACK:
{
wchar_t temp[128];
if (wmEvent < 10)
wmEvent = 10;
if (wmEvent > 200)
wmEvent = 200;
SendMessage((HWND)lParam, TBM_SETPOS, TRUE, wmEvent);
swprintf_s(temp, L"%d ms", wmEvent);
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
break;
}
default:
return FALSE;
}
return TRUE;
}
break;
default:
return FALSE;
}
return FALSE;
}
BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
int wmId, wmEvent; int wmId, wmEvent;
@ -298,9 +410,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case IDC_OUTCONF: case IDC_OUTCONF:
{ {
const int module = (int)SendMessage(GetDlgItem(hWnd, IDC_OUTPUT), CB_GETCURSEL, 0, 0); const int module = (int)SendMessage(GetDlgItem(hWnd, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
if (mods[module] == nullptr) if (mods[module] != CubebOut)
break; break;
mods[module]->Configure((uptr)hWnd);
if (DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_CUBEB), hWnd, (DLGPROC)CubebConfigProc, 1) == -1)
MessageBox(hWnd, L"Error Opening the config dialog.", L"Error", MB_OK | MB_SETFOREGROUND);
} }
break; break;

View File

@ -7,7 +7,6 @@
// //
// Generated from the TEXTINCLUDE 2 resource. // Generated from the TEXTINCLUDE 2 resource.
// //
#include "svnrev.h"
#include "common/afxresmw.h" #include "common/afxresmw.h"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
@ -175,25 +174,22 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// Dialog // Dialog
// //
IDD_PORTAUDIO DIALOGEX 0, 0, 316, 166 IDD_CUBEB DIALOGEX 0, 0, 316, 166
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Portaudio Output Module Settings" CAPTION "Cubeb Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "OK",IDOK,105,144,50,14 DEFPUSHBUTTON "OK",IDOK,105,144,50,14
PUSHBUTTON "Cancel",IDCANCEL,161,144,50,14 PUSHBUTTON "Cancel",IDCANCEL,161,144,50,14
COMBOBOX IDC_PA_HOSTAPI,7,17,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_BACKEND,7,17,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Host API:",IDC_STATIC,7,7,32,8 LTEXT "Backend:",IDC_STATIC,7,7,32,8
COMBOBOX IDC_PA_DEVICE,108,17,201,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Device Name:",IDC_STATIC,107,7,45,8
CONTROL "",IDC_LATENCY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,96,93,155,10 CONTROL "",IDC_LATENCY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,96,93,155,10
LTEXT "NOTE: Depending on the hardware and drivers, the suggested manual latency might not be used, and portaudio will choose the closest possible value.",IDC_STATIC,12,111,286,19 LTEXT "NOTE: Depending on the hardware and drivers, the suggested manual latency might not be used, and Cubeb will choose the closest possible value.",IDC_STATIC,12,111,286,19
CTEXT "20ms",IDC_LATENCY_LABEL,264,93,35,11 CTEXT "20ms",IDC_LATENCY_LABEL,264,93,35,11
GROUPBOX "Output Latency",IDC_STATIC,7,57,302,79 GROUPBOX "Output Latency",IDC_STATIC,7,57,302,79
CONTROL "Use smallest possible (may cause issues if the actual value is too small)",IDC_MINIMIZE, CONTROL "Use smallest possible (may cause issues if the actual value is too small)",IDC_MINIMIZE,
"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,75,258,10 "Button",BS_AUTORADIOBUTTON | WS_GROUP,12,75,258,10
CONTROL "Use this latency:",IDC_MANUAL,"Button",BS_AUTORADIOBUTTON,12,93,69,10 CONTROL "Use this latency:",IDC_MANUAL,"Button",BS_AUTORADIOBUTTON,12,93,69,10
CONTROL "WASAPI Exclusive Mode",IDC_EXCLUSIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,39,93,10
END END
@ -205,7 +201,7 @@ END
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO GUIDELINES DESIGNINFO
BEGIN BEGIN
IDD_PORTAUDIO, DIALOG IDD_CUBEB, DIALOG
BEGIN BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 309 RIGHTMARGIN, 309

View File

@ -5,7 +5,7 @@
#define IDD_DEBUG 105 #define IDD_DEBUG 105
#define IDD_CONFIG_SOUNDTOUCH 117 #define IDD_CONFIG_SOUNDTOUCH 117
#define IDD_CONFIG_DEBUG 118 #define IDD_CONFIG_DEBUG 118
#define IDD_PORTAUDIO 119 #define IDD_CUBEB 119
#define IDC_DUMPREGS 1003 #define IDC_DUMPREGS 1003
#define IDC_DUMPMEM 1004 #define IDC_DUMPMEM 1004
#define IDC_DUMPCORE 1005 #define IDC_DUMPCORE 1005
@ -27,7 +27,6 @@
#define IDC_OUTCONF 1028 #define IDC_OUTCONF 1028
#define IDC_DSP_ENABLE 1029 #define IDC_DSP_ENABLE 1029
#define IDC_DS_DEVICE 1032 #define IDC_DS_DEVICE 1032
#define IDC_PA_DEVICE 1033
#define IDC_DBG_OVERRUNS 1038 #define IDC_DBG_OVERRUNS 1038
#define IDC_DBG_CACHE 1039 #define IDC_DBG_CACHE 1039
#define IDC_LATENCY_SLIDER 1040 #define IDC_LATENCY_SLIDER 1040
@ -50,9 +49,8 @@
#define IDC_VOLUME_SLIDER 1068 #define IDC_VOLUME_SLIDER 1068
#define IDC_MINIMIZE 1069 #define IDC_MINIMIZE 1069
#define IDC_MANUAL 1070 #define IDC_MANUAL 1070
#define IDC_PA_HOSTAPI 1071 #define IDC_BACKEND 1071
#define IDC_LATENCY 1072 #define IDC_LATENCY 1072
#define IDC_EXCLUSIVE 1073
// Next default values for new objects // Next default values for new objects
// //

View File

@ -17,10 +17,22 @@
#include "SPU2/Config.h" #include "SPU2/Config.h"
#if !defined(_WIN32) // BSD, Macos #if !defined(_WIN32) // BSD, Macos
#include "SPU2/Linux/Config.h" #include "SPU2/Linux/Config.h"
#include "SPU2/Linux/Dialogs.h"
#endif #endif
#include "SPU2/Global.h" #include "SPU2/Global.h"
#include "wxConfig.h" #include "wxConfig.h"
static const wchar_t* s_backend_names[][2] = {
{L"Automatic", L""},
#ifdef __linux__
{L"ALSA", L"alsa"},
{L"JACK", L"jack"},
{L"PulseAudio", L"pulseaudio"},
#elif defined(__APPLE__)
{L"AudioUnit", L"audiounit"},
#endif
};
MixerTab::MixerTab(wxWindow* parent) MixerTab::MixerTab(wxWindow* parent)
: wxPanel(parent, wxID_ANY) : wxPanel(parent, wxID_ANY)
{ {
@ -352,49 +364,27 @@ Dialog::Dialog()
wxArrayString module_entries; wxArrayString module_entries;
module_entries.Add("No Sound (Emulate SPU2 only)"); module_entries.Add("No Sound (Emulate SPU2 only)");
#ifdef SPU2X_PORTAUDIO #ifdef SPU2X_CUBEB
module_entries.Add("PortAudio (Cross-platform)"); module_entries.Add("Cubeb (Cross-platform)");
#endif #endif
module_entries.Add("SDL Audio (Recommended for PulseAudio)");
m_module_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, module_entries); m_module_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, module_entries);
module_box->Add(m_module_select, wxSizerFlags().Centre()); module_box->Add(m_module_select, wxSizerFlags().Centre());
#ifdef SPU2X_PORTAUDIO #ifdef SPU2X_CUBEB
// Portaudio // Portaudio
m_portaudio_box = new wxBoxSizer(wxVERTICAL); m_cubeb_box = new wxBoxSizer(wxVERTICAL);
m_portaudio_text = new wxStaticText(this, wxID_ANY, "Portaudio API"); m_cubeb_text = new wxStaticText(this, wxID_ANY, "Backend");
m_portaudio_box->Add(m_portaudio_text, wxSizerFlags().Centre()); m_cubeb_box->Add(m_cubeb_text, wxSizerFlags().Centre());
wxArrayString portaudio_entries; m_cubeb_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
#ifdef __linux__ for (size_t i = 0; i < std::size(s_backend_names); i++)
portaudio_entries.Add("ALSA (recommended)"); m_cubeb_select->Append(s_backend_names[i][0]);
portaudio_entries.Add("OSS (legacy)"); m_cubeb_box->Add(m_cubeb_select, wxSizerFlags().Centre());
portaudio_entries.Add("JACK");
#elif defined(__APPLE__)
portaudio_entries.Add("CoreAudio");
#else
portaudio_entries.Add("OSS");
#endif
m_portaudio_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, portaudio_entries);
m_portaudio_box->Add(m_portaudio_select, wxSizerFlags().Centre());
#endif #endif
// SDL #ifdef SPU2X_CUBEB
m_sdl_box = new wxBoxSizer(wxVERTICAL); module_box->Add(m_cubeb_box, wxSizerFlags().Expand());
m_sdl_text = new wxStaticText(this, wxID_ANY, "SDL API");
m_sdl_box->Add(m_sdl_text, wxSizerFlags().Centre());
wxArrayString sdl_entries;
for (int i = 0; i < SDL_GetNumAudioDrivers(); ++i)
sdl_entries.Add(SDL_GetAudioDriver(i));
m_sdl_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sdl_entries);
m_sdl_box->Add(m_sdl_select, wxSizerFlags().Centre());
#ifdef SPU2X_PORTAUDIO
module_box->Add(m_portaudio_box, wxSizerFlags().Expand());
#endif #endif
module_box->Add(m_sdl_box, wxSizerFlags().Expand());
m_top_box->Add(module_box, wxSizerFlags().Centre().Border(wxALL, 5)); m_top_box->Add(module_box, wxSizerFlags().Centre().Border(wxALL, 5));
@ -423,34 +413,25 @@ Dialog::~Dialog()
void Dialog::Reconfigure() void Dialog::Reconfigure()
{ {
const int mod = m_module_select->GetCurrentSelection(); const int mod = m_module_select->GetCurrentSelection();
bool show_portaudio = false, show_sdl = false; bool show_cubeb = false;
switch (mod) switch (mod)
{ {
case 0: case 0:
show_portaudio = false; show_cubeb = false;
show_sdl = false;
break; break;
case 1: case 1:
show_portaudio = true; show_cubeb = true;
show_sdl = false;
break;
case 2:
show_portaudio = false;
show_sdl = true;
break; break;
default: default:
show_portaudio = false; show_cubeb = false;
show_sdl = false;
break; break;
} }
#ifdef SPU2X_PORTAUDIO #ifdef SPU2X_CUBEB
m_top_box->Show(m_portaudio_box, show_portaudio, true); m_top_box->Show(m_cubeb_box, show_cubeb, true);
#endif #endif
m_top_box->Show(m_sdl_box, show_sdl, true);
// Recalculating both of these accounts for if neither was showing initially. // Recalculating both of these accounts for if neither was showing initially.
m_top_box->Layout(); m_top_box->Layout();
@ -465,10 +446,18 @@ void Dialog::CallReconfigure(wxCommandEvent& event)
void Dialog::Load() void Dialog::Load()
{ {
m_module_select->SetSelection(OutputModule); m_module_select->SetSelection(OutputModule);
#ifdef SPU2X_PORTAUDIO #ifdef SPU2X_CUBEB
m_portaudio_select->SetSelection(OutputAPI); wxString backend;
CfgReadStr(L"Cubeb", L"BackendName", backend, L"");
for (size_t i = 0; i < std::size(s_backend_names); i++)
{
if (backend == s_backend_names[i][1])
{
m_cubeb_select->SetSelection(static_cast<int>(i));
break;
}
}
#endif #endif
m_sdl_select->SetSelection(SdlOutputAPI);
m_mixer_panel->Load(); m_mixer_panel->Load();
m_sync_panel->Load(); m_sync_panel->Load();
@ -481,19 +470,12 @@ void Dialog::Save()
{ {
OutputModule = m_module_select->GetSelection(); OutputModule = m_module_select->GetSelection();
#ifdef SPU2X_PORTAUDIO #ifdef SPU2X_CUBEB
OutputAPI = m_portaudio_select->GetSelection(); const int backend_selection = m_cubeb_select->GetSelection();
wxString p_api(m_portaudio_select->GetStringSelection()); if (backend_selection >= 0)
if (p_api.Find("ALSA") != wxNOT_FOUND) CfgWriteStr(L"Cubeb", L"BackendName", s_backend_names[backend_selection][1]);
p_api = "ALSA";
if (p_api.Find("OSS") != wxNOT_FOUND)
p_api = "OSS";
PortaudioOut->SetApiSettings(p_api);
#endif #endif
SdlOutputAPI = m_sdl_select->GetSelection();
SDLOut->SetApiSettings(m_sdl_select->GetStringSelection());
m_mixer_panel->Save(); m_mixer_panel->Save();
m_sync_panel->Save(); m_sync_panel->Save();
m_debug_panel->Save(); m_debug_panel->Save();

View File

@ -78,9 +78,9 @@ public:
class Dialog : public wxDialog class Dialog : public wxDialog
{ {
wxBoxSizer *m_top_box, *m_portaudio_box, *m_sdl_box; wxBoxSizer *m_top_box, *m_cubeb_box;
wxChoice *m_module_select, *m_portaudio_select, *m_sdl_select; wxChoice *m_module_select, *m_cubeb_select;
wxStaticText *m_portaudio_text, *m_sdl_text; wxStaticText *m_cubeb_text;
MixerTab* m_mixer_panel; MixerTab* m_mixer_panel;
SyncTab* m_sync_panel; SyncTab* m_sync_panel;

View File

@ -48,7 +48,7 @@
<ForcedIncludeFiles>PrecompiledHeader.h;%(ForcedIncludeFiles)</ForcedIncludeFiles> <ForcedIncludeFiles>PrecompiledHeader.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<AdditionalOptions>/Zc:externConstexpr %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zc:externConstexpr %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_CUBEB;SPU2X_PORTAUDIO;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_CUBEB;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(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(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -359,7 +359,6 @@
<ClCompile Include="SPU2\debug.cpp" /> <ClCompile Include="SPU2\debug.cpp" />
<ClCompile Include="SPU2\RegLog.cpp" /> <ClCompile Include="SPU2\RegLog.cpp" />
<ClCompile Include="SPU2\SndOut_Cubeb.cpp" /> <ClCompile Include="SPU2\SndOut_Cubeb.cpp" />
<ClCompile Include="SPU2\SndOut_Portaudio.cpp" />
<ClCompile Include="SPU2\wavedump_wav.cpp" /> <ClCompile Include="SPU2\wavedump_wav.cpp" />
<ClCompile Include="SPU2\SndOut.cpp" /> <ClCompile Include="SPU2\SndOut.cpp" />
<ClCompile Include="SPU2\Timestretcher.cpp" /> <ClCompile Include="SPU2\Timestretcher.cpp" />
@ -1120,9 +1119,6 @@
<ProjectReference Include="$(SolutionDir)3rdparty\libsamplerate\libsamplerate.vcxproj"> <ProjectReference Include="$(SolutionDir)3rdparty\libsamplerate\libsamplerate.vcxproj">
<Project>{47afdbef-f15f-4bc0-b436-5be443c3f80f}</Project> <Project>{47afdbef-f15f-4bc0-b436-5be443c3f80f}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\portaudio\build\msvc\portaudio.vcxproj">
<Project>{0a18a071-125e-442f-aff7-a3f68abecf99}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\pthreads4w\build\pthreads4w.vcxproj"> <ProjectReference Include="$(SolutionDir)3rdparty\pthreads4w\build\pthreads4w.vcxproj">
<Project>{0fae817d-9a32-4830-857e-81da57246e16}</Project> <Project>{0fae817d-9a32-4830-857e-81da57246e16}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly> <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

View File

@ -1133,9 +1133,6 @@
<ClCompile Include="SPU2\Wavedump_wav.cpp"> <ClCompile Include="SPU2\Wavedump_wav.cpp">
<Filter>System\Ps2\SPU2</Filter> <Filter>System\Ps2\SPU2</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="SPU2\SndOut_Portaudio.cpp">
<Filter>System\Ps2\SPU2</Filter>
</ClCompile>
<ClCompile Include="DEV9\ATA\Commands\ATA_Command.cpp"> <ClCompile Include="DEV9\ATA\Commands\ATA_Command.cpp">
<Filter>System\Ps2\DEV9\ATA\Commands</Filter> <Filter>System\Ps2\DEV9\ATA\Commands</Filter>
</ClCompile> </ClCompile>