spu2x (linux): allow to use sdl as audio backend instead of portaudio (recommended for pulseaudio user). Close i1413

Thanks to Matt Scheirer for his patch



git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5731 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gregory.hainaut 2013-09-14 15:23:35 +00:00
parent a73e1b294a
commit 00ea70d4d1
5 changed files with 181 additions and 7 deletions

View File

@ -97,8 +97,26 @@ set(spu2xLinuxHeaders
Linux/Dialogs.h)
# add additional include directories
include_directories(.
Linux)
include_directories(. Linux)
### Don't use yet c11 feature. I will bump gcc requirement to 4.7 when 4.9 is out.
### Note: actually it might work on 4.6 too
# # If compiling on GCC Version 4.7 or higher we build SDLMod in C++11 mode
# if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
# execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
# if(GCC_VERSION VERSION_GREATER 4.7)
# set_source_files_properties(SndOut_SDL.cpp PROPERTIES COMPILE_FLAGS -std=c++11)
# message(STATUS "GCC has C++11 support for SDLAudioMod")
# endif(GCC_VERSION VERSION_GREATER 4.7)
# endif()
if(SDL_FOUND)
add_definitions(-DSPU2X_SDL)
list(APPEND spu2xSources SndOut_SDL.cpp)
#elseif(SDL2_FOUND)
# add_definitions(-DSPU2X_SDL2)
# list(APPEND spu2xSources SndOut_SDL.cpp)
endif()
# add library
add_library(${Output} SHARED
@ -107,15 +125,13 @@ add_library(${Output} SHARED
${spu2xLinuxSources}
${spu2xLinuxHeaders})
# link target with project internal libraries
target_link_libraries(${Output} Utilities)
# link target with ALSA
# link target with various backend
target_link_libraries(${Output} ${ALSA_LIBRARIES})
# link target with PortAudio
target_link_libraries(${Output} ${PORTAUDIO_LIBRARIES})
target_link_libraries(${Output} ${SDL_LIBRARY})
# link target with SoundTouch
target_link_libraries(${Output} ${SOUNDTOUCH_LIBRARIES})

View File

@ -185,7 +185,8 @@ void DisplayDialog()
mod_box = gtk_combo_box_new_text ();
gtk_combo_box_append_text(GTK_COMBO_BOX(mod_box), "0 - No Sound (emulate SPU2 only)");
gtk_combo_box_append_text(GTK_COMBO_BOX(mod_box), "1 - PortAudio (cross-platform)");
//gtk_combo_box_append_text(GTK_COMBO_BOX(mod_box), "2 - Alsa (probably doesn't work)");
gtk_combo_box_append_text(GTK_COMBO_BOX(mod_box), "2 - SDL Audio (recommanded for pulseaudio");
//gtk_combo_box_append_text(GTK_COMBO_BOX(mod_box), "3 - Alsa (probably doesn't work)");
gtk_combo_box_set_active(GTK_COMBO_BOX(mod_box), OutputModule);
api_label = gtk_label_new ("PortAudio API:");

View File

@ -92,6 +92,9 @@ SndOutModule* mods[]=
WaveOut,
#endif
PortaudioOut,
#if defined(SPU2X_SDL) || defined(SPU2X_SDL2)
SDLOut,
#endif
#ifdef __LINUX__
AlsaOut,
#endif

View File

@ -488,6 +488,9 @@ extern SndOutModule* DSoundOut;
extern SndOutModule* XAudio2Out;
#endif
extern SndOutModule* PortaudioOut;
#if defined(SPU2X_SDL) || defined(SPU2X_SDL2)
extern SndOutModule * const SDLOut;
#endif
#ifdef __LINUX__
extern SndOutModule* AlsaOut;
#endif

View File

@ -0,0 +1,151 @@
/* SDL Audio sink for SPU2-X.
* Copyright (c) 2013, Matt Scheirer <matt.scheirer@gmail.com>
*
* SPU2-X 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.
*
* SPU2-X 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <iostream>
#include "Global.h"
#include "SndOut.h"
#if __cplusplus >= 201103L
#include <memory>
#else
#include <cstddef>
#endif
/* 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. */
#ifdef SPU2X_SDL2
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
typedef StereoOut32 StereoOut_SDL;
#else
#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
typedef StereoOut16 StereoOut_SDL;
#endif
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 = 1024;
const Uint16 format =
#if SDL_MAJOR_VERSION >= 2
AUDIO_S32SYS;
#else
AUDIO_S16SYS;
#endif
Uint16 samples = desiredSamples;
#if __cplusplus >= 201103L
std::unique_ptr<StereoOut_SDL[]> buffer;
#else
StereoOut_SDL *buffer = NULL;
#endif
void callback_fillBuffer(void *userdata, Uint8 *stream, int len) {
// Length should always be samples in bytes.
assert(len / sizeof(StereoOut_SDL) == samples);
for(Uint16 i = 0; i < samples; i += SndOutPacketSize)
SndBuffer::ReadSamples(&buffer[i]);
#if __cplusplus >= 201103L
SDL_MixAudio(stream, (Uint8*) buffer.get() , len, SDL_MIX_MAXVOLUME);
#else
SDL_MixAudio(stream, (Uint8*) buffer , len, SDL_MIX_MAXVOLUME);
#endif
}
}
struct SDLAudioMod : public SndOutModule {
static SDLAudioMod mod;
s32 Init() {
/* 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;
if(SDL_Init(SDL_INIT_AUDIO) < 0 || SDL_OpenAudio(&spec, NULL) < 0) {
std::cerr << "SPU2-X: SDL audio error: " << SDL_GetError() << std::endl;
return -1;
}
/* This is so ugly. It is hilariously ugly. I didn't use a vector to save reallocs. */
if(samples != spec.samples || buffer == NULL)
#if __cplusplus >= 201103L
buffer = std::unique_ptr<StereoOut_SDL[]>(new StereoOut_SDL[spec.samples]);
#else
buffer = new StereoOut_SDL[spec.samples];
#endif
if(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() {
SDL_CloseAudio();
#if __cplusplus < 201103L
delete[] buffer;
buffer = NULL;
#endif
}
s32 Test() const { return 0; }
void Configure(uptr parent) {}
void ReadSettings() {}
void SetApiSettings(wxString api) {}
void WriteSettings() const {};
int GetEmptySampleCount() { return 0; }
~SDLAudioMod() { Close(); }
private:
SDL_AudioSpec spec;
/* Only C++11 supports the aggregate initializer list syntax used here. */
SDLAudioMod()
#if __cplusplus >= 201103L
: spec({SampleRate, format, channels, 0,
desiredSamples, 0, 0, &callback_fillBuffer, nullptr}) {
#else
{
spec.freq = SampleRate;
spec.format = format;
spec.channels = channels;
spec.samples = desiredSamples;
spec.callback = callback_fillBuffer;
spec.userdata = NULL;
#endif
// Number of samples must be a multiple of packet size.
assert(samples % SndOutPacketSize == 0);
}
};
SDLAudioMod SDLAudioMod::mod;
SndOutModule * const SDLOut = &SDLAudioMod::mod;