cdrom: change pause timing again
[pcsx_rearmed.git] / plugins / dfsound / registers.c
index f6da131..6d72d3c 100644 (file)
@@ -22,6 +22,7 @@
 #include "externals.h"\r
 #include "registers.h"\r
 #include "spu_config.h"\r
+#include "spu.h"\r
 \r
 static void SoundOn(int start,int end,unsigned short val);\r
 static void SoundOff(int start,int end,unsigned short val);\r
@@ -36,17 +37,19 @@ static void ReverbOn(int start,int end,unsigned short val);
 // WRITE REGISTERS: called by main emu\r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-static const uint32_t ignore_dupe[8] = {\r
+static const uint32_t ignore_dupe[16] = {\r
  // ch 0-15  c40         c80         cc0\r
  0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,\r
  // ch 16-24 d40         control     reverb\r
- 0x7f7f7f7f, 0x7f7f7f7f, 0xff05ff0f, 0xffffffff\r
+ 0x7f7f7f7f, 0x7f7f7f7f, 0xff05ff0f, 0xffffffff,\r
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,\r
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff\r
 };\r
 \r
 void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,\r
  unsigned int cycles)\r
 {\r
- int r = reg & 0xfff;\r
+ int r = reg & 0xffe;\r
  int rofs = (r - 0xc00) >> 1;\r
  int changed = spu.regArea[rofs] != val;\r
  spu.regArea[rofs] = val;\r
@@ -57,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
@@ -112,28 +115,38 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
      //------------------------------------------------//\r
      case 14:                                          // loop?\r
        spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
+       spu.s_chan[ch].bIgnoreLoop = 1;\r
        goto upd_irq;\r
      //------------------------------------------------//\r
     }\r
    return;\r
   }\r
+ else if (0x0e00 <= r && r < 0x0e60)\r
+  {\r
+   int ch = (r >> 2) & 0x1f;\r
+   log_unhandled("c%02d w %cvol %04x\n", ch, (r & 2) ? 'r' : 'l', val);\r
+   spu.s_chan[ch].iVolume[(r >> 1) & 1] = (signed short)val >> 1;\r
+  }\r
 \r
  switch(r)\r
    {\r
     //-------------------------------------------------//\r
     case H_SPUaddr:\r
-      spu.spuAddr = (unsigned long) val<<3;\r
+      spu.spuAddr = (unsigned int)val << 3;\r
+      //check_irq_io(spu.spuAddr);\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUdata:\r
-      *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val;\r
+      *(unsigned short *)(spu.spuMemC + spu.spuAddr) = HTOLE16(val);\r
       spu.spuAddr += 2;\r
       spu.spuAddr &= 0x7fffe;\r
+      check_irq_io(spu.spuAddr);\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUctrl:\r
+      spu.spuStat = (spu.spuStat & ~0xbf) | (val & 0x3f) | ((val << 2) & 0x80);\r
+      spu.spuStat &= ~STAT_IRQ | val;\r
       if (!(spu.spuCtrl & CTRL_IRQ)) {\r
-        spu.spuStat&=~STAT_IRQ;\r
         if (val & CTRL_IRQ)\r
          schedule_next_irq();\r
       }\r
@@ -141,36 +154,39 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
       break;\r
     //-------------------------------------------------//\r
     case H_SPUstat:\r
-      spu.spuStat=val&0xf800;\r
+      //spu.spuStat=val&0xf800;\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUReverbAddr:\r
-      if(val==0xFFFF || val<=0x200)\r
-       {rvb.StartAddr=rvb.CurrAddr=0;}\r
-      else\r
-       {\r
-        const long iv=(unsigned long)val<<2;\r
-        if(rvb.StartAddr!=iv)\r
-         {\r
-          rvb.StartAddr=(unsigned long)val<<2;\r
-          rvb.CurrAddr=rvb.StartAddr;\r
-         }\r
-       }\r
       goto rvbd;\r
     //-------------------------------------------------//\r
     case H_SPUirqAddr:\r
-      spu.pSpuIrq=spu.spuMemC+(((unsigned long) val<<3)&~0xf);\r
+      //if (val & 1)\r
+      //  log_unhandled("w irq with lsb: %08lx %04x\n", reg, val);\r
+      spu.pSpuIrq = spu.spuMemC + (((int)val << 3) & ~0xf);\r
+      //check_irq_io(spu.spuAddr);\r
       goto upd_irq;\r
     //-------------------------------------------------//\r
     case H_SPUrvolL:\r
-      rvb.VolLeft=val;\r
+      spu.rvb->VolLeft = (int16_t)val;\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUrvolR:\r
-      rvb.VolRight=val;\r
+      spu.rvb->VolRight = (int16_t)val;\r
       break;\r
     //-------------------------------------------------//\r
 \r
+    case H_SPUmvolL:\r
+    case H_SPUmvolR:\r
+      if (val & 0x8000)\r
+        log_unhandled("w master sweep: %08lx %04x\n", reg, val);\r
+      break;\r
+\r
+    case 0x0dac:\r
+     if (val != 4)\r
+       log_unhandled("1f801dac %04x\n", val);\r
+     break;\r
+\r
 /*\r
     case H_ExtLeft:\r
      //auxprintf("EL %d\n",val);\r
@@ -198,28 +214,44 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
 */\r
     //-------------------------------------------------//\r
     case H_SPUon1:\r
+      spu.last_keyon_cycles = cycles;\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
+      spu.last_keyon_cycles = cycles;\r
+      do_samples_if_needed(cycles, 0, 2);\r
       SoundOn(16,24,val);\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUoff1:\r
+      if (cycles - spu.last_keyon_cycles < 786u) {\r
+       if (val & regAreaGet(H_SPUon1))\r
+        log_unhandled("koff1 %04x %d\n", val, cycles - spu.last_keyon_cycles);\r
+       val &= ~regAreaGet(H_SPUon1);\r
+      }\r
+      do_samples_if_needed(cycles, 0, 2);\r
       SoundOff(0,16,val);\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUoff2:\r
+      if (cycles - spu.last_keyon_cycles < 786u) {\r
+       if (val & regAreaGet(H_SPUon1))\r
+        log_unhandled("koff2 %04x %d\n", val, cycles - spu.last_keyon_cycles);\r
+       val &= ~regAreaGet(H_SPUon2);\r
+      }\r
+      do_samples_if_needed(cycles, 0, 2);\r
       SoundOff(16,24,val);\r
       break;\r
     //-------------------------------------------------//\r
     case H_CDLeft:\r
-      spu.iLeftXAVol=val  & 0x7fff;\r
-      if(spu.cddavCallback) spu.cddavCallback(0,val);\r
+      spu.iLeftXAVol=(int16_t)val;\r
+      //if(spu.cddavCallback) spu.cddavCallback(0,(int16_t)val);\r
       break;\r
     case H_CDRight:\r
-      spu.iRightXAVol=val & 0x7fff;\r
-      if(spu.cddavCallback) spu.cddavCallback(1,val);\r
+      spu.iRightXAVol=(int16_t)val;\r
+      //if(spu.cddavCallback) spu.cddavCallback(1,(int16_t)val);\r
       break;\r
     //-------------------------------------------------//\r
     case H_FMod1:\r
@@ -246,38 +278,38 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
       ReverbOn(16,24,val);\r
       break;\r
     //-------------------------------------------------//\r
-    case H_Reverb+0   : rvb.FB_SRC_A=val*4;         goto rvbd;\r
-    case H_Reverb+2   : rvb.FB_SRC_B=val*4;         goto rvbd;\r
-    case H_Reverb+4   : rvb.IIR_ALPHA=(short)val;   goto rvbd;\r
-    case H_Reverb+6   : rvb.ACC_COEF_A=(short)val;  goto rvbd;\r
-    case H_Reverb+8   : rvb.ACC_COEF_B=(short)val;  goto rvbd;\r
-    case H_Reverb+10  : rvb.ACC_COEF_C=(short)val;  goto rvbd;\r
-    case H_Reverb+12  : rvb.ACC_COEF_D=(short)val;  goto rvbd;\r
-    case H_Reverb+14  : rvb.IIR_COEF=(short)val;    goto rvbd;\r
-    case H_Reverb+16  : rvb.FB_ALPHA=(short)val;    goto rvbd;\r
-    case H_Reverb+18  : rvb.FB_X=(short)val;        goto rvbd;\r
-    case H_Reverb+20  : rvb.IIR_DEST_A0=val*4;      goto rvbd;\r
-    case H_Reverb+22  : rvb.IIR_DEST_A1=val*4;      goto rvbd;\r
-    case H_Reverb+24  : rvb.ACC_SRC_A0=val*4;       goto rvbd;\r
-    case H_Reverb+26  : rvb.ACC_SRC_A1=val*4;       goto rvbd;\r
-    case H_Reverb+28  : rvb.ACC_SRC_B0=val*4;       goto rvbd;\r
-    case H_Reverb+30  : rvb.ACC_SRC_B1=val*4;       goto rvbd;\r
-    case H_Reverb+32  : rvb.IIR_SRC_A0=val*4;       goto rvbd;\r
-    case H_Reverb+34  : rvb.IIR_SRC_A1=val*4;       goto rvbd;\r
-    case H_Reverb+36  : rvb.IIR_DEST_B0=val*4;      goto rvbd;\r
-    case H_Reverb+38  : rvb.IIR_DEST_B1=val*4;      goto rvbd;\r
-    case H_Reverb+40  : rvb.ACC_SRC_C0=val*4;       goto rvbd;\r
-    case H_Reverb+42  : rvb.ACC_SRC_C1=val*4;       goto rvbd;\r
-    case H_Reverb+44  : rvb.ACC_SRC_D0=val*4;       goto rvbd;\r
-    case H_Reverb+46  : rvb.ACC_SRC_D1=val*4;       goto rvbd;\r
-    case H_Reverb+48  : rvb.IIR_SRC_B1=val*4;       goto rvbd;\r
-    case H_Reverb+50  : rvb.IIR_SRC_B0=val*4;       goto rvbd;\r
-    case H_Reverb+52  : rvb.MIX_DEST_A0=val*4;      goto rvbd;\r
-    case H_Reverb+54  : rvb.MIX_DEST_A1=val*4;      goto rvbd;\r
-    case H_Reverb+56  : rvb.MIX_DEST_B0=val*4;      goto rvbd;\r
-    case H_Reverb+58  : rvb.MIX_DEST_B1=val*4;      goto rvbd;\r
-    case H_Reverb+60  : rvb.IN_COEF_L=(short)val;   goto rvbd;\r
-    case H_Reverb+62  : rvb.IN_COEF_R=(short)val;   goto rvbd;\r
+    case H_Reverb+0   : goto rvbd;\r
+    case H_Reverb+2   : goto rvbd;\r
+    case H_Reverb+4   : spu.rvb->IIR_ALPHA=(short)val;   break;\r
+    case H_Reverb+6   : spu.rvb->ACC_COEF_A=(short)val;  break;\r
+    case H_Reverb+8   : spu.rvb->ACC_COEF_B=(short)val;  break;\r
+    case H_Reverb+10  : spu.rvb->ACC_COEF_C=(short)val;  break;\r
+    case H_Reverb+12  : spu.rvb->ACC_COEF_D=(short)val;  break;\r
+    case H_Reverb+14  : spu.rvb->IIR_COEF=(short)val;    break;\r
+    case H_Reverb+16  : spu.rvb->FB_ALPHA=(short)val;    break;\r
+    case H_Reverb+18  : spu.rvb->FB_X=(short)val;        break;\r
+    case H_Reverb+20  : goto rvbd;\r
+    case H_Reverb+22  : goto rvbd;\r
+    case H_Reverb+24  : goto rvbd;\r
+    case H_Reverb+26  : goto rvbd;\r
+    case H_Reverb+28  : goto rvbd;\r
+    case H_Reverb+30  : goto rvbd;\r
+    case H_Reverb+32  : goto rvbd;\r
+    case H_Reverb+34  : goto rvbd;\r
+    case H_Reverb+36  : goto rvbd;\r
+    case H_Reverb+38  : goto rvbd;\r
+    case H_Reverb+40  : goto rvbd;\r
+    case H_Reverb+42  : goto rvbd;\r
+    case H_Reverb+44  : goto rvbd;\r
+    case H_Reverb+46  : goto rvbd;\r
+    case H_Reverb+48  : goto rvbd;\r
+    case H_Reverb+50  : goto rvbd;\r
+    case H_Reverb+52  : goto rvbd;\r
+    case H_Reverb+54  : goto rvbd;\r
+    case H_Reverb+56  : goto rvbd;\r
+    case H_Reverb+58  : goto rvbd;\r
+    case H_Reverb+60  : spu.rvb->IN_COEF_L=(short)val;   break;\r
+    case H_Reverb+62  : spu.rvb->IN_COEF_R=(short)val;   break;\r
    }\r
  return;\r
 \r
@@ -287,16 +319,16 @@ upd_irq:
  return;\r
 \r
 rvbd:\r
rvb.dirty = 1; // recalculate on next update\r
spu.rvb->dirty = 1; // recalculate on next update\r
 }\r
 \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&0xfff;\r
+ const unsigned long r = reg & 0xffe;\r
         \r
  if(r>=0x0c00 && r<0x0d80)\r
   {\r
@@ -304,12 +336,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.dwChannelOn&(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
@@ -319,6 +352,13 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
       }\r
     }\r
   }\r
+ else if (0x0e00 <= r && r < 0x0e60)\r
+  {\r
+   int ch = (r >> 2) & 0x1f;\r
+   int v = spu.s_chan[ch].iVolume[(r >> 1) & 1] << 1;\r
+   log_unhandled("c%02d r %cvol %04x\n", ch, (r & 2) ? 'r' : 'l', v);\r
+   return v;\r
+  }\r
 \r
  switch(r)\r
   {\r
@@ -331,11 +371,13 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
     case H_SPUaddr:\r
      return (unsigned short)(spu.spuAddr>>3);\r
 \r
+    // this reportedly doesn't work on real hw\r
     case H_SPUdata:\r
      {\r
-      unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr);\r
+      unsigned short s = LE16TOH(*(unsigned short *)(spu.spuMemC + spu.spuAddr));\r
       spu.spuAddr += 2;\r
       spu.spuAddr &= 0x7fffe;\r
+      //check_irq_io(spu.spuAddr);\r
       return s;\r
      }\r
 \r
@@ -345,6 +387,23 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
     //case H_SPUIsOn2:\r
     // return IsSoundOn(16,24);\r
  \r
+    case H_SPUMute1:\r
+    case H_SPUMute2:\r
+     log_unhandled("r isOn: %08lx\n", reg);\r
+     break;\r
+\r
+    case 0x0dac:\r
+    case H_SPUirqAddr:\r
+    case H_CDLeft:\r
+    case H_CDRight:\r
+    case H_ExtLeft:\r
+    case H_ExtRight:\r
+     break;\r
+\r
+    default:\r
+     if (r >= 0xda0)\r
+       log_unhandled("spu r %08lx\n", reg);\r
+     break;\r
   }\r
 \r
  return spu.regArea[(r-0xc00)>>1];\r
@@ -360,10 +419,10 @@ static void SoundOn(int start,int end,unsigned short val)
 \r
  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
   {\r
-   if((val&1) && regAreaGet(ch,6))                     // mmm... start has to be set before key on !?!\r
+   if((val&1) && regAreaGetCh(ch, 6))                  // mmm... start has to be set before key on !?!\r
     {\r
-     spu.s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
-     spu.s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
+     spu.s_chan[ch].bIgnoreLoop = 0;\r
+     spu.s_chan[ch].bStarting = 1;\r
      spu.dwNewChannel|=(1<<ch);\r
     }\r
   }\r
@@ -376,7 +435,7 @@ static void SoundOn(int start,int end,unsigned short val)
 static void SoundOff(int start,int end,unsigned short val)\r
 {\r
  int ch;\r
- for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
+ for (ch = start; val && ch < end; ch++, val >>= 1)    // loop channels\r
   {\r
    if(val&1)\r
     {\r
@@ -442,6 +501,7 @@ static void SetVolumeL(unsigned char ch,short vol)     // LEFT VOLUME
  if(vol&0x8000)                                        // sweep?\r
   {\r
    short sInc=1;                                       // -> sweep up?\r
+   log_unhandled("ch%d sweepl %04x\n", ch, vol);\r
    if(vol&0x2000) sInc=-1;                             // -> or down?\r
    if(vol&0x1000) vol^=0xffff;                         // -> mmm... phase inverted? have to investigate this\r
    vol=((vol&0x7f)+1)/2;                               // -> sweep: 0..127 -> 0..64\r
@@ -457,6 +517,7 @@ static void SetVolumeL(unsigned char ch,short vol)     // LEFT VOLUME
 \r
  vol&=0x3fff;\r
  spu.s_chan[ch].iLeftVolume=vol;                       // store volume\r
+ //spu.regArea[(0xe00-0xc00)/2 + ch*2 + 0] = vol << 1;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -468,6 +529,7 @@ static void SetVolumeR(unsigned char ch,short vol)     // RIGHT VOLUME
  if(vol&0x8000)                                        // comments... see above :)\r
   {\r
    short sInc=1;\r
+   log_unhandled("ch%d sweepr %04x\n", ch, vol);\r
    if(vol&0x2000) sInc=-1;\r
    if(vol&0x1000) vol^=0xffff;\r
    vol=((vol&0x7f)+1)/2;        \r
@@ -483,6 +545,7 @@ static void SetVolumeR(unsigned char ch,short vol)     // RIGHT VOLUME
  vol&=0x3fff;\r
 \r
  spu.s_chan[ch].iRightVolume=vol;\r
+ //spu.regArea[(0xe00-0xc00)/2 + ch*2 + 1] = vol << 1;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -495,10 +558,11 @@ static void SetPitch(int ch,unsigned short val)               // SET PITCH
  if(val>0x3fff) NP=0x3fff;                             // get pitch val\r
  else           NP=val;\r
 \r
- spu.s_chan[ch].iRawPitch=NP;\r
- spu.s_chan[ch].sinc=(NP<<4)|8;\r
- spu.s_chan[ch].sinc_inv=0;\r
- if(spu_config.iUseInterpolation==1) spu.s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag\r
+ spu.s_chan[ch].iRawPitch = NP;\r
+ spu.s_chan[ch].sinc = NP << 4;\r
+ spu.s_chan[ch].sinc_inv = 0;\r
+\r
+ // don't mess spu.dwChannelsAudible as adsr runs independently\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -514,3 +578,5 @@ static void ReverbOn(int start,int end,unsigned short val)
    spu.s_chan[ch].bReverb=val&1;                       // -> reverb on/off\r
   }\r
 }\r
+\r
+// vim:shiftwidth=1:expandtab\r