#include "emu.h"\r
#include "menu.h"\r
#include "asmutils.h"\r
+#include "../../Pico/PicoInt.h"\r
\r
/* we will need some gp2x internals here */\r
extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */\r
static unsigned char *shared_mem = 0;\r
static _940_data_t *shared_data = 0;\r
static _940_ctl_t *shared_ctl = 0;\r
+static unsigned char *mp3_mem = 0;\r
+\r
+#define MP3_SIZE_MAX (0x1000000 - 4*640*480)\r
\r
int crashed_940 = 0;\r
\r
shared_data = (_940_data_t *) (shared_mem+0x100000);\r
/* this area must not get buffered on either side */\r
shared_ctl = (_940_ctl_t *) (shared_mem+0x200000);\r
+ mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x3000000);\r
+ if (mp3_mem == MAP_FAILED)\r
+ {\r
+ printf("mmap(mp3_mem) failed with %i\n", errno);\r
+ exit(1);\r
+ }\r
crashed_940 = 1;\r
}\r
\r
}\r
\r
\r
+static void mix_samples(short *dest_buf, int *ym_buf, short *mp3_buf, int len, int stereo)\r
+{\r
+ if (mp3_buf)\r
+ {\r
+ if (stereo)\r
+ {\r
+ for (; len > 0; len--)\r
+ {\r
+ int l, r, lm, rm;\r
+ l = r = *dest_buf;\r
+ l += *ym_buf++; r += *ym_buf++;\r
+ lm = *mp3_buf++; rm = *mp3_buf++;\r
+ l += lm - lm/2; r += rm - rm/2;\r
+ Limit( l, MAXOUT, MINOUT );\r
+ Limit( r, MAXOUT, MINOUT );\r
+ *dest_buf++ = l; *dest_buf++ = r;\r
+ }\r
+ } else {\r
+ for (; len > 0; len--)\r
+ {\r
+ // TODO: normalize\r
+ int l = *ym_buf++;\r
+ l += *dest_buf;\r
+ l += *mp3_buf++;\r
+ Limit( l, MAXOUT, MINOUT );\r
+ *dest_buf++ = l;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (stereo)\r
+ {\r
+ for (; len > 0; len--)\r
+ {\r
+ int l, r;\r
+ l = r = *dest_buf;\r
+ l += *ym_buf++, r += *ym_buf++;\r
+ Limit( l, MAXOUT, MINOUT );\r
+ Limit( r, MAXOUT, MINOUT );\r
+ *dest_buf++ = l; *dest_buf++ = r;\r
+ }\r
+ } else {\r
+ for (; len > 0; len--)\r
+ {\r
+ int l = *ym_buf++;\r
+ l += *dest_buf;\r
+ Limit( l, MAXOUT, MINOUT );\r
+ *dest_buf++ = l;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+// here we assume that length is different between games, but constant in one game\r
+\r
+static FILE *loaded_mp3 = 0;\r
+\r
void YM2612UpdateOne_940(short *buffer, int length, int stereo)\r
{\r
- int i, *mix_buffer = shared_data->mix_buffer;\r
+ int cdda_on, *ym_buffer = shared_data->mix_buffer, mp3_job = 0;\r
+ static int mp3_samples_ready = 0, mp3_buffer_offs = 0;\r
+ static int mp3_play_bufsel = 1;\r
\r
//printf("YM2612UpdateOne_940()\n");\r
if (shared_ctl->busy) wait_busy_940();\r
// printf("%i ", shared_ctl->vstarts[i]);\r
//printf(")\n");\r
\r
+ // emulatind MCD, cdda enabled in config, not data track, CDC is reading, playback was started, track not ended\r
+ cdda_on = (PicoMCD & 1) && (currentConfig.EmuOpt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&\r
+ (Pico_mcd->scd.Status_CDC & 1) && loaded_mp3 && shared_ctl->mp3_offs < shared_ctl->mp3_len;\r
+\r
/* mix data from previous go */\r
- if (stereo) {\r
- int *mb = mix_buffer;\r
- for (i = length; i > 0; i--) {\r
- int l, r;\r
- l = r = *buffer;\r
- l += *mb++, r += *mb++;\r
- Limit( l, MAXOUT, MINOUT );\r
- Limit( r, MAXOUT, MINOUT );\r
- *buffer++ = l; *buffer++ = r;\r
+ if (cdda_on && mp3_samples_ready >= length)\r
+ {\r
+ if (1152 - mp3_buffer_offs >= length) {\r
+ mix_samples(buffer, ym_buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length, stereo);\r
+\r
+ mp3_buffer_offs += length;\r
+ } else {\r
+ // collect from both buffers..\r
+ int left = 1152 - mp3_buffer_offs;\r
+ mix_samples(buffer, ym_buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, left, stereo);\r
+ mp3_play_bufsel ^= 1;\r
+ mp3_buffer_offs = length - left;\r
+ mix_samples(buffer + left * 2, ym_buffer + left * 2,\r
+ shared_data->mp3_buffer[mp3_play_bufsel], mp3_buffer_offs, stereo);\r
}\r
+ mp3_samples_ready -= length;\r
} else {\r
- for (i = 0; i < length; i++) {\r
- int l = mix_buffer[i];\r
- l += buffer[i];\r
- Limit( l, MAXOUT, MINOUT );\r
- buffer[i] = l;\r
- }\r
+ mix_samples(buffer, ym_buffer, 0, length, stereo);\r
}\r
\r
//printf("new writes: %i\n", writebuff_ptr);\r
}\r
writebuff_ptr = 0;\r
\r
- /* give 940 another job */\r
+ /* give 940 ym job */\r
shared_ctl->writebuffsel ^= 1;\r
shared_ctl->length = length;\r
shared_ctl->stereo = stereo;\r
- add_job_940(JOB940_YM2612UPDATEONE, 0);\r
+\r
+ // make sure we will have enough mp3 samples next frame\r
+ if (cdda_on && mp3_samples_ready < length)\r
+ {\r
+ shared_ctl->mp3_buffsel ^= 1;\r
+ mp3_job = JOB940_MP3DECODE;\r
+ mp3_samples_ready += 1152;\r
+ }\r
+\r
+ add_job_940(JOB940_YM2612UPDATEONE, mp3_job);\r
//spend_cycles(512);\r
//printf("SRCPND: %08lx, INTMODE: %08lx, INTMASK: %08lx, INTPEND: %08lx\n",\r
// gp2x_memregl[0x4500>>2], gp2x_memregl[0x4504>>2], gp2x_memregl[0x4508>>2], gp2x_memregl[0x4510>>2]);\r
}\r
+\r
+\r
+/***********************************************************/\r
+\r
+void mp3_start_play(FILE *f, int pos) // pos is 0-1023\r
+{\r
+ int byte_offs = 0;\r
+\r
+ if (!(currentConfig.EmuOpt&0x800)) { // cdda disabled?\r
+ return;\r
+ }\r
+\r
+ if (loaded_mp3 != f)\r
+ {\r
+ printf("loading mp3... "); fflush(stdout);\r
+ fseek(f, 0, SEEK_SET);\r
+ fread(mp3_mem, 1, MP3_SIZE_MAX, f);\r
+ if (feof(f)) printf("done.\n");\r
+ else printf("done. mp3 too large, not all data loaded.\n");\r
+ shared_ctl->mp3_len = ftell(f);\r
+ loaded_mp3 = f;\r
+ }\r
+\r
+ // seek..\r
+ if (pos) {\r
+ byte_offs = (shared_ctl->mp3_len << 6) >> 10;\r
+ byte_offs *= pos;\r
+ byte_offs >>= 6;\r
+ }\r
+ printf("mp3 pos1024: %i, byte_offs %i/%i\n", pos, byte_offs, shared_ctl->mp3_len);\r
+\r
+ shared_ctl->mp3_offs = byte_offs;\r
+}\r
+\r
+\r
../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o\r
# unzip\r
OBJS += ../../unzip/unzip.o\r
+# mp3\r
+OBJS += mp3.o\r
# CPU cores\r
ifeq "$(use_musashi)" "1"\r
DEFINC += -DEMU_M68K\r
OBJS += ../../cpu/DrZ80/drz80.o\r
endif\r
\r
+\r
all: PicoDrive.gpe\r
\r
-PicoDrive.gpe : $(OBJS)\r
+PicoDrive.gpe : $(OBJS) helix/helix_mp3.a\r
@echo $@\r
- @$(GCC) $(COPT) $(OBJS) $(PRELIBS) -lm -o $@\r
+ @$(GCC) -o $@ $(COPT) $^ -lm\r
@$(STRIP) $@\r
-# @$(GCC) $(COPT) $(OBJS) $(PRELIBS) -lm -o PicoDrive_.gpe\r
+# @$(GCC) $(COPT) $(OBJS) -lm -o PicoDrive_.gpe\r
# @gpecomp PicoDrive_.gpe $@\r
ifeq "$(up)" "1"\r
@cmd //C copy $@ \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
\r
testrefr.gpe : test.o gp2x.o asmutils.o\r
@echo $@\r
- @$(GCC) $(COPT) $^ $(PRELIBS) -o $@\r
+ @$(GCC) $(COPT) $^ -o $@\r
@$(STRIP) $@\r
\r
.c.o:\r
@echo building Cyclone...\r
@make -C ../../cpu/Cyclone/proj -f Makefile.linux\r
\r
+# build helix libs\r
+helix/helix_mp3.a:\r
+ make -C helix\r
+\r
\r
# cleanup\r
clean: tidy\r
find ../.. -name '*.gcno' -delete\r
find ../.. -name '*.gcda' -delete\r
\r
+# ----------- release -----------\r
+ifneq ($(findstring rel,$(MAKECMDGOALS)),)\r
+ifeq ($(VER),)\r
+$(error need VER)\r
+endif\r
+endif\r
+\r
+rel: PicoDrive.gpe code940/code940.bin ../readme.txt config.txt\r
+ zip -9 -j ../../PicoDrive_$(VER).zip $^ mmuhack.o\r
+\r
+code940/code940.bin:\r
+ make -C code940/\r
+\r
+\r
# test\r
usbjoy.o : usbjoy.c\r
@echo $<\r
}\r
\r
/* it seems we have a CD image here. Try to detect region and load a suitable BIOS now.. */\r
- fseek(cd_f, (type == 1) ? 0x100 : 0x110, SEEK_SET);\r
+ fseek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);\r
fread(buf, 1, 1, cd_f);\r
fclose(cd_f);\r
\r
- if (buf[0] == 0x64) region = 4; // EU\r
+ if (buf[0] == 0x64) region = 8; // EU\r
if (buf[0] == 0xa1) region = 1; // JAP\r
\r
printf("detected %s Sega/Mega CD image with %s region\n",\r
// set default config\r
memset(¤tConfig, 0, sizeof(currentConfig));\r
currentConfig.lastRomFile[0] = 0;\r
- currentConfig.EmuOpt = 0x1f;\r
- currentConfig.PicoOpt = 0x0f;\r
- currentConfig.PsndRate = 22050;\r
+ currentConfig.EmuOpt = 0x1f | 0xc00; // | cd_leds | cd_cdda\r
+ currentConfig.PicoOpt = 0x0f | 0x200; // | use_940\r
+ currentConfig.PsndRate = 44100;\r
currentConfig.PicoRegion = 0; // auto\r
currentConfig.Frameskip = -1; // auto\r
currentConfig.CPUclock = 200;\r
if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
switch (menu_sel) {\r
case 3: tmp_opts.EmuOpt ^=0x400; break;\r
- case 4: return;\r
+ case 4: tmp_opts.EmuOpt ^=0x800; break;\r
+ case 5: return;\r
}\r
}\r
if(inp & (GP2X_X|GP2X_A)) return;\r
#include "../gp2x/gp2x.h"
#include "../gp2x/emu.h"
#include "../gp2x/menu.h"
+#include "../gp2x/code940/940shared.h"
+#include "../gp2x/helix/pub/mp3dec.h"
+#include "../../Pico/PicoInt.h"
static YM2612 ym2612;
int mix_buffer_[44100/50*2]; /* this is where the YM2612 samples will be mixed to */
int *mix_buffer = mix_buffer_;
+static _940_data_t shared_data_;
+static _940_ctl_t shared_ctl_;
+static _940_data_t *shared_data = &shared_data_;
+static _940_ctl_t *shared_ctl = &shared_ctl_;
+
+unsigned char *mp3_mem = 0;
+
+#define MP3_SIZE_MAX (0x1000000 - 4*640*480)
/***********************************************************/
void YM2612Init_940(int baseclock, int rate)
{
+ mp3_mem = malloc(MP3_SIZE_MAX);
+
YM2612Init_(baseclock, rate);
}
}
+static void mix_samples(short *dest_buf, int *ym_buf, short *mp3_buf, int len, int stereo)
+{
+ if (mp3_buf)
+ {
+ if (stereo)
+ {
+ for (; len > 0; len--)
+ {
+ int l, r;
+ l = r = *dest_buf;
+ l += *ym_buf++; r += *ym_buf++;
+ l += *mp3_buf++; r += *mp3_buf++;
+ Limit( l, MAXOUT, MINOUT );
+ Limit( r, MAXOUT, MINOUT );
+ *dest_buf++ = l; *dest_buf++ = r;
+ }
+ } else {
+ for (; len > 0; len--)
+ {
+ int l = *ym_buf++;
+ l += *dest_buf;
+ l += *mp3_buf++;
+ Limit( l, MAXOUT, MINOUT );
+ *dest_buf++ = l;
+ }
+ }
+ }
+ else
+ {
+ if (stereo)
+ {
+ for (; len > 0; len--)
+ {
+ int l, r;
+ l = r = *dest_buf;
+ l += *ym_buf++, r += *ym_buf++;
+ Limit( l, MAXOUT, MINOUT );
+ Limit( r, MAXOUT, MINOUT );
+ *dest_buf++ = l; *dest_buf++ = r;
+ }
+ } else {
+ for (; len > 0; len--)
+ {
+ int l = *ym_buf++;
+ l += *dest_buf;
+ Limit( l, MAXOUT, MINOUT );
+ *dest_buf++ = l;
+ }
+ }
+ }
+}
+
+#if 0
+static void local_decode(void)
+{
+ int mp3_offs = shared_ctl->mp3_offs;
+ unsigned char *readPtr = mp3_mem + mp3_offs;
+ int bytesLeft = shared_ctl->mp3_len - mp3_offs;
+ int offset; // frame offset from readPtr
+ int err = 0;
+
+ if (bytesLeft <= 0) return; // EOF, nothing to do
+
+ offset = MP3FindSyncWord(readPtr, bytesLeft);
+ if (offset < 0) {
+ shared_ctl->mp3_offs = shared_ctl->mp3_len;
+ return; // EOF
+ }
+ readPtr += offset;
+ bytesLeft -= offset;
+
+ err = MP3Decode(shared_data->mp3dec, &readPtr, &bytesLeft,
+ shared_data->mp3_buffer[shared_ctl->mp3_buffsel], 0);
+ if (err) {
+ if (err == ERR_MP3_INDATA_UNDERFLOW) {
+ shared_ctl->mp3_offs = shared_ctl->mp3_len; // EOF
+ return;
+ } else if (err <= -6 && err >= -12) {
+ // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*
+ // just try to skip the offending frame..
+ readPtr++;
+ }
+ shared_ctl->mp3_errors++;
+ shared_ctl->mp3_lasterr = err;
+ }
+ shared_ctl->mp3_offs = readPtr - mp3_mem;
+}
+#endif
+
+
+
+
+static FILE *loaded_mp3 = 0;
+
void YM2612UpdateOne_940(short *buffer, int length, int stereo)
{
- int i;
+#if 0
+ int cdda_on, *ym_buffer = mix_buffer;
+ static int mp3_samples_ready = 0, mp3_buffer_offs = 0;
+ static int mp3_play_bufsel = 1;
+
+
+ YM2612UpdateOne_(buffer, length, stereo); // really writes to mix_buffer
- YM2612UpdateOne_(buffer, length, stereo);
-
- /* mix data */
- if (stereo) {
- int *mb = mix_buffer;
- for (i = length; i > 0; i--) {
- int l, r;
- l = r = *buffer;
- l += *mb++, r += *mb++;
- Limit( l, MAXOUT, MINOUT );
- Limit( r, MAXOUT, MINOUT );
- *buffer++ = l; *buffer++ = r;
+ // emulatind MCD, not data track, CDC is reading, playback was started, track not ended
+ cdda_on = (PicoMCD & 1) && !(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1)
+ && loaded_mp3 && shared_ctl->mp3_offs < shared_ctl->mp3_len;
+
+ /* mix data from previous go */
+ if (cdda_on && mp3_samples_ready >= length)
+ {
+ if (1152 - mp3_buffer_offs >= length) {
+ mix_samples(buffer, ym_buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length, stereo);
+
+ mp3_buffer_offs += length;
+ } else {
+ // collect from both buffers..
+ int left = 1152 - mp3_buffer_offs;
+ mix_samples(buffer, ym_buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, left, stereo);
+ mp3_play_bufsel ^= 1;
+ mp3_buffer_offs = length - left;
+ mix_samples(buffer + left * 2, ym_buffer + left * 2,
+ shared_data->mp3_buffer[mp3_play_bufsel], mp3_buffer_offs, stereo);
}
+ mp3_samples_ready -= length;
} else {
- for (i = 0; i < length; i++) {
- int l = mix_buffer[i];
- l += buffer[i];
- Limit( l, MAXOUT, MINOUT );
- buffer[i] = l;
- }
+ mix_samples(buffer, ym_buffer, 0, length, stereo);
+ }
+
+ // make sure we will have enough mp3 samples next frame
+ if (cdda_on && mp3_samples_ready < length)
+ {
+ shared_ctl->mp3_buffsel ^= 1;
+ local_decode();
+ mp3_samples_ready += 1152;
+ }
+#else
+ YM2612UpdateOne_(buffer, length, stereo); // really writes to mix_buffer
+
+ mix_samples(buffer, mix_buffer, 0, length, stereo);
+#endif
+}
+
+
+/***********************************************************/
+
+void mp3_start_play(FILE *f, int pos) // pos is 0-1023
+{
+ int byte_offs = 0;
+
+ if (loaded_mp3 != f)
+ {
+ printf("loading mp3... "); fflush(stdout);
+ fseek(f, 0, SEEK_SET);
+ fread(mp3_mem, 1, MP3_SIZE_MAX, f);
+ if (feof(f)) printf("done.\n");
+ else printf("done. mp3 too large, not all data loaded.\n");
+ shared_ctl->mp3_len = ftell(f);
+ loaded_mp3 = f;
}
+
+ // seek..
+ if (pos) {
+ byte_offs = (shared_ctl->mp3_len << 6) >> 10;
+ byte_offs *= pos;
+ byte_offs >>= 6;
+ }
+ printf("mp3 pos1024: %i, byte_offs %i/%i\n", pos, byte_offs, shared_ctl->mp3_len);
+
+ shared_ctl->mp3_offs = byte_offs;
}
+
+
../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o
# unzip
OBJS += ../../unzip/unzip.o
+# mp3
+OBJS += ../gp2x/mp3.o
# CPU cores
DEFINC += -DEMU_M68K
OBJS += ../../cpu/musashi/m68kcpu.o ../../cpu/musashi/m68kopac.o ../../cpu/musashi/m68kopdm.o \
PicoDrive : $(OBJS)
@echo $@
- @$(GCC) $(COPT) $(OBJS) $(LDFLAGS) -lm -o $@
+ @$(GCC) $(COPT) $(OBJS) ../gp2x/helix/helix_mp3_x86.a $(LDFLAGS) -lm -o $@
../../cpu/mz80/mz80.o : ../../cpu/mz80/mz80.asm
write(sounddev, buff, len);
}
+void gp2x_sound_sync(void)
+{
+ ioctl(sounddev, SOUND_PCM_SYNC, 0);
+}
+
void gp2x_sound_volume(int l, int r)
{
l=l<0?0:l; l=l>255?255:l; r=r<0?0:r; r=r>255?255:r;