The code is as follows:
Code: Select all
#include <pspkernel.h>
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspsdk.h>
#include <pspaudiocodec.h>
#include <pspaudio.h>
#include <string.h>
#include <malloc.h>
#include <pspmpeg.h>
#include "hmp3.h"
static int bitrates[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
static int bitrates_v2[] = {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 };
static int samplerates[4][3] =
{
{11025, 12000, 8000,},//mpeg 2.5
{0, 0, 0,}, //reserved
{22050, 24000, 16000,},//mpeg 2
{44100, 48000, 32000}//mpeg 1
};
unsigned long mp3_codec_buffer[65] __attribute__((aligned(64)));
short mp3_mix_buffer[1152 * 2] __attribute__((aligned(64)));
short mp3_output_buffer[4][1152 * 2] __attribute__((aligned(64)));
int mp3_output_index = 0;
SceUID mp3_handle;
u8* mp3_data_buffer;
u16 mp3_data_align;
u32 mp3_sample_per_frame;
u16 mp3_channel_mode;
u32 mp3_data_start;
u32 mp3_data_size;
u8 mp3_getEDRAM;
u32 mp3_channels;
u32 mp3_samplerate;
int frame_size;
int size;
int eos = 0;
int achannel_set;
int samplesdecoded;
int audio_channel;
int module_started = 0;
int mp3_thread;
int ispaused = 0;
static int LoadStartModule(char *path)
{
u32 loadResult;
u32 startResult;
int status;
loadResult = sceKernelLoadModule(path, 0, NULL);
if (loadResult & 0x80000000)
return -1;
else
startResult =
sceKernelStartModule(loadResult, 0, NULL, &status, NULL);
if (loadResult != startResult)
return -2;
return 0;
}
void Mp3_init()
{
LoadStartModule("flash0:/kd/me_for_vsh.prx");
LoadStartModule("flash0:/kd/videocodec.prx");
LoadStartModule("flash0:/kd/audiocodec.prx");
LoadStartModule("flash0:/kd/mpegbase.prx");
LoadStartModule("flash0:/kd/mpeg_vsh.prx");
sceMpegInit();
}
void Mp3_stop()
{
if(mp3_handle >= 0){
sceIoClose(mp3_handle);
}
if(mp3_data_buffer){
free(mp3_data_buffer);
}
if ( mp3_getEDRAM ) {
sceAudiocodecReleaseEDRAM(mp3_codec_buffer);
}
//sceKernelSuspendThread (mp3_thread); ? Is there something special I need to do here?
}
void Mp3_load(char *filename)
{
mp3_handle = sceIoOpen(filename, PSP_O_RDONLY, 0777);
if ( ! mp3_handle ){
Mp3_stop();
}
mp3_channels = 2;
size = sceIoLseek32(mp3_handle, 0, PSP_SEEK_END);
sceIoLseek32(mp3_handle, 0, PSP_SEEK_SET);
mp3_data_start = SeekNextFrame(mp3_handle);
if (mp3_data_start < 0){
Mp3_stop();
}
size -= mp3_data_start;
memset(mp3_codec_buffer, 0, sizeof(mp3_codec_buffer));
if ( sceAudiocodecCheckNeedMem(mp3_codec_buffer, 0x1002) < 0 ) {
Mp3_stop();
}
if ( sceAudiocodecGetEDRAM(mp3_codec_buffer, 0x1002) < 0 ) {
Mp3_stop();
}
mp3_getEDRAM = 1;
if ( sceAudiocodecInit(mp3_codec_buffer, 0x1002) < 0 ) {
Mp3_stop();
}
eos = 0;
}
int Mp3thread(SceSize args, void *argp)
{
while( !eos ) {
memset(mp3_mix_buffer, 0, mp3_sample_per_frame*2*2);
unsigned char mp3_header_buf[4];
if ( sceIoRead( mp3_handle, mp3_header_buf, 4 ) != 4 ) {
eos = 1;
continue;
}
int mp3_header = mp3_header_buf[0];
mp3_header = (mp3_header<<8) | mp3_header_buf[1];
mp3_header = (mp3_header<<8) | mp3_header_buf[2];
mp3_header = (mp3_header<<8) | mp3_header_buf[3];
int bitrate = (mp3_header & 0xf000) >> 12;
int padding = (mp3_header & 0x200) >> 9;
int version = (mp3_header & 0x180000) >> 19;
mp3_samplerate = samplerates[version][ (mp3_header & 0xC00) >> 10 ];
if ((bitrate > 14) || (version == 1) || (mp3_samplerate == 0) || (bitrate == 0))//invalid frame, look for the next one
{
mp3_data_start = SeekNextFrame(mp3_handle);
if(mp3_data_start < 0)
{
eos = 1;
continue;
}
size -= mp3_data_start;
continue;
}
if (version == 3) //mpeg-1
{
mp3_sample_per_frame = 1152;
frame_size = 144000*bitrates[bitrate]/mp3_samplerate + padding;
}
else
{
mp3_sample_per_frame = 576;
frame_size = 72000*bitrates_v2[bitrate]/mp3_samplerate + padding;
}
if (achannel_set == 0) {
audio_channel = sceAudioChReserve(1, mp3_sample_per_frame , PSP_AUDIO_FORMAT_STEREO);
achannel_set = 1;
}
if ( mp3_data_buffer )
free(mp3_data_buffer);
mp3_data_buffer = (u8*)memalign(64, frame_size);
sceIoLseek32(mp3_handle, mp3_data_start, PSP_SEEK_SET); //seek back
size -= frame_size;
if ( sceIoRead( mp3_handle, mp3_data_buffer, frame_size ) != frame_size )
{
eos = 1;
continue;
}
mp3_data_start += frame_size;
mp3_codec_buffer[6] = (unsigned long)mp3_data_buffer;
mp3_codec_buffer[8] = (unsigned long)mp3_mix_buffer;
mp3_codec_buffer[7] = mp3_codec_buffer[10] = frame_size;
mp3_codec_buffer[9] = mp3_sample_per_frame * 4;
int res = sceAudiocodecDecode(mp3_codec_buffer, 0x1002);
if ( res < 0 ) {
mp3_data_start = SeekNextFrame(mp3_handle);
if (mp3_data_start < 0)
{
eos = 1;
continue;
}
size -= mp3_data_start;
continue;
}
memcpy(mp3_output_buffer[mp3_output_index], mp3_mix_buffer, mp3_sample_per_frame*4);
sceAudioOutputBlocking(audio_channel, PSP_AUDIO_VOLUME_MAX, mp3_output_buffer[mp3_output_index]);
mp3_output_index = (mp3_output_index+1)%4;
samplesdecoded = mp3_sample_per_frame;
}
return 0;
}
void Mp3_play()
{
if (module_started == 0) {
module_start(0, NULL);
module_started = 1;
} else {
sceKernelResumeThread(mp3_thread);
}
}
void Mp3_pause()
{
if (ispaused) {
sceKernelResumeThread(mp3_thread);
ispaused = 0;
} else {
sceKernelSuspendThread(mp3_thread);
ispaused = 1;
}
}
int Mp3_EndOfStream()
{
return eos;
}
int SeekNextFrame(SceUID fd)
{
int offset = 0;
unsigned char buf[1024];
unsigned char *pBuffer;
int i;
int size = 0;
offset = sceIoLseek32(fd, 0, PSP_SEEK_CUR);
sceIoRead(fd, buf, sizeof(buf));
if (!strncmp((char*)buf, "ID3", 3) || !strncmp((char*)buf, "ea3", 3)) //skip past id3v2 header, which can cause a false sync to be found
{
//get the real size from the syncsafe int
size = buf[6];
size = (size<<7) | buf[7];
size = (size<<7) | buf[8];
size = (size<<7) | buf[9];
size += 10;
if (buf[5] & 0x10) //has footer
size += 10;
}
sceIoLseek32(fd, offset + size, PSP_SEEK_SET); //now seek for a sync
while(1)
{
offset = sceIoLseek32(fd, 0, PSP_SEEK_CUR);
size = sceIoRead(fd, buf, sizeof(buf));
if (size <= 2)//at end of file
return -1;
if (!strncmp((char*)buf, "EA3", 3))//oma mp3 files have non-safe ints in the EA3 header
{
sceIoLseek32(fd, (buf[4]<<8)+buf[5], PSP_SEEK_CUR);
continue;
}
pBuffer = buf;
for( i = 0; i < size; i++)
{
//if this is a valid frame sync (0xe0 is for mpeg version 2.5,2+1)
if ( (pBuffer[i] == 0xff) && ((pBuffer[i+1] & 0xE0) == 0xE0))
{
offset += i;
sceIoLseek32(fd, offset, PSP_SEEK_SET);
return offset;
}
}
//go back two bytes to catch any syncs that on the boundary
sceIoLseek32(fd, -2, PSP_SEEK_CUR);
}
}
int module_start(SceSize args, void *argp)
{
/* Create a high priority thread */
mp3_thread = sceKernelCreateThread("FORMP3", Mp3thread, 0x12, 0x04000, 0, NULL);
if(mp3_thread >= 0)
{
sceKernelStartThread(mp3_thread, args, argp);
}
return 0;
}