PSP: fixed issue in ME MP3 player that prevented different MP3 layers and versions from working.

MAD doesn't give enough information to decide the length of the PCM data -- it provides the Layer but not the MPEG version. I had to read the MP3 header directly to figure it out. This fixes issues with any MP3 files that might be used in any of the games.

svn-id: r52191
This commit is contained in:
Yotam Barnoy 2010-08-18 16:58:32 +00:00
parent 844b466573
commit 70cd6cfda5
2 changed files with 53 additions and 32 deletions

View File

@ -60,6 +60,21 @@ bool Mp3PspStream::_decoderFail = true; // pretend the decoder failed
bool Mp3PspStream::_decoderFail = false; // has the decoder failed to load
#endif
// Arranged in groups of 3 (layers), starting with MPEG-1 and ending with MPEG 2.5
static uint32 mp3SamplesPerFrame[9] = {384, 1152, 1152, 384, 1152, 576, 384, 1152, 576};
// The numbering below doesn't correspond to the way they are in the header
enum {
MPEG_VER1 = 0,
MPEG_VER1_HEADER = 0x3,
MPEG_VER2 = 1,
MPEG_VER2_HEADER = 0x2,
MPEG_VER2_5 = 2,
MPEG_VER2_5_HEADER = 0x0
};
#define HEADER_GET_MPEG_VERSION(x) ((((x)[1])>>3) & 0x3)
bool Mp3PspStream::initDecoder() {
DEBUG_ENTER_FUNC();
@ -104,7 +119,7 @@ bool Mp3PspStream::stopDecoder() {
return true;
// Based on PSP firmware version, we need to do different things to do Media Engine processing
if (sceKernelDevkitVersion() == 0x01050001){
if (sceKernelDevkitVersion() == 0x01050001){ // TODO: how do we unload?
/* 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");
@ -172,17 +187,16 @@ Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse
initStream(); // init needed stuff for the stream
findValidHeader(); // get a first header so we can read basic stuff
_sampleRate = _header.samplerate; // copy it before it gets destroyed
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;
}
@ -284,27 +298,23 @@ void Mp3PspStream::decodeMP3Data() {
findValidHeader(); // seach for next valid header
while (_state == MP3_STATE_READY) {
while (_state == MP3_STATE_READY) { // not a real 'while'. Just for easy flow
_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);
updatePcmLength(); // Retrieve the number of PCM samples.
// We seem to change this, so it needs to be dynamic
PSP_DEBUG_PRINT("MP3 frame size[%d]. pcmLength[%d]\n", frame_size, _pcmLength);
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
_codecParams[9] = _pcmLength * 2; // x2 for stereo, though this one's not so important
// debug
#ifdef PRINT_BUFFERS
@ -319,7 +329,6 @@ void Mp3PspStream::decodeMP3Data() {
int ret = sceAudiocodecDecode(_codecParams, 0x1002);
if (ret < 0) {
PSP_INFO_PRINT("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret);
// handle error here
}
#ifdef PRINT_BUFFERS
@ -329,7 +338,6 @@ void Mp3PspStream::decodeMP3Data() {
}
PSP_DEBUG_PRINT("\n");
#endif
_pcmLength = samplesPerFrame;
_posInFrame = 0;
break;
}
@ -339,6 +347,27 @@ void Mp3PspStream::decodeMP3Data() {
_state = MP3_STATE_EOS;
}
inline void Mp3PspStream::updatePcmLength() {
uint32 mpegVer = HEADER_GET_MPEG_VERSION(_stream.this_frame); // sadly, MAD can't do this for us
PSP_DEBUG_PRINT("mpeg ver[%x]\n", mpegVer);
switch (mpegVer) {
case MPEG_VER1_HEADER:
mpegVer = MPEG_VER1;
break;
case MPEG_VER2_HEADER:
mpegVer = MPEG_VER2;
break;
case MPEG_VER2_5_HEADER:
mpegVer = MPEG_VER2_5;
break;
default:
PSP_ERROR("Unknown MPEG version %x\n", mpegVer);
break;
}
PSP_DEBUG_PRINT("layer[%d]\n", _header.layer);
_pcmLength = mp3SamplesPerFrame[(mpegVer * 3) + _header.layer - 1];
}
void Mp3PspStream::readMP3DataIntoBuffer() {
DEBUG_ENTER_FUNC();
@ -392,10 +421,6 @@ bool Mp3PspStream::seek(const Timestamp &where) {
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();
@ -462,9 +487,6 @@ int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
_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();
@ -481,6 +503,4 @@ int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
return samples;
}
} // End of namespace Audio
} // End of namespace Audio

View File

@ -46,7 +46,7 @@ protected:
MP3_STATE_EOS // end of data reached (may need to loop)
};
#define MAX_SAMPLES_PER_FRAME 2048 * 2
#define MAX_SAMPLES_PER_FRAME 1152 * 2 /* x2 for stereo */
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
@ -54,7 +54,7 @@ protected:
Common::SeekableReadStream *_inStream;
DisposeAfterUse::Flag _disposeAfterUse;
uint32 _pcmLength; // how many pcm samples we have (/2 for mono)
uint32 _pcmLength; // how many pcm samples we have for this type of file (x2 this for stereo)
uint _posInFrame; // position in frame
State _state; // what state the stream is in
@ -83,7 +83,8 @@ protected:
int initStream();
void findValidHeader();
void deinitStream();
void updatePcmLength();
// to init and uninit ME decoder
static bool initDecoder();
static bool stopDecoder();