diff --git a/Source/Core/AudioCommon/Src/AOSoundStream.h b/Source/Core/AudioCommon/Src/AOSoundStream.h index af7d1aaa64..afba7b363f 100644 --- a/Source/Core/AudioCommon/Src/AOSoundStream.h +++ b/Source/Core/AudioCommon/Src/AOSoundStream.h @@ -64,8 +64,7 @@ public: #else public: - AOSound(CMixer *mixer) : - SoundStream(mixer) {} + AOSound(CMixer *mixer) : SoundStream(mixer) {} #endif }; diff --git a/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp b/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp new file mode 100644 index 0000000000..048509314e --- /dev/null +++ b/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp @@ -0,0 +1,195 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "Thread.h" + +#include "AlsaSoundStream.h" + +#define BUFFER_SIZE 4096 +#define BUFFER_SIZE_BYTES (BUFFER_SIZE*2*2) + +AlsaSound::AlsaSound(CMixer *mixer) : SoundStream(mixer), thread_data(0), handle(NULL) +{ + mix_buffer = new u8[BUFFER_SIZE_BYTES]; +} + +AlsaSound::~AlsaSound() +{ + delete [] mix_buffer; +} + +static void *ThreadTrampoline(void *args) +{ + reinterpret_cast(args)->SoundLoop(); + return NULL; +} + +bool AlsaSound::Start() +{ + thread = new Common::Thread(&ThreadTrampoline, this); + thread_data = 0; + return true; +} + +void AlsaSound::Stop() +{ + thread_data = 1; + delete thread; + thread = NULL; +} + +void AlsaSound::Update() +{ + // don't need to do anything here. +} + +// Called on audio thread. +void AlsaSound::SoundLoop() +{ + AlsaInit(); + while (!thread_data) + { + int frames_to_deliver = 512; + m_mixer->Mix(reinterpret_cast(mix_buffer), frames_to_deliver); + int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver); + if (rc == -EPIPE) + { + // Underrun + snd_pcm_prepare(handle); + } + else if (rc < 0) + { + ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc)); + } + } + AlsaShutdown(); + thread_data = 2; +} + +bool AlsaSound::AlsaInit() +{ + unsigned int sample_rate = m_mixer->GetSampleRate(); + int err; + int dir; + snd_pcm_sw_params_t *swparams; + snd_pcm_hw_params_t *hwparams; + + err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + if (err < 0) + { + ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err)); + return false; + } + + snd_pcm_hw_params_alloca(&hwparams); + + err = snd_pcm_hw_params_any(handle, hwparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) + { + ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); + if (err < 0) + { + ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err)); + return false; + } + + // This is weird - if I do pass in a pointer to a variable, like the header wants me to, + // the sample rate goes mad. It seems that the alsa header doesn't match the library we link in :( + // If anyone know why, i'd appreciate if you let me know - ector. + err = snd_pcm_hw_params_set_rate_near(handle, hwparams, (unsigned int *)sample_rate, &dir); + if (err < 0) + { + ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_hw_params_set_channels(handle, hwparams, 2); + if (err < 0) + { + ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_hw_params(handle, hwparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err)); + return false; + } + + snd_pcm_sw_params_alloca(&swparams); + + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_sw_params_set_avail_min(handle, swparams, BUFFER_SIZE); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot set avail min: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err)); + return false; + } + + err = snd_pcm_prepare(handle); + if (err < 0) + { + ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err)); + return false; + } + NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n"); + return true; +} + +void AlsaSound::AlsaShutdown() +{ + if (handle != NULL) + { + snd_pcm_drop(handle); + snd_pcm_close(handle); + handle = NULL; + } +} + diff --git a/Source/Core/AudioCommon/Src/AlsaSoundStream.h b/Source/Core/AudioCommon/Src/AlsaSoundStream.h new file mode 100644 index 0000000000..a747b165ec --- /dev/null +++ b/Source/Core/AudioCommon/Src/AlsaSoundStream.h @@ -0,0 +1,69 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _ALSA_SOUND_STREAM_H +#define _ALSA_SOUND_STREAM_H + +#include + +#include "Common.h" +#include "SoundStream.h" + +#include "Thread.h" + +#define HAVE_ALSA 1 + +class AlsaSound : public SoundStream +{ +#if defined(HAVE_ALSA) && HAVE_ALSA +public: + AlsaSound(CMixer *mixer); + virtual ~AlsaSound(); + + virtual bool Start(); + virtual void SoundLoop(); + virtual void Stop(); + + static bool isValid() { + return true; + } + virtual bool usesMixer() const { + return true; + } + + virtual void Update(); + +private: + bool AlsaInit(); + void AlsaShutdown(); + + u8 *mix_buffer; + Common::Thread *thread; + // 0 = continue + // 1 = shutdown + // 2 = done shutting down. + volatile int thread_data; + + snd_pcm_t *handle; +#else +public: + AlsaSound(CMixer *mixer) : SoundStream(mixer) {} +#endif +}; + +#endif + diff --git a/Source/Core/AudioCommon/Src/AudioCommon.cpp b/Source/Core/AudioCommon/Src/AudioCommon.cpp index f416427d67..f87e31a949 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommon.cpp @@ -19,6 +19,7 @@ #include "Mixer.h" #include "DSoundStream.h" #include "AOSoundStream.h" +#include "AlsaSoundStream.h" #include "NullSoundStream.h" #include "OpenALStream.h" @@ -26,18 +27,22 @@ namespace AudioCommon { SoundStream *InitSoundStream(CMixer *mixer) { + // This looks evil. if (!mixer) mixer = new CMixer(); std::string backend = ac_Config.sBackend; - if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd); - if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer); - if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer); - if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer); - - if (soundStream != NULL) { + if (backend == BACKEND_DIRECTSOUND && DSound::isValid()) soundStream = new DSound(mixer, g_dspInitialize.hWnd); + if (backend == BACKEND_AOSOUND && AOSound::isValid()) soundStream = new AOSound(mixer); + if (backend == BACKEND_OPENAL && OpenALStream::isValid()) soundStream = new OpenALStream(mixer); + if (backend == BACKEND_ALSA && AlsaSound::isValid()) soundStream = new AlsaSound(mixer); + if (backend == BACKEND_NULL && NullSound::isValid()) soundStream = new NullSound(mixer); + + if (soundStream != NULL) + { ac_Config.Update(); - if (soundStream->Start()) { + if (soundStream->Start()) + { // Start the sound recording /* if (ac_Config.record) { @@ -81,6 +86,7 @@ namespace AudioCommon if (DSound::isValid()) backends.push_back(BACKEND_DIRECTSOUND); if (AOSound::isValid()) backends.push_back(BACKEND_AOSOUND); if (OpenALStream::isValid()) backends.push_back(BACKEND_OPENAL); + if (AlsaSound::isValid()) backends.push_back(BACKEND_ALSA); if (NullSound::isValid()) backends.push_back(BACKEND_NULL); return backends; diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h index 09518f94c4..b1932762af 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h @@ -25,7 +25,9 @@ #define BACKEND_DIRECTSOUND "DSound" #define BACKEND_AOSOUND "AOSound" #define BACKEND_OPENAL "OpenAL" +#define BACKEND_ALSA "ALSA" #define BACKEND_NULL "NullSound" + struct AudioCommonConfig { bool m_EnableDTKMusic; diff --git a/Source/Core/AudioCommon/Src/SConscript b/Source/Core/AudioCommon/Src/SConscript index 4b00e5631e..7caa6c2c6b 100644 --- a/Source/Core/AudioCommon/Src/SConscript +++ b/Source/Core/AudioCommon/Src/SConscript @@ -17,5 +17,8 @@ if acenv['HAVE_OPENAL']: if acenv['HAVE_AO']: files += [ 'AOSoundStream.cpp' ] + +# TODO: make conditional? +files += [ 'AlsaSoundStream.cpp' ] acenv.StaticLibrary(env['local_libs'] + 'audiocommon', files) diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index 82134ceab0..9f5dda0528 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -84,6 +84,7 @@ #define HAVE_WX 1 #define HAVE_SFML 1 #define HAVE_OPENAL 1 + #define HAVE_ALSA 1 // it is VERY DANGEROUS to mix _SECURE_SCL=0 and _SECURE_SCL=1 compiled libraries. // You will get bizarre crash bugs whenever you use STL. @@ -110,6 +111,11 @@ #define POSIX 1 #define MAX_PATH 260 +#ifdef __APPLE__ + #define HAVE_ALSA 0 +#else + #define HAVE_ALSA 1 +#endif // Windows compatibility #define __forceinline inline __attribute__((always_inline)) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp index 1cf7995c38..6b749280e7 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPFunctions.cpp @@ -120,10 +120,12 @@ void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const { // bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format) if (!g_Config.bEFBCopyDisable) + { if (g_Config.bCopyEFBToRAM) // To RAM TextureConverter::EncodeToRam(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); else // To OGL Texture TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc); + } } void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/DLCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/DLCache.cpp index 5f9f4228a2..ac277d44a2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/DLCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/DLCache.cpp @@ -75,6 +75,8 @@ struct CachedDisplayList frame_count = frameCount; } + bool uncachable; // if set, this DL will always be interpreted. This gets set if hash ever changes. + int pass; u32 dl_hash; @@ -87,8 +89,6 @@ struct CachedDisplayList int frame_count; - bool uncachable; // if set, this DL will always be interpreted. This gets set if hash ever changes. - // ... Something containing cached vertex buffers here ... // Compile the commands themselves down to native code. @@ -159,12 +159,12 @@ bool AnalyzeAndRunDisplayList(u32 address, int size, CachedDisplayList *dl) // Execute u32 Cmd2 = DataReadU32(); int transfer_size = ((Cmd2 >> 16) & 15) + 1; - u32 address = Cmd2 & 0xFFFF; + u32 xf_address = Cmd2 & 0xFFFF; // TODO - speed this up. pshufb? u32 data_buffer[16]; for (int i = 0; i < transfer_size; i++) data_buffer[i] = DataReadU32(); - LoadXFReg(transfer_size, address, data_buffer); + LoadXFReg(transfer_size, xf_address, data_buffer); INCSTAT(stats.thisFrame.numXFLoads); // Analyze @@ -311,13 +311,13 @@ bool CompileAndRunDisplayList(u32 address, int size, CachedDisplayList *dl) // Execute u32 Cmd2 = DataReadU32(); int transfer_size = ((Cmd2 >> 16) & 15) + 1; - u32 address = Cmd2 & 0xFFFF; + u32 xf_address = Cmd2 & 0xFFFF; // TODO - speed this up. pshufb? u8 *real_data_buffer = AllocStaticData(4 * transfer_size); u32 *data_buffer = (u32 *)real_data_buffer; for (int i = 0; i < transfer_size; i++) data_buffer[i] = DataReadU32(); - LoadXFReg(transfer_size, address, data_buffer); + LoadXFReg(transfer_size, xf_address, data_buffer); INCSTAT(stats.thisFrame.numXFLoads); // Compile