extern long CALLBACK SPUshutdown(void);
extern long CALLBACK SPUclose(void);
extern void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int);
-extern unsigned short CALLBACK SPUreadRegister(unsigned long);
+extern unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int);
extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int);
extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int);
extern void CALLBACK SPUplayADPCMchannel(void *, unsigned int, int);
pc_hook_func (GPU_updateLace, (void), (), PCNT_GPU)
pc_hook_func (SPU_writeRegister, (unsigned long a0, unsigned short a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
-pc_hook_func_ret(unsigned short,SPU_readRegister, (unsigned long a0), (a0), PCNT_SPU)
+pc_hook_func_ret(unsigned short,SPU_readRegister, (unsigned long a0, , unsigned int a1), (a0, a1), PCNT_SPU)
pc_hook_func (SPU_writeDMAMem, (unsigned short *a0, int a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
pc_hook_func (SPU_readDMAMem, (unsigned short *a0, int a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
pc_hook_func (SPU_playADPCMchannel, (void *a0, unsigned int a1, int a2), (a0, a1, a2), PCNT_SPU)
make_dma_func(4)
make_dma_func(6)
+static u32 io_spu_read16(u32 addr)
+{
+ return SPU_readRegister(addr, psxRegs.cycle);
+}
+
+static u32 io_spu_read32(u32 addr)
+{
+ u32 ret;
+ ret = SPU_readRegister(addr, psxRegs.cycle);
+ ret |= SPU_readRegister(addr + 2, psxRegs.cycle) << 16;
+ return ret;
+}
+
static void io_spu_write16(u32 value)
{
// meh
map_item(&mem_iortab[IOMEM8(0x1802)], cdrRead2, 1);
map_item(&mem_iortab[IOMEM8(0x1803)], cdrRead3, 1);
+ for (i = 0x1c00; i < 0x2000; i += 2) {
+ map_item(&mem_iortab[IOMEM16(i)], io_spu_read16, 1);
+ map_item(&mem_iortab[IOMEM32(i)], io_spu_read32, 1);
+ }
+
// write(u32 data)
map_item(&mem_iowtab[IOMEM32(0x1040)], io_write_sio32, 1);
map_item(&mem_iowtab[IOMEM32(0x1070)], psxHwWriteIstat, 1);
void new_dyna_pcsx_mem_reset(void)
{
- int i;
-
// plugins might change so update the pointers
map_item(&mem_iortab[IOMEM32(0x1810)], GPU_readData, 1);
-
- for (i = 0x1c00; i < 0x2000; i += 2)
- map_item(&mem_iortab[IOMEM16(i)], SPU_readRegister, 1);
-
map_item(&mem_iowtab[IOMEM32(0x1810)], GPU_writeData, 1);
}
typedef long (CALLBACK* SPUshutdown)(void); \r
typedef long (CALLBACK* SPUclose)(void); \r
typedef void (CALLBACK* SPUwriteRegister)(unsigned long, unsigned short, unsigned int);\r
-typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long);\r
+typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long, unsigned int);\r
typedef void (CALLBACK* SPUwriteDMAMem)(unsigned short *, int, unsigned int);\r
typedef void (CALLBACK* SPUreadDMAMem)(unsigned short *, int, unsigned int);\r
typedef void (CALLBACK* SPUplayADPCMchannel)(xa_decode_t *, unsigned int, int);\r
// falthrough
default:
if (0x1f801c00 <= add && add < 0x1f802000)
- return SPU_readRegister(add);
+ return SPU_readRegister(add, psxRegs.cycle);
hard = psxHu16(add);
#ifdef PSXHW_LOG
PSXHW_LOG("*Unkwnown 16bit read at address %x\n", add);
// falthrough
default:
if (0x1f801c00 <= add && add < 0x1f802000) {
- hard = SPU_readRegister(add);
- hard |= SPU_readRegister(add + 2) << 16;
+ hard = SPU_readRegister(add, psxRegs.cycle);
+ hard |= SPU_readRegister(add + 2, psxRegs.cycle) << 16;
return hard;
}
hard = psxHu32(add);
unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;\r
int i, irq;\r
\r
- do_samples_if_needed(cycles, 1);\r
+ do_samples_if_needed(cycles, 1, 2);\r
irq = addr <= irq_addr && irq_addr < addr + iSize*2;\r
\r
for(i = 0; i < iSize; i++)\r
unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;\r
int i, irq;\r
\r
- do_samples_if_needed(cycles, 1);\r
+ do_samples_if_needed(cycles, 1, 2);\r
spu.bMemDirty = 1;\r
irq = addr <= irq_addr && irq_addr < addr + iSize*2;\r
\r
unsigned int prevflags:3; // flags from previous block\r
unsigned int bIgnoreLoop:1; // Ignore loop\r
unsigned int bNewPitch:1; // pitch changed\r
+ unsigned int bStarting:1; // starting after keyon\r
union {\r
struct {\r
int iLeftVolume; // left volume\r
void schedule_next_irq(void);\r
void check_irq_io(unsigned int addr);\r
\r
-#define do_samples_if_needed(c, sync) \\r
+#define do_samples_if_needed(c, sync, samples) \\r
do { \\r
- if (sync || (int)((c) - spu.cycles_played) >= 16 * 768) \\r
+ if (sync || (int)((c) - spu.cycles_played) >= (samples) * 768) \\r
do_samples(c, sync); \\r
} while (0)\r
\r
if (val == 0 && (r & 0xff8) == 0xd88)\r
return;\r
\r
- do_samples_if_needed(cycles, 0);\r
+ do_samples_if_needed(cycles, 0, 16);\r
\r
if(r>=0x0c00 && r<0x0d80) // some channel info?\r
{\r
*/\r
//-------------------------------------------------//\r
case H_SPUon1:\r
+ do_samples_if_needed(cycles, 0, 2);\r
SoundOn(0,16,val);\r
break;\r
//-------------------------------------------------//\r
- case H_SPUon2:\r
+ case H_SPUon2:\r
+ do_samples_if_needed(cycles, 0, 2);\r
SoundOn(16,24,val);\r
break;\r
//-------------------------------------------------//\r
// READ REGISTER: called by main emu\r
////////////////////////////////////////////////////////////////////////\r
\r
-unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
+unsigned short CALLBACK SPUreadRegister(unsigned long reg, unsigned int cycles)\r
{\r
const unsigned long r = reg & 0xffe;\r
\r
{\r
case 12: // get adsr vol\r
{\r
- const int ch=(r>>4)-0xc0;\r
- if(spu.dwNewChannel&(1<<ch)) return 1; // we are started, but not processed? return 1\r
- if((spu.dwChannelsAudible&(1<<ch)) && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
- !spu.s_chan[ch].ADSRX.EnvelopeVol)\r
- return 1;\r
- return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16);\r
+ // this used to return 1 immediately after keyon to deal with\r
+ // some poor timing, but that causes Rayman 2 to lose track of\r
+ // it's channels on busy scenes and start looping some of them forever\r
+ const int ch = (r>>4) - 0xc0;\r
+ if (spu.s_chan[ch].bStarting)\r
+ do_samples_if_needed(cycles, 0, 2);\r
+ return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol >> 16);\r
}\r
\r
case 14: // get loop address\r
if((val&1) && regAreaGetCh(ch, 6)) // mmm... start has to be set before key on !?!\r
{\r
spu.s_chan[ch].bIgnoreLoop = 0;\r
+ spu.s_chan[ch].bStarting = 1;\r
spu.dwNewChannel|=(1<<ch);\r
}\r
}\r
StartADSR(ch);
StartREVERB(ch);
- s_chan->prevflags=2;
- s_chan->iSBPos=27;
- s_chan->spos=0;
+ s_chan->prevflags = 2;
+ s_chan->iSBPos = 27;
+ s_chan->spos = 0;
+ s_chan->bStarting = 1;
s_chan->pCurr = spu.spuMemC + ((regAreaGetCh(ch, 6) & ~1) << 3);
int ret = 0;
start = s_chan->pCurr; // set up the current pos
- if (start == spu.spuMemC) // ?
+ if (start - spu.spuMemC < 0x1000) { // ?
+ //log_unhandled("ch%02d plays decode bufs @%05lx\n",
+ // ch, (long)(start - spu.spuMemC));
ret = 1;
+ }
if (s_chan->prevflags & 1) // 1: stop/loop
{
s_chan->pCurr = start; // store values for next cycle
s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
return ret;
}
s_chan->pCurr = start;
s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
return ret;
}
d = do_samples_default(decode_block, NULL, ch, ns_to,
SB, sinc, &s_chan->spos, &s_chan->iSBPos);
- d = MixADSR(&s_chan->ADSRX, d);
- if (d < ns_to) {
- spu.dwChannelsAudible &= ~(1 << ch);
- s_chan->ADSRX.State = ADSR_RELEASE;
- s_chan->ADSRX.EnvelopeVol = 0;
- memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+ if (!s_chan->bStarting) {
+ d = MixADSR(&s_chan->ADSRX, d);
+ if (d < ns_to) {
+ spu.dwChannelsAudible &= ~(1 << ch);
+ s_chan->ADSRX.State = ADSR_RELEASE;
+ s_chan->ADSRX.EnvelopeVol = 0;
+ memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+ }
}
if (ch == 1 || ch == 3)
d = do_samples_skip(ch, ns_to);
work->ch[ch].ns_to = d;
- // note: d is not accurate on skip
- d = SkipADSR(&s_chan->ADSRX, d);
- if (d < ns_to) {
- spu.dwChannelsAudible &= ~(1 << ch);
- s_chan->ADSRX.State = ADSR_RELEASE;
- s_chan->ADSRX.EnvelopeVol = 0;
+ if (!s_chan->bStarting) {
+ // note: d is not accurate on skip
+ d = SkipADSR(&s_chan->ADSRX, d);
+ if (d < ns_to) {
+ spu.dwChannelsAudible &= ~(1 << ch);
+ s_chan->ADSRX.State = ADSR_RELEASE;
+ s_chan->ADSRX.EnvelopeVol = 0;
+ }
}
s_chan->bNewPitch = 0;
}
spu.cycles_played += ns_to * 768;
spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
+#if 0
+ static int ccount; static time_t ctime; ccount++;
+ if (time(NULL) != ctime)
+ { printf("%d\n", ccount); ccount = 0; ctime = time(NULL); }
+#endif
}
static void do_samples_finish(int *SSumLR, int ns_to,