forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Hardware MP3 Player

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
cools



Joined: 04 Mar 2006
Posts: 46

PostPosted: Fri Oct 05, 2007 11:30 am    Post subject: Hardware MP3 Player Reply with quote

Well I have created a hardware mp3 player, for general use, but it has some flaws. Now I am not the greatest c/c++ coder in the world and I wont pretend to be, but I do what I can to get by. Currently the twon main problems I am having are: after you stop a song, you can't start another one (program will freeze) and it has issues playing alongside a running app...

The code is as follows:
Code:
#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;
}


^Based on work by cooleyes and joek2100, so many thanks to them.
Back to top
View user's profile Send private message
Art



Joined: 09 Nov 2005
Posts: 647

PostPosted: Fri Oct 05, 2007 2:54 pm    Post subject: Reply with quote

Quote:
after you stop a song, you can't start another one (program will freeze)

I've got the same problem. My main program doesn't freeze, but once a
song has started playing, that's it. I can't start another one, or the same song again.
Back to top
View user's profile Send private message
Smong



Joined: 04 Sep 2007
Posts: 82

PostPosted: Fri Oct 05, 2007 8:41 pm    Post subject: Reply with quote

I notice your cleanup function is missing some code, original:
Code:
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?
}

You should be setting all those variables to invalid values so you don't attempt to make future reads or frees on them. For example:
Code:
    if(mp3_handle >= 0){
        sceIoClose(mp3_handle);
        mp3_handle = -1;
   }


Also depending on how you are loading/calling your code you may want to change this:
Code:
void Mp3_play()
{
   if (module_started == 0) {
      module_start(0, NULL);
      module_started = 1;
   } else {
   sceKernelResumeThread(mp3_thread);
   }
}
I would move module_started = 1 to be inside the module_start() function.

While I didn't look at all the code I notice Mp3_stop() is only called from Mp3_load(), assuming the mp3 doesn't loop it doesn't look like the mp3 will get cleaned up when it ends.
_________________
(+[__]%)
Back to top
View user's profile Send private message
cools



Joined: 04 Mar 2006
Posts: 46

PostPosted: Sat Oct 06, 2007 5:44 am    Post subject: Reply with quote

Well I did what you said, and it appears to be working! Thanks! The only problem that I have found out, after some testing, is that after so many seconds of playing the psp freezes and then shuts off. Any ideas?
Back to top
View user's profile Send private message
Smong



Joined: 04 Sep 2007
Posts: 82

PostPosted: Sat Oct 06, 2007 7:33 am    Post subject: Reply with quote

It could either be an exception (install psplinkusb to see it) or it could happen if you don't call sceKernelDelayThread or sceDisplayWaitVblankStart, the PSP will think your program has frozen and switch itself off.
_________________
(+[__]%)
Back to top
View user's profile Send private message
cools



Joined: 04 Mar 2006
Posts: 46

PostPosted: Sat Oct 06, 2007 7:58 am    Post subject: Reply with quote

Major Thanks Smong! I got it working!

EDIT: Well, the mp3 player has some issues when the song ends and you don't stop it yourself, but I'm pretty sure I'll get it figured out.
Back to top
View user's profile Send private message
cools



Joined: 04 Mar 2006
Posts: 46

PostPosted: Mon Oct 08, 2007 5:00 am    Post subject: Reply with quote

NVM: You have to wait a few sec, before you can switch songs...
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group