diff options
Diffstat (limited to 'backends/platform/sdl')
| -rw-r--r-- | backends/platform/sdl/sdl.cpp | 127 | ||||
| -rw-r--r-- | backends/platform/sdl/sdl.h | 30 | 
2 files changed, 150 insertions, 7 deletions
| diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 290fe63663..76ac91c282 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -191,7 +191,7 @@ OSystem_SDL::OSystem_SDL()  OSystem_SDL::~OSystem_SDL() {  	SDL_RemoveTimer(_timerID); -	SDL_CloseAudio(); +	closeMixer();  	free(_dirtyChecksums);  	free(_currentPalette); @@ -199,7 +199,6 @@ OSystem_SDL::~OSystem_SDL() {  	free(_mouseData);  	delete _savefile; -	delete _mixer;  	delete _timer;  } @@ -306,7 +305,7 @@ void OSystem_SDL::quit() {  	SDL_ShowCursor(SDL_ENABLE);  	SDL_RemoveTimer(_timerID); -	SDL_CloseAudio(); +	closeMixer();  	free(_dirtyChecksums);  	free(_currentPalette); @@ -314,7 +313,6 @@ void OSystem_SDL::quit() {  	free(_mouseData);  	delete _savefile; -	delete _mixer;  	delete _timer;  	SDL_Quit(); @@ -389,14 +387,110 @@ void OSystem_SDL::deleteMutex(MutexRef mutex) {  #pragma mark --- Audio ---  #pragma mark - +#ifdef MIXER_DOUBLE_BUFFERING + +void OSystem_SDL::mixerProducerThread() { +	byte nextSoundBuffer; + +	SDL_LockMutex(_soundMutex); +	while (true) { +		// Wait till we are allowed to produce data +		SDL_CondWait(_soundCond, _soundMutex); + +		if (_soundThreadShouldQuit) +			break; + +		// Generate samples and put them into the next buffer +		nextSoundBuffer = _activeSoundBuf ^ 1; +		_mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); +		 +		// Swap buffers +		_activeSoundBuf = nextSoundBuffer; +	} +	SDL_UnlockMutex(_soundMutex); +} + +int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) { +	OSystem_SDL *this_ = (OSystem_SDL *)arg; +	assert(this_); +	this_->mixerProducerThread(); +	return 0; +} + + +void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) { +	_soundThreadIsRunning = false; +	_soundThreadShouldQuit = false; + +	// Create mutex and condition variable +	_soundMutex = SDL_CreateMutex(); +	_soundCond = SDL_CreateCond(); + +	// Create two sound buffers +	_activeSoundBuf = 0; +	_soundBufSize = bufSize; +	_soundBuffers[0] = (byte *)calloc(1, bufSize); +	_soundBuffers[1] = (byte *)calloc(1, bufSize); + +	_soundThreadIsRunning = true; + +	// Finally start the thread +	_soundThread = SDL_CreateThread(mixerProducerThreadEntry, this); +} + +void OSystem_SDL::deinitThreadedMixer() { +	// Kill thread?? _soundThread + +	if (_soundThreadIsRunning) { +		// Signal the producer thread to end, and wait for it to actually finish. +		_soundThreadShouldQuit = true; +		SDL_CondBroadcast(_soundCond); +		SDL_WaitThread(_soundThread, NULL); + +		// Kill the mutex & cond variables.  +		// Attention: AT this point, the mixer callback must not be running +		// anymore, else we will crash! +		SDL_DestroyMutex(_soundMutex); +		SDL_DestroyCond(_soundCond); + +		_soundThreadIsRunning = false; + +		free(_soundBuffers[0]); +		free(_soundBuffers[1]); +	} +} + + +void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) { +	OSystem_SDL *this_ = (OSystem_SDL *)arg; +	assert(this_); +	assert(this_->_mixer); + +	assert((int)this_->_soundBufSize == len); + +	// Lock mutex, to ensure our data is not overwritten by the producer thread +	SDL_LockMutex(this_->_soundMutex); +	 +	// Copy data from the current sound buffer +	memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); +	 +	// Unlock mutex and wake up the produced thread +	SDL_UnlockMutex(this_->_soundMutex); +	SDL_CondSignal(this_->_soundCond); +} + +#else +  void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) {  	OSystem_SDL *this_ = (OSystem_SDL *)sys;  	assert(this_); +	assert(this_->_mixer); -	if (this_->_mixer) -		this_->_mixer->mixCallback(samples, len); +	this_->_mixer->mixCallback(samples, len);  } +#endif +  void OSystem_SDL::setupMixer() {  	SDL_AudioSpec desired;  	SDL_AudioSpec obtained; @@ -443,10 +537,31 @@ void OSystem_SDL::setupMixer() {  		// Tell the mixer that we are ready and start the sound processing  		_mixer->setOutputRate(_samplesPerSec);  		_mixer->setReady(true); + +#ifdef MIXER_DOUBLE_BUFFERING +		initThreadedMixer(_mixer, obtained.samples * 4); +#endif + +		// start the sound system  		SDL_PauseAudio(0);  	}  } +void OSystem_SDL::closeMixer() { +	if (_mixer) +		_mixer->setReady(false); + +	SDL_CloseAudio(); + +	delete _mixer; +	_mixer = 0; + +#ifdef MIXER_DOUBLE_BUFFERING +	deinitThreadedMixer(); +#endif + +} +  Audio::Mixer *OSystem_SDL::getMixer() {  	assert(_mixer);  	return _mixer; diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 8a94a17b00..4ad588f5f5 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -51,6 +51,15 @@ namespace Common {  #define USE_OSD	1  #endif +#if defined(MACOSX) +// On Mac OS X, we need to double buffer the audio buffer, else anything +// which produces sampled data with high latency (like the MT-32 emulator) +// will sound terribly. +// This could be enabled for more / most ports in the future, but needs some +// testing. +#define MIXER_DOUBLE_BUFFERING 1 +#endif +  enum {  	GFX_NORMAL = 0, @@ -137,6 +146,8 @@ public:  	virtual void setupMixer();  	static void mixCallback(void *s, byte *samples, int len); +	virtual void closeMixer(); +  	virtual Audio::Mixer *getMixer();  	// Poll CD status @@ -369,6 +380,23 @@ protected:  	 */  	MutexRef _graphicsMutex; +#ifdef MIXER_DOUBLE_BUFFERING +	SDL_mutex *_soundMutex; +	SDL_cond *_soundCond; +	SDL_Thread *_soundThread; +	bool _soundThreadIsRunning; +	bool _soundThreadShouldQuit; +	 +	byte _activeSoundBuf; +	uint _soundBufSize; +	byte *_soundBuffers[2]; + +	void mixerProducerThread(); +	static int SDLCALL mixerProducerThreadEntry(void *arg); +	void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize); +	void deinitThreadedMixer(); +#endif +  	Common::SaveFileManager *_savefile;  	Audio::MixerImpl *_mixer; @@ -377,7 +405,7 @@ protected:  	Common::TimerManager *_timer; - +protected:  	void addDirtyRgnAuto(const byte *buf);  	void makeChecksums(const byte *buf); | 
