[Scummvm-cvs-logs] SF.net SVN: scummvm:[49369] scummvm/branches/gsoc2010-opengl/backends/ platform/sdl

vgvgf at users.sourceforge.net vgvgf at users.sourceforge.net
Tue Jun 1 06:00:56 CEST 2010


Revision: 49369
          http://scummvm.svn.sourceforge.net/scummvm/?rev=49369&view=rev
Author:   vgvgf
Date:     2010-06-01 04:00:55 +0000 (Tue, 01 Jun 2010)

Log Message:
-----------
SDL audio subsystem created.

Added Paths:
-----------
    scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.cpp
    scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.h

Added: scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.cpp
===================================================================
--- scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.cpp	                        (rev 0)
+++ scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.cpp	2010-06-01 04:00:55 UTC (rev 49369)
@@ -0,0 +1,350 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/platform/sdl/audio.h"
+#include "sound/mixer_intern.h"
+#include "common/config-manager.h"
+
+//#define SAMPLES_PER_SEC 11025
+#define SAMPLES_PER_SEC 22050
+//#define SAMPLES_PER_SEC 44100
+
+SdlSubSys_Audio::SdlSubSys_Audio()
+	:
+	_inited(false),
+	_cdrom(0),
+#if MIXER_DOUBLE_BUFFERING
+	_soundMutex(0), _soundCond(0), _soundThread(0),
+	_soundThreadIsRunning(false), _soundThreadShouldQuit(false),
+#endif
+	_mixer(0) {
+
+}
+
+SdlSubSys_Audio::~SdlSubSys_Audio() {
+	if (_inited) {
+		audioDone();
+	}
+}
+
+void SdlSubSys_Audio::audioInit() {
+	if (_inited) {
+		return;
+	}
+
+	// Create and hook up the mixer, if none exists yet (we check for this to
+	// allow subclasses to provide their own).
+	if (_mixer == 0) {
+		setupMixer();
+	}
+
+	_inited = true;
+}
+
+void SdlSubSys_Audio::audioDone() {
+	if (_cdrom) {
+		SDL_CDStop(_cdrom);
+		SDL_CDClose(_cdrom);
+	}
+
+	closeMixer();
+
+	_inited = false;
+}
+
+bool SdlSubSys_Audio::hasFeature(Feature f) {
+	return false;
+}
+
+void SdlSubSys_Audio::setFeatureState(Feature f, bool enable) {
+	
+}
+
+bool SdlSubSys_Audio::getFeatureState(Feature f) {
+	return false;
+}
+
+#if MIXER_DOUBLE_BUFFERING
+
+void SdlSubSys_Audio::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 SdlSubSys_Audio::mixerProducerThreadEntry(void *arg) {
+	OSystem_SDL *this_ = (OSystem_SDL *)arg;
+	assert(this_);
+	this_->mixerProducerThread();
+	return 0;
+}
+
+
+void SdlSubSys_Audio::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 SdlSubSys_Audio::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 SdlSubSys_Audio::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 SdlSubSys_Audio::mixCallback(void *sys, byte *samples, int len) {
+	SdlSubSys_Audio *this_ = (SdlSubSys_Audio *)sys;
+	assert(this_);
+	assert(this_->_mixer);
+
+	this_->_mixer->mixCallback(samples, len);
+}
+
+#endif
+
+void SdlSubSys_Audio::setupMixer() {
+	SDL_AudioSpec desired;
+
+	// Determine the desired output sampling frequency.
+	uint32 samplesPerSec = 0;
+	if (ConfMan.hasKey("output_rate"))
+		samplesPerSec = ConfMan.getInt("output_rate");
+	if (samplesPerSec <= 0)
+		samplesPerSec = SAMPLES_PER_SEC;
+
+	// Determine the sample buffer size. We want it to store enough data for
+	// at least 1/16th of a second (though at most 8192 samples). Note
+	// that it must be a power of two. So e.g. at 22050 Hz, we request a
+	// sample buffer size of 2048.
+	uint32 samples = 8192;
+	while (samples * 16 > samplesPerSec * 2)
+		samples >>= 1;
+
+	memset(&desired, 0, sizeof(desired));
+	desired.freq = samplesPerSec;
+	desired.format = AUDIO_S16SYS;
+	desired.channels = 2;
+	desired.samples = (uint16)samples;
+	desired.callback = mixCallback;
+	desired.userdata = this;
+
+	assert(!_mixer);
+	if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) {
+		warning("Could not open audio device: %s", SDL_GetError());
+		_mixer = new Audio::MixerImpl(this, samplesPerSec);
+		assert(_mixer);
+		_mixer->setReady(false);
+	} else {
+		// Note: This should be the obtained output rate, but it seems that at
+		// least on some platforms SDL will lie and claim it did get the rate
+		// even if it didn't. Probably only happens for "weird" rates, though.
+		samplesPerSec = _obtainedRate.freq;
+		debug(1, "Output sample rate: %d Hz", samplesPerSec);
+
+		// Create the mixer instance and start the sound processing
+		_mixer = new Audio::MixerImpl(this, samplesPerSec);
+		assert(_mixer);
+		_mixer->setReady(true);
+
+#if MIXER_DOUBLE_BUFFERING
+		initThreadedMixer(_mixer, _obtainedRate.samples * 4);
+#endif
+
+		// start the sound system
+		SDL_PauseAudio(0);
+	}
+}
+
+void SdlSubSys_Audio::closeMixer() {
+	if (_mixer)
+		_mixer->setReady(false);
+
+	SDL_CloseAudio();
+
+	delete _mixer;
+	_mixer = 0;
+
+#if MIXER_DOUBLE_BUFFERING
+	deinitThreadedMixer();
+#endif
+
+}
+
+Audio::Mixer *SdlSubSys_Audio::getMixer() {
+	assert(_mixer);
+	return _mixer;
+}
+
+bool SdlSubSys_Audio::openCD(int drive) {
+	if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1)
+		_cdrom = NULL;
+	else {
+		_cdrom = SDL_CDOpen(drive);
+		// Did it open? Check if _cdrom is NULL
+		if (!_cdrom) {
+			warning("Couldn't open drive: %s", SDL_GetError());
+		} else {
+			_cdNumLoops = 0;
+			_cdStopTime = 0;
+			_cdEndTime = 0;
+		}
+	}
+
+	return (_cdrom != NULL);
+}
+
+void SdlSubSys_Audio::stopCD() {	/* Stop CD Audio in 1/10th of a second */
+	_cdStopTime = SDL_GetTicks() + 100;
+	_cdNumLoops = 0;
+}
+
+void SdlSubSys_Audio::playCD(int track, int num_loops, int start_frame, int duration) {
+	if (!num_loops && !start_frame)
+		return;
+
+	if (!_cdrom)
+		return;
+
+	if (duration > 0)
+		duration += 5;
+
+	_cdTrack = track;
+	_cdNumLoops = num_loops;
+	_cdStartFrame = start_frame;
+
+	SDL_CDStatus(_cdrom);
+	if (start_frame == 0 && duration == 0)
+		SDL_CDPlayTracks(_cdrom, track, 0, 1, 0);
+	else
+		SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration);
+	_cdDuration = duration;
+	_cdStopTime = 0;
+	_cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS;
+}
+
+bool SdlSubSys_Audio::pollCD() {
+	if (!_cdrom)
+		return false;
+
+	return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) == CD_PLAYING));
+}
+
+void SdlSubSys_Audio::updateCD() {
+	if (!_cdrom)
+		return;
+
+	if (_cdStopTime != 0 && SDL_GetTicks() >= _cdStopTime) {
+		SDL_CDStop(_cdrom);
+		_cdNumLoops = 0;
+		_cdStopTime = 0;
+		return;
+	}
+
+	if (_cdNumLoops == 0 || SDL_GetTicks() < _cdEndTime)
+		return;
+
+	if (_cdNumLoops != 1 && SDL_CDStatus(_cdrom) != CD_STOPPED) {
+		// Wait another second for it to be done
+		_cdEndTime += 1000;
+		return;
+	}
+
+	if (_cdNumLoops > 0)
+		_cdNumLoops--;
+
+	if (_cdNumLoops != 0) {
+		if (_cdStartFrame == 0 && _cdDuration == 0)
+			SDL_CDPlayTracks(_cdrom, _cdTrack, 0, 1, 0);
+		else
+			SDL_CDPlayTracks(_cdrom, _cdTrack, _cdStartFrame, 0, _cdDuration);
+		_cdEndTime = SDL_GetTicks() + _cdrom->track[_cdTrack].length * 1000 / CD_FPS;
+	}
+}


Property changes on: scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.h
===================================================================
--- scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.h	                        (rev 0)
+++ scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.h	2010-06-01 04:00:55 UTC (rev 49369)
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+
+ * 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 for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_SDL_SUBSYS_AUDIO_H
+#define BACKENDS_SDL_SUBSYS_AUDIO_H
+
+#include "backends/base-subsys-audio.h"
+
+#if defined(__SYMBIAN32__)
+#include <esdl\SDL.h>
+#else
+#include <SDL.h>
+#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
+
+namespace Audio {
+	class MixerImpl;
+}
+
+class SdlSubSys_Audio : public BaseSubSys_Audio {
+public:
+	SdlSubSys_Audio();
+	~SdlSubSys_Audio();
+
+	virtual void audioInit();
+	virtual void audioDone();
+
+	bool hasFeature(Feature f);
+	void setFeatureState(Feature f, bool enable);
+	bool getFeatureState(Feature f);
+
+	// Set function that generates samples
+	virtual void setupMixer();
+	static void mixCallback(void *s, byte *samples, int len);
+
+	virtual void closeMixer();
+
+	virtual Audio::Mixer *getMixer();
+
+	virtual bool openCD(int drive);
+
+	// Poll CD status
+	// Returns true if cd audio is playing
+	bool pollCD();
+
+	// Play CD audio track
+	void playCD(int track, int num_loops, int start_frame, int duration);
+
+	// Stop CD audio track
+	void stopCD();
+
+	// Update CD audio status
+	void updateCD();
+
+protected:
+	bool _inited;
+
+	SDL_AudioSpec _obtainedRate;
+
+	// CD Audio
+	SDL_CD *_cdrom;
+	int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;
+	uint32 _cdEndTime, _cdStopTime;
+
+#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
+
+	Audio::MixerImpl *_mixer;
+};
+
+
+#endif


Property changes on: scummvm/branches/gsoc2010-opengl/backends/platform/sdl/audio.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list