aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/psp
diff options
context:
space:
mode:
authorYotam Barnoy2010-05-23 05:51:32 +0000
committerYotam Barnoy2010-05-23 05:51:32 +0000
commit7a6a2a62eebfea5f09bf86fee3935e1ad031959d (patch)
tree3493d6335b22ba7ef4857366e73531f5007b0c5b /backends/platform/psp
parentd04c7a58aa5d72f62f49c5c3246d5e5c0af8920a (diff)
downloadscummvm-rg350-7a6a2a62eebfea5f09bf86fee3935e1ad031959d.tar.gz
scummvm-rg350-7a6a2a62eebfea5f09bf86fee3935e1ad031959d.tar.bz2
scummvm-rg350-7a6a2a62eebfea5f09bf86fee3935e1ad031959d.zip
PSP: switched from SDL's audio to my own thread. Removed needless blocking while playing and made it generally more efficient. To deactivate, simply comment out USE_PSP_AUDIO
svn-id: r49149
Diffstat (limited to 'backends/platform/psp')
-rw-r--r--backends/platform/psp/Makefile4
-rw-r--r--backends/platform/psp/audio.cpp228
-rw-r--r--backends/platform/psp/audio.h71
-rw-r--r--backends/platform/psp/module.mk3
-rw-r--r--backends/platform/psp/osys_psp.cpp31
-rw-r--r--backends/platform/psp/osys_psp.h2
6 files changed, 332 insertions, 7 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 8e83563d10..6967973da7 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -147,8 +147,8 @@ OBJS := powerman.o \
cursor.o \
trace.o \
psploader.o \
- pspkeyboard.o
-
+ pspkeyboard.o \
+ audio.o
# Include common Scummvm makefile
include $(srcdir)/Makefile.common
diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp
new file mode 100644
index 0000000000..c19cbb52a2
--- /dev/null
+++ b/backends/platform/psp/audio.cpp
@@ -0,0 +1,228 @@
+/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+#include <SDL.h>
+#include <pspthreadman.h>
+#include <pspaudio.h>
+
+#include "common/scummsys.h"
+#include "backends/platform/psp/audio.h"
+
+//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
+//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
+
+#include "backends/platform/psp/trace.h"
+
+bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData) {
+ DEBUG_ENTER_FUNC();
+ if (_init) {
+ PSP_ERROR("audio device already initialized\n");
+ return true;
+ }
+
+ PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
+ freq, numOfChannels, numOfSamples, callback, (uint32)userData);
+
+ numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples);
+ uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16);
+
+ PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen);
+
+ _buffers[0] = (byte *)memalign(64, bufLen);
+ if (!_buffers[0]) {
+ PSP_ERROR("failed to allocate memory for audio buffers\n");
+ return false;
+ }
+ memset(_buffers[0], 0, bufLen); // clean the buffer
+
+ // Fill in the rest of the buffer pointers
+ byte *pBuffer = _buffers[0];
+ for (int i = 1; i < NUM_BUFFERS; i++) {
+ pBuffer += numOfSamples * numOfChannels * sizeof(uint16);
+ _buffers[i] = pBuffer;
+ }
+
+ // Reserve a HW channel for our audio
+ _pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO);
+ if (_pspChannel < 0) {
+ PSP_ERROR("failed to reserve audio channel\n");
+ return false;
+ }
+
+ PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel);
+
+ // Save our data
+ _numOfChannels = numOfChannels;
+ _numOfSamples = numOfSamples;
+ _bufferSize = numOfSamples * numOfChannels * sizeof(uint16); // should be the right size to send the app
+ _callback = callback;
+ _userData = userData;
+ _emptyBuffers = NUM_BUFFERS;
+ _bufferToFill = 0;
+ _bufferToPlay = 0;
+
+ _init = true;
+ _paused = true; // start in paused mode
+
+ createThread();
+
+ return true;
+}
+
+bool PspAudio::createThread() {
+ DEBUG_ENTER_FUNC();
+ int threadId = sceKernelCreateThread("audioThread", thread, 30, 16*1024, THREAD_ATTR_USER, 0);
+
+ if (threadId < 0) { // error
+ PSP_ERROR("failed to create audio thread. Error code %d\n", threadId);
+ return false;
+ }
+
+ PspAudio *_this = this; // trick to get into context when the thread starts
+
+ if (sceKernelStartThread(threadId, sizeof(uint32 *), &_this) < 0) {
+ PSP_ERROR("failed to start thread %d\n", threadId);
+ return false;
+ }
+
+ PSP_DEBUG_PRINT("created audio thread[%x]\n", threadId);
+
+ return true;
+}
+
+// Static function to be called upon thread startup. Will call a non-static function
+int PspAudio::thread(SceSize, void *__this) {
+ DEBUG_ENTER_FUNC();
+ PspAudio *_this = *(PspAudio **)__this; // get our this for the context
+
+ _this->audioThread();
+ return 0;
+};
+
+// The real thread function
+void PspAudio::audioThread() {
+ bool isPlaying = false;
+ int remainingSamples = 0;
+
+ assert(_callback);
+ PSP_DEBUG_PRINT_FUNC("audio thread started\n");
+
+ while (_init) { // Keep looping so long as we haven't been told to stop
+ if (_paused)
+ PSP_DEBUG_PRINT("audio thread paused\n");
+ while (_paused) { // delay until we stop pausing
+ SDL_Delay(100);
+ }
+ if (!_paused)
+ PSP_DEBUG_PRINT("audio thread unpaused\n");
+
+ // check if the audio is playing
+ remainingSamples = sceAudioGetChannelRestLen(_pspChannel);
+ if (remainingSamples < 0) {
+ PSP_ERROR("failed to get remaining samples\n");
+ return;
+ }
+ isPlaying = remainingSamples ? true : false;
+
+ PSP_DEBUG_PRINT("remaining samples[%d]\n", remainingSamples);
+
+ while (true) { // really only execute once. this just helps write the logic
+ if (isPlaying) {
+ _stoppedPlayingOnceFlag = false;
+
+ // check if a buffer is empty
+ if (_emptyBuffers) { // we have some empty buffers
+ PSP_DEBUG_PRINT("sound playing & an empty buffer. filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers);
+ _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in
+ nextBuffer(_bufferToFill);
+ _emptyBuffers--;
+ break;
+ } else { // we have no empty buffers
+ // calculate how long we need to sleep. time(us) = samples * 1000000 / freq
+ // since frequency is always 44100, we can do a shortcut:
+ // time(us) = samples * (10000 / 441)
+ uint32 sleepTime = (remainingSamples * 10000) / 441;
+ if (!sleepTime)
+ break;
+ PSP_DEBUG_PRINT("sound playing & no empty buffers. sleeping for %d samples for %dus\n", remainingSamples, sleepTime);
+ sceKernelDelayThread(sleepTime);
+ break;
+ }
+ } else { // we're not playing right now
+ if (_stoppedPlayingOnceFlag == false) { // we only want to do this when we finish playing
+ nextBuffer(_bufferToPlay);
+ _emptyBuffers++;
+ _stoppedPlayingOnceFlag = true;
+ }
+
+ if (_emptyBuffers == NUM_BUFFERS) { // problem: we have only empty buffers!
+ PSP_DEBUG_PRINT("no sound playing & no full buffer. filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers);
+ _callback(_userData, _buffers[_bufferToFill], _bufferSize);
+ nextBuffer(_bufferToFill);
+ _emptyBuffers--;
+ break;
+ } else { // we have at least one non-empty buffer
+ PSP_DEBUG_PRINT("no sound playing & a full buffer. playing buffer[%d]. empty buffers[%d]\n", _bufferToPlay, _emptyBuffers);
+ playBuffer();
+ break;
+ }
+ }
+ } // while true
+ } // while _init
+
+ // destroy everything
+ free(_buffers[0]);
+ sceAudioChRelease(_pspChannel);
+ PSP_DEBUG_PRINT("audio thread exiting. ****************************\n");
+}
+
+// Much faster than using %
+inline void PspAudio::nextBuffer(int &bufferIdx) {
+ DEBUG_ENTER_FUNC();
+ bufferIdx++;
+ if (bufferIdx >= NUM_BUFFERS)
+ bufferIdx = 0;
+}
+
+// Don't do it with blocking
+inline bool PspAudio::playBuffer() {
+ DEBUG_ENTER_FUNC();
+ int ret;
+ if (_numOfChannels == 1)
+ ret = sceAudioOutput(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
+ else
+ ret = sceAudioOutputPanned(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
+
+ if (ret < 0) {
+ PSP_ERROR("failed to output audio. Error[%d]\n", ret);
+ return false;
+ }
+ return true;
+}
+
+void PspAudio::close() {
+ PSP_DEBUG_PRINT("close had been called ***************\n");
+ _init = false;
+}
diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h
new file mode 100644
index 0000000000..97e2391319
--- /dev/null
+++ b/backends/platform/psp/audio.h
@@ -0,0 +1,71 @@
+/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+#ifndef PSP_AUDIO_H
+#define PSP_AUDIO_H
+
+class PspAudio {
+public:
+ enum {
+ NUM_BUFFERS = 2,
+ FREQUENCY = 44100 /* only frequency we allow */
+ };
+ typedef void (* callbackFunc)(void *userData, byte *samples, int len);
+ PspAudio() : _pspChannel(0),
+ _numOfChannels(0), _numOfSamples(0), _callback(0),
+ _bufferToPlay(0), _bufferToFill(0), _emptyBuffers(NUM_BUFFERS),
+ _init(false), _paused(true), _stoppedPlayingOnceFlag(true) {
+ for (int i=0; i<NUM_BUFFERS; i++)
+ _buffers[i] = 0;
+ }
+ ~PspAudio() { close(); }
+ bool playBuffer();
+ void nextBuffer(int &bufferIdx);
+ static int thread(SceSize, void *);
+ void audioThread();
+ bool open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, callbackFunc callback, void *userData);
+ bool createThread();
+ void close();
+ uint32 getFrequency() { return FREQUENCY; }
+ void pause() { _paused = true; }
+ void unpause() { _paused = false; }
+
+private:
+ int _pspChannel; // chosen hardware output channel
+ uint32 _numOfChannels; // 1 for mono; 2 for stereo
+ uint32 _numOfSamples;
+ callbackFunc _callback; // the callback to call between outputting audio
+ void *_userData; // userData to send with callback
+ byte *_buffers[NUM_BUFFERS];
+ int _bufferToPlay; // the next buffer to output
+ int _bufferToFill;
+ int _bufferSize;
+ int _emptyBuffers;
+ bool _init; // flag for initialization
+ bool _paused;
+ bool _stoppedPlayingOnceFlag; // used to make sure we know when the playing stopped
+};
+
+#endif /* PSP_AUDIO_H */
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index f7191fe14f..0e5bd8737d 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -12,7 +12,8 @@ MODULE_OBJS := powerman.o \
cursor.o \
trace.o \
psploader.o \
- pspkeyboard.o
+ pspkeyboard.o \
+ audio.o
MODULE_DIRS += \
backends/platform/psp/
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index 58d98bc219..5f51135a9a 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -48,6 +48,7 @@
#include "backends/platform/psp/trace.h"
+#define USE_PSP_AUDIO
#define SAMPLES_PER_SEC 44100
@@ -58,7 +59,11 @@ static int timer_handler(int t) {
}
void OSystem_PSP::initSDL() {
+#ifdef USE_PSP_AUDIO
+ SDL_Init(SDL_INIT_TIMER);
+#else
SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER);
+#endif
}
OSystem_PSP::~OSystem_PSP() {}
@@ -331,8 +336,6 @@ void OSystem_PSP::mixCallback(void *sys, byte *samples, int len) {
}
void OSystem_PSP::setupMixer(void) {
- SDL_AudioSpec desired;
- SDL_AudioSpec obtained;
// Determine the desired output sampling frequency.
uint32 samplesPerSec = 0;
@@ -349,6 +352,22 @@ void OSystem_PSP::setupMixer(void) {
while (samples * 16 > samplesPerSec * 2)
samples >>= 1;
+ assert(!_mixer);
+
+#ifdef USE_PSP_AUDIO
+ if (!_audio.open(samplesPerSec, 2, samples, mixCallback, this)) {
+ PSP_ERROR("failed to open audio\n");
+ return;
+ }
+ samplesPerSec = _audio.getFrequency(); // may have been changed by audio system
+ _mixer = new Audio::MixerImpl(this, samplesPerSec);
+ assert(_mixer);
+ _mixer->setReady(true);
+ _audio.unpause();
+#else
+ SDL_AudioSpec obtained;
+ SDL_AudioSpec desired;
+
memset(&desired, 0, sizeof(desired));
desired.freq = samplesPerSec;
desired.format = AUDIO_S16SYS;
@@ -356,8 +375,7 @@ void OSystem_PSP::setupMixer(void) {
desired.samples = samples;
desired.callback = mixCallback;
desired.userdata = this;
-
- assert(!_mixer);
+
if (SDL_OpenAudio(&desired, &obtained) != 0) {
warning("Could not open audio: %s", SDL_GetError());
_mixer = new Audio::MixerImpl(this, samplesPerSec);
@@ -376,10 +394,15 @@ void OSystem_PSP::setupMixer(void) {
SDL_PauseAudio(0);
}
+#endif /* USE_PSP_AUDIO */
}
void OSystem_PSP::quit() {
+#ifdef USE_PSP_AUDIO
+ _audio.close();
+#else
SDL_CloseAudio();
+#endif
SDL_Quit();
sceKernelExitGame();
}
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 8c5b40dcdf..4d9cf31b18 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -38,6 +38,7 @@
#include "backends/platform/psp/pspkeyboard.h"
#include "backends/platform/psp/display_manager.h"
#include "backends/platform/psp/input.h"
+#include "backends/platform/psp/audio.h"
#include <SDL.h>
@@ -55,6 +56,7 @@ private:
DisplayManager _displayManager;
PSPKeyboard _keyboard;
InputHandler _inputHandler;
+ PspAudio _audio;
void initSDL();