aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYotam Barnoy2010-05-30 09:47:00 +0000
committerYotam Barnoy2010-05-30 09:47:00 +0000
commit6884ffc2918d192c9b091d4836f8c566ef3a7fcb (patch)
tree8fa0edf3a7617f3892fed6cd3d8f9809190ab42f
parent5f2ff0b1e7147a5638e66bbd1362196b5419c330 (diff)
downloadscummvm-rg350-6884ffc2918d192c9b091d4836f8c566ef3a7fcb.tar.gz
scummvm-rg350-6884ffc2918d192c9b091d4836f8c566ef3a7fcb.tar.bz2
scummvm-rg350-6884ffc2918d192c9b091d4836f8c566ef3a7fcb.zip
PSP: added preliminary support for using ME hardware to play MP3 files. If the decoder fails to load, MAD is used instead. Disable with DISABLE_PSP_MP3.
svn-id: r49319
-rw-r--r--backends/platform/psp/Makefile6
-rw-r--r--backends/platform/psp/module.mk3
-rw-r--r--backends/platform/psp/mp3.cpp487
-rw-r--r--backends/platform/psp/mp3.h121
-rw-r--r--backends/platform/psp/psp.spec2
-rw-r--r--sound/decoders/mp3.cpp15
6 files changed, 629 insertions, 5 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 7c33999b4d..7f8bb63b0a 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -129,7 +129,8 @@ SDLFLAGS := $(shell $(PSPBIN)/sdl-config --cflags)
SDLLIBS := $(shell $(PSPBIN)/sdl-config --libs)
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
- -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel
+ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
+ -lpspkernel
# Add in PSPSDK includes and libraries.
CXXFLAGS += $(SDLFLAGS)
@@ -149,7 +150,8 @@ OBJS := powerman.o \
psploader.o \
pspkeyboard.o \
audio.o \
- thread.o
+ thread.o \
+ mp3.o
# Include common Scummvm makefile
include $(srcdir)/Makefile.common
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index 4d375bcef0..99170ce7fb 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -14,7 +14,8 @@ MODULE_OBJS := powerman.o \
psploader.o \
pspkeyboard.o \
audio.o \
- thread.o
+ thread.o \
+ mp3.o
MODULE_DIRS += \
backends/platform/psp/
diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp
new file mode 100644
index 0000000000..972c5a8ba8
--- /dev/null
+++ b/backends/platform/psp/mp3.cpp
@@ -0,0 +1,487 @@
+/* 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 "common/debug.h"
+#include "common/stream.h"
+#include "common/util.h"
+#include "common/singleton.h"
+#include "common/mutex.h"
+
+#include "sound/audiostream.h"
+
+#include <pspaudiocodec.h>
+#include <psputility_modules.h>
+#include <pspthreadman.h>
+#include <pspsysmem.h>
+#include <pspmodulemgr.h>
+#include <psputility_avmodules.h>
+#include <mad.h>
+#include "backends/platform/psp/mp3.h"
+
+//#define DISABLE_PSP_MP3 // to make us use the regular MAD decoder instead
+
+//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
+//#define __PSP_DEBUG_PRINT__
+#include "backends/platform/psp/trace.h"
+
+//#define PRINT_BUFFERS /* to debug MP3 buffers */
+
+namespace Audio {
+
+class Mp3PspStream;
+
+bool Mp3PspStream::_decoderInit = false; // has the decoder been initialized
+#ifdef DISABLE_PSP_MP3
+bool Mp3PspStream::_decoderFail = true; // pretend the decoder failed
+#else
+bool Mp3PspStream::_decoderFail = false; // has the decoder failed to load
+#endif
+
+bool Mp3PspStream::initDecoder() {
+ DEBUG_ENTER_FUNC();
+
+ if (_decoderInit) {
+ PSP_ERROR("Already initialized!");
+ return true;
+ }
+
+ // Based on PSP firmware version, we need to do different things to do Media Engine processing
+ uint32 firmware = sceKernelDevkitVersion();
+ PSP_DEBUG_PRINT("Firmware version 0x%x\n", firmware);
+ if (firmware == 0x01050001){
+ if (!loadStartAudioModule((char *)(void *)"flash0:/kd/me_for_vsh.prx",
+ PSP_MEMORY_PARTITION_KERNEL)) {
+ PSP_ERROR("failed to load me_for_vsh.prx. ME cannot start.\n");
+ _decoderFail = true;
+ return false;
+ }
+ if (!loadStartAudioModule((char *)(void *)"flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL)) {
+ PSP_ERROR("failed to load audiocodec.prx. ME cannot start.\n");
+ _decoderFail = true;
+ return false;
+ }
+ } else {
+ if (sceUtilityLoadAvModule(PSP_AV_MODULE_AVCODEC) < 0) {
+ PSP_ERROR("failed to load AVCODEC module.\n");
+ _decoderFail = true;
+ return false;
+ }
+ }
+
+ PSP_INFO_PRINT("Using PSP's ME for MP3\n"); // important to know this is happening
+
+ _decoderInit = true;
+ return true;
+}
+
+bool Mp3PspStream::stopDecoder() {
+ DEBUG_ENTER_FUNC();
+
+ if (!_decoderInit)
+ return true;
+
+ // Based on PSP firmware version, we need to do different things to do Media Engine processing
+ if (sceKernelDevkitVersion() == 0x01050001){
+/* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) ||
+ !unloadAudioModule("flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL) {
+ PSP_ERROR("failed to unload audio module\n");
+ return false;
+ }
+*/
+ }else{
+ if (sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) < 0) {
+ PSP_ERROR("failed to unload avcodec module\n");
+ return false;
+ }
+ }
+
+ _decoderInit = false;
+ return true;
+}
+
+//Load a PSP audio module
+bool Mp3PspStream::loadStartAudioModule(const char *modname, int partition){
+ DEBUG_ENTER_FUNC();
+
+ SceKernelLMOption option;
+ SceUID modid;
+
+ memset(&option, 0, sizeof(option));
+ option.size = sizeof(option);
+ option.mpidtext = partition;
+ option.mpiddata = partition;
+ option.position = 0;
+ option.access = 1;
+
+ modid = sceKernelLoadModule(modname, 0, &option);
+ if (modid < 0) {
+ PSP_ERROR("Failed to load module %s. Got error 0x%x\n", modname, modid);
+ return false;
+ }
+
+ int ret = sceKernelStartModule(modid, 0, NULL, NULL, NULL);
+ if (ret < 0) {
+ PSP_ERROR("Failed to start module %s. Got error 0x%x\n", modname, ret);
+ return false;
+ }
+ return true;
+}
+
+// TODO: make parallel function for unloading the 1.50 modules
+
+Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
+ _inStream(inStream),
+ _disposeAfterUse(dispose),
+ _pcmLength(0),
+ _posInFrame(0),
+ _state(MP3_STATE_INIT),
+ _length(0, 1000),
+ _sampleRate(0),
+ _totalTime(mad_timer_zero) {
+
+ DEBUG_ENTER_FUNC();
+
+ assert(_decoderInit); // must be initialized by now
+
+ // let's leave the buffer guard -- who knows, it may be good?
+ memset(_buf, 0, sizeof(_buf));
+ memset(_codecInBuffer, 0, sizeof(_codecInBuffer));
+
+ initStream(); // init needed stuff for the stream
+
+ while (_state != MP3_STATE_EOS)
+ findValidHeader(); // get a first header so we can read basic stuff
+
+ _sampleRate = _header.samplerate; // copy it before it gets destroyed
+
+ _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate());
+
+ //initStreamME(); // init the stuff needed for the ME to work
+
+ deinitStream();
+ //releaseStreamME();
+
+ _state = MP3_STATE_INIT;
+}
+
+int Mp3PspStream::initStream() {
+ DEBUG_ENTER_FUNC();
+
+ if (_state != MP3_STATE_INIT)
+ deinitStream();
+
+ // Init MAD
+ mad_stream_init(&_stream);
+ mad_header_init(&_header);
+
+ // Reset the stream data
+ _inStream->seek(0, SEEK_SET);
+ _totalTime = mad_timer_zero;
+ _posInFrame = 0;
+
+ // Update state
+ _state = MP3_STATE_READY;
+
+ // Read the first few sample bytes into the buffer
+ readMP3DataIntoBuffer();
+
+ return true;
+}
+
+bool Mp3PspStream::initStreamME() {
+ // The following will eventually go into the thread
+ sceAudiocodecReleaseEDRAM(_codecParams); // do we need this?
+
+ memset(_codecParams, 0, sizeof(_codecParams));
+
+ // Init the MP3 hardware
+ int ret = 0;
+ ret = sceAudiocodecCheckNeedMem(_codecParams, 0x1002);
+ if (ret < 0) {
+ PSP_ERROR("failed to init MP3 ME module. sceAudiocodecCheckNeedMem returned 0x%x.\n", ret);
+ return false;
+ }
+ PSP_DEBUG_PRINT("sceAudiocodecCheckNeedMem returned %d\n", ret);
+ ret = sceAudiocodecGetEDRAM(_codecParams, 0x1002);
+ if (ret < 0) {
+ PSP_ERROR("failed to init MP3 ME module. sceAudiocodecGetEDRAM returned 0x%x.\n", ret);
+ return false;
+ }
+ PSP_DEBUG_PRINT("sceAudioCodecGetEDRAM returned %d\n", ret);
+
+ PSP_DEBUG_PRINT("samplerate[%d]\n", _sampleRate);
+ _codecParams[10] = _sampleRate;
+
+ ret = sceAudiocodecInit(_codecParams, 0x1002);
+ if (ret < 0) {
+ PSP_ERROR("failed to init MP3 ME module. sceAudiocodecInit returned 0x%x.\n", ret);
+ return false;
+ }
+
+ return true;
+}
+
+Mp3PspStream::~Mp3PspStream() {
+ DEBUG_ENTER_FUNC();
+
+ deinitStream();
+ releaseStreamME(); // free the memory used for this stream
+
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ delete _inStream;
+}
+
+void Mp3PspStream::deinitStream() {
+ DEBUG_ENTER_FUNC();
+
+ if (_state == MP3_STATE_INIT)
+ return;
+
+ // Deinit MAD
+ mad_header_finish(&_header);
+ mad_stream_finish(&_stream);
+
+ _state = MP3_STATE_EOS;
+}
+
+void Mp3PspStream::releaseStreamME() {
+ sceAudiocodecReleaseEDRAM(_codecParams);
+}
+
+void Mp3PspStream::decodeMP3Data() {
+ DEBUG_ENTER_FUNC();
+
+ do {
+ if (_state == MP3_STATE_INIT) {
+ initStream();
+ initStreamME();
+ }
+
+ if (_state == MP3_STATE_EOS)
+ return;
+
+ findValidHeader(); // seach for next valid header
+
+ while (_state == MP3_STATE_READY) {
+ _stream.error = MAD_ERROR_NONE;
+
+ uint32 frame_size = _stream.next_frame - _stream.this_frame;
+ uint32 samplesPerFrame = _header.layer == MAD_LAYER_III ? 576 : 1152; // Varies by layer
+ // calculate frame size -- try
+ //uint32 calc_frame_size = ((144 * _header.bitrate) / 22050) + (_header.flags & MAD_FLAG_PADDING ? 1 : 0);
+
+ // Get stereo/mono
+ uint32 multFactor = 1;
+ if (_header.mode != MAD_MODE_SINGLE_CHANNEL) // mono - x2 for 16bit
+ multFactor *= 2; // stereo - x4 for 16bit
+
+ PSP_DEBUG_PRINT("MP3 frame size[%d]. Samples[%d]. Multfactor[%d] pad[%d]\n", frame_size, samplesPerFrame, multFactor, _header.flags & MAD_FLAG_PADDING);
+ memcpy(_codecInBuffer, _stream.this_frame, frame_size); // we need it aligned
+
+ // set up parameters for ME
+ _codecParams[6] = (unsigned long)_codecInBuffer;
+ _codecParams[8] = (unsigned long)_pcmSamples;
+ _codecParams[7] = frame_size;
+ _codecParams[9] = samplesPerFrame * multFactor; // x2 for stereo
+
+ // debug
+#ifdef PRINT_BUFFERS
+ PSP_DEBUG_PRINT("mp3 frame:\n");
+ for (int i=0; i < (int)frame_size; i++) {
+ PSP_DEBUG_PRINT_SAMELN("%x ", _codecInBuffer[i]);
+ }
+ PSP_DEBUG_PRINT("\n");
+#endif
+ // Decode the next frame
+ // This function blocks. We'll want to put it in a thread
+ int ret = sceAudiocodecDecode(_codecParams, 0x1002);
+ if (ret < 0) {
+ PSP_ERROR("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret);
+ // handle error here
+ }
+
+#ifdef PRINT_BUFFERS
+ PSP_DEBUG_PRINT("PCM frame:\n");
+ for (int i=0; i < (int)_codecParams[9]; i+=2) { // changed from i+=2
+ PSP_DEBUG_PRINT_SAMELN("%d ", (int16)_pcmSamples[i]);
+ }
+ PSP_DEBUG_PRINT("\n");
+#endif
+ _pcmLength = samplesPerFrame;
+ _posInFrame = 0;
+ break;
+ }
+ } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
+
+ if (_stream.error != MAD_ERROR_NONE) // catch EOS
+ _state = MP3_STATE_EOS;
+}
+
+void Mp3PspStream::readMP3DataIntoBuffer() {
+ DEBUG_ENTER_FUNC();
+
+ uint32 remaining = 0;
+
+ // Give up immediately if we already used up all data in the stream
+ if (_inStream->eos()) {
+ _state = MP3_STATE_EOS;
+ return;
+ }
+
+ if (_stream.next_frame) {
+ // If there is still data in the MAD stream, we need to preserve it.
+ // Note that we use memmove, as we are reusing the same buffer,
+ // and hence the data regions we copy from and to may overlap.
+ remaining = _stream.bufend - _stream.next_frame;
+ assert(remaining < BUFFER_SIZE); // Paranoia check
+ memmove(_buf, _stream.next_frame, remaining); // TODO: may want another buffer
+ }
+
+ // Try to read the next block
+ uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining);
+ if (size <= 0) {
+ _state = MP3_STATE_EOS;
+ return;
+ }
+
+ // Feed the data we just read into the stream decoder
+ _stream.error = MAD_ERROR_NONE;
+ mad_stream_buffer(&_stream, _buf, size + remaining); // just setup the pointers
+}
+
+bool Mp3PspStream::seek(const Timestamp &where) {
+ DEBUG_ENTER_FUNC();
+
+ if (where == _length) {
+ _state = MP3_STATE_EOS;
+ return true;
+ } else if (where > _length) {
+ return false;
+ }
+
+ const uint32 time = where.msecs();
+
+ mad_timer_t destination;
+ mad_timer_set(&destination, time / 1000, time % 1000, 1000);
+
+ // Check if we need to rewind
+ if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) {
+ initStream();
+ initStreamME();
+ }
+
+ // The ME will need clear data no matter what once we seek?
+ //if (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
+ // initStreamME();
+
+ // Skip ahead
+ while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
+ findValidHeader();
+
+ return (_state != MP3_STATE_EOS);
+}
+
+// Seek in the stream, finding the next valid header
+void Mp3PspStream::findValidHeader() {
+ DEBUG_ENTER_FUNC();
+
+ if (_state != MP3_STATE_READY)
+ return;
+
+ // If necessary, load more data into the stream decoder
+ if (_stream.error == MAD_ERROR_BUFLEN)
+ readMP3DataIntoBuffer();
+
+ while (_state != MP3_STATE_EOS) {
+ _stream.error = MAD_ERROR_NONE;
+
+ // Decode the next header.
+ if (mad_header_decode(&_header, &_stream) == -1) {
+ if (_stream.error == MAD_ERROR_BUFLEN) {
+ readMP3DataIntoBuffer(); // Read more data
+ continue;
+ } else if (MAD_RECOVERABLE(_stream.error)) {
+ debug(6, "MP3PSPStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
+ continue;
+ } else {
+ warning("MP3PSPStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
+ break;
+ }
+ }
+
+ // Sum up the total playback time so far
+ mad_timer_add(&_totalTime, _header.duration);
+ break;
+ }
+
+ if (_stream.error != MAD_ERROR_NONE)
+ _state = MP3_STATE_EOS;
+}
+
+int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
+ DEBUG_ENTER_FUNC();
+
+ int samples = 0;
+#ifdef PRINT_BUFFERS
+ int16 *debugBuffer = buffer;
+#endif
+
+ // Keep going as long as we have input available
+ while (samples < numSamples && _state != MP3_STATE_EOS) {
+ const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header));
+
+ while (samples < len) {
+ *buffer++ = _pcmSamples[_posInFrame << 1];
+ samples++;
+ if (MAD_NCHANNELS(&_header) == 2) {
+ *buffer++ = _pcmSamples[(_posInFrame << 1) + 1];
+ samples++;
+ }
+ _posInFrame++; // always skip an extra sample since ME always outputs stereo
+ }
+
+ //memcpy(buffer, &_pcmSamples[_posInFrame], len << 1); // 16 bits
+ //_posInFrame += len; // next time we start from the middle
+
+ if (_posInFrame >= _pcmLength) {
+ // We used up all PCM data in the current frame -- read & decode more
+ decodeMP3Data();
+ }
+ }
+
+#ifdef PRINT_BUFFERS
+ PSP_INFO_PRINT("buffer:\n");
+ for (int i = 0; i<numSamples; i++)
+ PSP_INFO_PRINT("%d ", debugBuffer[i]);
+ PSP_INFO_PRINT("\n\n");
+#endif
+
+ return samples;
+}
+
+} // End of namespace Audio
+
+
diff --git a/backends/platform/psp/mp3.h b/backends/platform/psp/mp3.h
new file mode 100644
index 0000000000..f8802f930c
--- /dev/null
+++ b/backends/platform/psp/mp3.h
@@ -0,0 +1,121 @@
+/* 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 SOUND_MP3_PSP_H
+#define SOUND_MP3_PSP_H
+
+#include "common/types.h"
+#include "common/scummsys.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Audio {
+
+class AudioStream;
+class SeekableAudioStream;
+
+class Mp3PspStream : public SeekableAudioStream {
+protected:
+ enum State {
+ MP3_STATE_INIT, // Need to init the decoder
+ MP3_STATE_READY, // ready for processing data
+ MP3_STATE_EOS // end of data reached (may need to loop)
+ };
+
+ #define MAX_SAMPLES_PER_FRAME 2048 * 2
+ int16 _pcmSamples[MAX_SAMPLES_PER_FRAME] __attribute__((aligned(64))); // samples to output PCM data into
+ byte _codecInBuffer[3072] __attribute__((aligned(64))); // the codec always needs alignment
+ unsigned long _codecParams[65]__attribute__((aligned(64))); // TODO: change to struct
+
+ Common::SeekableReadStream *_inStream;
+ DisposeAfterUse::Flag _disposeAfterUse;
+
+ uint32 _pcmLength; // how many pcm samples we have (/2 for mono)
+
+ uint _posInFrame; // position in frame
+ State _state; // what state the stream is in
+
+ Timestamp _length;
+ uint32 _sampleRate;
+
+ mad_timer_t _totalTime;
+ mad_stream _stream; //
+ mad_header _header; // This is all we need from libmad
+
+ static bool _decoderInit; // has the decoder been initialized
+ static bool _decoderFail; // has the decoder failed to load
+
+ enum {
+ BUFFER_SIZE = 5 * 8192
+ };
+
+ // This buffer contains a slab of input data
+ byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
+
+ void decodeMP3Data();
+ void readMP3DataIntoBuffer();
+
+ static bool loadStartAudioModule(const char *modname, int partition);
+ int initStream();
+ void findValidHeader();
+ void deinitStream();
+
+ // to init and uninit ME decoder
+ static bool initDecoder();
+ static bool stopDecoder();
+
+ // ME functions for stream
+ bool initStreamME();
+ void releaseStreamME();
+
+public:
+ Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
+ ~Mp3PspStream();
+
+ // This function avoids having to create streams when it's not possible
+ static inline bool isOkToCreateStream() {
+ if (_decoderFail) // fatal failure
+ return false;
+ if (!_decoderInit) // if we're not initialized
+ if (!initDecoder()) // check if we failed init
+ return false;
+ return true;
+ }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool endOfData() const { return _state == MP3_STATE_EOS; }
+ bool isStereo() const { return MAD_NCHANNELS(&_header) == 2; }
+ int getRate() const { return _header.samplerate; }
+
+ bool seek(const Timestamp &where);
+ Timestamp getLength() const { return _length; }
+};
+
+} // End of namespace Audio
+
+#endif // #ifndef SOUND_MP3_PSP_H
diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec
index debdab3208..ac325b7fd6 100644
--- a/backends/platform/psp/psp.spec
+++ b/backends/platform/psp/psp.spec
@@ -1,3 +1,3 @@
%rename lib old_lib
*lib:
-%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspkernel
+%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel
diff --git a/sound/decoders/mp3.cpp b/sound/decoders/mp3.cpp
index f66d6324ef..732ae58b67 100644
--- a/sound/decoders/mp3.cpp
+++ b/sound/decoders/mp3.cpp
@@ -36,7 +36,9 @@
#include <mad.h>
-
+#if defined(__PSP__)
+ #include "backends/platform/psp/mp3.h"
+#endif
namespace Audio {
@@ -347,7 +349,18 @@ int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
SeekableAudioStream *makeMP3Stream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse) {
+
+#if defined(__PSP__)
+ SeekableAudioStream *s = 0;
+
+ if (Mp3PspStream::isOkToCreateStream())
+ s = new Mp3PspStream(stream, disposeAfterUse);
+
+ if (!s) // go to regular MAD mp3 stream if ME fails
+ s = new MP3Stream(stream, disposeAfterUse);
+#else
SeekableAudioStream *s = new MP3Stream(stream, disposeAfterUse);
+#endif
if (s && s->endOfData()) {
delete s;
return 0;