//////////////////////////////////////////////////
//* Custom Firmware Extender For 3.71 Firmware *//
//////////////////////////////////////////////////

#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <psppower.h>
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspctrl.h>
#include <psppower.h>
#include <pspdebug.h>
#include <psprtc.h>
#include <pspsdk.h>
#include <pspaudiocodec.h>
#include <pspaudio.h>
#include <string.h>
#include <malloc.h>
#include <pspmpeg.h>


PSP_MODULE_INFO("cfe_mp3_mod", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);

int build_args(char *args, const char *execfile, int argc, char **argv)
{
	int loc = 0;
	int i;

	strcpy(args, execfile);
	loc += strlen(execfile) + 1;
	for(i = 0; i < argc; i++)
	{
		strcpy(&args[loc], argv[i]);
		printf("Arg %i => %s\n", i, argv[i]);
		loc += strlen(argv[i]) + 1;
	}

	return loc;
}

int loadStartModule(const char *name, int argc, char **argv)
{
	SceUID modid;
	int status;
	char args[128];
	int len;

	modid = sceKernelLoadModule(name, 0, NULL);
	if(modid >= 0)
	{
		len = build_args(args, name, argc, argv);
		modid = sceKernelStartModule(modid, len, (void *) args, &status, NULL);
	}
	else
	{
		printf("lsm: Error loading module %s\n", name);
	}

	return modid;
}

__attribute__ ((constructor))
void loaderInit(){
   pspKernelSetKernelPC();
   pspSdkInstallNoDeviceCheckPatch();
   pspSdkInstallNoPlainModuleCheckPatch();
   pspSdkInstallKernelLoadModulePatch();
}

static int bitrates[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };

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 threadMain(SceSize args, void *argp)
{

 int result = loadStartModule("flash0:/kd/me_for_vsh.prx", 0, NULL);
   
   result = loadStartModule("flash0:/kd/videocodec.prx", 0, NULL);
   
   result = loadStartModule("flash0:/kd/audiocodec.prx", 0, NULL);
   
   result = loadStartModule("flash0:/kd/mpegbase.prx", 0, NULL);
   
   result = loadStartModule("flash0:/kd/mpeg_vsh.prx", 0, NULL);
   
   pspSdkFixupImports(result);
   
   sceMpeg_library_682A619B();
   
   mp3_handle = sceIoOpen("ms0:/Test.MP3", PSP_O_RDONLY, 0777);
   if (  ! mp3_handle )
      goto wait;
   
   mp3_channels = 2;
   mp3_samplerate = 44100; //this is mp3 file's samplerate, also can be 48000,....
   mp3_sample_per_frame = 1152;
   
   mp3_data_start = sceIoLseek32(mp3_handle, 0, PSP_SEEK_CUR);
   
   memset(mp3_codec_buffer, 0, sizeof(mp3_codec_buffer));
   
   if ( sceAudiocodec_Driver_9D3F790C(mp3_codec_buffer, 0x1002) < 0 )
      goto wait;
   if ( sceAudiocodec_Driver_3A20A200(mp3_codec_buffer, 0x1002) < 0 )
         goto wait;
   mp3_getEDRAM = 1;
   
   if ( sceAudiocodec_Driver_5B37EB1D(mp3_codec_buffer, 0x1002) < 0 ) {
      goto wait;
   }
   int audio_channel = sceAudio_driver_E4A9D621(0, mp3_sample_per_frame , PSP_AUDIO_FORMAT_STEREO);
   int eof = 0;   
   while( !eof ) {
      int samplesdecoded;
      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 ) {
         eof = 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 frame_size = 144000*bitrates[bitrate]/mp3_samplerate + padding;
       
      //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
       
      if ( sceIoRead( mp3_handle, mp3_data_buffer, frame_size ) != frame_size ) {
         eof = 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 = sceAudiocodec_Driver_70A703F8(mp3_codec_buffer, 0x1002);
      if ( res < 0 ) {

         eof = 1;
         continue;
      } 
      memcpy(mp3_output_buffer[mp3_output_index], mp3_mix_buffer, 1152*4);
      sceAudio_driver_798FB2A3(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;
   }


wait:
   
   if ( mp3_handle ) {
      sceIoClose(mp3_handle);
   }
   /*if ( mp3_data_buffer) {
      free(mp3_data_buffer);
   }*/
   if ( mp3_getEDRAM ) {
      sceAudiocodec_Driver_29681260(mp3_codec_buffer);
   }

	printf("sceKernelExitGame");
   return 0;
} 


int module_start(SceSize args, void *argp)
{

	int main_thid = sceKernelCreateThread("cfe_mp3_main", threadMain, 6, 0x01000, 0, NULL);
	if(main_thid >= 0) sceKernelStartThread(main_thid, args, argp);

	return 0;

	sceKernelExitDeleteThread(0);
}

int module_stop(SceSize args, void *argp)
{
	return 0;
}
