// to be called once on emu exit\r
void PicoExit(void)\r
{\r
- PicoExitMCD();\r
+ if (PicoMCD&1)\r
+ PicoExitMCD();\r
z80_exit();\r
\r
// notaz: sram\r
if (emustatus&1) emustatus|=2; else emustatus&=~2;\r
if (PicoWriteSound) PicoWriteSound();\r
// clear sound buffer\r
- memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));\r
+ sound_clear();\r
+ //memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));\r
}\r
else if(emustatus & 3) {\r
emustatus|= 2;\r
int mp3_get_bitrate(FILE *f, int size);\r
void mp3_start_play(FILE *f, int pos);\r
int mp3_get_offset(void); // 0-1023\r
+void mp3_update(int *buffer, int length, int stereo);\r
\r
\r
// Pico.c\r
// PicoOpt bits LSb->MSb:\r
// enable_ym2612&dac, enable_sn76496, enable_z80, stereo_sound,\r
// alt_renderer, 6button_gamepad, accurate_timing, accurate_sprites,\r
-// draw_no_32col_border, external_ym2612\r
+// draw_no_32col_border, external_ym2612, enable_pcm, enable cdda\r
extern int PicoOpt;\r
extern int PicoVer;\r
extern int PicoSkipFrame; // skip rendering frame, but still do sound (if enabled) and emulation stuff\r
#include "cd/LC89510.h"\r
#include "cd/gfx_cd.h"\r
\r
+struct mcd_pcm\r
+{\r
+ unsigned char control; // reg7\r
+ unsigned char enabled; // reg8\r
+ unsigned char cur_ch;\r
+ unsigned char bank;\r
+ int pad1;\r
+\r
+ struct pcm_chan\r
+ {\r
+ unsigned char regs[8];\r
+ unsigned int addr; // played sample address\r
+ int pad;\r
+ } ch[8];\r
+};\r
+\r
struct mcd_misc\r
{\r
unsigned short hint_vector;\r
unsigned short audio_offset; // for savestates: play pointer offset (0-1023)\r
unsigned char audio_track; // playing audio track # (zero based)\r
char pad1;\r
- int pad[12];\r
+ int timer_int3;\r
+ unsigned int timer_stopwatch;\r
+ int pad[10];\r
};\r
\r
typedef struct\r
unsigned char prg_ram_b[4][0x20000];\r
};\r
unsigned char word_ram[0x40000]; // 256K\r
+ union {\r
+ unsigned char pcm_ram[0x10000]; // 64K\r
+ unsigned char pcm_ram_b[0x10][0x1000];\r
+ };\r
unsigned char bram[0x2000]; // 8K\r
- unsigned char s68k_regs[0x200];\r
+ unsigned char s68k_regs[0x200]; // GA, not CPU regs\r
+ struct mcd_pcm pcm;\r
_scd_toc TOC; // not to be saved\r
CDD cdd;\r
CDC cdc;\r
// This is part of Pico Library
-// (c) Copyright 2006 notaz, All rights reserved.
+// (c) Copyright 2007 notaz, All rights reserved.
// Free for non-commercial use.
// For commercial use, separate licencing terms must be obtained.
CHUNK_S68K,
CHUNK_PRG_RAM,
CHUNK_WORD_RAM,
- CHUNK_BRAM, // 15
+ CHUNK_PCM_RAM, // 15
+ CHUNK_BRAM,
CHUNK_GA_REGS,
+ CHUNK_PCM,
CHUNK_CDC,
- CHUNK_CDD,
+ CHUNK_CDD, // 20
CHUNK_SCD,
- CHUNK_RC, // 20
+ CHUNK_RC,
CHUNK_MISC_CD,
} chunk_name_e;
CHECKED_WRITE_BUFF(CHUNK_S68K, buff);
CHECKED_WRITE_BUFF(CHUNK_PRG_RAM, Pico_mcd->prg_ram);
CHECKED_WRITE_BUFF(CHUNK_WORD_RAM, Pico_mcd->word_ram); // in 2M format
+ CHECKED_WRITE_BUFF(CHUNK_PCM_RAM, Pico_mcd->pcm_ram);
CHECKED_WRITE_BUFF(CHUNK_BRAM, Pico_mcd->bram);
- CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs);
+ CHECKED_WRITE_BUFF(CHUNK_GA_REGS, Pico_mcd->s68k_regs); // GA regs, not CPU regs
+ CHECKED_WRITE_BUFF(CHUNK_PCM, Pico_mcd->pcm);
CHECKED_WRITE_BUFF(CHUNK_CDD, Pico_mcd->cdd);
CHECKED_WRITE_BUFF(CHUNK_CDC, Pico_mcd->cdc);
CHECKED_WRITE_BUFF(CHUNK_SCD, Pico_mcd->scd);
CHECKED_READ(1, buff);
CHECKED_READ(4, &len);
if (len < 0 || len > 1024*512) R_ERROR_RETURN("bad length");
+ if (buff[0] > CHUNK_FM && !(PicoMCD & 1)) R_ERROR_RETURN("cd chunk in non CD state?");
switch (buff[0])
{
case CHUNK_PRG_RAM: CHECKED_READ_BUFF(Pico_mcd->prg_ram); break;
case CHUNK_WORD_RAM: CHECKED_READ_BUFF(Pico_mcd->word_ram); break;
+ case CHUNK_PCM_RAM: CHECKED_READ_BUFF(Pico_mcd->pcm_ram); break;
case CHUNK_BRAM: CHECKED_READ_BUFF(Pico_mcd->bram); break;
case CHUNK_GA_REGS: CHECKED_READ_BUFF(Pico_mcd->s68k_regs); break;
+ case CHUNK_PCM: CHECKED_READ_BUFF(Pico_mcd->pcm); break;
case CHUNK_CDD: CHECKED_READ_BUFF(Pico_mcd->cdd); break;
case CHUNK_CDC: CHECKED_READ_BUFF(Pico_mcd->cdc); break;
case CHUNK_SCD: CHECKED_READ_BUFF(Pico_mcd->scd); break;
#include "../sound/sn76496.h"\r
\r
#include "gfx_cd.h"\r
+#include "pcm.h"\r
\r
typedef unsigned char u8;\r
typedef unsigned short u16;\r
goto end;\r
case 0xC:\r
dprintf("s68k stopwatch timer read");\r
- break;\r
+ d = Pico_mcd->m.timer_stopwatch >> 16;\r
+ goto end;\r
case 0x30:\r
dprintf("s68k int3 timer read");\r
break;\r
dprintf("s68k set CDC dma addr");\r
break;\r
case 0xc:\r
+ case 0xd:\r
dprintf("s68k set stopwatch timer");\r
- break;\r
+ Pico_mcd->m.timer_stopwatch = 0;\r
+ return;\r
case 0x31:\r
- dprintf("s68k set int3 timer");\r
+ dprintf("s68k set int3 timer: %02x", d);\r
+ Pico_mcd->m.timer_int3 = d << 16;\r
break;\r
case 0x33: // IRQ mask\r
dprintf("s68k irq mask: %02x", d);\r
goto end;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ dprintf("s68k_pcm r8: [%06x] @%06x", a, SekPc);\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000)\r
+ d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff];\r
+ else if (a >= 0x20) {\r
+ a &= 0x1e;\r
+ d = Pico_mcd->pcm.ch[a>>2].addr >> PCM_STEP_SHIFT;\r
+ if (a & 2) d >>= 8;\r
+ }\r
+ dprintf("ret = %02x", (u8)d);\r
+ goto end;\r
+ }\r
+\r
// bram\r
if ((a&0xff0000)==0xfe0000) {\r
d = Pico_mcd->bram[(a>>1)&0x1fff];\r
\r
u16 PicoReadS68k16(u32 a)\r
{\r
- u16 d=0;\r
+ u32 d=0;\r
\r
a&=0xfffffe;\r
\r
if ((a&0xff0000)==0xfe0000) {\r
dprintf("s68k_bram r16: [%06x] @%06x", a, SekPc);\r
a = (a>>1)&0x1fff;\r
- d = Pico_mcd->bram[a++]; // Gens does little endian here, an so do we..\r
+ d = Pico_mcd->bram[a++]; // Gens does little endian here, and so do we..\r
d|= Pico_mcd->bram[a++] << 8;\r
dprintf("ret = %04x", d);\r
goto end;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ dprintf("s68k_pcm r16: [%06x] @%06x", a, SekPc);\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000)\r
+ d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff];\r
+ else if (a >= 0x20) {\r
+ a &= 0x1e;\r
+ d = Pico_mcd->pcm.ch[a>>2].addr >> PCM_STEP_SHIFT;\r
+ if (a & 2) d >>= 8;\r
+ }\r
+ dprintf("ret = %04x", d);\r
+ goto end;\r
+ }\r
+\r
dprintf("s68k r16: %06x, %04x @%06x", a&0xffffff, d, SekPcS68k);\r
\r
end:\r
goto end;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ dprintf("s68k_pcm r32: [%06x] @%06x", a, SekPc);\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000) {\r
+ a >>= 1;\r
+ d = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][a&0xfff] << 16;\r
+ d |= Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a+1)&0xfff];\r
+ } else if (a >= 0x20) {\r
+ a &= 0x1e;\r
+ if (a & 2) {\r
+ a >>= 2;\r
+ d = (Pico_mcd->pcm.ch[a].addr >> (PCM_STEP_SHIFT-8)) & 0xff0000;\r
+ d |= (Pico_mcd->pcm.ch[(a+1)&7].addr >> PCM_STEP_SHIFT) & 0xff;\r
+ } else {\r
+ d = Pico_mcd->pcm.ch[a>>2].addr >> PCM_STEP_SHIFT;\r
+ d = ((d<<16)&0xff0000) | ((d>>8)&0xff); // PCM chip is LE\r
+ }\r
+ }\r
+ dprintf("ret = %08x", d);\r
+ goto end;\r
+ }\r
+\r
// bram\r
if ((a&0xff0000)==0xfe0000) {\r
dprintf("s68k_bram r32: [%06x] @%06x", a, SekPc);\r
return;\r
}\r
\r
- if (a != 0xff0011 && (a&0xff8000) == 0xff0000) // PCM hack\r
- return;\r
-\r
// regs\r
if ((a&0xfffe00) == 0xff8000) {\r
a &= 0x1ff;\r
return;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000)\r
+ Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;\r
+ else if (a < 0x12)\r
+ pcm_write(a>>1, d);\r
+ return;\r
+ }\r
+\r
// bram\r
if ((a&0xff0000)==0xfe0000) {\r
Pico_mcd->bram[(a>>1)&0x1fff] = d;\r
return;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000)\r
+ Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a>>1)&0xfff] = d;\r
+ else if (a < 0x12)\r
+ pcm_write(a>>1, d & 0xff);\r
+ return;\r
+ }\r
+\r
// bram\r
if ((a&0xff0000)==0xfe0000) {\r
dprintf("s68k_bram w16: [%06x] %04x @%06x", a, d, SekPc);\r
return;\r
}\r
\r
+ // PCM\r
+ if ((a&0xff8000)==0xff0000) {\r
+ a &= 0x7fff;\r
+ if (a >= 0x2000) {\r
+ a >>= 1;\r
+ Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][a&0xfff] = (d >> 16);\r
+ Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank][(a+1)&0xfff] = d;\r
+ } else if (a < 0x12) {\r
+ a >>= 1;\r
+ pcm_write(a, (d>>16) & 0xff);\r
+ pcm_write(a+1, d & 0xff);\r
+ }\r
+ return;\r
+ }\r
+\r
// bram\r
if ((a&0xff0000)==0xfe0000) {\r
dprintf("s68k_bram w32: [%06x] %08x @%06x", a, d, SekPc);\r
{
memset(Pico_mcd->prg_ram, 0, sizeof(Pico_mcd->prg_ram));
memset(Pico_mcd->word_ram, 0, sizeof(Pico_mcd->word_ram));
+ memset(Pico_mcd->pcm_ram, 0, sizeof(Pico_mcd->pcm_ram));
if (hard) {
memset(Pico_mcd->bram, 0, sizeof(Pico_mcd->bram));
memcpy(Pico_mcd->bram + sizeof(Pico_mcd->bram) - 8*0x10, formatted_bram, 8*0x10);
}
memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
+ memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
*(unsigned int *)(Pico_mcd->bios + 0x70) = 0xffffffff; // reset hint vector (simplest way to implement reg6)
Pico_mcd->m.state_flags |= 2; // s68k reset pending
Update_CDC_TRansfer(ddx); // now go and do the actual transfer
}
+static __inline void update_chips(void)
+{
+ int counter_timer, int3_set;
+ int counter75hz_lim = Pico.m.pal ? 2080 : 2096;
+
+ // 75Hz CDC update
+ if ((Pico_mcd->m.counter75hz+=10) >= counter75hz_lim) {
+ Pico_mcd->m.counter75hz -= counter75hz_lim;
+ Check_CD_Command();
+ }
+
+ // update timers
+ counter_timer = Pico.m.pal ? 0x21630 : 0x2121c; // 136752 : 135708;
+ Pico_mcd->m.timer_stopwatch += counter_timer;
+ if ((int3_set = Pico_mcd->s68k_regs[0x31])) {
+ Pico_mcd->m.timer_int3 -= counter_timer;
+ if (Pico_mcd->m.timer_int3 < 0) {
+ if (Pico_mcd->s68k_regs[0x33] & (1<<3)) {
+ dprintf("s68k: timer irq 3");
+ SekInterruptS68k(3);
+ Pico_mcd->m.timer_int3 += int3_set << 16;
+ }
+ // is this really what happens if irq3 is masked out?
+ Pico_mcd->m.timer_int3 &= 0xffffff;
+ }
+ }
+
+ // update gfx chip
+ if (Pico_mcd->rot_comp.Reg_58 & 0x8000)
+ gfx_cd_update();
+}
+
// to be called on 224 or line_sample scanlines only
static __inline void getSamples(int y)
{
if (emustatus&1) emustatus|=2; else emustatus&=~2;
if (PicoWriteSound) PicoWriteSound();
// clear sound buffer
- memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));
+ sound_clear();
+ //memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));
}
else if(emustatus & 3) {
emustatus|= 2;
}
-
-// Accurate but slower frame which does hints
static int PicoFrameHintsMCD(void)
{
struct PicoVideo *pv=&Pico.video;
- int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample,counter75hz_lim;
+ int total_z80=0,lines,y,lines_vis = 224,z80CycleAim = 0,line_sample;
const int cycles_68k=488,cycles_z80=228,cycles_s68k=795; // both PAL and NTSC compile to same values
int skip=PicoSkipFrame || (PicoOpt&0x10);
int hint; // Hint counter
//cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228
lines = 312; // Steve Snake says there are 313 lines, but this seems to also work well
line_sample = 68;
- counter75hz_lim = 2080;
if(pv->reg[1]&8) lines_vis = 240;
} else {
//cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488
//cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
lines = 262;
- counter75hz_lim = 2096;
line_sample = 93;
}
total_z80+=z80_run(z80CycleAim-total_z80);
}
- if ((Pico_mcd->m.counter75hz+=10) >= counter75hz_lim) {
- Pico_mcd->m.counter75hz -= counter75hz_lim;
- Check_CD_Command();
- }
-
- if (Pico_mcd->rot_comp.Reg_58 & 0x8000)
- gfx_cd_update();
+ update_chips();
}
// draw a frame just after vblank in alternative render mode
--- /dev/null
+#define MAXOUT (+32767)
+#define MINOUT (-32768)
+
+/* limitter */
+#define Limit(val, max,min) { \
+ if ( val > max ) val = max; \
+ else if ( val < min ) val = min; \
+}
+
+
+
+
+void memcpy32(int *dest, int *src, int count)
+{
+ while (count--)
+ *dest++ = *src++;
+}
+
+
+void memset32(int *dest, int c, int count)
+{
+ while (count--)
+ *dest++ = c;
+}
+
+
+void mix_32_to_16l_stereo(short *dest, int *src, int count)
+{
+ int l, r;
+
+ for (; count > 0; count--)
+ {
+ l = r = *dest;
+ l += *src++;
+ r += *src++;
+ Limit( l, MAXOUT, MINOUT );
+ Limit( r, MAXOUT, MINOUT );
+ *dest++ = l;
+ *dest++ = r;
+ }
+}
+
+
+void mix_32_to_16_mono(short *dest, int *src, int count)
+{
+ int l;
+
+ for (; count > 0; count--)
+ {
+ l = *dest;
+ l += *src++;
+ Limit( l, MAXOUT, MINOUT );
+ *dest++ = l;
+ }
+}
+
+
--- /dev/null
+
+void memcpy32(int *dest, int *src, int count);
+void memset32(int *dest, int c, int count);
+//void mix_32_to_32(int *dest, int *src, int count);
+void mix_16h_to_32(int *dest, short *src, int count);
+void mix_16h_to_32_s1(int *dest, short *src, int count);
+void mix_16h_to_32_s2(int *dest, short *src, int count);
+void mix_32_to_16l_stereo(short *dest, int *src, int count);
+void mix_32_to_16_mono(short *dest, int *src, int count);
+
--- /dev/null
+@ vim:filetype=armasm
+
+.global memcpy32 @ int *dest, int *src, int count
+
+memcpy32:
+ stmfd sp!, {r4,lr}
+
+ subs r2, r2, #4
+ bmi mcp32_fin
+
+mcp32_loop:
+ ldmia r1!, {r3,r4,r12,lr}
+ subs r2, r2, #4
+ stmia r0!, {r3,r4,r12,lr}
+ bpl mcp32_loop
+
+mcp32_fin:
+ tst r2, #3
+ ldmeqfd sp!, {r4,pc}
+ tst r2, #1
+ ldrne r3, [r1], #4
+ strne r3, [r0], #4
+
+mcp32_no_unal1:
+ tst r2, #2
+ ldmneia r1!, {r3,r12}
+ ldmfd sp!, {r4,lr}
+ stmneia r0!, {r3,r12}
+ bx lr
+
+
+
+.global memset32 @ int *dest, int c, int count
+
+memset32:
+ stmfd sp!, {lr}
+
+ mov r3, r1
+ subs r2, r2, #4
+ bmi mst32_fin
+
+ mov r12,r1
+ mov lr, r1
+
+mst32_loop:
+ subs r2, r2, #4
+ stmia r0!, {r1,r3,r12,lr}
+ bpl mst32_loop
+
+mst32_fin:
+ tst r2, #1
+ strne r1, [r0], #4
+
+ tst r2, #2
+ stmneia r0!, {r1,r3}
+
+ ldmfd sp!, {lr}
+ bx lr
+
+
+
+@ this assumes src is word aligned
+.global mix_16h_to_32 @ int *dest, short *src, int count
+
+mix_16h_to_32:
+ stmfd sp!, {r4-r6,lr}
+/*
+ tst r1, #2
+ beq m16_32_mo_unalw
+ ldrsh r4, [r1], #2
+ ldr r3, [r0]
+ sub r2, r2, #1
+ add r3, r3, r4, asr #1
+ str r3, [r0], #4
+*/
+m16_32_mo_unalw:
+ subs r2, r2, #4
+ bmi m16_32_end
+
+m16_32_loop:
+ ldmia r0, {r3-r6}
+ ldmia r1!,{r12,lr}
+ subs r2, r2, #4
+ add r4, r4, r12,asr #17 @ we use half volume
+ mov r12,r12,lsl #16
+ add r3, r3, r12,asr #17
+ add r6, r6, lr, asr #17
+ mov lr, lr, lsl #16
+ add r5, r5, lr, asr #17
+ stmia r0!,{r3-r6}
+ bpl m16_32_loop
+
+m16_32_end:
+ tst r2, #2
+ beq m16_32_no_unal2
+ ldr r5, [r1], #4
+ ldmia r0, {r3,r4}
+ mov r12,r5, lsl #16
+ add r3, r3, r12,asr #17
+ add r4, r4, r5, asr #17
+ stmia r0!,{r3,r4}
+
+m16_32_no_unal2:
+ tst r2, #1
+ ldmeqfd sp!, {r4-r6,pc}
+ ldrsh r4, [r1], #2
+ ldr r3, [r0]
+ add r3, r3, r4, asr #1
+ str r3, [r0], #4
+
+ ldmfd sp!, {r4-r6,lr}
+ bx lr
+
+
+
+.global mix_16h_to_32_s1 @ int *dest, short *src, int count
+
+mix_16h_to_32_s1:
+ stmfd sp!, {r4-r6,lr}
+
+ subs r2, r2, #4
+ bmi m16_32_s1_end
+
+m16_32_s1_loop:
+ ldmia r0, {r3-r6}
+ ldr r12,[r1], #8
+ ldr lr, [r1], #8
+ subs r2, r2, #4
+ add r4, r4, r12,asr #17
+ mov r12,r12,lsl #16
+ add r3, r3, r12,asr #17 @ we use half volume
+ add r6, r6, lr, asr #17
+ mov lr, lr, lsl #16
+ add r5, r5, lr, asr #17
+ stmia r0!,{r3-r6}
+ bpl m16_32_s1_loop
+
+m16_32_s1_end:
+ tst r2, #2
+ beq m16_32_s1_no_unal2
+ ldr r5, [r1], #8
+ ldmia r0, {r3,r4}
+ mov r12,r5, lsl #16
+ add r3, r3, r12,asr #17
+ add r4, r4, r5, asr #17
+ stmia r0!,{r3,r4}
+
+m16_32_s1_no_unal2:
+ tst r2, #1
+ ldmeqfd sp!, {r4-r6,pc}
+ ldrsh r4, [r1], #2
+ ldr r3, [r0]
+ add r3, r3, r4, asr #1
+ str r3, [r0], #4
+
+ ldmfd sp!, {r4-r6,lr}
+ bx lr
+
+
+
+.global mix_16h_to_32_s2 @ int *dest, short *src, int count
+
+mix_16h_to_32_s2:
+ stmfd sp!, {r4-r6,lr}
+
+ subs r2, r2, #4
+ bmi m16_32_s2_end
+
+m16_32_s2_loop:
+ ldmia r0, {r3-r6}
+ ldr r12,[r1], #16
+ ldr lr, [r1], #16
+ subs r2, r2, #4
+ add r4, r4, r12,asr #17
+ mov r12,r12,lsl #16
+ add r3, r3, r12,asr #17 @ we use half volume
+ add r6, r6, lr, asr #17
+ mov lr, lr, lsl #16
+ add r5, r5, lr, asr #17
+ stmia r0!,{r3-r6}
+ bpl m16_32_s2_loop
+
+m16_32_s2_end:
+ tst r2, #2
+ beq m16_32_s2_no_unal2
+ ldr r5, [r1], #16
+ ldmia r0, {r3,r4}
+ mov r12,r5, lsl #16
+ add r3, r3, r12,asr #17
+ add r4, r4, r5, asr #17
+ stmia r0!,{r3,r4}
+
+m16_32_s2_no_unal2:
+ tst r2, #1
+ ldmeqfd sp!, {r4-r6,pc}
+ ldrsh r4, [r1], #2
+ ldr r3, [r0]
+ add r3, r3, r4, asr #1
+ str r3, [r0], #4
+
+ ldmfd sp!, {r4-r6,lr}
+ bx lr
+
+
+
+@ limit
+@ reg=int_sample, lr=1, r3=tmp, kills flags
+.macro Limit reg
+ add r3, lr, \reg, asr #16
+ bics r3, r3, #1 @ in non-overflow conditions r3 is 0 or 1
+ movne \reg, #0x8000
+ submi \reg, \reg, #1
+.endm
+
+
+@ limit and shift up by 16
+@ reg=int_sample, lr=1, r3=tmp, kills flags
+.macro Limitsh reg
+@ movs r4, r3, asr #16
+@ cmnne r4, #1
+@ beq c32_16_no_overflow
+@ tst r4, r4
+@ mov r3, #0x8000
+@ subpl r3, r3, #1
+
+ add r3, lr, \reg, asr #16
+ bics r3, r3, #1 @ in non-overflow conditions r3 is 0 or 1
+ moveq \reg, \reg, lsl #16
+ movne \reg, #0x80000000
+ submi \reg, \reg, #0x00010000
+.endm
+
+
+@ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio with left channel only
+@ warning: this function assumes dest is word aligned
+.global mix_32_to_16l_stereo @ short *dest, int *src, int count
+
+mix_32_to_16l_stereo:
+ stmfd sp!, {r4-r8,lr}
+
+ mov lr, #1
+
+ mov r2, r2, lsl #1
+ subs r2, r2, #4
+ bmi m32_16l_st_end
+
+m32_16l_st_loop:
+ ldmia r0, {r8,r12}
+ ldmia r1!, {r4-r7}
+ mov r8, r8, lsl #16
+ mov r12,r12,lsl #16
+ add r4, r4, r8, asr #16
+ add r5, r5, r8, asr #16
+ add r6, r6, r12,asr #16
+ add r7, r7, r12,asr #16
+ Limitsh r4
+ Limitsh r5
+ Limitsh r6
+ Limitsh r7
+ subs r2, r2, #4
+ orr r4, r5, r4, lsr #16
+ orr r5, r7, r6, lsr #16
+ stmia r0!, {r4,r5}
+ bpl m32_16l_st_loop
+
+m32_16l_st_end:
+ @ check for remaining bytes to convert
+ tst r2, #2
+ beq m32_16l_st_no_unal2
+ ldrsh r6, [r0]
+ ldmia r1!,{r4,r5}
+ add r4, r4, r6
+ add r5, r5, r6
+ Limitsh r4
+ Limitsh r5
+ orr r4, r5, r4, lsr #16
+ str r4, [r0], #4
+
+m32_16l_st_no_unal2:
+ ldmfd sp!, {r4-r8,lr}
+ bx lr
+
+
+@ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio (for mono sound)
+.global mix_32_to_16_mono @ short *dest, int *src, int count
+
+mix_32_to_16_mono:
+ stmfd sp!, {r4-r8,lr}
+
+ mov lr, #1
+
+ @ check if dest is word aligned
+ tst r0, #2
+ beq m32_16_mo_no_unalw
+ ldrsh r5, [r0], #2
+ ldr r4, [r1], #4
+ sub r2, r2, #1
+ add r4, r4, r5
+ Limit r4
+ strh r4, [r0], #2
+
+m32_16_mo_no_unalw:
+ subs r2, r2, #4
+ bmi m32_16_mo_end
+
+m32_16_mo_loop:
+ ldmia r0, {r8,r12}
+ ldmia r1!, {r4-r7}
+ add r5, r5, r8, asr #16
+ mov r8, r8, lsl #16
+ add r4, r4, r8, asr #16
+ add r7, r7, r12,asr #16
+ mov r12,r12,lsl #16
+ add r6, r6, r12,asr #16
+ Limitsh r4
+ Limitsh r5
+ Limitsh r6
+ Limitsh r7
+ subs r2, r2, #4
+ orr r4, r5, r4, lsr #16
+ orr r5, r7, r6, lsr #16
+ stmia r0!, {r4,r5}
+ bpl m32_16_mo_loop
+
+m32_16_mo_end:
+ @ check for remaining bytes to convert
+ tst r2, #2
+ beq m32_16_mo_no_unal2
+ ldr r6, [r0]
+ ldmia r1!,{r4,r5}
+ add r5, r5, r6, asr #16
+ mov r6, r6, lsl #16
+ add r4, r4, r6, asr #16
+ Limitsh r4
+ Limitsh r5
+ orr r4, r5, r4, lsr #16
+ str r4, [r0], #4
+
+m32_16_mo_no_unal2:
+ tst r2, #1
+ ldmeqfd sp!, {r4-r8,pc}
+ ldrsh r5, [r0], #2
+ ldr r4, [r1], #4
+ add r4, r4, r5
+ Limit r4
+ strh r4, [r0], #2
+
+ ldmfd sp!, {r4-r8,lr}
+ bx lr
+
*/\r
\r
//static\r
-void SN76496Update(short *buffer,int length,int stereo)\r
+void SN76496Update(short *buffer, int length, int stereo)\r
{\r
int i;\r
struct SN76496 *R = &ono_sn;\r
\r
if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;\r
\r
- out /= STEP; // will be optimized to shift\r
- if(stereo) {\r
- // only left channel for stereo (will be copied to right by ym2612 mixing code)\r
+ if ((out /= STEP)) // will be optimized to shift; max 0x47ff = 18431\r
*buffer += out;\r
- buffer+=2;\r
- } else\r
- *buffer++ += out;\r
+ if(stereo) buffer+=2; // only left for stereo, to be mixed to right later\r
+ else buffer++;\r
\r
length--;\r
}\r
#endif\r
\r
#include "../PicoInt.h"\r
+#include "../cd/pcm.h"\r
+#include "mix.h"\r
\r
+// master int buffer to mix to\r
+static int PsndBuffer[2*44100/50];\r
\r
//int z80CycleAim = 0;\r
\r
dac_cnt -= lines;\r
len++;\r
}\r
- if (i == mid) // midpoint\r
+ if (i == mid) // midpoint\r
while(pos+len < PsndLen/2) {\r
dac_cnt -= lines;\r
len++;\r
{\r
unsigned int state[28];\r
\r
+ // not all rates are supported in MCD mode due to mp3 decoder\r
+ if (PicoMCD & 1) {\r
+ if (PsndRate != 11025 && PsndRate != 22050 && PsndRate != 44100) PsndRate = 22050;\r
+ if (!(PicoOpt & 8)) PicoOpt |= 8;\r
+ }\r
+\r
+ if ((PicoMCD & 1) && Pico_mcd->m.audio_track) Pico_mcd->m.audio_offset = mp3_get_offset();\r
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PsndRate);\r
// feed it back it's own registers, just like after loading state\r
YM2612PicoStateLoad();\r
+ if ((PicoMCD & 1) && Pico_mcd->m.audio_track)\r
+ mp3_start_play(Pico_mcd->TOC.Tracks[Pico_mcd->m.audio_track].F, Pico_mcd->m.audio_offset);\r
\r
memcpy(state, sn76496_regs, 28*4); // remember old state\r
SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PsndRate);\r
\r
// recalculate dac info\r
dac_recalculate();\r
+\r
+ if (PicoMCD & 1)\r
+ pcm_set_rate(PsndRate);\r
}\r
\r
\r
// This is called once per raster (aka line), but not necessarily for every line\r
-int sound_timers_and_dac(int raster)\r
+void sound_timers_and_dac(int raster)\r
{\r
- if(raster >= 0 && PsndOut && (PicoOpt&1) && *ym2612_dacen) {\r
- short dout = (short) *ym2612_dacout;\r
- int pos=dac_info[raster], len=pos&0xf;\r
- short *d;\r
- pos>>=4;\r
-\r
- if(PicoOpt&8) { // only left channel for stereo (will be copied to right by ym2612 mixing code)\r
- d=PsndOut+pos*2;\r
- while(len--) { *d = dout; d += 2; }\r
+ int pos, len;\r
+ int do_dac = PsndOut && (PicoOpt&1) && *ym2612_dacen;\r
+// int do_pcm = PsndOut && (PicoMCD&1) && (PicoOpt&0x400);\r
+\r
+ // Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)\r
+ YM2612PicoTick(1);\r
+\r
+ if (!do_dac /*&& !do_pcm*/) return;\r
+\r
+ pos=dac_info[raster], len=pos&0xf;\r
+ if (!len) return;\r
+\r
+ pos>>=4;\r
+\r
+ if (do_dac) {\r
+ short *d = PsndOut + pos*2;\r
+ int dout = *ym2612_dacout;\r
+ if(PicoOpt&8) {\r
+ // some manual loop unrolling here :)\r
+ d[0] = dout;\r
+ if (len > 1) {\r
+ d[2] = dout;\r
+ if (len > 2) {\r
+ d[4] = dout;\r
+ if (len > 3)\r
+ d[6] = dout;\r
+ }\r
+ }\r
} else {\r
- d=PsndOut+pos;\r
- while(len--) *d++ = dout;\r
+ short *d = PsndOut + pos;\r
+ d[0] = dout;\r
+ if (len > 1) {\r
+ d[1] = dout;\r
+ if (len > 2) {\r
+ d[2] = dout;\r
+ if (len > 3)\r
+ d[3] = dout;\r
+ }\r
+ }\r
}\r
}\r
\r
- //dprintf("s: %03i", raster);\r
+#if 0\r
+ if (do_pcm) {\r
+ int *d = PsndBuffer;\r
+ d += (PicoOpt&8) ? pos*2 : pos;\r
+ pcm_update(d, len, 1);\r
+ }\r
+#endif\r
+}\r
\r
- // Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)\r
- YM2612PicoTick(1);\r
\r
- return 0;\r
+void sound_clear(void)\r
+{\r
+ if (PicoOpt & 8) memset32((int *) PsndOut, 0, PsndLen);\r
+ else memset(PsndOut, 0, PsndLen<<1);\r
+// memset(PsndBuffer, 0, (PicoOpt & 8) ? (PsndLen<<3) : (PsndLen<<2));\r
}\r
\r
\r
int sound_render(int offset, int length)\r
{\r
+ int *buf32 = PsndBuffer+offset;\r
int stereo = (PicoOpt & 8) >> 3;\r
+ // emulating CD && PCM option enabled && PCM chip on && have enabled channels\r
+ int do_pcm = (PicoMCD&1) && (PicoOpt&0x400) && (Pico_mcd->pcm.control & 0x80) && Pico_mcd->pcm.enabled;\r
offset <<= stereo;\r
\r
// PSG\r
- if(PicoOpt & 2)\r
+ if (PicoOpt & 2)\r
SN76496Update(PsndOut+offset, length, stereo);\r
\r
// Add in the stereo FM buffer\r
- if(PicoOpt & 1) {\r
- YM2612UpdateOne(PsndOut+offset, length, stereo);\r
- } else {\r
- // YM2612 upmixes to stereo, so we have to do this manually here\r
- int i;\r
- short *s = PsndOut+offset;\r
- for (i = 0; i < length; i++) {\r
- *(s+1) = *s; s+=2;\r
- }\r
- }\r
+ if (PicoOpt & 1)\r
+ YM2612UpdateOne(buf32, length, stereo, 1);\r
+\r
+ if (do_pcm)\r
+ pcm_update(buf32, length, stereo);\r
+\r
+ // CDDA audio\r
+// if ((PicoMCD & 1) && (PicoOpt & 0x800))\r
+// mp3_update(PsndBuffer+offset, length, stereo);\r
+\r
+ // convert + limit to normal 16bit output\r
+ if (stereo)\r
+ mix_32_to_16l_stereo(PsndOut+offset, buf32, length);\r
+ else mix_32_to_16_mono (PsndOut+offset, buf32, length);\r
\r
return 0;\r
}\r
mz80init();\r
// Modify the default context\r
mz80GetContext(&z80);\r
- \r
+\r
// point mz80 stuff\r
z80.z80Base=Pico.zram;\r
z80.z80MemRead=mz80_mem_read;\r
z80.z80MemWrite=mz80_mem_write;\r
z80.z80IoRead=mz80_io_read;\r
z80.z80IoWrite=mz80_io_write;\r
- \r
+\r
mz80SetContext(&z80);\r
\r
#elif defined(_USE_DRZ80)\r
extern "C" {\r
#endif\r
\r
-int sound_timers_and_dac(int raster);\r
-int sound_render(int offset, int length);\r
+void sound_timers_and_dac(int raster);\r
+int sound_render(int offset, int length);\r
+void sound_clear(void);\r
\r
//int YM2612PicoTick(int n);\r
\r
/*\r
-** This is a bunch of remains of original fm.c from MAME project. All stuff \r
+** This is a bunch of remains of original fm.c from MAME project. All stuff\r
** unrelated to ym2612 was removed, multiple chip support was removed,\r
** some parts of code were slightly rewritten and tied to the emulator.\r
**\r
#include <math.h>\r
\r
#include "ym2612.h"\r
+#include "mix.h"\r
\r
#ifndef EXTERNAL_YM2612\r
#include <stdlib.h>\r
\r
#else\r
extern YM2612 *ym2612_940;\r
-extern int *mix_buffer;\r
#define ym2612 (*ym2612_940)\r
\r
#endif\r
\r
\r
/* Generate samples for YM2612 */\r
-void YM2612UpdateOne_(short *buffer, int length, int stereo)\r
+int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)\r
{\r
int pan;\r
-#ifndef EXTERNAL_YM2612\r
- int i;\r
- static int *mix_buffer = 0, mix_buffer_length = 0;\r
-#endif\r
+\r
+ // if !is_buf_empty, it means it has valid samples to mix with, else it may contain trash\r
+ if (is_buf_empty) memset32(buffer, 0, length<<stereo);\r
\r
/* refresh PG and EG */\r
refresh_fc_eg_chan( &ym2612.CH[0] );\r
pan = ym2612.OPN.pan;\r
if (stereo) stereo = 1;\r
\r
-#ifndef EXTERNAL_YM2612\r
- if (mix_buffer_length < length) {\r
- mix_buffer = realloc(mix_buffer, length*4<<stereo); // FIXME: need to free this at some point\r
- if (!mix_buffer) return;\r
- mix_buffer_length = length;\r
- }\r
-#endif\r
- memset(mix_buffer, 0, length*4<<stereo);\r
+ /* mix to 32bit dest */\r
+ chan_render(buffer, length, &ym2612.CH[0], stereo|((pan&0x003)<<4)); // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
+ chan_render(buffer, length, &ym2612.CH[1], stereo|((pan&0x00c)<<2));\r
+ chan_render(buffer, length, &ym2612.CH[2], stereo|((pan&0x030) ));\r
+ chan_render(buffer, length, &ym2612.CH[3], stereo|((pan&0x0c0)>>2));\r
+ chan_render(buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4));\r
+ chan_render(buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2);\r
\r
- /* mix to 32bit temporary buffer */\r
- chan_render(mix_buffer, length, &ym2612.CH[0], stereo|((pan&0x003)<<4)); // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
- chan_render(mix_buffer, length, &ym2612.CH[1], stereo|((pan&0x00c)<<2));\r
- chan_render(mix_buffer, length, &ym2612.CH[2], stereo|((pan&0x030) ));\r
- chan_render(mix_buffer, length, &ym2612.CH[3], stereo|((pan&0x0c0)>>2));\r
- chan_render(mix_buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4));\r
- chan_render(mix_buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2);\r
-\r
-#ifndef EXTERNAL_YM2612\r
- /* limit and mix to output buffer */\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
- }\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
- }\r
-#endif\r
+ return 1; // buffer updated\r
}\r
\r
\r
\r
void YM2612Init_(int baseclock, int rate);\r
void YM2612ResetChip_(void);\r
-void YM2612UpdateOne_(short *buffer, int length, int stereo);\r
+int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty);\r
\r
int YM2612Write_(unsigned int a, unsigned int v);\r
unsigned char YM2612Read_(void);\r
if (PicoOpt&0x200) YM2612ResetChip_940(); \\r
else YM2612ResetChip_(); \\r
}\r
-#define YM2612UpdateOne(buffer,length,stereo) { \\r
- if (PicoOpt&0x200) YM2612UpdateOne_940(buffer, length, stereo); \\r
- else YM2612UpdateOne_(buffer, length, stereo); \\r
+#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) { \\r
+ if (PicoOpt&0x200) YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty); \\r
+ else YM2612UpdateOne_(buffer, length, stereo, is_buf_empty); \\r
}\r
#define YM2612Write(a,v) \\r
(PicoOpt&0x200) ? YM2612Write_940(a, v) : YM2612Write_(a, v)\r
#include "asmutils.h"\r
#include "../../Pico/PicoInt.h"\r
\r
+// tmp\r
+#include "../../Pico/sound/mix.h"\r
+\r
/* we will need some gp2x internals here */\r
extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */\r
extern volatile unsigned long *gp2x_memregl;\r
return 0;\r
}\r
\r
+static int g_busy = 10;\r
\r
static void wait_busy_940(void)\r
{\r
}\r
printf("wait iterations: %i\n", i);\r
#else\r
- for (i = 0; shared_ctl->busy && i < 0x10000; i++)\r
+ for (i = 0; /*shared_ctl->busy*/gp2x_memregs[0x3B3E>>1] && i < 0x10000; i++)\r
spend_cycles(8*1024); // tested to be best for mp3 dec\r
+ //printf("i = 0x%x\n", i);\r
if (i < 0x10000) return;\r
\r
/* 940 crashed */\r
for (i = 0; i < 8; i++)\r
printf("%i ", shared_ctl->vstarts[i]);\r
printf(")\n");\r
+ printf("irq pending flags: DUALCPU %04x (see 15?), SRCPND %08lx (see 26), INTPND %08lx\n",\r
+ gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);\r
+ printf("last irq PC: %08x, lastjob: 0x%03x, busy: %x, lastbusy: %x, g_busy: %x\n", shared_ctl->last_irq_pc,\r
+ shared_ctl->lastjob, gp2x_memregs[0x3B3E>>1]/*shared_ctl->busy*/, shared_ctl->lastbusy, g_busy);\r
+ printf("trying to interrupt..\n");\r
+ gp2x_memregs[0x3B3E>>1] = 0xffff;\r
+ for (i = 0; /*shared_ctl->busy*/gp2x_memregs[0x3B3E>>1] && i < 0x10000; i++)\r
+ spend_cycles(8*1024);\r
+ printf("i = 0x%x\n", i);\r
+ printf("irq pending flags: DUALCPU %04x (see 15?), SRCPND %08lx (see 26), INTPND %08lx\n",\r
+ gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);\r
+ printf("last irq PC: %08x, lastjob: 0x%03x, busy: %x\n", shared_ctl->last_irq_pc, shared_ctl->lastjob, gp2x_memregs[0x3B3E>>1]/*shared_ctl->busy*/);\r
+\r
strcpy(menuErrorMsg, "940 crashed.");\r
engineState = PGS_Menu;\r
crashed_940 = 1;\r
\r
static void add_job_940(int job0, int job1)\r
{\r
+/* if (gp2x_memregs[0x3b46>>1] || shared_ctl->busy)\r
+ {\r
+ printf("!!add_job_940: irq pending flags: DUALCPU %04x (see 15?), SRCPND %08lx (see 26), INTPND %08lx, busy: %x\n",\r
+ gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2], shared_ctl->busy);\r
+ }\r
+*/\r
shared_ctl->jobs[0] = job0;\r
shared_ctl->jobs[1] = job1;\r
- shared_ctl->busy = 1;\r
- gp2x_memregs[0x3B3E>>1] = 0xffff; // cause an IRQ for 940\r
+ //shared_ctl->busy = ++g_busy; // 1;\r
+ gp2x_memregs[0x3B3E>>1] = ++g_busy; // set busy flag\r
+// gp2x_memregs[0x3B3E>>1] = 0xffff; // cause interrupt\r
}\r
\r
\r
{\r
int i, old_A1 = addr_A1;\r
\r
- if (shared_ctl->busy) wait_busy_940();\r
+ if (/*shared_ctl->busy*/gp2x_memregs[0x3B3E>>1]) wait_busy_940();\r
\r
// feed all the registers and update internal state\r
for(i = 0; i < 0x100; i++) {\r
Reset940(1, 2);\r
Pause940(1);\r
\r
- gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940\r
- gp2x_memregs[0x3B42>>1] = 0xffff; // enable DUALCPU interrupts for 940\r
-\r
- gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller\r
+ gp2x_memregs[0x3B40>>1] = 0; // disable DUALCPU interrupts for 920\r
+ gp2x_memregs[0x3B42>>1] = 1; // enable DUALCPU interrupts for 940\r
\r
if (shared_mem == NULL)\r
{\r
shared_ctl->rate = rate;\r
shared_ctl->jobs[0] = JOB940_INITALL;\r
shared_ctl->jobs[1] = 0;\r
- shared_ctl->busy = 1;\r
+ //shared_ctl->busy = 1;\r
+ gp2x_memregs[0x3B3E>>1] = 1; // set busy flag\r
+\r
+ gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940\r
+ gp2x_memregl[0x4500>>2] = 0; // clear pending IRQs in SRCPND\r
+ gp2x_memregl[0x4510>>2] = 0; // clear pending IRQs in INTPND\r
+ gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller\r
\r
/* start the 940 */\r
Reset940(0, 2);\r
return;\r
}\r
\r
- if (shared_ctl->busy) wait_busy_940();\r
+ if (/*shared_ctl->busy*/gp2x_memregs[0x3B3E>>1]) wait_busy_940();\r
\r
internal_reset();\r
\r
}\r
\r
\r
-static void mix_samples(short *dest_buf, int *ym_buf, short *mp3_buf, int len, int stereo)\r
+//extern int pcm_buffer[2*44100/50];\r
+/*\r
+static void mix_samples(int *dest_buf, short *mp3_buf, int len, int stereo)\r
{\r
- if (mp3_buf)\r
+// int *pcm = pcm_buffer + offset * 2;\r
+\r
+ if (stereo)\r
{\r
- if (stereo)\r
+ for (; len > 0; len--)\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
+ int lm, rm;\r
+ lm = *mp3_buf++; rm = *mp3_buf++;\r
+ *dest_buf++ += lm - lm/2; *dest_buf++ += rm - rm/2;\r
}\r
- }\r
- else\r
- {\r
- if (stereo)\r
+ } else {\r
+ for (; len > 0; len--)\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
+ int l = *mp3_buf++;\r
+ *dest_buf++ = l - l/2;\r
}\r
}\r
}\r
-\r
+*/\r
\r
// here we assume that length is different between games, but constant in one game\r
\r
static int mp3_samples_ready = 0, mp3_buffer_offs = 0;\r
static int mp3_play_bufsel = 0;\r
\r
-void YM2612UpdateOne_940(short *buffer, int length, int stereo)\r
+int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)\r
{\r
- int cdda_on, *ym_buffer = shared_data->mix_buffer, mp3_job = 0;\r
+ int length_mp3 = Pico.m.pal ? 44100/50 : 44100/60; // mp3s are locked to 44100Hz stereo\r
+ int *ym_buf = shared_data->mix_buffer;\r
+// int *dest_buf = buffer;\r
+ int cdda_on, mp3_job = 0;\r
+// int len;\r
+\r
+ // emulating CD, enabled in opts, not data track, CDC is reading, playback was started, track not ended\r
+ cdda_on = (PicoMCD & 1) && (PicoOpt & 0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&\r
+ (Pico_mcd->scd.Status_CDC & 1) && loaded_mp3;\r
\r
//printf("YM2612UpdateOne_940()\n");\r
- if (shared_ctl->busy) wait_busy_940();\r
+ if (/*shared_ctl->busy*/gp2x_memregs[0x3B3E>>1]) wait_busy_940();\r
\r
- //printf("940 (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc);\r
- //for (i = 0; i < 8; i++)\r
- // printf("%i ", shared_ctl->vstarts[i]);\r
- //printf(")\n");\r
+ // track ended?\r
+ cdda_on = cdda_on && shared_ctl->mp3_offs < shared_ctl->mp3_len;\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
+ // mix in ym buffer\r
+ if (is_buf_empty) memcpy32(buffer, ym_buf, length<<stereo);\r
+ // else TODO\r
+\r
+// for (len = length << stereo; len > 0; len--)\r
+// {\r
+// *dest_buf++ += *ym_buf++;\r
+// }\r
\r
- /* mix data from previous go */\r
- if (cdda_on && mp3_samples_ready >= length)\r
+ /* mix mp3 data, only stereo */\r
+ if (cdda_on && mp3_samples_ready >= length_mp3)\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
+ int shr = 0;\r
+ void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;\r
+ if (PsndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }\r
+ else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }\r
\r
- mp3_buffer_offs += length;\r
+ if (1152 - mp3_buffer_offs >= length_mp3) {\r
+ mix_samples(buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, (length_mp3>>shr)<<1);\r
+\r
+ mp3_buffer_offs += length_mp3;\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
+ if (mp3_play_bufsel == 0)\r
+ {\r
+ mix_samples(buffer, shared_data->mp3_buffer[0] + mp3_buffer_offs*2, (length_mp3>>shr)<<1);\r
+ mp3_buffer_offs = length_mp3 - left;\r
+ mp3_play_bufsel = 1;\r
+ } else {\r
+ mix_samples(buffer, shared_data->mp3_buffer[1] + mp3_buffer_offs*2, (left>>shr)<<1);\r
+ mp3_buffer_offs = length_mp3 - left;\r
+ mix_samples(buffer + ((left>>shr)<<1),\r
+ shared_data->mp3_buffer[0], (mp3_buffer_offs>>shr)<<1);\r
+ mp3_play_bufsel = 0;\r
+ }\r
}\r
- mp3_samples_ready -= length;\r
- } else {\r
- mix_samples(buffer, ym_buffer, 0, length, stereo);\r
+ mp3_samples_ready -= length_mp3;\r
}\r
\r
- //printf("new writes: %i\n", writebuff_ptr);\r
if (shared_ctl->writebuffsel == 1) {\r
shared_ctl->writebuff0[writebuff_ptr] = 0xffff;\r
} else {\r
shared_ctl->stereo = stereo;\r
\r
// make sure we will have enough mp3 samples next frame\r
- if (cdda_on && mp3_samples_ready < length)\r
+ if (cdda_on && mp3_samples_ready < length_mp3)\r
{\r
shared_ctl->mp3_buffsel ^= 1;\r
mp3_job = JOB940_MP3DECODE;\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
+ return 1;\r
}\r
\r
\r
\r
if (loaded_mp3 != f)\r
{\r
- printf("loading mp3... "); fflush(stdout);\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
+ // 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
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
+ // 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
void YM2612Init_940(int baseclock, int rate);\r
void YM2612ResetChip_940(void);\r
-void YM2612UpdateOne_940(short *buffer, int length, int stereo);\r
+int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);\r
\r
int YM2612Write_940(unsigned int a, unsigned int v);\r
unsigned char YM2612Read_940(void);\r
# Pico - CD\r
OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pico/cd/LC89510.o \\r
../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/gfx_cd.o \\r
- ../../Pico/cd/Area.o ../../Pico/cd/Misc.o\r
+ ../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o\r
# asm stuff\r
ifeq "$(asm_render)" "1"\r
DEFINC += -D_ASM_DRAW_C\r
OBJS += ../../Pico/sound/ym2612_asm.o\r
endif\r
# Pico - sound\r
+OBJS += ../../Pico/sound/mix_asm.o\r
OBJS += ../../Pico/sound/sound.o ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o\r
# zlib\r
OBJS += ../../zlib/gzio.o ../../zlib/inffast.o ../../zlib/inflate.o ../../zlib/inftrees.o ../../zlib/trees.o \\r
@cmd //C copy $@ \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
endif\r
\r
-up:\r
+up: PicoDrive.gpe\r
@cp -v PicoDrive.gpe /mnt/gp2x/mnt/sd/games/PicoDrive/\r
\r
# @cmd //C copy PicoDrive.gpe \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
../../Pico/sound/ym2612_asm.o : ../../Pico/sound/ym2612.s\r
@echo $<\r
@$(AS) $(ASOPT) $< -o $@\r
+../../Pico/sound/mix_asm.o : ../../Pico/sound/mix.s\r
+ @echo $<\r
+ @$(AS) $(ASOPT) $< -o $@\r
\r
# build Cyclone\r
../../cpu/Cyclone/proj/Cyclone.s :\r
void vidCpyM2_32col(void *dest, void *src);\r
void vidCpyM2_32col_nobord(void *dest, void *src);\r
void spend_cycles(int c); // utility\r
+void flushcache(void);\r
+\r
@ (c) Copyright 2006, notaz\r
@ All Rights Reserved\r
\r
+@ vim:filetype=armasm\r
\r
@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0\r
@ to 00000000 rrr00000 ggg00000 bbb00000 ...\r
b vidCpyM2_32_loop_out\r
\r
\r
-@ test\r
.global spend_cycles @ c\r
\r
spend_cycles:\r
bpl .sc_loop\r
\r
bx lr\r
+\r
+\r
+@ test\r
+.global flushcache\r
+\r
+flushcache: \r
+ swi #0x9f0002 \r
+ mov pc, lr \r
+ \r
}\r
\r
\r
-void Main940(int startvector)\r
+void Main940(int startvector, int pc_at_irq)\r
{\r
ym2612_940 = &shared_data->ym2612;\r
mix_buffer = shared_data->mix_buffer;\r
\r
// debug\r
shared_ctl->vstarts[startvector]++;\r
+ shared_ctl->last_irq_pc = pc_at_irq;\r
// asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0");\r
\r
\r
- for (;;)\r
+// for (;;)\r
{\r
int job_num = 0;\r
/*\r
spend_cycles(8*1024);\r
}\r
*/\r
+/*\r
if (!shared_ctl->busy)\r
{\r
wait_irq();\r
}\r
+ shared_ctl->lastbusy = shared_ctl->busy;\r
+*/\r
\r
for (job_num = 0; job_num < MAX_940JOBS; job_num++)\r
{\r
+ shared_ctl->lastjob = (job_num << 8) | shared_ctl->jobs[job_num];\r
+\r
switch (shared_ctl->jobs[job_num])\r
{\r
case JOB940_INITALL:\r
YM2612Write_(d >> 8, d);\r
}\r
\r
- YM2612UpdateOne_(0, shared_ctl->length, shared_ctl->stereo);\r
+ YM2612UpdateOne_(mix_buffer, shared_ctl->length, shared_ctl->stereo, 1);\r
break;\r
}\r
\r
// cache_clean_flush();\r
\r
shared_ctl->loopc++;\r
- shared_ctl->busy = 0;\r
+\r
+// // shared_ctl->busy = 0; // shared mem is not reliable?\r
+\r
+ wait_irq();\r
}\r
}\r
\r
.global code940\r
\r
+.equ mmsp2_regs, (0xc0000000-0x02000000) @ assume we live @ 0x2000000 bank\r
+\r
code940: @ interrupt table:\r
b .b_reset @ reset\r
b .b_undef @ undefined instructions\r
mov r12, #6\r
mov sp, #0x100000 @ reset stack\r
sub sp, sp, #4\r
- mov r1, #0xbe000000 @ assume we live @ 0x2000000 bank\r
+ mov r1, #mmsp2_regs\r
orr r2, r1, #0x3B00\r
orr r2, r2, #0x0046\r
mvn r3, #0\r
\r
@ set up region 3: 64k 0xbe000000-0xbe010000 (hw control registers)\r
mov r0, #(0x0f<<1)|1\r
- orr r0, r0, #0xbe000000\r
+ orr r0, r0, #mmsp2_regs\r
mcr p15, 0, r0, c6, c3, 0\r
mcr p15, 0, r0, c6, c3, 1\r
\r
mov r0, #(1<<1)\r
mcr p15, 0, r0, c3, c0, 0\r
\r
- @ set protection, allow accsess only to regions 1 and 2\r
+ @ set protection, allow access only to regions 1 and 2\r
mov r0, #(3<<8)|(3<<6)|(3<<4)|(3<<2)|(0) @ data: [full, full, full, full, no access] for regions [4 3 2 1 0]\r
mcr p15, 0, r0, c5, c0, 0\r
mov r0, #(0<<8)|(0<<6)|(0<<4)|(3<<2)|(0) @ instructions: [no access, no, no, full, no]\r
orr r0, r0, #1 @ 0x00000001: enable protection unit\r
orr r0, r0, #4 @ 0x00000004: enable D cache\r
orr r0, r0, #0x1000 @ 0x00001000: enable I cache\r
- bic r0, r0, #0xC0000000\r
- orr r0, r0, #0x40000000 @ 0x40000000: synchronous, faster?\r
-@ orr r0, r0, #0xC0000000 @ 0xC0000000: async\r
+@ bic r0, r0, #0xC0000000\r
+@ orr r0, r0, #0x40000000 @ 0x40000000: synchronous, faster?\r
+ orr r0, r0, #0xC0000000 @ 0xC0000000: async\r
mcr p15, 0, r0, c1, c0, 0 @ set control reg\r
\r
@ flush (invalidate) the cache (just in case)\r
\r
.Enter:\r
mov r0, r12\r
+ mov r1, lr\r
bl Main940\r
\r
@ we should never get here\r
-.b_deadloop:\r
- b .b_deadloop\r
+@.b_deadloop:\r
+@ b .b_deadloop\r
+ b .b_reserved\r
\r
\r
\r
.global wait_irq\r
\r
wait_irq:\r
+ mov r0, #mmsp2_regs\r
+ orr r0, r0, #0x3B00\r
+ orr r1, r0, #0x0042\r
+ mov r3, #0\r
+ strh r3, [r1] @ disable interrupts\r
+ orr r2, r0, #0x003E\r
+ strh r3, [r2] @ remove busy flag\r
+ mov r3, #1\r
+ strh r3, [r1] @ enable interrupts\r
+\r
mrs r0, cpsr\r
bic r0, r0, #0x80\r
- msr cpsr_c, r0 @ enable interrupts\r
+ msr cpsr_c, r0 @ enable interrupts\r
\r
mov r0, #0\r
mcr p15, 0, r0, c7, c0, 4 @ wait for IRQ\r
@ mcr p15, 0, r0, c15, c8, 2\r
+ nop\r
+ nop\r
b .b_reserved\r
\r
.pool\r
typedef struct\r
{\r
int jobs[MAX_940JOBS]; /* jobs for second core */\r
- int busy; /* busy status of the 940 core */\r
+ int busy_; /* unused */\r
int length; /* number of samples to mix (882 max) */\r
int stereo; /* mix samples as stereo, doubles sample count automatically */\r
int baseclock; /* ym2612 settings */\r
int loopc; /* debug: main loop counter */\r
int mp3_errors; /* debug: mp3 decoder's error counter */\r
int mp3_lasterr; /* debug: mp3 decoder's last error */\r
+ int last_irq_pc; /* debug: PC value when IRQ happened */\r
+ int lastjob; /* debug: last job id */\r
+ int lastbusy; /* debug: */\r
} _940_ctl_t;\r
\r
DEFINC = -I../.. -I. -D__GP2X__ -DARM # -DBENCHMARK\r
COPT_COMMON = -static -s -O3 -ftracer -fstrength-reduce -Wall -funroll-loops -fomit-frame-pointer -fstrict-aliasing -ffast-math\r
-COPT = $(COPT_COMMON) -mtune=arm920t\r
+COPT = $(COPT_COMMON) -mtune=arm940t\r
GCC = $(CROSS)gcc\r
STRIP = $(CROSS)strip\r
AS = $(CROSS)as\r
\r
all: code940.bin\r
\r
-up940:\r
- @cp -v code940.bin /mnt/gp2x/mnt/sd/games/PicoDrive/\r
-\r
-# @cmd //C copy code940.bin \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
\r
.c.o:\r
@echo $<\r
# stuff for 940 core\r
\r
# init, emu_control, emu\r
-OBJS940 += 940init.o 940.o 940ym2612.o memcpy.o\r
+OBJS940 += 940init.o 940.o 940ym2612.o memcpy.o mix.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
\r
code940.gpe : $(OBJS940) ../helix/helix_mp3.a\r
@echo $@\r
- @$(LD) -static -e code940 -Ttext 0x0 $^ -L$(lgcc_path) -lgcc -o $@\r
+ @$(LD) -static -e code940 -Ttext 0x0 $^ -L$(lgcc_path) -lgcc -o $@ -Map code940.map\r
\r
940ym2612.o : ../../../Pico/sound/ym2612.c\r
@echo $@\r
- @$(GCC) $(COPT_COMMON) -mtune=arm940t $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@\r
+ @$(GCC) $(COPT) $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@\r
+\r
+mix.o : ../../../Pico/sound/mix.s\r
+ @echo $@\r
+ @$(GCC) $(COPT) $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@\r
\r
../helix/helix_mp3.a:\r
@make -C ../helix/\r
\r
\r
-up:\r
+up: code940.bin\r
@cp -v code940.bin /mnt/gp2x/mnt/sd/games/PicoDrive/\r
\r
\r
clean: tidy\r
@$(RM) code940.bin\r
tidy:\r
- @$(RM) code940.gpe $(OBJS940)\r
+ @$(RM) code940.gpe $(OBJS940) code940.map\r
\r
\r
OBJSMP3T = mp3test.o ../gp2x.o ../asmutils.o ../usbjoy.o\r
// bios_help() ?\r
return 0;\r
} else {\r
+ if (PicoMCD & 1) PicoExitMCD();\r
PicoMCD &= ~1;\r
}\r
\r
}\r
}\r
gettimeofday(¬iceMsgTime, 0);\r
-printf("PicoMCD: %x\n", PicoMCD);\r
+\r
// load SRAM for this ROM\r
if(currentConfig.EmuOpt & 1)\r
emu_SaveLoadGame(1, 1);\r
// set default config\r
memset(¤tConfig, 0, sizeof(currentConfig));\r
currentConfig.lastRomFile[0] = 0;\r
- currentConfig.EmuOpt = 0x1f | 0xc00; // | cd_leds | cd_cdda\r
- currentConfig.PicoOpt = 0x0f | 0x200; // | use_940\r
+ currentConfig.EmuOpt = 0x1f | 0x400; // | cd_leds\r
+ currentConfig.PicoOpt = 0x0f | 0xe00; // | use_940 | cd_pcm | cd_cdda\r
currentConfig.PsndRate = 44100;\r
currentConfig.PicoRegion = 0; // auto\r
currentConfig.PicoAutoRgnOrder = 0x184; // US, EU, JP\r
// 8-bit modes\r
unsigned int col_g = (old_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;\r
unsigned int col_r = (old_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;\r
- *(unsigned int *)((char *)gp2x_screen + 320*2+306) =\r
- *(unsigned int *)((char *)gp2x_screen + 320*3+306) =\r
- *(unsigned int *)((char *)gp2x_screen + 320*4+306) = col_g;\r
- *(unsigned int *)((char *)gp2x_screen + 320*2+312) =\r
- *(unsigned int *)((char *)gp2x_screen + 320*3+312) =\r
- *(unsigned int *)((char *)gp2x_screen + 320*4+312) = col_r;\r
+ *(unsigned int *)((char *)gp2x_screen + 320*2+ 4) =\r
+ *(unsigned int *)((char *)gp2x_screen + 320*3+ 4) =\r
+ *(unsigned int *)((char *)gp2x_screen + 320*4+ 4) = col_g;\r
+ *(unsigned int *)((char *)gp2x_screen + 320*2+12) =\r
+ *(unsigned int *)((char *)gp2x_screen + 320*3+12) =\r
+ *(unsigned int *)((char *)gp2x_screen + 320*4+12) = col_r;\r
} else {\r
// 16-bit modes\r
- unsigned int *p = (unsigned int *)((short *)gp2x_screen + 320*2+306);\r
+ unsigned int *p = (unsigned int *)((short *)gp2x_screen + 320*2+4);\r
unsigned int col_g = (old_reg & 2) ? 0x06000600 : 0;\r
unsigned int col_r = (old_reg & 1) ? 0xc000c000 : 0;\r
- *p++ = col_g; *p++ = col_g; p++; *p++ = col_r; *p++ = col_r; p += 320/2 - 10/2;\r
- *p++ = col_g; *p++ = col_g; p++; *p++ = col_r; *p++ = col_r; p += 320/2 - 10/2;\r
- *p++ = col_g; *p++ = col_g; p++; *p++ = col_r; *p++ = col_r; p += 320/2 - 10/2;\r
+ *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;\r
+ *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;\r
+ *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;\r
}\r
}\r
\r
char lastRomFile[512];\r
int EmuOpt; // LSb->MSb: use_sram, show_fps, enable_sound, gzip_saves,\r
// squidgehack, save_cfg_on_exit, <unused>, 16_bit_mode\r
- // craigix_ram, confirm_save, show_cd_leds, enable_cdda\r
- // enable_pcm\r
+ // craigix_ram, confirm_save, show_cd_leds\r
+ //\r
int PicoOpt; // used for config saving only, see Pico.h\r
int PsndRate; // ditto\r
int PicoRegion; // ditto\r
gp2x_text_out8(tl_x, (y+=10), "EUR BIOS: %s", b_eu); // 1\r
gp2x_text_out8(tl_x, (y+=10), "JAP BIOS: %s", b_jp); // 2\r
gp2x_text_out8(tl_x, (y+=10), "CD LEDs %s", (currentConfig.EmuOpt &0x400)?"ON":"OFF"); // 3\r
- gp2x_text_out8(tl_x, (y+=10), "CDDA audio (using mp3s) %s", (currentConfig.EmuOpt &0x800)?"ON":"OFF"); // 4\r
+ gp2x_text_out8(tl_x, (y+=10), "CDDA audio (using mp3s) %s", (currentConfig.PicoOpt&0x800)?"ON":"OFF"); // 4\r
+ gp2x_text_out8(tl_x, (y+=10), "PCM audio %s", (currentConfig.PicoOpt&0x400)?"ON":"OFF"); // 5\r
gp2x_text_out8(tl_x, (y+=10), "Done");\r
\r
// draw cursor\r
\r
static void cd_menu_loop_options(void)\r
{\r
- int menu_sel = 0, menu_sel_max = 5;\r
+ int menu_sel = 0, menu_sel_max = 6;\r
unsigned long inp = 0;\r
char bios_us[32], bios_eu[32], bios_jp[32], *bios, *p;\r
\r
if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
switch (menu_sel) {\r
case 3: currentConfig.EmuOpt ^=0x400; break;\r
- case 4: currentConfig.EmuOpt ^=0x800; break;\r
- case 5: return;\r
+ case 4: currentConfig.PicoOpt^=0x800; break;\r
+ case 5: currentConfig.PicoOpt^=0x400; break;\r
+ case 6: return;\r
}\r
}\r
if(inp & (GP2X_X|GP2X_A)) return;\r
static YM2612 ym2612;
YM2612 *ym2612_940 = &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 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)
{
static FILE *loaded_mp3 = 0;
-void YM2612UpdateOne_940(short *buffer, int length, int stereo)
+int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)
{
#if 0
int cdda_on, *ym_buffer = mix_buffer;
mp3_samples_ready += 1152;
}
#else
- YM2612UpdateOne_(buffer, length, stereo); // really writes to mix_buffer
-
- mix_samples(buffer, mix_buffer, 0, length, stereo);
+ return YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);
#endif
}
# Pico - CD
OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pico/cd/LC89510.o \
../../Pico/cd/cd_sys.o ../../Pico/cd/cd_file.o ../../Pico/cd/gfx_cd.o \
- ../../Pico/cd/Area.o ../../Pico/cd/Misc.o
+ ../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o
# Pico - sound
-OBJS += ../../Pico/sound/sound.o ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o
+OBJS += ../../Pico/sound/sound.o ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o ../../Pico/sound/mix.o
# zlib
OBJS += ../../zlib/gzio.o ../../zlib/inffast.o ../../zlib/inflate.o ../../zlib/inftrees.o ../../zlib/trees.o \
../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o