Support compiling without pthreads
[pcsx_rearmed.git] / plugins / dfsound / spu.c
index f4426ab..f5e8de5 100644 (file)
  *                                                                         *
  ***************************************************************************/
 
-#if !defined(_WIN32) && !defined(NO_OS)
-#include <sys/time.h> // gettimeofday in xa.c
-#define THREAD_ENABLED 1
-#endif
 #include "stdafx.h"
 
 #define _IN_SPU
@@ -212,7 +208,7 @@ static void do_irq(void)
 
 static int check_irq(int ch, unsigned char *pos)
 {
- if((spu.spuCtrl & CTRL_IRQ) && pos == spu.pSpuIrq)
+ if((spu.spuCtrl & (CTRL_ON|CTRL_IRQ)) == (CTRL_ON|CTRL_IRQ) && pos == spu.pSpuIrq)
  {
   //printf("ch%d irq %04x\n", ch, pos - spu.spuMemC);
   do_irq();
@@ -221,6 +217,17 @@ static int check_irq(int ch, unsigned char *pos)
  return 0;
 }
 
+void check_irq_io(unsigned int addr)
+{
+ unsigned int irq_addr = regAreaGet(H_SPUirqAddr) << 3;
+ //addr &= ~7; // ?
+ if((spu.spuCtrl & (CTRL_ON|CTRL_IRQ)) == (CTRL_ON|CTRL_IRQ) && addr == irq_addr)
+ {
+  //printf("io   irq %04x\n", irq_addr);
+  do_irq();
+ }
+}
+
 ////////////////////////////////////////////////////////////////////////
 // START SOUND... called by main thread to setup a new sound on a channel
 ////////////////////////////////////////////////////////////////////////
@@ -251,8 +258,7 @@ static void StartSoundMain(int ch)
 
  spu.dwNewChannel&=~(1<<ch);                           // clear new channel bit
  spu.dwChannelDead&=~(1<<ch);
- if (s_chan->iRawPitch)
-  spu.dwChannelsAudible|=1<<ch;
+ spu.dwChannelsAudible|=1<<ch;
 }
 
 static void StartSound(int ch)
@@ -276,9 +282,8 @@ INLINE int FModChangeFrequency(int *SB, int pitch, int ns)
  if(NP<0x1)    NP=0x1;
 
  sinc=NP<<4;                                           // calc frequency
- if(spu_config.iUseInterpolation==1)                   // freq change in simple interpolation mode
-  SB[32]=1;
  iFMod[ns]=0;
+ SB[32]=1;                                             // reset interpolation
 
  return sinc;
 }                    
@@ -348,11 +353,11 @@ INLINE int iGetInterpolationVal(int *SB, int sinc, int spos, int fmod_freq)
      int vl, vr;int gpos;
      vl = (spos >> 6) & ~3;
      gpos = SB[28];
-     vr=(gauss[vl]*(int)gval0)&~2047;
-     vr+=(gauss[vl+1]*gval(1))&~2047;
-     vr+=(gauss[vl+2]*gval(2))&~2047;
-     vr+=(gauss[vl+3]*gval(3))&~2047;
-     fa = vr>>11;
+     vr=(gauss[vl]*(int)gval0) >> 15;
+     vr+=(gauss[vl+1]*gval(1)) >> 15;
+     vr+=(gauss[vl+2]*gval(2)) >> 15;
+     vr+=(gauss[vl+3]*gval(3)) >> 15;
+     fa = vr;
     } break;
    //--------------------------------------------------//
    case 1:                                             // simple interpolation
@@ -770,6 +775,9 @@ static void do_channels(int ns_to)
    s_chan = &spu.s_chan[ch];
    SB = spu.SB + ch * SB_SIZE;
    sinc = s_chan->sinc;
+   if (spu.s_chan[ch].bNewPitch)
+    SB[32] = 1;                                    // reset interpolation
+   spu.s_chan[ch].bNewPitch = 0;
 
    if (s_chan->bNoise)
     d = do_samples_noise(ch, ns_to);
@@ -821,7 +829,7 @@ static void do_samples_finish(int *SSumLR, int ns_to,
 
 // optional worker thread handling
 
-#if defined(THREAD_ENABLED) || defined(WANT_THREAD_CODE)
+#if HAVE_PTHREAD || defined(WANT_THREAD_CODE)
 
 // worker thread state
 static struct spu_worker {
@@ -858,11 +866,14 @@ static struct spu_worker {
    int sinc;
    int start;
    int loop;
-   int ns_to;
    short vol_l;
    short vol_r;
+   unsigned short ns_to;
+   unsigned short bNoise:1;
+   unsigned short bFMod:2;
+   unsigned short bRVBActive:1;
+   unsigned short bNewPitch:1;
    ADSRInfoEx adsr;
-   // might also want to add fmod flags..
   } ch[24];
   int SSumLR[NSSIZE * 2];
  } i[4];
@@ -940,6 +951,10 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
    work->ch[ch].vol_r = s_chan->iRightVolume;
    work->ch[ch].start = s_chan->pCurr - spu.spuMemC;
    work->ch[ch].loop = s_chan->pLoop - spu.spuMemC;
+   work->ch[ch].bNoise = s_chan->bNoise;
+   work->ch[ch].bFMod = s_chan->bFMod;
+   work->ch[ch].bRVBActive = s_chan->bRVBActive;
+   work->ch[ch].bNewPitch = s_chan->bNewPitch;
    if (s_chan->prevflags & 1)
     work->ch[ch].start = work->ch[ch].loop;
 
@@ -950,8 +965,10 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
    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;
   }
 
  work->rvb_addr = 0;
@@ -971,8 +988,6 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
 static void do_channel_work(struct work_item *work)
 {
  unsigned int mask;
- unsigned int decode_dirty_ch = 0;
- const SPUCHAN *s_chan;
  int *SB, sinc, spos, sbpos;
  int d, ch, ns_to;
 
@@ -997,15 +1012,16 @@ static void do_channel_work(struct work_item *work)
    sbpos = work->ch[ch].sbpos;
    sinc = work->ch[ch].sinc;
 
-   s_chan = &spu.s_chan[ch];
    SB = spu.SB + ch * SB_SIZE;
+   if (work->ch[ch].bNewPitch)
+    SB[32] = 1; // reset interpolation
 
-   if (s_chan->bNoise)
+   if (work->ch[ch].bNoise)
     do_lsfr_samples(d, work->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
-   else if (s_chan->bFMod == 2
-         || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0))
+   else if (work->ch[ch].bFMod == 2
+         || (work->ch[ch].bFMod == 0 && spu_config.iUseInterpolation == 0))
     do_samples_noint(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
-   else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1)
+   else if (work->ch[ch].bFMod == 0 && spu_config.iUseInterpolation == 1)
     do_samples_simple(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
    else
     do_samples_default(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
@@ -1017,14 +1033,11 @@ static void do_channel_work(struct work_item *work)
    }
 
    if (ch == 1 || ch == 3)
-    {
-     do_decode_bufs(spu.spuMem, ch/2, ns_to, work->decode_pos);
-     decode_dirty_ch |= 1 << ch;
-    }
+    do_decode_bufs(spu.spuMem, ch/2, ns_to, work->decode_pos);
 
-   if (s_chan->bFMod == 2)                         // fmod freq channel
+   if (work->ch[ch].bFMod == 2)                         // fmod freq channel
     memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
-   if (s_chan->bRVBActive && work->rvb_addr)
+   if (work->ch[ch].bRVBActive && work->rvb_addr)
     mix_chan_rvb(work->SSumLR, ns_to,
       work->ch[ch].vol_l, work->ch[ch].vol_r, RVB);
    else
@@ -1071,7 +1084,7 @@ static void sync_worker_thread(int force) {}
 
 static const void * const worker = NULL;
 
-#endif // THREAD_ENABLED
+#endif // HAVE_PTHREAD || defined(WANT_THREAD_CODE)
 
 ////////////////////////////////////////////////////////////////////////
 // MAIN SPU FUNCTION
@@ -1136,6 +1149,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
       do_irq();
      }
    }
+  check_irq_io(spu.spuAddr);
 
   if (unlikely(spu.rvb->dirty))
    REVERBPrep();
@@ -1146,6 +1160,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
   }
   else {
    queue_channel_work(ns_to, silentch);
+   //sync_worker_thread(1); // uncomment for debug
   }
 
   // advance "stopped" channels that can cause irqs
@@ -1193,13 +1208,13 @@ static void do_samples_finish(int *SSumLR, int ns_to,
   for (ns = 0; ns < ns_to * 2; )
    {
     d = SSumLR[ns]; SSumLR[ns] = 0;
-    d = d * vol_l >> 15;
+    d = d * vol_l >> 14;
     ssat32_to_16(d);
     *spu.pS++ = d;
     ns++;
 
     d = SSumLR[ns]; SSumLR[ns] = 0;
-    d = d * vol_r >> 15;
+    d = d * vol_r >> 14;
     ssat32_to_16(d);
     *spu.pS++ = d;
     ns++;
@@ -1350,7 +1365,7 @@ static void RemoveStreams(void)
 /* special code for TI C64x DSP */
 #include "spu_c64x.c"
 
-#elif defined(THREAD_ENABLED)
+#elif HAVE_PTHREAD
 
 #include <pthread.h>
 #include <semaphore.h>
@@ -1449,7 +1464,7 @@ static void exit_spu_thread(void)
  worker = NULL;
 }
 
-#else // if !THREAD_ENABLED
+#else // if !HAVE_PTHREAD
 
 static void init_spu_thread(void)
 {