+ int i;
+ for (i = 0; i < len-1; i++)
+ {
+ if ( data[i+0] != 0xff) continue;
+ if ((data[i+1] & 0xfe) == 0xfa) return i;
+ i++;
+ }
+ return -1;
+}
+
+static int read_next_frame(int which_buffer)
+{
+ int i, bytes_read, frame_offset;
+ int bitrate, padding, frame_size = 0;
+
+ for (i = 0; i < 32; i++)
+ {
+ bytes_read = sceIoRead(mp3_handle, mp3_src_buffer[which_buffer], sizeof(mp3_src_buffer[which_buffer]));
+ mp3_src_pos += bytes_read;
+ if (bytes_read < MIN_INFRAME_SIZE) {
+ mp3_src_pos = mp3_src_size;
+ return 0; // EOF/IO failure
+ }
+ frame_offset = find_sync_word(mp3_src_buffer[which_buffer], bytes_read);
+ if (frame_offset < 0) {
+ lprintf("missing syncword, foffs=%i\n", mp3_src_pos - bytes_read);
+ mp3_src_pos--;
+ sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
+ continue;
+ }
+ if (bytes_read - frame_offset < 4) {
+ lprintf("syncword @ EOB, foffs=%i\n", mp3_src_pos - bytes_read);
+ mp3_src_pos--;
+ sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
+ continue;
+ }
+
+ bitrate = mp3_src_buffer[which_buffer][frame_offset+2] >> 4;
+ padding = (mp3_src_buffer[which_buffer][frame_offset+2] & 2) >> 1;
+
+ frame_size = 144000*bitrates[bitrate]/44100 + padding;
+ if (frame_size <= 0) {
+ lprintf("bad frame, foffs=%i\n", mp3_src_pos - bytes_read);
+ continue; // bad frame
+ }
+
+ if (bytes_read - frame_offset < frame_size)
+ {
+ lprintf("unfit, foffs=%i\n", mp3_src_pos - bytes_read);
+ mp3_src_pos -= bytes_read - frame_offset;
+ if (mp3_src_size - mp3_src_pos < frame_size) {
+ mp3_src_pos = mp3_src_size;
+ return 0; // EOF
+ }
+ sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
+ continue; // didn't fit, re-read..
+ }
+
+ if (frame_offset) {
+ //lprintf("unaligned, foffs=%i, offs=%i\n", mp3_src_pos - bytes_read, frame_offset);
+ memmove(mp3_src_buffer[which_buffer], mp3_src_buffer[which_buffer] + frame_offset, frame_size);
+ }
+
+ // align for next frame read
+ mp3_src_pos -= bytes_read - (frame_offset + frame_size);
+ sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
+
+ break;
+ }
+
+ return frame_size > 0 ? frame_size : -1;
+}
+
+
+static SceUID load_start_module(const char *prxname)
+{
+ SceUID mod, mod1;
+ int status, ret;
+
+ mod = pspSdkLoadStartModule(prxname, PSP_MEMORY_PARTITION_KERNEL);
+ if (mod < 0) {
+ lprintf("failed to load %s (%08x), trying kuKernelLoadModule\n", prxname, mod);
+ mod1 = kuKernelLoadModule(prxname, 0, NULL);
+ if (mod1 < 0) lprintf("kuKernelLoadModule failed with %08x\n", mod1);
+ else {
+ ret = sceKernelStartModule(mod1, 0, NULL, &status, 0);
+ if (ret < 0) lprintf("sceKernelStartModule failed with %08x\n", ret);
+ else mod = mod1;
+ }
+ }
+ return mod;
+}
+
+
+int mp3_init(void)
+{
+ SceUID thid, mod;
+ int ret;
+
+ /* load modules */
+ /* <= 1.5 (and probably some other, not sure which) fw need this to for audiocodec to work,
+ * so if it fails, assume we are just on new enough firmware and continue.. */
+ load_start_module("flash0:/kd/me_for_vsh.prx");
+
+ if (sceKernelDevkitVersion() < 0x02070010)
+ mod = load_start_module("flash0:/kd/audiocodec.prx");
+ else mod = load_start_module("flash0:/kd/avcodec.prx");
+ if (mod < 0) {
+ ret = mod;
+ mod = load_start_module("flash0:/kd/audiocodec_260.prx"); // last chance..
+ if (mod < 0) goto fail;
+ }
+
+ /* audiocodec init */
+ memset(mp3_codec_struct, 0, sizeof(mp3_codec_struct));
+ ret = sceAudiocodecCheckNeedMem(mp3_codec_struct, 0x1002);
+ if (ret < 0) {
+ lprintf("sceAudiocodecCheckNeedMem failed with %08x\n", ret);
+ goto fail;
+ }
+
+ ret = sceAudiocodecGetEDRAM(mp3_codec_struct, 0x1002);
+ if (ret < 0) {
+ lprintf("sceAudiocodecGetEDRAM failed with %08x\n", ret);
+ goto fail;
+ }
+
+ ret = sceAudiocodecInit(mp3_codec_struct, 0x1002);
+ if (ret < 0) {
+ lprintf("sceAudiocodecInit failed with %08x\n", ret);
+ goto fail1;
+ }
+
+ /* thread and stuff */
+ thread_job_sem = sceKernelCreateSema("p_mp3job_sem", 0, 0, 1, NULL);
+ if (thread_job_sem < 0) {
+ lprintf("sceKernelCreateSema() failed: %08x\n", thread_job_sem);
+ ret = thread_job_sem;
+ goto fail1;
+ }
+
+ thread_busy_sem = sceKernelCreateSema("p_mp3busy_sem", 0, 1, 1, NULL);
+ if (thread_busy_sem < 0) {
+ lprintf("sceKernelCreateSema() failed: %08x\n", thread_busy_sem);
+ ret = thread_busy_sem;
+ goto fail2;
+ }
+
+ /* use slightly higher prio then main */
+ thread_exit = 0;
+ thid = sceKernelCreateThread("mp3decode_thread", decode_thread, 30, 0x2000, 0, NULL);
+ if (thid < 0) {
+ lprintf("failed to create decode thread: %08x\n", thid);
+ ret = thid;
+ goto fail3;
+ }
+ ret = sceKernelStartThread(thid, 0, 0);
+ if (ret < 0) {
+ lprintf("failed to start decode thread: %08x\n", ret);
+ goto fail3;
+ }
+
+ mp3_last_error = 0;
+ initialized = 1;