+#include <string.h>
+
+#include <pspkernel.h>
+#include <pspsdk.h>
+#include <pspaudiocodec.h>
+#include <kubridge.h>
+
+#include "../../pico/pico_int.h"
+#include "../../pico/sound/mix.h"
+#include "../common/lprintf.h"
+
+int mp3_last_error = 0;
+
+static int initialized = 0;
+static SceUID thread_job_sem = -1;
+static SceUID thread_busy_sem = -1;
+static int thread_exit = 0;
+
+// MPEG-1, layer 3
+static int bitrates[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };
+//static int samplerates[] = { 44100, 48000, 32000, 0 };
+
+#define MIN_INFRAME_SIZE 96
+#define IN_BUFFER_SIZE (2*1024)
+
+static unsigned long mp3_codec_struct[65] __attribute__((aligned(64)));
+
+static unsigned char mp3_src_buffer[2][IN_BUFFER_SIZE] __attribute__((aligned(64)));
+static short mp3_mix_buffer[2][1152*2] __attribute__((aligned(64)));
+static int working_buf = 0;
+
+static const char *mp3_fname = NULL;
+static SceUID mp3_handle = -1;
+static int mp3_src_pos = 0, mp3_src_size = 0;
+
+static int decode_thread(SceSize args, void *argp);
+
+
+static void psp_sem_lock(SceUID sem)
+{
+ int ret = sceKernelWaitSema(sem, 1, 0);
+ if (ret < 0) lprintf("sceKernelWaitSema(%08x) failed with %08x\n", sem, ret);
+}
+
+static void psp_sem_unlock(SceUID sem)
+{
+ int ret = sceKernelSignalSema(sem, 1);
+ if (ret < 0) lprintf("sceKernelSignalSema(%08x) failed with %08x\n", sem, ret);
+}
+
+// only accepts MPEG-1, layer3
+static int find_sync_word(unsigned char *data, int len)
+{
+ 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;