spu: add decode buffer and reverb read handling
authornotaz <notasas@gmail.com>
Sun, 8 Jul 2012 21:28:04 +0000 (00:28 +0300)
committernotaz <notasas@gmail.com>
Sun, 15 Jul 2012 17:30:10 +0000 (20:30 +0300)
plugins/dfsound/externals.h
plugins/dfsound/registers.c
plugins/dfsound/reverb.c
plugins/dfsound/spu.c

index 3cb388c..f844b25 100644 (file)
 // generic defines\r
 /////////////////////////////////////////////////////////\r
 \r
+#if 0 //def __GNUC__\r
+#define noinline __attribute__((noinline))\r
+#define unlikely(x) __builtin_expect((x), 0)\r
+#else\r
+#define noinline\r
+#define unlikely(x) x\r
+#endif\r
+\r
 #define PSE_LT_SPU                  4\r
 #define PSE_SPU_ERR_SUCCESS         0\r
 #define PSE_SPU_ERR                 -60\r
@@ -202,6 +210,7 @@ extern int        iUseInterpolation;
 // MISC\r
 \r
 extern int had_dma;\r
+extern int decode_pos;\r
 \r
 extern SPUCHAN s_chan[];\r
 extern REVERBInfo rvb;\r
index 45df2eb..54e4000 100644 (file)
@@ -212,6 +212,9 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val)
          {\r
           rvb.StartAddr=(unsigned long)val<<2;\r
           rvb.CurrAddr=rvb.StartAddr;\r
+          // sync-with-decode-buffers hack..\r
+          if(rvb.StartAddr==0x3ff00)\r
+            rvb.CurrAddr+=decode_pos/2;\r
          }\r
        }\r
       rvb.dirty = 1;\r
index 2d65a69..ebb709b 100644 (file)
@@ -157,11 +157,44 @@ static void MixREVERB(void)
    s_buffer(MIX_DEST_B0, mix_dest_b0);\r
    s_buffer(MIX_DEST_B1, mix_dest_b1);\r
 \r
-   l = (mix_dest_a0 + mix_dest_b0) / 3;\r
-   r = (mix_dest_a1 + mix_dest_b1) / 3;\r
+   l = (mix_dest_a0 + mix_dest_b0) / 2;\r
+   r = (mix_dest_a1 + mix_dest_b1) / 2;\r
 \r
-   l = (l * rvb.VolLeft)  >> 14;\r
-   r = (r * rvb.VolRight) >> 14;\r
+   l = (l * rvb.VolLeft)  >> 15; // 15?\r
+   r = (r * rvb.VolRight) >> 15;\r
+\r
+   SSumLR[ns++] += (l + l_old) / 2;\r
+   SSumLR[ns++] += (r + r_old) / 2;\r
+   SSumLR[ns++] += l;\r
+   SSumLR[ns++] += r;\r
+\r
+   l_old = l;\r
+   r_old = r;\r
+\r
+   curr_addr++;\r
+   if (curr_addr >= 0x40000) curr_addr = rvb.StartAddr;\r
+  }\r
+\r
+ rvb.iRVBLeft = l;\r
+ rvb.iRVBRight = r;\r
+ rvb.CurrAddr = curr_addr;\r
+}\r
+\r
+static void MixREVERB_off(void)\r
+{\r
+ int l_old = rvb.iRVBLeft;\r
+ int r_old = rvb.iRVBRight;\r
+ int curr_addr = rvb.CurrAddr;\r
+ int space = 0x40000 - rvb.StartAddr;\r
+ int l, r, ns;\r
+\r
+ for (ns = 0; ns < NSSIZE*2; )\r
+  {\r
+   l = (g_buffer(MIX_DEST_A0) + g_buffer(MIX_DEST_B0)) / 2;\r
+   r = (g_buffer(MIX_DEST_A1) + g_buffer(MIX_DEST_B1)) / 2;\r
+\r
+   l = (l * rvb.VolLeft)  >> 15;\r
+   r = (r * rvb.VolRight) >> 15;\r
 \r
    SSumLR[ns++] += (l + l_old) / 2;\r
    SSumLR[ns++] += (r + r_old) / 2;\r
@@ -235,14 +268,21 @@ INLINE void REVERBDo(void)
 \r
  if (spuCtrl & 0x80)                                   // -> reverb on? oki\r
  {\r
-  if (rvb.dirty)\r
+  if (unlikely(rvb.dirty))\r
    prepare_offsets();\r
 \r
   MixREVERB();\r
  }\r
+ else if (rvb.VolLeft || rvb.VolRight)\r
+ {\r
+  if (unlikely(rvb.dirty))\r
+   prepare_offsets();\r
+\r
+  MixREVERB_off();\r
+ }\r
  else                                                  // -> reverb off\r
  {\r
-  // supposedly runs anyway?\r
+  // reverb runs anyway\r
   rvb.CurrAddr += NSSIZE/2;\r
   while (rvb.CurrAddr >= 0x40000)\r
    rvb.CurrAddr -= 0x40000 - rvb.StartAddr;\r
index d5a8215..bf02946 100644 (file)
@@ -75,7 +75,6 @@ unsigned short  spuMem[256*1024];
 unsigned char * spuMemC;
 unsigned char * pSpuIrq=0;
 unsigned char * pSpuBuffer;
-unsigned char * pMixIrq=0;
 
 // user settings
 
@@ -120,6 +119,8 @@ int iFMod[NSSIZE];
 int iCycle = 0;
 short * pS;
 
+static int decode_dirty_ch;
+int decode_pos;
 int had_dma;
 int lastch=-1;             // last channel processed on spu irq in timer mode
 static int lastns=0;       // last ns pos
@@ -657,6 +658,23 @@ static void mix_chan_rvb(int start, int count, int lv, int rv)
 }
 #endif
 
+// 0x0800-0x0bff  Voice 1
+// 0x0c00-0x0fff  Voice 3
+static void noinline do_decode_bufs(int which, int start, int count)
+{
+ const int *src = ChanBuf + start;
+ unsigned short *dst = &spuMem[0x800/2 + which*0x400/2];
+ int cursor = decode_pos;
+
+ while (count-- > 0)
+  {
+   dst[cursor] = *src++;
+   cursor = (cursor + 1) & 0x1ff;
+  }
+
+ // decode_pos is updated and irqs are checked later, after voice loop
+}
+
 ////////////////////////////////////////////////////////////////////////
 // MAIN SPU FUNCTION
 // here is the main job handler...
@@ -728,6 +746,12 @@ static int do_samples(int forced_updates)
 
        MixADSR(ch, ns_from, ns_to);
 
+       if(ch==1 || ch==3)
+        {
+         do_decode_bufs(ch/2, ns_from, ns_to-ns_from);
+         decode_dirty_ch |= 1<<ch;
+        }
+
        if(s_chan[ch].bFMod==2)                         // fmod freq channel
         memcpy(iFMod, ChanBuf, sizeof(iFMod));
        else if(s_chan[ch].bRVBActive)
@@ -769,6 +793,16 @@ static int do_samples(int forced_updates)
     if(bIRQReturn)                                     // special return for "spu irq - wait for cpu action"
       return 0;
 
+  if(unlikely(silentch & decode_dirty_ch & (1<<1)))    // must clear silent channel decode buffers
+   {
+    memset(&spuMem[0x800/2], 0, 0x400);
+    decode_dirty_ch &= ~(1<<1);
+   }
+  if(unlikely(silentch & decode_dirty_ch & (1<<3)))
+   {
+    memset(&spuMem[0xc00/2], 0, 0x400);
+    decode_dirty_ch &= ~(1<<3);
+   }
 
   //---------------------------------------------------//
   //- here we have another 1 ms of sound data
@@ -822,18 +856,17 @@ static int do_samples(int forced_updates)
   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
   // in some of Peops timer modes. So: we ignore this option here (for now).
 
-  if(pMixIrq && (spuCtrl&CTRL_IRQ) && pSpuIrq && pSpuIrq<spuMemC+0x1000)                 
+  if(unlikely((spuCtrl&CTRL_IRQ) && pSpuIrq && pSpuIrq<spuMemC+0x1000))
    {
-    for(ns=0;ns<NSSIZE;ns++)
+    int irq_pos=(pSpuIrq-spuMemC)/2 & 0x1ff;
+    if((decode_pos <= irq_pos && irq_pos < decode_pos+NSSIZE)
+       || (decode_pos+NSSIZE > 0x200 && irq_pos < ((decode_pos+NSSIZE) & 0x1ff)))
      {
-        for(ch=0;ch<4;ch++)
-         {
-          if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
-           do_irq();
-         }
-      pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
+      //printf("decoder irq %x\n", decode_pos);
+      do_irq();
      }
    }
+  decode_pos = (decode_pos + NSSIZE) & 0x1ff;
 
   InitREVERB();
 
@@ -966,8 +999,6 @@ void SetupStreams(void)
    s_chan[i].pCurr=spuMemC;
   }
 
- pMixIrq=spuMemC;                                      // enable decoded buffer irqs by setting the address
-
  ClearWorkingState();
 
  bSpuInit=1;                                           // flag: we are inited
@@ -998,7 +1029,7 @@ long CALLBACK SPUinit(void)
  spuIrq = 0;
  spuAddr = 0xffffffff;
  spuMemC = (unsigned char *)spuMem;
pMixIrq = 0;
decode_pos = 0;
  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
  pSpuIrq = 0;
  lastch = -1;