mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-12 12:09:15 +00:00
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
This commit is contained in:
parent
5f2ff0b1e7
commit
6884ffc291
@ -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
|
||||
|
@ -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/
|
||||
|
487
backends/platform/psp/mp3.cpp
Normal file
487
backends/platform/psp/mp3.cpp
Normal file
@ -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
|
||||
|
||||
|
121
backends/platform/psp/mp3.h
Normal file
121
backends/platform/psp/mp3.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user