spu: try to improve timing
authornotaz <notasas@gmail.com>
Wed, 27 Sep 2023 20:12:48 +0000 (23:12 +0300)
committernotaz <notasas@gmail.com>
Wed, 27 Sep 2023 22:42:15 +0000 (01:42 +0300)
notaz/pcsx_rearmed#305

frontend/plugin.c
libpcsxcore/new_dynarec/pcsxmem.c
libpcsxcore/plugins.h
libpcsxcore/psxhw.c
plugins/dfsound/dma.c
plugins/dfsound/externals.h
plugins/dfsound/registers.c
plugins/dfsound/spu.c

index 3374141..2f8dcc2 100644 (file)
@@ -51,7 +51,7 @@ extern long CALLBACK SPUinit(void);
 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);
@@ -309,7 +309,7 @@ pc_hook_func_ret(long,     GPU_dmaChain, (uint32_t *a0, int32_t a1), (a0, a1), P
 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)
index da5b67e..7c670f8 100644 (file)
@@ -180,6 +180,19 @@ make_dma_func(3)
 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
@@ -387,6 +400,11 @@ void new_dyna_pcsx_mem_init(void)
        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);
@@ -456,14 +474,8 @@ void new_dyna_pcsx_mem_init(void)
 
 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);
 }
 
index e43ff9a..fbbd44f 100644 (file)
@@ -166,7 +166,7 @@ typedef long (CALLBACK* SPUinit)(void);
 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
index fb365c0..ecb8eaf 100644 (file)
@@ -253,7 +253,7 @@ u16 psxHwRead16(u32 add) {
                        // 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);
@@ -411,8 +411,8 @@ u32 psxHwRead32(u32 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);
index ada007f..1aebfce 100644 (file)
@@ -41,7 +41,7 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
  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
@@ -66,7 +66,7 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
  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
index f638b94..f3fbc67 100644 (file)
@@ -118,6 +118,7 @@ typedef struct
  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
@@ -261,9 +262,9 @@ void do_samples(unsigned int cycles_to, int do_sync);
 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
index bcac4d9..a20538a 100644 (file)
@@ -60,7 +60,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
  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
@@ -213,10 +213,12 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
 */\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
@@ -309,7 +311,7 @@ rvbd:
 // 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
@@ -319,12 +321,13 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
     {\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
@@ -404,6 +407,7 @@ static void SoundOn(int start,int end,unsigned short val)
    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
index fead03c..283d598 100644 (file)
@@ -250,9 +250,10 @@ static void StartSoundMain(int ch)
  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);
 
@@ -421,8 +422,11 @@ static int decode_block(void *unused, int ch, int *SB)
  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
  {
@@ -448,6 +452,7 @@ static int decode_block(void *unused, int ch, int *SB)
 
  s_chan->pCurr = start;                    // store values for next cycle
  s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
 
  return ret;
 }
@@ -477,6 +482,7 @@ static int skip_block(int ch)
 
  s_chan->pCurr = start;
  s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
 
  return ret;
 }
@@ -794,12 +800,14 @@ static void do_channels(int ns_to)
     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)
@@ -965,12 +973,14 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
    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;
   }
@@ -1178,6 +1188,11 @@ void do_samples(unsigned int cycles_to, int do_direct)
 
   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,