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
* 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
* 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_SETCAP "Do not set files capabilities")
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(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)")
if(UNIX AND NOT APPLE)

View File

@ -12,7 +12,6 @@ if (WIN32)
add_subdirectory(3rdparty/libsamplerate EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/baseclasses 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/soundtouch EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL)
@ -144,9 +143,6 @@ else()
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(SAMPLERATE samplerate samplerate.h)

View File

@ -51,11 +51,6 @@ elseif("${PGO}" STREQUAL "use")
target_compile_options(PCSX2_FLAGS INTERFACE -fprofile-use)
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)
target_compile_definitions(PCSX2_FLAGS INTERFACE SPU2X_PULSEAUDIO)
target_link_libraries(PCSX2_FLAGS INTERFACE PulseAudio::PulseAudio)
@ -293,17 +288,12 @@ set(pcsx2SPU2Sources
SPU2/RegTable.cpp
SPU2/Reverb.cpp
SPU2/SndOut.cpp
SPU2/SndOut_SDL.cpp
SPU2/spu2freeze.cpp
SPU2/spu2sys.cpp
SPU2/Timestretcher.cpp
SPU2/Wavedump_wav.cpp
)
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")

View File

@ -64,10 +64,6 @@ bool _visual_debug_enabled = false; // Windows-only feature
u32 OutputModule = 0;
int SndOutLatencyMS = 100;
int SynchMode = 0; // Time Stretch, Async or Disabled.
#ifdef SPU2X_PORTAUDIO
u32 OutputAPI = 0;
#endif
u32 SdlOutputAPI = 0;
int numSpeakers = 0;
int dplLevel = 0;
@ -105,54 +101,20 @@ void ReadSettings()
VolumeAdjustSR = powf(10, VolumeAdjustSRdb / 10);
VolumeAdjustLFE = powf(10, VolumeAdjustLFEdb / 10);
#ifdef SPU2X_CUBEB
const SndOutModule* const defaultModule = CubebOut;
#else
const SndOutModule* const defaultModule = NullOut;
#endif
wxString temp;
#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
CfgReadStr(L"OUTPUT", L"Output_Module", temp, defaultModule->GetIdent());
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);
SynchMode = CfgReadInt(L"OUTPUT", L"Synch_Mode", 0);
numSpeakers = CfgReadInt(L"OUTPUT", L"SpeakerConfiguration", 0);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->ReadSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->ReadSettings();
#endif
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
@ -164,8 +126,8 @@ void ReadSettings()
if (mods[OutputModule] == nullptr)
{
Console.Warning("* SPU2: Unknown output module '%s' specified in configuration file.", temp.wc_str());
Console.Warning("* SPU2: Defaulting to SDL (%s).", SDLOut->GetIdent());
OutputModule = FindOutputModuleById(SDLOut->GetIdent());
Console.Warning("* SPU2: Defaulting to %s (%s).", defaultModule->GetLongName(), defaultModule->GetIdent());
OutputModule = FindOutputModuleById(defaultModule->GetIdent());
}
WriteSettings();
@ -200,12 +162,6 @@ void WriteSettings()
CfgWriteInt(L"OUTPUT", L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT", L"SpeakerConfiguration", numSpeakers);
#ifdef SPU2X_PORTAUDIO
PortaudioOut->WriteSettings();
#endif
#if defined(__unix__) || defined(__APPLE__)
SDLOut->WriteSettings();
#endif
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}

View File

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

View File

@ -49,50 +49,47 @@ StereoOut32 StereoOut16::UpSample() const
class NullOutModule : public SndOutModule
{
public:
s32 Init() { return 0; }
void Close() {}
s32 Test() const { return 0; }
void Configure(uptr parent) {}
int GetEmptySampleCount() { return 0; }
s32 Init() override { return 0; }
void Close() override {}
s32 Test() const override { return 0; }
void Configure(uptr parent) override {}
int GetEmptySampleCount() override { return 0; }
const wchar_t* GetIdent() const
const wchar_t* GetIdent() const override
{
return L"nullout";
}
const wchar_t* GetLongName() const
const wchar_t* GetLongName() const override
{
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[] =
{
&NullOut,
#ifdef _MSC_VER
NullOut,
#ifdef _WIN32
XAudio2Out,
#endif
#if defined(SPU2X_PORTAUDIO)
PortaudioOut,
#endif
#if defined(SPU2X_CUBEB)
CubebOut,
#endif
#if defined(__linux__) || defined(__APPLE__)
SDLOut,
#endif
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
// the game to emulate properly (hopefully), albeit without sound.
OutputModule = FindOutputModuleById(NullOut.GetIdent());
OutputModule = FindOutputModuleById(NullOut->GetIdent());
mods[OutputModule]->Init();
}
@ -447,7 +444,7 @@ void SndBuffer::Write(const StereoOut32& Sample)
if (WavRecordEnabled)
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;
sndTempBuffer[sndTempProgress++] = Sample;
@ -464,7 +461,7 @@ void SndBuffer::Write(const StereoOut32& Sample)
// Play silence
std::fill_n(sndTempBuffer, SndOutPacketSize, StereoOut32{});
}
#ifndef __POSIX__
#if defined(_WIN32) && !defined(PCSX2_CORE)
if (dspPluginEnabled)
{
// Convert in, send to winamp DSP, and convert out.

View File

@ -663,17 +663,13 @@ public:
virtual int GetEmptySampleCount() = 0;
};
#ifdef _MSC_VER
//internal
extern SndOutModule* NullOut;
#ifdef _WIN32
extern SndOutModule* XAudio2Out;
#endif
#if defined(SPU2X_PORTAUDIO)
extern SndOutModule* PortaudioOut;
#endif
#if defined(SPU2X_CUBEB)
extern SndOutModule* CubebOut;
#endif
extern SndOutModule* const SDLOut;
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);
dspPluginEnabled = CfgReadBool(L"DSP PLUGIN", L"Enabled", false);
PortaudioOut->ReadSettings();
SoundtouchCfg::ReadSettings();
DebugConfig::ReadSettings();
@ -173,7 +171,6 @@ void WriteSettings()
CfgWriteInt(L"DSP PLUGIN", L"ModuleNum", dspPluginModule);
CfgWriteBool(L"DSP PLUGIN", L"Enabled", dspPluginEnabled);
PortaudioOut->WriteSettings();
SoundtouchCfg::WriteSettings();
DebugConfig::WriteSettings();
}
@ -181,16 +178,131 @@ void WriteSettings()
void CheckOutputModule(HWND window)
{
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 =
mods[OutputModule] == XAudio2Out ||
mods[OutputModule] == PortaudioOut;
mods[OutputModule] == CubebOut;
EnableWindow(GetDlgItem(window, IDC_OUTCONF), IsConfigurable);
EnableWindow(GetDlgItem(window, IDC_SPEAKERS), 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)
{
int wmId, wmEvent;
@ -298,9 +410,11 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case IDC_OUTCONF:
{
const int module = (int)SendMessage(GetDlgItem(hWnd, IDC_OUTPUT), CB_GETCURSEL, 0, 0);
if (mods[module] == nullptr)
if (mods[module] != CubebOut)
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;

View File

@ -7,7 +7,6 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "svnrev.h"
#include "common/afxresmw.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@ -175,25 +174,22 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// 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
CAPTION "Portaudio Output Module Settings"
CAPTION "Cubeb Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,105,144,50,14
PUSHBUTTON "Cancel",IDCANCEL,161,144,50,14
COMBOBOX IDC_PA_HOSTAPI,7,17,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Host API:",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
COMBOBOX IDC_BACKEND,7,17,95,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Backend:",IDC_STATIC,7,7,32,8
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
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,
"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,75,258,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
@ -205,7 +201,7 @@ END
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PORTAUDIO, DIALOG
IDD_CUBEB, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309

View File

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

View File

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

View File

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

View File

@ -48,7 +48,7 @@
<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_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(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(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\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" />
<ClCompile Include="SPU2\Timestretcher.cpp" />
@ -1120,9 +1119,6 @@
<ProjectReference Include="$(SolutionDir)3rdparty\libsamplerate\libsamplerate.vcxproj">
<Project>{47afdbef-f15f-4bc0-b436-5be443c3f80f}</Project>
</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">
<Project>{0fae817d-9a32-4830-857e-81da57246e16}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>

View File

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