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;
}