endif # USE_FRONTEND
-OBJS += platform/common/mp3.o
+OBJS += platform/common/mp3.o platform/common/mp3_sync.o
ifeq "$(PLATFORM_MP3)" "1"
+platform/common/mp3_helix.o: CFLAGS += -Iplatform/libpicofe
+OBJS += platform/common/mp3_helix.o
else ifeq "$(HAVE_LIBAVCODEC)" "1"
OBJS += platform/common/mp3_libavcodec.o
else
--- /dev/null
+CROSS ?= arm-linux-gnueabi-
+
+CC = $(CROSS)gcc
+AS = $(CROSS)as
+AR = $(CROSS)ar
+TOOLCHAIN = $(notdir $(CROSS))
+
+CFLAGS += -Ipub -O2 -Wall -fstrict-aliasing -ffast-math
+ifneq ($(findstring arm-,$(TOOLCHAIN)),)
+CFLAGS += -mcpu=arm940t -mtune=arm940t -mfloat-abi=soft -mfpu=fpa -mabi=apcs-gnu -mno-thumb-interwork
+ASFLAGS = -mcpu=arm940t -mfloat-abi=soft -mfpu=fpa -mabi=apcs-gnu
+OBJS += real/arm/asmpoly_gcc.o
+else
+CFLAGS += -m32
+ASFLAGS += -m32
+OBJS += real/polyphase.o
+endif
+
+LIB = $(TOOLCHAIN)helix_mp3.a
+SHLIB = $(TOOLCHAIN)helix_mp3.so
+
+all: $(LIB) $(SHLIB)
+
+
+OBJS += mp3dec.o mp3tabs.o
+#OBJS += ipp/bitstream.o ipp/buffers.o ipp/dequant.o ipp/huffman.o ipp/imdct.o ipp/subband.o
+OBJS += real/bitstream.o real/buffers.o real/dct32.o real/dequant.o real/dqchan.o real/huffman.o
+OBJS += real/hufftabs.o real/imdct.o real/scalfact.o real/stproc.o real/subband.o real/trigtabs.o
+
+OBJS += lib.o
+
+real/arm/asmpoly_gcc.o: real/arm/asmpoly_gcc.s
+ $(CC) -o $@ $(ASFLAGS) -c $<
+
+$(LIB) : $(OBJS)
+ $(AR) r $@ $^
+$(SHLIB) : $(OBJS) /home/build/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1/libgcc.a
+ $(CC) -o $@ -nostdlib -shared $(CFLAGS) $^
+
+clean:
+ $(RM) -f $(OBJS)
+
--- /dev/null
+#include <stdlib.h>
+#include <stdint.h>
+
+// libgcc has this with gcc 4.x
+void raise(int sig)
+{
+}
+
+// very limited heap functions for helix decoder
+
+static char heap[65000] __attribute__((aligned(16)));
+static long heap_offs;
+
+void __malloc_init(void)
+{
+ heap_offs = 0;
+}
+
+void *malloc(size_t size)
+{
+ void *chunk = heap + heap_offs;
+ size = (size+15) & ~15;
+ if (heap_offs + size > sizeof(heap))
+ return NULL;
+ else {
+ heap_offs += size;
+ return chunk;
+ }
+}
+
+void free(void *chunk)
+{
+ if (chunk == heap)
+ heap_offs = 0;
+}
+
+#if 0
+void *memcpy (void *dest, const void *src, size_t n)
+{
+ char *_dest = dest;
+ const char *_src = src;
+ while (n--) *_dest++ = *_src++;
+ return dest;
+}
+
+void *memmove (void *dest, const void *src, size_t n)
+{
+ char *_dest = dest+n;
+ const char *_src = src+n;
+ if (dest <= src || dest >= _src)
+ return memcpy(dest, src, n);
+ while (n--) *--_dest = *--_src;
+ return dest;
+}
+#else
+/* memcpy/memmove in C with some simple optimizations.
+ * ATTN does dirty aliasing tricks with undefined behaviour by standard.
+ * (this works fine with gcc, though...)
+ */
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ struct _16 { uint32_t a[4]; };
+ union { const void *v; char *c; uint64_t *l; struct _16 *s; }
+ ss = { src }, ds = { dest };
+ const int lm = sizeof(uint32_t)-1;
+
+ if ((((unsigned)ss.c ^ (unsigned)ds.c) & lm) == 0) {
+ /* fast copy if pointers have the same aligment */
+ while (((unsigned)ss.c & lm) && n > 0) /* align to word */
+ *ds.c++ = *ss.c++, n--;
+ while (n >= sizeof(struct _16)) /* copy 16 bytes blocks */
+ *ds.s++ = *ss.s++, n -= sizeof(struct _16);
+ if (n >= sizeof(uint64_t)) /* copy leftover 8 byte block */
+ *ds.l++ = *ss.l++, n -= sizeof(uint64_t);
+ } else {
+ /* byte copy if pointers are unaligned */
+ while (n >= 8) { /* copy 8 byte blocks */
+ *ds.c++ = *ss.c++, n--; *ds.c++ = *ss.c++, n--;
+ *ds.c++ = *ss.c++, n--; *ds.c++ = *ss.c++, n--;
+ *ds.c++ = *ss.c++, n--; *ds.c++ = *ss.c++, n--;
+ *ds.c++ = *ss.c++, n--; *ds.c++ = *ss.c++, n--;
+ }
+ }
+ /* copy max. 8 leftover bytes */
+ while (n > 0)
+ *ds.c++ = *ss.c++, n--;
+ return dest;
+}
+
+void *memmove (void *dest, const void *src, size_t n)
+{
+ struct _16 { uint32_t a[4]; };
+ union { const void *v; char *c; uint64_t *l; struct _16 *s; }
+ ss = { src+n }, ds = { dest+n };
+ const int lm = sizeof(uint32_t)-1;
+
+ if (dest <= src || dest >= src+n)
+ return memcpy(dest, src, n);
+
+ if ((((unsigned)ss.c ^ (unsigned)ds.c) & lm) == 0) {
+ /* fast copy if pointers have the same aligment */
+ while (((unsigned)ss.c & lm) && n > 0)
+ *--ds.c = *--ss.c, n--;
+ while (n >= sizeof(struct _16))
+ *--ds.s = *--ss.s, n -= sizeof(struct _16);
+ if (n >= sizeof(uint64_t))
+ *--ds.l = *--ss.l, n -= sizeof(uint64_t);
+ } else {
+ /* byte copy if pointers are unaligned */
+ while (n >= 8) {
+ *--ds.c = *--ss.c, n--; *--ds.c = *--ss.c, n--;
+ *--ds.c = *--ss.c, n--; *--ds.c = *--ss.c, n--;
+ *--ds.c = *--ss.c, n--; *--ds.c = *--ss.c, n--;
+ *--ds.c = *--ss.c, n--; *--ds.c = *--ss.c, n--;
+ }
+ }
+ /* copy max. 8 leftover bytes */
+ while (n > 0)
+ *--ds.c = *--ss.c, n--;
+ return dest;
+}
+#endif
0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
};
-int mp3_find_sync_word(const unsigned char *buf, int size)
-{
- const unsigned char *p, *pe;
-
- /* find byte-aligned syncword - need 12 (MPEG 1,2) or 11 (MPEG 2.5) matching bits */
- for (p = buf, pe = buf + size - 3; p <= pe; p++)
- {
- int pn;
- if (p[0] != 0xff)
- continue;
- pn = p[1];
- if ((pn & 0xf8) != 0xf8 || // currently must be MPEG1
- (pn & 6) == 0) { // invalid layer
- p++; continue;
- }
- pn = p[2];
- if ((pn & 0xf0) < 0x20 || (pn & 0xf0) == 0xf0 || // bitrates
- (pn & 0x0c) != 0) { // not 44kHz
- continue;
- }
-
- return p - buf;
- }
-
- return -1;
-}
-
static int try_get_bitrate(unsigned char *buf, int buf_size)
{
int offs1, offs = 0;
extern unsigned short mpeg1_l3_bitrates[16];
#ifdef __GP2X__
-void mp3_update_local(int *buffer, int length, int stereo);
-void mp3_start_play_local(void *f, int pos);
+int _mp3dec_start(FILE *f, int fpos_start);
+int _mp3dec_decode(FILE *f, int *file_pos, int file_len);
#endif
#endif // __COMMON_MP3_H__
#include <stdio.h>
#include <string.h>
+#include <dlfcn.h>
#include <pico/pico_int.h>
#include <pico/sound/mix.h>
static unsigned char mp3_input_buffer[2 * 1024];
#ifdef __GP2X__
-#define mp3_update mp3_update_local
-#define mp3_start_play mp3_start_play_local
+#define mp3dec_decode _mp3dec_decode
+#define mp3dec_start _mp3dec_start
#endif
+static void *libhelix;
+HMP3Decoder (*p_MP3InitDecoder)(void);
+void (*p_MP3FreeDecoder)(HMP3Decoder);
+int (*p_MP3Decode)(HMP3Decoder, unsigned char **, int *, short *, int);
+
int mp3dec_decode(FILE *f, int *file_pos, int file_len)
{
unsigned char *readPtr;
bytesLeft -= offset;
had_err = err;
- err = MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
+ err = p_MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
if (err) {
if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) {
// just need another frame
int mp3dec_start(FILE *f, int fpos_start)
{
+ if (libhelix == NULL) {
+ libhelix = dlopen("./libhelix.so", RTLD_NOW);
+ if (libhelix == NULL) {
+ lprintf("mp3dec: load libhelix.so: %s\n", dlerror());
+ return -1;
+ }
+
+ p_MP3InitDecoder = dlsym(libhelix, "MP3InitDecoder");
+ p_MP3FreeDecoder = dlsym(libhelix, "MP3FreeDecoder");
+ p_MP3Decode = dlsym(libhelix, "MP3Decode");
+
+ if (p_MP3InitDecoder == NULL || p_MP3FreeDecoder == NULL
+ || p_MP3Decode == NULL)
+ {
+ lprintf("mp3dec: missing symbol(s) in libhelix.so\n");
+ dlclose(libhelix);
+ libhelix = NULL;
+ return -1;
+ }
+ }
+
// must re-init decoder for new track
if (mp3dec)
- MP3FreeDecoder(mp3dec);
- mp3dec = MP3InitDecoder();
+ p_MP3FreeDecoder(mp3dec);
+ mp3dec = p_MP3InitDecoder();
return (mp3dec == 0) ? -1 : 0;
}
--- /dev/null
+
+int mp3_find_sync_word(const unsigned char *buf, int size)
+{
+ const unsigned char *p, *pe;
+
+ /* find byte-aligned syncword - need 12 (MPEG 1,2) or 11 (MPEG 2.5) matching bits */
+ for (p = buf, pe = buf + size - 3; p <= pe; p++)
+ {
+ int pn;
+ if (p[0] != 0xff)
+ continue;
+ pn = p[1];
+ if ((pn & 0xf8) != 0xf8 || // currently must be MPEG1
+ (pn & 6) == 0) { // invalid layer
+ p++; continue;
+ }
+ pn = p[2];
+ if ((pn & 0xf0) < 0x20 || (pn & 0xf0) == 0xf0 || // bitrates
+ (pn & 0x0c) != 0) { // not 44kHz
+ continue;
+ }
+
+ return p - buf;
+ }
+
+ return -1;
+}
int mp3dec_decode(FILE *f, int *file_pos, int file_len)\r
{\r
if (!(PicoIn.opt & POPT_EXT_FM)) {\r
- //mp3_update_local(buffer, length, stereo);\r
- return 0;\r
+ return _mp3dec_decode(f, file_pos, file_len);\r
}\r
\r
// check if playback was started, track not ended\r
int mp3dec_start(FILE *f, int fpos_start)\r
{\r
if (!(PicoIn.opt & POPT_EXT_FM)) {\r
- //mp3_start_play_local(f, pos);\r
- return -1;\r
+ return _mp3dec_start(f, fpos_start);\r
}\r
\r
if (loaded_mp3 != f)\r
// (c) Copyright 2006-2007, Grazvydas "notaz" Ignotas\r
\r
#include "940shared.h"\r
-#include "../../common/mp3.h"\r
+#include "../../common/helix/pub/mp3dec.h"\r
\r
static _940_data_t *shared_data = (_940_data_t *) 0x00100000;\r
static _940_ctl_t *shared_ctl = (_940_ctl_t *) 0x00200000;\r
// is changed by other core just before we update it\r
void set_if_not_changed(int *val, int oldval, int newval);\r
\r
-void _memcpy(void *dst, const void *src, int count);\r
+extern void *memcpy(void *dest, const void *src, unsigned long n);\r
\r
// asm volatile ("mov r0, #0" ::: "r0");\r
// asm volatile ("mcr p15, 0, r0, c7, c6, 0" ::: "r0"); /* flush dcache */\r
int job = 0;\r
ym2612_940 = &shared_data->ym2612;\r
\r
+// extern unsigned __bss_start__, __bss_end__;\r
+// memset(&__bss_start__, 0, &__bss_end__ - &__bss_start__);\r
\r
for (;;)\r
{\r
shared_ctl->writebuff0[0] = shared_ctl->writebuff1[0] = 0xffff;\r
YM2612Init_(shared_ctl->baseclock, shared_ctl->rate);\r
/* Helix mp3 decoder */\r
+ __malloc_init();\r
shared_data->mp3dec = MP3InitDecoder();\r
break;\r
\r
\r
case JOB940_PICOSTATESAVE2:\r
YM2612PicoStateSave2(0, 0);\r
- _memcpy(shared_ctl->writebuff0, ym2612_940->REGS, 0x200);\r
+ memcpy(shared_ctl->writebuff0, ym2612_940->REGS, 0x200);\r
break;\r
\r
case JOB940_PICOSTATELOAD2_PREP:\r
break;\r
\r
case JOB940_PICOSTATELOAD2:\r
- _memcpy(ym2612_940->REGS, shared_ctl->writebuff0, 0x200);\r
+ memcpy(ym2612_940->REGS, shared_ctl->writebuff0, 0x200);\r
YM2612PicoStateLoad2(0, 0);\r
break;\r
\r
\r
case JOB940_MP3RESET:\r
if (shared_data->mp3dec) MP3FreeDecoder(shared_data->mp3dec);\r
+ __malloc_init();\r
shared_data->mp3dec = MP3InitDecoder();\r
break;\r
}\r
dcache_clean();\r
}\r
}\r
-\r
# you may or may not need to change this\r
-#devkit_path = x:/stuff/dev/devkitgp2x/\r
-devkit_path ?= $(HOME)/opt/devkitGP2X/\r
-lgcc_path = $(devkit_path)lib/gcc/arm-linux/4.0.3/\r
-CROSS = arm-linux-\r
+#devkit_path ?= $(HOME)/opt/devkitGP2X/\r
+#lgcc_path = $(devkit_path)lib/gcc/arm-linux/4.0.3/\r
#CROSS = $(devkit_path)bin/arm-linux-\r
+#devkit_path ?= $(HOME)/opt/open2x\r
+#lgcc_path = $(devkit_path)/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1/\r
+#CROSS ?= $(devkit_path)/gcc-4.1.1-glibc-2.3.6/bin/arm-open2x-linux-\r
+#devkit_path ?= $(HOME)/opt/arm-unknown-linux-gnu\r
+#lgcc_path = $(HOME)/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1/\r
+#CROSS ?= $(devkit_path)/bin/arm-unknown-linux-gnu-\r
+lgcc_path = $(HOME)/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib/gcc/arm-open2x-linux/4.1.1/\r
+CROSS ?= arm-linux-gnueabi-\r
\r
# settings\r
#up = 1\r
\r
-CFLAGS += -O2 -Wall -fomit-frame-pointer -fstrict-aliasing -ffast-math\r
-CFLAGS += -I../.. -I. -D__GP2X__ -DARM\r
-CFLAGS += -mcpu=arm940t -mtune=arm940t\r
-LDFLAGS = -static -s -e code940 -Ttext 0x0 -L$(lgcc_path) -lgcc\r
+CFLAGS += -O2 -Wall -mno-thumb-interwork -fstrict-aliasing -ffast-math\r
+CFLAGS += -I../../common/helix/pub -I../../.. -I. -D__GP2X__ -DARM\r
+CFLAGS += -mcpu=arm940t -mtune=arm940t -mabi=apcs-gnu -mfloat-abi=soft -mfpu=fpa\r
+LDFLAGS = -static -e code940 -Ttext 0x0 -L$(lgcc_path) -lgcc\r
\r
GCC = $(CROSS)gcc\r
STRIP = $(CROSS)strip\r
# stuff for 940 core\r
\r
# init, emu_control, emu\r
-OBJS940 += 940init.o 940.o 940ym2612.o memcpy.o misc_arm.o mp3.o\r
+OBJS940 += 940init.o 940.o 940ym2612.o misc_arm.o mp3_sync.o\r
+# the asm memcpy code crashes job LOAD2 on 940. Possibly a globbered reg?\r
+# OBJS940 += memcpy.o\r
# the asm code seems to be faster when run on 920, but not on 940 for some reason\r
# OBJS940 += ../../Pico/sound/ym2612_asm.o\r
\r
OBJS940 += uClibc/memset.o uClibc/s_floor.o uClibc/e_pow.o uClibc/e_sqrt.o uClibc/s_fabs.o\r
OBJS940 += uClibc/s_scalbn.o uClibc/s_copysign.o uClibc/k_sin.o uClibc/k_cos.o uClibc/s_sin.o\r
OBJS940 += uClibc/e_rem_pio2.o uClibc/k_rem_pio2.o uClibc/e_log.o uClibc/wrappers.o\r
+LIBHELIX ?= ../../common/helix/$(notdir $(CROSS))helix_mp3.a\r
\r
$(BIN) : code940.elf\r
@echo ">>>" $@\r
$(OBJCOPY) -O binary $< $@\r
\r
-code940.elf : $(OBJS940) ../../common/helix/$(CROSS)helix-mp3.a\r
+code940.elf : $(OBJS940) $(LIBHELIX)\r
@echo ">>>" $@\r
$(LD) $^ $(LDFLAGS) -o $@ -Map code940.map\r
\r
@echo ">>>" $@\r
$(GCC) $(CFLAGS) -DEXTERNAL_YM2612 -c $< -o $@\r
\r
-../../common/helix/helix_mp3.a:\r
- @make -C ../../common/helix/\r
+mp3_sync.o: ../../common/mp3_sync.c\r
+ @echo ">>>" $@\r
+ $(GCC) $(CFLAGS) -Os -DCODE940 -c $< -o $@\r
+\r
+$(LIBHELIX):\r
+ @$(MAKE) -C ../../common/helix/ CROSS=$(CROSS)\r
\r
\r
up: $(BIN)\r
##\r
OBJSMP3T = mp3test.o ../gp2x.o ../asmutils.o ../usbjoy.o\r
\r
-mp3test.gpe : $(OBJSMP3T) ../helix/helix_mp3.a\r
+mp3test.gpe : $(OBJSMP3T) $(LIBHELIX)\r
$(GCC) -static -o $@ $^\r
$(STRIP) $@\r
@cp -v $@ /mnt/gp2x/mnt/sd\r
//#include "emu.h"\r
//#include "menu.h"\r
#include "../asmutils.h"\r
-#include "../helix/pub/mp3dec.h"\r
+#include "../../helix/pub/mp3dec.h"\r
\r
/* we will need some gp2x internals here */\r
extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */\r
.text\r
.global memset\r
.type memset,%function\r
- .align 4\r
+ .align 2\r
\r
memset:\r
mov a4, a1\r
{\r
return __ieee754_pow(x, y);\r
}\r
+double __pow_finite(double x, double y)\r
+{\r
+ return __ieee754_pow(x, y);\r
+}\r
\r
\r
double log(double x)\r
{\r
return __ieee754_log(x);\r
}\r
+double __log_finite(double x)\r
+{\r
+ return __ieee754_log(x);\r
+}\r